I am in the process of changing my Asp.Net MVC3 project to use Autofac for service injection into my controllers. So far this has been pretty straightforward. My services all have a Telerik OpenAccess db property which I inject through the constructors (In a service base class). And my controllers all have constructor properties for services which also get injected.
I have a class called AuditInfo which encapsulates auditable properties of a controller:
public class AuditInfo
{
public string RemoteAddress { get; set; }
public string XForwardedFor { get; set; }
public Guid UserId { get; set; }
public string UserName { get; set; }
}
My OpenAccess db property in my service classes needs to have an instance of this class injected in to it in order to use as auditing information in various database calls.
The problem is that this is not a class that can be instantiated at Application_Start because at least two properties of it, RemoteAddress and XForwardedFor are populated at the earliest stage of OnActionExecuting, i.e. once the Request variables exist.
Therefore, I instantiate this in the OnActionExecuting method of my BaseController class as such:
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
db.AuditInfo = AuditInfo;
}
public AuditInfo AuditInfo
{
get
{
return new AuditInfo()
{
RemoteAddress = this.Request.ServerVariables["REMOTE_ADDR"],
XForwardedFor = this.Request.ServerVariables["X_FORWARDED_FOR"],
UserId = this.UserId,
UserName = this.UserName
};
}
}
So - my problem/questions are:
How would I setup autofac to inject AuditInfo in to any class that has it as a property? Or is there a better way of sidestepping the circular dependency and using some form of lambda/lazy constructor properties?
Is it at all concerning that AuditInfo gets re-initialized potentially unnecessarily at every request even though a lot of requests may be part of the same session and not have different ip address/user info?
Thanks
Autofac is an open-source dependency injection (DI) or inversion of control (IoC) container developed on Google Code. Autofac differs from many related technologies in that it sticks as close to bare-metal C# programming as possible.
In property injection, we need to pass object of the dependent class through a public property of the client class. Let's use the below example for the implementation of the Property Injection or even it is called Setter Injection as value or dependency getting set in property.
Autofac is an IoC container for Microsoft . NET 4.5, Silverlight 5, Windows Store apps, and Windows Phone 8 apps. It manages the dependencies between classes so that applications stay easy to change as they grow in size and complexity.
Property injection is a type of dependency injection where dependencies are provided through properties. Visit the Dependency Injection chapter to learn more about it. Let's understand how we can perform property injection using Unity container. Consider the following example classes. Example: C#
It turns out Autofac's MVC Integration can resolve an HttpRequestBase
for you. So you don't need to reference HttpContext.Current.Request
directly.
Autofac's implementation uses HttpContext.Current
behind the scenes. This works because the MVC framework sets HttpContext.Current
before your code (or Autofac's) runs. So there's no circular dependency - the Request "naturally exists" on HttpContext.Current.Request
just as much as in your controller. (This question kind of explains how)
So you could do an IAuditInfoFactory
as Steven suggests but demand an HttpRequestBase
in its constructor instead of using HttpContext.Current
if it makes you feel better about not referencing static variables.
Also, there's no circular dependency and you could constructor-inject the AuditInfo
if you want:
builder.Register(c => c.Resolve<IAuditInfoFactory>().CreateNew())
.As<AuditInfo>()
.InstancePerHttpRequest();
The answer is: Use a factory.
Inject an IAuditInfoFactory
into the type that needs it, and create an implementation like this:
public class HttpRequestAuditInfoFactory : IAuditInfoFactory
{
// Service for requesting information about the current user.
private readonly ICurrentUserServices user;
public HttpRequestAuditInfoFactory(ICurrentUserServices user)
{
this.user = user;
}
AuditInfo IAuditInfoFactory.CreateNew()
{
var req = HttpContext.Current.Request;
return new AuditInfo()
{
RemoteAddress = req.ServerVariables["REMOTE_ADDR"],
XForwardedFor = req.ServerVariables["X_FORWARDED_FOR"],
UserId = this.user.UserId,
UserName = this.user.UserName
};
}
}
You can register that class as follows:
builder.RegisterType<HttpRequestAuditInfoFactory>()
.As<IAuditInfoFactory>()
.SingleInstance();
Now you can inject
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With