EF 7 (Core). Crear DBContext como AddTransient

asp.net-core asp.net-core-mvc c# entity-framework-core

Pregunta

De acuerdo con los documentos cuando configuro DbContext como abajo, DI lo registra en el alcance (por solicitud http)

services.AddEntityFramework()
   .AddSqlServer()
   .AddDbContext<DBData>(options => {
        options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]);                    
    }
);

El problema aparece cuando intento acceder a él en otro hilo.

public class HomeController : Controller
{
    private readonly DBData _context;

    public HomeController(DBData context)
    {
        _context = context;
    }

    public IActionResult StartInBackground()
    {
        Task.Run(() =>
            {
                Thread.Sleep(3000);
                //System.ObjectDisposedException here
                var res = _context.Users.FirstOrDefault(x => x.Id == 1);
            });

        return View();
    }
}

Quiero configurar la creación de DbContext para cada llamada (AddTransition). Me daría la posibilidad de escribir el siguiente código.

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddEntityFramework()
            .AddSqlServer()
            .AddDbContext<DBData>(options => {
                //somehow configure it to use AddTransient
                options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]);                    
                }
            );

        services.AddTransient<IUnitOfWorkFactoryPerCall, UnitOfWorkFactory>();
        services.AddScoped<IUnitOfWorkFactoryPerRequest, UnitOfWorkFactory>();

        services.AddMvc();
    }

    public interface IUnitOfWorkFactoryPerCall : IUnitOfWorkFactory { }
    public interface IUnitOfWorkFactoryPerRequest : IUnitOfWorkFactory { }

    public interface IUnitOfWorkFactory : IDisposable
    {
       DBData Context { get; }
    }

    public class UnitOfWorkFactory : IUnitOfWorkFactoryPerCall, IUnitOfWorkFactoryPerRequest
    {
        public UnitOfWorkFactory(DBData context)
        {
            Context = context;
        }

        public DBData Context
        {
            get; private set;
        }

        public void Dispose()
        {
            Context.Dispose();
        }
    }

Así que ahora, si quiero crear DBContext por solicitud, IUnitOfWorkFactoryPerRequest , y cuando quiera usar DBContext en algún hilo de fondo, puedo usar IUnitOfWorkFactoryPerCall .

Respuesta aceptada

Mi solución temporal. Creé Singleton que puede crear Contexto "de manera transitoria"

public class AppDependencyResolver
{
    private static AppDependencyResolver _resolver;

    public static AppDependencyResolver Current
    {
        get
        {
            if (_resolver == null)
                throw new Exception("AppDependencyResolver not initialized. You should initialize it in Startup class");
            return _resolver;
        }
    }

    public static void Init(IServiceProvider services)
    {
        _resolver = new AppDependencyResolver(services);
    }

    private readonly IServiceProvider _serviceProvider;

    public AppDependencyResolver(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public IUnitOfWorkFactory CreateUoWinCurrentThread()
    {
        var scopeResolver = _serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope();
        return new UnitOfWorkFactory(scopeResolver.ServiceProvider.GetRequiredService<DBData>(), scopeResolver);
    }
}

Entonces llamo al método de inicio en el método de configuración de inicio

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    AppDependencyResolver.Init(app.ApplicationServices);
    //other configure code
}

Y, después de todo, puedo llamar a AppDependencyResolver.Current.CreateUoWinCurrentThread() en algún hilo de fondo.

Si alguien puede proporcionar una solución más elegante seré apreciado.



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué