Nov
12
Written by:
Michael Washington
11/12/2018 12:03 PM

The primary benefit we have when using server-side Blazor is that we do not have to make web http calls from the client code to the server code. This reduces the code we need to write and eliminates many security concerns.
In this article, we will demonstrate how a list of Weather forecasts can be added to the database by each user. A user will only have the ability to see their own forecasts.

We will start with the code from the article: A Demonstration of Simple Server-side Blazor Cookie Authentication.
NOTE: This sample code does not check to see if a person is using a legitimate username and password! You would need to add the proper code to check. This code is just a demonstration of how the process of authorizing a user works.
Create The Database

Open the project from A Demonstration of Simple Server-side Blazor Cookie Authentication in Visual Studio 2017 (or higher).
In Visual Studio, select Tools then Connect to Database.

Connect to any database you wish. However, if you want to use the SQL Server Express LocalDB for development…
- Click the Change button to switch providers
- Select the Microsoft SQL Server Database File provider
- Enter BlazorCookieAuthDB for Database file name
- Click OK

A box will pop up and ask if you want to create the database.
Click Yes.

If you look on your file system, at the location indicated in the popup, you will see the database files have been created.

In Visual Studio, select View then Server Explorer.

The database will display in the window (if it doesn’t, right-click on the Data Connections node and select Add connection and navigate to the database .mdf file).
Right-click on the Tables node and select Add New Table.

Paste the following script in the T-SQL window and then click the Update button:
CREATE TABLE [dbo].[WeatherForecast] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[Date] DATETIME NULL,
[TemperatureC] INT NULL,
[TemperatureF] INT NULL,
[Summary] NVARCHAR (50) NULL,
[UserName] NVARCHAR (50) NULL,
PRIMARY KEY CLUSTERED ([Id] ASC)
);

The script will prepare.
Click the Update Database button.

Back in the Server Explorer window, right-click on Tables and select Refresh.

The WeatherForecast table will display.
Right-click on the table and select Show Table Data.

We will enter some sample data for UserName Test@Test.com so that we will be able to test the data connection in the next steps.
Create Data Context

We will need to use Entity Framework Core to connect to the database from our code.
To do this, right-click on the BlazorCookieAuth.App node in the Solution Explorer and select Manage NuGet Packages.

Add a reference to Microsoft.EntityFrameworkCore.SqlServer

If you do not already have it installed, install EF Core Power Tools from:
https://marketplace.visualstudio.com/items?itemName=ErikEJ.EFCorePowerTools
(Note: Before installing, close Visual Studio)
(Note: Please give this project a 5 star review!)

Right-click on the BlazorCookieAuth.App node in the Solution Explorer and select EF Core Power Tools then Reverse Engineer.

Select the database file and click OK.

Select the WeatherForecast table and click OK.

Set the values and click OK.

Click OK.

In the Solution Explorer, you will see the Data Context has been created.

Select Build, then Rebuild Solution.
Set Run-Time Database Connection

We now desire to allow the database connection to be set in the application settings file.
This allows us to easily change the database connection when the application is deployed to different environments, such as production.
Create a file, in the BlazorCookieAuth.Server project called appsettings.json using the following code:

Replace {Path To Your database file} with the exact location of the of the .mdf database file you created earlier.
For example, on my computer the full path to the file is: C:\\Users\\Michael\\Documents\\
Alternatively, if you have used a connection to SQL Server, or another database, you would put that connection string here.

Open the Startup.cs file in the BlazorCookieAuth.Server project.
Add the following method:
public IConfigurationRoot Configuration { get; }
// This allows the appsettings.json file to be read
// this allows the database connection string to be passed to the
// Blazor Client app
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
Next, add the following code to the end of the existing ConfigureServices method:
// Allows: Configuration.GetConnectionString("DefaultConnection")
services.AddSingleton(Configuration);
Read From The Database

Delete the WeatherForecast.cs file in the BlazorCookieAuth.App project.
We will use the WeatherForcast class file created by the EF Core Tools.

Open the WeatherForecastService.cs file in the BlazorCookieAuth.App project.
Replace all the code with the following code:
using BlazorCookieAuth.Model;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace BlazorCookieAuth.App.Services
{
public class WeatherForecastService
{
private IHttpContextAccessor _httpContextAccessor;
private IConfigurationRoot _configRoot { get; set; }
public WeatherForecastService(
IHttpContextAccessor httpContextAccessor,
IConfigurationRoot configRoot)
{
// Allows us to determine who the logged in user is
_httpContextAccessor = httpContextAccessor;
// Allows us to call:
// Configuration.GetConnectionString("DefaultConnection")
// to get the connection to the database
_configRoot = configRoot;
}
public Task<List<WeatherForecast>> GetForecastAsync()
{
List<WeatherForecast> colWeatherForcasts = new List<WeatherForecast>();
// Get the name of the current user
string strCurrentUser = _httpContextAccessor.HttpContext.User.Identity.Name;
// Get the connection string that was set in the appsettings.json file
string strConnectionString = _configRoot.GetConnectionString("DefaultConnection");
// Create database options to connect to the database
var optionsBuilder = new DbContextOptionsBuilder<DatabaseContext>();
optionsBuilder.UseSqlServer(strConnectionString);
// Connect to the database
using (var context = new DatabaseContext(optionsBuilder.Options))
{
// Get Weather Forecasts
colWeatherForcasts = (from weatherForecast in context.WeatherForecast
// only get entries for the current logged in user
where weatherForecast.UserName == strCurrentUser
select weatherForecast).ToList();
}
return Task.FromResult(colWeatherForcasts);
}
}
}

