我有一个类需要访问我的Web API服务中的HttpRequestMessage。目前,我已经获得以下代码来捕获管道中的消息并将其保存以供日后使用(基于this和this):
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堆栈的单例性质,但还是无法理清如何正确处理它。
一般情况下,由于报告错误(并忽略)here,我无法使用Ninject web api的最新不稳定Nuget包。
任何人都可以提出正确的方法来改进我的代码,使其更清晰,让未来的维护者更轻松(让我们面对它 - 这可能是我)。
感谢。
答案 0 :(得分: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;
}
}
}
然后我在请求范围内使用ToMethod绑定将HttpRequestMessage绑定到属性。
container.Bind<HttpRequestMessage>().ToMethod(ctx => new HttpRequestMessageWrapper().RequestMessage).InRequestScope();
答案 1 :(得分:0)
我已经尝试过@Mackers提出的方法,这是最干净的方法....但是,在我的具体情况下,由于时间问题,它无法正常工作。对于我的情况,我需要将一个对象注入apicontroller 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());
答案 2 :(得分:0)
基于Macker的答案,System.Web具有HttpRequestBase class,您可以使用它并简化代码的单元测试。在需要该请求的代码中的任何位置,将HttpRequestBase类型指定为构造函数参数,并使用以下方法注册它:
注入示例:
this._settings[t]
团结示例:
select t1.item, t2.item, count(*) as num_customers
from transaction t1 join
transaction t2
on t1.consumer_id = t2.consumer_id and
t1.item < t2.item
group by t1.item, t2.item