WCF 4.5新功能簡介

by vivid 20. 六月 2012 04:36

.NET Magazine國際中文電子雜誌
者:許薰尹
稿:張智凱
文章編號:N120612502
出刊日期:2012/6/20

.NET Framework 4.5 與Visual Studio 11 Beta版剛釋出,在本篇文章中將介紹WCF 4.5的新功能。

本文撰寫時使用的工具是Visual Studio 11 Beta,因此本文探討的內容在正式版上市時可能不適用。

簡化組態檔案

在WCF 4.5中簡化了用戶端程式的組態檔,在組態檔案中的binding區段,只有非預設值的設定,才會出現。底下是WCF 4.5用戶端程式的組態範例:

<?xml version = "1.0" encoding = "utf-8" ?>
<configuration>
    <startup>
        <supportedRuntime version = "v4.0" sku = ".NETFramework,Version=v4.5" />
    </startup>
    <system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <binding name = "BasicHttpBinding_IService" />
            </basicHttpBinding>
        </bindings>
        <client>
            <endpoint address = "http://localhost:11542/Service.svc" binding = "basicHttpBinding"
                bindingConfiguration = "BasicHttpBinding_IService" contract = "ServiceReference1.IService"
                name = "BasicHttpBinding_IService" />
        </client>
    </system.serviceModel>
</configuration>

底下是WCF 4的用戶端程式組態檔範例,basicHttpBinding之中allowCookies、receiveTimeout、sendTimeout等等屬性都會出現在組態檔中,看起來相當的複雜:

<?xml version = "1.0" encoding = "utf-8" ?>
<configuration>
    <system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <binding name = "BasicHttpBinding_IService1" closeTimeout = "00:01:00"
                    openTimeout = "00:01:00" receiveTimeout = "00:10:00" sendTimeout = "00:01:00"
                    allowCookies = "false" bypassProxyOnLocal = "false" hostNameComparisonMode = "StrongWildcard"
                    maxBufferSize = "65536" maxBufferPoolSize = "524288" maxReceivedMessageSize = "65536"
                    messageEncoding = "Text" textEncoding = "utf-8" transferMode = "Buffered"
                    useDefaultWebProxy = "true">
                    <readerQuotas maxDepth = "32" maxStringContentLength = "8192" maxArrayLength = "16384"
                        maxBytesPerRead = "4096" maxNameTableCharCount = "16384" />
                    <security mode = "None">
                        <transport clientCredentialType = "None" proxyCredentialType = "None"
                            realm = "" />
                        <message clientCredentialType = "UserName" algorithmSuite = "Default" />
                    </security>
                </binding>
            </basicHttpBinding>
        </bindings>
        <client>
            <endpoint address = "http://localhost:2924/Service1.svc" binding = "basicHttpBinding"
                bindingConfiguration = "BasicHttpBinding_IService1" contract = "ServiceReference1.IService1"
                name = "BasicHttpBinding_IService1" />
        </client>
    </system.serviceModel>
</configuration>

相較之下,在WCF 4.5之中,組態設定簡化了不少。

組態檔提示

在設定組態檔案時,Visual Studio 11 Beta工具提供更佳的提示,以及更多的說明來輔助你設計應用程式。例如,當你將游標停留在組態檔案<system.serviceModel>區段上,Visual Studio 11 Beta工具就會自動顯示組態提示訊息,請參考圖1所示:

clip_image002

圖 1:Visual Studio 11 Beta自動顯示的組態提示訊息。

若將游標停留在組態檔案<service>區段上,Visual Studio 11 Beta就會自動顯示說明,請參考圖2所示:

clip_image004

圖 2:Visual Studio 11 Beta工具自動顯示說明。

當你在<services>區段之中定義服務時,Visual Studio 11 Beta 工具會主動列出目前專案中可用的服務,請參考圖3所示:

clip_image006

圖 3:自動列出可用的服務。

