2010-03-05 83 views
4

我想用WCF服務替換一個asmx WebService。我的主要目標是保持SOAP消息相同。調用者不是.NET,需要大量的重新工作才能對合同進行微小的更改。可以將單個數組作爲參數的WCF操作使用MessageContracts嗎?

我的痛點是,Web方法,我試圖取代的webmethod使用下列屬性減速:

[SoapDocumentMethod(ParameterStyle = SoapParameterStyle.Bare)] 

這消除了圍繞每一個參數的XML元素的一個額外層。

我知道使用WCF模擬此的唯一方法是使用MessageContracts而不是DataContracts,並使用WrappedName和IsWrapped屬性來控制參數如何格式化。

這種方法適用於我所有的方法,除了一個,它將一個POCO對象的單個數組作爲參數。

我的結論是,我沒有選擇。我無法升級這個webservice並維護同一個合同。

我的問題是:

1)是複製的唯一途徑:

[SoapDocumentMethod(ParameterStyle = SoapParameterStyle.Bare)] 

在WCF Web方法使用MessageContract?

2)有沒有辦法讓一個方法把一個數組作爲參數?

下面是一個簡單實施例I一直在努力,以顯示我所看到/用做 [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請求(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%。

的問題是,我想實現這樣的WCFand的方法守合同相同:

[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

事實證明,你可以添加一個「主機類」與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

我有點被你的聲明難倒,那SoapParameterStyle.Bare消除周圍的參數XML層,但你可以只複製使用消息合同,IsWrapped=true,而這又主要增加了圍繞SOAP有效載荷的XML包裝......似乎有點矛盾。

你能向我們展示你的方法的Web方法聲明,該方法以POCO數組爲參數?到目前爲止,你在WCF中嘗試過什麼?通常,與BasicHttpBinding和幾乎沒有選項,你很接近ASMX在過去的做法。

+0

Marc, 我很感謝您的回覆。 我已經添加了關於SoapParameterStyle.Bare的通用代碼示例,以及我如何使用消息合約來替換asmx Soap格式。 我的意圖不是說我必須使用IsWrapped = true,而是使用屬性屬性來獲得預期的效果。我希望我的樣品能澄清我的意思。 在這種情況下,「非常接近」並不夠接近。我可能能夠處理元素名稱的變化,但是如果元素嵌套發生變化,我就會遇到問題。 – 2010-03-05 20:37:04

相關問題