我已经在我的ASP中构建了一个后台任务.本教程之后的NET Core 2.1:https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-2.1#consuming-a-scoped-service-in-a-background-task

编译给了我一个错误:

系统InvalidOperationException:"无法使用singleton"Microsoft提供的作用域服务"MyDbContext".AspNetCore.群众或部队的集合.内部的HostedServiceExecutor''

是什么导致了这个错误,以及如何修复它?

背景任务:

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();
    }
}

创业.反恐精英:

services.AddHostedService<OnlineTaggerMS>();

程序反恐精英:

 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();
}

完整的启动.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");
            }
        }
    }

推荐答案

我找到了出错的原因.它是CoordinatesHelper类,在后台任务OnlineTaggerMS中使用,并且是Transient-因此导致错误.我不知道为什么编译器不断抛出指向MyDbContext的错误,让我偏离了几个小时的轨道.

Asp.net相关问答推荐

Razor 页面客户端站点验证不起作用

什么是 SNIReadSyncOverAsync,为什么需要很长时间才能完成?

WebResource.axd 上的填充无效且无法删除异常

在每个对象上设置 ClientIDMode = Static 是否有任何缺点(在母版页的 maincontent 上设置)

Firefox 和 Chrome 之间 1 像素的行高差

httpCompression 和 urlCompression 有什么区别?

如何防止 Azure 网站进入Hibernate 状态?

测试项目中的 App.config

在控制器 asp.net mvc 5 的视图上显示错误消息

ASP.NET MVC4 jquery/javascript 包的使用

如何在页面的基类中执行 Page_Load()?

c# - 如何从列表中获取值的总和?

解析器错误:无法创建类型

我的 asp.net mvc Web 应用程序中的 OutputCache 设置.防止缓存的多种语法

缩小 ASP.Net MVC 应用程序的 HTML 输出

OWIN 和 Katana,为什么要将应用程序与服务器解耦?

IIS - 无法通过 ip 地址而不是 localhost 访问页面

在后面的代码中删除 css 类

如何从 ASP.NET Identity 获取用户列表?

ASP.NET 5 (vNext) - 获取配置设置