不僅如此,Visual Studio 11 Beta工具在設定endpoint 的binding項目時,也會有提示視窗顯示,請參考圖4所示:

clip_image008

圖 4:自動列出可用Binding。

下圖是設定Contract提示,自動列出專案中可用的合約,請參考圖5所示:

clip_image010

圖 5:自動列出專案中可用的合約。

另外,設定Binding設定檔時,也會有提示,請參考圖6所示:

clip_image012

圖 6:自動提示可用的Binding設定檔。

組態檔案驗證

在Visual Studio 11 Beta 工具設定WCF服務組態檔時,也提供了組態設定驗證的機制,防止您不小心設定了錯誤的組態。

例如以下範例,故意將服務的名稱拼錯,服務的名稱為「WcfServiceLibrary1.Service1」,本例故意將服務名稱中的「s」拼字改為小寫,此時Visual Studio 11 Beta工具會在名稱下方顯示藍色的波浪狀線條,並在「Error List」視窗中,顯示警告訊息,請參考圖7所示:

clip_image014

圖 7:組態檔案驗證。

ASP.NET相容性模型

在WCF 4.5預設便支援ASP.NET相容性模型,當你建立一個裝載在ASP.NET環境下執行的WCF服務時,專案組態檔案serviceHostingEnvironment 項目預設的aspNetCompatibilityEnabled值會設定為「true」,請參考以下的範例組態檔。這樣才能夠存取到ASP.NET的一些功能。

<?xml version = "1.0"?>
<configuration>

  <system.web>
    <compilation debug = "false" targetFramework = "4.5" />
  </system.web>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information, set the values below to false before deployment -->
          <serviceMetadata httpGetEnabled = "true" httpsGetEnabled = "true"/>
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults = "false"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment aspNetCompatibilityEnabled = "true"
        multipleSiteBindingsEnabled = "true" />
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests = "true"/>
    <!--
        To browse web app root directory during debugging, set the value below to true.
        Set to false before deployment to avoid disclosing web app folder information.
      -->
    <directoryBrowse enabled = "true"/>
  </system.webServer>

</configuration>


在WCF 4預設AspNetCompatibilityRequirements的RequirementsMode屬性的值為「NotAllowed」;而在WCF 4.5,預設會將AspNetCompatibilityRequirements的RequirementsMode屬性自動設定為「Allowed」,因此您不必像WCF 4版,需要在服務的類別上方利用AspNetCompatibilityRequirements Attribute來設定之,例如在WCF 4中,你需要撰寫以下程式:

 

[AspNetCompatibilityRequirements( RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed )]

產生單一WSDL文件檔

有一些第三協力廠商工具無法存取有相依關係的WSDL文件,例如以下wsdl文件片段,利用xsd:import描述WSDL和其它XML Schema文件有相依關係。

<wsdl:types>
<xsd:schema targetNamespace = "http://tempuri.org/Imports">
<xsd:import schemaLocation = "http://localhost:11542/Service.svc?xsd=xsd0" namespace = "http://tempuri.org/" />
<xsd:import schemaLocation = "http://localhost:11542/Service.svc?xsd=xsd1" namespace = "http://schemas.microsoft.com/2003/10/Serialization/" />
<xsd:import schemaLocation = "http://localhost:11542/Service.svc?xsd=xsd2" namespace = "http://schemas.datacontract.org/2004/07/" />
</xsd:schema>
</wsdl:types>

在WCF 4.5,當你執行一個裝載在ASP.NET的WCF服務,svc檔案的說明頁面就會提示你是否使用「?singleWSDL」查詢字串,將WSDL文件和相關的XML Schema以一個檔案的方式回傳,請參考圖8所示:

clip_image016

圖 8:使用「?singleWSDL」查詢字串回傳單一檔。

若在Url中使用「?wsdl」字串,則只回傳WSDL文件,相依的XML Schema不回傳:

參考下圖所示:

clip_image018

