我正在编写使用XmlSerializer的WCF服务。该服务是基于WSDL和XSD的实现,该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>
我需要<myprop>
元素看起来像这样:
<myprop xsi:type="ns1:MapType"
xmlns:ns1="urn:example.com:types"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
如何让XmlSerializer为数组属性xsi:type
生成myprop
?
我发现这些类似的问题与我的问题最接近,但它们不适用于数组:
xsi type and xsd tag
How can I force the use of an xsi:type attribute?
我是否需要使用自定义序列化程序执行此操作?
如果我需要发布任何服务合同,请告诉我。服务中的其他所有工作都很好,只是这一点。
答案 0 :(得分:0)
我找不到使用任何内置机制(属性,配置等)的任何方法,所以我最终编写了一个自定义消息检查器,以便在响应中发送之前动态更改XML。这是代码:
Custom 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>