組態與中繼資料支援

這個主題描述如何啟用繫結和繫結項目的組態與中繼資料支援。

組態與中繼資料概觀

這個主題討論下列工作,這些工作是開發通道工作清單中的選用項目 1、2 和 4。

  • 啟用繫結項目的組態檔支援。
  • 啟用繫結的組態檔支援。
  • 匯出繫結項目的 WSDL 和原則判斷提示。
  • 識別要插入並設定繫結或繫結項目的 WSDL 和原則判斷提示。

如需建立使用者定義繫結和繫結項目的相關資訊,請分別參閱建立使用者定義繫結建立 BindingElement

新增組態支援

若要啟用通道的組態檔支援,您必須實作兩個組態區段,其中一個是 System.ServiceModel.Configuration.BindingElementExtensionElement,它會啟用繫結項目的組態支援;而另一個是 System.ServiceModel.Configuration.StandardBindingElementSystem.ServiceModel.Configuration.StandardBindingCollectionElement,它會啟用繫結的組態支援。

若要達到這個目的,其中一個較容易的方法是使用 ConfigurationCodeGenerator 範例工具,以產生繫結和繫結項目的組態程式碼。

延伸 BindingElementExtensionElement

下列範例程式碼是取自Transport: UDP 範例。 ``UdpTransportElementBindingElementExtensionElement,它會將 UdpTransportBindingElement 公開至組態系統。範例會使用一些基本的覆寫,定義組態區段名稱、繫結項目的型別,以及如何建立繫結項目。然後使用者可以在組態檔中登錄延伸區段,如同下列所示。

<configuration>
  <system.serviceModel>
    <extensions>
      <bindingElementExtensions>
      <add name="udpTransport" type="Microsoft.ServiceModel.Samples.UdpTransportElement, UdpTransport />
      </bindingElementExtensions>
    </extensions>
  </system.serviceModel>
</configuration>

您可以從自訂繫結參考該延伸,以使用 UDP 做為傳輸方式。

<configuration>
  <system.serviceModel>
    <bindings>
      <customBinding>
       <binding configurationName="UdpCustomBinding">
         <udpTransport/>
       </binding>
      </customBinding>
    </bindings>
  </system.serviceModel>
</configuration>

新增繫結組態

區段 ``SampleProfileUdpBindingCollectionElementStandardBindingCollectionElement,它會將 SampleProfileUdpBinding 公開至組態系統。大量實作會委派至衍生自 StandardBindingElementSampleProfileUdpBindingConfigurationElementSampleProfileUdpBindingConfigurationElement 的某些屬性會對應至 SampleProfileUdpBinding 的屬性,以及有些從 ConfigurationElement 繫結對應的函式。最後,在 SampleProfileUdpBinding 中會覆寫 OnApplyConfiguration 方法,如同下列範例程式碼所示。

protected override void OnApplyConfiguration(string configurationName)
{
            if (binding == null)
                throw new ArgumentNullException("binding");

            if (binding.GetType() != typeof(SampleProfileUdpBinding))
            {
                throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
                    "Invalid type for binding. Expected type: {0}. Type passed in: {1}.",
                    typeof(SampleProfileUdpBinding).AssemblyQualifiedName,
                    binding.GetType().AssemblyQualifiedName));
            }
            SampleProfileUdpBinding udpBinding = (SampleProfileUdpBinding)binding;

            udpBinding.OrderedSession = this.OrderedSession;
            udpBinding.ReliableSessionEnabled = this.ReliableSessionEnabled;
            udpBinding.SessionInactivityTimeout = this.SessionInactivityTimeout;
            if (this.ClientBaseAddress != null)
                   udpBinding.ClientBaseAddress = ClientBaseAddress;
}

若要使用組態系統註冊這個處理常式,請將下列區段新增至相關的組態檔。

<configuration>
  <configSections>
     <sectionGroup name="system.serviceModel">
         <sectionGroup name="bindings">
                 <section name="sampleProfileUdpBinding" type="Microsoft.ServiceModel.Samples.SampleProfileUdpBindingCollectionElement, UdpTransport />
         </sectionGroup>
     </sectionGroup>
  </configSections>
