你的位置:首页 > ASP.net教程

[ASP.net教程]从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协议,需要

 

比如另一个是.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中配置如下:

 

<??>
<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

 

以上的的

 

回到名称为"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="PC201312021114\Administrator" />
    </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

 

就酱。