Reputation: 1369
I have an ASP.NET Web Api 2 REST service with several controllers. Each one of these controllers' constructor has got an ILogger argument which I have to inject with StructureMap. Is it possibile to instantiate an ILogger per request, in order to get client's specific informations - such as the IP address - and thus save the log file to a specific path?
This is the code I'm trying to run in the DefaultRegistry, but HttpContext is always null. Where am I wrong?
For<ILogger>()
.Use(() => new TextFileLogger(
HttpContext.Current.Request.UserHostAddress +
DirectorySeparatorChar + "log.txt"));
Upvotes: 0
Views: 217
Reputation: 5540
I'm not an expert on StructureMap but I understand the problem. The problem you have is that you use runtime data to build up your object graph. And injecting runtime data is an anti-pattern.
The simple solution here is not to use the HttpContext
directly in your composition root but to create a provider which you can use to determine the path in the FileLogger
. In that case both the FileLogger
as this new provider can become singleton, which is far easier to work with and understand.
A provider could be as simple as (c#6 syntax):
public class HttpLogfileProvider : ILogFileProvider
{
public string PathToLogfile =>
Path.Combine(HttpContext.Current.Request.UserHostAddress, "log.txt");
}
Your FileLogger
can use this provider as follows:
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;
}
I'm not an structuremap user but I think the registration should be:
For<ILogFileProvider>.Use<HttpLogfileProvider>.Singleton;
For<ILogger>.Use<FileLogger>.Singleton;
Upvotes: 4