В ASP.NET Web API экземпляры HttpControllerContext предоставляют много информации о текущей среде, включая URI текущего запроса.
Если служба полагается на такую информацию (например, URI запроса), она должна быть доступна для ввода этой информации в службу.
Это довольно просто сделать, используя "Бедный человек": просто реализовать пользовательский IHttpControllerActivator.
Однако, с замком Виндзор это становится очень сложно. Раньше Я описал очень запутанный путь, чтобы решить эту проблему, но она зависит от стиля PerWebRequest, и оказывается, что этот образ жизни не не работайте в сценариях самообслуживания, поскольку HttpContext.Current пуст.
До сих пор мне удалось выполнить эту работу, передав нужную информацию как встроенный аргумент метода Resolve из пользовательского IHttpControllerActivator:
public IHttpController Create(
HttpControllerContext controllerContext,
Type controllerType)
{
var baseUri = new Uri(
controllerContext
.Request
.RequestUri
.GetLeftPart(UriPartial.Authority));
return (IHttpController)this.container.Resolve(
controllerType,
new { baseUri = baseUri });
}
Однако по умолчанию это работает только в том случае, если запрашиваемый тип полагается на аргумент (т.е. если сам запрашиваемый контроллер зависит от baseUri
). Если зависимость от baseUri
затухает глубже в иерархии зависимостей, она по умолчанию не работает, потому что встроенные аргументы не распространяются на более глубокие слои.
Это поведение может быть изменено с помощью настраиваемого IDependencyResolver (замок Windsor IDependencyResolver, а не ASP.NET Web API IDependencyResolver):
public class InlineDependenciesPropagatingDependencyResolver :
DefaultDependencyResolver
{
protected override CreationContext RebuildContextForParameter(
CreationContext current, Type parameterType)
{
if (parameterType.ContainsGenericParameters)
{
return current;
}
return new CreationContext(parameterType, current, true);
}
}
Обратите внимание, что true
передается как аргумент конструктора propagateInlineDependencies
вместо false
, который является реализацией по умолчанию.
Чтобы подключить экземпляр контейнера с классом InlineDependenciesPropagatingDependencyResolver, он должен быть сконструирован таким образом:
this.container =
new WindsorContainer(
new DefaultKernel(
new InlineDependenciesPropagatingDependencyResolver(),
new DefaultProxyFactory()),
new DefaultComponentInstaller());
Мне интересно, если это лучшее решение этой проблемы, или если есть лучший/более простой способ?