2016-11-08 67 views
1

我正在編寫使用XmlSerializer的WCF服務。該服務是一個基於WSDL和一個XSD的實現,這個XSD是從將要使用該服務的組提供給我的。基本上它是他們的系統和我的系統之間的數據適配器。爲數組屬性指定xsi:type

一個特定的類有一個屬性,該屬性是項目中定義的另一個引用類型的數組。我需要爲此屬性指定xsi:type

我使用svcutil從WSDL和XSD生成代碼,然後在幾個地方「固定」生成的代碼。這個屬性是我必須修復的。

的類定義是(修剪下降到只有問題區域):

[GeneratedCode("svcutil", "4.6.1055.0")] 
[Serializable] 
[DebuggerStepThrough] 
[DesignerCategory("code")] 
[XmlType(Namespace = "urn:example.com:types")] 
public class userData 
{ 
    private ItemType[] itemTypeField; 

    [XmlArray(Order = 0, Namespace = "urn:example.com:types")] 
    [XmlArrayItem("item", IsNullable = false, Type = typeof(ItemType), Namespace = "urn:example.com:types")] 
    public ItemType[] myprop 
    { 
     get { return itemTypeField; } 
     set { itemTypeField = value; } 
    } 
} 

被調用服務的方法時產生的XML是(userDatagetUserResponse類的屬性):

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> 
    <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
     <getUserResponse xmlns="urn:example.com:types"> 
     <userData> 
      <myprop> 
       <item> 
        <key>some key</key> 
        <value>some value</value> 
       </item> 
       <item> 
        <key>some other key</key> 
        <value>some other value</value> 
       </item> 
      </myprop> 
     </userData> 
     </getUserResponse> 
    </s:Body> 
</s:Envelope> 

我需要<myprop>元素看起來像這樣:

<myprop xsi:type="ns1:MapType" 
    xmlns:ns1="urn:example.com:types" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 

如何獲取XmlSerializer爲陣列屬性myprop生成xsi:type

我發現這些類似的問題作爲最接近我的問題,但他們並不適用於數組:
xsi type and xsd tag
How can I force the use of an xsi:type attribute?

我需要用自定義序列做到這一點?

請讓我知道,如果我需要張貼任何服務合同。服務中的其他一切都運行良好,只是這一點點而已。

回答

0

我找不到任何使用任何內置機制(屬性,配置等)來完成此操作的方法,因此我最終編寫了自定義消息檢查器,以便在響應中發送之前即時更改XML 。下面是代碼:

定製Ispector - 執行XML重寫添加所需的標記

using System.IO; 
using System.ServiceModel; 
using System.ServiceModel.Channels; 
using System.ServiceModel.Dispatcher; 
using System.Xml; 

namespace MyProj 
{ 
    public class CustomInspector : IDispatchMessageInspector 
    { 
     public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext) 
     { 
      return null; 
     } 

     public void BeforeSendReply(ref Message reply, object correlationState) 
     { 
      if (reply.Headers.Action == "urn:example:wsdl/Adapter/getUserResponse") 
      { 
       MessageBuffer copy = reply.CreateBufferedCopy(int.MaxValue); 
       XmlDictionaryReader xdr = copy.CreateMessage().GetReaderAtBodyContents(); 
       XmlDocument doc = new XmlDocument(); 
       doc.Load(xdr); 
       xdr.Close(); 

       doc.InnerXml = doc.InnerXml.Replace(@"<myprop>", 
        @"<myprop xsi:type=""ns1:MapType"" xmlns:ns1=""urn:example.com:types"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"">"); 
       doc.InnerXml = doc.InnerXml.Replace(@"<item>", @"<item xmlns=""urn:example.com:types"">"); 

       MemoryStream ms = new MemoryStream(); 
       XmlWriter xw = XmlWriter.Create(ms); 
       doc.Save(xw); 
       xw.Flush(); 
       xw.Close(); 
       ms.Position = 0; 
       XmlReader reader = XmlReader.Create(ms); 


       Message newMsg = Message.CreateMessage(reply.Version, reply.Headers.Action, reader); 
       reply = newMsg; 
      } 

     } 
    } 
} 

自定義端點行爲 - 附加新的消息檢查到服務端點:

using System.ServiceModel.Channels; 
using System.ServiceModel.Description; 
using System.ServiceModel.Dispatcher; 

namespace MyProj 
{ 
    public class CustomBehavior : IEndpointBehavior 
    { 
     public void Validate(ServiceEndpoint endpoint) 
     { 
     } 

     public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) 
     { 
     } 

     public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) 
     { 
      endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new CustomInspector()); 
     } 

     public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) 
     { 
     } 
    } 
} 

定製行爲擴展元素 - 定義新行爲

using System; 
using System.ServiceModel.Configuration; 

namespace KeypadIdmAdaptor 
{ 
    public class CustomBehaviorExtensionElement : BehaviorExtensionElement 
    { 
     protected override object CreateBehavior() 
     { 
      return new CustomBehavior(); 
     } 

     public override Type BehaviorType 
     { 
      get { return typeof(CustomBehavior); } 
     } 
    } 
} 

電線它在web.config中:

<system.serviceModel> 
    <extensions> 
     <behaviorExtensions> 
     <add name="CustomBehaviorExtension" type="MyProj.CustomBehaviorExtensionElement, MyProj, Version=1.0.0.0, Culture=neutral" /> 
     </behaviorExtensions> 
    </extensions> 
    <behaviors> 
     <endpointBehaviors> 
     <behavior> 
      <CustomBehaviorExtension /> 
     </behavior> 
     </endpointBehaviors> 
     <serviceBehaviors> 
     <behavior> 
      <serviceMetadata httpGetEnabled="true" httpsGetEnabled="false" /> 
      <serviceDebug includeExceptionDetailInFaults="false" /> 
     </behavior> 
     </serviceBehaviors> 
    </behaviors> 
    <services> 
     <service name="MyProj.MyService"> 
     <endpoint binding="mexHttpBinding" address="mex" contract="IMetadataExchange"></endpoint> 
     <endpoint name="MyServiceEndpoint" binding="basicHttpBinding" contract="MyProjServiceContract"></endpoint> 
     </service> 
    </services> 
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" /> 
    </system.serviceModel> 

這裏是在響應消息中所產生的XML:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> 
    <s:Body> 
     <getUserResponse xmlns="urn:example.com:types"> 
     <userData> 
      <myProp xsi:type="ns1:MapType" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns1="urn:example.com:types"> 
       <item> 
        <key>some key</key> 
        <value>some value</value> 
       </item> 
       <item> 
        <key>some other key</key> 
        <value>some other value</value> 
       </item> 
      </myProp > 
     </userData> 
     </getUserResponse> 
    </s:Body> 
</s:Envelope>