</configuration>

然後就可以從 <system.ServiceModel> 組態區段參考它。

<configuration>
  <system.serviceModel>
    <client>
      <endpoint configurationName="calculator"
                address="soap.udp://localhost:8001/" 
                bindingConfiguration="CalculatorServer"
                binding="sampleProfileUdpBinding" 
                contract= "Microsoft.ServiceModel.Samples.ICalculatorContract">
      </endpoint>
    </client>
  </system.serviceModel>
</configuration>

新增繫結項目的中繼資料支援

若要將通道整合至中繼資料系統,通道必須同時支援匯入與匯出原則。這可以讓像是 ServiceModel Metadata Utility Tool (Svcutil.exe) 的工具產生繫結項目的用戶端。

新增 WSDL 支援

繫結中的傳輸繫結項目是負責匯出與匯入中繼資料中的定址資訊。當使用 SOAP 繫結時,傳輸繫結項目也應該匯出中繼資料中的正確傳輸 URI。下列範例程式碼是取自Transport: UDP 範例。

WSDL 匯出

若要匯出定址資訊,UdpTransportBindingElement 會實作 System.ServiceModel.Description.IWsdlExportExtension 介面。System.ServiceModel.Description.IWsdlExportExtension.ExportEndpoint(System.ServiceModel.Description.WsdlExporter,System.ServiceModel.Description.WsdlEndpointConversionContext) 方法會將正確的定址資訊新增至 WSDL 連接埠。

if (context.WsdlPort != null)
{
    AddAddressToWsdlPort(context.WsdlPort, context.Endpoint.Address, encodingBindingElement.MessageVersion.Addressing);
}

當端點使用 SOAP 繫結時,ExportEndpoint 方法的 UdpTransportBindingElement 實作也會匯出傳輸 URI:

WsdlNS.SoapBinding soapBinding = GetSoapBinding(context, exporter);
if (soapBinding != null)
{
    soapBinding.Transport = UdpPolicyStrings.UdpNamespace;
}

WSDL 匯入

若要延伸 WSDL 匯入系統以處理位址匯入,請將下列組態新增至 Svcutil.exe 的組態檔中,如同 Svcutil.exe.config 檔中所示:

<configuration>
  <system.serviceModel>
    <client>
      <metadata>
        <wsdlImporters>
          <extension type=" Microsoft.ServiceModel.Samples.UdpBindingElementImporter, UdpTransport" />
        </policyImporters>
      </metadata>
    </client>
  </system.serviceModel>
</configuration>

當執行 Svcutil.exe 時,有兩個選項可以讓 Svcutil.exe 載入 WSDL 匯入延伸:

  1. 使用 /SvcutilConfig:<file> 將 Svcutil.exe 指向組態檔。
  2. 將組態區段新增至與 Svcutil.exe 位於相同目錄的 Svcutil.exe.config 中。

UdpBindingElementImporter 型別會實作 System.ServiceModel.Description.IWsdlImportExtension 介面。ImportEndpoint 方法會從 WSDL 連接埠匯入位址:

BindingElementCollection bindingElements = context.Endpoint.Binding.CreateBindingElements();
TransportBindingElement transportBindingElement = bindingElements.Find<TransportBindingElement>();
if (transportBindingElement is UdpTransportBindingElement)
{
    ImportAddress(context);
}

新增原則支援

自訂繫結項目可以匯出服務端點之 WSDL 繫結的原則判斷提示,以表示該繫結項目的功能。下列範例程式碼是取自Transport: UDP 範例。

原則匯出

UdpTransportBindingElement 型別會實作 System.ServiceModel.Description.IPolicyExportExtension 以增加對匯出原則的支援。因此,System.ServiceModel.Description.MetadataExporter 會針對包含它的任何繫結,在產生原則時包含 UdpTransportBindingElement

System.ServiceModel.Description.IPolicyExportExtension.ExportPolicy(System.ServiceModel.Description.MetadataExporter,System.ServiceModel.Description.PolicyConversionContext) 中,新增 UDP 的判斷提示和其他判斷提示 (如果通道使用多點傳送模式)。這是因為多點傳送模式會影響通訊堆疊的建構方式,所以必須同時對兩端進行協調。

