Внедрить WebAPI UrlHelper в службу с помощью Autofac

у меня есть служба, используемая несколькими контроллерами в моем проекте WebAPI. Сервис должен генерировать URL-адреса, поэтому в идеале он получит UrlHelper через параметр конструктора.

public class MyService
{
    public MyService(UrlHelper urlHelper) { ... }
}

Я использую Autofac в качестве контейнера IoC. Как я могу зарегистрироваться UrlHelper в контейнере? Ему нужен HttpRequestMessage и я не могу выяснить, как получить "текущее" сообщение.

3 ответов


использовать RegisterHttpRequestMessage метод регистрации текущего запроса, а затем вы также можете зарегистрировать помощник URL так:

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;
}

основываясь на комментарии Даррела Миллера, я создал следующее:

простой класс контейнера для хранения ссылки на" текущий " HttpRequestMessage

public class CurrentRequest
{
    public HttpRequestMessage Value { get; set; }
}

обработчик сообщений, который будет хранить текущий запрос

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);
    }
}

В Глобальном.asax при настройке WebAPI добавьте обработчик сообщений.

GlobalConfiguration.Configuration.MessageHandlers.Insert(0, new CurrentRequestHandler());

затем настройте контейнер Autofac, чтобы он построил UrlHelper, получение текущего запроса от CurrentRequest объект.

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 можно после этого впрыснуть в MyService как и любая другая зависимость.

спасибо Даррелу за то, что указал мне в правильном направлении.


лучшее, что я могу придумать, это сделать вашу службу реализовать IAutofacActionFilter вот так

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();
        }
    }

а затем используйте что-то вроде следующей конфигурации Autofac

builder.RegisterType<MyService>()
                 .AsWebApiActionFilterFor<SomeController>()
                 .AsSelf()
                 .InstancePerApiRequest();