在 Blazor 服务器中使用数据库上下文工厂

Posted

技术标签:

【中文标题】在 Blazor 服务器中使用数据库上下文工厂【英文标题】:Using a DB context factory in Blazor server 【发布时间】:2022-01-07 06:47:18 【问题描述】:

我在为服务器端 Blazor 应用设置 EF 数据库连接时遇到了一些问题。它一直在使用标准的DbContext 设置,直到我注意到由于 Blazor 的性质在整个过程中使用相同的上下文而导致连接无法正确关闭的一些问题。我的研究使我查看了DbContextFactory,但现在不推荐使用接口IDbContextFactory,取而代之的是IDesignTimeDbContextFactory

我已经设置了一个类来实现接口:

public class FIS2ContextFactory : IDesignTimeDbContextFactory<FIS2_DbContext>

    private readonly DbContextOptions<FIS2_FranklinContext_AutoGenerated> options;

    public FIS2ContextFactory(DbContextOptions<FIS2_FranklinContext_AutoGenerated> contextOptions)
    
        options = contextOptions;
    

    public FIS2_DbContext CreateDbContext(string[] args)
    
        return new FIS2_DbContext(options);
    

我要使用的 DbContext 是这个,它继承并扩展了 EF Power Tools 生成的 DbContext:

public partial class FIS2_DbContext : FIS2_FranklinContext_AutoGenerated

    public FIS2_DbContext()
    
    

    public FIS2_DbContext(DbContextOptions<FIS2_FranklinContext_AutoGenerated> options) : base(options)

    
    

    public virtual DbSet<StudentBasicDetailsWithCurrentTg> StudentBasicDetailsWithCurrentTgs  get; set; 
    public virtual DbSet<CurriculumSearchBasicDetails> CurriculumSearchBasicDetails  get; set; 
    public virtual DbSet<StudentAllEnrolments> StudentAllEnrolments  get; set; 

在我的startup.cs 中,我在ConfigureServices 方法中这样设置:

    public void ConfigureServices(IServiceCollection services)
    
        services.AddDbContextFactory<FIS2_DbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("FIS2")));

        services.AddRazorPages();
        services.AddServerSideBlazor();
        services.AddScoped<IFileService, FileService>();
        services.AddScoped<IEmailService, EmailService>();
        services.AddScoped<ITimetableService, TimetableService>();
        services.AddScoped<ICurriculumService, CurriculumServiceEf>();
        services.AddScoped<IStudentService, StudentServiceEf>();
        services.AddScoped<ICollectionService, CollectionsServiceEf>();
        services.AddHttpContextAccessor();
        services.AddHttpClient();
        services.AddAuthenticationCore();
        services.AddAuthentication(IISDefaults.AuthenticationScheme);
        services.AddAuthorization();
        services.AddSyncfusionBlazor();
        services.AddScoped<SessionState>();
    

我的问题是,在设置使用此数据库连接的服务时,我在program.cs 中遇到此错误消息:

