C# 是否使用AsyncLocal存储请求信息?
我们从ASP.NETCore2开始。我们需要为请求中涉及的每个元素提供一种将消息写入消息处理程序的方法 一些限制:C# 是否使用AsyncLocal存储请求信息?,c#,asp.net,asp.net-core,C#,Asp.net,Asp.net Core,我们从ASP.NETCore2开始。我们需要为请求中涉及的每个元素提供一种将消息写入消息处理程序的方法 一些限制: 我们将不使用HttpContext.Items(HttpContext在我们在控制器内使用的类中不可用,并且我们不希望在那里转发整个上下文) 我们尝试在没有依赖注入的情况下使用它,因为如果我们有多个不同的服务,那么在构造函数中会有太多的参数 还必须使用async/wait 我们尝试了一种使用AsyncLocal的方法 为此,我们创建了一个类: public class Noti
- 我们将不使用
(HttpContext.Items
在我们在控制器内使用的类中不可用,并且我们不希望在那里转发整个上下文)HttpContext
- 我们尝试在没有依赖注入的情况下使用它,因为如果我们有多个不同的服务,那么在构造函数中会有太多的参数
- 还必须使用
/async
wait
AsyncLocal
的方法
为此,我们创建了一个类:
public class NotificationExecutionContext
{
private static readonly AsyncLocal<NotificationHandler> NotificationHandler =
new AsyncLocal<NotificationHandler>();
public static NotificationHandler Instance =>
NotificationHandler.Value ?? (NotificationHandler.Value = new NotificationHandler());
}
使用此解决方案,我可以轻松获取此上下文的NotificationHandler
,并添加通知
NotificationExecutionContext.Instance.AddNotification(new NotificationBase(){..})
在中间件内部,我们正在等待响应.onStart()
事件,然后从NotificationHandler
获取所有消息,并将它们添加到响应头中:
public async Task Invoke(HttpContext context)
{
var e = NotificationExecutionContext.Instance; // Required so that notification handler will be created in this context
context.Response.OnStarting((state) =>
{
List<NotificationBase> notifications = NotificationExecutionContext.Instance.Notifications;
if (notifications.Count > 0)
{
string messageString = JsonConvert.SerializeObject(notifications, Formatting.None);
context.Response.Headers.Add("NotificationHeader", messageString);
}
return Task.FromResult(0);
}, null);
await Next(context);
}
公共异步任务调用(HttpContext上下文)
{
var e=NotificationExecutionContext.Instance;//必需,以便在此上下文中创建通知处理程序
context.Response.onStart((状态)=>
{
列表通知=NotificationExecutionContext.Instance.notifications;
如果(notifications.Count>0)
{
string messageString=JsonConvert.SerializeObject(通知、格式化、无);
Add(“NotificationHeader”,messageString);
}
返回Task.FromResult(0);
},空);
等待下一个(上下文);
}
这段代码是有效的,但是否存在我们不知道的陷阱?或者有更好的解决方案吗?您应该不要像那样使用静态单例。在代码中包含这样的静态依赖关系会破坏依赖关系注入的整个目的。您应该在这里接受依赖项注入,这将使这变得非常简单:
/* in Startup.ConfigureServices */
// register the notification handler as a scoped dependency, this automatically makes the
// instance shared per request but not outside of it
services.AddScoped<INotificationHandler, NotificationHandler>();
/* in Startup.Configure */
// register your custom middleware
app.Use<NotificationHandlerMiddleware>();
就这些。不需要引入静态,但使用完全依赖项注入可以使代码完全可测试,并且所有依赖项都清晰可见
我们尝试在没有依赖注入的情况下使用它,因为如果我们有多个不同的服务,我们将不得不在构造函数中使用许多参数
太多的构造函数参数是违反的明显标志。如果发现服务有很多依赖关系,则应该考虑拆分。你也可以考虑。
/* in Startup.ConfigureServices */
// register the notification handler as a scoped dependency, this automatically makes the
// instance shared per request but not outside of it
services.AddScoped<INotificationHandler, NotificationHandler>();
/* in Startup.Configure */
// register your custom middleware
app.Use<NotificationHandlerMiddleware>();
public class NotificationHandlerMiddleware
{
private readonly RequestDelegate _next;
private readonly NotificationHandler _notificationHandler;
public NotificationHandlerMiddleware(RequestDelegate next, INotificationHandler notificationHandler)
{
_next = next;
_notificationHandler = notificationHandler;
}
public void Invoke(HttpContext context)
{
// do whatever with _notificationHandler
await _next(context);
}
}