如何在ServiceStack Core中注册DbContext EF Core?

问题描述 投票:2回答:1

使用EF Core,DbContext被EF服务扩展注册为Scoped。这是可取的,因为DbContext不是线程安全的,因此应该根据请求创建它。

ServiceStack IOC将Startup中的任何Scoped注册视为单例,这与上述内容相矛盾。

一种可能的解决方案是不使用EF Core的服务扩展,但这似乎带来了大量的样板代码并降低了可维护性。有没有更好的方法?

--

UPDATE

为了清晰起见,我想提供示例代码

我添加了一个DbContext类的私有指南,以便我可以判断我们是否有新实例。

public class BloggingContext : DbContext
{
    private readonly Guid _instance;

    public BloggingContext(DbContextOptions<BloggingContext> options)
        : base(options)
    { 
        _instance = Guid.NewGuid();
    }

    public DbSet<Blog> Blogs { get; set; }
}

使用.NET Core MVC,控制器代码看起来像

public class BlogsController : Controller
{
    private readonly BloggingContext _context;

    public BlogsController(BloggingContext context) 
    {
        _context = context;
    }

    // skip for readability
}

对于命中控制器的每个请求,BloggingContext中的_instance返回唯一值。但是,在ServiceStack服务中使用时,_instance始终返回相同的值。

public class BlogService : ServiceStack.Service
{
    private readonly BloggingContext _context;

    public BlogService(BloggingContext context) 
    {
        _context = context;
    }

    // skip for readability
}

此行为与关于.NET Core Container Adapter的ServiceStack文档一致,在.NET Core Startup中注册的作用域依赖项是ServiceStack中的单例。但是,这是不可取的,因为我们希望每个请求创建DbContext。

我的解决方案是将DbContext注册移动到AppHost代码中,如下所示

public override void Configure(Container container)
{
    container.AddScoped(c => 
    {
        var optionsBuilder = new DbContextOptionsBuilder<BloggingContext>();
        optionsBuilder.UseSqlServer(connection);
        return new BloggingContext(optionsBuilder.Options);
    });     
}

这段代码可以正常运行。注入我的BlogService的每个BloggingContext实例现在都是唯一的。但是,我发现自己无法使用任何服务集合扩展,这在.Net Core Startup中非常方便。例如,我想使用Entity Framework Unit Of Work而我无法打电话

services
    .AddUnitOfWork<BloggingContext>();

相反,我必须自己连接该库的所有依赖项

public override void Configure(Container container)
{
    container.AddScoped(c => 
    {
        var optionsBuilder = new DbContextOptionsBuilder<BloggingContext>();
        optionsBuilder.UseSqlServer(connection);
        return new BloggingContext(optionsBuilder.Options);
    });     
    container.AddScoped<IRepositoryFactory, UnitOfWork<BloggingContext>>();
    container.AddScoped<IUnitOfWork, UnitOfWork<BloggingContext>>();
    container.AddScoped<IUnitOfWork<BloggingContext>, UnitOfWork<BloggingContext>>();
}
entity-framework servicestack inversion-of-control dbcontext
1个回答
1
投票

您应该能够像任何.NET Core App一样在.NET Core's IOC中注册它:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<BloggingContext>(options => 
       options.UseSqlite("Data Source=blog.db"));
}

然后像ServiceStack Services中的普通依赖项一样引用:

public class MyServices : Service
{
     public BloggingContext BloggingContext { get; set; }
}

在.NET Core的IOC中,使用ServiceStack's .NET Core Container Adapter来解析不在ServiceStack的IOC中的任何依赖关系。

© www.soinside.com 2019 - 2024. All rights reserved.