首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Windows服务设计帮助

Windows服务设计帮助
EN

Stack Overflow用户
提问于 2010-09-07 06:30:20
回答 1查看 714关注 0票数 1

我正在设计一个我计划构建的应用程序的体系结构,需要一些关于实现下面描述的特定windows服务组件的最佳方法的建议。我将使用MSMQ4.0构建服务,这样我就可以利用新的并行和任务API,我也考虑过使用.net服务,但我不确定这是否适合我希望实现的目标。

解释我的用例的最简单的方法是,用户可以为他们需要完成的任务创建许多不同类型的提醒,这些提醒是使用ASP.NET MVC2中内置的基于web的应用程序创建的。这些提醒可以是各种类型的,例如电子邮件和短信,这些提醒必须在指定的时间发送。提醒可以被更改,直到它们被发送给用户,暂停和取消一起,我猜这使得基于队列的服务,如MSMQ不合适?

我计划定期托管一个windows服务(除非有更合适的方式?)检查是否有任何到期的提醒,确定它们的类型,并将它们传递给特定的组件来处理它们并发送它们。如果发生异常,提醒将以设置的间隔排队并再次尝试,这将随着间隔的增加而继续发生,直到它们达到设置的阈值,此时它们将被丢弃并记录为失败。为了给服务增加最后一层复杂性,我希望在配置文件中指定每种类型的具体实现(这意味着我可以说,由于成本或其他原因而更改SMS服务),它们在服务启动时动态加载。任何未知或不可用类型的提醒都会自动失败,并像以前一样记录下来。

一旦提醒成功发送,它就会简单地丢弃它,但是对于我计划使用的SMS网关,它需要我调用它的API来确定消息是否成功传递,这意味着需要以设置的时间间隔额外的计时器来检查它。如果能够在服务启动时添加符合统一接口的额外提醒类型服务,而不需要更改其代码,那将是一件很好的事情。

最后,我不知道这是否应该作为一个单独的问题发布,但我想知道是否可以说构建一个控制台应用程序,它可以在任何时候启动/停止,并且在运行时可以看到windows服务当前正在做什么?

这是我在Stackoverflow上的第一个问题,尽管我已经使用这个社区有一段时间了,所以如果我做错了一些事情,我要道歉。

提前谢谢你,韦恩

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2010-09-07 06:59:48

对于你的问题的第二部分,我一直在思考这个问题,下面是我整理的一个类,它有助于创建一个既可以作为控制台应用程序运行,也可以作为Windows服务运行的服务。这是刚刚出版的,所以可能会有一些问题需要解决,并且需要一些重构。围绕反射代码。

NB:您应该将服务项目输出类型设置为Console Application,这仍然可以作为普通服务正常工作。

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using System.Reflection;
using System.ServiceProcess;
using System.Threading;

namespace DotNetWarrior.ServiceProcess
{  
  public class ServiceManager
  {
    private List<ServiceBase> _services = new List<ServiceBase>();

    public void RegisterService(ServiceBase service)
    {
      if (service == null) throw new ArgumentNullException("service");
      _services.Add(service);
    }

    public void Start(string[] args)
    {
      if (Environment.UserInteractive)
      {
        foreach (ServiceBase service in _services)
        {
          Start(service, args);
        }
        Console.CancelKeyPress += new ConsoleCancelEventHandler(Console_CancelKeyPress);
        Thread.Sleep(Timeout.Infinite);
      }
      else
      {
        ServiceBase.Run(_services.ToArray());
      }
    }    

    public void Stop()
    {
      foreach (ServiceBase service in _services)
      {
        Stop(service);
      }
    }

    private void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
    {
      Stop();
      Environment.Exit(0);
    }

