2012-09-26 15 views
8

कहा जाता है, मैं डब्ल्यूसीएफ में लागू एक आरईएसटी सेवा के लिए प्रमाणीकरण को लागू करने और Azure पर होस्ट करने का प्रयास कर रहा हूं। मैं प्रमाणीकरण Request, PostAuthenticationRequest और EndRequest घटनाओं को संभालने के लिए HttpModule का उपयोग कर रहा हूं। अगर प्राधिकरण शीर्षलेख गुम है या यदि उसमें निहित टोकन अमान्य है, तो EndRequest के दौरान मैं 401 पर प्रतिक्रिया पर स्टेटस कोड स्थापित कर रहा हूं। हालांकि, मैंने यह निर्धारित किया है कि एंड्रॉक्वेट को दो बार बुलाया जाता है, और दूसरी कॉल पर प्रतिक्रिया में पहले से ही हेडर होते हैं सेट करें, जो कोड को स्टेटसोड को अपवाद फेंकने के लिए सेट करता है।HttpModule EndRequest हैंडलर को दो बार

मैंने यह सुनिश्चित करने के लिए इनक() में ताले जोड़े हैं कि हैंडलर को दो बार पंजीकृत नहीं किया जा रहा था; अभी भी दो बार भाग गया। Init() भी दो बार भाग गया, यह दर्शाता है कि HttpModule के दो उदाहरण बनाए जा रहे थे। हालांकि, वीएस डीबगर में सेट ऑब्जेक्ट आईडी का उपयोग करना इंगित करता है कि अनुरोध वास्तव में अलग-अलग अनुरोध हैं। मैंने फिडलर में सत्यापित किया है कि ब्राउज़र से मेरी सेवा के लिए केवल एक ही अनुरोध जारी किया जा रहा है।

यदि मैं डब्ल्यूसीएफ सेवा होस्ट कॉन्फ़िगरेशन के आधार पर ग्लोबल.एक्सएक्स रूटिंग का उपयोग करने के लिए स्विच करता हूं, तो हैंडलर को केवल एक बार बुलाया जाता है और सब कुछ ठीक काम करता है।

यदि मैं system.web कॉन्फ़िगरेशन अनुभाग के साथ-साथ system.web सर्वर कॉन्फ़िगरेशन अनुभाग में कॉन्फ़िगरेशन को जोड़ता हूं, तो हैंडलर को केवल एक बार बुलाया जाता है और सब कुछ ठीक काम करता है।

तो मेरे पास कमजोरियां हैं, लेकिन मैं वास्तव में व्यवहार से नापसंद हूं जिसे मैं समझ नहीं पा रहा हूं। हैंडलर को दो बार क्यों बुलाया जाता है?

Web.config:

यहाँ समस्या का एक न्यूनतम रेप्रो है

<system.web> 
    <compilation debug="true" targetFramework="4.0" /> 
    <!--<httpModules> 
     <add name="AuthModule" type="TestWCFRole.AuthModule, TestWCFRole"/> 
    </httpModules>--> 
    </system.web> 
    <system.serviceModel> 
    <behaviors> 
     <endpointBehaviors> 
     <behavior name="WebBehavior"> 
      <webHttp/> 
     </behavior> 
     </endpointBehaviors> 
     <serviceBehaviors> 
     <behavior> 
      <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment --> 
      <serviceMetadata httpGetEnabled="true" /> 
      <!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information --> 
      <serviceDebug includeExceptionDetailInFaults="true"/> 
     </behavior> 
     </serviceBehaviors> 
    </behaviors> 
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true" /> 
    <services> 
     <service name="TestWCFRole.Service1"> 
     <endpoint binding="webHttpBinding" name="RestEndpoint" contract="TestWCFRole.IService1" bindingConfiguration="HttpSecurityBinding" behaviorConfiguration="WebBehavior"/> 
     <host> 
      <baseAddresses> 
      <add baseAddress="http://localhost/" /> 
      </baseAddresses> 
     </host> 
     </service> 
    </services> 
    <standardEndpoints> 
     <webHttpEndpoint> 
     <standardEndpoint name="" helpEnabled="true" automaticFormatSelectionEnabled="true"/> 
     </webHttpEndpoint> 
    </standardEndpoints> 
    <bindings> 
     <webHttpBinding> 
     <binding name="HttpSecurityBinding" > 
      <security mode="None" /> 
     </binding> 
     </webHttpBinding> 
    </bindings> 
    </system.serviceModel> 
    <system.webServer> 
    <modules runAllManagedModulesForAllRequests="true"> 
     <add name="AuthModule" type="TestWCFRole.AuthModule, TestWCFRole"/> 
    </modules> 
    <directoryBrowse enabled="true"/> 
    </system.webServer> 

