【问题标题】:ObjectDisposedException on a ASP.NET Core 2.0 MVC custom database initializer classASP.NET Core 2.0 MVC 自定义数据库初始化程序类上的 ObjectDisposedException
【发布时间】:2018-02-18 06:48:16
【问题描述】:

我的自定义数据库初始化程序类中出现以下异常:

System.ObjectDisposedException 发生 HResult=0x80131622
Message=无法访问已处置的对象。此错误的常见原因 正在处理从依赖注入解决的上下文,并且 然后稍后尝试在您的其他地方使用相同的上下文实例 应用。如果您在 上下文,或将上下文包装在 using 语句中。如果你是 使用依赖注入,你应该让依赖注入 容器负责处理上下文实例。来源= StackTrace:在 Microsoft.EntityFrameworkCore.DbContext.CheckDisposed() 在 Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider() 在 Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies() 在 Microsoft.EntityFrameworkCore.DbContext.d__48.MoveNext() 在 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore9.<CreateAsync>d__22.MoveNext() at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter
1.GetResult() 在 Microsoft.AspNetCore.Identity.UserManager1.<CreateAsync>d__73.MoveNext() at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter
1.GetResult() 在 Microsoft.AspNetCore.Identity.UserManager1.<CreateAsync>d__78.MoveNext() at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter1.GetResult() 在 E:\C# 中的 LlabApp.Data.DbInitializer.d__4.MoveNext() 项目\Atenea\LlabApp\LlabApp\LlabApp\Data\DbInitializer.cs:58 行

这里是初始化器:

public class DbInitializer : IDbInitializer
{
    private readonly ApplicationDbContext _Context;
    private readonly UserManager<ApplicationUser> _userManager;
    private readonly RoleManager<ApplicationRole> _roleManager;

    public DbInitializer(
        ApplicationDbContext context,
        UserManager<ApplicationUser> userManager,
        RoleManager<ApplicationRole> roleManager)
    {
        _context = context;
        _userManager = userManager;
        _roleManager = roleManager;
    }

    public async void Initialize()
    {
        var adminUsers = _userManager.GetUsersInRoleAsync(RoleClaimValues.Admin).Result;
        if (adminUsers == null || adminUsers.Count == 0)
        {
(...)
        }
     }
}

public interface IDbInitializer
{
    void Initialize();
}

这里是startup.cs,我在ConfigureService 中添加IDbInitializer 的范围,然后从Configure 调用它:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }


    public void ConfigureServices(IServiceCollection services)
    {
        // Add framework services.
        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(Configuration.GetConnectionString("ApplicationConnection")));

        services.AddIdentity<ApplicationUser, ApplicationRole>(o => {
            o.Password.RequireDigit = false;
            o.Password.RequiredLength = 4;
            o.Password.RequireLowercase = false;
            o.Password.RequireUppercase = false;
            o.Password.RequireNonAlphanumeric = false;
            o.User.RequireUniqueEmail = true;
        })
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders();

        services.AddMvc();

        // Add application services.
        services.AddTransient<IEmailSender, MessageServices>();
        //Seed database
        services.AddScoped<IDbInitializer, DbInitializer>();
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IDbInitializer dbInitializer)
    {
        loggerFactory.AddConsole();

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();

            app.UseBrowserLink();
            app.UseDatabaseErrorPage();

            app.UseStatusCodePages("text/plain", "Status code page, status code: {0}");
        }
        else
        {
            app.UseExceptionHandler("/Error");
        }

        app.UseStaticFiles();
        app.UseAuthentication();

        dbInitializer.Initialize();

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });
    }
}

我不知道为什么异常表明问题可能是上下文被放置在某个地方。

我也加了

.UseDefaultServiceProvider(options =>
  options.ValidateScopes = false)

.UseStartup&lt;Startup&gt;() 之后,以防万一它与范围相关,但例外是相同的。

【问题讨论】:

    标签: c# asp.net-core-2.0


    【解决方案1】:

    我遇到了和你一样的问题。 您确实必须更改所有代码以返回Task。否则,DbContext 在所有操作完成之前被释放。

    在 dotnet core 2.0 中更改了数据库初始化。我创建了一个关于这个特定主题的博客。 请参阅http://www.locktar.nl/programming/net-core/seed-database-users-roles-dotnet-core-2-0-ef/ 了解更多信息。

    【讨论】:

      【解决方案2】:

      好的,问题出在这一行:

      public async void Initialize()
      

      因为它是一个异步方法,它内部有 await,但因为它是 void,所以 ServiceProvider 在到达第一个 await 后处理依赖项,并在从启动返回方法调用并继续执行时离开上下文。

      因此,解决方案是将DbInitializerIDbInitializer处的void更改为Task,然后在startap中转换dbInitializer参数并等待它完成:

      ((DbInitializer)dbInitializer).Initialize().Wait();
      

      当然,调用异步方法然后等待它们全部完成并不是很有用,但我不知道是否可以将Configure方法设置为异步方法......所以这就是解决方案我发现并且因为它只是用于在开发环境中播种数据库,我对此很满意。

      任何进一步的建议将不胜感激。

      【讨论】:

        猜你喜欢
        • 2018-05-16
        • 1970-01-01
        • 2016-08-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-09-27
        • 2017-11-16
        • 2020-03-29
        相关资源
        最近更新 更多