Nat*_*ley 14 .net c# windows-services .net-3.5
我需要在我的服务器上的Windows服务中运行一堆可插入的进程,并希望创建一个用户界面,允许我与服务使用的每个插件进行交互.
用户界面和长时间运行的Windows服务之间通信的最常用方法是什么?我正在考虑提供一个中间位置,如数据库,并使用某种消息队列向服务发出命令.你们有没有实施过这样的方法,或者其他一些优秀的方法?你在这个过程中遇到了什么问题?
Mat*_*vis 37
不要使用远程处理! 虽然它肯定会有效,但微软表示远程处理是一项传统技术,所有新的分布式应用程序都应该使用WCF开发.有关详细信息,请参见此处
Windows Communication Foundation(WCF)是两个.NET进程相互通信的推荐方法.WCF提供了一个统一的编程模型,通过抽象与特定通信机制相关的许多复杂性,例如套接字,管道等,大大简化了分布式开发.
鉴于您的情况的详细信息,我建议将每个Windows服务插件作为WCF服务.对于每个WCF服务,即插件,定义它需要向UI公开的接口.界面只是一个装有ServiceContract属性的C#界面.此接口包含方法,每个方法都使用OperationContract属性进行装饰,您的UI将使用该方法与WCF服务(插件)进行通信.这些方法可以接受并返回任何可序列化的.NET类型,或者通常是您自己的自定义类型.要在WCF中使用自定义类型,只需使用DataContract属性修饰它们,并使用DataMember属性标记要通过WCF交换的成员.
一旦定义了ServiceContract接口,就定义一个实现该接口的类.每个OperationContract方法都会执行它需要做的任何事情,例如,与数据库交互,计算某些值等.一旦完成此操作,您就已经有效地定义了WCF服务.这是一个简短但有效的例子:
using System.ServiceModel;
namespace AdditionServiceNamespace
{
[DataContract]
public class Complex
{
[DataMember]
public int real;
[DataMember]
public int imag;
}
[ServiceContract]
public interface IAdditionService
{
[OperationContract]
Complex Add(Complex c1, Complex c2);
}
public class AdditionService : IAdditionService
{
public Complex Add(Complex c1, Complex c2)
{
Complex result = new Complex();
result.real = c1.real + c2.real;
result.imag = c1.imag + c2.imag;
return result;
}
}
}
Run Code Online (Sandbox Code Playgroud)
下一步是托管此WCF服务,以便UI可以使用它.由于您将使用OnStart()Windows服务,因此在Windows服务的回调中可以轻松地托管您的WCF 服务,如下所示:
using System.ServiceModel;
using System.ServiceProcess;
using AdditionServiceNamespace;
namespace WindowsServiceNamespace
{
public class WindowsService : ServiceBase
{
static void Main()
{
ServiceBase[] ServicesToRun = new ServiceBase[]
{ new WindowsService() };
ServiceBase.Run(ServicesToRun);
}
private ServiceHost _host;
public WindowsService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
_host = new ServiceHost(typeof(AdditionService));
_host.Open();
}
protected override void OnStop()
{
try
{
if (_host.State != CommunicationState.Closed)
{
_host.Close();
}
}
catch
{
// handle exception somehow...log to event viewer, for example
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
剩下要做的唯一事情是为Windows服务定义一个app.config文件,该文件将配置WCF服务的某些必需方面.这似乎有点矫枉过正,但记住两件事.首先,当您向项目添加WCF服务类时,Visual Studio会自动为您提供基本的app.config文件.其次,app.config文件为您提供了对WCF服务的巨大控制,而无需更改代码.这是上面示例的配套app.config文件:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<service name="AdditionServiceNamespace.MyAdditionService"
behaviorConfiguration="default">
<endpoint name="AdditionService"
address="net.pipe://localhost/AdditionService"
binding="netNamedPipeBinding"
contract="AdditionServiceNamespace.IAdditionService" />
<endpoint address="net.pipe://localhost/AdditionService/MEX"
binding="mexNamedPipeBinding"
contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="default">
<serviceMetadata />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
Run Code Online (Sandbox Code Playgroud)
请注意,AdditionService WCF服务有两个端点.元数据交换端点用于客户端生成代码,因此暂时忽略它.第一个端点配置为使用NetNamedPipeBinding.如果您的UI和Windows服务将在同一台机器上运行,那么这是使用的绑定(有关选择要使用的适当绑定的流程图,请参见此处).但是,如果您的UI和Windows服务将在不同的计算机上运行,则无法使用此绑定.在这种情况下,您可以使用NetTcpBinding作为替代.要将NetTcpBinding替换为NetNamedPipeBinding,您只需要更改端点的地址和绑定,如下所示:
<endpoint name="AdditionService"
address="net.tcp://<machine hostname here>/AdditionService"
binding="netTcpBinding"
contract="AdditionServiceNamespace.IAdditionService" />
Run Code Online (Sandbox Code Playgroud)
无需更改代码!进行更改,重新启动服务,您的WCF服务现在可供远程计算机使用.如果需要,您甚至可以为同一个WCF服务允许多个端点.关键是,app.config文件提供了极大的灵活性,而无需更改代码.
而已!您现在可以在Windows服务中托管WCF服务,供UI使用.
那么UI方面(即客户端)如何工作?
这就是WCF的真正力量发挥作用的地方.在开始使用WCF时,最简单的方法是利用Visual Studio的代码生成功能.确保您的Windows服务(托管AdditionService的服务)正在运行.在UI项目中,右键单击解决方案资源管理器中的项目,然后选择" 添加服务引用..."菜单选项.在" 地址"框中,键入net.pipe://localhost/AdditionService,然后单击" 转到"按钮.您应该会看到AdditionService显示在" 服务"列表中.在" 命名空间"框中,键入AdditionService并单击" 确定"按钮.
执行这些步骤将生成客户端代理和正确定义的app.config文件,这些文件将添加到UI项目中.此客户端代理成为您的客户端AdditionService API,您可以像这样使用它:
using TestConsoleApp.AdditionService;
namespace TestConsoleApp
class Program
{
static void Main(string[] args)
{
AdditionServiceClient client = new AdditionServiceClient();
Complex c1 = new Complex(), c2 = new Complex();
c1.real = 3; c1.imag = 5;
c2.real = 1; c2.imag = 7;
Complex result = client.Add(c1, c2);
}
}
}
Run Code Online (Sandbox Code Playgroud)
请注意这是多么简单.基本上,AdditionServiceClient实例化客户端代理.然后Complex创建两个对象.最后,Add()调用客户端代理上的方法,并Complex返回结果.
幕后发生的事情是Add()客户端代理的方法实际上是将两个Complex对象传递给Windows服务中托管的AdditionService WCF服务.AdditionService执行添加,然后返回结果.所有这些都发生在命名管道上,但请注意,这里根本没有命名管道专用代码! WCF已经抽象出了IAdditionService接口定义的编程模型背后的所有复杂性.
我知道这是要消化的大量信息,但我希望WCF的强大和易用性是显而易见的.当然,此示例仅触及WCF中可用的所有内容的一小部分.
但最后,WCF应该是用于在UI和Windows服务之间进行通信的机制.有关更多信息,我强烈推荐Juval Lowy 为WCF所有内容编写WCF服务的书.您还可以访问他的网站IDesign.net,获取免费的WCF代码示例.有关WCF的更多介绍,请在dnrTV上观看此免费视频.它涵盖了WCF的目的,并通过一些易于理解的示例演示了WCF编程.
| 归档时间: |
|
| 查看次数: |
10673 次 |
| 最近记录: |