导航

WCF 实例

Posted on 2011-06-24 16:40  杨彬Allen  阅读(242)  评论(0编辑  收藏  举报

这篇文章转自http://www.docin.com/p-59081680.html,但因为在原文有些地方我没读懂,后来又借鉴其他一些文章才写完整个代码,故在原文做了一些修改并重新整理,希望对您有所帮助!如果您在看的时候有疑惑,可留言或发邮件至:takako_yang@sina.com。

本文讲述的是最简单的WCF程序示例:如何在控制台应用程序实现和承载WCF服务,以及如何创建、配置和使用WCF客户端。

文章主体可分为两部分,分别介绍服务器端和客户端的变成实现。细分的话,可以分为五项任务。

·服务器端

定义WCF服务协定(任务一)

  这是创建基本WCF服务和可以使用该服务的客户端所需的六项任务中的第一项任务。

  创建基本WCF服务时,第一项任务是为与外界共享的服务创建协定,并在其中描述如何与该服务进行通信。

 

  具体步骤为:

  1、创建新的控制台应用程序项目。开启VS2010(或其他版本),在左上角"File"中选择"New"->"Project",选择"Visual C#"中的"Console Application",将项目的Name改成"TakakoService"。注意此时的命名空间也应该是"TakakoService",(命名空间很重要,后续要用到)。

  2、右击"Solution"中的"TakakoService"项目,选择"Add Reference",在弹出的对话框中的".Net"选项卡中选择"System.ServiceModel",然后单击"OK"。

  

  下面是编程步骤:

  1、在program.cs中添加两个using语句,它们是:

      using System.ServiceModel;
      using System.ServiceModel.Description;

  2、创建一个新的ICalculator接口,并将ServiceContractAttribute属性应用于该接口,并将Namespace值设置为http://TakakoService。此命名空间指定该服务在计算机上的路径,并构成该服务的基址部分。请注意,在通过采用方括号表示法的属性来批注接口或类时,该属性类可以从其名称中去掉"Attribute"部分。

  [ServiceContract(Namespace = "http://TakakoService")]

  public interface ICalculator

  3、在接口中创建方法声明,并将OperationContract属性应用于每个要作为公共WCF协定的一部分公开的方法。

        [OperationContract]
        double Add(double n1, double n2);

        [OperationContract]
        double Subtract(double n1, double n2);

        [OperationContract]
        double Multiply(double n1, double n2);

        [OperationContract]
        double Divide(double n1, double n2);  

  下面是创建服务协定的完整代码段:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Description;

namespace TakakoService
{
#region My Test
[ServiceContract(Namespace
="http://TakakoService")]
publicinterface ICalculator
{
[OperationContract]
double Add(double n1, double n2);

[OperationContract]
double Subtract(double n1, double n2);

[OperationContract]
double Multiply(double n1, double n2);

[OperationContract]
double Divide(double n1, double n2);
}
}

  

定义WCF服务协定(任务二)

  1、创建一个新的CalculatorService类,该类从用户定义的ICalculator接口继承而来并实现该接口定义的协定功能。

  public class CalculatorService : ICalculator

  

  2、实现每个算术运算符的功能。

   在创建和实现了服务协定后,下一步是运行该服务。运行服务由三个步骤组成:配置、承载和打开服务。

publicclass CalculatorService : ICalculator
{
publicdouble Add(double n1, double n2)
{
double result = n1 + n2;
Console.WriteLine(
"Received Add({0},{1})", n1, n2);
Console.WriteLine(
"Return:{0}", result);
return result;
}

publicdouble Subtract(double n1, double n2)
{
double result = n1 - n2;
Console.WriteLine(
"Received Subtract({0},{1})", n1, n2);
Console.WriteLine(
"Return:{0}", result);
return result;
}

publicdouble Multiply(double n1, double n2)
{
double result = n1 * n2;
Console.WriteLine(
"Received Multiply({0},{1})", n1, n2);
Console.WriteLine(
"Return:{0}", result);
return result;
}

publicdouble Divide(double n1, double n2)
{
double result = n1 / n2;
Console.WriteLine(
"Received Divide({0},{1})", n1, n2);
Console.WriteLine(
"Return:{0}", result);
return result;
}
}

  在创建和实现了服务协定后,下一步是运行该服务。运行服务由三个步骤组成:配置、承载和打开服务。

  

配置、承载和运行服务(任务三)

  · 为服务配置基址

  为服务的基址创建URI实例。此URI指定HTTP方案、本地计算机、端口号8000,以及服务协定中为服务命名空间指定的服务路径 ServiceModelSample/Services。

Uri baseAddress =new Uri(http://localhost:8000/ServiceModelSamples/Service);

  · 承载服务

 1、创建一个新的ServiceHost实例以承载服务。必须指定实现服务协定和基址的类型。对于此示例,我们将基址指定为:http://localhost:8000/ServiceModelSamples/Service,并将CalculatorService指定为实现服务协定的类型。

 

ServiceHost selfHost =new ServiceHost(typeof(CalculatorService), baseAddress);

  2、添加一个捕获CommunicationException的try catch语句,并在接下来的三个步骤中将该代码添加到try块中。

  3、添加公开服务的终结点。为此,必须指定终结点公开的协议、绑定和终结点的地址。此例中,将ICalculator指定为协定,将WSHttpBinding指定为绑定,并将CalculatorService指定为地址。在这里注意,我们指定的是相对地址。终结点的完整地址是基址和终结点地址的组合。在此例中,完整地址是http://localhost:8000/ServiceModelSamples/Service/CalculatorService

try
{
selfHost.AddServiceEndpoint(
typeof(ICalculator),
new WSHttpBinding(),
"CalculatorService"
);

  4、启用元数据交换。为此,必须添加服务元数据行为。首先创建一个ServiceMetadataBehavior实例,将HttpGetEnabled属性设置为true,然后为服务添加新行为。

try
{
selfHost.AddServiceEndpoint(
typeof(ICalculator),
new WSHttpBinding(),
"CalculatorService"
);

ServiceMetadataBehavior smb
=new ServiceMetadataBehavior();
smb.HttpGetEnabled
=true;
selfHost.Description.Behaviors.Add(smb);

  5、打开ServiceHost并等待传入消息。用户按Enter键时,关闭ServiceHost。

try
{
selfHost.AddServiceEndpoint(
typeof(ICalculator),
new WSHttpBinding(),
"CalculatorService"
);

ServiceMetadataBehavior smb
=new ServiceMetadataBehavior();
smb.HttpGetEnabled
=true;
selfHost.Description.Behaviors.Add(smb);

selfHost.Open();
Console.WriteLine(
"The service is ready");
Console.WriteLine(
"Press<ENTER> to terminate service");

Console.WriteLine();
Console.ReadLine();

selfHost.Close();
}

  下面是服务端(即“Service”项目中的Program.cs文件中)的完整程序代码:

using System;
using System.ServiceModel;
using System.ServiceModel.Description;

namespace TakakoService
{
#region My Test
[ServiceContract(Namespace
="http://TakakoService")]
publicinterface ICalculator
{
[OperationContract]
double Add(double n1, double n2);

[OperationContract]
double Subtract(double n1, double n2);

[OperationContract]
double Multiply(double n1, double n2);

[OperationContract]
double Divide(double n1, double n2);
}

publicclass CalculatorService : ICalculator
{
publicdouble Add(double n1, double n2)
{
double result = n1 + n2;
Console.WriteLine(
"Received Add({0},{1})", n1, n2);
Console.WriteLine(
"Return:{0}", result);
return result;
}

publicdouble Subtract(double n1, double n2)
{
double result = n1 - n2;
Console.WriteLine(
"Received Subtract({0},{1})", n1, n2);
Console.WriteLine(
"Return:{0}", result);
return result;
}

publicdouble Multiply(double n1, double n2)
{
double result = n1 * n2;
Console.WriteLine(
"Received Multiply({0},{1})", n1, n2);
Console.WriteLine(
"Return:{0}", result);
return result;
}

publicdouble Divide(double n1, double n2)
{
double result = n1 / n2;
Console.WriteLine(
"Received Divide({0},{1})", n1, n2);
Console.WriteLine(
"Return:{0}", result);
return result;
}
}
#endregion

class Program
{
staticvoid Main(string[] args)
{
Test();
}

staticvoid Test()
{
Uri baseAddress
=new Uri("http://localhost:8000/ServiceModelSamples/Service");

ServiceHost selfHost
=new ServiceHost(typeof(CalculatorService), baseAddress);
try
{
selfHost.AddServiceEndpoint(
typeof(ICalculator),
new WSHttpBinding(),
"CalculatorService"
);

ServiceMetadataBehavior smb
=new ServiceMetadataBehavior();
smb.HttpGetEnabled
=true;
selfHost.Description.Behaviors.Add(smb);

selfHost.Open();
Console.WriteLine(
"The service is ready");
Console.WriteLine(
"Press<ENTER> to terminate service");

Console.WriteLine();
Console.ReadLine();

selfHost.Close();
}
catch (CommunicationException ce)
{
Console.WriteLine(
"An exception occurred:{0}", ce.Message);
selfHost.Abort();
}
}
}
}

  若要运行服务,启动项目文件夹下bin目录中的Service.exe即可。

  前面三篇文章是讲服务器端的部署和运行,下面讲讲客户端如何配置和使用。 

创建和配置WCF客户端(任务四)

  1、通过执行以下步骤,在Visual Studio中为客户端创建新项目:

    1、在包含该服务(之前文章所述的服务)的同一解决方案中的“解决方案资源管理器”(位于右上角)中,右击当前解决方案,然后选择“添加新项目”。

    2、在“添加新项目”的对话框中,选择“控制台应用程序”模板,然后将其命名为Client。使用默认的位置。

    3、单击“确定”。

  2、为项目提供对System.ServiceModel命名空间的引用:在“解决方案资源管理器”中右击"Service”项目,从".Net"选项卡上的“组件名称”列中选择"System.ServiceModel",然后单击“确定”。

  3、为System.ServiceModel命名空间添加using语句:using System.ServiceModel;

  4、启动在前面的步骤中创建的服务。(即打开在服务器项目中生成的Service.exe可执行文件,一定要开启,否则后续无法生成客户端所需文件

  5、这里和原文有点出入。我建议大家可以看这篇“通过SvcUtil.exe生成客户端代码和配置http://www.cnblogs.com/cjfwu/archive/2010/05/21/1740895.html

  这时会在你源代码的文件夹下多出两个代理文件来:output.config和CalculatorService.cs。在“解决方案资源管理器”中右击"Client”并选择“添加现有项”,然后选择前面生成的两个代理文件。到此,你的Client程序应该有3个文件:Program.cs, CalculationService.cs, output.config。

使用WCF客户端(任务五)

  1、为要调用的服务的基址创建EndpointAddress实例,然后创建WCF Client对象。

EndpointAddress epAddress =new EndpointAddress("http://localhost:8000/ServiceModelSamples/Service/CalculatorService");
CalculatorClient client
=new CalculatorClient(new WSHttpBinding(), epAddress);

  2、从Client内调用客户端操作。

double value1 =100.00D;
double value2 =15.99D;
double result = client.Add(value1, value2);
Console.WriteLine(
"Add({0},{1})={2}", value1, value2, result);

value1
=145.00D;
value2
=76.54D;
result
= client.Subtract(value1, value2);
Console.WriteLine(
"Subtract({0},{1})={2}", value1, value2, result);

value1
=22.00D;
value2
=7.00D;
result
= client.Divide(value1, value2);
Console.WriteLine(
"Divide({0},{1})={2}", value1, value2, result);

  3、在WCF客户端上调用Close。

client.Close();

  

  下面是客户端的完整代码:

namespace Client
{
class Program
{
staticvoid Main(string[] args)
{
EndpointAddress epAddress
=new EndpointAddress("http://localhost:8000/ServiceModelSamples/Service/CalculatorService");
CalculatorClient client
=new CalculatorClient(new WSHttpBinding(), epAddress);

double value1 =100.00D;
double value2 =15.99D;
double result = client.Add(value1, value2);
Console.WriteLine(
"Add({0},{1})={2}", value1, value2, result);

value1
=145.00D;
value2
=76.54D;
result
= client.Subtract(value1, value2);
Console.WriteLine(
"Subtract({0},{1})={2}", value1, value2, result);

value1
=22.00D;
value2
=7.00D;
result
= client.Divide(value1, value2);
Console.WriteLine(
"Divide({0},{1})={2}", value1, value2, result);

client.Close();

Console.WriteLine();
Console.WriteLine(
"Press <ENTER> to terminate client");
Console.ReadLine();
}
}
}

  先启动Server端,就是先debug第一个程式(或者直接双击其bin文件夹下的.exe),再启动Client端,就是debug第二个程式(或者直接双击其bin文件夹下的.exe)。

  如果您看到第一个dos界面如下所述,证明这段程式调试成功。

The service is ready

Press<ENTER> to terminate service

Received Add(100,15.99)

Return:115.99

Received Subtract(145,76.54)

Return:68.46

Received Divide(22,7)

Return:3.14285714285714