在下面的代码中,我在构造函数中定义了_serviceScope
变量。但是,当我在dbContext
上调用.SaveChanges()时,会导致空引用异常。
public class Seed
{
private readonly IServiceProvider _serviceProvider;
private IServiceScope _serviceScope;
public Seed(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
// define service scope in the constructor
_serviceScope = _serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope();
}
public async Task EventTypes()
{
string[] eventTypes = { "Copy", "Counter-Proposal" };
var dbContext = _serviceScope.ServiceProvider.GetService<ApplicationDbContext>();
foreach (string eventType in eventTypes)
{
if (!dbContext.EventTypes.Any(x => x.Name.ToUpperInvariant() == eventType.ToUpperInvariant()))
{
await dbContext.EventTypes.AddAsync(new EventType { Id = Guid.NewGuid(), Name = eventType });
// null reference exception occurs on this line...
dbContext.SaveChanges();
}
}
}
public async Task EventScheduleItemTypes()
{
string[] eventScheduleItemTypes = { "Orientation", "Event" };
var dbContext = _serviceScope.ServiceProvider.GetService<ApplicationDbContext>();
foreach (string eventScheduleItemType in eventScheduleItemTypes)
{
if (!dbContext.EventScheduleItemTypes.Any(x => x.Name.ToUpperInvariant() == eventScheduleItemType.ToUpperInvariant()))
{
await dbContext.EventScheduleItemTypes.AddAsync(new EventScheduleItemType { Id = Guid.NewGuid(), Name = eventScheduleItemType });
dbContext.SaveChanges();
}
}
}
}
相比之下,当我在EventTypes方法中定义变量时,代码运行时没有错误。 为什么不能在构造函数中定义_serviceScope
并在整个类中使用?是否与IServiceScope的处理方式有关?
公共类种子 { private readonly IServiceProvider _serviceProvider;
public Seed(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public async Task EventTypes()
{
string[] eventTypes = { "Copy", "Counter-Proposal" };
// define service scope in the method
var _serviceScope = _serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope();
var dbContext = _serviceScope.ServiceProvider.GetService<ApplicationDbContext>();
foreach (string eventType in eventTypes)
{
if (!dbContext.EventTypes.Any(x => x.Name.ToUpperInvariant() == eventType.ToUpperInvariant()))
{
await dbContext.EventTypes.AddAsync(new EventType { Id = Guid.NewGuid(), Name = eventType });
// no errors
dbContext.SaveChanges();
}
}
}
public async Task EventScheduleItemTypes()
{
string[] eventScheduleItemTypes = { "Orientation", "Event" };
// define service scope in the method
var _serviceScope = _serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope();
var dbContext = _serviceScope.ServiceProvider.GetService<ApplicationDbContext>();
foreach (string eventScheduleItemType in eventScheduleItemTypes)
{
if (!dbContext.EventScheduleItemTypes.Any(x => x.Name.ToUpperInvariant() == eventScheduleItemType.ToUpperInvariant()))
{
await dbContext.EventScheduleItemTypes.AddAsync(new EventScheduleItemType { Id = Guid.NewGuid(), Name = eventScheduleItemType });
// no errors
dbContext.SaveChanges();
}
}
}
}
为了完整性,我使用这样的类:
public async void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
...
var Seed = new Seed(app.ApplicationServices);
//await Seed.Roles();
//await Seed.Users();
await Seed.EventTypes();
await Seed.EventScheduleItemTypes();
}
堆栈追踪:
at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.System.IObserver<System.Collections.Generic.KeyValuePair<System.String,System.Object>>.OnNext(KeyValuePair`2 keyValuePair)
at System.Diagnostics.DiagnosticListener.Write(String name, Object value)
at Microsoft.EntityFrameworkCore.Internal.CoreLoggerExtensions.SaveChangesFailed(IDiagnosticsLogger`1 diagnostics, DbContext context, Exception exception)
at Microsoft.EntityFrameworkCore.DbContext.SaveChanges(Boolean acceptAllChangesOnSuccess)
at Microsoft.EntityFrameworkCore.DbContext.SaveChanges()
at ProjectX.Seed.<EventScheduleItemTypes>d__6.MoveNext() in C:\VSO\Source\Internal\Project X\ProjectX\Startup.cs:line 174
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at ProjectX.Startup.<Configure>d__5.MoveNext() in C:\VSO\Source\Internal\Project X\ProjectX\Startup.cs:line 87
编辑:当我将方法创建为静态并将每个方法传递给新范围时,它也有效。显然,它摆脱了这个范围而没有告诉任何人。有没有更好的方法,所以我不需要4个范围!?
await Seed.Roles(app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope().ServiceProvider.GetService<RoleManager<IdentityRole>>());
await Seed.Users(app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope().ServiceProvider.GetService<UserManager<ApplicationUser>>());
await Seed.EventTypes(app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope().ServiceProvider.GetService<ApplicationDbContext>());
await Seed.EventScheduleItemTypes(app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope().ServiceProvider.GetService<ApplicationDbContext>());
注意:我也尝试将方法包装在using语句中,但服务显然已经消失了。