Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WCF webHttpBinding error with method parameters. "At most one body parameter can be serialized without wrapper elements"

Tags:

json

rest

c#

wcf

Operation '' of contract '' specifies multiple request body parameters to be serialized without any wrapper elements. At most one body parameter can be serialized without wrapper elements. Either remove the extra body parameters or set the BodyStyle property on the WebGetAttribute/WebInvokeAttribute to Wrapped.

I am trying to expose a C# 4.0 WCF Service with JSON via the following config (set via the WCF Config Editor):

<?xml version="1.0"?>
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <services>
      <service name="iPhoneAPI.API">
        <endpoint address="" behaviorConfiguration="NewBehavior0" binding="webHttpBinding"
          bindingConfiguration="" contract="iPhoneAPI.IApi" />
      </service>
    </services>
    <protocolMapping>
      <add scheme="http" binding="webHttpBinding" bindingConfiguration="" />
    </protocolMapping>
    <behaviors>
      <endpointBehaviors>
        <behavior name="NewBehavior0">
          <webHttp defaultOutgoingResponseFormat="Json" />
        </behavior>
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior name="">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="false" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
 <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>  
</configuration>

When I access /API.svc, I get the previously listed exception message.

If I only specify the following (parameter-less)contract, the service works:

[OperationContract]
[WebInvoke(Method = "GET", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, UriTemplate = "test")]
GenericApiResult<IEnumerable<LiveFeedEntity>> test();

If I have methods that require parameters that are non-strings, I get the previously listed exception.

Example:

[OperationContract]
[WebInvoke(Method = "GET", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, UriTemplate = "login")]
LoginApiResult Login(String UserName, String Password);

If I change this function like so:

[OperationContract]
[WebInvoke(Method = "GET", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, UriTemplate = "login/{UserName}/{Password}")]
LoginApiResult Login(String UserName, String Password);

It works; but this is only possible for parameters of Type String. How do I respolve this for my other functions like:

[OperationContract]
[WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, UriTemplate = "logout")]
GenericApiResult<bool> Logout(Guid SessionKey);

Tried a lot of google searches, but turned up empty handed, any help is appreciated.

Cheers,

Nick.

like image 979
NKCSS Avatar asked Apr 28 '11 14:04

NKCSS


3 Answers

Have you tried setting the WebInvokeAttribute.BodyStyle to Wrapped as the error recommends?

like image 183
Oppositional Avatar answered Oct 21 '22 18:10

Oppositional


The problem is that your UriTemplate must specify all the values being passed in except for one. It is fine to have complex types other than strings as parameters, we frequently send lightweight json objects to our services and they come in just fine. Here is an example using your last example.

[OperationContract]
[WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, UriTemplate = "logout")]
GenericApiResult<bool> Logout(Guid SessionKey);

Would work because there is only one parameter being passed in, and it is expected to be in the post body because it is not passed in as a URL parameter, but you can only pass in one body parameter (a parameter passed in the body of the post, not the URL).

You could change your first method like this

[OperationContract]
[WebInvoke(Method = "GET", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, UriTemplate = "login/{UserName}")]
LoginApiResult Login(String UserName, String Password);

and it would work, but Password would come in the post body. The best way in this particular example is to do what you did for the second example like so

[OperationContract]
[WebInvoke(Method = "GET", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, UriTemplate = "login/{UserName}/{Password}")]
LoginApiResult Login(String UserName, String Password);

Does that make sense? Basically all values passed in need to be represented as a URL parameter, except for one that can be passed in the post body. If you need multiple values passed in the post body, make a lightweight object that has the multiple values you need and accept that whole object in the post body.

like image 32
ljkyser Avatar answered Oct 21 '22 16:10

ljkyser


WCF doesn't support more than one parameter with bare body, if you need pass several parameters in one post method operation, then we need set the BodyStyle to Wrapped.

So in your case you'd have to change your operation contract to the following:

[WebInvoke(Method = "POST", UriTemplate = "evals", BodyStyle = WebMessageBodyStyle.WrappedRequest)]
[OperationContract]
void SubmitVideoPOST(Video videoArg, string userId);

Source: Click Here

like image 42
Ankit Avatar answered Oct 21 '22 17:10

Ankit