无法从单例消费范围服务 [英] Cannot consume scoped service from singleton

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

问题描述

我正在尝试在托管服务中使用 DBContext,但出现此错误.我试图遵循这个接受的答案,但不知何故它不起作用,我不确定我做错了什么.

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

<块引用>

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

公共类 TokenService : IHostedService{公共 IConfiguration _Configuration { 获取;}受保护的 IMemoryCache _cache;私人定时器_timer;公共 IHttpClientFactory _clientFactory;公共 DBContext _DBcontext;私有只读 IServiceScopeFactory _scopeFactory;public TokenService(IConfiguration配置,IMemoryCache memoryCache,IHttpClientFactory clientFactory,DBContext DBcontext,IServiceScopeFactory scopeFactory){_Configuration = 配置;_cache = 内存缓存;_clientFactory = 客户端工厂;_scopeFactory = scopeFactory;_DBcontext = _scopeFactory.CreateScope().ServiceProvider.GetRequiredService();}公共任务 StartAsync(CancellationToken 取消令牌){_timer = new Timer(getOrg, null, 0, 1000);返回 Task.CompletedTask;}公共任务停止异步(CancellationToken 取消令牌){//定时器没有停止._timer?.Change(Timeout.Infinite, 0);返回 Task.CompletedTask;}公共异步任务 getOrg(){var request = new HttpRequestMessage(HttpMethod.Get, "organizations");var response = await _client_NP.SendAsync(request);var json = 等待 response.Content.ReadAsStringAsync();OrganizationsClass.OrgsRootObject 模型 = JsonConvert.DeserializeObject(json);foreach(model.resources 中的 var 项目){var g = Guid.Parse(item.guid);var x = _DBcontext.Organizations.FirstOrDefault(o => o.OrgGuid == g);如果(x == 空){_DBcontext.Organizations.Add(新组织{OrgGuid = g,名称 = 项目名称,CreatedAt = item.created_at,UpdatedAt = item.updated_at,时间戳 = DateTime.Now,基础 = 3});}否则如果 (x.UpdatedAt != item.updated_at){x.CreatedAt = item.created_at;x.UpdatedAt = item.updated_at;x.Timestamp = DateTime.Now;}}等待 _DBcontext.SaveChangesAsync();}}

解决方案

大功告成,但您在 TokenService 的依赖项中留下了 DBContext构造函数.删除它,您将不再收到错误.

<前>公共令牌服务(IConfiguration 配置,IMemoryCache 内存缓存,IHttpClientFactory 客户端工厂,DBContext DBContext,IServiceScopeFactory scopeFactory)

然而,您并没有完全遵循在单例服务中处理 DbContext 的建议.与其在构造函​​数中创建 DBContext 的单个实例并将其存储为字段,不如在需要时创建作用域和相应的 DBContext.在您的情况下,这是在 getOrg 方法中.

请按照以下步骤实现:

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

    公共 DBContext _DBcontext;

  2. TokenService 构造函数中移除关联的赋值:

    _DBcontext = _scopeFactory.CreateScope().ServiceProvider.GetRequiredService();

  3. getOrg中,创建一个作用域,解析一个DBContext的实例,最后处理这个作用域:

    公共异步任务 getOrg(){var request = new HttpRequestMessage(HttpMethod.Get, "organizations");var response = await _client_NP.SendAsync(request);var json = 等待 response.Content.ReadAsStringAsync();OrganizationsClass.OrgsRootObject 模型 = JsonConvert.DeserializeObject(json);使用 (var scope = _scopeFactory.CreateScope()){var dbContext = scope.ServiceProvider.GetRequiredService();foreach(model.resources 中的 var 项目){var g = Guid.Parse(item.guid);var x = dbContext.Organizations.FirstOrDefault(o => o.OrgGuid == g);如果(x == 空){dbContext.Organizations.Add(新组织{OrgGuid = g,名称 = 项目名称,CreatedAt = item.created_at,UpdatedAt = item.updated_at,时间戳 = DateTime.Now,基础 = 3});}否则如果 (x.UpdatedAt != item.updated_at){x.CreatedAt = item.created_at;x.UpdatedAt = item.updated_at;x.Timestamp = DateTime.Now;}}等待 dbContext.SaveChangesAsync();}}

上面的代码没有使用 _DBContext 字段,而是创建了一个本地的、范围适当的变量 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.

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

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

解决方案

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)

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.

Follow these steps to achieve that:

  1. Remove the _DBcontext field from your TokenService class:

    public DBContext _DBcontext;

  2. Remove the associated assignment from the TokenService constructor:

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

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

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

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

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