首页 > 解决方案 > ASP.NET Core InvalidOperationException:尝试激活 UserStore 时无法解析 DbContext 类型的服务

问题描述

我在使用 IdentityDbContext 的应用程序中有这个 DbContext

public class ShopDbContext : IdentityDbContext<User>, IDisposable
    {


        public ShopDbContext(DbContextOptions options): base(options)
        {            
            Products = base.Set<Product>();
            Categories = base.Set<Category>();
            Shops = base.Set<Shop>();
            Properties = base.Set<Property>();
            Orders = base.Set<Order>();
            OrderItems = base.Set<OrderItem>();
            Customers = base.Set<Customer>();
            Carts = base.Set<Cart>();
            CartItems = base.Set<CartItem>();
            UserShops = base.Set<UserShop>();
            Images = base.Set<Image>();

        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            // Use singular table names
            modelBuilder.ApplyConfiguration<Product>(new ProductConfiguration());
            modelBuilder.ApplyConfiguration<Category>(new CategoryConfiguration());
            modelBuilder.ApplyConfiguration<Shop>(new ShopConfiguration());
            modelBuilder.ApplyConfiguration<Property>(new PropertyConfiguration());
            modelBuilder.ApplyConfiguration<Order>(new OrderConfiguration());
            modelBuilder.ApplyConfiguration<OrderItem>(new OrderItemConfiguration());
            modelBuilder.ApplyConfiguration<Customer>(new CustomerConfiguration());
            modelBuilder.ApplyConfiguration<Cart>(new CartConfiguration());
            modelBuilder.ApplyConfiguration<CartItem>(new CartItemConfiguration());
            modelBuilder.ApplyConfiguration<UserShop>(new UserShopConfiguration());
            modelBuilder.ApplyConfiguration<Image>(new ImageConfiguration());
        }

        public DbSet<Shop> Shops { get; set; }
        public DbSet<Category> Categories { get; set; }
        public DbSet<Product> Products { get; set; }
        public DbSet<Property> Properties { get; set; }
        public DbSet<Order> Orders { get; set; }
        public DbSet<OrderItem> OrderItems { get; set; }
        public DbSet<Customer> Customers { get; set; }
        public DbSet<Cart> Carts { get; set; }
        public DbSet<CartItem> CartItems { get; set; }
        public DbSet<UserShop> UserShops { get; set; }
        public DbSet<Image> Images { get; set; }

    }

这是我的用户模型:

public class User : IdentityUser
    {
        public string Name { get; set; }
        public string LastName { get; set; }
        public string MobilePhone { get; set; }
        public string Address { get; set; }
        public Guid ImageId { get; set; }
        public Guid ShopId { get; set; }
        public DateTime LastActive { get; set; }
        public List<UserShop> UserShopList { get; set; }
        public bool HasImage()
        {
            return Guid.Empty != ImageId;
        }
    }