圖 9:只回傳WSDL文件,不回傳XML Schema。

若在Url中使用使用「?singleWsdl」字串,如:

則回傳的資料參考如下,XML Schema資訊會內嵌在WSDL文件之中,請參考圖10所示:

clip_image020

圖 10:回傳內嵌XML Schema資訊的WSDL。

預設HTTPS端點

WCF4.5中允許你建立預設的HTTPS端點了,你不用手動地為服務定義服務端點,讓服務的組態檔更為簡化。

若將服務裝載在IIS中,你需要先在IIS設定並啟用SSL。第一個動作便是先伸請一個X.509的憑證給伺服器使用。若是使用IIS 7.5,可以在Internet Information Services (IIS) Manager工具中,為IIS建立一個自我簽章的憑證。

在IIS啟用SSL

開啟Internet Information Services (IIS) Manager工具,點選左方清單方塊中的電腦名稱,然後再使用滑鼠雙擊右方的「Service Certificates」項目,請參考圖11所示:

clip_image022

圖 11:在Internet Information Services (IIS) Manager工具建立憑證。

在左方的「Actions」區塊中,選擇「Create Self - Signed Certificates」建立自我簽章的憑證,請參考圖12所示:

clip_image024

圖 12:建立自我簽章的憑證。

在「Specify Friendly Name」對話盒中,設定憑證的名稱,本例為「myserver」,然後按下「OK」按鈕,請參考圖13所示:

clip_image026

圖 13:設定憑證的名稱。

在Internet Information Services (IIS) Manager工具,點選左方清單方塊中「Sites」-「Default Web Site」,然後再點選右方「Actions」區塊中的「Bindings」項目,請參考圖14所示:

clip_image028

圖 14:設定Site Bindings。

在「Site Bindings」對話盒中,按下「Add」按鈕,新增HTTPS繫結,請參考圖15所示:

clip_image030

圖 15:新增HTTPS繫結。

在「Add Site Binding」對話盒中,從「SSL certificate」下方的清單,選取剛建立的憑證,請參考圖16所示:

clip_image032

圖 16:選取憑證。

目前「Site Bindings」對話盒的畫面看起來如下圖所示:

clip_image034

圖 17:「Site Bindings」。

建立WCF服務

完成IIS的SSL設定之後,我們便可以在IIS上建立WCF服務。在Visual Studio 11 Beta工具「File」-「New」-「Web Site」-「Visual C#」-「WCF Service」,將「Web Location」設定為「HTTP」,名稱為「https://localhost/MyService」,然後按下「OK」按鈕,請參考圖18所示。

clip_image036

圖 18:建立WCF服務。

完成之後,檢視Web.config組態檔案,其中的httpsGetEnabled項目值已經設定為「true」了。

<?xml version = "1.0"?>
<configuration>
  <system.web>
    <compilation debug = "false" targetFramework = "4.5" />
  </system.web>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information, set the values below to false before deployment -->
          <serviceMetadata httpGetEnabled = "true" httpsGetEnabled = "true"/>
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults = "false"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment aspNetCompatibilityEnabled = "true"
        multipleSiteBindingsEnabled = "true" />
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests = "true"/>
    <!--
        To browse web app root directory during debugging, set the value below to true.
        Set to false before deployment to avoid disclosing web app folder information.
      -->
    <directoryBrowse enabled = "true"/>
  </system.webServer>
</configuration>

在Internet Information Services (IIS) Manager工具,點選左方清單方塊中「Sites」-「Default Web Site」-選取剛建立的「MyService」,然後再使用滑鼠雙擊中間的「SSL Settings」項目,勾選「Require SSL」,再點選右方「Actions」區段中的「Apply」套用這個設定,請參考圖19所示:

clip_image038

圖 19:勾選「Require SSL」。

接下來你就可以試著在瀏覽器上測試svc檔案執行是否正常。在瀏覽器輸入以下URI位置:

預設瀏覽器會顯示憑證錯誤的訊息,這部分可以忽略,點選瀏覽器上的「Continue to this website (not recommended)」超連結,請參考圖20所示:

clip_image040

圖 20:忽略憑證錯誤。

接著就可以看到服務頁面,請參考圖21所示:

clip_image042

圖 21:服務頁面。

點選服務頁面中的超連結來檢視WSDL,服務會有兩個端點,location部分分別使用機器名稱(windows_phone)與localhost來描述。

<wsdl:service name = "Service">
<wsdl:port name = "BasicHttpBinding_IService" binding = "tns:BasicHttpBinding_IService">
<soap:address location = "http://windows_phone/MyService/Service.svc" />
</wsdl:port>
<wsdl:port name = "BasicHttpsBinding_IService" binding = "tns:BasicHttpsBinding_IService">
<soap:address location = "https://localhost/MyService/Service.svc" />
</wsdl:port>

不過,以筆者目前的環境產生出的WSDL有些奇怪,使用https時,應該使用機器名稱才能夠運作,而目前產生出來的WSDL文件中使用的是「localhost」,這或許是Visual Studio 11 Beta測試版的關係。

建立WCF用戶端

最後我們寫了一個Console應用程式來叫用WCF服務。在目前的方案中加入Console應用程式,從Visual Studio 11 Beta工具「File」-「Add」-「New Project」選取「Console Application」,命名為「ConsoleClient」。

在「Solution Explorer」視窗,選取「ConsoleClient」專案,按滑鼠右鍵,在突顯示選單中選取「Add Service Reference」項目,這時會跳出一個「Security Alert」對話盒,提示服務的憑證資訊,按下「Yes」按鈕,請參考圖22所示:

clip_image044

圖 22:服務憑證。

完成之後用戶端專案會產生組態檔案,參考如下,用戶端<client>區段會產生兩個端點設定:

<?xml version = "1.0" encoding = "utf-8" ?>
<configuration>
    <startup>
        <supportedRuntime version = "v4.0" sku = ".NETFramework,Version=v4.5" />
    </startup>
    <system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <binding name = "BasicHttpBinding_IService" />
                <binding name = "BasicHttpsBinding_IService">
                    <security mode = "Transport" />
                </binding>
            </basicHttpBinding>
        </bindings>
        <client>
            <endpoint address = "http://windows_phone/MyService/Service.svc"
                binding = "basicHttpBinding" bindingConfiguration = "BasicHttpBinding_IService"
                contract = "ServiceReference1.IService" name = "BasicHttpBinding_IService" />
            <endpoint address = "https://localhost/MyService/Service.svc" binding = "basicHttpBinding"
                bindingConfiguration = "BasicHttpsBinding_IService" contract = "ServiceReference1.IService"
                name = "BasicHttpsBinding_IService" />
        </client>
    </system.serviceModel>
</configuration>

不過如前文所提,要使用SSL時,需要使用機器名稱,不可以使用「localhost」,因此目前需要手動修訂此組態檔案,將address部份,改用機器名稱:

<endpoint address = "https://windows_phone/MyService/Service.svc" binding = "basicHttpBinding"
     bindingConfiguration = "BasicHttpsBinding_IService" contract = "ServiceReference1.IService"
     name = "BasicHttpsBinding_IService" />

最後在用戶端程式Main方法中,加入以下程式碼,建立ServiceClient服務代理物件,並傳入BasicHttpsBinding_IService字串,然後叫用服務的GetData方法:

ServiceReference1.ServiceClient c = new ServiceReference1.ServiceClient( "BasicHttpsBinding_IService" );
Console.WriteLine( c.GetData(10) );

若沒有修訂組態檔案,而使用https://localhost/MyService/Service.svc URI位址來呼叫服務,則呼叫服務時,會產生例外錯誤,請參考圖23所示:

clip_image046

圖 23:使用localhost會產生例外錯誤。

支援新的繫結(Binding)