Http मॉड्यूल:

using System; 
using System.Web; 

namespace TestWCFRole 
{ 
    public class AuthModule : IHttpModule 
    { 
     /// <summary> 
     /// You will need to configure this module in the web.config file of your 
     /// web and register it with IIS before being able to use it. For more information 
     /// see the following link: http://go.microsoft.com/?linkid=8101007 
     /// </summary> 
     #region IHttpModule Members 

     public void Dispose() 
     { 
      //clean-up code here. 
     } 

     public void Init(HttpApplication context) 
     { 
      // Below is an example of how you can handle LogRequest event and provide 
      // custom logging implementation for it 
      context.EndRequest += new EventHandler(OnEndRequest); 
     } 

     #endregion 

     public void OnEndRequest(Object source, EventArgs e) 
     { 
      HttpContext.Current.Response.StatusCode = 401; 
     } 
    } 
} 
+0

आप अपने आवेदन में UrlRewrite उपयोग करते हैं? ऐसा लगता है कि यह एंड्रॉवेस्ट को दो बार आग लगने का कारण बनता है। –

+0

क्या यह पृष्ठभूमि में सक्षम है? मेरे पास urlRrriteModule मेरे web.config में नहीं है। –

+0

मुझे ऐसा नहीं लगता है। यह वास्तव में अजीब है, क्योंकि मैं यह नहीं कह सकता कि मेरी सभी समस्या UrlRewiteModule के कारण होती है। लेकिन उनमें से कुछ हैं। –

उत्तर

2

क्षमा करें कोई संकेत नहीं कि इसे दो बार क्यों कहा जा सकता है, हालांकि EndRequest कई कारणों से बुलाया जा सकता है। अनुरोध समाप्त हो गया, अनुरोध निरस्त कर दिया गया, कुछ त्रुटि हुई। तो मैं यह मानने में मेरा विश्वास नहीं लगाऊंगा कि यदि आप वहां जाते हैं, तो आपके पास वास्तव में 401 है, यह अन्य कारणों से हो सकता है।

मैं सिर्फ AuthenticateRequest पाइप लाइन में मेरी तर्क रखना चाहते हैं:

public class AuthenticationModule : IHttpModule 
    { 
     public void Dispose() { } 

     public void Init(HttpApplication context) 
     { 
      context.AuthenticateRequest += Authenticate; 
     } 

     public static void Authenticate(object sender, EventArgs e) 
     { 
      // authentication logic here    
      //............. 

      if (authenticated) { 
       HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(myUser, myRoles); 
      } 

      // failure logic here   
      //.............   
     } 
    } 
+0

हाँ, मुझे नहीं पता कि मुझे यह क्यों नहीं पता था कि मुझे इससे पहले कैसे आना चाहिए (मुझे लगता है कि मैंने सोचा होगा कि मैं जिस नमूना का उपयोग कर रहा था वह इसे "सही" कर रहा था), लेकिन अंततः मैंने तर्क को प्रमाणीकरण में प्रवेश किया , PostAuthenticateRequest और AuthorizeRequest खंड। दुर्भाग्यवश, यह सवाल का जवाब नहीं देता है कि हैंडलर इस तरह से क्यों व्यवहार करता है। –

7

जब एक ASP.net आवेदन प्रदर्शन को अधिकतम करने, शुरू होता है एएसपी.नेट वर्कर प्रक्रिया जितनी जरूरत हो उतनी HttpApplication ऑब्जेक्ट्स को तुरंत चालू करेगी। प्रत्येक HttpApplication ऑब्जेक्ट, प्रत्येक IHttpModule की एक प्रति को तुरंत चालू करेगा जो कि पंजीकृत है और इनिट विधि को कॉल करें! यह वास्तव में आईआईएस (या कैसिनी जो वेबसर्वर में निर्मित वीएस है) के तहत चल रही एएसपी.NET प्रक्रिया का आंतरिक डिजाइन है। हो सकता है क्योंकि आपके एएसपीएक्स पेज में अन्य संसाधनों के लिंक हैं जो आपका ब्राउज़र डाउनलोड करने का प्रयास करेगा, बाहरी संसाधन, और आईफ्रेम, एक सीएसएस फ़ाइल, या शायद एएसपी.नेट वर्कर प्रक्रिया व्यवहार।

