Can a WCF Operation that takes a single array as a parameter use MessageContracts?
.net, messagecontract, soap, wcf
Solution
It turns out, that you can add a "Host Class" with IsWrapped=false, and it works.
From the sample in the original question, Here is what the wrapper class would look like:
[DataContract,MessageContract(IsWrapped=false)]
public class AddArraysReq
{
[DataMember]
[MessageBodyMember]
public AddReq[] AddReqs;
}
And this is what the Method would look like:
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;
}
The resulting SOAP Request:
<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>
I did not realize the IsWrapped=false removed all repsentation of the class from the request.
Problem
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