我尝试重构一些代码,以便通过startup.cs中的映射服务使用.NET Core依赖注入。我想在这里注入一个IRequestDatabaseLogger而不是新建它。但是它需要构造函数中的上下文。我怎样才能做到这一点?甚至没有DI框架甚至可能吗?
public class ActionFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
var requestDatabaseLogger = new RequestDatabaseLogger(context);
long logId = requestDatabaseLogger.Log();
context.HttpContext.AddCurrentLogId(logId);
base.OnActionExecuting(context);
}
}
答案 0 :(得分:8)
但是它需要构造函数中的上下文。
让应用程序组件的构造依赖于运行时数据是一种反模式,如here所述。那篇文章描述了如何解决这些问题。
在您的情况下,这可能意味着您的组件应该依赖于ASP.NET Core的IHttpContextAccessor
抽象,而这是参考文章中描述的模式。
或者,如本文所述,您可以使用Log
方法将所需的运行时数据传递给记录器。
答案 1 :(得分:2)
您应该使用TypeFilter来实现此目的,并将具有依赖关系的过滤器(在本例中为记录器或上下文)包装在过滤器内部。我在MSDN Article on ASP.NET Core Filters中展示了一个详细的例子。相关的源代码是here(查看ValidateAuthorExists过滤器)。
以下是您的方案中的样子:
public class MyFilterAttribute : TypeFilterAttribute
{
public MyFilterAttribute():base(typeof(MyFilterImpl))
{
}
private class MyFilterImpl : IAsyncActionFilter
{
public MyFilterImpl( *inject dependencies here*)
{}
}
}
这是在如何使用.NET Core中的属性同时仍将依赖项注入基础操作过滤器的方法。我还将在即将到来的DevIQ.com上的ASP.NET核心快速入门课程中介绍这一点(本月末查找)。
答案 2 :(得分:0)
在构造函数中注入RequestDatabaseLoggerFactory
,可用于创建RequestDatabaseLogger
实例。
public interface IRequestDatabaseLoggerFactory {
IRequestDatabaseLogger Create(ActionExecutingContext context);
}
public class RequestDatabaseLoggerFactory : IRequestDatabaseLoggerFactory {
public IRequestDatabaseLogger Create(ActionExecutingContext context) {
return new RequestDatabaseLogger(context);
}
}
public class ActionFilter : ActionFilterAttribute
{
public ActionFilter(IRequestDatabaseLoggerFactory factory) {
_factory = factory;
}
private readonly IRequestDatabaseLoggerFactory _factory;
public override void OnActionExecuting(ActionExecutingContext context)
{
var requestDatabaseLogger = _factory.Create(context);
long logId = requestDatabaseLogger.Log();
context.HttpContext.AddCurrentLogId(logId);
base.OnActionExecuting(context);
}
}