从Web Service和Remoting Service引出WCF服务

本篇先通过Web Service和Remoting Service创建服务,抛砖引玉,再体验WCF服务。首先一些基本面:


什么是WCF?

 

Windows Communication Foundation,微软的平台,用来搭建分布式的、互操作的应用程序。

什么是分布式应用程序?

 

如果把计算机看成是节点,分布式应用程序跑在2个或2个以上的节点上。比如,一个应用程序运行在一台电脑上,另一个服务运行在另外一台电脑上,应用程序消费所提供的服务。

为什么需要分布式应用程序?

 

比如有一个应用程序的结构是数据层,业务层,表现层,而这些层可能分布在不同的电脑上。当用户请求比较少的时候,可以把这些层放在同一台服务器上,当用户请求达到一定的数量级,为了不影响性能,这时后就需要把这些层扩展到不同的服务器上。

另外,一个公司可能消费另一个公司提供的服务,这也是分布式的。

什么是互操作应用程序?

 

一个应用程序如果可以和任何平台上的应用程序通讯,这个应用程序就是互操纵应用程序。Web Service是互操作应用程序。.NET remoting Service不是,它只能被.NET 应用程序消费。

为什么要学WCF?

 

比如有2个客户端应用程序。

比如一个是Java应用程序,接收HTTP协议,需要XML格式的返回信息。为此,我们可以创建一个Web Service服务。

比如另一个是.NET应用程序,接收TCP协议,需要二进制格式的返回信息,为此,我们可以创建一个Remoting Service。

在这里,作为开发者,需要同时学会使用Web Service和Remoting Service。

而WCF统一了这些方面,只要学会WCF,就能处理上诉的应用场景。WCF提供2个end point,在end point的configuraiton中设置协议以及信息格式。

创建Web Service

 

大致思路是:

→ 创建Web Service
→ 客户端引用服务,并调用服务方法

创建一个空的ASP.NET Web应用程序。

添加"HelloWebService.asmx"文件。

修改如下:

    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
    // 若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消注释以下行。 
    // [System.Web.Script.Services.ScriptService]
    public class HelloWebService : System.Web.Services.WebService
    {
        [WebMethod]
        public string GetMessage(string name)
        {
            return "Hello " + name;
        }
    }

在浏览器中浏览"HelloWebService.asmx"文件:

1

点击"GetMessage"方法,在界面中输入实参,点击"调用"。

2

显示如下:

3

"http://localhost:3087/HelloWebService.asmx/GetMessage"这个就是获取Web Service的具体地址。

在当前的解决方案下再添加一个空的ASP.NET Web应用程序,名称为"HelloWebClient",并创建一个名称为"WebForm1.aspx"的Web窗体。

右键"HelloWebClient"下的"引用",点击"添加服务引用"。

4

点击"确定",在"HelloWebClient"下多了引用的Web Service。

5


完善"WebForm1.aspx"页面。

    <table>
         <tr>
             <td>
                 <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
                 <asp:Button ID="Button1" runat="server" Text="获取信息" OnClick="Button1_Click" />
             </td>
         </tr>
         <tr>
             
             <td>
                 <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
             </td>
         </tr>
     </table>

当在TextBox中输入信息,点击"获取信息按钮",调用Web Service服务,就可获取到信息。

        protected void Button1_Click(object sender, EventArgs e)
        {
            HelloWebService.HelloWebServiceSoapClient client = new HelloWebService.HelloWebServiceSoapClient();
            Label1.Text = client.GetMessage(TextBox1.Text);
        }

6

创建Remoting Service

大致思路是:

→ 写一个接口
→ 实现接口,并派生于MarshalByRefObject
→ 宿主,注册信道,规定端口
→ 应用程序,也注册信道,调用方法

打开一个新的Visual Studio界面。

创建一个名称为"HelloRemotingService"的类库。

在该类库下创建一个"IHelloRemotingService"的接口。

namespace HelloRemotingService
{
    public interface IHelloRemotingService
    {
        string GetMessage(string name);
    }
}

在"HelloRemotingService"类库所在解决方案下创建名称为"MyRemotingService"的类库。

