代码改变世界

使用Visual Studio 开发、调试WCF入门-2-无脑建立客户端

2012-08-06 15:27  duzher  阅读(1104)  评论(0编辑  收藏  举报

继续上一节的内容。上一节的网址:http://www.cnblogs.com/kinoo/archive/2012/08/06/2624917.html

 

本节代码下载地址:Kinoo.WCF-2.rar

 

1、在解决方案中新增一个WPF Windows项目,或者根据你的能力建立其他可独立执行的项目Console或者WinForm都可以,我这里命名为Kinoo.WCF.Client

2、不做任何工作,直接打开项目的app.config,发现里面没WCF的东西,只有这点内容:

App.Config

3、右键单击此项目选择【添加服务引用】,弹出下面窗体,直接点击【发现(Discovery)】:

image

4、直接点击【确定】,Visual Studio会自动启动那个服务端,获取服务器端的各种存取端口(或者说Contract),执行完成,发现几个变化

a、App.config中多了一段话,就是上一节的最后一个截图中那个配置文件的内容

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
    <system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <binding name="BasicHttpBinding_IService1" />
            </basicHttpBinding>
        </bindings>
        <client>
            <endpoint address="http://localhost:8733/Design_Time_Addresses/Kinoo.WCF.ServiceLibrary/Service1/"
                binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IService1"
                contract="ServiceReference1.IService1" name="BasicHttpBinding_IService1" />
        </client>
    </system.serviceModel>
</configuration>

b、解决方案多了一些内容:增加了一个Service Reference,增加了与其配套的命名空间,比如System.ServiceModel、System.Runtime.Serialization,如下图所示,其中这些命名空间看来是客户端必备了,具体左右以后章节再说,或者自己现在去Google。

image

5、我们双击ServiceReference1,可以打开对象浏览器,看到Service1Client,如下图所示,同时构造方法默认有多达5个重载,当然,我们的无脑开发,还是采用无参数的,后面的章节再讲其它构造方法。

image

6、打开MainWindow的设计视图,拖拽几个控件上来:

<Window x:Class="Kinoo.WCF.Client.MainWindow" 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
        <Button Name="btnInvokeRequest" Content="Invoke" HorizontalAlignment="Left" Margin="351,104,0,0" VerticalAlignment="Top" Width="75" Height="23" Click="btnInvokeRequest_Click"/> 
        <TextBox Name="txtRequest" HorizontalAlignment="Left" Height="23" Margin="67,104,0,0" TextWrapping="Wrap" Text="Please input a number" VerticalAlignment="Top" Width="265"/> 
        <TextBlock Name="txtResponse" HorizontalAlignment="Left" Margin="67,150,0,0" TextWrapping="Wrap" Text="Responses" VerticalAlignment="Top" Height="48" Width="359"/>

    </Grid> 
</Window> 

7、在按钮的Click事件里,添加如下代码:

首先添加引用:

using Kinoo.WCF.Client.ServiceReference1;

然后添加代码:

   1:          private void btnInvokeRequest_Click(object sender, RoutedEventArgs e)
   2:          {
   3:              try
   4:              {
   5:                  Service1Client client = new Service1Client();
   6:                  txtResponse.Text = client.GetData(Int32.Parse(txtRequest.Text));
   7:              }
   8:              catch (Exception ex)
   9:              {
  10:                  txtResponse.Text = ex.Message;
  11:              }
  12:          }

7、OK,一个完整的客户端完成了,可以调用服务器端所有的开发接口(或者说服务契约ServiceContract)。

8、右键单机项目【Kinoo.WCF.Client】,选择【调试】-【启动新实例】,然后WPF客户端启动了,但是也发现另一个问题,Host服务器端也自动启动了。先不管为什么自动启动,我们先输入个值试试火力!

image

9、至此,完整的wCF客户端+半完整的WCF服务器端(为什么说服务器端半完整,可以去看上一节所说),已经OK了。

 

神秘莫测的WCF入门至此完成,只写了两行代码,感觉如何呢?WCF简单吗?NO,看看那些长篇大论的WCF入门教程你就知道了。只不过Visual Studio讲这一切简化了。感谢微软!

 

那么问题来了:

1、为什么我调试Client的时候,服务器端会自动执行?

右键单击WCF服务库项目,选择【属性】,此项目比别的项目多一个标签:【WCF选项】,这里有个【在调试同一解决方案中的其他项目是启动WCF服务主机】,默认这个CheckBox是被Checked的,所以只要是解决方案中的其它项目调试,他都会自动启动。这个实在太方便了。因为我们的WCF服务将来可以发布成一个独立的Windows程序作为运行时主机,也可以发布成一个Console程序作为运行时主机,还可以发布成Windows服务作为运行时主机,但是这个都是发布以后的事情,调试阶段,有这个东西在,实在太爽了,用一段时间就会体会到了。

image

2、为什么【添加服务引用】时,使用【发现】,而不是使用明确的地址,原因有几点:

a、如果你引用的是别的项目组、别的产品、甚至是别的公司的引用,输入明确的网址是当然的、必须的。如果你的项目组把WCF服务器端客户端是分开两个解决方案各自编译的,不得不各自调试,最好建议你的头儿整合到一起,这个是为了自己好,省的误导。

b、服务器端客户端在一个解决方案下不会产生任何影响、冲突。反倒调试的时候非常爽,你可以在服务端GetData上加个断点,一调试就知道了。

c、服务端接口发生变化了,怎么办?右键单机服务引用,选择【更新服务引用】

image

3、现在可以问问为什么能看到IService1、还能看到ServiceClient、还能调用GetData接口?

a、之所以能看到IService1接口,是因为添加服务引用;之所以能看到ServiceClient,是因为Visual Studio帮你封装了一个只要是写客户端的人都会封装的代码,之所以封装的这个Client里能看到GetData接口,是因为你服务器端的声明。

b、所谓的契约就是以前我们常说的接口,Service1是服务契约,GetData是操作契约。输入的参数、返回的值都是数据契约,Int、String这些基础数据类型可以理解为数据契约,你自己建立的类要想作为输入输出的参数之一,标记上DataContract即可,如下图所示。把各种文章说到的各种理论全忘记,记住刚才这句话以及下面这个图就足够了。以后的开发再慢慢深化即可。

image

4、数据也获取了,程序也调通了,这个实例用的是什么数据存取协议呢??SOAP?Socket?Remoting?

都不是,看看服务器端或客户端的配置文件即可了,至于协议,也是虽然入门必知,但也是较深的内容,后面的章节再讲。因为:WCF接口在开发时可以不用管用什么协议存取,只要专注于接口开发即可。至于到底采用什么协议,可以由配置文件决定(当然也可以代码决定,但是写这种初级代码不是现代程序员的风格),甚至配置文件可以决定同时采用N种协议,一起支持!是不是很爽呢?

如果你的宿主程序的代码(下一节开始我们自己写宿主程序代码),在初始化Host或客户端时,使用C#代码在指定存取协议,最好抓紧改掉,那代码80%的可能没法见人的。就像如今的ADO.NET的基础操作现在基本没人会写一样,那种代码最好不要写,也没必要记住。

 

5、说起上面这个特性不得不提到WCF的另一种项目类型【WCF服务应用程序】,我们建立一个,会发现,里面也有个配置文件,不过这个文件是Web.Config,而不是App.Config,说明这种项目比较适合Web,同时,右键单击项目,点击【发布】,是以发布Web应用的形式来发布的。这种通用性不高,尤其是在大数据量传输的时候,WEB模式传数据速度、稳定性等没保证。至于再后面两种服务应用,暂时不做讨论,后面章节再说。

image

image

5、如果解决方案中,有N个子项目都要调用服务器,难道每个都要添加服务引用吗?

单建一个类库项目,添加服务引用,其他所有使用服务器端的子项目都引用这个类库即可了。

6、如果你【添加服务引用】时【发现】不了服务,可以到下面这个网址看看原因:

http://www.christiano.ch/wordpress/2010/02/20/vs-net-add-service-reference-discover-service-does-not-work/

如果改了GUID还是不行,重建一个项目好了。