ASP.NET 核心 2 种子数据库
ASP.NET Core 2 Seed Database
我已经在 SO 上看到了一些与此相关的类似示例,但我对这种语言的了解还不够,还看不出我做错了什么。我拼凑了一个演示以了解更多信息,但我在为数据库做种时遇到问题。
我收到以下错误:
InvalidOperationException: Cannot resolve scoped service 'demoApp.Models.AppDbContext' from root provider.
Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteValidator.ValidateResolution(Type serviceType, ServiceProvider serviceProvider)
这是有问题的三个文件:
Models/AppDbContext.cs
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
{
}
public DbSet<Product> Products{ get; set; }
public DbSet<Category> Categories { get; set; }
}
Models/DBInitializer.cs
public static class DbInitializer
{
public static void Seed(IApplicationBuilder applicationBuilder)
{
//I'm bombing here
AppDbContext context = applicationBuilder.ApplicationServices.GetRequiredService<AppDbContext>();
if (!context.Products.Any())
{
// Add range of products
}
context.SaveChanges();
}
private static Dictionary<string, Category> _categories;
public static Dictionary<string, Category> Categories
{
get
{
if (_categories == null)
{
// Add categories...
}
return _categories;
}
}
}
Startup.cs
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<ICategoryRepository, CategoryRepository>();
services.AddTransient<IProductRepository, ProductRepository>();
services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
app.UseStatusCodePages();
// Kersplat!
DbInitializer.Seed(app);
}
else ...
app.UseStaticFiles();
app.UseMvc(routes => {...});
}
有人可以帮助解释我做错了什么以及如何补救吗?
根据原始答案更新:
对于 .NET Core 2.0,请改为查看
原答案:
我也不是 .NET Core 专家,但这可能是您的解决方案。
在DBInitializer.cs
public static void Seed(IApplicationBuilder applicationBuilder)
{
using (var serviceScope = applicationBuilder.ApplicationServices.GetRequiredService<IServiceScopeFactory>()
.CreateScope())
{
AppDbContext context = serviceScope.ServiceProvider.GetService<AppDbContext>();
if (!context.Products.Any())
{
// Seed Here
}
context.SaveChanges();
}
}
错误表明上下文应该是范围内的。
此外,如果您还没有这样做,我会看一下 Introduction to Dependency Injection in ASP.NET Core doc, but more specifically, the Service Lifetimes and Registration Options 部分。
在 ASP.NET Core 2.0 中,建议进行以下更改。 (在 startup.cs 中播种适用于核心 1.x。对于 2.0 进入 Program.cs,修改 Main 方法以在应用程序启动时执行以下操作:
从依赖注入容器中获取数据库上下文实例。
调用 seed 方法,将上下文传递给它。
seed 方法完成后释放上下文。
(这是来自 Microsoft 站点的示例。https://docs.microsoft.com/en-us/aspnet/core/data/ef-mvc/intro )
public static void Main(string[] args)
{
var host = BuildWebHost(args);
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
var context = services.GetRequiredService<yourDBContext>();
DbInitializer.Seed(context);//<---Do your seeding here
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred while seeding the database.");
}
}
host.Run();
}
我已经在 SO 上看到了一些与此相关的类似示例,但我对这种语言的了解还不够,还看不出我做错了什么。我拼凑了一个演示以了解更多信息,但我在为数据库做种时遇到问题。
我收到以下错误:
InvalidOperationException: Cannot resolve scoped service 'demoApp.Models.AppDbContext' from root provider.
Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteValidator.ValidateResolution(Type serviceType, ServiceProvider serviceProvider)
这是有问题的三个文件:
Models/AppDbContext.cs
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
{
}
public DbSet<Product> Products{ get; set; }
public DbSet<Category> Categories { get; set; }
}
Models/DBInitializer.cs
public static class DbInitializer
{
public static void Seed(IApplicationBuilder applicationBuilder)
{
//I'm bombing here
AppDbContext context = applicationBuilder.ApplicationServices.GetRequiredService<AppDbContext>();
if (!context.Products.Any())
{
// Add range of products
}
context.SaveChanges();
}
private static Dictionary<string, Category> _categories;
public static Dictionary<string, Category> Categories
{
get
{
if (_categories == null)
{
// Add categories...
}
return _categories;
}
}
}
Startup.cs
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<ICategoryRepository, CategoryRepository>();
services.AddTransient<IProductRepository, ProductRepository>();
services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
app.UseStatusCodePages();
// Kersplat!
DbInitializer.Seed(app);
}
else ...
app.UseStaticFiles();
app.UseMvc(routes => {...});
}
有人可以帮助解释我做错了什么以及如何补救吗?
根据原始答案更新:
对于 .NET Core 2.0,请改为查看
原答案:
我也不是 .NET Core 专家,但这可能是您的解决方案。
在DBInitializer.cs
public static void Seed(IApplicationBuilder applicationBuilder)
{
using (var serviceScope = applicationBuilder.ApplicationServices.GetRequiredService<IServiceScopeFactory>()
.CreateScope())
{
AppDbContext context = serviceScope.ServiceProvider.GetService<AppDbContext>();
if (!context.Products.Any())
{
// Seed Here
}
context.SaveChanges();
}
}
错误表明上下文应该是范围内的。
此外,如果您还没有这样做,我会看一下 Introduction to Dependency Injection in ASP.NET Core doc, but more specifically, the Service Lifetimes and Registration Options 部分。
在 ASP.NET Core 2.0 中,建议进行以下更改。 (在 startup.cs 中播种适用于核心 1.x。对于 2.0 进入 Program.cs,修改 Main 方法以在应用程序启动时执行以下操作: 从依赖注入容器中获取数据库上下文实例。 调用 seed 方法,将上下文传递给它。 seed 方法完成后释放上下文。 (这是来自 Microsoft 站点的示例。https://docs.microsoft.com/en-us/aspnet/core/data/ef-mvc/intro )
public static void Main(string[] args)
{
var host = BuildWebHost(args);
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
var context = services.GetRequiredService<yourDBContext>();
DbInitializer.Seed(context);//<---Do your seeding here
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred while seeding the database.");
}
}
host.Run();
}