如何在 Windows 服务应用程序中托管 .NET Remoting 对象






3.17/5 (15投票s)
关于如何创建 Windows 服务应用程序并将 Remoting 对象托管到服务应用程序中的教程

有一段时间,我一直在从事 .NET Remoting 项目,但每次我总是创建一个控制台应用程序来运行作为远程服务器并托管 Remoting 对象。在实际应用程序中,这绝对是行不通的。大多数情况下,您需要让您的远程对象托管在一个始终运行并且不需要任何用户干预的服务器上,就像控制台应用程序那样。您有几种托管选项,例如:Web服务器、托管可执行文件(例如控制台应用程序)或组件服务。
本文不是关于 .NET Remoting 是什么。您可以在 .NET 文档或我的另一篇文章 .NET Remoting Spied On 中阅读相关内容。本文结合了如何编写 Windows 服务应用程序(以前称为 NT Service)以及如何在该服务中托管您的 Remoting 对象。
如何创建 Windows 服务应用程序
.NET 在线文档有一个关于“创建和配置 Windows 服务应用程序”的完整章节。本章包含关于引言、体系结构、安全问题、安装/卸载问题的非常有用的信息。因此,如果我开始讨论这些内容,那将是浪费时间和空间。但有些事情在该文档中并不十分清楚。所以,我将尝试解释这些内容,并展示 VS.NET 中有哪些工具可用于编写 Windows 服务应用程序。
在 VS.NET 中,如果您点击“新建/项目”,您会发现在“Visual C# 项目”类型下,有一个名为“Windows 服务”的。如果您想编写服务应用程序,这就是您要选择的类型。这并不意味着您只能使用 C# 编写 Windows 服务应用程序。您可以用任何语言编写。本文将仅专注于使用 C#。

