I have a service used by a few controllers in my WebAPI project. The service needs to generate URLs, so ideally it would get a UrlHelper
via a constructor parameter
Based on Darrel Miller's comment, I created the following:
A simple container class to hold a reference to the "current" HttpRequestMessage
public class CurrentRequest
{
public HttpRequestMessage Value { get; set; }
}
A message handler that will store the current request
public class CurrentRequestHandler : DelegatingHandler
{
protected async override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
var scope = request.GetDependencyScope();
var currentRequest = (CurrentRequest)scope.GetService(typeof(CurrentRequest));
currentRequest.Value = request;
return await base.SendAsync(request, cancellationToken);
}
}
In Global.asax, when configuring WebAPI, add the message handler.
GlobalConfiguration.Configuration.MessageHandlers.Insert(0, new CurrentRequestHandler());
Then, configure the Autofac container to let it construct UrlHelper
, getting the current request from the CurrentRequest
object.
var builder = new ContainerBuilder();
builder.RegisterType<CurrentRequest>().InstancePerApiRequest();
builder.Register(c => new UrlHelper(c.Resolve<CurrentRequest>().Value));
builder.RegisterType<MyService>();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
...
container = builder.Build();
UrlHelper
can then be injected into the MyService
just like any other dependency.
Thanks to Darrel for pointing me in the right direction.
Use the RegisterHttpRequestMessage
method to register the current request and then you can also register the URL helper like so:
public static IContainer SetupContainer(HttpConfiguration config)
{
var containerBuilder = new ContainerBuilder();
// Register your Web API.
containerBuilder.RegisterApiControllers(Assembly.GetExecutingAssembly());
containerBuilder.RegisterHttpRequestMessage(config);
containerBuilder.Register(x => new UrlHelper(x.Resolve<HttpRequestMessage>()));
containerBuilder.RegisterWebApiFilterProvider(config);
containerBuilder.RegisterWebApiModelBinderProvider();
// Register your other types...
var container = containerBuilder.Build();
// Set the dependency resolver to be Autofac.
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
return container;
}
Best I can think of is make your service implement IAutofacActionFilter
like so
public class MyService : IAutofacActionFilter
{
private UrlHelper _urlHelper;
public void DoSomething()
{
var link = Url.Link("SomeRoute", new {});
}
private UrlHelper Url
{
get
{
if(_urlHelper == null)
throw new InvalidOperationException();
return _urlHelper;
}
}
public void OnActionExecuted(System.Web.Http.Filters.HttpActionExecutedContext actionExecutedContext)
{
}
public void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
{
this._urlHelper = actionContext.Request.GetUrlHelper();
}
}
and then use something like the following Autofac config
builder.RegisterType<MyService>()
.AsWebApiActionFilterFor<SomeController>()
.AsSelf()
.InstancePerApiRequest();