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

ASP.NET Core使用TopShelf部署Windows服务

程序员文章站 2022-03-26 14:21:28
asp.net core很大的方便了跨平台的开发者,linux的开发者可以使用apache和nginx来做反向代理,windows上可以用IIS进行反向代理。 反向代理可以提供很多特性,固然很好。但是还有复杂性,我们也可以使用windows service来直接启动kestrel。 asp.net ......

asp.net core很大的方便了跨平台的开发者,linux的开发者可以使用apache和nginx来做反向代理,windows上可以用iis进行反向代理。
反向代理可以提供很多特性,固然很好。但是还有复杂性,我们也可以使用windows service来直接启动kestrel。

asp.net core官方网站提供了一种基于windows服务部署的方法:在 windows 服务中托管 asp.net core
这种方式需要修改代码,然后部署的时候,使用命令行创建、安装服务,然后再启动。

感觉还是不够爽快,我们可以使用topshelf改造一下。

topshelf

topshelf可以很便捷地将一个windows console程序改造成windows service,只需要稍微修改一下代码结构,然后通过nuget包就可以简单操作了。安装与部署也是极其方便,而且,topshelf在调试的时候,直接是作为console程序,极其便于调试。

topshelf项目地址:

步骤

首先引用nuget包:

install-package topshelf

然后改造一下program.cs

public class program
{
    public static void main(string[] args)
    {
        var rc = hostfactory.run(x =>                                   //1
        {
            x.service<mainservice>(s =>                                   //2
            {
                s.constructusing(name => new mainservice(args));                //3
                s.whenstarted(tc => tc.start());                         //4
                s.whenstopped(tc => tc.stop());                          //5
            });
            x.runaslocalsystem();                                       //6

            x.setdescription("jwtapiservice");                   //7
            x.setdisplayname("jwtapiservice");                                  //8
            x.setservicename("jwtapiservice");                                  //9
        });                                                             //10

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

        //createwebhostbuilder(args).build().runasservice();
    }
}

这里指定服务程序的内容在mainservice这个类里面,并通过代码指定了服务的名称和描述等行为。以前的启动createwebhostbuilder方法转移到了这个类中:

public class mainservice
{
    private string[] args;
    public mainservice(string[] vs)
    {
        args = vs;
    }
    public void start()
    {
        var isservice = !(debugger.isattached || args.contains("--console"));
        var builder = createwebhostbuilder(args.where(arg => arg != "--console").toarray());

        if (isservice)
        {
            var pathtoexe = process.getcurrentprocess().mainmodule.filename;
            var pathtocontentroot = path.getdirectoryname(pathtoexe);
            builder.usecontentroot(pathtocontentroot);
        }

        var host = builder.build();
        host.run();
    }

    public void stop()
    {
    }

    public static iwebhostbuilder createwebhostbuilder(string[] args)
    {
        var config = new configurationbuilder()
// .setbasepath(directory.getcurrentdirectory())
.addjsonfile("config.json", optional: true, reloadonchange: true)
.build();

        return webhost.createdefaultbuilder(args)
                .usekestrel()
                .useconfiguration(config)
                .usestartup<startup>();
    }
}

start方法指定服务启动时,服务的执行不需要依赖于microsoft.aspnetcore.hosting.windowsservices这个nuget包。
另外contentroot需要注意,使用windows服务进行提供服务,getcurrentdirectory的根目录是system32,而不是asp.net core的dll的目录。使用appsettings.json时,可能会引起问题,最好使用自定义的程序配置(例如这里通过config.json进行设置)。

运行

  • 确定是否存在 windows 运行时标识符 (rid),或将其添加到包含目标框架的 中:
<propertygroup>
   <targetframework>netcoreapp2.1</targetframework>
   <runtimeidentifier>win7-x64</runtimeidentifier>
</propertygroup>
  • 发布,最终可以得到可执行程序。直接双击运行,程序就可以以console的形式启动,方便调试。
  • 命令行运行xxxx.exe install就而可以安装服务,然后服务就可以自动启动。
  • 命令行运行xxxx.exe uninstall就可以卸载服务。整个过程不需要新建用户与策略。

后记

吐槽:直接使用topshelf,调试windows服务的过程变得不那么痛苦了,想起附加调试器的过程,简直了。
p.s. 需要最新版本的topshelf才可以支持asp.net core的服务部署。