You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET MVC中混用注入DbContext与Startup.Auth创建的DbContext技术问询

解决ASP.NET MVC中同时使用DI注入的DbContext与Owin的DbContext的问题

嘿,这个问题我之前也碰到过!核心是要让Owin上下文里的DbContext和你通过DI注入的DbContext共享同一个实例——默认情况下,CreatePerOwinContext会为每个Owin请求单独创建DbContext实例,而DI注入的Scoped实例是另一个,这会导致同一个请求里两个上下文跟踪同一实体,引发状态异常或者保存失败。下面给你具体的实现方案:

步骤1:在DI容器中配置DbContext和UserManager

首先在Startup.cs的ConfigureServices方法里,把ApplicationDbContext和ApplicationUserManager注册为Scoped(每个请求一个实例),确保DI容器统一管理它们的生命周期:

public void ConfigureServices(IServiceCollection services)
{
    // 配置DbContext为Scoped生命周期
    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")),
        ServiceLifetime.Scoped);

    // 注册ApplicationUserManager,依赖DI提供的DbContext
    services.AddScoped<ApplicationUserManager>(provider =>
    {
        var userStore = new UserStore<ApplicationUser>(provider.GetRequiredService<ApplicationDbContext>());
        var userManager = new ApplicationUserManager(userStore);

        // 这里可以添加你的UserManager自定义配置,比如密码规则、用户验证逻辑
        userManager.UserValidator = new UserValidator<ApplicationUser>(userManager)
        {
            AllowOnlyAlphanumericUserNames = false,
            RequireUniqueEmail = true
        };

        userManager.PasswordValidator = new PasswordValidator
        {
            RequiredLength = 6,
            RequireNonLetterOrDigit = true,
            RequireDigit = true,
            RequireLowercase = true,
            RequireUppercase = true,
        };

        return userManager;
    });

    // 其他MVC相关配置
    services.AddControllersWithViews();
}

步骤2:修改ConfigureAuth方法,从DI获取实例

接下来在Startup.Auth.cs的ConfigureAuth方法里,不再用默认的CreatePerOwinContext来创建DbContext和UserManager,而是从DI容器中获取已经注册好的Scoped实例:

public void ConfigureAuth(IAppBuilder app)
{
    // 获取DI的服务提供者
    var serviceProvider = app.GetApplicationServices();

    // 替换默认的DbContext创建逻辑,使用DI中的实例
    app.CreatePerOwinContext(() => serviceProvider.GetRequiredService<ApplicationDbContext>());

    // 同样,使用DI中的ApplicationUserManager实例
    app.CreatePerOwinContext(() => serviceProvider.GetRequiredService<ApplicationUserManager>());

    // 继续保留你的身份验证配置,比如Cookie认证
    app.UseCookieAuthentication(new CookieAuthenticationOptions
    {
        AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
        LoginPath = new PathString("/Account/Login"),
        Provider = new CookieAuthenticationProvider
        {
            OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                validateInterval: TimeSpan.FromMinutes(30),
                regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
        }
    });
}

为什么这样有效?

通过这种方式,Owin上下文里的ApplicationDbContext和ApplicationUserManager,与你在Controller中通过构造函数注入的ApplicationDbContext,都是同一个请求内的同一个实例,完美解决了上下文冲突的问题。

如果你用的是第三方DI容器(比如Autofac、Unity),思路也是一样的:先在容器中注册DbContext和UserManager为PerRequest生命周期,然后让Owin从容器中解析这些实例即可。

内容的提问来源于stack exchange,提问作者Hooman Bahreini

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:33:20