65.9K
CodeProject 正在变化。 阅读更多。
Home

WCF 服务库( 使用 Windows 服务托管)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.86/5 (91投票s)

2009年7月15日

CPOL

11分钟阅读

viewsIcon

336734

使用此应用程序作为示例, 任何人都可以使用 N 层模型设计他们的应用程序, 使用 WCF

引言

通常,我们准备 WCF 服务并将其托管在 IIS 中,这在有不同客户端从系统外部访问服务时很有用。但如果服务旨在供本地系统客户端使用,那么将 WCF 服务作为 Windows 服务托管会是更好的主意。在本文中,我们将了解如何创建 WCF 服务并使其作为 Windows 服务运行。

任何人都可以在分层模型中使用 WCF 设计其应用程序,并将此应用程序作为示例。

为此,我们遵循分层架构,其中服务驻留在一个位置,托管在另一个位置,并从另一个位置进行消费。

为了清楚地了解我们将要做什么,以下是议程

  1. 创建打包服务到 DLL 文件的 WCF 服务库
  2. 使用测试宿主环境测试创建的服务
  3. 从该环境消费服务
  4. 向 Windows 操作系统注册服务 DLL,使其作为 Windows 服务运行
  5. 消费作为 Windows 服务运行的 WCF 服务

由于我们的主要目的是展示如何遵循这些步骤,因此我们正在准备一个非常简单的服务,以使事情不那么复杂。此服务获取默认 pubs 数据库中 Jobs 表的 JobId,并返回 Job 描述和一些其他数据。

所以,事不宜迟,我们开始构建应用程序。

创建 WCF 服务库

i. 创建新的 WCF 服务库并添加我们的服务

在 Visual Studio 中创建新项目时,WCF 服务库模板位于 WCF 项目类型下。

因此,创建一个新项目 -> 导航到 WCF 选项 -> 选择 WCF 服务库并指定名称。这里我们将其命名为 WCFJobsLibrary。

这将创建一个服务库,其中包含默认服务接口和用于实现它的类。由于我们不需要它们,我们只需删除它们并创建一个具有我们自己自定义名称的服务。为此,在解决方案资源管理器中,右键单击项目,选择添加 -> 新建项,然后选择 WCF 服务。我们将其命名为 Jobs。

此步骤将创建 IJobs 接口和 Jobs 类。此外,Jobs 的服务配置将由 Visual Studio 自动写入 App.Config。您可以向下滚动到 <services> 标签以查看终结点详细信息,以及 <system.serviceModel> 下的 <behaviors> 标签以查看服务行为。

默认情况下,将创建两个终结点——一个使用 wsHttpBinding,另一个使用 mexHttpBinding 的 mex 终结点。mex 终结点向客户端提供元数据以创建代理,我们稍后将讨论此过程。

ii. 准备我们自己的复杂类型并使其可序列化和支持 WCF

现在,我们将继续为服务编写代码。在 Jobs 类中,我们将定义一个返回包含 Job 详细信息的复杂类型的方法。对于此复杂类型,我们应该准备一个包含所有必需字段的类。因此,从添加 -> 新建项中添加一个新类,并将其命名为 Job.cs。

该类必须通过 [DataContract] 属性指定,以使其可序列化并支持 WCF。类似地,属性应通过 [DataMember] 属性指定。由于这些属性存在于 System.Runtime.Serialization 命名空间中,而该命名空间在类中默认不可用,因此我们需要导入该命名空间。

using System.Runtime.Serialization;
namespace WCFJobsLibrary
{
    [DataContract]
    public class Job
    {
        [DataMember]
        public string Description { get; set; }
        [DataMember]
        public int MinLevel{get;set;}
        [DataMember]
        public int MaxLevel { get; set; }
 
    }
}

iii. 添加契约

现在,我们的下一步是添加契约。为此,我们在 IJobs 接口中指定我们的方法,并用 [OperationContract] 属性装饰它们。

    [ServiceContract]
    public interface IJobs
    {
        [OperationContract]
        DataSet GetJobs();
 
        [OperationContract]
        Job GetJobInfo(int Jobid);
    }

这里这两个方法执行的操作几乎相同,只是略有不同:GetJobs() 方法将获取 Jobs 表中的所有记录,而 GetJobInfo() 将只获取与给定 Jobid 匹配的记录。

GetJobs() 返回一个 DataSet,它是一个内置复杂类型,而 GetJobInfo 将返回我们已经在 Job 类中定义的 Job 类型。

iv. 实现接口

我们在 Jobs 类中实现 IJobs 接口。为此,我们转到 Jobs 类,右键单击 IJobs 并选择“实现接口”选项,以自动在 Jobs 类中实现 IJobs 接口。完成此操作后,我们将得到空方法,我们需要在其中编写代码。方法的代码如下所示:

public class Jobs : IJobs
{
   #region IJobs Members
 
