使用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>>();
}
您应该能够像任何.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中的任何依赖关系。