2012-08-17 18 views
9

मेरे last post के आधार पर मैं बैचिंग काम करने में सक्षम था ... एक निश्चित बिंदु तक। मार्ग विशिष्ट हैंडलर पंजीकृत करने के अलावा मैं भी 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: 

एक config विकल्प मुझे याद आ रहा है, या मैं delegating संचालकों को बायपास करना चाहिए?

संपादित करें यहां मेरा प्रमाणीकरण हैंडलर है।

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); 
    } 
} 

किरण के जवाब के आधार पर एक subclassed httpserver एक समस्या ठीक होती है और एक अन्य का परिचय। मेरी भूमिका प्रदाता को एक शून्य संदर्भ अपवाद मिल रहा है। उसमें देख रहे हैं।

+0

क्या आप अपना प्रमाणीकरण हैंडलर कोड और इसके प्रारंभिक कोड पोस्ट कर सकते हैं? –

उत्तर

12

यही कारण है, लेकिन वहाँ एक सरल समाधान आप एक Startup या OwinStartup वर्ग का उपयोग कर Owin कॉन्फ़िगर कर रहे हैं, यदि:

बदलें UseWebApi(this IAppBuilder builder, HttpServer httpServer); तो को UseWebApi(this IAppBuilder builder, HttpConfiguration configuration); से Owin विन्यास कॉल है कि अपने बैच हैंडलर एक ओडिन पाइपलाइन उसी HttpServer उदाहरण का उपयोग कर रहे हैं।

इस का मूल कारण यह है कि बैचिंग लेख/उदाहरण के कई (जैसे http://bradwilson.typepad.com/blog/2012/06/batching-handler-for-web-api.html) एक नई HttpServer बैचिंग के लिए मुख्य HttpServer कि HTTP अनुरोध से निपटने के अतिरिक्त बनाएँ; और HttpServer दोनों एक ही HttpConfiguration का उपयोग कर रहे हैं।

जब प्रत्येक HttpServer पहली बार यह अनुरोध प्राप्त आरंभ नहीं हो जाता है, यह एक सब के लिए कॉन्फ़िगर सौंपने के संचालकों पीछे (जैसे संचालकों, या अन्य प्रॉक्सी प्रकार संचालकों का पता लगाने), और पाइप लाइन को समाप्त द्वारा संचालकों की पाइपलाइन (HttpClientFactory.CreatePipeline में) बनाता है वेब एपीआई प्रेषक के साथ।

यदि आपके पास कोई प्रतिनिधि हैंडलर कॉन्फ़िगर नहीं है, तो यह समस्या आपको काट नहीं देगी - आपके पास 2 HttpServer ऑब्जेक्ट्स हो सकती हैं जो HttpConfiguration का उपयोग करती हैं।

लेकिन अगर आप किसी भी delegating संचालकों स्पष्ट या परोक्ष कॉन्फ़िगर नहीं होने (enabling Web API Tracing द्वारा जैसे) है, तो वेब एपीआई 2 पाइपलाइन का निर्माण नहीं कर सकते हैं - सौंपने के संचालकों को पहले से ही पहले पाइप लाइन में जुड़े हुए हैं - और यह अपवाद पर फेंक दिया जाता है पहले HttpServer पर पहला अनुरोध।

यह अपवाद बिल्कुल क्या हो रहा है इसके बारे में अधिक स्पष्ट होना चाहिए। अभी तक बेहतर, यह समस्या भी संभव नहीं होनी चाहिए - कॉन्फ़िगरेशन कॉन्फ़िगरेशन होना चाहिए, व्यक्तिगत हैंडलर नहीं।कॉन्फ़िगरेशन हैंडलर को प्रतिनिधि देने के लिए एक कारखाना हो सकता है। लेकिन मैं पीछे हटना ...

जबकि इस मुद्दे को यह पता लगाने की थोड़े कठिन है, वहाँ एक बहुत आसान ठीक है:

  1. आप Owin उपयोग कर रहे हैं, एक ही HttpServer पारित रूप में आप बैच हैंडलर में उपयोग करें के माध्यम से UseWebApi(this IAppBuilder builder, HttpServer httpServer);
  2. Owin पाइप लाइन के लिए आप आईआईएस + जाल एपीआई (कोई Owin स्टार्टअप वर्ग) का उपयोग कर रहे हैं, तो अपने बैच हैंडलर को GlobalConfiguration.DefaultServer पास, एक नया HttpServer

यहाँ बनाने से बचने के लिए एक उदाहरण Owin है स्टार्टअप क्लास जो एक HttpServer बनाता है और बैच हैंडलर और वेब एपीआई दोनों को पास करता है। यह उदाहरण ओडाटा बैच हैंडलर का उपयोग करता है:

[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

दिलचस्प! Startup.cs के डिफ़ॉल्ट 'सार्वजनिक शून्य विन्यास (IAppBuilder ऐप)' में (जहां डिफ़ॉल्ट रूप से OWIN डिफ़ॉल्ट रूप से कॉर्स और सह कॉन्फ़िगर करता है), मैं httpServer कैसे प्राप्त करूं? धन्यवाद –

+1

मेरे उत्तर में एक उदाहरण जोड़ा गया। – crimbo

+0

'UseWebApi' के बाद 'IOC' प्रारंभिक कॉल करें अन्यथा आपको त्रुटि मिल सकती है" एपीकंट्रोलर 'उदाहरण का पुन: उपयोग नहीं किया जा सकता है।' एपीकंट्रोलर 'को प्रत्येक आने वाले संदेश का निर्माण करना होगा। अपने कस्टम' IHttpControllerActivator 'की जांच करें और सुनिश्चित करें कि यह निर्माण नहीं करेगा एक ही उदाहरण। " मेरे मामले में वे 'UseAutofacMiddleware' और' UseAutofacWebApi' –

1

मुझे बैचिंग के बिना यह त्रुटि मिली है। मैंने अपने खुद के HttpClientFactory बनाए और यह HandlerFactory में भी मेरा स्वयं का है।

यह कन्स्ट्रक्टर में HandlerFactory.Create() विधि को कॉल करता है और परिणामी हैंडलर को संग्रहीत करता है।

जब भी फैक्ट्री को HttpClient बनाने की आवश्यकता होती है तो ये System.Net.Http.HttpClientFactory.Create(...) विधि पर पास की जाती हैं।

लेकिन यह केवल एक कॉल के लिए अच्छा है क्योंकि हैंडलर स्वयं को एक राज्य में छोड़कर .NET कोड द्वारा उत्परिवर्तित होते हैं जिसका अर्थ है कि उनका पुन: उपयोग नहीं किया जा सकता है।

मैंने अपने कन्स्ट्रक्टर को बदल दिया ताकि यह हैंडलर को सामने न बनाये, लेकिन हर बार। यह अब काम करता है।

संबंधित मुद्दे