为什么ServiceScope会导致空引用异常?

时间:2017-10-24 20:32:04

标签: c# entity-framework asp.net-core

在下面的代码中,我在构造函数中定义了_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语句中,但服务显然已经消失了。

0 个答案:

没有答案