共用方式為


自訂服務主機

CustomServiceHost 範例示範如何使用 類別的ServiceHost自定義衍生專案來改變服務的運行時間行為。 此方法提供可重複使用的替代方案,讓您以一般方式設定大量服務。 此範例也會示範如何使用 ServiceHostFactory 類別,在 Internet Information Services (IIS) 或 Windows Process Activation Service (WAS) 裝載環境中使用自定義 ServiceHost。

關於案例

為了避免意外洩漏潛在的敏感性服務元數據,Windows Communication Foundation (WCF) 服務的預設設定會停用元數據發佈。 此行為預設是安全的,但也表示您無法使用元數據匯入工具(例如 Svcutil.exe)來產生呼叫服務所需的用戶端程序代碼,除非服務元數據發佈行為在組態中明確啟用。

為大量服務啟用元數據發佈需要將相同的配置元素新增至每個服務中,這樣會導致組態資訊大量重複。 除了個別設定每個服務,也可以撰寫命令式程式碼,讓元數據發行一次,然後跨數個不同的服務重複使用該程序代碼。 這是透過建立一個衍生自ServiceHost的新類別,並覆寫ApplyConfiguration()方法以強制地新增元數據發佈行為來完成的。

這很重要

為了清楚起見,此範例示範如何建立不安全的元數據發佈端點。 這類端點可能可供匿名未經驗證的取用者使用,而且在部署這類端點之前必須小心,以確保公開披露服務的元數據是適當的。

實作自定義 ServiceHost

類別 ServiceHost 會公開數個有用的虛擬方法,繼承者可以覆寫以改變服務的運行時間行為。 例如,ApplyConfiguration()方法會從組態存放區讀取服務組態資訊,並據此更改主機的ServiceDescription。 默認實作會從應用程式的組態檔讀取組態。 自定義實作可以覆寫 ApplyConfiguration() 以進一步改變 ServiceDescription 使用命令式程序代碼,甚至完全取代預設組態存放區。 例如,從資料庫讀取服務的端點組態,而不是應用程式的組態檔。

在此範例中,我們想要建立一個自訂的 ServiceHost,來新增 ServiceMetadataBehavior(啟用元資料發佈的功能),即便此行為未明確列入服務的配置檔中也一樣。 若要達成此目的,請建立繼承自 ServiceHost 的新類別並覆寫 ApplyConfiguration()。

class SelfDescribingServiceHost : ServiceHost
{
    public SelfDescribingServiceHost(Type serviceType, params Uri[] baseAddresses)
        : base(serviceType, baseAddresses) { }

    //Overriding ApplyConfiguration() allows us to
    //alter the ServiceDescription prior to opening
    //the service host.
    protected override void ApplyConfiguration()
    {
        //First, we call base.ApplyConfiguration()
        //to read any configuration that was provided for
        //the service we're hosting. After this call,
        //this.Description describes the service
        //as it was configured.
        base.ApplyConfiguration();

        //(rest of implementation elided for clarity)
    }
}

因為我們不想忽略應用程式組態檔中提供的任何設定,所以我們覆寫 ApplyConfiguration的第一件事就是呼叫基底實作。 這個方法完成後,我們可以使用下列命令式程序代碼,以命令方式將 新增 ServiceMetadataBehavior 至描述。

ServiceMetadataBehavior mexBehavior = this.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (mexBehavior == null)
{
    mexBehavior = new ServiceMetadataBehavior();
    this.Description.Behaviors.Add(mexBehavior);
}
else
{
    //Metadata behavior has already been configured,
    //so we do not have any work to do.
    return;
}

我們 ApplyConfiguration() 覆寫必須執行的最後一件事是新增預設元數據端點。 根據慣例,服務主機的BaseAddresses集合中會為每個URI建立一個元數據端點。

//Add a metadata endpoint at each base address
//using the "/mex" addressing convention
foreach (Uri baseAddress in this.BaseAddresses)
{
    if (baseAddress.Scheme == Uri.UriSchemeHttp)
    {
        mexBehavior.HttpGetEnabled = true;
        this.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName,
                                MetadataExchangeBindings.CreateMexHttpBinding(),
                                "mex");
    }
    else if (baseAddress.Scheme == Uri.UriSchemeHttps)
    {
        mexBehavior.HttpsGetEnabled = true;
        this.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName,
                                MetadataExchangeBindings.CreateMexHttpsBinding(),
                                "mex");
    }
    else if (baseAddress.Scheme == Uri.UriSchemeNetPipe)
    {
        this.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName,
                                MetadataExchangeBindings.CreateMexNamedPipeBinding(),
                                "mex");
    }
    else if (baseAddress.Scheme == Uri.UriSchemeNetTcp)
    {
        this.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName,
                                MetadataExchangeBindings.CreateMexTcpBinding(),
                                "mex");
    }
}