WCF 4.5新增NetHttpBinding,以支援WebSocket,可以透過HTTP(S)或WebSocket傳送二進位編碼的SOAP封包。但目前只有Windows 8 Customer Preview作業系統才可以使用WebSocket。

合約優先設計(Contract First)

WCF支援合約優先的設計方式,您可以先定義好WSDL文件或XML Schema,或者從遠端服務下載,然後利用svcutil.exe工具來產生服務或資料合約。

底下是使用 Visual Studio 11 Beta來產生資料合約的步驟,先使用Visual Studio 11 Beta建立一個WCF Service Library類型的專案。從Visual Studio 11 Beta工具「File」-「New」-「Project」-「Visual C#」 -「WCF」選取「WCF Service Library」,命名為「MyWcfService」,請參考圖24所示:

clip_image048

圖 24:新增WCF Service Library類型的專案。

首先將定義好的 XML Schema加入專案,從「SOLUTION EXPLORER」視窗-「MyWcfService」專案,按滑鼠右鍵,選取「Add」-「Existing Item」項目,然後選取XML Schema檔案,本例檔案為WcfServiceLibrary1.xsd,請參考圖25所示::

clip_image050

圖 25:加入XML Schema檔案。

WcfServiceLibrary1.xsd 檔案的內容如下:

<?xml version = "1.0" encoding = "utf-8"?>
<xs:schema xmlns:tns = "http://schemas.datacontract.org/2004/07/WcfServiceLibrary1" elementFormDefault = "qualified" targetNamespace = "http://schemas.datacontract.org/2004/07/WcfServiceLibrary1" xmlns:xs = "http://www.w3.org/2001/XMLSchema">
  <xs:complexType name = "CompositeType">
    <xs:sequence>
      <xs:element minOccurs = "0" name = "BoolValue" type = "xs:boolean" />
      <xs:element minOccurs = "0" name = "StringValue" nillable = "true" type = "xs:string" />
    </xs:sequence>
  </xs:complexType>
  <xs:element name = "CompositeType" nillable = "true" type = "tns:CompositeType" />
</xs:schema>

從「SOLUTION EXPLORER」視窗-「MyWcfService」專案,按滑鼠右鍵,選取「Properties」開啟專案屬性頁,在屬性頁中選取「WCF Options」區段,預設勾選了「Enable XSD as type definition language」項目,表示可以從XML Schema產生資料合約類別,請參考圖26所示:

clip_image052

圖 26:勾選「Enable XSD as type definition language」項目。

點選畫面中的「Advanced」按鈕,會進入到「Advanced Contract Code Generation Settings」對話盒,在此可以進一步設定要使用的序列化的模式,例如使用XML Serializer或DataContract Serializer。也可以定義遇到Collection與Dictionary類型的資料該如何處理,請參考圖27所示:

clip_image054

圖 27:資料合約序列化進階設定。

「NamespaceMappings」項目則定義了產生的資料合約的命名空間。而「Output Directory」則設定將來會將資料合約的原始程式碼放在XsdGeneratedCode目錄中。

若點選「InputXsdFiles」項目,會跳出「String Collection Editor」對話盒,預設會把專案中的XSD表列在左方清單方塊之中,您可以視情況新增或移除其它的XSD檔案,請參考圖28所示:

clip_image056

圖 28:新增或移除其它的XSD檔案。

選取Visual Studio 11 Beta工具「Build」-「Build Solution」項目,編譯此方案。然後選取「View」-「Object Browser」工具,您可以看到產生出來的型別資訊,請參考圖29所示:

clip_image058

圖 29:使用Object Browser檢視型別資訊。

檢視專案下obj\Debug下的XsdGeneratedCode目錄,包含一個GeneratedXsdTypes.cs檔案,其中包含了資料合約的定義,請參考圖30所示:

clip_image060

圖 30:GeneratedXsdTypes.cs檔案包含資料合約的定義。

