• Chapter 2.2:元数据通用查询类 MetadataHelper


      本章主要介绍元数据通用查询类 MetadataHelper。

      有时候,客户端需要通过编程方式验证一个特定的终结点(通过地址进行识别)是否支持一个特定的契约。设想有这样一个应用程序,终端用户在安装时(甚至在运行时)指定或配置应用程序,用以使用服务并与服务交互。如果服务不支持所需的契约,应用程序就会向用户发出警告,提示配置的地址是无效的,询问是否更正地址或替换地址。为了支持这一功能,应用程序需要获取服务终结点的元数据,查看是否存在至少一个终结点支持请求的契约。为了简化对返回元数据的解析工作 ,现提供元数据通用查询类 MetadataHelper,如下所示:

    using System;
    using System.ServiceModel;
    using System.Diagnostics;
    using System.Collections.Generic;
    using System.ServiceModel.Channels;
    using System.ServiceModel.Description;
    using System.Linq;
    
    namespace WCF.Chapter2.Metadata.Client
    {
        public static class MetadataHelper
        {
            const int MessageSizeMultiplier = 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)
            {
                if (String.IsNullOrEmpty(mexAddress))
                {
                    Debug.Assert(false, "Empty address");
                    return null;
                }
                Uri address = new Uri(mexAddress);
                ServiceEndpointCollection endpoints = null;
    
                if (address.Scheme == "http")
                {
                    HttpTransportBindingElement httpBindingElement = new HttpTransportBindingElement();
                    httpBindingElement.MaxReceivedMessageSize *= MessageSizeMultiplier;
    
                    //Try the HTTP MEX Endpoint
                    try
                    {
                        endpoints = QueryMexEndpoint(mexAddress, httpBindingElement);
                    }
                    catch
                    { }
    
                    //Try over HTTP-GET
                    if (endpoints == null)
                    {
                        string httpGetAddress = mexAddress;
                        if (mexAddress.EndsWith("?wsdl") == false)
                        {
                            httpGetAddress += "?wsdl";
                        }
                        CustomBinding binding = new CustomBinding(httpBindingElement);
                        MetadataExchangeClient MEXClient = new MetadataExchangeClient(binding);
                        MetadataSet metadata = MEXClient.GetMetadata(new Uri(httpGetAddress), MetadataExchangeClientMode.HttpGet);
                        MetadataImporter importer = new WsdlImporter(metadata);
                        endpoints = importer.ImportAllEndpoints();
                    }
                }
                if (address.Scheme == "https")
                {
                    HttpsTransportBindingElement httpsBindingElement = new HttpsTransportBindingElement();
                    httpsBindingElement.MaxReceivedMessageSize *= MessageSizeMultiplier;
    
                    //Try the HTTPS MEX Endpoint
                    try
                    {
                        endpoints = QueryMexEndpoint(mexAddress, httpsBindingElement);
                    }
                    catch
                    { }
    
                    //Try over HTTP-GET
                    if (endpoints == null)
                    {
                        string httpsGetAddress = mexAddress;
                        if (mexAddress.EndsWith("?wsdl") == false)
                        {
                            httpsGetAddress += "?wsdl";
                        }
                        CustomBinding binding = new CustomBinding(httpsBindingElement);
                        MetadataExchangeClient MEXClient = new MetadataExchangeClient(binding);
                        MetadataSet metadata = MEXClient.GetMetadata(new Uri(httpsGetAddress), MetadataExchangeClientMode.HttpGet);
                        MetadataImporter importer = new WsdlImporter(metadata);
                        endpoints = importer.ImportAllEndpoints();
                    }
                }
                if (address.Scheme == "net.tcp")
                {
                    TcpTransportBindingElement tcpBindingElement = new TcpTransportBindingElement();
                    tcpBindingElement.MaxReceivedMessageSize *= MessageSizeMultiplier;
                    endpoints = QueryMexEndpoint(mexAddress, tcpBindingElement);
                }
                if (address.Scheme == "net.pipe")
                {
                    NamedPipeTransportBindingElement ipcBindingElement = new NamedPipeTransportBindingElement();
                    ipcBindingElement.MaxReceivedMessageSize *= MessageSizeMultiplier;
                    endpoints = QueryMexEndpoint(mexAddress, ipcBindingElement);
                }
                return endpoints.ToArray();
            }
    
    
            public static Type GetCallbackContract(string mexAddress, Type contractType)
            {
                if (contractType.IsInterface == false)
                {
                    Debug.Assert(false, contractType + " is not an interface");
                    return null;
                }
    
                object[] attributes = contractType.GetCustomAttributes(typeof(ServiceContractAttribute), false);
                if (attributes.Length == 0)
                {
                    Debug.Assert(false, "Interface " + contractType + " does not have the ServiceContractAttribute");
                    return null;
                }
                ServiceContractAttribute attribute = attributes[0] as ServiceContractAttribute;
                if (attribute.Name == null)
                {
                    attribute.Name = contractType.ToString();
                }
                if (attribute.Namespace == null)
                {
                    attribute.Namespace = "http://tempuri.org/";
                }
                return GetCallbackContract(mexAddress, attribute.Namespace, attribute.Name);
            }
    
            public static Type GetCallbackContract(string mexAddress, string contractNamespace, string contractName)
            {
                if (String.IsNullOrEmpty(contractNamespace))
                {
                    Debug.Assert(false, "Empty namespace");
                    return null;
                }
                if (String.IsNullOrEmpty(contractName))
                {
                    Debug.Assert(false, "Empty name");
                    return null;
                }
                try
                {
                    ServiceEndpoint[] endpoints = GetEndpoints(mexAddress);
                    foreach (ServiceEndpoint endpoint in endpoints)
                    {
                        if (endpoint.Contract.Namespace == contractNamespace && endpoint.Contract.Name == contractName)
                        {
                            return endpoint.Contract.CallbackContractType;
                        }
                    }
                }
                catch
                { }
                return null;
            }
            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);
            }
            public 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);
    
                    return endpoints.Any(endpoint => endpoint.Contract.Namespace == contractNamespace && endpoint.Contract.Name == contractName);
                }
    
                catch
                { }
                return false;
            }
            public static string[] GetContracts(string mexAddress)
            {
                return GetContracts(typeof(Binding), mexAddress);
            }
            public static string[] GetContracts(Type bindingType, string mexAddress)
            {
                Debug.Assert(bindingType.IsSubclassOf(typeof(Binding)) || bindingType == typeof(Binding));
    
                ServiceEndpoint[] endpoints = GetEndpoints(mexAddress);
    
                List<string> contracts = new List<string>();
                string contract;
                foreach (ServiceEndpoint endpoint in endpoints)
                {
                    if (bindingType.IsInstanceOfType(endpoint.Binding))
                    {
                        contract = endpoint.Contract.Namespace + " " + endpoint.Contract.Name;
    
                        if (contracts.Contains(contract) == false)
                        {
                            contracts.Add(contract);
                        }
                    }
                }
                return contracts.ToArray();
            }
            public static string[] GetAddresses(string mexAddress, Type contractType)
            {
                if (contractType.IsInterface == false)
                {
                    Debug.Assert(false, contractType + " is not an interface");
                    return new string[] { };
                }
    
                object[] attributes = contractType.GetCustomAttributes(typeof(ServiceContractAttribute), false);
                if (attributes.Length == 0)
                {
                    Debug.Assert(false, "Interface " + contractType + " does not have the ServiceContractAttribute");
                    return new string[] { };
                }
                ServiceContractAttribute attribute = attributes[0] as ServiceContractAttribute;
                if (attribute.Name == null)
                {
                    attribute.Name = contractType.ToString();
                }
                if (attribute.Namespace == null)
                {
                    attribute.Namespace = "http://tempuri.org/";
                }
                return GetAddresses(mexAddress, attribute.Namespace, attribute.Name);
            }
            public static string[] GetAddresses(string mexAddress, string contractNamespace, string contractName)
            {
                ServiceEndpoint[] endpoints = GetEndpoints(mexAddress);
    
                List<string> addresses = new List<string>();
    
                foreach (ServiceEndpoint endpoint in endpoints)
                {
                    if (endpoint.Contract.Namespace == contractNamespace && endpoint.Contract.Name == contractName)
                    {
                        Debug.Assert(addresses.Contains(endpoint.Address.Uri.AbsoluteUri) == false);
                        addresses.Add(endpoint.Address.Uri.AbsoluteUri);
                    }
                }
                return addresses.ToArray();
            }
            public static string[] GetAddresses(Type bindingType, string mexAddress, Type contractType)
            {
                Debug.Assert(bindingType.IsSubclassOf(typeof(Binding)) || bindingType == typeof(Binding));
    
                if (contractType.IsInterface == false)
                {
                    Debug.Assert(false, contractType + " is not an interface");
                    return new string[] { };
                }
    
                object[] attributes = contractType.GetCustomAttributes(typeof(ServiceContractAttribute), false);
                if (attributes.Length == 0)
                {
                    Debug.Assert(false, "Interface " + contractType + " does not have the ServiceContractAttribute");
                    return new string[] { };
                }
                ServiceContractAttribute attribute = attributes[0] as ServiceContractAttribute;
                if (attribute.Name == null)
                {
                    attribute.Name = contractType.ToString();
                }
                if (attribute.Namespace == null)
                {
                    attribute.Namespace = "http://tempuri.org/";
                }
                return GetAddresses(bindingType, mexAddress, attribute.Namespace, attribute.Name);
            }
            public static string[] GetAddresses(Type bindingType, string mexAddress, string contractNamespace, string contractName)
            {
                Debug.Assert(bindingType.IsSubclassOf(typeof(Binding)) || bindingType == typeof(Binding));
    
                ServiceEndpoint[] endpoints = GetEndpoints(mexAddress);
    
                List<string> addresses = new List<string>();
    
                foreach (ServiceEndpoint endpoint in endpoints)
                {
                    if (bindingType.IsInstanceOfType(endpoint.Binding))
                    {
                        if (endpoint.Contract.Namespace == contractNamespace && endpoint.Contract.Name == contractName)
                        {
                            Debug.Assert(addresses.Contains(endpoint.Address.Uri.AbsoluteUri) == false);
                            addresses.Add(endpoint.Address.Uri.AbsoluteUri);
                        }
                    }
                }
                return addresses.ToArray();
            }
            public static string[] GetOperations(string mexAddress, Type contractType)
            {
                if (contractType.IsInterface == false)
                {
                    Debug.Assert(false, contractType + " is not an interface");
                    return new string[] { };
                }
    
                object[] attributes = contractType.GetCustomAttributes(typeof(ServiceContractAttribute), false);
                if (attributes.Length == 0)
                {
                    Debug.Assert(false, "Interface " + contractType + " does not have the ServiceContractAttribute");
                    return new string[] { };
                }
                ServiceContractAttribute attribute = attributes[0] as ServiceContractAttribute;
                if (attribute.Name == null)
                {
                    attribute.Name = contractType.ToString();
                }
                if (attribute.Namespace == null)
                {
                    attribute.Namespace = "http://tempuri.org/";
                }
                return GetOperations(mexAddress, attribute.Namespace, attribute.Name);
            }
            public static string[] GetOperations(string mexAddress, string contractNamespace, string contractName)
            {
                ServiceEndpoint[] endpoints = GetEndpoints(mexAddress);
    
                List<string> operations = new List<string>();
    
                foreach (ServiceEndpoint endpoint in endpoints)
                {
                    if (endpoint.Contract.Namespace == contractNamespace && endpoint.Contract.Name == contractName)
                    {
                        foreach (OperationDescription operation in endpoint.Contract.Operations)
                        {
                            Debug.Assert(operations.Contains(operation.Name) == false);
                            operations.Add(operation.Name);
                        }
                        break;
                    }
                }
                return operations.ToArray();
            }
    
            public static Binding GetBinding(string address)
            {
                if (String.IsNullOrEmpty(address))
                {
                    Debug.Assert(false, "Empty address");
                    return null;
                }
                string baseAddress = GetBaseAddress(address) + "?wsdl";
    
                ServiceEndpoint[] endpoints = GetEndpoints(address);
    
                foreach (ServiceEndpoint endpoint in endpoints)
                {
                    if (endpoint.Address.Uri.AbsoluteUri == address)
                    {
                        return endpoint.Binding;
                    }
                }
                return null;
            }
    
            static string GetBaseAddress(string address)
            {
                string[] segments = address.Split('/');
                return segments[0] + segments[1] + segments[2] + "/";
            }
        }
    }
    
    

      GetEndpoints() 方法对元数据交换地址的样式进行了解析。根据找到的传输样式,GetEndpoints() 方法创建了一个需要使用的绑定元素, 这样就可以设置它的 MaxReceivedMessageSize 属性值。MaxReceiveMessageSize 的默认值为 64K 。它适用于简单的服务。如果服务包含多个终结点 ,终结点又使 用了复杂类型,就会生成更大的消息。此时,调用 MetadataExchangeClient.GetMetadata() 方法就会失败。根据经验,大多数情况下最合适的倍数因子是 5。接着,GetEndpoints() 调用了 QueryMexEndpoint() 私有方法,以获取元数据。

      QueryMexEndpoint() 方法接收元数据交换终结点的地址以及要使用的绑定元素。使用绑定元素是为了创建定制绑定,并将它提供给 MetadataExchange-Client 实例。MetadataExchangeClient 实例能够获取元数据,返回终结点集合。

      QueryContract() 方法首先会验证传入的Type类型是否是接口类型,如果是,则判断该接口是否标记了 ServiceContract 特性。因为 ServiceContract特性可以为契约的请求类型指定名称和命名空间的别名,QueryContract()使用这些值查询符合条件的契约。如果没有指定别名, QueryContract()方法则使用类型的名字与默认的命名空间 http :// tem puri.org,然后调用另一个重载版本的 QueryContract()方法,它能够操作契约的名称和命名空间。该版本的 QueryContract() 方法调用了GetEndpoints()方法,以获得终结点数组,然后遍历该数组。如果找到至少一个终结点支持该契约,则返回 true。不管出现何种错误, QueryContract()方法都会返回false。

  • 相关阅读:
    菜鸟也能飞:SQL数据库实战专业教程(二)
    菜鸟也能飞:SQL数据库实战专业教程(三)
    我的时间管理柳暗花明
    真正的全能文件批量重命名工具(命令形式)
    关于提高班最近的一些事
    菜鸟也能飞:SQL数据库实战专业教程(一)
    JQuery以POST方法从ASP.NET服务器获取Json数据完整示例
    先有鸡还是先有蛋:数据库中的相互依赖
    一个简单的性能计数器:CodeTimer
    数据库范式
  • 原文地址:https://www.cnblogs.com/tianzhiliang/p/1943203.html
Copyright © 2020-2023  润新知