欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

控制台程序秒变Windows服务(Topshelf)

程序员文章站 2022-06-04 11:51:31
项目中有些时候需要写服务,一般我们都是先创建控制台程序,测试,运行,成功之后再创建windows服务程序,这样好麻烦啊,有没有简单的控制台程序直接变成Widnows服务,经过查找,找到了Topshelf。Topshelf是一个托管使用.NET框架编写的服务的框架,简化了服务的创建,允许开发人员创建一 ......

项目中有些时候需要写服务,一般我们都是先创建控制台程序,测试,运行,成功之后再创建windows服务程序,这样好麻烦啊,有没有简单的控制台程序直接变成widnows服务,经过查找,找到了topshelf。topshelf是一个托管使用.net框架编写的服务的框架,简化了服务的创建,允许开发人员创建一个简单的控制台应用程序,可以使用topshelf作为服务安装。

topshelf介绍

topshelf是一个托管使用.net框架编写的服务的框架。简化了服务的创建,允许开发人员创建一个简单的控制台应用程序,可以使用topshelf作为服务安装。原因很简单:调试控制台应用程序比使用服务要容易得多。一旦应用程序经过测试并可以投入生产,topshelf便可以轻松地将应用程序作为服务进行安装。这是一个开源的项目,项目地址,nuget上可以搜到响应的库。

topshelf使用

1.创建控制台程序
2.安装topshelf,在nuget上搜下
3.安装nlog、nlog.config,目的是为了看日志,可以清楚的知道服务在运行,可以不要
nlog.config简单配置

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/nlog.xsd"
      xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"
      xsi:schemalocation="http://www.nlog-project.org/schemas/nlog.xsd nlog.xsd"
      autoreload="true"
      throwexceptions="false"
      internalloglevel="off" internallogfile="c:\temp\nlog-internal.log">

  <!-- optional, add some variables
  https://github.com/nlog/nlog/wiki/configuration-file#variables
  -->
  <variable name="myvar" value="myvalue"/>

  <!--
  see https://github.com/nlog/nlog/wiki/configuration-file
  for information on customizing logging rules and outputs.
   -->
  <targets>

    <!--
    add your targets here
    see https://github.com/nlog/nlog/wiki/targets for possible targets.
    see https://github.com/nlog/nlog/wiki/layout-renderers for the possible layout renderers.
    -->

    <!--
    write events to a file with the date in the filename.
    -->
    <target xsi:type="file" name="f" filename="${basedir}/logs/${shortdate}.log"
        layout="${longdate} ${uppercase:${level}} ${message}" />
  </targets>

  <rules>
    <!-- add your logging rules here -->

    <!--
    write all events with minimal level of debug (so debug, info, warn, error and fatal, but not trace)  to "f"
    -->
    <logger name="*" minlevel="debug" writeto="f" />
  </rules>
</nlog>

4.代码实现

class program
{
    private static readonly logger logger = logmanager.getlogger("program");
    static void main(string[] args)
    {
        logger.info($"main主程序{datetime.now}");
        var rc = hostfactory.run(x =>                         //1.启动程序
        {
            logger.info($"主程序{datetime.now}");
            x.service<towncrier>(s =>                         //2.设置服务类型
            {
                s.constructusing(name => new towncrier());    //3.创建服务实例
                s.whenstarted(tc => tc.start());              //4.启动程序
                s.whenstopped(tc => tc.stop());               //5.停止程序
            });
            x.runaslocalsystem();                             //6.本地系统运行

            x.setdescription("超级简单的windows服务");         //7.windows服务的描述
            x.setdisplayname("simplewindowsservice 服务");                        //8.windows服务的显示名称
            x.setservicename("simplewindowsservice");                        //9.windows服务的服务名称
        });

        var exitcode = (int)convert.changetype(rc, rc.gettypecode());  //11.退出程序
        environment.exitcode = exitcode;

    }
}

public class towncrier
{
    private static readonly logger logger = logmanager.getlogger("logtest");
    readonly timer _timer; //system.timers不要引用错误
    public towncrier()
    {
        _timer = new timer(1000) { autoreset = true };
        _timer.elapsed += (sender, eventargs) =>
        {
            console.writeline($"it is {datetime.now} and all is well");
            logger.info($"it is {datetime.now} and all is well");
        };
    }
    public void start() { _timer.start(); }
    public void stop() { _timer.stop(); }
}

必须有启动方法(start)和停止方法(stop)

4. 运行控制台程序,也可以是调试,效果如下

控制台程序秒变Windows服务(Topshelf)

