天天看点

在Blazor项目中结合数据库及身份验证的尝试

初次接触Blazor项目,很喜欢这个框架,使我等C#程序员不必再花时间和精力去学习各种前端UI框架。手头的项目正好要做一个界面丰富的前端,于是决定用Blazor Server来做。

项目分为前端和后台管理,后台管理已经用ASP.NET Core MVC完成。前端和后台共享一个数据库,前端主要是查询和展示,有少量提交和更新。

微软在github中的AspNetCore源码中提供了Blazor Server使用EF Core的源码:下载

在源码目录aspnetcore\blazor\common\samples\版本号\BlazorServerEFCoreSample\BlazorServerDbContextExample\Data中复制以下三个文件到自己的项目中:

DbContextFactory.cs
FactoryExtensions.cs
IDbContextFactory.cs
           

FactoryExtensions中包含一个扩展方法AddDbContextFactory,用来在StartUp中注册工厂方法。DbContextFactory则包含了创建EF上下文的工厂方法。

首先在StartUp中注册工厂方法

//以下代码添加到StartUp的ConfigureServices方法中
services.AddDbContextFactory<CloudContext>(options =>
     options.UseMySql(Configuration.GetConnectionString("CloudContextConnection")));
//DeviceService是访问数据的类,需要在这里注册
services.AddSingleton<DeviceService>();
           

接下来创建DeviceService,用来访问数据库中的Device表

public class DeviceService
 {
     private readonly IServiceProvider provider;
     public DeviceService(IServiceProvider provider)
     {
         this.provider = provider;
     }

     public Task<Service[]> GetAllDevices()
     {
         using var context = new DbContextFactory<CloudContext>(provider).CreateDbContext();
         return Task.FromResult(context.Devices.ToArray());
     }
}
           

blazor的组件Device.razor的代码:

@inject DeviceService deviceService
<div>
    <ul>
        @foreach (var device in devices)
        {
            <li>
            	@device.deviceName
            </li>
        }
    </ul>
</div>

@code {
    private Device[] devices;
    protected override async Task OnInitializedAsync()
    {
        devices= await deviceService.GetAllDevices();
    }
}
           

解决了数据库问题,还要处理用户授权验证问题。本项目的前端是需要用户注册登录,并根据是否登录和用户身份来展现不同内容。

Blazor支持ASP.NET Core的Identity基架,而且AuthorizeView组件可以根据是否授权来呈现不同内容。

按照微软官方文档的教程,向Blazor项目添加Identity基架却总是不能成功,出现各种服务未注册、不能解析DB上下文等异常,经过反复尝试,最后总算成功了。

首先,重新创建Blazor项目,创建时,点击右边的身份验证下的“更改”,然后选择“个人用户账户”。

在Blazor项目中结合数据库及身份验证的尝试

项目创建成功后,Ctrl+F5运行,可以发现Identity基架没有任何问题,注册登录等功能都可以使用。但项目模板使用的是默认的SqlExpress数据库,登录注册等页面也是完全被封装而无法更改,所以我们还要加以改造。

右键单击Blazor项目,在弹出菜单中选择:添加->新搭建基架的项目,在模板对话框中选择“标识”,最后按图所示点“确定”。

在Blazor项目中结合数据库及身份验证的尝试

完成后查看项目

在Blazor项目中结合数据库及身份验证的尝试

这时我们可以自由修改注册登录的页面内容了。

不过项目现在还不能运行,会有一些错误。

打开Register.cshtml.cs,把和IEmailSender相关的代码都注释掉。这是一个验证Email的服务,但是我们并没有实现它,如果需要这个服务,你必须得自己实现发送及验证Email的代码,并在StartUp中注册你的服务:

services.AddTransient<IEmailSender,YourEmailSender>();

。如果使用了自定义的用户类来代替IdentityUser,那么再打开Pages\Shared_Layout.cshtml,把嵌入_LoginPartial.cshtml的代码

await Html.RenderPartialAsync("_LoginPartial");

也注释掉,因为这里始终会报一个无法解析IdentityUser的错误,没有找到原因。好在我们并不需要_LoginPartial.cshtml。

接下来修改StartUp的ConfigureServices方法,修改后的代码类似如下:

public void ConfigureServices(IServiceCollection services)
 {
 	//注册访问EF上下文的工厂方法,这行和下一行的顺序一定不能错
     services.AddDbContextFactory<CloudContext>(options =>
         options.UseMySql(Configuration.GetConnectionString("CloudContextConnection")));
     //添加Identity基架的数据库支持
     services.AddDbContext<CloudContext>(options =>
         options.UseMySql(Configuration.GetConnectionString("CloudContextConnection")));
     //如果使用默认的IdentityUser类进行身份验证,则取消这一行的注释,注释掉下面一行
     //services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
     //    .AddEntityFrameworkStores<CloudContext>();
     //使用自定义的User和Role类进行身份验证
     services.AddIdentity<User, Role>().AddEntityFrameworkStores<CloudContext>();
     services.AddRazorPages();
     services.AddServerSideBlazor();
     //如果使用IdentityUser类,把User改为IdentityUser
     services.AddScoped<AuthenticationStateProvider, RevalidatingIdentityAuthenticationStateProvider<User>>();
     services.AddSingleton<DeviceService>();
 }
           

至此大功告成。注册登录等页面可以根据项目的实际需求重写。

继续阅读