在"MyRemotingService"的类库中,添加对"HelloRemotingService"类库的引用。

在"MyRemotingService"中添加名称为"Hello"的类文件。

using HelloRemotingService;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MyRemotingService
{
    public class Hello : MarshalByRefObject, IHelloRemotingService
    {
        public string GetMessage(string name)
        {
            return "Hello" + name;
        }
    }
}

现在需要宿主。在当前解决方案下添加一个名称为"RemotingServiceHost"的控制台应用程序。并添加对"HelloRemotingService"类库和MyRemotingService"类库的引用,再添加"System.Runtime.Remoting"组件。

......
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using MyRemotingService;
namespace RemotingServiceHost
{
    class Program
    {
        static void Main(string[] args)
        {
            Hello h = new Hello();
            //信道
            TcpChannel channel = new TcpChannel(9090);
            //向信道服务注册信道
            ChannelServices.RegisterChannel(channel,true);
            //注册服务端对象
            RemotingConfiguration.RegisterWellKnownServiceType(typeof(Hello), "GetMessage", WellKnownObjectMode.Singleton);
            Console.WriteLine("Remoting service启动了 @" + DateTime.Now);
            Console.ReadKey();
        }
    }
}

在解决方案下创建一个名称为"HelloRemotingServiceClient"的窗体。创建如下界面:

7

添加对"HelloRemotingService"类库和MyRemotingService"类库的引用,再添加"System.Runtime.Remoting"组件。

......
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using MyRemotingService;
namespace HelloRemotingServiceClient
{
    public partial class Form1 : Form
    {
        IHelloRemotingService client;
        public Form1()
        {
            InitializeComponent();
            TcpChannel channel = new TcpChannel();
            ChannelServices.RegisterChannel(channel, true);
            client = (IHelloRemotingService)Activator.GetObject(typeof(IHelloRemotingService), "tcp://localhost:9090/GetMessage");
        }
        
        private void button1_Click(object sender, EventArgs e)
        {
            label1.Text = client.GetMessage(textBox1.Text);
        }
    }
}

生成解决方案。

运行宿主程序。

8

运行窗体程序。

9


WCF登场

 

在Visual Studio中创建一个名称为"HelloWcf"的类库。

在"HelloWcf"的类库添加一个名称为"FirstWcf"的"WCF 服务",项目自动为我们创建了"IFristWcf"和"FirstWcf"两个类文件,并自动添加了对"System.ServiceModel"的引用。

10

修改"IFirstWcf"接口:

namespace HelloWcf
{
    // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的接口名“IFirstWcf”。
    [ServiceContract]
    public interface IFirstWcf
    {
        [OperationContract]
        string GetMessage(string name);
    }
}

修改"FirstWcf"类:

namespace HelloWcf
{
    // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的类名“FirstWcf”。
    public class FirstWcf : IFirstWcf
    {
        public string GetMessage(string name)
        {
            return "Hello " + name;
        }
    }
}

现在需要宿主。在当前解决方案下添加一个"WcfHost"的控制台应用程序。

为"WcfHost"添加对"System.ServiceModel"的引用。

为"WcfHost"添加对"HelloWcf"类库的引用。

再为"WcfHost"配置end point, 需要添加2个end point,一个用来接收HTTP协议,一个用来接收TCP协议。

在App.config中配置如下:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
    <system.serviceModel>
      <services>
        <service name="HelloWcf.FirstWcf" behaviorConfiguration="mexBehaviour">
          <endpoint address="HelloWcf" binding="basicHttpBinding" contract="HelloWcf.IFirstWcf"></endpoint>
          <endpoint address="HelloWcf" binding="netTcpBinding" contract="HelloWcf.IFirstWcf"></endpoint>
          <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"></endpoint>
          <host>
            <baseAddresses>
              <add baseAddress="http://localhost:9090"/>
              <add baseAddress="net.tcp://localhost:6060"/>
            </baseAddresses>
          </host>
        </service>
      </services>
    
      <behaviors>
          <serviceBehaviors>
            <behavior name="mexBehaviour">
              <serviceMetadata httpGetEnabled="true"/>
            </behavior>
          </serviceBehaviors>
      </behaviors>
    
    </system.serviceModel>