    private void Start(ServiceBase service, string[] args)
    {
      try
      {
        Type serviceType = typeof(ServiceBase);       

        MethodInfo onStartMethod = serviceType.GetMethod(
          "OnStart", 
          BindingFlags.NonPublic | BindingFlags.Instance, 
          null, 
          new Type[] { typeof(string[]) }, 
          null);

        if (onStartMethod == null)
        {
          throw new Exception("Could not locate OnStart");
        }

        Console.WriteLine("Starting Service: {0}", service.ServiceName);
        onStartMethod.Invoke(service, new object[] { args });
        Console.WriteLine("Started Service: {0}", service.ServiceName);
      }
      catch (Exception ex)
      {
        Console.WriteLine("Start Service Failed: {0} - {1}", service.ServiceName, ex.Message);
      }
    }

    private void Stop(ServiceBase service)
    {
      try
      {
        Type serviceType = typeof(ServiceBase);
        MethodInfo onStopMethod = serviceType.GetMethod(
          "OnStop", 
          BindingFlags.NonPublic | BindingFlags.Instance);
        if (onStopMethod == null)
        {
          throw new Exception("Could not locate OnStart");
        }
        Console.WriteLine("Stoping Service: {0}", service.ServiceName);
        onStopMethod.Invoke(service, null);
        Console.WriteLine("Stopped Service: {0}", service.ServiceName);
      }
      catch (Exception ex)
      {
        Console.WriteLine("Stop Service Failed: {0} - {1}", service.ServiceName, ex.Message);
      }
    }
  }
}

要使用它,您可以从服务的Main入口点中提取标准代码,并将其替换为以下代码。

代码语言:javascript
复制
static void Main(string[] args)
{
  ServiceManager services = new ServiceManager();
  services.RegisterService(new Service1());

  services.Start(args);      
}

services.Start()方法将检测到服务正在作为交互式应用程序运行,并手动调用所有已注册服务的OnStart方法,一旦启动,主线程将进入睡眠状态。要停止服务,只需按'Ctrl+C`,这将导致通过调用服务的OnStop方法来停止服务。

当然,应用程序是由SCM作为服务运行的,然后一切都像正常的服务一样工作。唯一需要注意的是,该服务不应该要求以“允许服务与桌面交互”的方式运行,因为这将使该服务以交互方式运行,即使它是作为服务运行的。这是可以解决的,如果需要的话,但嘿,我只是写了代码。

监视和启动/停止服务

在命令行中,您可以使用NET.EXE启动/停止服务

代码语言:javascript
复制
Start a service
net start <service name>

Stop a service
net stop <service name>

要从.NET管理服务,可以使用System.ServiceProcess.ServiceController

代码语言:javascript
复制
// Stop a service
System.ServiceProcess.ServiceController sc = new
  System.ServiceProcess.ServiceController("<service name>");
sc.Stop();

对于与服务的常规通信,而不是通过ServiceController提供的通信,我建议您托管一个WCF服务作为您的服务的一部分,然后您可以使用它与服务通信,以查询特定于您的服务的内部详细信息。

处理调度的

老实说,我在回答这方面的问题时犹豫不决,因为有太多的方法,每种方法都有优缺点。因此,我将只提供一些高级选项供您考虑。您可能已经考虑过这一点,但这里有几件事是我想不到的

如果使用SQL Server存储通知,则为。

有一个SP,您可以调用它来检索到期的提醒,然后处理结果以相应地引发提醒。

使用此SP时,您有一些选项

SQL定期从您的服务调用SP,并处理reminders

  • Have a
  1. ,该作业会定期运行SP并向Service Broker Queue添加提醒。然后,您的服务可以订阅队列并在提醒出现在队列中时对其进行处理。这种方法的优点是,您可以横向扩展多个处理提醒通知生成的服务器,而无需任何特殊编码,只需添加另一个运行您的服务的服务器,消息将自动在这两个服务器之间分发。

如果未使用SQL Server存储提醒,则为

您仍然可以使用与SQL Server类似的方法。当然,Windows服务可以使用任何适当的方式查询数据存储并处理提醒。要实现这一点有点困难,因为您需要确保多个服务器不会处理相同的提醒等,而不是火车碰撞。

我认为这涵盖了它的要点,其他所有东西都是上面的一些变体。最终,您的决定将取决于目标卷、可靠性要求等。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3654629

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档