• WCF学习之旅——第一个WCF示例(三)


    WCF学习之旅目录

    WCF学习之旅——第一个WCF示例(一)

    WCF学习之旅——第一个WCF示例(二)

    WCF学习之旅——第一个WCF示例(三)

    第五步:创建客户端

          WCF应用服务被成功寄宿后,WCF服务应用便开始了服务调用请求的监听工作。此外,服务寄宿将服务描述通过元数据的形式发布出来,相应的客户端就可以获取这些元数据。接下来我们来创建客户端程序进行服务的调用。

          1) 现在请先运行服务寄宿程序(Hosting.exe)。

          2) 在Visual Studio 2015的“解决方案资源管理器”中,把WinClient项目展开,左键选中“引用”,点击鼠标右键,弹出菜单,在弹出的上下文菜单中选择“添加服务引用(Add Service References)”。如下图。

           3) 此时会弹出一个对话框,如下图所示。在对话框中的“地址”输入框中输入服务元数据发布的源地址:http://127.0.0.1:8888/BookService/metadata,并在“命名空间”输入框中输入一个命名空间,然后点击“确定”按钮(如下图)。Visual studio 2015会自动生成一系列用于服务调用的代码和配置。

     

     添加服务引用

         4)  在Visual Studio 2015自动生成的类中,包含一个服务协定接口、一个服务代理对象和其他相关的类。被客户端直接用于服务调用的是一个继承自 ClientBase<IBookService>并实现了IBookService接口的服务代理类BookServiceClient。 如下图。

     

         5)BookServiceClient的具体实现如下图。

     

     

          6) 我们可以实例化BookServiceClient对象,执行相应方法调用WCF服务操作。客户端进行WCF服务调用的代码如下:

     

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
     
    namespace WinClient
    {
        public partial class FrmBook : Form
        {
            public FrmBook()
            {
    
                InitializeComponent();
            }
    
            private void btnGetBook_Click(object sender, EventArgs e)
            {
                BookServiceRef.Books book = new BookServiceRef.Books();
                BookServiceRef.BookServiceClient bookSvrClient = new BookServiceRef.BookServiceClient();
                textBoxMsg.Text= bookSvrClient.GetBook("3");
                book = XMLHelper.DeSerializer<BookServiceRef.Books>(textBoxMsg.Text);
                txtBookId.Text = book.BookID.ToString();
                txtAuthorID.Text = book.AuthorID.ToString();
                textBoxName.Text = book.Name;
                textBoxCategory.Text = book.Category.ToString();
                textBoxPrice.Text = book.Price.ToString();
    
            }
    
        }
    
    }

    运行后的结果,如下图。

     

    第六步:客户端通过ChannelFactory<T>方式调用WCF服务

          客户端通过服务代理对象进行服务的调用,上面的例子通过创建自动生成的继承自ClientBase<T>的类型对象进行服务调用。实际上,我们还具有另外一种创建服务代理的方法,就是通过ChannelFactory<T>。此外,WCF采用基于协定的服务调用方法,从上面的例子我们也可以看到,Visual Studio 2015在进行服务引用添加的过程中,会在客户端创建一个与服务端等效的服务协定接口。在我们的例子中,由于服务端和客户端都是在同一个解决方案中,完全可以让服务端和客户端引用相同的协定。

           1)  为了实现通过ChannelFactory<T>调用WCF服务的功能,我们需要添加一个新的项目,命名为SCF.Contracts,把原来在SCF. WcfService项目中的IBookService.cs文件移到SCF.Contracts项目中,同时变更命名空间。SCF. WcfService与WinClient项目同时添加对SCF.Contracts项目的引用。最后的项目结构如下图。

     

           2)  我们将通过于这个SCF.Contracts项目中的IBookService服务协定接口,使用 ChannelFactory<IBookService>创建服务代理对象,直接进行相应的服务调用。我们先实现全部在代码中实现基于 ChannelFacotory<T>进行服务代理的创建和服务调用的方式。代码如下:

    private void buttonChannelFactory_Click(object sender, EventArgs e)
    
            {
    
                using (ChannelFactory<IBookService> channelFactory = new ChannelFactory<IBookService>
    
                    (new WSHttpBinding(), "http://127.0.0.1:8888/BookService"))
    
                {
    
                    IBookService proxy = channelFactory.CreateChannel();
                    using (proxy as IDisposable)
    
                    {
                        textBoxMsg.Text = proxy.GetBook("4");
                        Books book = XMLHelper.DeSerializer<Books>(textBoxMsg.Text);
                        txtBookId.Text = book.BookID.ToString();
                        txtAuthorID.Text = book.AuthorID.ToString();
                        textBoxName.Text = book.Name;
                        textBoxCategory.Text = book.Category.ToString();
                        textBoxPrice.Text = book.Price.ToString();
                    }
    
                }
    
                }

            3)  点击“ChannelFactory方式”按钮之后,结果如下图。

     

           4)  由于终结点是WCF进行通信的唯一手段,ChannelFactory<T>本质上是通过指定的终结点创建用于进行服务调用的服务代理。在上面的代码中,在创建ChannelFactory<T>的时候再在构造函数中指定终结点的相关要素(协定通过范型类型表示,地址和绑定则通过参数指定)。上面这种直接在代码中写相应地址与绑定的方法,对于后期的维护不方便。在实际的WCF应用中,一般在配置文件中写地址与绑定,然后通过读取配置文件的方式来实现服务调用。我们在app.config配置文件中配置指定终结点的三要素,并为相应的终结点指定一个终结点配置名称(BookService)。配置信息如下:

    <?xml version="1.0" encoding="utf-8" ?>
    
    <configuration>
    
        <startup>
            <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
        </startup>
        <system.serviceModel>
            <bindings>
                <wsHttpBinding>
                    <binding name="WSHttpBinding_IBookService" />
                </wsHttpBinding>
            </bindings>
            <client>
                <endpoint address="http://127.0.0.1:8888/BookService" binding="wsHttpBinding"
                    bindingConfiguration="WSHttpBinding_IBookService" contract="SCF.Contracts.IBookService"
                    name="WSHttpBinding_IBookService">
                    <identity>
                        <userPrincipalName value="DEVELOPERAdministrator" />
                    </identity>
                </endpoint>
            </client>
        </system.serviceModel>
    
    </configuration>

     

            5)  接下来我们通过配置信息来创建ChannelFactory<T>对象,此时无须再指定终结点的绑定和地址了,而只须制定对应的终结点配置名称。代码如下。

     

      private void buttonChannelConfig_Click(object sender, EventArgs e)
    
            {
    
                using (ChannelFactory<IBookService> channelFactory = new ChannelFactory<IBookService>("WSHttpBinding_IBookService"))
    
                {
    
                    IBookService proxy = channelFactory.CreateChannel();
    
                    using (proxy as IDisposable)
    
                    {
    
                        textBoxMsg.Text = proxy.GetBook("5");
    
                        Books book = XMLHelper.DeSerializer<Books>(textBoxMsg.Text);
    
                        txtBookId.Text = book.BookID.ToString();
    
                        txtAuthorID.Text = book.AuthorID.ToString();
    
                        textBoxName.Text = book.Name;
    
                        textBoxCategory.Text = book.Category.ToString();
    
                        textBoxPrice.Text = book.Price.ToString();
    
                    }
    
                }
    
            }

            6) 点击“ChannelFactorys配置方式”按钮之后,结果如下图。

     

     

     

    注: 我在编写这个示例项目的过程中遇到了以下问题:

    WCF由于目标计算机积极拒绝,无法连接错误

    错误描述:新建的WCF类库项目,由WinForm程序托管,托管的时候没有错误,但是在客户端引用服务的时候,却找不到服务,而且 如果打开多个服务也不会报端口占用错误。

    解决思路:

    1)检查配置文件,看配置信息是否写的正确,不行

    2)重启电脑,不行

    3)把配置方式改成了直接代码方式,不行

    4)不寄宿WCF服务的情况下引用服务,提示一样的错误。我打开监听端口仔细找,没有找到我定义的8888端口。看来WCF服务寄宿没有成功,如果寄宿成功,端口肯定是在监听状态。

    解决办法:首先去掉using,然后再试,引用服务成功,调用也成功。原来当使用using时,如果using被释放,则host会被using关闭,所以服务打开之后,然后就立即被关闭了。请仔细观察下面两段代码的区别。

    错误代码:

     

     static void Main(string[] args)
            {
                try
                {
                    using (ServiceHost host = new ServiceHost(typeof(BookService)))
                    {
                        host.Opened += delegate
                        {
                            Console.WriteLine("BookService,使用配置文件,按任意键终止服务!");
                        };
                        host.Open();
                                       }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
                Console.Read();
            }

    正确代码:

    static void Main(string[] args)
            {
                try
                {
                    using (ServiceHost host = new ServiceHost(typeof(BookService)))
                    {
    host.Opened
    += delegate { Console.WriteLine("BookService,使用配置文件,按任意键终止服务!"); }; host.Open(); Console.Read(); } } catch (Exception ex) { Console.WriteLine(ex.Message); } }
  • 相关阅读:
    汇编语言(王爽) 实验九
    汇编语言(王爽)实验十
    leetcode longest common prefix(easy) /java
    leetcode container-with-most-water(medium) /java
    jdbc 驱动设置
    天上的星星都洒在我身上(mysql重装失败指南)
    leetcode palindrome number(easy) /java
    异常处理
    递归函数
    序列化模块
  • 原文地址:https://www.cnblogs.com/chillsrc/p/5304913.html
Copyright © 2020-2023  润新知