我正在尝试用WCF服务替换asmx WebService。我的主要目标是保持SOAP消息相同。调用者不是.NET,并且需要进行大量的重新工作才能对合同进行微小的更改。
我的痛点是我试图替换webmethod的web方法使用以下属性减速:
[SoapDocumentMethod(ParameterStyle = SoapParameterStyle.Bare)]
这将删除每个参数周围的额外XML元素层。
我知道用WCF模拟这个的唯一方法是使用MessageContracts而不是DataContracts,并使用WrappedName和IsWrapped属性来控制参数的格式化。
这种方法适用于我的所有方法,除了一个方法,它将POCO对象的单个数组作为参数。
我的结论是我没有选择权。我无法升级此Web服务并维护相同的合同。
我的问题是:
1)是复制的唯一方法:
[SoapDocumentMethod(ParameterStyle = SoapParameterStyle.Bare)]
在WCF中的Web方法上使用MessageContract?
2)有没有办法让一个方法将一个数组作为参数?
这是一个简单的示例,我一直在努力展示我所看到/正在做的事情 [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对象:(带MessageContracts的V2)
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肥皂请求(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%。
问题是,我想在WCF中实现这样的方法并保持合同相同:
[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类型时,该方法不得使用任何其他类型的参数。
谢谢, 布赖恩
答案 0 :(得分:2)
事实证明,您可以使用IsWrapped = false添加“主机类”,并且它可以正常工作。
从原始问题中的示例中,以下是包装类的外观:
[DataContract,MessageContract(IsWrapped=false)]
public class AddArraysReq
{
[DataMember]
[MessageBodyMember]
public AddReq[] AddReqs;
}
这就是方法的样子:
public AddResp AddArrays(AddArraysReq addInput)
{
AddResp resp = new AddResp {result = 0};
foreach (var addrequest in addInput.AddReqs)
{
resp.result += (addrequest.NumOne + addrequest.NumTwo);
}
return resp;
}
生成的SOAP请求:
<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:AddReqs>
<web:AddReq>
<web:NumOne>10</web:NumOne>
<web:NumTwo>10</web:NumTwo>
</web:AddReq>
<web:AddReq>
<web:NumOne>10</web:NumOne>
<web:NumTwo>10</web:NumTwo>
</web:AddReq>
</tem:AddReqs>
</soap:Body>
</soap:Envelope>
我没有意识到IsWrapped = false从请求中删除了所有类的代表。
答案 1 :(得分:1)
我对你的陈述感到有点困惑,SoapParameterStyle.Bare
在参数周围删除了一层XML,但你只能通过使用IsWrapped=true
的消息契约来复制它,而BasicHttpBinding
基本上< em>再次围绕SOAP有效负载添加 XML包装器......似乎有点矛盾。
您能告诉我们您的方法的Web方法声明,它将POCO数组作为参数吗?你到目前为止在WCF中尝试过什么?通常情况下,使用{{1}}并且几乎没有选项,您可以非常接近ASMX过去所做的事情。