两种方法供你动态调用WCF接口

写在前面

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

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

如何使用

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

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

客户端调用DEMO

//第一种方式
string url = "http://localhost:3000/DoubleService.svc";
IDoubleService proxy = WcfInvokeFactory.CreateServiceByUrl<IDoubleService>(url);
int result = proxy.Add(1, 3);

//第二种方式

int result1  = WCFInvoke.Invoke(t => t.Add(1, 3));
 <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>

第一种调用方式

 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
    }

第二种调用方式

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);
        }
    }
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;
        }
    }
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,稍后放出下载链接。

时间: 2024-10-04 13:19:59

两种方法供你动态调用WCF接口的相关文章

js+jquery动态设置/增加/删除/获取元素属性的两种方法集锦对比(动态onclick属性设置+动态title设置)

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html140/strict.dtd"> <html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"/> <title>

C#动态调用WCF接口

C#动态调用WCF接口 写在前面 接触WCF还是它在最初诞生之处,一个分布式应用的巨作. 从开始接触到现在断断续续,真正使用的项目少之又少,更谈不上深入WCF内部实现机制和原理去研究,最近自己做一个项目时用到了WCF. 从这个小项目中我学会了两个地方: 1.利用IIS部署WCF服务,也就是大家接触到的发布SVC文件.2.动态调用WCF接口. 在这个项目中接触WCF时遇到的其实不仅仅是这两个问题,甚至连IIS支持SVC文件也让我折腾了好几把,IIS都重新卸载了两次. 我在这篇文章里用两种方式来实现

Android Camera 使用小结。两种方法:一是调用系统camera app,二是自己写camera程序。

源文链接:http://www.cnblogs.com/franksunny/archive/2011/11/17/2252926.html Android Camera 使用小结 Android手机关于Camera的使用,一是拍照,二是摄像,由于Android提供了强大的组件功能,为此对于在Android手机系统上进行Camera的开发,我们可以使用两类方法:一是借助Intent和MediaStroe调用系统Camera App程序来实现拍照和摄像功能,二是根据Camera API自写Came

js+jquery动态设置/添加/删除/获取元素属性的两种方法集锦对照(动态onclick属性设置+动态title设置)

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html140/strict.dtd"> <html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"/> <title>

Unity调用安卓的两种方法

总结的两种方法,供参考. 方法一 (要将方法写到UnityPlayerActivity 类下,不然调用不到): 1 //获得类 2 3 AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); 4 5 6 7 //获得java对象 8 9 AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject>("currentAc

[转]Delphi调用cmd的两种方法

delphi调用cmd的两种方法vars:string;begins:='cmd.exe /c '+edit1.Text+' >c:\1.txt';winexec(pchar(s),sw_hide);sleep(2000);memo1.Lines.LoadFromFile('c:\1.txt'); 2shellexecute(handle,nil,'cmd.exe',pchar(form2.edit1.text),nil,sw_hide);WinExec主要运行EXE文件.如:WinExec(’

OC中动态创建可变数组的问题.有一个数组,数组中有13个元素,先将该数组进行分组,每3个元素为一组,分为若干组,最后用一个数组统一管理这些分组.(要动态创建数组).两种方法

<span style="font-size:24px;">//////第一种方法 // NSMutableArray *arr = [NSMutableArray array]; // for (int i = 0; i < 13; i ++) { // [arr addObject:[NSString stringWithFormat:@"lanou%d",i + 1]]; // } // NSLog(@"%@",arr);

ListView动态加载数据分页(使用Handler+线程和AsyncTask两种方法)

ListView动态加载数据分页(使用Handler+线程和AsyncTask两种方法)

【开发实例】C#调用SAPI实现语音合成的两种方法

我们都知道现在的语音合成TTS是可以通过微软的SAPI实现的,好处我就不多说了,方便而已,因为在微软的操作系统里面就自带了这个玩意,主要的方式有两种:  1.使用COM组件技术,不管是C++,C#,Delphi都能玩的转,开发出来的东西在XP和WIN7都能跑.(要引入SpeechLib,好像在项目上点引用,然后选到系统COM吧,好久没弄,记不清楚了)  2.使用WIN7的windows api,其实最终还是调用了SAPI,所以开发出来的东西就只能在WIN7上面跑.  其实不管是哪一种,都是调用S