web-dev-qa-db-fra.com

Erreur WCF webHttpBinding avec les paramètres de méthode. "Au plus, un paramètre de corps peut être sérialisé sans éléments wrapper"

L'opération '' du contrat '' spécifie plusieurs paramètres de corps de demande à sérialiser sans aucun élément wrapper. Au plus, un paramètre de corps peut être sérialisé sans éléments wrapper. Supprimez les paramètres de corps supplémentaires ou définissez la propriété BodyStyle sur WebGetAttribute/WebInvokeAttribute sur Wrapped.

J'essaie d'exposer un service WCF C # 4.0 avec JSON via la configuration suivante (définie via l'éditeur de configuration WCF):

<?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>

Lorsque j'accède à /API.svc, j'obtiens le message d'exception répertorié précédemment.

Si je spécifie uniquement le contrat suivant (sans paramètre), le service fonctionne:

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

Si j'ai des méthodes qui nécessitent des paramètres qui ne sont pas des chaînes, j'obtiens l'exception répertoriée précédemment.

Exemple:

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

Si je change cette fonction comme ceci:

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

Ça marche; mais cela n'est possible que pour les paramètres de Type String. Comment puis-je résoudre cela pour mes autres fonctions comme:

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

J'ai essayé beaucoup de recherches sur Google, mais je me suis retrouvé les mains vides, toute aide est appréciée.

À votre santé,

Pseudo.

31
NKCSS

Avez-vous essayé de définir WebInvokeAttribute.BodyStyle sur Wrapped comme l'erreur le recommande?

38
Oppositional

Le problème est que votre UriTemplate doit spécifier toutes les valeurs transmises sauf une. Il est bien d'avoir des types complexes autres que des chaînes comme paramètres, nous envoyons fréquemment des objets json légers à nos services et ils arrivent très bien. Voici un exemple utilisant votre dernier exemple.

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

Fonctionnerait car il n'y a qu'un seul paramètre transmis et il devrait être dans le corps du message car il n'est pas passé en tant que paramètre d'URL, mais vous ne pouvez passer qu'un seul paramètre de corps (un paramètre passé dans le corps de la publication, pas l'URL).

Vous pouvez changer votre première méthode comme celle-ci

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

et cela fonctionnerait, mais Password entrerait dans le corps du message. La meilleure façon dans cet exemple particulier est de faire ce que vous avez fait pour le deuxième exemple comme ça

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

Cela a-t-il du sens? Fondamentalement, toutes les valeurs transmises doivent être représentées sous la forme d'un paramètre d'URL, sauf une qui peut être transmise dans le corps du message. Si vous avez besoin de plusieurs valeurs transmises dans le corps du message, créez un objet léger qui a les multiples valeurs dont vous avez besoin et acceptez cet objet entier dans le corps du message.

23
ljkyser

WCF ne prend pas en charge plus d'un paramètre avec un corps nu, si vous devez passer plusieurs paramètres en une seule opération de méthode post, alors nous devons définir BodyStyle sur Wrapped.

Dans votre cas, vous devrez donc modifier votre contrat d'exploitation comme suit:

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

Source: Cliquez ici

6
Ankit