   public System.Data.DataSet GetJobs()
   {
       SqlConnection cn = new SqlConnection("data source=mytoy; user
                                             id=sa; database=pubs");
       DataSet ds = new DataSet();
       SqlDataAdapter da = new SqlDataAdapter("Select * from jobs", cn);
       da.Fill(ds, "jobs");
       return ds;
   }
 
   public Job GetJobInfo(int Jobid)
   {
       SqlConnection cn = new SqlConnection("data source=mytoy; user id=sa;
                                             database=pubs");
       cn.Open();
       string sqlstat = "select * from jobs where job_id=" + Jobid;
       SqlCommand cmd = new SqlCommand(sqlstat, cn);
       SqlDataReader dr=cmd.ExecuteReader();
       Job jobObj=new Job();
       if(dr.Read())
       {
           jobObj.Description=dr["job_desc"].ToString();
           jobObj.MinLevel=Convert.ToInt32(dr["min_lvl"].ToString();
             jobObj.MaxLevel=Convert.ToInt32(dr["max_lvl"].ToString();
       }
       else
             jobObj.Description="-1";
       return jobObj;
    }
 
    #endregion
}

这段代码没什么好讨论的,它执行从数据库检索所需数据的任务。为清楚起见,所有连接字符串和语句都硬编码在这里,但您可以以标准方式进行。这里要注意的主要事情是,这两个方法从数据库获取数据并以复杂类型返回。

至此,我们的服务就准备好了。要将其打包成程序集,我们应该构建项目。成功构建后,我们将在项目目录的 bin 文件夹中获得一个 dll 文件,即 WCFJobsLibrary.dll

测试 WCF 服务

库构建完成后,运行该程序集。这将把我们的服务托管在测试环境中。任务栏中会出现一个新图标,显示服务已托管。

还会打开一个测试客户端窗口,显示服务已成功添加的状态信息。

服务客户端包含所使用的地址和绑定信息。它甚至包含可供消费的方法信息。在测试环境中,某些方法可能不受支持,这是因为某些复杂类型不受测试客户端支持。对于任何不受支持的方法,该方法名称旁边会显示一个感叹号,如上图所示的 GetJobs() 方法。

尽管如此,我们可以测试另一个方法 GetJobInfo()。只需在测试客户端窗口中单击该服务方法,它将在窗口右侧显示服务信息。此信息分为请求和响应两部分。在请求中,列出了参数名称、它们的值和类型。类似地,在响应中给出了返回类型的信息。当我们在请求中输入参数值并按下调用按钮时,它将在响应中给出结果,如下图所示。

但如果测试客户端窗口关闭,服务也会从主机环境中移除。为了使服务独立于此测试客户端,我们必须从项目中分离测试客户端。为此,请转到 WCFJobsLibrary 属性并移动到调试选项卡。在这里,我们将在命令行参数框中找到测试客户端名称。从该框中移除客户端名称将把客户端从服务中分离。

消费 WCF 服务

由于我们已成功测试服务,下一步是消费它。为此,我们创建一个 Windows 应用程序作为客户端。

i. 设计窗体

新建 > 项目 > Windows 窗体应用程序,并将其命名为 ConsumeJobs。

我们按下图所示设计窗体,其中包含一个文本框用于提供 JobId,一个按钮用于调用服务,以及几个文本框用于显示结果。类似地,我们使用一个 DataGridView 和另一个按钮来显示 Jobs 表中的所有记录。

ii. 创建代理

为了与服务通信,客户端应该有一个代理。

为了创建代理,客户端需要 WCF 服务的引用。

要添加引用,请转到解决方案资源管理器,右键单击项目(客户端应用程序)并选择“添加服务引用”。会打开一个窗口,我们需要在其中提供服务地址。我们可以从 WCF 服务库的 app.config 文件中的基地址复制此地址。如果客户端和服务器之间的通信是通过 http,则可以直接使用该地址;否则,如果是通过任何其他通道,则需要在地址末尾添加 '/mex'。

例如,如果基地址是

https://:8731/Design_Time_Addresses/WCFJobsLibrary/Jobs/

那么对于 http 之外的任何通道,我们必须在末尾添加 '/mex',像这样

https://:8731/Design_Time_Addresses/WCFJobsLibrary/Jobs/mex

提供地址并单击“Go”按钮后,将找到该地址上可用的服务,并显示这些服务上的接口列表。请记住,此步骤只有在服务运行的情况下才能成功。

选择服务并为命名空间提供一个有意义的名称(或者您也可以使用默认名称)。在我们的例子中,我们将名称提供为 JobsService。单击“确定”按钮后,将在客户端创建一个代理,其名称与服务上的原始类相似,但后缀为“Client”。在 WCF 服务库中,我们的类名是 Jobs,在客户端,代理名称将是 JobsClient。

iii. 编写代码以消费服务

代理类创建后,我们可以继续在客户端 Windows 窗体的按钮点击事件中编写代码。

private void btnViewDetails_Click(object sender, EventArgs e)
{
    //an instance of the proxy class
    JobsService.JobsClient obj = new ConsumeJobs.JobsService.JobsClient();
 
    //Reading the result into complex type object (Job type)
    JobsService.Job jobObj = obj.GetJobInfo(int.Parse(txtJobId.Text));
 
    //Displaying result in text boxes
    txtDescription.Text = jobObj.Description;
    txtMinValue.Text = jobObj.MinLevel.ToString();
    txtMaxValue.Text = jobObj.MaxLevel.ToString();
           
 }
 
 private void btnShow_Click(object sender, EventArgs e)
 {
    JobsService.JobsClient obj = new ConsumeJobs.JobsService.JobsClient();
    DataSet ds = obj.GetJobs();
    dataGridView1.DataSource = ds.Tables[0];
 }

我们从数据库中获取结果,该结果由服务程序检索,并由客户端的代理类访问。

到目前为止,我们已经了解了在 Visual Studio 提供的宿主环境中托管服务时如何使用服务。现在我们将了解如何向 Windows 注册此服务,使其作为 Windows 服务运行。

创建 Windows 服务以宿主服务 DLL

为此,我们首先必须创建一个 Windows 服务。这可以通过 Visual Studio 使用 Windows 服务模板完成,该模板可以在 Windows 项目类型下找到。

新建 > 项目 > Windows 服务 > 命名为 ABCService

我们必须在此服务中添加 WCF DLL 的引用。为此,在解决方案资源管理器中右键单击项目,然后选择“添加引用”。要在引用中添加 dll,请在出现的窗口中选择“浏览”选项卡,然后导航到 WCF 服务库所在的文件夹。在该位置,可以在 bin->debug 文件夹中找到 dll。添加此 dll 后,它将被导入到 Windows 服务应用程序中。

同样,我们需要 System.ServiceModel 命名空间的引用,因为它在 Windows 服务中默认不可用。要转到服务类的代码窗口,请转到默认创建的服务的设计视图,然后单击“单击此处切换到代码视图”链接。此链接将带您进入代码视图。在此处导入 System.ServiceModel 命名空间,因为托管我们的 WCF 服务需要它。默认的服务类 Service1.cs 提供了两个事件——OnStart 和 OnStop。我们可以在这两个事件中分别编写服务启动和停止时要执行的代码。

该类的代码如下所示

namespace ABCService
{
    public partial class Service1 : ServiceBase
    {
        ServiceHost sHost;
        public Service1()
        {
            InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
            sHost = new ServiceHost(typeof(WCFJobsLibrary.Jobs));
            sHost.Open();
        }
 
        protected override void OnStop()
        {
            sHost.Close();
        }
    }
}

我们只是在 OnStart 事件中为我们的 WCF 库创建一个服务宿主并打开它。当 Windows 服务关闭时,它应该关闭服务宿主,这在 OnStop 事件中指定。

仅仅编写这些代码是不够的,因为我们还需要进行配置。我们需要进行配置,以便服务能够按需正常托管和运行。这些配置需要在 Windows 服务应用程序的 App.Config 文件中指定。由于此文件默认不可用,我们必须通过将其添加为新项并选择应用程序配置文件模板来创建它。

创建的 App.Config 文件具有空配置,即在 <configuration> 标签下未指定任何配置。我们无需繁琐地编写所有这些配置,只需将它们从服务库的 App.Config 复制过来即可。复制 <system.serviceModel> 下的所有内容,然后将其粘贴到 Windows 服务的 App.Config 中。

现在构建服务。这将完成我们将 WCF 服务作为 Windows 服务托管的步骤。现在只剩下将其注册到 Windows 操作系统了。

将服务注册到 Windows 操作系统

  1. 转到 Windows 服务的设​​计视图,右键单击并单击“添加安装程序”选项。
  2. 单击此选项后,我们将得到两个进程 – ServiceProcessInstallerServiceInstaller

    点击 ServiceProcessInstaller 并将其帐户属性设置为本地系统。

    现在,单击 ServiceInstaller 并提供一个显示名称,例如 ABCNITJobsService。同时选择启动类型——手动、自动或禁用。在我们的例子中,我们可以选择手动或自动。

  3. 现在再次构建服务。这将创建一个名为 ABCService(在我们的案例中)的可执行文件,该文件位于项目目录中。

    此 exe 文件应注册到 Windows 操作系统,使其作为服务运行。

  4. 复制此 exe 文件位置的路径,并从命令提示符中打开包含该文件的文件夹。

    在该路径中输入命令 InstallUtil ABCService.exe,这会将服务注册到 Windows 操作系统。

    一旦注册到 Windows,我们就可以在服务列表中看到它。

    (控制面板 > 管理工具 > 服务)

    如果它没有自动启动,我们可以通过单击启动链接手动启动它。

  5. 当服务启动时,我们可以通过在命令提示符中使用 netstat –a 命令来判断它是否正在监听。

由于服务作为 Windows 服务运行,因此我们的 WCF 服务库不需要运行。我们可以关闭它,并从 Windows 环境中使用该服务。

注意:如果使用 Vista 操作系统,则应以管理员模式运行以托管服务。

© . All rights reserved.