I am trying to replace asmx WebService with a WCF service. My main goal is to keep the SOAP message the same. The caller is not .NET and requires significant overhaul to make minor changes to the contract.
My pain is that the web methods that I'm trying to replace the webmethod use the following attribute braking:
[SoapDocumentMethod(ParameterStyle = SoapParameterStyle.Bare)]
This removes an extra layer of XML elements around each parameter.
The only way I can mimic this with WCF is to use MessageContracts instead of DataContracts and use the WrappedName and IsWrapped property to control the formatting of the parameters.
This approach works for all my methods except one, which takes as a parameter one array of the POCO object.
My conclusion is that I have no options. I cannot update this web service and maintain the same contract.
My questions:
1) The only way to replicate:
[SoapDocumentMethod(ParameterStyle = SoapParameterStyle.Bare)]
on a web method in WCF to use MessageContract?
2) And is there a way for a method to take a single array as a parameter?
Here is a simple example that I worked with to show what I see / Do with [SoapDocumentMethod (ParameterStyle = SoapParameterStyle.Bare)] and Message Contract
Support Code:
using System.Web.Services; using System.Web.Services.Protocols; using System.ServiceModel; namespace WebApplication1{
POCO Objects: (V1 with Data Contracts)
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 request with WCF data contract
<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>
Allows the use of Message Contracts in our arguments and return types: POCO Objects: (V2 with 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; } } }
Soap request 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>
Here is what I am doing now, which corresponds to 90% of what I need.
The problem is that I would like to implement such a method in WCF and keep the contract the same:
[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; }
When I do this now, I get the following exception because AddReq [] is not a MessageContract. AddReq [] is of type System.Array, which I cannot change.
The AddArrays operation cannot be loaded because it has a parameter or return type of type System.ServiceModel.Channels.Message or a type that has MessageContractAttribute and other parameters of different types. When using System.ServiceModel.Channels.Message or types with MessageContractAttribute, the method must not use other types of parameters.
Thanks Brian