2016-11-08 2 views
1

Я пишу службу WCF, которая использует XmlSerializer. Служба представляет собой реализацию на основе WSDL и 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, который производится при вызове метода обслуживания является (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

Я не мог найти никакого способа сделать это, используя какой-либо встроенный механизм (атрибуты, конфиг и т. Д.), Поэтому я закончил писать инспектор сообщений для изменения 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; 
      } 

     } 
    } 
} 

Пользовательские Endpoint Behavior - придает новое сообщение инспектору обслуживания конечной точки:

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> 
Смежные вопросы