我想用WCF服务替换一个asmx WebService。我的主要目标是保持SOAP消息相同。调用者不是.NET,需要大量的重新工作才能对合同进行微小的更改。可以将单个数组作为参数的WCF操作使用MessageContracts吗?
我的痛点是,Web方法,我试图取代的webmethod使用下列属性减速:
[SoapDocumentMethod(ParameterStyle = SoapParameterStyle.Bare)]
这消除了围绕每一个参数的XML元素的一个额外层。
我知道使用WCF模拟此的唯一方法是使用MessageContracts而不是DataContracts,并使用WrappedName和IsWrapped属性来控制参数如何格式化。
这种方法适用于我所有的方法,除了一个,它将一个POCO对象的单个数组作为参数。
我的结论是,我没有选择。我无法升级这个webservice并维护同一个合同。
我的问题是:
1)是复制的唯一途径:
[SoapDocumentMethod(ParameterStyle = SoapParameterStyle.Bare)]
在WCF Web方法使用MessageContract?
2)有没有办法让一个方法把一个数组作为参数?
下面是一个简单实施例I一直在努力,以显示我所看到/用做 [SoapDocumentMethod(ParameterStyle = SoapParameterStyle.Bare)]和消息合同
背衬服务代码:
using System.Web.Services;
using System.Web.Services.Protocols;
using System.ServiceModel;
namespace WebApplication1{
/// <summary>
/// The Service Contract
/// </summary>
[ServiceContract]
public interface ISimpleMathService
{
[OperationContract()]
AddResp Add(AddReq add);
}
/// <summary>
/// The Service Implementation
/// </summary>
public class simpleMath : ISimpleMathService
{
[WebMethod()] //Allows the Service to be exposed as a asmx Service
[SoapDocumentMethod(ParameterStyle = SoapParameterStyle.Bare)]
public AddResp Add(AddReq add)
{
return new AddResp {result = add.NumOne + add.NumTwo};
}
}
}
POCO对象:(V1与数据协定)
using System.Runtime.Serialization;
using System.ServiceModel;
namespace WebApplication1
{
[DataContract]
public class AddReq
{
[DataMember]
public int NumOne { get; set; }
[DataMember]
public int NumTwo { get; set; }
}
[DataContract]
public class AddResp
{
[DataMember]
public int result{ get; set; }
}
}
ASMX SOAP
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/">
<soapenv:Header/>
<soapenv:Body>
<tem:add>
<tem:NumOne>12</tem:NumOne>
<tem:NumTwo>12</tem:NumTwo>
</tem:add>
</soapenv:Body>
</soapenv:Envelope>
SOAP请求,与WCF数据契约
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:tem="http://tempuri.org/" xmlns:web="http://schemas.datacontract.org/2004/07/WebApplication1">
<soap:Header/>
<soap:Body>
<tem:Add>
<tem:add>
<web:NumOne>10</web:NumOne>
<web:NumTwo>10</web:NumTwo>
</tem:add>
</tem:Add>
</soap:Body>
</soap:Envelope>
让我们的参数使用消息合同并返回类型: POCO对象:(V2与MessageContracts)
namespace WebApplication1
{
[DataContract]
[MessageContract(WrapperName="add", IsWrapped = true)] //Default Wrapper Name is "Add", not add
public class AddReq
{
[DataMember]
[MessageBodyMember]
public int NumOne { get; set; }
[DataMember]
[MessageBodyMember]
public int NumTwo { get; set; }
}
[DataContract]
[MessageContract(IsWrapped = true)]
public class AddResp
{
[DataMember]
[MessageBodyMember]
public int result{ get; set; }
}
}
WCF SOAP请求(V2):
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:tem="http://tempuri.org/">
<soap:Header/>
<soap:Body>
<tem:add>
<tem:NumOne>19</tem:NumOne>
<tem:NumTwo>12</tem:NumTwo>
</tem:add>
</soap:Body>
</soap:Envelope>
这就是我现在正在做的事,它符合我需要的90%。
的问题是,我想实现这样的WCFand的方法守合同相同:
[WebMethod()]
[SoapDocumentMethod(ParameterStyle = SoapParameterStyle.Bare)]
public AddResp AddArrays(AddReq [] addInput)
{
AddResp resp= new AddResp{result=0}
foreach (var addrequest in addInput)
{
resp.result += (addrequest.NumOne + addrequest.NumTwo);
}
return resp;
}
当我做到这一点,现在,我得到下面的异常,因为AddReq []是不是MessageContract。 AddReq []是System.Array类型的,我不能改变它。
无法加载操作'AddArrays',因为它具有System.ServiceModel.Channels.Message类型的参数或返回类型或具有MessageContractAttribute和其他不同类型参数的类型。当使用System.ServiceModel.Channels.Message或具有MessageContractAttribute的类型时,该方法不得使用任何其他类型的参数。
感谢, 布赖恩
Marc, 我很感谢您的回复。 我已经添加了关于SoapParameterStyle.Bare的通用代码示例,以及我如何使用消息合约来替换asmx Soap格式。 我的意图不是说我必须使用IsWrapped = true,而是使用属性属性来获得预期的效果。我希望我的样品能澄清我的意思。 在这种情况下,“非常接近”并不够接近。我可能能够处理元素名称的变化,但是如果元素嵌套发生变化,我就会遇到问题。 – 2010-03-05 20:37:04