启动代码如下:

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

    public IConfiguration Configuration { get; }
    public IServiceProvider ServiceProvider { get; set; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {

        services.AddDbContextFactory<ShopDbContext>(builder => 
            builder.UseSqlServer("DefaultConnection"));
        services.AddIdentity<User, IdentityRole>()
            .AddEntityFrameworkStores<ShopDbContext>()
            .AddDefaultTokenProviders();
        services.AddSqlServerDbContextFactory<ShopDbContext>();
        services.AddScoped<IShopEFRepository, EFRepository<ShopDbContext>>();

        Shop.Core.Configure.Configure.ConfigureServices(services);
        services.AddScoped<IUpdateService, UpdateService>();
        //services.AddSingleton<IBotService, BotService>();

        services.AddHttpContextAccessor();

        ServiceProvider = services.BuildServiceProvider();


        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
        services.AddCors();

        services.AddAuthentication(options => {
            options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
        })
            .AddJwtBearer(options =>
            {
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII
                        .GetBytes(Configuration.GetSection("AppSettings:Token").Value)),
                    ValidateIssuer = false,
                    ValidateAudience = false,
                    ValidateLifetime = true,
                    ClockSkew = TimeSpan.Zero //the default for this setting is 5 minutes
                };
                options.Events = new JwtBearerEvents
                {
                    OnAuthenticationFailed = context =>
                    {
                        if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
                        {
                            context.Response.Headers.Add("Token-Expired", "true");
                        }
                        return Task.CompletedTask;
                    }
                };
            });

        services.AddAuthorization(options =>
        {
            options.AddPolicy("RequireAdminRole", policy => policy.RequireRole("Admin"));
            options.AddPolicy("User", policy => policy.RequireRole("User"));
            options.AddPolicy("ShopManager", policy => policy.RequireRole("Manager"));
            options.AddPolicy("DeviceRole", policy => policy.RequireRole("Device"));
            options.AddPolicy("OwnerRole", policy => policy.RequireRole("Owner"));
        });

        services.AddMvc(options =>
        {
            var policy = new AuthorizationPolicyBuilder()
                .RequireAuthenticatedUser()
                .Build();
            options.Filters.Add(new AuthorizeFilter(policy));
        })
            .SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
            .AddJsonOptions(opt =>
            {
                opt.SerializerSettings.ReferenceLoopHandling =
                    Newtonsoft.Json.ReferenceLoopHandling.Ignore;
            });
        //services.AddCors();            
        Mapper.Reset();
        services.AddAutoMapper(typeof(Startup));


    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
       // loggerFactory.AddMongoFramework<InfoLog>(ServiceProvider);
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler(builder =>
            {
                builder.Run(async context =>
                {
                    context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;

                    var error = context.Features.Get<IExceptionHandlerFeature>();
                    if (error != null)
                    {
                        context.Response.AddApplicationError(error.Error.Message);
                        await context.Response.WriteAsync(error.Error.Message);
                    }
                });
            });
        }

        app.UseCors(x => x.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod());
        app.UseAuthentication();
        app.UseMvc();
    }
}

此外,我将EFCore.DbContextFactory用于我的通用存储库。当我尝试构建数据库时,出现异常:

InvalidOperationException: Unable to resolve service for type
        Shop.SQLData.ShopDbContext while attempting to activate
        Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore Shop.SqlModel.User,Microsoft.AspNetCore.Identity.IdentityRole,Shop.SQLData.ShopDbContext,System.String,Microsoft.AspNetCore.Identity.IdentityUserClaim`1[System.String],Microsoft.AspNetCore.Identity.IdentityUserRole`1[System.String],Microsoft.AspNetCore.Identity.IdentityUserLogin`1[System.String],Microsoft.AspNetCore.Identity.IdentityUserToken`1[System.String],Microsoft.AspNetCore.Identity.IdentityRoleClaim`1[System.String]].

我认为问题出在我设置 DbContextFactory 的方式上,但是当我按照随附的示例进行操作时,我采用了相同的方法。

此外,我的连接字符串是:

"ConnectionStrings": {
    "DefaultConnection": "User ID=sa; Password=123456;Server=.\\sqlexpress;Database=ShopDb;"
  } 

当我尝试使用 Package Manager update-database 生成数据库时,出现此错误:

Format of the initialization string does not conform to specification starting at index 0.

标签: c#asp.net-coreentity-framework-coredbcontext

解决方案


 public ShopDbContext(DbContextOptions options): base(options)

试试改成这个

 public ShopDbContext(DbContextOptions<ShopDbContext> options): base(options)

并改变它

 services.AddDbContextFactory<ShopDbContext>(builder => 
            builder.UseSqlServer("DefaultConnection"));

对此

string connectionString = Configuration.GetConnectionString("DefaultConnection");
services.AddDbContextFactory<DbContext,ShopDbContext>(builder => 
            builder.UseSqlServer(connectionString));

推荐阅读