</configuration>

把"WcfHost"设置为启动程序。

再启动一个新的Visual Studio。

■ Web客户端消费WCF服务

 

创建一个名称为"WcfClient"的空的ASP.NET网站。

打开宿主应用程序。

11

在浏览器中输入:http://localhost:9090

12

点击"http://localhost:9090/?wsdl"链接。

13

以上的的xml格式和Web Service是很像的。

回到名称为"WcfClient"的空的ASP.NET网站,右键"引用",点击"添加服务引用",填写如下:

14

点击"确定"。

这时,自动添加了对"System.ServiceModel"的引用,自动添加了"Service References"文件。

15

同时,自动在Web.config中增加了<system.serviceModel>节点。

<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" />
  </system.web>
  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBinding_IFirstWcf" />
      </basicHttpBinding>
      <netTcpBinding>
        <binding name="NetTcpBinding_IFirstWcf" />
      </netTcpBinding>
    </bindings>
    <client>
      <endpoint address="http://localhost:9090/HelloWcf" binding="basicHttpBinding"
        bindingConfiguration="BasicHttpBinding_IFirstWcf" contract="HelloService.IFirstWcf"
        name="BasicHttpBinding_IFirstWcf" />
      <endpoint address="net.tcp://localhost:6060/HelloWcf" binding="netTcpBinding"
        bindingConfiguration="NetTcpBinding_IFirstWcf" contract="HelloService.IFirstWcf"
        name="NetTcpBinding_IFirstWcf">
        <identity>
          <userPrincipalName value="PC201312021114Administrator" />
        </identity>
      </endpoint>
    </client>
  </system.serviceModel>
</configuration>

添加一个aspx文件,编写如下:

    <div>
        <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
        <asp:Button ID="Button1" runat="server" Text="获取信息" OnClick="Button1_Click" />
        <br />
        <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
    </div>

编写按钮事件如下:

        protected void Button1_Click(object sender, EventArgs e)
        {
            HelloService.FirstWcfClient client = new HelloService.FirstWcfClient();
            Label1.Text = client.GetMessage(TextBox1.Text);
        }

浏览该页面,点击按钮,发生如下报错:

16

提示需要明确end point。

我们需要用到Web.config中的如下节点:

<endpoint address="http://localhost:9090/HelloWcf" binding="basicHttpBinding"
        bindingConfiguration="BasicHttpBinding_IFirstWcf" contract="HelloService.IFirstWcf"
        name="BasicHttpBinding_IFirstWcf" />         

修改按钮事件如下:

        protected void Button1_Click(object sender, EventArgs e)
        {
            HelloService.FirstWcfClient client = new HelloService.FirstWcfClient("BasicHttpBinding_IFirstWcf");
            Label1.Text = client.GetMessage(TextBox1.Text);
        }

再次浏览页面,输入内容,点击按钮,一切正常。

17   

■ 窗体应用程序消费WCF服务

 

重新打开一个Visual Studio, 创建一个名称为"WcfFormClient"的窗体应用程序。

添加服务引用如下:

18

设计界面如下:

19

编写按钮事件如下:

        private void button1_Click(object sender, EventArgs e)
        {
            HelloServiceTwo.FirstWcfClient client = new HelloServiceTwo.FirstWcfClient("NetTcpBinding_IFirstWcf");
            label1.Text = client.GetMessage(textBox1.Text);
        }

运行窗体应用程序,输入内容,点击按钮,一切正常。       

20

至此,通过WCF的2个end point,客户端既可以使用HTTP协议通讯,也可以使用TCP协议通讯。


总结一下WCF服务的调用过程:

 

→ 创建WCF服务,自动生成一个接口和实现类
→ 宿主需要添加对"System.ServiceModel"的引用以及WCF服务所在类库的引用
→ 在宿主的配置文件中配置<system.serviceModel>节点,以及end point等信息
→ 客户端程序添加对WCF服务的引用
→ 客户端在声明WCF服务代理类实例的时候,需要明确指出使用哪一个end point

就酱。

原文地址:https://www.cnblogs.com/darrenji/p/4630090.html