无法从单例使用作用域服务 [英] Cannot consume scoped service from singleton

查看:569
本文介绍了无法从单例使用作用域服务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在托管服务中使用DBContext,但收到此错误. 我试图遵循接受的答案,但某种程度上它不起作用,我不确定我在做什么错.

I'm trying to use DBContext in Hosted services but getting this error. I tried to follow this accepted answer but somehow its not working, I'm not sure what I'm doing wrong.

我是.net的新手,请引导我正确的方向.

I'm new to .net please guide me into right direction.

未处理的异常:System.InvalidOperationException:无法使用 单例的作用域服务'StatusApp.Context.DBContext' "Microsoft.AspNetCore.Hosting.Internal.HostedServiceExecutor".

Unhandled Exception: System.InvalidOperationException: Cannot consume scoped service 'StatusApp.Context.DBContext' from singleton 'Microsoft.AspNetCore.Hosting.Internal.HostedServiceExecutor'.

public class TokenService : IHostedService
{
    public IConfiguration _Configuration { get; }
    protected IMemoryCache _cache;
    private Timer _timer;
    public IHttpClientFactory _clientFactory;
    public DBContext _DBcontext;

    private readonly IServiceScopeFactory _scopeFactory;

    public TokenService(IConfiguration configuration, IMemoryCache memoryCache, IHttpClientFactory clientFactory, DBContext DBcontext, IServiceScopeFactory scopeFactory)
    {
        _Configuration = configuration;
        _cache = memoryCache;
        _clientFactory = clientFactory;
        _scopeFactory = scopeFactory;
        _DBcontext = _scopeFactory.CreateScope().ServiceProvider.GetRequiredService<DBcontext>();
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _timer = new Timer(getOrg, null, 0, 1000);
        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        //Timer does not have a stop. 
        _timer?.Change(Timeout.Infinite, 0);
        return Task.CompletedTask;
    }

    public async Task getOrg()
    {
        var request = new HttpRequestMessage(HttpMethod.Get, "organizations");
        var response = await _client_NP.SendAsync(request);
        var json = await response.Content.ReadAsStringAsync();
        OrganizationsClass.OrgsRootObject model = JsonConvert.DeserializeObject<OrganizationsClass.OrgsRootObject>(json);

        foreach (var item in model.resources)
        {
            var g = Guid.Parse(item.guid);
            var x = _DBcontext.Organizations.FirstOrDefault(o => o.OrgGuid == g);
            if (x == null)
            {
                _DBcontext.Organizations.Add(new Organizations
                {
                    OrgGuid = g,
                    Name = item.name,
                    CreatedAt = item.created_at,
                    UpdatedAt = item.updated_at,
                    Timestamp = DateTime.Now,
                    Foundation = 3
                });
            }
            else if (x.UpdatedAt != item.updated_at)
            {
                x.CreatedAt = item.created_at;
                x.UpdatedAt = item.updated_at;
                x.Timestamp = DateTime.Now;
            }
        }

        await _DBcontext.SaveChangesAsync();
    }
}

推荐答案

您已经差不多了,但是您已经将DBContext作为依赖项保留在TokenService的构造函数中.删除它,您将不再收到错误.

You're almost there, but you've left DBContext as a dependency in TokenService's constructor. Remove that and you'll no longer receive the error.


public TokenService(
    IConfiguration configuration,
    IMemoryCache memoryCache,
    IHttpClientFactory clientFactory,
    DBContext DBcontext,
    IServiceScopeFactory scopeFactory)

但是,您不太遵循有关在单例服务中处理DbContext的建议.无需在构造函数中创建DBContext的单个实例并将其存储为字段,而是在需要时创建范围和相应的DBContext.您的情况就是在getOrg方法中.

However, you're not quite following the recommendation for dealing with DbContext's in a singleton service. Instead of creating a single instance of DBContext in the constructor and storing it as a field, create a scope and a corresponding DBContext whenever you need it. In your case, that's in the getOrg method.

请按照以下步骤操作:

  1. 从您的TokenService类中删除_DBcontext字段:

public DBContext _DBcontext;

TokenService构造函数中删除关联的分配:

Remove the associated assignment from the TokenService constructor:

_DBcontext = _scopeFactory.CreateScope().ServiceProvider.GetRequiredService<DBcontext>();

getOrg中,创建作用域,解析DBContext的实例,最后处置该作用域:

In getOrg, create a scope, resolve an instance of DBContext and, lastly, dispose of the scope:

public async Task getOrg()
{
    var request = new HttpRequestMessage(HttpMethod.Get, "organizations");
    var response = await _client_NP.SendAsync(request);
    var json = await response.Content.ReadAsStringAsync();
    OrganizationsClass.OrgsRootObject model = JsonConvert.DeserializeObject<OrganizationsClass.OrgsRootObject>(json);

    using (var scope = _scopeFactory.CreateScope())
    {
        var dbContext = scope.ServiceProvider.GetRequiredService<DBcontext>();

        foreach (var item in model.resources)
        {
            var g = Guid.Parse(item.guid);
            var x = dbContext.Organizations.FirstOrDefault(o => o.OrgGuid == g);
            if (x == null)
            {
                dbContext.Organizations.Add(new Organizations
                {
                    OrgGuid = g,
                    Name = item.name,
                    CreatedAt = item.created_at,
                    UpdatedAt = item.updated_at,
                    Timestamp = DateTime.Now,
                    Foundation = 3
                });
            }
            else if (x.UpdatedAt != item.updated_at)
            {
                x.CreatedAt = item.created_at;
                x.UpdatedAt = item.updated_at;
                x.Timestamp = DateTime.Now;
            }
        }

        await dbContext.SaveChangesAsync();
    }
}

上面的代码没有使用_DBContext字段,而是创建了一个适当范围的局部变量dbContext并使用了该变量.

Instead of using the _DBContext field, the code above creates a local, properly-scoped variable dbContext and uses that instead.

这篇关于无法从单例使用作用域服务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