Finally, open the FetchData.cshtml file in the BlazorCookieAuth.App project.
Replace all the code with the following code:
@using BlazorCookieAuth.App.Services
@using BlazorCookieAuth.Model
@page "/fetchdata"
@inject WeatherForecastService ForecastService
<h1>Weather forecast</h1>
<p>This component demonstrates fetching data from the server.</p>
@if (forecasts == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.Date.Value.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
}
@functions {
List<WeatherForecast> forecasts;
protected override async Task OnInitAsync()
{
forecasts = await ForecastService.GetForecastAsync();
}
}
This code simply calls the GetForecastAsync method we created in the previous step.
In a normal web application we would have to make a http web call from this client code to the code that connects to the database.
With server-side Blazor we don’t have to do that, yet the call is still secure because the pages are rendered on the server.

Build and run the project.
Note: If the build gets stuck or hangs. First cancel the build then select Clean build then try running the project again.
Click the Login button.

Log in as Test@Test.com (because we created data for that user earlier).
(Note: The password you enter does not matter because this sample code does not actually validate the password)

After you are logged in, switch to the Fetch data page and you will see the data for the test@test.com user we entered earlier.
Inserting Data Into The Database

Open the WeatherForecastService.cs file and add the following method:
public void AddForecast(WeatherForecast objNewWeatherForecast)
{
// Get the name of the current user
string strCurrentUser = _httpContextAccessor.HttpContext.User.Identity.Name;
// Get the connection string that was set in the appsettings.json file
string strConnectionString = _configRoot.GetConnectionString("DefaultConnection");
// Create database options to conect to the database
var optionsBuilder = new DbContextOptionsBuilder<DatabaseContext>();
optionsBuilder.UseSqlServer(strConnectionString);
// Connect to the database
using (var context = new DatabaseContext(optionsBuilder.Options))
{
// Set this forecast as the current user
// Convert Fahrenheit to Celsius
// Set the date to today
objNewWeatherForecast.UserName = strCurrentUser;
objNewWeatherForecast.TemperatureC =
(objNewWeatherForecast.TemperatureF.Value - 32) * 5 / 9;
objNewWeatherForecast.Date = System.DateTime.Now;
// Save the forecast
context.WeatherForecast.Add(objNewWeatherForecast);
context.SaveChanges();
}
}
Note that we are computing and setting values, such as the current logged in user, rather than trusting user input.

Open the FetchData.cshtml file.
Add the following HTML markup directly under the existing table element:
<p>
<button class="btn btn-primary" onclick="@OpenPopup">Add New Forecast</button>
</p>
@if (ShowAdd)
{
<div class="modal" tabindex="-1" style="display:block" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title">Add Forecast</h3>
<button type="button" class="close" onclick="@ClosePopup">
<span aria-hidden="true">X</span>
</button>
</div>
<div class="modal-body">
<input class="form-control" type="text"
placeholder="Fahrenheit forecast" bind="@NewFahrenheit" />
<input class="form-control" type="text"
placeholder="Summary" bind="@NewSummary" />
<br/>
<button class="btn btn-primary"
onclick="@AddForecast">Add</button>
</div>
</div>
</div>
</div>
}
Finally add the following code to the @functions section:
// Add Forcast
bool ShowAdd = false;
string NewFahrenheit;
string NewSummary;
void OpenPopup()
{
NewFahrenheit = "";
NewSummary = "";
ShowAdd = true;
}
void ClosePopup()
{
ShowAdd = false;
}
async Task AddForecast()
{
// Close the Popup
ShowAdd = false;
// Create as new forcast
// Only set the Fahrenheit and Summary values for now
// All other values will be set in the service method
WeatherForecast objNewWeatherForecast = new WeatherForecast();
objNewWeatherForecast.TemperatureF = Convert.ToInt32(NewFahrenheit);
objNewWeatherForecast.Summary = NewSummary;
ForecastService.AddForecast(objNewWeatherForecast);
// Update the forecasts
forecasts = await ForecastService.GetForecastAsync();
}

When you run the project, you can click the Add New Forecast button to add an entry.

The form only requires a Fahrenheit value and a summary, because all other values will be computed and set by the service method.

After clicking the Add button, the entry is saved to the database and displayed.
Links
Blazor.net
Blazor: Single Page Application Using Server-Side Blazor
Work with SQL Server LocalDB and ASP.NET Core
EF Core Power Tools
Download
The project is available at http://lightswitchhelpwebsite.com/Downloads.aspx
You must have Visual Studio 2017 (or higher) installed to run the code.