Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

343
Views
No se puede consumir el servicio de ámbito 'MyDbContext' del singleton 'Microsoft.AspNetCore.Hosting.Internal.HostedServiceExecutor'

Creé una tarea en segundo plano en mi ASP.NET Core 2.1 siguiendo este tutorial: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-2.1# consumir-un-servicio-alcance-en-una-tarea-en-segundo plano

Al compilar me da error:

System.InvalidOperationException: 'No se puede consumir el servicio de ámbito 'MyDbContext' del singleton 'Microsoft.AspNetCore.Hosting.Internal.HostedServiceExecutor'.'

¿Qué causa ese error y cómo solucionarlo?

Tarea de fondo:

 internal class OnlineTaggerMS : IHostedService, IDisposable { private readonly CoordinatesHelper _coordinatesHelper; private Timer _timer; public IServiceProvider Services { get; } public OnlineTaggerMS(IServiceProvider services, CoordinatesHelper coordinatesHelper) { Services = services; _coordinatesHelper = coordinatesHelper; } public Task StartAsync(CancellationToken cancellationToken) { // Run every 30 sec _timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromSeconds(30)); return Task.CompletedTask; } private async void DoWork(object state) { using (var scope = Services.CreateScope()) { var dbContext = scope.ServiceProvider.GetRequiredService<MyDbContext>(); Console.WriteLine("Online tagger Service is Running"); // Run something await ProcessCoords(dbContext); } } public Task StopAsync(CancellationToken cancellationToken) { _timer?.Change(Timeout.Infinite, 0); return Task.CompletedTask; } private async Task ProcessCoords(MyDbContext dbContext) { var topCoords = await _coordinatesHelper.GetTopCoordinates(); foreach (var coord in topCoords) { var user = await dbContext.Users.SingleOrDefaultAsync(c => c.Id == coord.UserId); if (user != null) { var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); //expire time = 120 sec var coordTimeStamp = DateTimeOffset.FromUnixTimeMilliseconds(coord.TimeStamp).AddSeconds(120).ToUnixTimeMilliseconds(); if (coordTimeStamp < now && user.IsOnline == true) { user.IsOnline = false; await dbContext.SaveChangesAsync(); } else if (coordTimeStamp > now && user.IsOnline == false) { user.IsOnline = true; await dbContext.SaveChangesAsync(); } } } } public void Dispose() { _timer?.Dispose(); } }

Inicio.cs:

 services.AddHostedService<OnlineTaggerMS>();

Programa.cs:

 public class Program { 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<TutorDbContext>(); DbInitializer.Initialize(context); } catch(Exception ex) { var logger = services.GetRequiredService<ILogger<Program>>(); logger.LogError(ex, "An error occurred while seeding the database."); } } host.Run(); } public static IWebHost BuildWebHost(string[] args) => WebHost.CreateDefaultBuilder(args) .UseStartup<Startup>() .Build(); }