ICollection<XmlElement> bindingAssertions = context.GetBindingAssertions();
XmlDocument xmlDocument = new XmlDocument();
bindingAssertions.Add(xmlDocument.CreateElement(
UdpPolicyStrings.Prefix, UdpPolicyStrings.TransportAssertion, UdpPolicyStrings.UdpNamespace));
if (Multicast)
{
    bindingAssertions.Add(xmlDocument.CreateElement(
UdpPolicyStrings.Prefix, UdpPolicyStrings.MulticastAssertion,     UdpPolicyStrings.UdpNamespace));
}

因為自訂傳輸繫結項目會負責處理定址,所以 UdpTransportBindingElement 上的 System.ServiceModel.Description.IPolicyExportExtension 實作也必須處理適當之 WS-Addressing 原則判斷提示的匯出,以表示所使用的 WS-Addressing 版本。

AddWSAddressingAssertion(context, encodingBindingElement.MessageVersion.Addressing);

原則匯入

若要延伸原則匯入系統,請將下列組態新增至 Svcutil.exe 的組態檔中,如同 Svcutil.exe.config 檔中所示:

<configuration>
  <system.serviceModel>
    <client>
      <metadata>
        <policyImporters>
          <extension type=" Microsoft.ServiceModel.Samples.UdpBindingElementImporter, UdpTransport" />
        </policyImporters>
      </metadata>
    </client>
  </system.serviceModel>
</configuration>

然後從已註冊類別 (UdpBindingElementImporter) 實作 System.ServiceModel.Description.IPolicyImportExtension。在 System.ServiceModel.Description.IPolicyImportExtension.ImportPolicy(System.ServiceModel.Description.MetadataImporter,System.ServiceModel.Description.PolicyConversionContext) 中,檢視適當命名空間的判斷提示,然後處理用來產生傳輸的判斷提示,並且檢查其是否使用多點傳送。此外,從繫結判斷提示清單中移除匯入工具處理的判斷提示。同樣地,當執行 Svcutil.exe 時有兩個整合的選項:

  1. 使用 /SvcutilConfig:<file> 將 Svcutil.exe 指向組態檔。
  2. 將組態區段新增至與 Svcutil.exe 位於相同目錄的 Svcutil.exe.config 中。

新增自訂標準繫結匯入工具

根據預設,Svcutil.exe 和 System.ServiceModel.Description.WsdlImporter 型別會識別與匯入系統提供的繫結。否則,會將繫結當做 System.ServiceModel.Channels.CustomBinding 執行個體匯入。為了讓 Svcutil.exe 和 WsdlImporter 能夠匯入 SampleProfileUdpBindingUdpBindingElementImporter 也會當做自訂標準繫結匯入工具。

自訂標準繫結匯入工具會實作 System.ServiceModel.Description.IWsdlImportExtension 介面上的 ImportEndpoint 方法,檢視從中繼資料匯入的 System.ServiceModel.Channels.CustomBinding 執行個體,以檢查特定標準繫結是否已產生該執行個體。

if (context.Endpoint.Binding is CustomBinding)
{
    Binding binding;
    if (transportBindingElement is UdpTransportBindingElement)
    {
        //if TryCreate is true, the CustomBinding will be replace by a SampleProfileUdpBinding in the
        //generated config file for better typed generation.
        if (SampleProfileUdpBinding.TryCreate(bindingElements, out binding))
        {
            binding.Name = context.Endpoint.Binding.Name;
            binding.Namespace = context.Endpoint.Binding.Namespace;
            context.Endpoint.Binding = binding;
        }
    }
}

一般來說,實作自訂標準繫結匯入工具包含檢查已匯入之繫結項目的屬性,以驗證只有變更由標準繫結設定的屬性,而所有其他屬性都還是預設值。實作標準繫結匯入工具的基本策略,是建立標準繫結的執行個體、從繫結項目將屬性傳播至標準繫結支援的標準繫結執行個體,然後比較標準繫結與已匯入繫結項目上的繫結項目。