.NET Framework 提供了 System.ServiceProcess
命名空间,其中包含编写和安装服务应用程序所需的所有类。每个 Windows 服务应用程序类都必须派生自 ServiceProcess.SystemBase
。对于本文的演示项目,定义如下。
public class PS_RemoteSrvrSrvc : System.ServiceProcess.ServiceBase
默认情况下,向导会为您提供服务应用程序的最小框架。它提供了 OnStart
和 OnStop
方法,它们是服务应用程序的基本组成部分。当服务在系统启动时自动启动,或者从服务控制管理器手动启动时,就会调用 OnStart
方法。当服务停止时,就会调用 OnStop
。您的服务应用程序还可以实现其他方法,但这取决于应用程序的体系结构和设置的选项。例如,您可以实现 OnPause
、OnContinue
、OnShutdown
方法。但如果您的服务应用程序不支持暂停和继续,则无需实现这些方法。您可以通过设置 ServiceBase
类支持的属性值来设置应用程序的特性,我强烈建议您查阅文档中的这些属性。由于调试 Windows 服务应用程序并非易事,因此设置 EventLog
属性非常重要。我建议在项目初期广泛使用 EventLog
,以便您可以将跟踪消息记录到事件日志中。
如何安装 Windows 服务应用程序
文档中关于“创建和配置 Windows 服务应用程序”的部分提到,您需要添加安装程序组件才能在系统上安装服务,以便将其添加到服务控制管理器 (SCM)。.NET Framework 文档在“配置和部署您的 .NET 应用程序”中涵盖了此主题。让我们看看为我们的 Windows 服务应用程序添加安装程序组件需要做什么。
.NET Framework 提供了 installutil
。在您的服务应用程序的可执行文件所在的文件夹中,运行此实用程序来安装或卸载应用程序。以下是安装和卸载的语法。
installutil myService.exe
installutil /u myService
当 installutil
实用程序运行时,它会查找一个属性设置为 true
的 RunInstallerAttribute
属性的类。因此,为应用程序添加服务安装程序的第一步是添加一个具有此属性的类。在演示项目中,我已将 PS_ServiceInstall
派生自 System.Configuration.Install.Installer
添加到 PS_RemoteServer
命名空间,并设置了 RunInstallerAttribute
属性。
[RunInstallerAttribute(true)]
public class PS_ServiceInstall : Installer
{
.
.
}
在此安装程序类的构造函数中,您可以添加安装逻辑。System.ServiceProcess.ServiceInstaller
和 System.ServiceProcess.ServiceProcessInstaller
类提供了添加 Service
和 ServiceProcess
安装程序组件的功能。请遵循以下简单步骤为您的 Windows 服务应用程序添加一个最基本的安装程序。
- 添加一个派生自
System.Configuration.Install.Installer
类的类。 - 将此类的
RunInstallerAttribute
属性设置为True
。 - 在构造函数中,为每个服务应用程序创建一个
ServiceProcessInstaller
的新实例,并为应用程序中的每个服务创建一个ServiceInstaller
类的新实例。 - 将这些安装程序对象添加到
Installer
类的InstallerCollection
中。
ServiceInstaller
和 ServiceProcessInstaller
有许多属性可用于设置服务的属性。ServiceInstaller
具有以下属性:
DisplayName
:设置友好的名称,用于向用户标识服务。ServiceName
:设置系统用于标识服务的名称。ServicesDependedOn
:指定此服务运行必须先运行的服务。StartType
:设置服务将如何以及何时启动。此属性的可能值为Automatic
、Manual
或Disabled
,表示服务将在系统启动时自动启动,用户将从 SCM 手动启动服务,或者服务将处于禁用模式启动。
ServiceProcessInstaller
具有一些与服务应用程序的安全问题相关的非常重要的属性。
RunUnderSystemAccount
:指定服务是将在计算机的系统帐户下运行,还是将在特定用户的帐户下运行。如果此属性设置为true
,则服务应用程序将在系统帐户下启动。这意味着它可以在系统重新启动时启动,而无需任何用户登录到系统。但如果此属性设置为false
,则在安装过程中,用户将看到一个登录对话框,以输入用于身份验证的用户名和密码。UserName
:设置服务将在其下运行的用户名。仅当RunUnderSystemAccount
属性设置为false
时才需要。Password
:设置与服务将在其下运行的用户帐户相关的密码。与UserName
属性一样,仅当RunUnderSystemAccount
属性设置为false
时才需要。HelpText
:设置在服务安装选项中显示的帮助文本。
与这两个类关联的方法会在安装实用程序在安装和卸载过程中调用。您无需在 Installer
类中显式调用这些方法中的任何一个。
public PS_ServiceInstall()
{
this.m_ServiceInstaller = new ServiceInstaller ();
this.m_ServiceInstaller.StartType = ServiceStart.Manual;
this.m_ServiceInstaller.ServiceName = "RemoteSystemInfo";
this.m_ServiceInstaller.DisplayName = "Remote System Info";
Installers.Add (this.m_ServiceInstaller);
this.m_ProcessInstaller = new ServiceProcessInstaller ();
this.m_ProcessInstaller.RunUnderSystemAccount = true;
Installers.Add (this.m_ProcessInstaller);
}
如何托管 .NET Remoting 对象
要托管 .NET Remoting 对象在服务器上,您需要执行以下操作:
- 创建并使用
ChannelServices
注册传输通道(用于封送的对象)。例如,您可以使用 TCP、HTTP 或 SMTP 通道。 - 使用
RemotingServices
注册您的对象。
在您可以访问远程对象之前,服务器必须正在运行,并且已完成上述任务。因此,最佳的执行地点是您服务的 OnStart
方法。
protected override void OnStart(string[] args)
{
EventLog.WriteEntry("RemoteSystemInfo: OnStart -- Entering");
TCPChannel tcpChannel = new TCPChannel (8085);
EventLog.WriteEntry("RemoteSystemInfo: OnStart -- Created Channel");
ChannelServices.RegisterChannel (tcpChannel);
EventLog.WriteEntry("RemoteSystemInfo:" +
" OnStart -- Registered Channel");
RemotingServices.RegisterWellKnownType ("PS_RemoteSrvr",
"PS_RemoteSrvr.PS_SystemInfoSrvr",
"PS_SystemInfoSrvr",
WellKnownObjectMode.SingleCall);
EventLog.WriteEntry("RemoteSystemInfo:" +
" OnStart -- RegisterWellKnownType Done");
EventLog.WriteEntry ("RemoteSystemInfo: OnStart -- Leaving");
}
上面的代码是托管 Windows 服务应用程序中简单的 .NET 远程对象所需的一切。根据 Remoting 对象的性质以及您配置它的方法,您可能需要一些额外的步骤或程序。但关键是您应该在服务的 OnStart
方法中完成所有任务。
如何使用演示项目
本文配套的演示项目并没有做什么花哨的事情。我编写了一个获取操作系统信息的实用类。我已将 GetOSInfo
方法添加到我的 Remoting 对象 PS_SystemInfoSrvr
中。此方法创建一个 PS_OSInfo
对象的实例(该对象在 PS_SystemInfoUtil
项目中实现),并将其返回给客户端。然后,客户端可以调用 PS_OSInfo
类实现的类的方法和属性。我包含了客户端可以用来配置远程服务器访问的配置文件 PS_SystemInfo.cfg。客户端应用程序在 PS_RemoteSystemInfo
项目中实现。以下代码显示了客户端应用程序如何配置和访问 Remoting 对象。
private void ConfigureRemoteServer ()
{
try
{
RemotingServices.ConfigureRemoting ("PS_RemoteSystemInfo.cfg");
this.m_RemoteInfoSrvr = (PS_SystemInfoSrvr)
Activator.GetObject (typeof (PS_SystemInfoSrvr),
"tcp://sultan:8085/PS_SystemInfoSrvr");
PS_SystemOS sysOS = this.m_RemoteInfoSrvr.GetOSInfo ();
string strSystemDir = sysOS.SystemFolder;
string strOS = sysOS.OS;
string strVersion = sysOS.ServicePack;
}
catch (RemotingException e)
{
Trace.WriteLine (e.Message);
}
}
我使用 TCP 作为传输机制,并且“sultan”是我的远程服务器,托管 Remoting 对象的服务应用程序正在那里运行。对于您的应用程序,您需要在配置文件或 GetObject
调用中提供服务器的名称或 IP 地址。如果您想在同一台计算机上运行客户端和服务器应用程序,只需使用“localhost”作为服务器名称即可。
要安装服务应用程序,请将 PS_RemoteSrvr.exe 和 PS_SystemInfoUtil.dll 复制到您要安装它的文件夹。在命令行中,在该文件夹中运行 installutil
实用程序。然后打开服务控制管理器。在那里您将看到服务应用程序。它尚未启动,因为我将启动类型设置为 Manual
。右键单击它并选择“启动”。现在您的 Remoting 对象已托管在服务应用程序中。只要服务应用程序正在运行,您的客户端应用程序就可以访问它。
在客户端计算机上,您不需要运行 installutil
实用程序。只需运行 PS_RemoteSystemInfo.exe。在 ConfigureRemoteServer
方法中设置一个断点,然后您就可以看到 Remoting 正在运行。
我是否需要 VS.NET 来编写服务应用程序
您绝对可以在没有 VS.NET 的情况下编写 Windows 服务应用程序。您只需要创建一个派生自 System.ServiceProcess.ServiceBase
类的类。使用 VS.NET 的唯一好处是它会创建一个服务应用程序的框架。
项目需要添加哪些附加引用
Remoting 在 Service.Runtime.Remoting
中实现,因此您的服务应用程序和客户端应用程序都需要添加该引用。
历史
- 2001 年 5 月 13 日:初始发布