2014-01-23 2 views
2

У меня есть класс, который требует доступа к HttpRequestMessage в моей службе веб-API. На данный момент у меня есть следующий код, чтобы захватить сообщение в трубопроводе и сохранить его для последующего использования (на основе this и this):Захват и инъекция HttpRequestMessage в веб-API с помощью Ninject

public class ContextCapturingControllerActivator : IHttpControllerActivator 
{ 
    private readonly IKernel kernel; 
    private HttpRequestMessage requestMessage; 

    public ContextCapturingControllerActivator(IKernel kernel) 
    { 
     this.kernel = kernel; 
    } 

    public IHttpController Create(HttpRequestMessage requestMessage, 
            HttpControllerDescriptor controllerDescriptor, 
            Type controllerType) 
    { 
     this.kernel.Rebind<HttpRequestMessage>() 
      .ToConstant<HttpRequestMessage>(requestMessage); 

     var controller = (IHttpController)this.kernel.GetService(controllerType); 

     this.requestMessage = requestMessage; 
     requestMessage.RegisterForDispose(
      new Release(() => this.kernel.Release(controller))); 

     return controller; 
    } 

    private class Release : IDisposable 
    { 
     private readonly Action release; 

     public Release(Action release) 
     { 
      this.release = release; 
     } 

     public void Dispose() 
     { 
      this.release(); 
     } 
    } 
} 

В моей композиции корень, я настраиваю ControllerActivator:

kernel.Bind<IHttpControllerActivator>() 
     .To<ContextCapturingControllerActivator>(); 

Конечным результатом является то, что с точки зрения конфигурации HttpRequestMessage является «волшебным» вводится там, где он просил, так как это делается для нас внутри ControllerActivator. Я не смог ввести сообщение из моего корня композиции. Я также не сумасшедший о Rebind, так как он там, чтобы не добавлять новое связывание при каждом вызове службы. Я подозреваю, что это связано с одноэлементным характером стека веб-API, но не смогло разобраться, как правильно справиться с этим.

В общем, я не могу использовать последний неустойчивый пакет Nuget из Ninject web api из-за сообщенной ошибки (и игнорируется) here.

Может кто-нибудь предложить правильный способ улучшить мой код, чтобы сделать его более понятным и облегчить жизнь будущим сопровождающим (и давайте посмотрим правде в глаза - это, вероятно, будет мне).

Спасибо.

+0

Я должен был сделать то же самое в последнее время с Ninject (и ранее с StructureMap) и до сих пор найти лучшее решение. –

+0

@BenFoster С тех пор я перешел на Autofac (по многим причинам, а не только по этой проблеме), и хотя он обеспечивает более чистый способ ввода HttpRequestMessage в запущенный код, я не смог получить доступ к нему в моей памяти интеграционные тесты. Таким образом, каждая инфраструктура DI, похоже, имеет свои собственные уникальные компромиссы. –

+1

Любой прорыв? У меня такая же проблема ... – Hudvoy

ответ

1

Вот что я сделал, но я считаю, что это зависит от Web API 2.0+.

Я создал класс экземпляра, который оборачивает запрос HTTP текущего контекста в:

public class HttpRequestMessageWrapper 
{ 
    private readonly HttpRequestMessage m_httpRequestMessage; 

    public HttpRequestMessageWrapper() 
    { 
     m_httpRequestMessage = HttpContext.Current.Items["MS_HttpRequestMessage"] as HttpRequestMessage; 
    } 

    public HttpRequestMessage RequestMessage 
    { 
     get 
     { 
      return m_httpRequestMessage; 
     } 
    } 
} 

Тогда я связала HttpRequestMessage к свойству с ToMethod связывания в области действия запроса.

container.Bind<HttpRequestMessage>().ToMethod(ctx => new HttpRequestMessageWrapper().RequestMessage).InRequestScope(); 
0

Я попробовал метод, предложенный @Mackers, который является чистым способом .... Однако, в моем конкретном случае, она не работает в связи с проблемой синхронизации. Для моего случая мне нужно было вставить объект в apikontroller ctor, и этому объекту потребовался HttpRequestMessage. HttpContext.Current.Items["MS_HttpRequestMessage"] не заполняется до тех пор, пока контроллер не будет сконструирован и не инициализирован, и я не смог найти другого способа получить к нему доступ. Поэтому я прибег к созданию пользовательского DelegatingHandler и подмене текущего сообщения с запросом, как они приходят в.

public class CurrentHttpRequestMessageHandler : DelegatingHandler 
    { 
     [SecuritySafeCritical] 
     protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) 
     { 
      UpdateScopeWithHttpRequestMessage(request); 

      return base.SendAsync(request, cancellationToken); 
     } 

     internal static void UpdateScopeWithHttpRequestMessage(HttpRequestMessage request) 
     { 
      NinjectConfig.GetConfiguredKernel().Rebind<HttpRequestMessage>().ToMethod(ctx => { return request; }) 
       .InRequestScope(); 
     } 
    } 

GetConfiguredKernel статический метод, который я создал, чтобы просто вернуть статический экземпляр ядра уже сконфигурирован.

public class NinjectConfig 
    { 
     private static readonly Bootstrapper bootstrapper = new Bootstrapper(); 
     private static StandardKernel _kernel; 

     public static void Start() 
     { 
      DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule)); 
      DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule)); 
      bootstrapper.Initialize(CreateKernel); 
     } 

     public static IKernel GetConfiguredKernel() 
     { 
      if (_kernel != null) 
       return _kernel; 

      return CreateKernel(); 
     } 
     .... 

Затем зарегистрировать DelegatingHandler с HttpConfiguration:

config.MessageHandlers.Add(new CurrentHttpRequestMessageHandler()); 
Смежные вопросы