सौभाग्य से यह Global.asax के लिए ऐसा नहीं है:

Here's from MSDN:

Application_Start और Application_End तरीकों विशेष तरीकों कि HttpApplication घटनाओं का प्रतिनिधित्व नहीं करते हैं। एएसपी.नेट उन्हें को एप्लिकेशन डोमेन के जीवनकाल के लिए एक बार कॉल करता है, प्रत्येक एचटीपी अनुप्रयोग उदाहरण के लिए नहीं।

हालांकि HTTPModule's init विधि के बाद सभी मॉड्यूल

पहली बार एक ASP.NET पेज बनाया गया है या प्रक्रिया एक आवेदन में अनुरोध किया गया है HttpApplication वर्ग के प्रत्येक उदाहरण के एक बार कहा जाता है, एक नया Http अनुप्रयोग का उदाहरण बनाया गया है।हालांकि, प्रदर्शन को अधिकतम करने के लिए, Http अनुप्रयोग उदाहरणों को एकाधिक अनुरोधों के लिए पुन: उपयोग किया जा सकता है।

और निम्न आरेख द्वारा सचित्र: enter image description here

आप कोड सिर्फ एक बार चलाने के लिए गारंटी है कि चाहते हैं, आप Global.asax की Application_Start उपयोग कर सकते हैं या एक ध्वज सेट और अंतर्निहित मॉड्यूल में यह ताला जो ऐसा नहीं लगता कि प्रमाणीकरण के लिए एक अच्छा अभ्यास है!

+0

मैं बस सेटिंग 'runAllManagedModulesForAllRequests = "true" 'स्थिर फ़ाइलों (जेएस/सीएसएस/छवियों) सहित प्रत्येक अनुरोध के लिए कस्टम मॉड्यूल निष्पादित करने का कारण बनता है। इसलिए केवल एक पृष्ठ लोड के लिए दो बार उस सेटअप के साथ मेरे लिए बहुत कम लगता है। – astaykov

+0

मुझे एक बार चलाने के लिए कोड की आवश्यकता नहीं है; समस्या यह है कि मैं सेवा के लिए एक अनुरोध के लिए दो EndRequests देखता हूं। यह जेएस/सीएसएस/छवियां नहीं होनी चाहिए, क्योंकि यह एक सेवा है, न कि वेब पेज। मैं फिडलर में देख सकता हूं कि केवल एक ही अनुरोध किया जा रहा है। सवाल यह है कि मुझे फिडलर के माध्यम से एक ही अनुरोध क्यों दिखाई देता है लेकिन मॉड्यूल में दो अनुरोध, और यदि मैं web.config में कॉन्फ़िगरेशन को डुप्लिकेट करता हूं तो यह समस्या क्यों दूर हो जाती है। –

+0

आम तौर पर आपको कॉन्फ़िगरेशन को डुप्लिकेट करने की आवश्यकता नहीं है, यदि आप IIS7 + का उपयोग कर रहे हैं तो कॉन्फ़िगरेशन 'system.webServer' सेक्शन में सेट होना चाहिए! मॉड्यूल के 'इनिट' विधि को एक बार बुलाया जाता है जबकि 'EndRequest' को एक ही अनुरोध के लिए दो बार बुलाया जाता है? क्योंकि 'EndRequest' प्रति अनुरोध दो बार नहीं कहा जा सकता है! हालांकि मुझे लगता है कि आप अपने डब्ल्यूसीएफ होस्ट कॉन्फ़िगरेशन में 'aspNetCompatibilityEnabled' को सक्षम कर रहे हैं, आप किस वेबसर्वर के साथ परीक्षण कर रहे हैं? आईआईएस? आईआईएस एक्सप्रेस? वीएस वेब सर्वर? आईआईएस में आप अपने डब्ल्यूसीएफ की मेजबानी कैसे करते हैं? एक 'WebServiceHost'? '.svc' फ़ाइल? क्या आप EndRequest में 'HttpContext.Current.Request.Path' पोस्ट कर सकते हैं? –

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