GeneratedXsdTypes.cs檔案內容其中如下所示:

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.17379
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace MyWcfService.ContractTypes
{
    using System.Xml.Serialization;
   
   
    /// <remarks/>
    [System.CodeDom.Compiler.GeneratedCodeAttribute("MSBuild", "4.0.30319.17379")]
    [System.SerializableAttribute()]
    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.ComponentModel.DesignerCategoryAttribute("code")]
    [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://schemas.datacontract.org/2004/07/WcfServiceLibrary1")]
    [System.Xml.Serialization.XmlRootAttribute(Namespace="http://schemas.datacontract.org/2004/07/WcfServiceLibrary1", IsNullable=true)]
    public partial class CompositeType
    {
       
        private bool boolValueField;
       
        private bool boolValueFieldSpecified;
       
        private string stringValueField;
       
        /// <remarks/>
        public bool BoolValue
        {
            get
            {
                return this.boolValueField;
            }
            set
            {
                this.boolValueField = value;
            }
        }
       
        /// <remarks/>
        [System.Xml.Serialization.XmlIgnoreAttribute()]
        public bool BoolValueSpecified
        {
            get
            {
                return this.boolValueFieldSpecified;
            }
            set
            {
                this.boolValueFieldSpecified = value;
            }
        }
       
        /// <remarks/>
        [System.Xml.Serialization.XmlElementAttribute(IsNullable=true)]
        public string StringValue
        {
            get
            {
                return this.stringValueField;
            }
            set
            {
                this.stringValueField = value;
            }
        }
    }
}


有了資料合約之後,您就可以將它加入WCF服務的專案來使用。例如使用Visual Studio 11 Beta工具「File」-「Add」-「New Web Site」加入一個WCF Service類型的網站,命名為「WCFService1」,請參考圖31所示:

clip_image062

圖 31:加入WCF服務。

從「SOLUTION EXPLORER」視窗-「WCFService1」專案-按滑鼠右鍵,選取「Add Reference」,在「Reference Manager」對話盒中勾選包含資料合約定義的「MyWcfService」專案,然後按下「OK」按鈕,請參考圖32所示:。

clip_image064

圖 32:加入專案參考。

預設的WCF服務範本中包含一個IService.cs檔案,在IService.cs先引用MyWcfService.ContractTypes命名空間,然後刪除原有的CompositeType類別的定義,然後將檔案程式碼修改如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

using MyWcfService.ContractTypes;


[ServiceContract]
public interface IService
{

    [OperationContract]
    string GetData( int value );

    [OperationContract]
    CompositeType GetDataUsingDataContract( CompositeType composite );

}

同樣地在Service.cs檔案的最上方,引用MyWcfService.ContractTypes命名空間:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

using MyWcfService.ContractTypes;


public class Service : IService
{
    public string GetData( int value )
    {
        return string.Format( "You entered: {0}", value );
    }

    public CompositeType GetDataUsingDataContract( CompositeType composite )
    {
        if (composite == null)
        {
            throw new ArgumentNullException("composite");
        }
        if (composite.BoolValue)
        {
            composite.StringValue += "Suffix";
        }
        return composite;
    }
}


這樣服務就可以正常運作了。

Tags:

.NET Magazine國際中文電子雜誌 | WCF | 許薰尹Vivid Hsu

新增評論




  Country flag
biuquote
  • 評論
  • 線上預覽
Loading






NET Magazine國際中文電子雜誌

NET Magazine國際中文電子版雜誌,由恆逸資訊創立於2000,自發刊日起迄今已發行超過500篇.NET相關技術文章,擁有超過40000名註冊讀者群。NET Magazine國際中文電子版雜誌希望藉於電子雜誌與NET Developer達到共同學習與技術新知分享,歡迎每一位對.NET 技術有興趣的朋友們多多支持本雜誌,讓作者群們可以有持續性的動力繼續爬文。<請加入免費訂閱>

月分類Month List