2016-03-26 6 views
12

मैं एक एसओएपी सेवा के साथ इंटरफेसिंग पर काम कर रहा हूं जो डिफ़ॉल्ट नामस्थानों से निपटने के लिए प्रतीत नहीं होता है, लेकिन एसओएपी लिफाफा स्तर पर घोषित वैश्विक नामस्थानों और नामस्थान उपसर्गों के साथ ठीक काम करता है।डब्ल्यूसीएफ क्लाइंट: ग्लोबल नेमस्पेस को मजबूर करना

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

का उपयोग WCF उत्पादन इस तरह उत्पन्न दिखता है:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> 
    <s:Header> 
    <h:Security xmlns:h="http://docs.oasis-open.org/wss/2004/01/oasis- 
      ... 
    </h:Security> 
    </s:Header> 
    <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <cancelShipmentRequest xmlns="http://www.royalmailgroup.com/api/ship/V2"> 
     <integrationHeader> 
     <dateTime xmlns="http://www.royalmailgroup.com/integration/core/V1">2016-03-26T01:44:37.0493801Z</dateTime> 
     <version xmlns="http://www.royalmailgroup.com/integration/core/V1">2</version> 
     <identification xmlns="http://www.royalmailgroup.com/integration/core/V1"> 
      <applicationId>RMG-API-G-01</applicationId> 
      <transactionId>ozhckwej6sxg</transactionId> 
     </identification> 
     </integrationHeader> 
     <cancelShipments> 
     <shipmentNumber>TTT001908905GB</shipmentNumber> 
     </cancelShipments> 
    </cancelShipmentRequest> 
    </s:Body> 
</s:Envelope> 

जो काम नहीं करता।

निम्नलिखित सोप ​​लिफाफा (SoapUI में मैन्युअल रूप से) का उपयोग करना फिर भी काम करता है:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
    xmlns:oas="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" 
    xmlns:v2="http://www.royalmailgroup.com/api/ship/V2" 
    xmlns:v1="http://www.royalmailgroup.com/integration/core/V1"> 
    <soapenv:Header> 
    <h:Security xmlns:h="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
     ... 
    </h:Security> 
    </soapenv:Header> 
    <soapenv:Body> 
    <v2:cancelShipmentRequest> 
     <v2:integrationHeader> 
     <v1:dateTime>2016-03-02T14:55:00Z</v1:dateTime> 
     <v1:version>2</v1:version> 
     <v1:identification> 
      <v1:applicationId>RMG-API-G-01</v1:applicationId> 
      <v1:transactionId>wftdaife96gv</v1:transactionId> 
     </v1:identification> 
     </v2:integrationHeader> 
     <v2:cancelShipments> 
     <v2:shipmentNumber>TTT001908905GB</v2:shipmentNumber> 
     </v2:cancelShipments> 
    </v2:cancelShipmentRequest> 
    </soapenv:Body> 
</soapenv:Envelope> 

दोनों के बीच अंतर यह है कि v1 और v2 नामस्थान दस्तावेज़ के शीर्ष पर विश्व स्तर पर घोषित कर रहे हैं और वहाँ कोई नहीं है दूसरे दस्तावेज़ में स्थानीय नेमस्पेस घोषणाएं।

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

एकमात्र अंतर जो मैं बता सकता हूं वह यह है कि नामस्थान घोषित किए जाने का तरीका है। और हालांकि डब्ल्यूसीएफ संस्करण वैध और समान नामस्थान का उत्पादन प्रतीत होता है, सेवा अवैध नामस्थान संदर्भों के बारे में शिकायत करती है।

