无法从单例消费范围服务 [英] Cannot consume scoped service from singleton
问题描述
我正在尝试在托管服务中使用 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
构造函数.删除它,您将不再收到错误.
然而,您并没有完全遵循在单例服务中处理 DbContext
的建议.与其在构造函数中创建 DBContext
的单个实例并将其存储为字段,不如在需要时创建作用域和相应的 DBContext
.在您的情况下,这是在 getOrg
方法中.
请按照以下步骤实现:
从您的
TokenService
类中删除_DBcontext
字段:公共 DBContext _DBcontext;
从
TokenService
构造函数中移除关联的赋值:_DBcontext = _scopeFactory.CreateScope().ServiceProvider.GetRequiredService
(); 在
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:
Remove the
_DBcontext
field from yourTokenService
class:public DBContext _DBcontext;
Remove the associated assignment from the
TokenService
constructor:_DBcontext = _scopeFactory.CreateScope().ServiceProvider.GetRequiredService<DBcontext>();
In
getOrg
, create a scope, resolve an instance ofDBContext
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屋!