在自我主機中使用自定義 ServiceHost

既然我們已經完成自定義 ServiceHost 實作,我們可以使用它,將元數據發佈行為新增至任何服務,方法是將該服務裝載在我們的 實例 SelfDescribingServiceHost內。 下列程式代碼示範如何在自托管情境中使用。

SelfDescribingServiceHost host =
         new SelfDescribingServiceHost( typeof( Calculator ) );
host.Open();

我們的自定義主機仍會從應用程式的組態檔讀取服務的端點組態,就像我們已使用預設 ServiceHost 類別來裝載服務一樣。 不過,因為我們新增了邏輯來啟用自定義主機內部的元數據發佈,因此我們不再需要在組態中明確啟用元數據發佈行為。 當您建置包含數個服務的應用程式時,此方法具有明顯的優勢,而且您想要在每一個服務上啟用元數據發佈,而不需多次寫入相同的組態專案。

在 IIS 或 WAS 中使用自定義 ServiceHost

在自我托管場景中使用自訂服務主機很簡單,因為它是您的應用程式碼,最終負責建立和開啟服務主機實例。 不過,在 IIS 或 WAS 裝載環境中,WCF 基礎結構會動態具現化服務的主機,以回應傳入訊息。 自定義服務主機也可用於此裝載環境中,但它們需要 ServiceHostFactory 形式的一些額外程式代碼。 下列程式代碼顯示一個從 ServiceHostFactory 衍生的類別,它會傳回我們自定義 SelfDescribingServiceHost 的實例。

public class SelfDescribingServiceHostFactory : ServiceHostFactory
{
    protected override ServiceHost CreateServiceHost(Type serviceType,
     Uri[] baseAddresses)
    {
        //All the custom factory does is return a new instance
        //of our custom host class. The bulk of the custom logic should
        //live in the custom host (as opposed to the factory)
        //for maximum
        //reuse value outside of the IIS/WAS hosting environment.
        return new SelfDescribingServiceHost(serviceType,
                                             baseAddresses);
    }
}

如您所見,實作自定義 ServiceHostFactory 很簡單。 所有自定義邏輯都位於 ServiceHost 實作內;Factory 會傳回衍生類別的實例。

若要使用自定義處理站搭配服務實作,我們必須將一些額外的元數據新增至服務的 .svc 檔案。

<% @ServiceHost Service="Microsoft.ServiceModel.Samples.CalculatorService"
               Factory="Microsoft.ServiceModel.Samples.SelfDescribingServiceHostFactory"
               language=c# Debug="true" %>

在這裡,我們已將額外的 Factory 屬性新增至 @ServiceHost 指令,並將自定義工廠的 CLR 類型名稱作為屬性的值傳遞。 當 IIS 或 WAS 收到此服務的訊息時,WCF 裝載基礎結構會先建立 ServiceHostFactory 的實例,然後呼叫 ServiceHostFactory.CreateServiceHost()來具現化服務主機本身。

執行範例

雖然此範例確實提供功能完整的客戶端和服務實作,但此範例的重點是說明如何透過自定義主機改變服務的運行時間行為。請執行下列步驟:

觀察自定義主機的效果

  1. 開啟服務的 Web.config 檔案,並觀察沒有明確啟用服務的元數據設定。

  2. 開啟服務的 .svc 檔案,並觀察其 @ServiceHost 指示詞包含指定自定義 ServiceHostFactory 名稱的 Factory 屬性。

設定、建置和執行範例

  1. 請確定您已針對 Windows Communication Foundation 範例 執行One-Time 安裝程式。

  2. 若要建置解決方案,請遵循 建置 Windows Communication Foundation 範例中的指示。

  3. 建置解決方案之後,請執行 Setup.bat 在 IIS 7.0 中設定 ServiceModelSamples 應用程式。 ServiceModelSamples 目錄現在應該會顯示為 IIS 7.0 應用程式。

  4. 若要在單一或跨計算機組態中執行範例,請遵循執行 Windows Communication Foundation 範例 中的指示。

  5. 若要移除 IIS 7.0 應用程式,請執行 Cleanup.bat

另請參閱