2014-01-23 44 views
2

我有一個需要訪問Web API服務中的HttpRequestMessage的類。 (基於thisthis)的那一刻,我有下面的代碼在管道中捕捉信息,並保存起來以備以後:使用Ninject在Web API中捕獲和注入HttpRequestMessage

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也沒什麼興趣,因爲它在那裏避免每次調用服務時都添加新的綁定。我懷疑這是由於Web API堆棧的單例性質,但無法解決如何正確處理這些問題。

一般來說,我不能使用Ninject web api的最新不穩定的Nuget包,因爲報告(並且被忽略)的錯誤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提出這是最徹底的方法....然而,在我的具體情況,也沒有工作的方法,由於計時問題。對於我的情況,我需要將一個對象注入到控制器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(); 
     } 
     .... 

然後用HttpConfiguration註冊DelegatingHandler:

config.MessageHandlers.Add(new CurrentHttpRequestMessageHandler()); 
相關問題