2012-08-17 10 views
9

basierend auf meiner last post Ich konnte Batching arbeiten ... bis zu einem gewissen Punkt. Ich habe auch 2 Delegieren HandlerWebapi Batching und Delegieren von Handlern

  1. Authentifizieren des Benutzers
  2. Anmeldung

die Batch-Handler geht durch die Delegierung Handler Neben der Route spezifischen Handler Registrierung der Benutzer authentifiziert und die Anforderung zu protokollieren. Wenn der Message-Handler-Invoker beginnt, die untergeordneten/verschachtelten Anfragen zu senden, wird die folgende Ausnahme ausgelöst.

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: 

Gibt es eine Konfigurationsoption, die ich vermisse, oder muss ich die delegierenden Handler umgehen?

bearbeiten hier ist meine Authentifizierung Handler.

basierend auf Kirans Antwort behebt ein Unterklasse-httpserver ein Problem und führt ein anderes ein. Mein Rollenanbieter erhält eine Nullreferenzausnahme. schaue das jetzt an.

+0

könnten Sie Ihren Authentifizierungshandlercode und seinen Initialisierungscode posten? –

Antwort

12

Das Blog-Post richtig das Problem identifiziert, aber es ist eine einfachere Lösung, wenn Sie OWIN konfigurieren eine Startup oder OwinStartup-Klasse:

ändern der OWIN Konfiguration Anruf von UseWebApi(this IAppBuilder builder, HttpConfiguration configuration); zu UseWebApi(this IAppBuilder builder, HttpServer httpServer); , so dass Ihre Batch-Handler ein nd die OWIN-Pipeline verwendet die gleiche HttpServer Instanz.

Die Ursache hierfür ist, dass viele der batching articles/Beispiele (zB http://bradwilson.typepad.com/blog/2012/06/batching-handler-for-web-api.html) für ein neues HttpServer batching zusätzlich zu dem Haupt HttpServer erstellen, die HTTP-Anfragen ist Handhabung; und beide HttpServer s verwenden dasselbe HttpConfiguration.

Wenn jedes HttpServer das erste Mal ist es Anforderungen empfängt initialisiert wird, erzeugt es eine Pipeline-Handler (in HttpClientFactory.CreatePipeline) durch alle konfigurierten Delegieren Handler Umkehren (zB Handler Verfolgung oder andere Proxy-Typ-Handler), und zur Einstellung der Rohrleitung mit dem Web-API-Dispatcher.

Wenn Sie keine delegierenden Handler konfiguriert haben, wird Sie dieses Problem nicht beißen - Sie können 2 HttpServer Objekte verwenden, die denselben HttpConfiguration verwenden.

Wenn jedoch delegierende Handler explizit oder implizit konfiguriert sind (z. B. enabling Web API Tracing), kann die Web - API die zweite Pipeline nicht erstellen - die delegierenden Handler sind bereits in der ersten Pipeline verknüpft - und diese Ausnahme wird auf die erste Anfrage an die 2. HttpServer.

Diese Ausnahme sollte unbedingt klarer sein, was vor sich geht. Besser noch, dieses Problem sollte nicht einmal möglich sein - Konfiguration sollte Konfiguration sein, nicht einzelne Handler.Die Konfiguration könnte eine Fabrik zum Delegieren von Handlern sein. Aber ich schweife ab ...

Während das Problem irgendwie schwer ist, um herauszufinden, gibt es eine ziemlich einfache Lösung:

  1. Wenn Sie OWIN verwenden, übergeben Sie die gleichen HttpServer, wie Sie in den Batch-Handler zur OWIN Pipeline über UseWebApi(this IAppBuilder builder, HttpServer httpServer);
  2. Wenn Sie IIS + Web API (keine OWIN Startup-Klasse) verwenden, GlobalConfiguration.DefaultServer zu Batch-Handler übergeben, um zu verhindern ein neues HttpServer

Schaffung Hier ist ein Beispiel OWIN Startklasse, die einen einzelnen HttpServer erstellt und an den Batch-Handler und die Web-API übergibt. Dieses Beispiel verwendet OData Batch-Handler:

[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

interessant! In der standardmäßigen 'öffentlichen Void-Konfiguration (IAppBuilder-App)' von startup.cs (wo OWIN standardmäßig Cors & co konfiguriert), wie würde ich den httpServer bekommen? Danke –

+1

Ein Beispiel zu meiner Antwort hinzugefügt. – crimbo

+0

"IOC" Initialisierung nach 'UseWebApi 'aufrufen, sonst kann der Fehler auftreten" Eine' ApiController 'Instanz kann nicht wiederverwendet werden.' ApiController 'muss für jede eingehende Nachricht erstellt werden. Überprüfen Sie Ihren benutzerdefinierten' IHttpControllerActivator 'und vergewissern Sie sich, dass er den gleiche Instanz. ". In meinem Fall waren sie 'UseAutofacMiddleware' und' UseAutofacWebApi' –

1

Ich hatte diesen Fehler ohne Batching. Ich machte einen HttpClientFactory von meinem eigenen und es nimmt einen HandlerFactory, auch mein eigenes auf.

Es ruft die HandlerFactory.Create() Methode im Konstruktor auf und speichert die daraus resultierenden Handler.

Diese werden an die Methode System.Net.Http.HttpClientFactory.Create(...) weitergegeben, wenn die Fabrik eine neue HttpClient erstellen muss.

Aber es ist dann nur gut für einen einzigen Aufruf, weil die Handler selbst durch den .NET-Code mutiert sind, was sie in einem Zustand zurücklässt, der bedeutet, dass sie nicht wiederverwendet werden können.

Ich habe meinen Konstruktor so geändert, dass er die Handler nicht im Voraus erstellt, sondern jedes Mal. Es funktioniert jetzt.