joh*_*y 5 3 c# dependency-injection background-process signalr asp.net-core
编辑摘要
我有一个后台服务,它需要一个DBContext,我的DbContext依赖于HttPContext,因为它使用UserClaims来过滤上下文.HttpContext在从BackgroundService请求DbContext时为null(这是设计原因,因为没有与BackgroundService关联的WebRequest).
我如何捕获和moq HTTPContext,所以我的用户声称将转移到后台服务?
我正在编写一个托管服务来排队从Signalr中的中心推送消息.我的背景.
public interface IBackgroundTaskQueue
{
void QueueBackgroundWorkItem(Func<IServiceProvider, CancellationToken, Task> workItem);
Task<Func<IServiceProvider, CancellationToken, Task>> DequeueAsync(CancellationToken cancellationToken);
}
public class BackgroundTaskQueue : IBackgroundTaskQueue
{
private ConcurrentQueue<Func<IServiceProvider, CancellationToken, Task>> _workItems = new ConcurrentQueue<Func<IServiceProvider, CancellationToken, Task>>();
private SemaphoreSlim _signal = new SemaphoreSlim(0);
public void QueueBackgroundWorkItem(Func<IServiceProvider, CancellationToken, Task> workItem)
{
if (workItem == null)
{
throw new ArgumentNullException(nameof(workItem));
}
this._workItems.Enqueue(workItem);
this._signal.Release();
}
public async Task<Func<IServiceProvider, CancellationToken, Task>> DequeueAsync(
CancellationToken cancellationToken)
{
await this._signal.WaitAsync(cancellationToken);
this._workItems.TryDequeue(out var workItem);
return workItem;
}
}
Run Code Online (Sandbox Code Playgroud)
我正在排队需要我的DbContext的工作项,My Db Context根据登录用户自动过滤数据,因此它需要访问HTTPContextAccessor.
当我对需要我的DbContext的项进行排队时,我得到一个错误,HTTPContext为null,这是有道理的,因为我正在后台进程中运行.
var backgroundTask = sp.GetRequiredService<IBackgroundTaskQueue>();
backgroundTask.QueueBackgroundWorkItem((isp, ct) => {
//When this line is executed on the background task it throws
var context = sp.GetService<CustomDbContext>();
//... Do work with context
});
Run Code Online (Sandbox Code Playgroud)
我的DBContext使用HTTPContextAccessor来过滤数据:
public CustomDbContext(DbContextOptions options, IHttpContextAccessor httpContextAccessor)
{
}
Run Code Online (Sandbox Code Playgroud)
有没有办法可以捕获每个Task的HTTPContext,或者可能是Moq one捕获UserClaims,并在BackgroundService的范围内替换它们?
如何使用依赖于我的后台服务的HTTPContext的服务.
我的DbContext依赖于HttpContext,因为它使用UserClaims来过滤上下文.
这听起来像是一个糟糕的设计.您的数据库上下文应该只担心提供数据库访问.我认为基于用户权限的过滤已经对数据库上下文负有太多责任,并且您应该将其移动到另一层.但即便如此,您可能应该尝试不依赖于HTTP上下文,尤其是当您计划从在HTTP上下文之外执行的某个地方使用它时.相反,请考虑明确地将用户或用户声明传递给被调用的方法.这样,您就不会引入隐藏在上下文中的用户的隐式依赖项.
至于模拟上下文,你真的不需要用像Moq这样的模拟库来模拟它.你可以创建一个DefaultHttpContext并在里面设置用户,例如:
var context = new DefaultHttpContext()
{
User = new ClaimsPrincipal(new ClaimsIdentity(new Claim[]
{
new Claim(ClaimTypes.Name, "Foo"),
})),
};
Run Code Online (Sandbox Code Playgroud)
但是能够创建HTTP上下文并不能帮助您为数据库上下文提供上下文:在创建服务提供者之后,您无法替换已注册的服务,因此您必须设置上下文HttpContextAccessor- 我强烈建议反对因为在后台服务中使用可能不安全,或者明确地创建数据库上下文 - 我也建议反对,因为这会破坏DI的目的.
因此,"正确"的方式可能会重新考虑您的体系结构,这样您就不需要依赖HTTP上下文,理想情况下甚至不需要依赖用户.因为毕竟,您的后台服务没有在HTTP上下文的范围内运行,因此它也不在单个用户的范围内运行.
通常还要记住数据库上下文是作用域依赖项,因此无论如何都不应在依赖项作用域之外解析它们.如果您需要后台服务中的数据库上下文,则应首先使用以下命令显式打开依赖项作用域IServiceScopeFactory.
| 归档时间: |
|
| 查看次数: |
942 次 |
| 最近记录: |