今天终于开始客户端的开发了,客户端完成以后,我们将可以进行简单的交流。开发完成的程序只是一个很简单的雏形,在本系统完成以后,以及完成的过程中,大家都可以下载源码,在此基础上融入自己的想法和尝试,可以按照自己的思路,完成后面的部分。
下面我们开始客户端的开发,我们新建一个类库项目,作为与服务器端交互的中枢,同时也是为了分离服务和界面逻辑。目前我们将首先我们WPF客户端开发,在稍后的时间,我们再进行Winform的开发。
1.新建类库项目,作为客户端与服务器端的交互中枢
2.在新项目上添加服务引用
3.在弹出的窗体中输入我们的服务地址(服务地址可以从服务器端获取到):net.tcp://localhost:1121/InChatter
发生错误:元数据包含无法解析的引用:“net.tcp://localhost:1121/InChatter"
为什么会这样,其实这个跟我们的服务器端有关,我们设置了绑定的地址,但是并没有设置元数据的地址,记得在上节我说过,我们的配置文件配置的tcp连接方式,是有问题的,其实就是这个。
解决这个问题的方法有两种:
(1)为服务添加元数据的地址,我们在NetTcpBinding的基础上修改,这个应该说是比较正统的方法,当然不是说另外一种方法不正确了,看个人习惯了。
首先修改我们的服务器端代码,注意行号4以及行号4,我们添加了新的Behaviour,第10行提供了元数据的获取路径和方式
1 using (ServiceHost host = new ServiceHost(typeof(Chat))) 2 { 3 NetTcpBinding binding = new NetTcpBinding(); 4 Binding mexBinding = MetadataExchangeBindings.CreateMexTcpBinding(); 5 binding.Security.Mode = SecurityMode.None; 6 //会话保持时间 7 binding.ReceiveTimeout = TimeSpan.FromHours(2); 8 host.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = false }); 9 host.AddServiceEndpoint(typeof(IChat), binding, "net.tcp://localhost:1121/InChatter"); 10 host.AddServiceEndpoint(typeof(IMetadataExchange), mexBinding, "net.tcp://localhost:1121/InChatter/Mex"); 11 host.Opened += host_Opened; 12 try 13 { 14 host.Open(); 15 16 } 17 catch (Exception ex) 18 { 19 Console.WriteLine(ex.Message); 20 } 21 Console.WriteLine("Press 'exit' to exit!"); 22 string enterStr = Console.ReadLine(); 23 while (enterStr.ToLower() != "exit") 24 { 25 enterStr = Console.ReadLine(); 26 } 27 }
代码方面有个问题就是第8行一定要在AddServiceEndPoint前面,否则会出下面的问题:
未处理InvalidOperationException:在服务InChatter.Service.Chat实现的协定列表中找不到协定名称“IMetadataExchange”。将ServiceMetadataBehaviour添加到配置文件或直接添加到ServiceHost,以启用对该协定的支持。
xml的配置方式如下:
<system.serviceModel> <bindings> <netTcpBinding> <binding name="ChatServiceBinding" transactionFlow="true"/> </netTcpBinding> </bindings> <services> <service name="InChatter.Service.Chat" behaviorConfiguration="ChatBehavior"> <host> <baseAddresses> <add baseAddress="net.tcp://localhost:1121/InChatter" /> </baseAddresses> </host> <endpoint address="" binding="netTcpBinding" bindingConfiguration="ChatServiceBinding" contract="InChatter.Service.IChat" /> <endpoint address="Mex" binding="mexTcpBinding" contract="IMetadataExchange" /> </service> </services> <behaviors> <serviceBehaviors> <behavior name="ChatBehavior"> <serviceMetadata httpGetEnabled="False" /> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel>
(2)第二种方法就是使用http来定义我们元数据访问路径,其实也是前一节我们所采用的方式
1 Uri baseUri = new Uri("http://localhost:1378/InChatter"); 2 using (ServiceHost host = new ServiceHost(typeof(Chat), baseUri)) 3 { 4 NetTcpBinding binding = new NetTcpBinding(); 5 binding.Security.Mode = SecurityMode.None; 6 //会话保持时间 7 binding.ReceiveTimeout = TimeSpan.FromHours(2); 8 host.AddServiceEndpoint(typeof(IChat), binding, "net.tcp://localhost:1121/InChatter"); 9 host.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true }); 10 host.Opened += host_Opened; 11 try 12 { 13 host.Open(); 14 15 } 16 catch (Exception ex) 17 { 18 Console.WriteLine(ex.Message); 19 } 20 Console.WriteLine("Press 'exit' to exit!"); 21 string enterStr = Console.ReadLine(); 22 while (enterStr.ToLower() != "exit") 23 { 24 enterStr = Console.ReadLine(); 25 } 26 }
这里要注意,第1行以及第9行,而我们在添加服务引用的时候,自然需要使用http://localhost:1378/InChatter这个路径
4.确定服务的命名空间,就完成了服务的添加
我们明明的ChatServer,在生成以后,会在我们命名空间的基础上追加,如图所示。