【问题标题】:Specify xsi:type for array property为数组属性指定 xsi:type
【发布时间】:2016-11-08 22:51:06
【问题描述】:

我正在编写一个使用 XmlSerializer 的 WCF 服务。该服务是基于 WSDL 和一个 XSD 的实现,它是由将使用该服务的小组提供给我的。基本上它是他们的系统和我的系统之间的数据适配器。

一个特定类的属性是项目中定义的另一种引用类型的数组。我需要为此属性指定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是(userData是getUserResponse类的一个属性):

<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>

我需要&lt;myprop&gt; 元素看起来像这样:

<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?

我需要使用自定义序列化程序吗?

如果我需要发布任何服务合同,请告诉我。服务中的其他一切都运行良好,只是一点点。

【问题讨论】:

    标签: c# wcf xmlserializer


    【解决方案1】:

    我找不到使用任何内置机制(属性、配置等)的任何方法,所以我最终编写了一个自定义消息检查器来在响应中发送 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>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-11-19
      • 1970-01-01
      • 2015-10-24
      • 1970-01-01
      • 1970-01-01
      • 2014-04-25
      • 2011-04-20
      相关资源
      最近更新 更多