Bootstrap

.NET 动态调用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
//第一种方式
string  url =  "http://localhost:3000/DoubleService.svc" ;
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< string string > 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< string string > 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< string string > 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< string string >(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,稍后放出下载链接。

 

转载于:https://www.cnblogs.com/leo-gong/p/9365418.html

;