विफल स्कीमा सत्यापन: संदेश विफल स्कीमा सत्यापन: स्कीमा वैधता त्रुटि: तत्व 'xmlns': इस तत्व की अपेक्षा नहीं है। अपेक्षित है ({http://www.royalmailgroup.com/api/ship/V2} एकीकरण हेडर)।

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

कोई भी विचार जो मैं डब्ल्यूसीएफ को संदेश नाम मैन्युअल रूप से लिखने के बिना स्पष्ट नामस्थान उपसर्ग का उपयोग करने के लिए मजबूर करने का प्रयास कर सकता हूं?

+0

मेरे पास हाल ही में एक ही नाम था जो एक नए नामस्थान के साथ मौजूदा नामस्थान को मर्ज करने का प्रयास कर रहा था .. मैं निश्चित उत्तर नहीं दे सकता। मुझे जो मिला वह यह था कि मैंने विलय, पुनर्निर्माण, वीएस से बाहर निकलने के प्रयास को हटा दिए जाने के बाद, और फिर मौजूदा कोड को एकीकृत किया, सब ठीक थे। लंग जवाब, मैं सहमत हूं। मैंने निष्कर्ष निकाला कि यह वीएस में बग है, लेकिन एक रेपो परिदृश्य का प्रयास करने के लिए भी गड़बड़ है। शुभकामनाएं, और मैं आपकी स्थिति के बेहतर समाधान/उत्तर का इंतजार कर रहा हूं। – JamieMeyer

+1

क्या आपने [इस ब्लॉग पोस्ट] (http://vanacosmin.ro/Articles/Read/WCFEnvelopeNamespacePrefix) में सुझावों का प्रयास किया है, या [यह उत्तर] (http://stackoverflow.com/a/17798306/124386)? –

+0

धन्यवाद रिचर्ड। ब्लॉग पोस्ट सहायक था और मुझे सही दिशा में इंगित किया। –

उत्तर

7

तो इस समस्या का जवाब एक कस्टम IClientMessageFormatter और Message तो Message.OnWriteStartEnvelope() अधिभावी स्पष्ट रूप से साबुन दस्तावेज़ जड़ में सभी नामस्थान को लिखने के लिए बनाने के लिए किया गया था। प्रस्तुत दस्तावेज़, फिर बाल तत्वों पर स्पष्ट रूप से नामस्थान निर्दिष्ट करने के बजाय इन नामस्थानों का पुन: उपयोग करता है।

3 वर्गों काम करने के लिए इस के लिए बनाया जा करने के लिए कर रहे हैं:

  • संदेश कार्यान्वयन है कि वास्तविक OnWriteStartEnvelope()
  • IClientMessageFormatter है कि ग्राहक के प्रत्येक विधि के लिए संलग्न करने के लिए WCF
  • FormatMessageAttribute में झुका है संभालती है

    :

यहाँ तीनों के लिए कोड है

public class RoyalMailCustomMessage : Message 
{ 
    private readonly Message message; 

    public RoyalMailCustomMessage(Message message) 
    { 
     this.message = message; 
    } 
    public override MessageHeaders Headers 
    { 
     get { return this.message.Headers; } 
    } 
    public override MessageProperties Properties 
    { 
     get { return this.message.Properties; } 
    } 
    public override MessageVersion Version 
    { 
     get { return this.message.Version; } 
    } 

    protected override void OnWriteStartBody(XmlDictionaryWriter writer) 
    { 
     writer.WriteStartElement("Body", "http://schemas.xmlsoap.org/soap/envelope/"); 
    } 
    protected override void OnWriteBodyContents(XmlDictionaryWriter writer) 
    { 
     this.message.WriteBodyContents(writer); 
    } 
    protected override void OnWriteStartEnvelope(XmlDictionaryWriter writer) 
    { 
     writer.WriteStartElement("soapenv", "Envelope", "http://schemas.xmlsoap.org/soap/envelope/"); 
     writer.WriteAttributeString("xmlns", "oas", null, "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"); 
     writer.WriteAttributeString("xmlns", "v2", null, "http://www.royalmailgroup.com/api/ship/V2"); 
     writer.WriteAttributeString("xmlns", "v1", null, "http://www.royalmailgroup.com/integration/core/V1"); 
     writer.WriteAttributeString("xmlns", "xsi", null, "http://www.w3.org/2001/XMLSchema-instance"); 
     writer.WriteAttributeString("xmlns", "xsd", null, "http://www.w3.org/2001/XMLSchema");    
    } 
} 

public class RoyalMailMessageFormatter : IClientMessageFormatter 
{ 
    private readonly IClientMessageFormatter formatter; 

    public RoyalMailMessageFormatter(IClientMessageFormatter formatter) 
    { 
     this.formatter = formatter; 
    } 

    public Message SerializeRequest(MessageVersion messageVersion, object[] parameters) 
    { 
     var message = this.formatter.SerializeRequest(messageVersion, parameters); 
     return new RoyalMailCustomMessage(message); 
    } 

    public object DeserializeReply(Message message, object[] parameters) 
    { 
     return this.formatter.DeserializeReply(message, parameters); 
    } 
} 


[AttributeUsage(AttributeTargets.Method)] 
public class RoyalMailFormatMessageAttribute : Attribute, IOperationBehavior 
{ 
    public void AddBindingParameters(OperationDescription operationDescription, 
     BindingParameterCollection bindingParameters) 
    { } 

    public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation) 
    { 
     var serializerBehavior = operationDescription.Behaviors.Find<XmlSerializerOperationBehavior>(); 

     if (clientOperation.Formatter == null) 
      ((IOperationBehavior)serializerBehavior).ApplyClientBehavior(operationDescription, clientOperation); 

     IClientMessageFormatter innerClientFormatter = clientOperation.Formatter; 
     clientOperation.Formatter = new RoyalMailMessageFormatter(innerClientFormatter); 
    } 

    public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation) 
    { } 

    public void Validate(OperationDescription operationDescription) { } 
} 

इनमें से अधिकांश समारोह और बॉयलरप्लेट कोड है। कुंजी कोड टुकड़े OnWriteStartEnvelope हैं जहां वास्तविक नामस्थानों को हुक किया गया है, SerializeRequest जहां फ़ॉर्मेटर डब्लूसीएफ पाइपलाइन और ApplyClientBehavior में लगाया गया है जहां संदेश फ़ॉर्मेटर वास्तविक ऑपरेशन से जुड़ा हुआ है।

इसे हुक करने के लिए, मैंने सेवा इंटरफ़ेस पर क्लाइंट विधि में विशेषता जोड़ा - इस मामले में मेरे जेनरेट किए गए डब्ल्यूसीएफ क्लाइंट में Reference.cs में।

// CODEGEN: Generating message contract since the operation cancelShipment is neither RPC nor document wrapped. 
    [System.ServiceModel.OperationContractAttribute(Action="cancelShipment", ReplyAction="*")] 
    [System.ServiceModel.FaultContractAttribute(typeof(MarvelPress.Workflow.Business.RoyalShippingApi.exceptionDetails), Action="cancelShipment", Name="exceptionDetails")] 
    [System.ServiceModel.XmlSerializerFormatAttribute(SupportFaults=true)] 
    [System.ServiceModel.ServiceKnownTypeAttribute(typeof(contactMechanism))] 
    [System.ServiceModel.ServiceKnownTypeAttribute(typeof(baseRequest))] 
    [RoyalMailFormatMessage()] 
    MarvelPress.Workflow.Business.RoyalShippingApi.cancelShipmentResponse1 cancelShipment(MarvelPress.Workflow.Business.RoyalShippingApi.cancelShipmentRequest1 request); 

WCF से उत्पन्न संदेश अब देखो नामस्थान सभी दस्तावेज़ के शीर्ष पर परिभाषित के साथ के रूप में उम्मीद:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:oas="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:v2="http://www.royalmailgroup.com/api/ship/V2" xmlns:v1="http://www.royalmailgroup.com/integration/core/V1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <s:Header xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> 
    <h:Security>...</h:Security> 
    </s:Header> 
    <soapenv:Body> 
    <v2:cancelShipmentRequest> 
     <v2:integrationHeader> 
     <v1:dateTime>2016-04-02T01:04:50.4122473Z</v1:dateTime> 
     <v1:version>2</v1:version> 
     <v1:identification> 
      <v1:applicationId>RMG-API-G-01</v1:applicationId> 
      <v1:transactionId>fshrxevdnc7n</v1:transactionId> 
     </v1:identification> 
     </v2:integrationHeader> 
     <v2:cancelShipments> 
     <v2:shipmentNumber>TTT001908905GB</v2:shipmentNumber> 
     </v2:cancelShipments> 
    </v2:cancelShipmentRequest> 
    </soapenv:Body> 
</soapenv:Envelope>  

अधिक जानकारी और एक सामान्य नाम स्थान जोड़ने फ़ॉर्मेटर बाहर की जांच यहाँ मेरी संबंधित ब्लॉग पोस्ट के लिए : http://weblog.west-wind.com/posts/2016/Apr/02/Custom-Message-Formatting-in-WCF-to-add-all-Namespaces-to-the-SOAP-Envelope

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