基于我的last post我能够让批处理工作......直到某一点。除了注册路由特定处理程序之外,我还有2个委派处理程序
批处理程序遍历委派处理程序,对用户进行身份验证并记录请求。当messagehandlerinvoker开始发送子/嵌套请求时,抛出以下异常。
System.ArgumentException was unhandled by user code
HResult=-2147024809
Message=The 'DelegatingHandler' list is invalid because the property 'InnerHandler' of 'AuthenticationMessageHandler' is not null.
Parameter name: handlers
Source=System.Net.Http.Formatting
ParamName=handlers
StackTrace:
at System.Net.Http.HttpClientFactory.CreatePipeline(HttpMessageHandler innerHandler, IEnumerable`1 handlers)
at System.Web.Http.HttpServer.Initialize()
at System.Web.Http.HttpServer.<EnsureInitialized>b__3()
at System.Threading.LazyInitializer.EnsureInitializedCore[T](T& target, Boolean& initialized, Object& syncLock, Func`1 valueFactory)
at System.Threading.LazyInitializer.EnsureInitialized[T](T& target, Boolean& initialized, Object& syncLock, Func`1 valueFactory)
at System.Web.Http.HttpServer.EnsureInitialized()
at System.Web.Http.HttpServer.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpMessageInvoker.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at RoutingRequest.Service.Startup.BatchMessageHandler.<>c__DisplayClassd.<PrcoessRequest>b__b(Task`1 m) in C:\CEI\Clients\Footlocker.com\FL - Vendor Routing Portal\source\RoutingRequest.Service\Startup\BatchMessageHandler.cs:line 45
at System.Threading.Tasks.ContinuationResultTaskFromResultTask`2.InnerInvoke()
at System.Threading.Tasks.Task.Execute()
InnerException:
是否有我缺少的配置选项,还是我需要绕过委托处理程序?
修改 这是我的身份验证处理程序。
public class AuthenticationMessageHandler
: DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
SetCurrentUser(request);
return base.SendAsync(request, cancellationToken);
}
private void SetCurrentUser(HttpRequestMessage request)
{
var values = new List<string>().AsEnumerable();
if (request.Headers.TryGetValues("routingrequest-username", out values) == false) return;
var username = values.First();
var user = Membership.GetUser(username, true);
if (user == null)
{
var message = string.Format("membership information for '{0}' could not be found.", username);
throw new HttpRequestException(message);
}
var roles = Roles.GetRolesForUser(username);
Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity(user.UserName), roles);
}
}
根据Kiran的回答,子类的httpserver修复了一个问题并引入了另一个问题。我的角色提供程序正在获取空引用异常。现在正在调查。
答案 0 :(得分:13)
该博客文章正确识别问题,但如果您使用Startup
或OwinStartup
类配置OWIN,则有一个更简单的解决方案:
更改OWIN配置调用
UseWebApi(this IAppBuilder builder, HttpConfiguration configuration);
至
UseWebApi(this IAppBuilder builder, HttpServer httpServer);
以便您的批处理程序和OWIN管道使用相同的HttpServer
实例。
这样做的根本原因是许多批处理文章/示例(例如http://bradwilson.typepad.com/blog/2012/06/batching-handler-for-web-api.html)除了处理HTTP请求的主HttpServer
之外还为批处理创建了新的HttpServer
;并且HttpServer
都使用相同的HttpConfiguration
。
当第一次接收请求时初始化每个HttpServer
时,它会通过反转所有已配置的委托处理程序(例如,跟踪处理程序或其他代理类型)来创建处理程序管道(在HttpClientFactory.CreatePipeline
中)处理程序),并使用Web API调度程序终止管道。
如果您没有配置任何委派处理程序,那么此问题不会让您感到困惑 - 您可以拥有使用相同HttpServer
的2个HttpConfiguration
个对象。
但是如果你有任何明确或隐式配置的委托处理程序(例如enabling Web API Tracing),那么Web API就无法构建第二个管道 - 委托处理程序已经在第一个管道中链接了 - 这个例外是第二次HttpServer
的第一次请求时抛出。
这个例外应该更清楚地说明发生了什么。更好的是,这个问题甚至不可能 - 配置应该是配置,而不是单个处理程序。配置可以是委派处理程序的工厂。但我离题了......
虽然这个问题有点难以理解,但还有一个非常简单的方法:
HttpServer
UseWebApi(this IAppBuilder builder, HttpServer httpServer);
传递给OWIN管道
GlobalConfiguration.DefaultServer
传递给批处理程序,以避免创建新的HttpServer
这是一个示例OWIN启动类,它创建一个HttpServer
并将其传递给批处理程序和Web API。此示例用于OData批处理程序:
[assembly: OwinStartup(typeof(My.Web.OwinStartup))]
namespace My.Web
{
/// <summary>
/// OWIN webapp configuration.
/// </summary>
public sealed class OwinStartup
{
/// <summary>
/// Configure all the OWIN modules that participate in each request.
/// </summary>
/// <param name="app">The OWIN appBuilder</param>
public void Configuration(IAppBuilder app)
{
HttpConfiguration webApiConfig = new HttpConfiguration();
webApiConfig.MapHttpAttributeRoutes();
HttpServer webApiServer = new HttpServer(webApiConfig);
// Configure batch handler
var batchHandler = new DefaultODataBatchHandler(webApiServer);
webApiConfig.Routes.MapODataServiceRoute("ODataRoute",
"odata",
BuildEdmModel(),
new DefaultODataPathHandler(),
ODataRoutingConventions.CreateDefault(),
batchHandler);
app.UseWebApi(webApiServer);
}
private EdmModel BuildEdmModel()
{
// ...
}
}
}
答案 1 :(得分:5)
特洛伊有一个关于解决此问题的博客:
http://trocolate.wordpress.com/2012/07/19/mitigate-issue-260-in-batching-scenario/
答案 2 :(得分:1)
我没有批处理就遇到了这个错误。我创建了HttpClientFactory
我自己的HandlerFactory
,也是我自己的。{/ p>
它在构造函数中调用HandlerFactory.Create()
方法并存储它所生成的处理程序。
只要工厂需要制作新的System.Net.Http.HttpClientFactory.Create(...)
,就会将这些传递给HttpClient
方法。
但它只适用于单个调用,因为处理程序本身会被.NET代码变异,使它们处于一种状态,这意味着它们无法重用。
我改变了我的构造函数,以便它不会在前面创建处理程序,但每次都是这样。它现在有效。