¿Cómo debo inyectar (usando la inyección de dependencia estándar) una instancia de DbContext en un IHostedService ?
Actualmente, mi clase IHostedService toma una instancia de MainContext (derivada de DbContext ) en el constructor.
Cuando ejecuto la aplicación me sale:
No se puede consumir el servicio de ámbito 'Microsoft.EntityFrameworkCore.DbContextOptions' del singleton 'Microsoft.Extensions.Hosting.IHostedService'.
Así que traté de hacer que DbContextOptions transitorio especificando:
services.AddDbContext<MainContext>(options => options.UseSqlite("Data Source=development.db"), ServiceLifetime.Transient); en mi clase de Startup .
Pero el error sigue siendo el mismo, aunque, de acuerdo con este problema resuelto de Github, las DbContextOptions pasadas deberían tener el mismo tiempo de vida especificado en la llamada AddDbContext .
No puedo hacer que el contexto de la base de datos sea un singleton; de lo contrario, las llamadas simultáneas generarían excepciones de concurrencia (debido al hecho de que no se garantiza que el contexto de la base de datos sea seguro para subprocesos).
Una buena forma de usar servicios dentro de servicios alojados es crear un alcance cuando sea necesario. Esto permite usar servicios/contextos de base de datos, etc. con la configuración de por vida con la que están configurados. En teoría, no crear un ámbito podría dar lugar a la creación de DbContexts únicos y a la reutilización inadecuada del contexto (EF Core 2.0 con grupos de DbContext).
Para hacer esto, inyecte un IServiceScopeFactory y utilícelo para crear un alcance cuando sea necesario. A continuación, resuelva las dependencias que necesite de este ámbito. Esto también le permite registrar servicios personalizados como dependencias con ámbito en caso de que desee mover la lógica fuera del servicio alojado y utilizar el servicio alojado solo para desencadenar algún trabajo (por ejemplo, desencadenar una tarea con regularidad; esto crearía ámbitos con regularidad, crearía el servicio de tareas en este alcance que también recibe un contexto db inyectado).
public class MyHostedService : IHostedService { private readonly IServiceScopeFactory scopeFactory; public MyHostedService(IServiceScopeFactory scopeFactory) { this.scopeFactory = scopeFactory; } public void DoWork() { using (var scope = scopeFactory.CreateScope()) { var dbContext = scope.ServiceProvider.GetRequiredService<MyDbContext>(); … } } … }Puede agregar crear Scope en el constructor de la siguiente manera:
public ServiceBusQueueListner(ILogger<ServiceBusQueueListner> logger, IServiceProvider serviceProvider, IConfiguration configuration) { _logger = logger; _reportProcessor = serviceProvider.CreateScope().ServiceProvider.GetRequiredService<IReportProcessor>(); _configuration = configuration; }agregar
using Microsoft.Extensions.DependencyInjection;