Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Windows服务设计帮助_C#_.net_Windows Services - Fatal编程技术网

C# Windows服务设计帮助

C# Windows服务设计帮助,c#,.net,windows-services,C#,.net,Windows Services,我正在设计我正在计划构建的应用程序的体系结构,需要一些关于实现下面描述的特定windows服务组件的最佳方法的建议。我将使用.NET4.0构建该服务,以便能够利用新的并行和任务API,我还研究了使用MSMQ服务,但我不确定这是否适合我希望实现的目标 解释我的用例最简单的方法是,用户可以为他们需要完成的任务创建许多不同类型的提醒,这些提醒是使用ASP.NET MVC 2中内置的基于web的应用程序创建的。这些提醒可以是各种类型的,例如电子邮件和短信,当然必须在指定的到期时间发送。提醒可以一直更改到

我正在设计我正在计划构建的应用程序的体系结构,需要一些关于实现下面描述的特定windows服务组件的最佳方法的建议。我将使用.NET4.0构建该服务,以便能够利用新的并行和任务API,我还研究了使用MSMQ服务,但我不确定这是否适合我希望实现的目标

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

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

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

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

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

提前感谢,,
Wayne

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

NB:您应该将服务项目输出类型设置为
控制台应用程序
,这仍然可以作为正常服务正常工作

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);
      }
    }
  }
}
services.Start()
方法将检测服务是否作为交互式应用程序运行,并手动调用所有已注册服务的OnStart方法,一旦启动,主线程将进入睡眠状态。要停止服务,只需按“Ctrl+C”,这将导致通过调用服务的OnStop方法停止服务

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

监视和启动/停止服务

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

Start a service
net start <service name>

Stop a service
net stop <service name>
启动服务
净启动
停止服务
净止点
对于从.NET管理服务,您可以使用

//停止服务
System.ServiceProcess.ServiceController sc=新建
System.ServiceProcess.ServiceController(“”);
sc.停止();
对于与服务的一般通信,而不是通过提供的内容,我建议您作为服务的一部分承载WCF服务,然后您可以使用该服务与服务通信,以查询特定于您的服务的内部详细信息

处理调度

老实说,我对回答这方面的问题犹豫不决,因为有太多的方法,每种方法都有利弊。所以我会给你们一些高层次的选择供你们考虑。你可能已经仔细考虑过了,但这里有几件事是我脑子里想不出来的

如果您使用SQL Server存储通知。

有一个SP,您可以调用它来检索到期的提醒,然后处理结果以适当地发出提醒

使用此SP,您有一些选择

  • 定期从您的服务中致电SP并处理提醒
  • 具有一个SQL作业,该作业定期运行SP并向SP添加提醒。然后,您的服务可以订阅队列并处理队列中出现的提醒。这种方法的优点是,您可以扩展到多个处理提醒通知生成的服务器,而无需任何特殊编码,只需添加另一个运行您的服务的服务器,消息将自动在两个服务器之间分发
  • 如果未使用SQL Server存储提醒

    您仍然可以使用与SQLServer类似的方法。当然是温多
    Start a service
    net start <service name>
    
    Stop a service
    net stop <service name>
    
    // Stop a service
    System.ServiceProcess.ServiceController sc = new
      System.ServiceProcess.ServiceController("<service name>");
    sc.Stop();