Может ли операция WCF, которая принимает один массив в качестве параметра, использовать MessageContracts? - PullRequest
4 голосов
/ 05 марта 2010

Я пытаюсь заменить asmx WebService на службу WCF.Моя основная цель - сохранить сообщение SOAP таким же.Вызывающая сторона не является .NET, и для внесения незначительных изменений в контракт потребуется значительная доработка.

Моя главная проблема в том, что веб-методы, которые я пытаюсь заменить webmethod, используют следующее замедление атрибута:

[SoapDocumentMethod(ParameterStyle = SoapParameterStyle.Bare)]

При этом удаляется дополнительный слой элементов XML вокруг каждого параметра.

Единственный известный мне способ моделирования этого с WCF - это использование MessageContracts вместо DataContracts и использование WrappedNameи свойство IsWrapped для управления форматированием параметров.

Этот подход работает для всех моих методов, кроме одного, в котором в качестве параметра используется один массив объекта POCO.

Мой выводчто у меня нет вариантов.Я не могу обновить этот веб-сервис и поддерживать тот же контракт.

Мои вопросы:

1) Есть ли единственный способ реплицироваться:

    [SoapDocumentMethod(ParameterStyle = SoapParameterStyle.Bare)]

на веб-метод в WCF для использования MessageContract?

2) И есть ли способ заставить метод принимать один массив в качестве параметра?

Вот простой пример, с которым я работал, чтобы показать, что я вижу / делаю с помощью [SoapDocumentMethod (ParameterStyle =SoapParameterStyle.Bare)] и контракт сообщения

Код вспомогательного сервиса:

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: (V1 с контрактами данных)

    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-запрос с контрактом данных WCF

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

Позволяет использовать контракты сообщений в наших аргументах и ​​возвращаемых типах: объекты POCO: (V2 с 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>

Это то, что я делаю сейчас, что соответствует 90% того, что мне нужно.

Проблема в том, что я хотел бы реализоватьтакой метод в WCF и держите контракт таким же:

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

Когда я делаю это сейчас, я получаюследующее исключение, потому что AddReq [] не является MessageContract.AddReq [] имеет тип System.Array, который я не могу изменить.

Операция 'AddArrays' не может быть загружена, поскольку она имеет параметр или тип возврата типа System.ServiceModel.Channels.Message или типакоторый имеет MessageContractAttribute и другие параметры разных типов.При использовании System.ServiceModel.Channels.Message или типов с MessageContractAttribute метод не должен использовать какие-либо другие типы параметров.

Спасибо, Брайан

Ответы [ 2 ]

2 голосов
/ 06 марта 2010

Оказывается, вы можете добавить "Host Class" с IsWrapped = false, и это работает.

Из примера в исходном вопросе, вот как будет выглядеть класс-оболочка:

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

}

И вот как будет выглядеть Метод:

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

Полученный SOAP-запрос:

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

Я не понял, что IsWrapped = false удалил все представления класса из запроса.

1 голос
/ 05 марта 2010

Я немного озадачен вашим утверждением, что SoapParameterStyle.Bare удаляет слой XML вокруг параметров, но вы можете повторить это только с помощью контрактов сообщений с IsWrapped=true, что, в свою очередь, в основном добавляет XML-оболочка вокруг полезной нагрузки SOAP снова ... кажется немного противоречивой.

Можете ли вы показать нам объявление веб-метода для вашего метода, которое принимает массив POCO в качестве параметра? Что вы уже пробовали в WCF? Как правило, с BasicHttpBinding и практически без вариантов, вы очень близки к тому, что ASMX делал в прежние времена.

...