2010-03-05 2 views
4

J'essaie de remplacer un WebService asmx par un service WCF. Mon objectif principal est de garder le même message SOAP. L'appelant n'est pas .NET, et nécessiterait un travail important pour apporter des modifications mineures au contrat.Une opération WCF qui prend un seul tableau en tant que paramètre peut-elle utiliser MessageContracts?

Mon point de douleur est que les méthodes Web que je suis en train de remplacer webmethod utilise la décélération des attributs suivants:

[SoapDocumentMethod(ParameterStyle = SoapParameterStyle.Bare)] 

Cela supprime une couche supplémentaire d'éléments XML autour de chaque paramètre. La seule façon que je sache de simuler ceci avec WCF est d'utiliser un MessageContracts au lieu de DataContracts, et d'utiliser WrappedName, et IsWrapped Property pour contrôler comment les paramètres sont formatés.

Cette approche fonctionne pour toutes mes méthodes sauf une, qui prend un seul tableau d'un objet POCO en tant que paramètre. Ma conclusion est que je suis à court d'options. Je ne peux pas mettre à niveau ce service Web et maintenir le même contrat.

Mes questions sont les suivantes:

1) est la seule façon de répliquer:

[SoapDocumentMethod(ParameterStyle = SoapParameterStyle.Bare)] 

sur une méthode Web WCF d'utiliser un MessageContract?

2) Y a-t-il un moyen de faire en sorte qu'une méthode utilise une seule matrice comme paramètre?

Voici un exemple simple, je travaille avec pour montrer ce que je vois/Faire avec [SoapDocumentMethod (ParameterStyle = SoapParameterStyle.Bare)] et un message contrat

Le support Code de service:

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 Objets: (V1 avec des contrats de données)

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> 

requête SOAP, avec données WCF contrat

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

permet d'utiliser des messages contrats sur nos arguments et types de retour: POCO Objets: (V2 avec 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 Demande savon (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> 

C'est ce que je fais maintenant, qui correspond à 90% de ce dont j'ai besoin.

Le problème est, je voudrais mettre en œuvre une méthode comme celui-ci dans WCFand garder le contrat même:

[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; 
} 

Quand je le fais maintenant, je reçois l'exception suivante parce AddReq [] est pas MessageContract. AddReq [] est de type System.Array, que je ne peux pas modifier.

L'opération 'AddArrays' n'a pas pu être chargée car elle a un paramètre ou un type de retour de type System.ServiceModel.Channels.Message ou un type qui contient MessageContractAttribute et d'autres paramètres de types différents. Lors de l'utilisation de System.ServiceModel.Channels.Message ou de types avec MessageContractAttribute, la méthode ne doit pas utiliser d'autres types de paramètres.

Merci, Brian

Répondre

2

Il s'avère que vous pouvez ajouter une "classe d'hôte" avec IsWrapped = false, et cela fonctionne.

De l'échantillon dans la question initiale, voici ce que la classe wrapper ressemblerait à ceci:

[DataContract,MessageContract(IsWrapped=false)] 
public class AddArraysReq 
{ 
    [DataMember] 
    [MessageBodyMember] 
    public AddReq[] AddReqs; 

} 

Voici ce que la méthode ressemblerait à ceci:

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; 
    } 

La requête SOAP résultant :

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

Je ne savais pas le IsWrapped = false tous repsentation enlevé de la classe de la demande.

1

Je suis un peu perplexe par votre déclaration, que SoapParameterStyle.Bare supprime une couche de XML autour des paramètres, mais vous ne pouvez reproduire qu'en utilisant des contrats de message avec IsWrapped=true, ce qui en fait à son tour ajoute un wrapper XML autour de la charge utile SOAP ... semble un peu contradictoire. Pouvez-vous nous montrer la déclaration de méthode web pour votre méthode qui prend comme paramètre le tableau de POCOs? Qu'avez-vous essayé dans la WCF jusqu'à présent? En règle générale, avec BasicHttpBinding et à peu près pas d'options, vous obtenez très proche de ce que ASMX faisait dans l'ancien temps.

+0

Marc, Je vous remercie de répondre. J'ai ajouté des exemples de code génériques entourant SoapParameterStyle.Bare et comment j'utilise les contrats de message pour remplacer le format de savon asmx. Mon intention n'était pas de dire que je devais utiliser IsWrapped = true, mais plutôt utiliser les propriétés de l'attribut pour obtenir l'effet voulu. J'espère que mes échantillons clarifient ma signification. Dans ce cas, "très proche" n'est pas assez proche. Je peux être capable de gérer les noms des éléments qui changent, mais si l'imbrication des éléments change, j'ai des problèmes. –

Questions connexes