无法从单例使用作用域服务 [英] Cannot consume scoped service from singleton
问题描述
我正在尝试在托管服务中使用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.
请按照以下步骤操作:
-
从您的
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屋!