[英]Java serialization vs .NET serialization
我們正在合作的Java商店供應商需要我們(.NET商店)提供符合他們發送給我們的WSDL的RESTful服務。 我們返回的XML與供應商的期望之間存在一些差異。 我的過程從根本上講是錯誤的,還是Java和.NET進行序列化的方式只是不同?
我的過程:
該合同第一個想法是新的給我,但在這樣的職位上覆蓋好這個 。 因此,只要具備一點知識,我就可以通過SvcUtil.exe運行WSDL和關聯的.XSD來生成C#(下面的一些相關摘錄),並且我將這些類型用作服務的返回類型。
我也嘗試使用生成的代碼wsdl.exe
和xsd.exe
,但也顯著改變的結果。
區別:
結果和代碼摘錄:
供應商希望該服務返回如下所示的消息:
<?xml version="1.0" encoding="UTF-8"?>
<gms:GetClassificationResponse xmlns:gms="http://vendor.com/metadata/cms/services/integration/gms" xmlns:class="http://vendor.com/metadata/model/classification" xmlns:core="http://vendor.com/metadata/model/core" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://vendor.com/metadata/cms/services/integration/gms ../gms_services.xsd">
<class:ClassificationVersion>
<class:Code codeValue="01">
<Name core:type="Preferred">Northland Region</Name>
<class:Code codeValue="001">
<Name core:type="Preferred">Far North District</Name>
<class:Code codeValue="500206">
<Name core:type="Preferred">North Cape</Name>
</class:Code>
<class:Code codeValue="500207">
<Name core:type="Preferred">Houhora</Name>
</class:Code>
<!-- Truncated -->
</class:Code>
<class:Code codeValue="002">
<Name core:type="Preferred">Whangarei District</Name>
<!-- Children omitted -->
</class:Code>
<!-- Truncated -->
</class:Code>
<class:Code codeValue="02">
<Name core:type="Preferred">Auckland Region</Name>
<!-- Children omitted -->
</class:Code>
<!-- Truncated -->
</class:ClassificationVersion>
</gms:GetClassificationResponse>
我們正在產生這樣的結果:
<GetClassificationResponseType xmlns="http://schemas.datacontract.org/2004/07/metadata.cms.services.integration.gms" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<ClassificationVersion>
<actionField>ADD</actionField>
<actionFieldSpecified>false</actionFieldSpecified>
<anyAttrField xmlns:a="http://schemas.datacontract.org/2004/07/System.Xml" i:nil="true"/>
<descriptionField i:nil="true"/>
<detailField>full</detailField>
<idField i:nil="true"/>
<itemsField xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays" i:nil="true"/>
<lastUpdateField>0001-01-01T00:00:00</lastUpdateField>
<lastUpdateFieldSpecified>false</lastUpdateFieldSpecified>
<nameField i:nil="true"/>
<uriField i:nil="true"/>
<isPreferredField>false</isPreferredField>
<itemField i:nil="true"/>
<validFromField>0001-01-01T00:00:00</validFromField>
<validFromFieldSpecified>false</validFromFieldSpecified>
<validToField>0001-01-01T00:00:00</validToField>
<validToFieldSpecified>false</validToFieldSpecified>
<Code>
<CodeType>
<actionField>ADD</actionField>
<actionFieldSpecified>false</actionFieldSpecified>
<anyAttrField xmlns:a="http://schemas.datacontract.org/2004/07/System.Xml" i:nil="true"/>
<descriptionField i:nil="true"/>
<detailField>full</detailField>
<idField>Whangarei</idField>
<itemsField xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays" i:nil="true"/>
<lastUpdateField>0001-01-01T00:00:00</lastUpdateField>
<lastUpdateFieldSpecified>false</lastUpdateFieldSpecified>
<nameField>
<ContextualStringType>
<anyField/>
<isStructuredField>true</isStructuredField>
<actionField>ADD</actionField>
<actionFieldSpecified>false</actionFieldSpecified>
<anyAttrField xmlns:a="http://schemas.datacontract.org/2004/07/System.Xml" i:nil="true"/>
<langField i:nil="true"/>
<typeField>Preferred</typeField>
</ContextualStringType>
</nameField>
<uriField i:nil="true"/>
<Code>
<CodeType>
<actionField>ADD</actionField>
<actionFieldSpecified>false</actionFieldSpecified>
<anyAttrField xmlns:a="http://schemas.datacontract.org/2004/07/System.Xml" i:nil="true"/>
<descriptionField i:nil="true"/>
<detailField>full</detailField>
<idField>Springs Flat</idField>
<itemsField xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays" i:nil="true"/>
<lastUpdateField>0001-01-01T00:00:00</lastUpdateField>
<lastUpdateFieldSpecified>false</lastUpdateFieldSpecified>
<nameField>
<ContextualStringType>
<anyField/>
<isStructuredField>true</isStructuredField>
<actionField>ADD</actionField>
<actionFieldSpecified>false</actionFieldSpecified>
<anyAttrField xmlns:a="http://schemas.datacontract.org/2004/07/System.Xml" i:nil="true"/>
<langField i:nil="true"/>
<typeField>Preferred</typeField>
</ContextualStringType>
</nameField>
<uriField i:nil="true"/>
<Code/>
<category i:nil="true"/>
<codeValue>502001</codeValue>
<level xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays" i:nil="true"/>
</CodeType>
還有一些生成的代碼
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("svcutil", "4.0.30319.1")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://mtna.us/metadata/cms/services/integration/gms")]
[DataContract]
public partial class GetClassificationResponseType
{
private ClassificationVersionType classificationVersionField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Namespace = "http://mtna.us/metadata/model/classification", Order = 0)]
[DataMember]
public ClassificationVersionType ClassificationVersion
{
get
{
return this.classificationVersionField;
}
set
{
this.classificationVersionField = value;
}
}
}
...
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("svcutil", "4.0.30319.1")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://vendor.com/metadata/model/classification")]
public partial class ClassificationVersionType : ObjectVersionType
{
private LevelType1[] levelField;
private CodeType[] codeField;
private bool isViewField;
private string basisField;
public ClassificationVersionType()
{
this.isViewField = false;
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("Level", Order = 0)]
public LevelType1[] Level
{
get
{
return this.levelField;
}
set
{
this.levelField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("Code", Order = 1)]
public CodeType[] Code
{
get
{
return this.codeField;
}
set
{
this.codeField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlAttributeAttribute()]
[System.ComponentModel.DefaultValueAttribute(false)]
public bool isView
{
get
{
return this.isViewField;
}
set
{
this.isViewField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlAttributeAttribute(DataType = "anyURI")]
public string basis
{
get
{
return this.basisField;
}
set
{
this.basisField = value;
}
}
}
在供應商的大量幫助下,我們最終使這項工作奏效。 從那以后,我離開了組織-但我保留了代碼的副本。
我們使用了它-https://msdn.microsoft.com/zh-cn/library/aa395223(v=vs.110).aspx-我們的完整實現如下。
我們用DispatchByBodyElementBehavior
裝飾了服務接口:
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[ServiceContract(Namespace = "http://vendor.com/project/wsdl"), XmlSerializerFormat, DispatchByBodyElementBehavior]
public interface IContractFirstService
我們還必須修改SvcUtil.exe生成的代碼,但不能進行大量修改。 只有幾個地方需要調整。 與數組限制有關。 對不起,我不記得了。 我很確定從編譯/運行時錯誤中明顯可以做什么。
這是我們實現DispatchByBodyElementBehavior
:
using System;
using System.Diagnostics;
using System.ServiceModel.Channels;
using System.Collections.Generic;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.Xml;
/*
* This code was written based on the sample provided at http://msdn.microsoft.com/en-us/library/aa395223(v=vs.110).aspx.
* The purpose of this is to allow dispatching of the incoming SOAP requests based on the payload XML element.
* This allows the more standard document/literal service contract design to be used and does not rely on SOAP actions.
*/
namespace OurOrganisation.Services.VendorIntegrationServices
{
class DispatchByBodyElementOperationSelector : IDispatchOperationSelector
{
Dictionary<XmlQualifiedName, string> dispatchDictionary;
string defaultOperationName;
public DispatchByBodyElementOperationSelector(Dictionary<XmlQualifiedName, string> dispatchDictionary, string defaultOperationName)
{
try
{
this.dispatchDictionary = dispatchDictionary;
this.defaultOperationName = defaultOperationName;
}
catch (Exception ex)
{
Logger.Write(ex.Message);
throw;
}
}
#region IDispatchOperationSelector Members
private Message CreateMessageCopy(Message message, XmlDictionaryReader body)
{
Message copy = Message.CreateMessage(message.Version, message.Headers.Action, body);
copy.Headers.CopyHeaderFrom(message, 0);
copy.Properties.CopyProperties(message.Properties);
return copy;
}
public string SelectOperation(ref System.ServiceModel.Channels.Message message)
{
try
{
XmlDictionaryReader bodyReader = message.GetReaderAtBodyContents();
XmlQualifiedName lookupQName = new XmlQualifiedName(bodyReader.LocalName, bodyReader.NamespaceURI);
message = CreateMessageCopy(message, bodyReader);
if (dispatchDictionary.ContainsKey(lookupQName))
{
return dispatchDictionary[lookupQName];
}
else
{
return defaultOperationName;
}
}
catch (Exception ex)
{
Logger.Write(ex.Message);
throw;
}
}
#endregion
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface)]
sealed class DispatchByBodyElementBehaviorAttribute : Attribute, IContractBehavior
{
#region IContractBehavior Members
public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
// no binding parameters need to be set here
return;
}
public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
{
// this is a dispatch-side behavior which doesn't require
// any action on the client
return;
}
public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.DispatchRuntime dispatchRuntime)
{
// We iterate over the operation descriptions in the contract and
// try to locate an DispatchBodyElementAttribute behaviors on each
// operation. If found, we add the operation, keyed by QName of the body element
// that selects which calls shall be dispatched to this operation to a
// dictionary.
//Logger.Write("starting ApplyDispatchBehavior");
try
{
Dictionary<XmlQualifiedName, string> dispatchDictionary = new Dictionary<XmlQualifiedName, string>();
foreach (OperationDescription operationDescription in contractDescription.Operations)
{
DispatchBodyElementAttribute dispatchBodyElement =
operationDescription.Behaviors.Find<DispatchBodyElementAttribute>();
if (dispatchBodyElement != null)
{
dispatchDictionary.Add(dispatchBodyElement.QName, operationDescription.Name);
//Logger.Write(string.Format("method {0} added", operationDescription.Name));
}
}
// Lastly, we create and assign and instance of our operation selector that
// gets the dispatch dictionary we've just created.
dispatchRuntime.OperationSelector =
new DispatchByBodyElementOperationSelector(
dispatchDictionary,
dispatchRuntime.UnhandledDispatchOperation.Name);
}
catch(Exception ex)
{
Logger.Write(ex.Message);
throw;
}
}
public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
{
//
}
#endregion
}
[AttributeUsage(AttributeTargets.Method)]
sealed class DispatchBodyElementAttribute : Attribute, IOperationBehavior
{
XmlQualifiedName qname;
public DispatchBodyElementAttribute(string name)
{
qname = new XmlQualifiedName(name);
}
public DispatchBodyElementAttribute(string name, string ns)
{
qname = new XmlQualifiedName(name, ns);
}
internal XmlQualifiedName QName
{
get { return qname; }
set { qname = value; }
}
#region IOperationBehavior Members
public void AddBindingParameters(OperationDescription operationDescription, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(OperationDescription operationDescription, System.ServiceModel.Dispatcher.ClientOperation clientOperation)
{
}
public void ApplyDispatchBehavior(OperationDescription operationDescription, System.ServiceModel.Dispatcher.DispatchOperation dispatchOperation)
{
}
public void Validate(OperationDescription operationDescription)
{
}
#endregion
}
internal class Logger
{
public static void Write(string message)
{
string sSource;
string sLog;
string sEvent;
sSource = "MAL dispatch by body extension";
sLog = "Application";
sEvent = message;
if (!EventLog.SourceExists(sSource))
EventLog.CreateEventSource(sSource, sLog);
EventLog.WriteEntry(sSource, sEvent);
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.