例2-1:服务端的操作重载
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; namespace WCFServiceProgramming { [ServiceContract] class ICalculator { [OperationContract(Name = "AddInt")] int Add(int arg1, int arg2); [OperationContract(Name = "AddDouble")] double Add(double arg1, double arg2); } }
例2-2:客户端操作重载
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; namespace WCFServiceProgramming { public partial class CalculatorClient : ClientBase<ICalculator>, ICalculator { public int Add(int arg1, int arg2) { return Channel.Add(arg1, arg2); } public double Add(double arg1, double arg2) { return Channel.Add(arg1, arg2); } } }
例 2-3:服务端契约层级
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; namespace WCFServiceProgramming { [ServiceContract] interface ISimpleCalculator { [OperationContract] int Add(int arg1, int arg2); } [ServiceContract] interface IScientificCalculator : ISimpleCalculator { [OperationContract] int Multiply(int arg1, int arg2); } class MyCalculator : IScientificCalculator { public int Multiply(int arg1, int arg2) { return arg1 * arg2; } public int Add(int arg1, int arg2) { return arg1 + arg2; } } }
例2-4:取消层级关系的客户端定义
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; namespace WCFServiceProgramming { [ServiceContract] public interface IScientificCalculator { [OperationContract(Action=".../ISimpleCalculator/Add", ReplyAction=".../ISimpleCalculator/AddResponse")] int Add(int arg1, int arg2); [OperationContract(Action=".../IScientificCalculator/Multiply", ReplyAction=".../IScientificCalculator/MultiplyResponse")] int Multiply(int arg1, int arg2); } public partial class ScientificCalculatorClient : ClientBase<IScientificCalculator>, IScientificCalculator { public int Add(int arg1, int arg2) { return arg1 + arg2; } public int Multiply(int arg1, int arg2) { return arg1 * arg2; } } }
例2-5:客户端契约层级
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; namespace WCFServiceProgramming { [ServiceContract] public interface ISimpleCalculator { [OperationContract] int Add(int arg1, int arg2); } public partial class SimpleCalculatorClient : ClientBase<ISimpleCalculator>, ISimpleCalculator { public int Add(int arg1, int arg2) { return Channel.Add(arg1, arg2); } } [ServiceContract] public interface IScientificCalculator : ISimpleCalculator { [OperationContract] int Multiply(int arg1, int arg2); } public partial class ScientificCalculatorClient : ClientBase<IScientificCalculator>, IScientificCalculator { public int Add(int arg1, int arg2) { return Channel.Add(arg1, arg2); } public int Multiply(int arg1, int arg2) { return Channel.Multiply(arg1, arg2); } } }
例2-6:代理链
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; namespace WCFServiceProgramming { [ServiceContract] public interface ISimpleCalculator { [OperationContract] int Add(int arg1, int arg2); } [ServiceContract] public interface IScientificCalculator : ISimpleCalculator { [OperationContract] int Multiply(int arg1, int arg2); } public partial class SimpleCalculatorClient : ClientBase<IScientificCalculator>, ISimpleCalculator { public int Add(int arg1, int arg2) { return Channel.Add(arg1, arg2); } } public partial class ScientificCalculatorClient : SimpleCalculatorClient, IScientificCalculator { public int Multiply(int arg1, int arg2) { return Channel.Multiply(arg1, arg2); } } }
例2-7:支持元数据处理的类型
using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Runtime; using System.Xml; using System.Xml.Serialization; using System.Net; using System.Net.Mime; using System.ServiceModel; using System.ServiceModel.Channels; using System.Text; namespace System.ServiceModel.Description { public enum MetadataExchangeClientMode { MetadataExchange = 0, HttpGet = 1, } public class MetadataSet : IXmlSerializable { } public class ServiceEndpointCollection : Collection<ServiceEndpoint> { } public class MetadataExchangeClient { public MetadataExchangeClient(); public MetadataExchangeClient(Binding mexBinding); public MetadataExchangeClient(Uri address, MetadataExchangeClientMode mode); public MetadataSet GetMetadata(); public MetadataSet GetMetadata(EndpointAddress address); } public abstract class MetadataImporter { public abstract ServiceEndpointCollection ImportAllEndpoints(); } public class WsdlImporter : MetadataImporter { public WsdlImporter(MetadataSet metadata); } public class ServiceEndpoint { public EndpointAddress Address { get; set; } public Binding Binding { get; set; } public ContractDescription Contract { get; set; } } public class ContractDescription { public string Name { get; set; } public string Namespace { get; set; } } }
例2-8:查询契约的地址
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; using System.ServiceModel.Channels; using System.ServiceModel.Description; namespace WCFServiceProgramming { class Program { static void Main(string[] args) { bool contractSupported = false; string mexAddress = "...?WSDL"; MetadataExchangeClient mexClient = new MetadataExchangeClient( new Uri(mexAddress), MetadataExchangeClientMode.HttpGet); MetadataSet metadata = mexClient.GetMetadata(); MetadataImporter importer = new WsdlImporter(metadata); ServiceEndpointCollection endpoints = importer.ImportAllEndpoints(); foreach (ServiceEndpoint endpoint in endpoints) { if (endpoint.Contract.Namespace == "MyNamespace" && endpoint.Contract.Name == "IMyContract") { contractSupported = true; break; } } } } }
例 2-9 MetadataHelper.QueryContract() 的实现
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel.Description; using System.ServiceModel.Channels; using System.ServiceModel; using System.Diagnostics; namespace WCFServiceProgramming { public static class MetadataHelper { const int MessageMultiplier = 5; static ServiceEndpointCollection QueryMexEndpoint(string mexAddress, BindingElement bindingElement) { CustomBinding binding = new CustomBinding(bindingElement); MetadataExchangeClient MEXClient = new MetadataExchangeClient(binding); MetadataSet metadata = MEXClient.GetMetadata(new EndpointAddress(mexAddress)); MetadataImporter importer = new WsdlImporter(metadata); return importer.ImportAllEndpoints(); } public static ServiceEndpoint[] GetEndpoints(string mexAddress) { Uri address = new Uri(mexAddress); ServiceEndpointCollection endpoints = null; if(address.Scheme == "net.tcp") { TcpTransportBindingElement tcpBindingElement = new TcpTransportBindingElement(); tcpBindingElement.MaxReceivedMessageSize *= MessageMultiplier; endpoints = QueryMexEndpoint(mexAddress,tcpBindingElement); } if (address.Scheme == "net.pipe") { } if (address.Scheme == "http") { } if (address.Scheme == "https") { } return endpoints.ToArray(); } public static bool QueryContract(string mexAddress, Type contractType) { if (contractType.IsInterface == false) { Debug.Assert(false, contractType + " is not an interface"); return false; } object[] attributes = contractType.GetCustomAttributes( typeof(ServiceContractAttribute), false); if (attributes.Length == 0) { Debug.Assert(false, "Interface " + contractType + " does not have the ServiceContractAttribute"); return false; } ServiceContractAttribute attribute = attributes[0] as ServiceContractAttribute; if (attribute.Name == null) { attribute.Name = contractType.ToString(); } if (attribute.Namespace == null) { attribute.Namespace = "http://tempuri.org/"; } return QueryContract(mexAddress, attribute.Namespace, attribute.Name); } private static bool QueryContract(string mexAddress, string contractNamespace, string contractName) { if (String.IsNullOrEmpty(contractNamespace)) { Debug.Assert(false, "Empty namespace"); return false; } if (String.IsNullOrEmpty(contractName)) { Debug.Assert(false, "Empty name"); return false; } try { ServiceEndpoint[] endpoints = GetEndpoints(mexAddress); foreach (ServiceEndpoint endpoint in endpoints) { if (endpoint.Contract.Namespace == contractNamespace && endpoint.Contract.Name == contractName) { return true; } } } catch { } return false; } } }
例 2-10 MetadataHelper类
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel.Description; using System.ServiceModel.Channels; using System.ServiceModel; using System.Diagnostics; namespace WCFServiceProgramming { public static class MetadataHelper { public static ServiceEndpoint[] GetEndpoints(string mexAddress); public static string[] GetAddresses(string mexAddress, Type contractType); public static string[] GetAddresses(string mexAddress, string contractNamespace, string contractName); public static string[] GetAddresses(Type bindingType, string mexAddress, Type contractType); public static string[] GetAddresses(Type bindingType, string mexAddress, string contractNamespace, string contractName); public static string[] GetContracts(string mexAddress); public static string[] GetContracts(Type bindingType, string mexAddress); public static string[] GetOperations(string mexAddress, Type contractType); public static string[] GetOperations(string mexAddress, string contractNamespace, string contractName); public static bool QueryContract(string mexAddress, Type contractType); public static bool QueryContract(string mexAddress, string contractNamespace, string contractName); } }