无法构造某些服务(验证服务描述符“ServiceType:DataLibrary.Data.Interfaces.ITimetableService Lifetime:Scoped ImplementationType:DataLibrary.Data.BusinessLayer.TimetableService”时出错:无法解析“DataLibrary”类型的服务.Models.FIS2ContextFactory',同时尝试激活'DataLibrary.Data.BusinessLayer.TimetableService'。)(验证服务描述符'ServiceType:DataLibrary.Data.Interfaces.ICurriculumService Lifetime:Scoped ImplementationType:DataLibrary.Data.BusinessLayer.CurriculumServiceEf'时出错:尝试激活“DataLibrary.Data.BusinessLayer.CurriculumServiceEf”时,无法解析“DataLibrary.Models.FIS2ContextFactory”类型的服务。)(验证服务描述符“ServiceType:DataLibrary.Data.Interfaces.ISTudentService Lifetime:Scoped ImplementationType”时出错:DataLibrary.Data.BusinessLayer.StudentServiceEf':无法解析“DataLibrary.Model”类型的服务s.FIS2ContextFactory',同时尝试激活'DataLibrary.Data.BusinessLayer.StudentServiceEf'。)(验证服务描述符'ServiceType:DataLibrary.Data.Interfaces.ICollectionService Lifetime:Scoped ImplementationType:DataLibrary.Data.BusinessLayer.CollectionsServiceEf'时出错:尝试激活“DataLibrary.Data.BusinessLayer.CollectionsServiceEf”时无法解析“DataLibrary.Models.FIS2ContextFactory”类型的服务。)

作为参考,这里是一个如何设置TimetableService 的示例(其他的实例化方式相同):

using DataLibrary.Data.Interfaces;
using DataLibrary.Models;
using DataLibrary.Models.timetable;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace DataLibrary.Data.BusinessLayer

    public class TimetableService : ITimetableService
    
        private FIS2ContextFactory _contextFactory;

        public TimetableService(FIS2ContextFactory db)
        
            _contextFactory = db;
        

        public async Task<List<spGetHolidaysBetweenDatesResult>> GetHolidaysBetweenDatesAsync(DateTime startDate, DateTime endDate)
        
            string[] args =  "" ;
            var _db = _contextFactory.CreateDbContext(args);
            var procedures = _db.Procedures;

            return await procedures.spGetHolidaysBetweenDatesAsync(startDate, endDate);
        

        public async Task<List<PeriodsBetweenDates>> GetPeriodsBetweenDatesAsync(DateTime startDate, DateTime endDate)
        
            string[] args =  "" ;
            var _db = _contextFactory.CreateDbContext(args);
            var procedures = _db.Procedures;
            var toReturn = new List<PeriodsBetweenDates>();
            var results = await procedures.spGetPeriodsBetweenDatesAsync(startDate, endDate);
            foreach (var item in results)
            
                toReturn.Add(new PeriodsBetweenDates(item.Date, item.Timetable, item.BlockCode, item.StartTime, item.EndTime));
            
            return toReturn;
        

        public async Task<List<StudentTimetable>> GetStudentTimetableAsync(DateTime startDate, DateTime endDate, string studentID)
        
            string[] args =  "" ;
            var _db = _contextFactory.CreateDbContext(args);
            var procedures = _db.Procedures;
            var results = await procedures.spGetStudentTimetableAsync(startDate, endDate, studentID);

            List<StudentTimetable> studentTimetables = new List<StudentTimetable>();
            foreach (var item in results)
            
                studentTimetables.Add(JsonConvert.DeserializeObject<StudentTimetable>(item.timetable));
            
            return studentTimetables;
        
    

是因为我在启动时使用了错误的方法来创建上下文工厂,还是后来我弄错了?

【问题讨论】:

【参考方案1】:

如果要解析特定的工厂类型,则必须注册此重载,AddDbContextFactory&lt;TContext,TFactory&gt; 记录在 here:

这个重载允许一个特定的实现 要注册的 IDbContextFactory 而不是使用 EF Core 附带的默认工厂。

所以

services.AddDbContextFactory<FIS2_DbContext,FIS2ContextFactory>(options => options.UseSqlServer(Configuration.GetConnectionString("FIS2")));

【讨论】:

啊,我没有发现它被隐藏在 DI 区域而不是其他地方的类/接口特定块。虽然,这样做它不喜欢IDesignTimeDbContextFactory 实现,所以我已经恢复到IDbContextFactory

以上是关于在 Blazor 服务器中使用数据库上下文工厂的主要内容,如果未能解决你的问题,请参考以下文章

在 Blazor 中使用带有 AddDbContextFactory 的标识

Blazor 服务器应用程序和 IDbContextFactory 未处理

在 Blazor 服务器端应用程序中违反主键约束“PK_AspNetUsers”

ASP.NET Core Blazor 服务器中的实体框架上下文生命周期

Blazor:在前一个操作完成之前在此上下文上启动了第二个操作

Blazor、对象生命周期和依赖注入