.NET 动态调用WCF

it2022-05-05  101

写在前面

           接触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

相关资源:wcf动态调用

最新回复(0)