承接上篇,本文著重於 HTTP-GET 方式發布元資料的內部實作。不同於 WS-MEX 僅需自訂 MEX 端點的 DispatchRuntime,HTTP-GET 需從 ChannelDispatcher 起重建完整分發體系。我們將自訂的 ServiceMetadataBehaviorAttribute 擴充,同時支援兩種發布模式。
IHttpGetMetadata 契約,其 Get 操作接受/回傳 Message,Action/ReplyAction 為 *。MetadataProvisionService 實作此介面。CreateHttpGetChannelDispatcher 方法,組裝 TextMessageEncodingBindingElement(MessageVersion.None)與 HttpTransportBindingElement(Method=GET)組成 CustomBinding。ChannelListener、ChannelDispatcher、EndpointDispatcher,並自訂其 DispatchRuntime:設定 DispatchOperation、MessageOperationFormatter、SyncMethodInvoker、SingletonInstanceContext 等。ContractFilter、AddressFilter 設為 MatchAllMessageFilter,最後加入 ServiceHost 的 ChannelDispatchers。private static void CreateHttpGetChannelDispatcher(ServiceHostBase host, Uri listenUri, MetadataSet metadata)
{
// 建立 Binding
TextMessageEncodingBindingElement messageEncodingElement = new TextMessageEncodingBindingElement() { MessageVersion = MessageVersion.None };
HttpTransportBindingElement transportElement = new HttpTransportBindingElement();
Utility.SetPropertyValue(transportElement, "Method", "GET");
Binding binding = new CustomBinding(messageEncodingElement, transportElement);
// 建立 ChannelListener
IChannelListener listener = binding.BuildChannelListener<IReplyChannel>(listenUri, string.Empty, ListenUriMode.Explicit, new BindingParameterCollection());
ChannelDispatcher dispatcher = new ChannelDispatcher(listener, "ServiceMetadataBehaviorHttpGetBinding", binding) { MessageVersion = binding.MessageVersion };
// 建立 EndpointDispatcher
EndpointDispatcher endpoint = new EndpointDispatcher(new EndpointAddress(listenUri), "IHttpGetMetadata", "https://www.artech.com/");
// 建立 DispatchOperation,設定 Formatter 與 Invoker
DispatchOperation operation = new DispatchOperation(endpoint.DispatchRuntime, "Get", "*", "*");
operation.Formatter = Utility.CreateInstance<IDispatchMessageFormatter>(MessageOperationFormatterType, Type.EmptyTypes, new object[0]);
MethodInfo method = typeof(IHttpGetMetadata).GetMethod("Get");
operation.Invoker = Utility.CreateInstance<IOperationInvoker>(SyncMethodInvokerType, new Type[] { typeof(MethodInfo) }, new object[] { method });
endpoint.DispatchRuntime.Operations.Add(operation);
// 設定 SingletonInstanceContext 與 InstanceContextProvider
MetadataProvisionService serviceInstance = new MetadataProvisionService(metadata);
endpoint.DispatchRuntime.SingletonInstanceContext = new InstanceContext(host, serviceInstance);
endpoint.DispatchRuntime.InstanceContextProvider = Utility.CreateInstance<IInstanceContextProvider>(SingletonInstanceContextProviderType, new Type[] { typeof(DispatchRuntime) }, new object[] { endpoint.DispatchRuntime });
dispatcher.Endpoints.Add(endpoint);
// 設定過濾器
endpoint.ContractFilter = new MatchAllMessageFilter();
endpoint.AddressFilter = new MatchAllMessageFilter();
host.ChannelDispatchers.Add(dispatcher);
}
在 ApplyDispatchBehavior 中依 HttpGetEnabled、HttpGetUrl 決定是否啟用。最終將自訂 Attribute 應用於服務類別,寄宿成功後即可直接用瀏覽器存取 HttpGetUrl 取得 WSDL(圖 2)。

圖 2 通過 IE 獲取發布的元資料