5. 程序调试运行成功,一切ok,现在可以安装服务了,以管理员身份运行cmd找到对应路径,开始安装

安装:simplewindowsservice.exe install

控制台程序秒变Windows服务(Topshelf)

查看服务

控制台程序秒变Windows服务(Topshelf)

启动:simplewindowsservice.exe start

控制台程序秒变Windows服务(Topshelf)

控制台程序秒变Windows服务(Topshelf)

服务已经运行,查看运行情况,日志

控制台程序秒变Windows服务(Topshelf)

卸载:simplewindowsservice.exe uninstall

控制台程序秒变Windows服务(Topshelf)

控制台程序秒变Windows服务(Topshelf)

可以看到服务已经没有了

停止:simplewindowsservice.exe stop
停止之后可以再次启动,这个功能不介绍了,卸载服务的时候会调用这个方法。

topshelf的其他功能

安装动作之前:topshelf允许指定在安装服务之前执行的操作。请注意,只有在安装服务时才会执行此操作。

hostfactory.new(x =>
{
    x.beforeinstall(settings => { ... });
});

安装动作后:topshelf允许指定在安装服务后执行的操作。请注意,只有在安装服务时才会执行此操作。

hostfactory.new(x =>
{
    x.afterinstall(settings => { ... });
});

在卸载操作之前:topshelf允许指定在卸载服务之前执行的操作。请注意,只有在卸载服务时才会执行此操作。

hostfactory.new(x =>
{
    x.beforeuninstall(() => { ... });
});

卸载操作后:topshelf允许指定在卸载服务后执行的操作。请注意,只有在卸载服务时才会执行此操作。

hostfactory.new(x =>
{
    x.afteruninstall(() => { ... });
});

异常:为服务运行时抛出的异常提供回调。此回调不是处理程序,不会影响topshelf已提供的默认异常处理。它旨在提供对触发外部操作,日志记录等的抛出异常的可见性。

hostfactory.new(x =>
{
    x.onexception(ex =>
    {
        // do something with the exception
    });
});

其他的一些功能,如果需要可以查看

定时任务的服务

一般的服务都没有这么简单,一般都需要定时任务,这里的定时任务服务用到了fluentscheduler,fluentscheduler定时器介绍 ,这篇文章对fluentscheduler定时器进行了详细的介绍,这里不再介绍,只展示使用。

/// <summary>
/// 用myschedule的任务定时功能
/// </summary>
public class myjob {
    private static readonly logger logger = logmanager.getlogger("myjob");
    public myjob() { }
    public void start()
    {
        logger.info($"myschedule启动 {datetime.now}");
        jobmanager.initialize(new myschedule());
    }
    public void stop()
    {
        logger.info($"myschedule停止 {datetime.now}");
        jobmanager.stop();
    }
}

/// <summary>
/// 定时器
/// </summary>
public class myschedule : registry
{
    private static readonly logger logger = logmanager.getlogger("myschedule");
    public myschedule()
    {
        setnewsschedule();
    }

    /// <summary>
    /// 设置任务
    /// </summary>
    private void setnewsschedule()
    {
        //获取链接发送邮件
        schedule(() =>
        {
            logger.info($"myschedule运行 {datetime.now}");
        }
        ).torunnow().andevery(1000).milliseconds();
    }
}

控制台程序调用

class program
{
    private static readonly logger logger = logmanager.getlogger("program");
    static void main(string[] args)
    {
        logger.info($"main主程序{datetime.now}");
        var rc = hostfactory.run(x =>                         //1.启动程序
        {
            logger.info($"主程序{datetime.now}");
            x.service<myjob>(s =>                         //2.设置服务类型
            {
                s.constructusing(name => new myjob());    //3.创建服务实例
                s.whenstarted(tc => tc.start());              //4.启动程序
                s.whenstopped(tc => tc.stop());               //5.停止程序
            });
            x.runaslocalsystem();                             //6.本地系统运行

            x.setdescription("超级简单的windows服务");         //7.windows服务的描述
            x.setdisplayname("simplewindowsservice 服务");                        //8.windows服务的显示名称
            x.setservicename("simplewindowsservice");                        //9.windows服务的服务名称
        });
        var exitcode = (int)convert.changetype(rc, rc.gettypecode());  //11.退出程序
        environment.exitcode = exitcode;

    }
}

服务安装两步走,管理员cmd,simplewindowsservice.exe install, simplewindowsservice.exe start

总结

1. 写控制台程序

2.管理员cmd,simplewindowsservice.exe install

3.启动服务simplewindowsservice.exe start

4.卸载服务simplewindowsservice.exe uninstall