Inicio completo.cs:

 public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddCors(options => { options.AddPolicy("CorsPolicy", builder => builder.AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader() .AllowCredentials()); }); services.AddDbContext<MyDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); // ===== Add Identity ======== services.AddIdentity<User, IdentityRole>() .AddEntityFrameworkStores<TutorDbContext>() .AddDefaultTokenProviders(); JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); // => remove default claims services .AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(cfg => { cfg.RequireHttpsMetadata = false; cfg.SaveToken = true; cfg.TokenValidationParameters = new TokenValidationParameters { ValidIssuer = Configuration["JwtIssuer"], ValidAudience = Configuration["JwtIssuer"], IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JwtKey"])), ClockSkew = TimeSpan.Zero // remove delay of token when expire }; }); //return 401 instead of redirect services.ConfigureApplicationCookie(options => { options.Events.OnRedirectToLogin = context => { context.Response.StatusCode = 401; return Task.CompletedTask; }; options.Events.OnRedirectToAccessDenied = context => { context.Response.StatusCode = 401; return Task.CompletedTask; }; }); services.AddMvc(); services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new Info { Version = "v1", Title = "xyz", }); // Swagger 2.+ support var security = new Dictionary<string, IEnumerable<string>> { {"Bearer", new string[] { }}, }; c.AddSecurityDefinition("Bearer", new ApiKeyScheme { Description = "JWT Authorization header using the Bearer scheme. Example: \"Bearer {token}\"", Name = "Authorization", In = "header", Type = "apiKey" }); c.AddSecurityRequirement(security); }); services.AddHostedService<OnlineTaggerMS>(); services.AddTransient<UsersHelper, UsersHelper>(); services.AddTransient<CoordinatesHelper, CoordinatesHelper>(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IServiceProvider serviceProvider, IApplicationBuilder app, IHostingEnvironment env, TutorDbContext dbContext) { dbContext.Database.Migrate(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseCors("CorsPolicy"); app.UseAuthentication(); app.UseMvc(); app.UseSwagger(); app.UseSwaggerUI(c => { c.SwaggerEndpoint("v1/swagger.json", "xyz V1"); }); CreateRoles(serviceProvider).GetAwaiter().GetResult(); } private async Task CreateRoles(IServiceProvider serviceProvider) { var RoleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>(); var UserManager = serviceProvider.GetRequiredService<UserManager<User>>(); string[] roleNames = { "x", "y", "z", "a" }; IdentityResult roleResult; foreach (var roleName in roleNames) { var roleExist = await RoleManager.RoleExistsAsync(roleName); if (!roleExist) { roleResult = await RoleManager.CreateAsync(new IdentityRole(roleName)); } } var _user = await UserManager.FindByEmailAsync("xxx"); if (_user == null) { var poweruser = new User { UserName = "xxx", Email = "xxx", FirstName = "xxx", LastName = "xxx" }; string adminPassword = "xxx"; var createPowerUser = await UserManager.CreateAsync(poweruser, adminPassword); if (createPowerUser.Succeeded) { await UserManager.AddToRoleAsync(poweruser, "xxx"); } } }
over 4 years ago · Santiago Trujillo
5 answers
Answer question

0

Aún debe registrar MyDbContext con el proveedor de servicios. Por lo general, esto se hace así:

 services.AddDbContext<MyDbContext>(options => { // Your options here, usually: options.UseSqlServer("YourConnectionStringHere"); });

Si también publicó sus archivos Program.cs y Startup.cs, puede arrojar más luz sobre las cosas, ya que pude configurar rápidamente un proyecto de prueba implementando el código y no pude reproducir su problema.

over 4 years ago · Santiago Trujillo Report

0

Debe inyectar IServiceScopeFactory para generar un alcance. De lo contrario, no podrá resolver los servicios con ámbito en un singleton.

 using (var scope = serviceScopeFactory.CreateScope()) { var context = scope.ServiceProvider.GetService<MyDbContext>(); }

Editar: está perfectamente bien simplemente inyectar IServiceProvider y hacer lo siguiente:

 using (var scope = serviceProvider.CreateScope()) // this will use `IServiceScopeFactory` internally { var context = scope.ServiceProvider.GetService<MyDbContext>(); }

La segunda forma interna solo resuelve IServiceProviderScopeFactory y básicamente hace lo mismo.

over 4 years ago · Santiago Trujillo Report

0

Encontré la razón de un error. Era la clase CoordinatesHelper , que se usa en la tarea en segundo plano OnlineTaggerMS y es Transient , por lo que resultó con un error. No tengo idea de por qué el compilador seguía arrojando errores que apuntaban a MyDbContext , lo que me mantuvo fuera del camino durante unas horas.

over 4 years ago · Santiago Trujillo Report

0

Aunque la respuesta de @peace funcionó para él, si tiene un DBContext en su IHostedService , necesita usar un IServiceScopeFactory .

Para ver un ejemplo sorprendente de cómo hacer esto, consulte esta respuesta ¿Cómo debo inyectar una instancia de DbContext en un IHostedService? .

Si desea leer más sobre esto en un blog, consulte esto .

over 4 years ago · Santiago Trujillo Report

0

Para las clases de Entity Framework DbContext, ahora hay una mejor manera con:

 services.AddDbContextFactory<MyDbContext>(options => options.UseSqlServer(...))

Luego, puede inyectar la fábrica en su clase singleton de esta manera:

 IDbContextFactory<MyDbContext> myDbContextFactory

Y finalmente úsalo así:

 using var myDbContex = _myDbContextFactory.CreateDbContext();
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!