• C#动态调用WCF接口


    C#动态调用WCF接口

    写在前面

               接触WCF还是它在最初诞生之处,一个分布式应用的巨作。 从开始接触到现在断断续续,真正使用的项目少之又少,更谈不上深入WCF内部实现机制和原理去研究,最近自己做一个项目时用到了WCF。 从这个小项目中我学会了两个地方: 1、利用IIS部署WCF服务,也就是大家接触到的发布SVC文件。2、动态调用WCF接口。

               在这个项目中接触WCF时遇到的其实不仅仅是这两个问题,甚至连IIS支持SVC文件也让我折腾了好几把,IIS都重新卸载了两次。 我在这篇文章里用两种方式来实现。

    如何使用

          1、第一种方式比较简单,而且也是大家喜欢的,因为不需要任何配置文件就可解决,只需知道服务契约接口和服务地址就可以调用。

          2、使用Invoke的方式,但是需要在调用客户端配置WCF,配置后在Invoke类里封装服务契约接口即可。

    客户端调用DEMO

    1
    2
    3
    4
    5
    6
    7
    //第一种方式
    IDoubleService proxy = WcfInvokeFactory.CreateServiceByUrl<IDoubleService>(url);
    int result = proxy.Add(1, 3);
     
     
    //第二种方式<br><br>int result1  = WCFInvoke.Invoke(t => t.Add(1, 3));<br><br>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    <system.serviceModel>
       <behaviors>
         <endpointBehaviors>
           <behavior name="NewBehavior">
             <dataContractSerializer maxItemsInObjectGraph="65536000" />
           </behavior>
         </endpointBehaviors>
       </behaviors>
       <bindings>
         <basicHttpBinding>    
           <binding name="BasicHttpBinding_IDoubleService"
                    closeTimeout="01:00:00"
                    openTimeout="01:00:00"
                    sendTimeout="01:00:00"
                    receiveTimeout="01:00:00"
                    maxBufferSize="2147483647"
                    maxBufferPoolSize="524288"
                    maxReceivedMessageSize="2147483647">
             <readerQuotas maxDepth="128" maxStringContentLength="2147483647" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
           </binding>
         </basicHttpBinding>
         <netMsmqBinding>
           <binding name="NetMsmqBinding_IAsyncSender">
             <security mode="None" />
           </binding>
         </netMsmqBinding>
       </bindings>
       <client>
         
         <endpoint address="http://localhost:3000/DoubleService.svc"
                   binding="basicHttpBinding"
                   bindingConfiguration="BasicHttpBinding_IDoubleService"
                   contract="DoubleStone.WebHost.IDoubleService"
                   name="BasicHttpBinding_IDoubleService" />
        
       </client>
     </system.serviceModel>

    第一种调用方式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    public class WcfInvokeFactory
       {
           #region WCF服务工厂
           public static T CreateServiceByUrl<T>(string url)
           {
               return CreateServiceByUrl<T>(url, "basicHttpBinding");
           }
     
           public static T CreateServiceByUrl<T>(string url, string bing)
           {
               try
               {
                   if (string.IsNullOrEmpty(url)) throw new NotSupportedException("This url is not Null or Empty!");
                   EndpointAddress address = new EndpointAddress(url);
                   Binding binding = CreateBinding(bing);
                   ChannelFactory<T> factory = new ChannelFactory<T>(binding, address);
                   return factory.CreateChannel();
               }
               catch (Exception ex)
               {
                   throw new Exception("创建服务工厂出现异常.");
               }
           }
           #endregion
     
           #region 创建传输协议
           /// <summary>
           /// 创建传输协议
           /// </summary>
           /// <param name="binding">传输协议名称</param>
           /// <returns></returns>
           private static Binding CreateBinding(string binding)
           {
               Binding bindinginstance = null;
               if (binding.ToLower() == "basichttpbinding")
               {
                   BasicHttpBinding ws = new BasicHttpBinding();
                   ws.MaxBufferSize = 2147483647;
                   ws.MaxBufferPoolSize = 2147483647;
                   ws.MaxReceivedMessageSize = 2147483647;
                   ws.ReaderQuotas.MaxStringContentLength = 2147483647;
                   ws.CloseTimeout = new TimeSpan(0, 30, 0);
                   ws.OpenTimeout = new TimeSpan(0, 30, 0);
                   ws.ReceiveTimeout = new TimeSpan(0, 30, 0);
                   ws.SendTimeout = new TimeSpan(0, 30, 0);
     
                   bindinginstance = ws;
               }
               else if (binding.ToLower() == "nettcpbinding")
               {
                   NetTcpBinding ws = new NetTcpBinding();
                   ws.MaxReceivedMessageSize = 65535000;
                   ws.Security.Mode = SecurityMode.None;
                   bindinginstance = ws;
               }
               else if (binding.ToLower() == "wshttpbinding")
               {
                   WSHttpBinding ws = new WSHttpBinding(SecurityMode.None);
                   ws.MaxReceivedMessageSize = 65535000;
                   ws.Security.Message.ClientCredentialType = System.ServiceModel.MessageCredentialType.Windows;
                   ws.Security.Transport.ClientCredentialType = System.ServiceModel.HttpClientCredentialType.Windows;
                   bindinginstance = ws;
               }
               return bindinginstance;
     
           }
           #endregion
       }

    第二种调用方式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public class WCFInvoke
        {
            /// <summary>
            /// 你需要调用的服务契约
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="func"></param>
            /// <returns></returns>
            public static T Invoke<T>(Func<IDoubleService, T> func)
            {
                IServiceInvoker serviceInvoker=new WCFServiceInvoker();
                return serviceInvoker.InvokeService(func);
            }
        }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    public interface IServiceInvoker
        {
            void InvokeService<T>(Action<T> invokeHandler) where T : class;
            TReslt InvokeService<T, TReslt>(Func<T, TReslt> invokeHandler) where T : class;
        }
     
    public class WCFServiceInvoker:IServiceInvoker
        {
            private static readonly ChannelFactoryManager FactoryManager = new ChannelFactoryManager();
     
            private static readonly ClientSection ClientSection =
                ConfigurationManager.GetSection("system.serviceModel/client"as ClientSection;
     
     
            public void InvokeService<T>(Action<T> invokeHandler) where T : class
            {
                KeyValuePair<stringstring> endpointNameAddressPair = GetEndpointNameAddressPair(typeof(T));
                var arg = FactoryManager.CreateChannel<T>(endpointNameAddressPair.Key, endpointNameAddressPair.Value);
                var obj2 = (ICommunicationObject)arg;
                try
                {
                    invokeHandler(arg);
                }
                finally
                {
                    try
                    {
                        if (obj2.State != CommunicationState.Faulted)
                        {
                            obj2.Close();
                        }
                    }
                    catch
                    {
                        obj2.Abort();
                    }
                }
            }
     
     
            public TReslt InvokeService<T, TReslt>(Func<T, TReslt> invokeHandler) where T : class
            {
                KeyValuePair<stringstring> endpointNameAddressPair = GetEndpointNameAddressPair(typeof(T));
                var arg = FactoryManager.CreateChannel<T>(endpointNameAddressPair.Key, endpointNameAddressPair.Value);
                var obj2 = (ICommunicationObject)arg;
                try
                {
                    return invokeHandler(arg);
                }
                finally
                {
                    try
                    {
                        if (obj2.State != CommunicationState.Closed || obj2.State != CommunicationState.Faulted)
                        {
                            obj2.Close();
                        }
                    }
                    catch
                    {
                        obj2.Abort();
                    }
                }
            }
     
            private KeyValuePair<stringstring> GetEndpointNameAddressPair(Type serviceContractType)
            {
                var configException =
                    new ConfigurationErrorsException(
                        string.Format(
                            "No client endpoint found for type {0}. Please add the section <client><endpoint name="myservice" address="http://address/" binding="basicHttpBinding" contract="{0}"/></client> in the config file.",
                            serviceContractType));
                if (((ClientSection == null) || (ClientSection.Endpoints == null)) || (ClientSection.Endpoints.Count < 1))
                {
                    throw configException;
                }
                foreach (ChannelEndpointElement element in ClientSection.Endpoints)
                {
                    if (element.Contract == serviceContractType.ToString())
                    {
                        return new KeyValuePair<stringstring>(element.Name, element.Address.AbsoluteUri);
                    }
                }
                throw configException;
            }
        }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    public class ChannelFactoryManager : IDisposable
        {
            private static readonly Dictionary<Type, ChannelFactory> Factories = new Dictionary<Type, ChannelFactory>();
            private static readonly object SyncRoot = new object();
     
            public void Dispose()
            {
                Dispose(true);
            }
     
            public virtual T CreateChannel<T>() where T : class
            {
                return CreateChannel<T>("*"null);
            }
     
            public virtual T CreateChannel<T>(string endpointConfigurationName) where T : class
            {
                return CreateChannel<T>(endpointConfigurationName, null);
            }
     
            public virtual T CreateChannel<T>(string endpointConfigurationName, string endpointAddress) where T : class
            {
                T local = GetFactory<T>(endpointConfigurationName, endpointAddress).CreateChannel();
                ((IClientChannel)local).Faulted += ChannelFaulted;
                return local;
            }
     
            protected virtual ChannelFactory<T> GetFactory<T>(string endpointConfigurationName, string endpointAddress)
                where T : class
            {
                lock (SyncRoot)
                {
                    ChannelFactory factory;
                    if (!Factories.TryGetValue(typeof(T), out factory))
                    {
                        factory = CreateFactoryInstance<T>(endpointConfigurationName, endpointAddress);
                        Factories.Add(typeof(T), factory);
                    }
                    return (factory as ChannelFactory<T>);
                }
            }
     
            private ChannelFactory CreateFactoryInstance<T>(string endpointConfigurationName, string endpointAddress)
            {
                ChannelFactory factory = null;
                factory = !string.IsNullOrEmpty(endpointAddress) ? new ChannelFactory<T>(endpointConfigurationName, new EndpointAddress(endpointAddress)) : new ChannelFactory<T>(endpointConfigurationName);
     
                factory.Faulted += FactoryFaulted;
                factory.Open();
                return factory;
            }
     
            private void ChannelFaulted(object sender, EventArgs e)
            {
                var channel = (IClientChannel)sender;
                try
                {
                    channel.Close();
                }
                catch
                {
                    channel.Abort();
                }
            }
     
            private void FactoryFaulted(object sender, EventArgs args)
            {
                var factory = (ChannelFactory)sender;
                try
                {
                    factory.Close();
                }
                catch
                {
                    factory.Abort();
                }
                Type[] genericArguments = factory.GetType().GetGenericArguments();
                if ((genericArguments.Length == 1))
                {
                    Type key = genericArguments[0];
                    if (Factories.ContainsKey(key))
                    {
                        Factories.Remove(key);
                    }
                }
            }
     
            protected virtual void Dispose(bool disposing)
            {
                if (disposing)
                {
                    lock (SyncRoot)
                    {
                        foreach (Type type in Factories.Keys)
                        {
                            ChannelFactory factory = Factories[type];
                            try
                            {
                                factory.Close();
                            }
                            catch
                            {
                                factory.Abort();
                            }
                        }
                        Factories.Clear();
                    }
                }
            }
        }

    总结

          第一种方式比较常见,第二种方式是我参考另外一个项目中的写法,其中的有一些细节我还没有搞明白,实现了这个功能后还需要再看看这部分代码,再消化消化。由于是直接在项目中,所以没有提供源代码下载,有朋友需要的话我会整理出demo,稍后放出下载链接。

  • 相关阅读:
    [HihoCoder1259]A Math Problem
    [POJ1205]Water Treatment Plants
    [HDU5492]Find a path
    [USACO08JAN]Cell Phone Network
    [CodeForces-543D]Road Improvement
    [HAOI2012]外星人
    [CodeForces-869C]The Intriguing Obsession
    [CodeChef-CAPTCITI]Snakes capturing the Mongoose Cities
    CF741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths
    Luogu P4095 [HEOI2013]Eden的新背包问题
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/4762784.html
Copyright © 2020-2023  润新知