我們有兩種典型的WCF調用方式:通過SvcUtil.exe(或者添加Web引用)導入發布的服務元數據生成服務代理相關的代碼和配置;通過ChannelFactory<TChannel>創建服務代理對象。在這篇文章中,我們采用一種獨特的方式進行服務的調用。從本質上講,我們只要能夠創建於服務端相匹配的終結點,就能夠實現正常的服務調用。在WCF客戶端元數據架構體系中,利用MetadataExchangeClient可以獲取服務的元數據,而利用MetadataImporter將獲取的元數據導入成ServiceEndpoint對象。在本例中,我們將利用這兩個組件定義了一個獨特的服務調用的簡單的例子,相信可以幫助讀者進一步加深對WCF元數據框架體系的理解。
本文配套源碼:http://www.bianceng.net/dotnet/201212/656.htm
我們依然采用我們熟悉的計算服務的例子,下面是該服務相應的服務契約、服務類型的定義和寄宿該服務采用的配置。
1: using System.ServiceModel;
2: namespace Artech.ServiceInvocationViaMetadata.Contracts
3: {
4: [ServiceContract(Namespace = "http://www.artech.com/")]
5: public interface ICalculator
6: {
7: [OperationContract]
8: double Add(double x, double y);
9: }
10: }
服務類型:
1: using System.ServiceModel;
2: using Artech.ServiceInvocationViaMetadata.Contracts;
3:
4: namespace Artech.ServiceInvocationViaMetadata.Services
5: {
6: public class CalculatorService : ICalculator
7: {
8: public double Add(double x, double y)
9: {
10: return x + y;
11: }
12: }
13: }
配置:
1: <?xml version="1.0" encoding="utf-8" ?>
2: <configuration>
3: <system.serviceModel>
4: <behaviors>
5: <serviceBehaviors>
6: <behavior name="mexBehavior">
7: <serviceMetadata />
8: </behavior>
9: </serviceBehaviors>
10: </behaviors>
11: <services>
12: <service behaviorConfiguration="mexBehavior" name="Artech.ServiceInvocationViaMetadata.Services.CalculatorService">
13: <endpoint address="http://127.0.0.1:3721/calculatorservice" binding="ws2007HttpBinding" contract="Artech.ServiceInvocationViaMetadata.Contracts.ICalculator" />
14: <endpoint address="http://127.0.0.1:3721/calculatorservice/mex" binding="mexHttpBinding" contract="IMetadataExchange" />
15: </service>
16: </services>
17: </system.serviceModel>
18: </configuration>
從上面的配置我們可以看到,服務的元數據通過WS-MEX模式發布出來,發布的地址和采用的MEX綁定分別為:http://127.0.0.1:3721/calculatorservice/mex和mexHttpBinding。
接下來,我們就可以通過下面的方式對該服務進行調用了。我們先創建MetadataExchangeClient對象並利用它獲取包含元數據的MetadataSet對象,並利用該對象創建WsdlImporter對象。接下來,我們將基於ICalculator接口的服務契約添加到該WsdlImporter的已知契約列表中,調用ImportAllEndpoints方法得到導入的ServiceEndpoint列表。最後根據導出的ServiceEndpoint對象創建ChannelFactory<ICalculator>對象,並創建服務代理進行服務調用。
1: sing System;
2: using System.ServiceModel;
3: using System.ServiceModel.Description;
4: using System.Xml;
5: using Artech.ServiceInvocationViaMetadata.Contracts;
6: namespace Artech.ServiceInvocationViaMetadata.Client
7: {
8: class Program
9: {
10: static void Main(string[] args)
11: {
12: MetadataExchangeClient metadataExchangeClient = new MetadataExchangeClient(MetadataExchangeBindings.CreateMexHttpBinding());
13: MetadataSet metadata = metadataExchangeClient.GetMetadata(new EndpointAddress("http://127.0.0.1:3721/calculatorservice/mex"));
14: WsdlImporter wsdlImporter = new WsdlImporter(metadata);
15: //添加已知契約類型
16: ContractDescription contract = ContractDescription.GetContract(typeof(ICalculator));
17: wsdlImporter.KnownContracts.Add(new XmlQualifiedName(contract.Name, contract.Namespace), contract);
18: ServiceEndpointCollection endpoints = wsdlImporter.ImportAllEndpoints();
19: using (ChannelFactory<ICalculator> channelFactory = new ChannelFactory<ICalculator>(endpoints[0]))
20: {
21: ICalculator calculator = channelFactory.CreateChannel();
22: using (calculator as IDisposable)
23: {
24: try
25: {
26: Console.WriteLine("x + y = {2} when x = {0} and y = {1}", 1, 2, calculator.Add(1, 2));
27: }
28: catch(TimeoutException)
29: {
30: (calculator as ICommunicationObject).Abort();
31: throw;
32: }
33: catch(CommunicationException)
34: {
35: (calculator as ICommunicationObject).Abort();
36: throw;
37: }
38: }
39: }
40: Console.Read();
41: }
42: }
43: }