webapi批处理和委托处理程序

Jas*_*ley 9 batch-processing asp.net-web-api

基于我的一篇文章,我能够让批处理工作......直到某一点.除了注册路由特定处理程序之外,我还有2个委派处理程序

  1. 验证用户
  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: 
Run Code Online (Sandbox Code Playgroud)

是否有我缺少的配置选项,或者我是否需要绕过委托处理程序?

编辑 这里是我的认证处理程序.

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

根据Kiran的回答,子类的httpserver修复了一个问题并引入了另一个问题.我的角色提供程序正在获取空引用异常.现在正在调查

cri*_*mbo 15

该博客文章正确识别问题,但如果您使用StartupOwinStartup类配置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)创建了一个HttpServer用于批处理的新内容除了HttpServer处理HTTP请求的main之外; 两者HttpServer都使用相同的HttpConfiguration.

HttpServer第一次接收请求时初始化每个请求时,它会HttpClientFactory.CreatePipeline通过反转所有已配置的委托处理程序(例如,跟踪处理程序或其他代理类型处理程序)并使用Web API调度程序终止管道来创建处理程序管道(in ).

如果您没有配置任何委派处理程序,那么这个问题不会让您感到困惑 - 您可以拥有2个HttpServer使用相同的对象HttpConfiguration.

但是,如果您有任何显式或隐式配置的委托处理程序(例如,通过启用Web API跟踪),那么Web API无法构建第二个管道 - 委托处理程序已在第一个管道中链接 - 并且此异常在第一个管道中引发要求到第二HttpServer.

这个例外应该更清楚地说明发生了什么.更好的是,这个问题甚至不可能 - 配置应该是配置,而不是单个处理程序.配置可以是委派处理程序的工厂.但我离题了......

虽然这个问题有点难以理解,但有一个非常简单的方法:

  1. 如果您正在使用OWIN,请将HttpServer您在批处理程序中使用的相同内容传递给OWIN管道UseWebApi(this IAppBuilder builder, HttpServer httpServer);
  2. 如果您使用的是IIS + Web API(没有OWIN Startup类),请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()
        {
            // ...
        }
    }

}
Run Code Online (Sandbox Code Playgroud)