2016-07-06 4 views
8

मैं अपने शोकहारा WCF सेवा के निर्माता के भीतर फेंक दिया प्राधिकरण अपवाद को संभालने के लिए IErrorHandler को लागू किया है है। जब एक सामान्य अपवाद पकड़ा है अपने कस्टम प्रकार की उम्मीद के रूप में लौटा है, लेकिन ContentType हेडर गलत है।IErrorHandler गलत संदेश के मुख्य भाग लौटने जब HTTP स्थिति कोड 401 अनधिकृत

HTTP/1.1 500 Internal Server Error 
Content-Type: application/xml; 
... 

{"ErrorMessage":"Error!"} 

लेकिन जब त्रुटि हैंडलर एक 401 अनधिकृत HTTP स्थिति कोड संदेश के मुख्य भाग डिफ़ॉल्ट प्रकार लेकिन ContentType शीर्षक के ओवरराइड की गई है है के रूप में यह होना चाहिए वापस जाने के लिए कोशिश करता है।

HTTP/1.1 401 Unauthorized 
Content-Type: application/json; 
... 

{"Message":"Authentication failed.","StackTrace":null,"ExceptionType":"System.InvalidOperationException"} 

जाहिर है कुछ यहाँ गलत है, लेकिन मुझे यकीन है कि क्या नहीं कर रहा हूँ।

मैं आईररहैंडलर को कैसे कार्यान्वित कर सकता हूं जैसे कि यह सही हेडर के साथ जेसन में अपना कस्टम प्रकार देता है?

BaseDataResponseContract वस्तु:

[Serializable] 
[DataContract(Name = "BaseDataResponseContract")] 
public class BaseDataResponseContract 
{ 
    [DataMember] 
    public string ErrorMessage { get; set; } 

} // end 

इस वस्तु मैं वापस जाने के लिए चाहते हैं। मेरे आवेदन में अन्य सभी ऑब्जेक्ट्स इस ऑब्जेक्ट से प्राप्त होते हैं। जब कोई अपवाद फेंक दिया जाता है तो हम वास्तव में http स्थिति कोड और त्रुटि संदेश की परवाह करते हैं।

IErrorHandler कार्यान्वयन (प्रवेश संक्षिप्तता के लिए नहीं दिखाया गया है):

namespace WebServices.BehaviorsAndInspectors 
{ 
    public class ErrorHandler : IErrorHandler 
    { 
     public bool HandleError(Exception error) 
     { 
      return true; 

     } // end 

     public void ProvideFault(Exception ex, MessageVersion version, ref Message fault) 
     { 
      // Create a new instance of the object I would like to return with a default message 
      var baseDataResponseContract = new BaseDataResponseContract { ErrorMessage = "Error!" }; 

      // Get the outgoing response portion of the current context 
      var response = WebOperationContext.Current.OutgoingResponse; 

      // Set the http status code 
      response.StatusCode = HttpStatusCode.InternalServerError; 

      // If the exception is a specific type change the default settings 
      if (ex.GetType() == typeof(UserNotFoundException)) 
      { 
       baseDataResponseContract.ErrorMessage = "Invalid Username!"; 
       response.StatusCode = HttpStatusCode.Unauthorized; 
      }  

      // Create the fault message that is returned (note the ref parameter) 
      fault = Message.CreateMessage(version, "", baseDataResponseContract, new DataContractJsonSerializer(typeof(BaseDataResponseContract))); 

      // Tell WCF to use JSON encoding rather than default XML 
      var webBodyFormatMessageProperty = new WebBodyFormatMessageProperty(WebContentFormat.Json); 
      fault.Properties.Add(WebBodyFormatMessageProperty.Name, webBodyFormatMessageProperty); 

      // Add ContentType header that specifies we are using json 
      var httpResponseMessageProperty = new HttpResponseMessageProperty(); 
      httpResponseMessageProperty.Headers[HttpResponseHeader.ContentType] = "application/json"; 
      fault.Properties.Add(HttpResponseMessageProperty.Name, httpResponseMessageProperty); 

     } // end 

    } // end class 

} // end namespace 

IServiceBehavior कार्यान्वयन:

namespace WebServices.BehaviorsAndInspectors 
{ 
    public class ErrorHandlerExtensionBehavior : BehaviorExtensionElement, IServiceBehavior 
    { 
     public override Type BehaviorType 
     { 
      get { return GetType(); } 
     } 

     protected override object CreateBehavior() 
     { 
      return this; 
     } 

     private IErrorHandler GetInstance() 
     { 
      return new ErrorHandler(); 
     } 

     void IServiceBehavior.AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters) { } // end 

     void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) 
     { 
      var errorHandlerInstance = GetInstance(); 

      foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers) 
      { 
       dispatcher.ErrorHandlers.Add(errorHandlerInstance); 
      } 
     } 

     void IServiceBehavior.Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { } // end 

    } // end class 

} // end namespace 

Web.Config:

<system.serviceModel> 

    <services>  
     <service name="WebServices.MyService"> 
     <endpoint binding="webHttpBinding" contract="WebServices.IMyService" /> 
     </service> 
    </services> 

    <extensions>  
     <behaviorExtensions>   
     <!-- This extension if for the WCF Error Handling--> 
     <add name="ErrorHandlerBehavior" type="WebServices.BehaviorsAndInspectors.ErrorHandlerExtensionBehavior, WebServices, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />  
     </behaviorExtensions>  
    </extensions> 

    <behaviors>   
     <serviceBehaviors>   
     <behavior> 
      <serviceMetadata httpGetEnabled="true"/> 
      <serviceDebug includeExceptionDetailInFaults="true"/> 
      <ErrorHandlerBehavior /> 
     </behavior>  
     </serviceBehaviors>  
    </behaviors> 

    .... 
</system.serviceModel> 

अंत में, मैं समान व्यवहार देख रहा हूँ WebFaultException का उपयोग करते समय। मेरा विचार यह है कि यह कुछ गहराई से दफन किया गया है। नेट शेन्नीगन्स। मैं इतना है कि मैं किसी अन्य अपवाद नहीं संभाला जा सकता है पकड़ कर सकते हैं IErrorHandler लागू करने के लिए चुनने कर रहा हूँ।

संदर्भ:

https://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.ierrorhandler(v=vs.100).aspx

http://www.brainthud.com/cards/5218/25441/which-four-behavior-interfaces-exist-for-interacting-with-a-service-or-client-description-what-methods-do-they-implement-and

अन्य उदाहरण:

IErrorHandler doesn't seem to be handling my errors in WCF .. any ideas?

How to make custom WCF error handler return JSON response with non-OK http code?

How do you set the Content-Type header for an HttpClient request?

उत्तर

0

लगभग पूरे दिन के लिए संघर्ष करने के बाद मुझे पता चला कि यह आईआईएस सेटिंग के कारण हुआ था।

प्रमाणीकरण मेनू के तहत आईआईएस में मेरे एपीआई प्रोजेक्ट के तहत मेरे पास 'फॉर्म प्रमाणीकरण' सेट 'सक्षम' था। मैंने इस 'फीचर' को बंद कर दिया और उपर्युक्त कोड अपेक्षित काम करना शुरू कर दिया। मैंने पाया कि यह मेरी टीम पर एक अन्य डेवलपर के कारण था जो web.config फ़ाइल में कोड डाल रहा था जो आईआईएस में सेटिंग्स को बदल देता था। विशेष रूप से:

<?xml version="1.0" encoding="utf-8"?> 
<configuration> 
    ... 
    <system.web> 
     <authentication mode="Forms" /> 
    </system.web> 
    ... 
</configuration> 

इसके अलावा, मैं WebOperationContext OutgoingResponse वस्तु पर ContentType संपत्ति का उपयोग करके सही ढंग से प्रदर्शित करने के ContentType हेडर प्राप्त करने में सक्षम था।

// Get the outgoing response portion of the current context 
var response = WebOperationContext.Current.OutgoingResponse; 

// Add ContentType header that specifies we are using JSON 
response.ContentType = new MediaTypeHeaderValue("application/json").ToString(); 
0

मैं काफी यकीन है कि कैसे अपने आवेदन कार्यान्वित किया जाता है नहीं कर रहा हूँ। अपने विवरण के आधार पर, मैं दृश्य स्टूडियो का उपयोग कर अपने ErrorHandler डिबग करने के लिए देखने के लिए अपवाद अपने कॉलबैक आने कि क्या सुझाव देते हैं।

यदि हाँ, तो मैन्युअल रूप से अपने साबुन गलती या जिस तरह से आप चाहते हैं में प्रतिक्रिया का निर्माण।

यदि नहीं, तो इसका मतलब है कि आपके सेवा संचालन के आने से पहले अपवाद होता है, यह पहले से ही चैनल स्टैक में असफल हो सकता है, इस मामले में, एक आसान दृष्टिकोण अतिरिक्त एचटीपी मॉड्यूल को कस्टम या प्रतिक्रिया को मैप करने के लिए जोड़ता है। या आप चैनल स्टैक में एन्कोडर को कस्टम करने का प्रयास कर सकते हैं।

+0

हाँ ... लेकिन कैसे? मुझे WebOperationContext.current.OutgoingResponse के साथ एक ही प्रोजेम मिला है लेकिन मुझे इसमें कोई लिखें विधि नहीं है, तो कस्टम प्रतिक्रिया कैसे बनाएं? – DestyNova

0

आपके द्वारा लिखे गए आधार पर आधार, आप सेवा कार्यान्वयन के निर्माता में अपवाद फेंक देते हैं। चूंकि डब्ल्यूसीएफ आपकी सेवा कार्यान्वयन के लिए प्रतिबिंब का उपयोग करता है, जब तक कि आपकी सेवा सिंगलटन न हो, आपको एक लक्ष्यInvocationException मिलेगा।

उदाहरण (उपयोग LINQPad):

void Main() 
{ 
    try 
    { 
     Activator.CreateInstance(typeof(Foo)); 
    } 
    catch(Exception e) 
    { 
     e.Message.Dump(); 
     e.GetType().Name.Dump(); 
    } 
} 

public class Foo 
{ 
    public Foo() 
    { 
     throw new AuthorizationFailedException(); 
    } 
} 

public class AuthorizationFailedException : Exception 
{ 

} 

असल में, एक निर्माता में व्यापार तर्क के आधार पर अपवाद फेंकने से बचें। केवल प्रोग्रामिंग त्रुटियों को संभालने के लिए ऐसा करें।

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