每个Web请求的StructureMap注入

时间:2016-05-13 14:50:17

标签: c# dependency-injection asp.net-web-api2 structuremap

我有一个带有多个控制器的ASP.NET Web Api 2 REST服务。这些控制器中的每一个都是'构造函数有一个ILogger参数,我必须使用StructureMap注入。是否有可能为每个请求实例化ILogger,以获取客户端的特定信息(例如IP地址),从而将日志文件保存到特定路径?

这是我尝试在DefaultRegistry中运行的代码,但HttpContext始终为null。我哪里错了?

For<ILogger>()
    .Use(() => new TextFileLogger(
        HttpContext.Current.Request.UserHostAddress +
        DirectorySeparatorChar + "log.txt"));

1 个答案:

答案 0 :(得分:4)

我不是StructureMap的专家,但我理解这个问题。您遇到的问题是您使用运行时数据来构建对象图。并injecting runtime data is an anti-pattern

这里的简单解决方案不是直接在合成根中使用HttpContext,而是创建一个可用于确定FileLogger中路径的提供程序。在这种情况下,FileLogger这个新的提供者都可以成为单身人士,这更容易使用和理解。

提供者可以像(c#6语法)一样简单:

public class HttpLogfileProvider : ILogFileProvider
{
     public string PathToLogfile => 
        Path.Combine(HttpContext.Current.Request.UserHostAddress, "log.txt");
}

您的FileLogger可以按如下方式使用此提供商:

public class FileLogger : ILogger
{
    private readonly ILogFileProvider logFileProvider;
    public FileLogger(ILogFileProvider logFileProvider)
    {
        this.logFileProvider = logFileProvider;
    }

    public void Log(string message)
    {
         using (var writer = new StreamWriter(this.currentLogFile))
         {
              writer.WriteLine(message);
         }
    }

    private string currentLogFile =>
         this.logFileProvider.PathToLogFile;
}

我不是结构图用户,但我认为注册应该是:

For<ILogFileProvider>.Use<HttpLogfileProvider>.Singleton;
For<ILogger>.Use<FileLogger>.Singleton;