Reputation: 5451
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.
public class MyService
{
public MyService(UrlHelper urlHelper) { ... }
}
I'm using Autofac as my IoC container. How can I register UrlHelper
in the container? It needs a HttpRequestMessage
and I can't figure out how to get the "current" message.
Upvotes: 9
Views: 3823
Reputation: 38417
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;
}
Upvotes: 9
Reputation: 5451
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.
Upvotes: 5
Reputation: 581
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();
Upvotes: 0