我的WCF摸爬滚打之路(1)
等了好久终于等到今天!盼了好久终于把梦实现……哈哈,仅以此歌词来庆祝我为期3天的wcf学习之路圆满结束。
今天写这个文章的目的在于记录一下我自己在学习WCF的时候碰到的一些问题,俗话说,好记心不如烂笔头嘛。也为看见我这篇文章的有缘人(正在wcf中探索的人们,提供一点借鉴吧)。
还是老样子,图文并茂的文章才是好文章(我自己定义的,勿喷!)。那么接下来我将把我这一路的细节以及碰到的问题和解决方法一一展示出来。
我在学习wcf的时候第一件事就是自己做了个wcf的例子,因为wcf的传输协议有很多,比如说http、tcp。我主要讲讲tcp协议的wcf吧,因为这个确实比较麻烦的一个东西,有时候出现bug也是一些稀奇古怪的exception。废话不多说直接上图。
新建一个项目
新建好了的wcf服务库如下图
会自动生成几个类文件。这几个类文件分别是两个interface和两个interface的实现类(需要自己手动实现)。可能有的人会问,我怎么只生成了一个interface和它的实现类额?因为我想实现的是wcf通过一个servicehost和一个端口同时发布多个服务出来。另外两个是我自己新建的 。哈哈……
看看具体的代码都是啥!很简单只是声明了一个GetData(int value)函数。翻翻书或者百度一下都知道wcf的基本概念:以契约(Contract)来定义双方通信,契约必须以接口的形式体现。这里面比较重要的两个特性[ServiceContract]、[OperationContract]。一个服务契约,一个操作契约,只有定义了这两个别人才认识你是个wcf服务撒。用这个时必须引用命名空间:using System.ServiceModel;
1 namespace WcfServiceLibrary 2 { 3 // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的接口名“IService1”。 4 [ServiceContract] 5 public interface IService1 6 { 7 [OperationContract] 8 string GetData(int value); 9 10 11 } 12 13 14 }
既然wcf叫服务那他总的有服务吧!不然怎么服务于我。别急,上代码:上面是契约、下面是服务。实际的服务代码要由契约接口派生实现。
1 namespace WcfServiceLibrary 2 { 3 // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的类名“Service1”。 4 public class Service1 : IService1 5 { 6 public string GetData(int value) 7 { 8 if (value==1) 9 { 10 throw new NotImplementedException(); 11 } 12 return string.Format("You entered: {0}", value); 13 } 14 15 16 } 17 }
以上工作完成后,wcf的创建算是完工了。接下来的重点,是建立wcf的宿主程序。
我就做了和控制台程序作为wcf说的宿主程序!
一般常见的是通过config文件进行配置,以为要深究的话,config文件是在有很东西要讲,而我也只是初出茅庐。所以我就一代码的形式进行配置文件的生成。而且只需要几个常用的属性就ok。且看代码
1.我先实例化绑定形式NetTcpBinding
1 private static NetTcpBinding netTcpBinding = new NetTcpBinding(); 2 public static NetTcpBinding InitNetTcpBinding() 3 { 4 netTcpBinding.Security.Mode = SecurityMode.None; 5 netTcpBinding.ReceiveTimeout = TimeSpan.Parse("00:10:00"); 6 netTcpBinding.MaxBufferPoolSize = 2147483647; // 7 netTcpBinding.MaxBufferSize = 2147483647; 8 //netTcpBinding.MaxConnections = 10; 9 //netTcpBinding.PortSharingEnabled = true; 10 11 netTcpBinding.ReaderQuotas.MaxDepth = 2147483647; 12 netTcpBinding.ReaderQuotas.MaxStringContentLength = 2147483647; 13 netTcpBinding.ReaderQuotas.MaxArrayLength = 2147483647; 14 netTcpBinding.ReaderQuotas.MaxBytesPerRead = 2147483647; 15 netTcpBinding.ReaderQuotas.MaxNameTableCharCount = 2147483647; 16 netTcpBinding.MaxReceivedMessageSize = 2147483647; 17 return netTcpBinding; 18 }
2.我通过反射的形式拿到wcf的契约和服务。
1 public static void LoadAssemBly(string assemblyName) 2 { 3 Assembly assem = Assembly.Load(assemblyName); 4 Dictionary<Type, Type> svTypes = new Dictionary<Type, Type>(); 5 List<TypeInfo> list = assem.DefinedTypes.ToList(); 6 foreach (TypeInfo typeInfo in list) 7 { 8 if (typeInfo.Attributes.ToString().IndexOf("Abstract") >= 0) 9 { 10 TypeInfo tempK = typeInfo; 11 var result = (from t in list where t.Name==(tempK.Name.Substring(1)) select t).ToList(); 12 TypeInfo tempV = result[0]; 13 svTypes.Add(tempK, tempV); 14 } 15 16 } 17 string serviceAddress = string.Format("net.tcp://{0}:{1}", "localhost", "13141"); 18 string endpointAddress = string.Empty; 19 string tName = string.Empty; 20 foreach (var item in svTypes) 21 { 22 tName = item.Key.Name.Substring(1); 23 endpointAddress = serviceAddress +"/"+ tName; 24 25 ServiceHost serviceHost = new ServiceHost(item.Value, new Uri(endpointAddress)); 26 27 //加载元数据节点 28 ServiceMetadataBehavior smb = new ServiceMetadataBehavior(); 29 serviceHost.Description.Behaviors.Add(smb); 30 serviceHost.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexTcpBinding(), "mex"); 31 32 serviceHost.AddServiceEndpoint(item.Key, netTcpBinding, endpointAddress); 33 34 serviceHost.Opened += delegate 35 { 36 msg.AppendLine(string.Format("{0}开始监听 Uri 为 :{1}/mex", tName, endpointAddress.ToString())); 37 }; 38 serviceHost.Open(); 39 serviceHosts.Add(serviceHost); 40 41 }
这样我们得宿主程序就完成了。运行一下看看结果
这样看来是没问题了,那么们测试一下添加服务引用是否能找到服务。如果找到了就说明确实是没问题了。
OK,搞定!看似一帆风顺。其实这中间我遇到了很多问题,下次再专门写个博客讲解吧
《转载注明出处!》