I am trying to replace an asmx WebService with a WCF service. My primary goal is to keep the SOAP message the same. The caller is not .NET, and would require significant re-work to take minor changes to the contract.
My pain point is that the web methods I am trying to replace webmethod uses the the following Attribute deceleration:
[SoapDocumentMethod(ParameterStyle = SoapParameterStyle.Bare)]
This removes an extra layer of XML elements around each parameter.
The only way I know about to simulate this with WCF is to use a MessageContracts instead of DataContracts, and use the WrappedName, and IsWrapped Property to control how paramaters are formatted.
This approach works for all of my methods except one, which takes a single Array of a POCO object as a parameter.
My conclusion is that I am out of options. I cannot upgrade this webservice and maintain the same contract.
My questions are:
1) Is the only way to replicate :
[SoapDocumentMethod(ParameterStyle = SoapParameterStyle.Bare)]
on a web method in WCF to use a MessageContract?
2) And is there a way to have a method take a single array as a parameter?
Here is a simple Example I have been working with to show what I am seeing/ Doing with [SoapDocumentMethod(ParameterStyle = SoapParameterStyle.Bare)] and Message Contract
The backing Service Code:
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 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>
Lets Use Message Contracts on 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; }
}
}
WCF Soap Request (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>
That is what I am doing now, which meets 90% of what I need.
The problem is, I would like to Implement a method like this in WCFand 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 alter.
The operation 'AddArrays' could not 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 any other types of parameters.
Thanks, Brian