在一个ASP.NET核心项目中,我有以下关于启动的内容:
services.AddDbContext<Context>(x => x.UseSqlServer(connectionString));
services.AddTransient<IValidationService, ValidationService>();
services.AddTransient<IValidator<Model>, ModelValidator>();ValidationService如下:
public interface IValidationService {
Task<List<Error>> ValidateAsync<T>(T model);
}
public class ValidationService : IValidationService {
private readonly IServiceProvider _provider;
public ValidationService(IServiceProvider provider) {
_provider = provider;
}
public async Task<List<Error>> ValidateAsync<T>(T model) {
IValidator<T> validator = _provider.GetRequiredService<IValidator<T>>();
return await validator.ValidateAsync(model);
}
}ModelValidator如下:
public class ModelValidator : AbstractValidator<Model> {
public ModelValidator(Context context) {
// Some code using context
}
}当我将IValidationService注入控制器并将其用作:
List<Error> errors = await _validator.ValidateAsync(order); 我知道错误:
System.ObjectDisposedException:无法访问已释放的对象。造成此错误的一个常见原因是处理通过依赖项注入解决的上下文,然后尝试在应用程序的其他位置使用相同的上下文实例。这可能发生在对上下文调用This (),或者将上下文包装在using语句中。如果您使用的是依赖注入,则应该让依赖注入容器负责处理上下文实例。对象名称:“上下文”。
知道为什么在ModelValidator中使用上下文时会出现此错误。
怎么解决这个问题?
更新
所以我把代码改为:
services.AddScoped<IValidationService, ValidationService>();
services.AddScoped<IValidator<Model>, ModelValidator>();但我也犯了同样的错误。
更新种子数据代码在启动上的配置方法
因此,关于配置方法,我有:
if (hostingEnvironment.IsDevelopment())
applicationBuilder.SeedData();SeedData扩展是:
public static class DataSeedExtensions {
private static IServiceProvider _provider;
public static void SeedData(this IApplicationBuilder builder) {
_provider = builder.ApplicationServices;
_type = type;
using (Context context = (Context)_provider.GetService<Context>()) {
await context.Database.MigrateAsync();
// Insert data code
}
}我遗漏了什么?
更新--一个可能的解决方案
将我的种子方法改为以下方法似乎是可行的:
using (IServiceScope scope =
_provider.GetRequiredService<IServiceScopeFactory>().CreateScope()) {
Context context = _provider.GetService<Context>();
// Insert data in database
}发布于 2016-08-01 17:31:15
更新ASP.NET核心2.1
在ASP.NET Core2.1中,方法略有改变。通用方法与2.0类似,只是方法名称和返回类型已经更改。
public static void Main(string[] args)
{
CreateWebHostBuilder(args)
.Build()
.Seed();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
return new WebHostBuilder()
...; // Do not call .Build() here
}应用ASP.NET Core2.0
在ASP.NET Core2.0中,etc (dotnet ef migrations等)的使用方式发生了一些变化。在设计时确定DbContext和连接字符串。
下面的答案将导致在调用任何dotnet ef xxx命令时应用迁移和种子。
获取EF核心工具设计时实例的新模式是使用BuildHostWeb静态方法。
根据本公告,EF现在将使用静态BuildWebHost方法来配置整个应用程序,但不运行它。
公共类程序{公共静态空主(string[] args) { var host = BuildWebHost(args);host.Run();} //工具将使用此方法获取应用程序服务--公共静态.UseContentRoot(Directory.GetCurrentDirectory()) IWebHost BuildWebHost(string[] args) =>新WebHostBuilder() .UseKestrel() .UseKestrel .UseIISIntegration() .UseStartup() .Build();}
在旧的Main方法中替换它
public static void Main(string[] args)
{
var host = BuildWebHost(args)
.Seed();
host.Run();
}其中种子是一种扩展方法:
public static IWebHost Seed(this IWebHost webhost)
{
using (var scope = webhost.Services.GetService<IServiceScopeFactory>().CreateScope())
{
// alternatively resolve UserManager instead and pass that if only think you want to seed are the users
using (var dbContext = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>())
{
SeedData.SeedAsync(dbContext).GetAwaiter().GetResult();
}
}
}
public static class SeedData
{
public static async Task SeedAsync(ApplicationDbContext dbContext)
{
dbContext.Users.Add(new User { Id = 1, Username = "admin", PasswordHash = ... });
}
}旧的答案,仍然适用于ASP.NET核心1.x
对于如何在ASP.NET核心应用程序中应用实体框架核心,有一种半官方的模式,因为在应用程序启动期间没有请求,因此也没有RequestServices (解决范围内的服务)。
本质上,它归结为创建一个新的作用域,解析所需的类型,并在完成后再次释放该作用域。
// serviceProvider is app.ApplicationServices from Configure(IApplicationBuilder app) method
using (var serviceScope = serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
var db = serviceScope.ServiceProvider.GetService<AppDbContext>();
if (await db.Database.EnsureCreatedAsync())
{
await SeedDatabase(db);
}
}通过app.ApplicationServices.GetService<MyService>()直接解析服务的原因之一是,ApplicationServices是应用程序(或生存期)范围提供程序,而此处解析的服务在应用程序关闭之前一直处于活动状态。
通常,如果对象已经存在,作用域容器将从其父容器解析。因此,如果您在应用程序中以这种方式实例化DbContext,那么它将在ApplicationServices容器中可用,当请求发生时,将创建一个子容器。
现在解析DbContext时,它不会被解析为作用域,因为它已经存在于父容器中,因此将返回父容器的实例。但由于它已在播种期间处置,它将无法访问。
一个作用域容器就是一个寿命有限的单例容器。
因此,不要使用上面的模式解析应用程序启动w/o中的作用域服务,首先创建一个作用域并从中解析。
发布于 2017-05-09 17:44:33
只是猜测一下是什么导致了您的错误:
您正在使用DI和异步调用。如果调用堆栈中的某个位置返回了一个空值,而不是任务,那么您将得到所描述的行为。此时,调用结束,上下文被释放。因此,请检查是否有一个异步调用返回一个空而不是任务。如果更改返回值,则ObjectDisposedException可能是固定的。
public static class DataSeedExtensions {
private static IServiceProvider _provider;
public static async Task SeedData(this IApplicationBuilder builder) { //This line of code
_provider = builder.ApplicationServices;
_type = type;
using (Context context = (Context)_provider.GetService<Context>()) {
await context.Database.MigrateAsync();
// Insert data code
}
}在配置中:
if (hostingEnvironment.IsDevelopment()){
await applicationBuilder.SeedData();
}关于如何修复此错误的博客文章:注入ASP.NET时无法访问DbContext内核中已释放的对象
发布于 2018-02-18 05:14:59
我在使用asp.net内核时也遇到了类似的问题。我的控制器中有一个异步POST方法,当它返回when时,我将有这个异常。在我更改POST方法后,返回一个任务,问题就解决了。
更改如下:
public async void PostAsync([FromBody] Model yourmodel)至
public async Task PostAsync([FromBody] Model yourmodel)https://stackoverflow.com/questions/38704025
复制相似问题