当前位置: 移动技术网 > IT编程>开发语言>.net > .NET Core 代码安装服务启动

.NET Core 代码安装服务启动

2019年09月22日  | 移动技术网IT编程  | 我要评论

爸爸去哪儿第三期完整版高清,香剑吟歌词,畦地令子

最近做了一些.net core的程序,有在windows下运行的 有在centos 下运行的,windows下运行的还好,对windows下还算比较熟悉了,但centos 下 每次都是找笔记支持命令

于是今天晚上就干脆把以.net core程序已服务形式启动的代码封装了下,代码 主要是便于安装。

我们写好一个程序后 然后要已服务启动 每次都是需要输入命令,对于我这种不记单词的人来说太痛苦了,

当然windows环境下命令到是很简单。

废话不说了 先给大家看下效果

centos 下的运行效果是这样的

dotnet consoleapp2.dll -i 

 

进行服务的安装

dotnet consoleapp2.dll -u

进行服务的卸载

 

 

 

 

安装完成后使用 ps x 进行进程查看 是否存在。

window 下运行效果

 

 

 安装完成,我们在到window 服务管理工具去看看

 

 

 

 

发现已经多了一个服务,说明安装成功了

 

然后再来分析代码

首先centos 下让程序以服务形式启动 我们需要做以下工作

1、写service文件

2、systemctl 启动service

service文件内容如下:

[unit]
description="服务说明"      
[service]
type=simple
guessmainpid=true
workingdirectory=//项目路径
standardoutput=journal
standarderror=journal
execstart=/usr/bin/dotnet 项目文件dll  //启动指令
restart=always

[install]
wantedby=multi-user.target

参考:

在使用systemctl 命令使其生效

systemctl enable *.service 使自启动生效
systemctl start *.service 立即启动项目服务

那么结合代码就好说了

 var servicepath = $"/etc/systemd/system/{servicename}.service";// 创建服务文件
                    system.io.file.writealltext(servicepath, $"[unit]{environment.newline}");
                    system.io.file.appendalltext(servicepath, $"description={servicedescription}{environment.newline}");// 服务描述
                    system.io.file.appendalltext(servicepath, $"[service]{environment.newline}");
                    system.io.file.appendalltext(servicepath, $"type=simple{environment.newline}");//设置进程的启动类型, 必须设为 simple, forking, oneshot, dbus, notify, idle 之一。
                    system.io.file.appendalltext(servicepath, $"guessmainpid=true{environment.newline}");
                    system.io.file.appendalltext(servicepath, $"workingdirectory={workingdirectory}{environment.newline}");
                    system.io.file.appendalltext(servicepath, $"standardoutput=journal{environment.newline}");
                    system.io.file.appendalltext(servicepath, $"standarderror=journal{environment.newline}");
                    system.io.file.appendalltext(servicepath, $"execstart=/usr/bin/dotnet {system.io.path.getfilename(filepath)}{environment.newline}");
                    system.io.file.appendalltext(servicepath, $"restart=always{environment.newline}");
                    system.io.file.appendalltext(servicepath, $"[install]{environment.newline}");
                    system.io.file.appendalltext(servicepath, $"wantedby=multi-user.target{environment.newline}");
                    console.writeline(startprocess("/usr/bin/systemctl", $"enable {servicename}.service"));
                    console.writeline(startprocess("/usr/bin/systemctl", $"start {servicename}.service"));
                    console.writeline($"unix 下安装服务完成,如果失败请手动执行以下命令完成安装:");
                    console.writeline($"systemctl enable {servicename}.service  //使自启动生效");
                    console.writeline($"systemctl start {servicename}.service  //立即启动项目服务");
                    console.writeline($"systemctl status {servicename}.service -l //查看服务状态");

这样 我们就可以安装并启动服务了,

那么windows下面 其实根据简单 ,就一个命令

sc  create  服务名称 binpath=启动文件 就可以了

当然 需要添加一个servicebase的子类,这里我搞了一个通用的

代码如下

/// <summary>
    /// windows 服务
    /// </summary>
    class winservice : servicebase
    {
        private static string winservicename;
        private static action<string[]> startrun;
        public winservice()
        {
            servicename = winservicename;
        }
        /// <summary>
        /// 启动服务
        /// </summary>
        /// <param name="args"></param>
        protected override void onstart(string[] args)
        {
            startrun(args);
        }
        public static void config(action<string[]> startrun,string servicename)
        {
            winservicename = servicename;
            startrun = startrun;
        }
    }

这里为什么是action<string[]> startrun; 了 就是因为让服务启动后 执行实际要执行的代码。

比如demo

class program
    {
        [description("这是一个测试服务")]
        [displayname("测试服务")]
        static void main(string[] args)
        {
            dotnet.install.serviceinstall.run("test", args, run);
        }
        static void run(string[] args)
        {
            httpserver httpserver = new httpserver();
            httpserver.start();
        }
    }

服务启动后是执行的run方法。

windows下的安装代码那就是

/// <summary>
        /// windows 环境下运行
        /// </summary>
        /// <param name="filepath">启动文件</param>
        /// <param name="servicename">服务名称</param>
        /// <param name="displayname">显示名称</param>
        /// <param name="servicedescription">服务说明</param>
        /// <param name="args"></param>
        /// <param name="startrun">实际运行方法</param>
        /// <returns></returns>
        static bool runwin(string filepath, string servicename,string displayname, string servicedescription, string[] args, action<string[]> startrun)
        {
            if (args.length == 1)
            {
                var workingdirectory = system.io.path.getdirectoryname(filepath);
                if (system.io.file.exists(system.io.path.changeextension(filepath, ".exe")))//判断是否存在exe ,如果存在则启动exe
                {
                    filepath = system.io.path.changeextension(filepath, ".exe");//修改后缀名为exe
                }
                else
                {
                    var dotnetpath = system.io.path.combine(environment.getfolderpath(environment.specialfolder.programfiles), "dotnet", "dotnet.exe");//查找默认软件安装目录下的dotnet.exe
                    if (system.io.file.exists(dotnetpath))
                    {
                        filepath = $"\\\"{dotnetpath}\\\" \\\"{filepath}\\\"";
                    }
                    else
                    {
                        dotnetpath = system.io.path.combine(environment.getfolderpath(environment.specialfolder.programfilesx86), "dotnet", "dotnet.exe");//为了防止有的人只装了x86位的,所以查找x86下的软件安装目录下的dotnet.exe
                        if (system.io.file.exists(dotnetpath))
                        {
                            filepath = $"\\\"{dotnetpath}\\\" \\\"{filepath}\\\"";
                        }
                        else
                        {
                            console.writeline($"系统无法定位dotnet core的安装目录。");
                            return true;
                        }
                    }
                }
                if (args[0].equals("-i", stringcomparison.ordinalignorecase))
                {
                    if (!adminrestartapp(filepath, args))
                    {
                        return true;
                    }
                    console.writeline(startprocess("sc.exe", $"create {servicename} binpath=\"{filepath}\" start=auto displayname=\"{displayname}\""));
                    console.writeline($"windows 下安装服务完成,如果失败请手动执行以下命令完成安装:");
                    console.writeline($"sc create {servicename} binpath=\"{filepath}\" start=auto displayname=\"{displayname}\" //安装服务");
                    using (var service = registry.localmachine.opensubkey($@"system\currentcontrolset\services\{servicename}", true))
                    {
                        service.setvalue("description", servicedescription);
                    }
                    return true;
                }
                else if (args[0].equals("-u", stringcomparison.ordinalignorecase))
                {
                    if (!adminrestartapp(filepath, args))
                    {
                        return true;
                    }
                    console.writeline(startprocess("sc.exe", $"delete {servicename}"));
                    console.writeline($"windows 下卸载服务完成,如果失败请手动执行以下命令完成卸载:");
                    console.writeline($"sc delete {servicename}  //卸载服务");
                    return true;
                }
            }
            winservice.config(startrun, servicename);
            using (var service = new winservice())
            {
                system.serviceprocess.servicebase.run(service);
            }
            return false;
        }

这样我们就完美了

在放上整个代码:

/**************************************************************
* copyright (c) 2019 www.hnlyf.com 版权所有(盗版必究)
*
* 作者: 李益芬(qq 12482335)
* 创建时间: 2019/09/22 22:40:15
* 文件名: 
* 描述: 
* 
* 修改历史
* 修改人:
* 时间:
* 修改说明:
*
**************************************************************/
using system;
using system.collections.generic;
using system.diagnostics;
using system.text;
using system.linq;
using system.componentmodel;
using microsoft.win32;

namespace dotnet.install
{
    /// <summary>
    /// 服务安装
    /// </summary>
    public static class serviceinstall
    {
        /// <summary>
        /// windows 环境下运行
        /// </summary>
        /// <param name="filepath">启动文件</param>
        /// <param name="servicename">服务名称</param>
        /// <param name="displayname">显示名称</param>
        /// <param name="servicedescription">服务说明</param>
        /// <param name="args"></param>
        /// <param name="startrun">实际运行方法</param>
        /// <returns></returns>
        static bool runwin(string filepath, string servicename,string displayname, string servicedescription, string[] args, action<string[]> startrun)
        {
            if (args.length == 1)
            {
                var workingdirectory = system.io.path.getdirectoryname(filepath);
                if (system.io.file.exists(system.io.path.changeextension(filepath, ".exe")))//判断是否存在exe ,如果存在则启动exe
                {
                    filepath = system.io.path.changeextension(filepath, ".exe");//修改后缀名为exe
                }
                else
                {
                    var dotnetpath = system.io.path.combine(environment.getfolderpath(environment.specialfolder.programfiles), "dotnet", "dotnet.exe");//查找默认软件安装目录下的dotnet.exe
                    if (system.io.file.exists(dotnetpath))
                    {
                        filepath = $"\\\"{dotnetpath}\\\" \\\"{filepath}\\\"";
                    }
                    else
                    {
                        dotnetpath = system.io.path.combine(environment.getfolderpath(environment.specialfolder.programfilesx86), "dotnet", "dotnet.exe");//为了防止有的人只装了x86位的,所以查找x86下的软件安装目录下的dotnet.exe
                        if (system.io.file.exists(dotnetpath))
                        {
                            filepath = $"\\\"{dotnetpath}\\\" \\\"{filepath}\\\"";
                        }
                        else
                        {
                            console.writeline($"系统无法定位dotnet core的安装目录。");
                            return true;
                        }
                    }
                }
                if (args[0].equals("-i", stringcomparison.ordinalignorecase))
                {
                    if (!adminrestartapp(filepath, args))
                    {
                        return true;
                    }
                    console.writeline(startprocess("sc.exe", $"create {servicename} binpath=\"{filepath}\" start=auto displayname=\"{displayname}\""));
                    console.writeline($"windows 下安装服务完成,如果失败请手动执行以下命令完成安装:");
                    console.writeline($"sc create {servicename} binpath=\"{filepath}\" start=auto displayname=\"{displayname}\" //安装服务");
                    using (var service = registry.localmachine.opensubkey($@"system\currentcontrolset\services\{servicename}", true))
                    {
                        service.setvalue("description", servicedescription);
                    }
                    return true;
                }
                else if (args[0].equals("-u", stringcomparison.ordinalignorecase))
                {
                    if (!adminrestartapp(filepath, args))
                    {
                        return true;
                    }
                    console.writeline(startprocess("sc.exe", $"delete {servicename}"));
                    console.writeline($"windows 下卸载服务完成,如果失败请手动执行以下命令完成卸载:");
                    console.writeline($"sc delete {servicename}  //卸载服务");
                    return true;
                }
            }
            winservice.config(startrun, servicename);
            using (var service = new winservice())
            {
                system.serviceprocess.servicebase.run(service);
            }
            return false;
        }
        /// <summary>
        /// unix环境下运行
        /// </summary>
        /// <param name="filepath"></param>
        /// <param name="servicename"></param>
        /// <param name="servicedescription"></param>
        /// <param name="args"></param>
        /// <param name="startrun"></param>
        /// <returns></returns>
        static bool rununix(string filepath, string servicename, string servicedescription, string[] args, action<string[]> startrun)
        {
            var workingdirectory = system.io.path.getdirectoryname(filepath);
            if (args.length == 1)
            {
                if (args[0].equals("-i", stringcomparison.ordinalignorecase))
                {
                    var servicepath = $"/etc/systemd/system/{servicename}.service";// 创建服务文件
                    system.io.file.writealltext(servicepath, $"[unit]{environment.newline}");
                    system.io.file.appendalltext(servicepath, $"description={servicedescription}{environment.newline}");// 服务描述
                    system.io.file.appendalltext(servicepath, $"[service]{environment.newline}");
                    system.io.file.appendalltext(servicepath, $"type=simple{environment.newline}");//设置进程的启动类型, 必须设为 simple, forking, oneshot, dbus, notify, idle 之一。
                    system.io.file.appendalltext(servicepath, $"guessmainpid=true{environment.newline}");
                    system.io.file.appendalltext(servicepath, $"workingdirectory={workingdirectory}{environment.newline}");
                    system.io.file.appendalltext(servicepath, $"standardoutput=journal{environment.newline}");
                    system.io.file.appendalltext(servicepath, $"standarderror=journal{environment.newline}");
                    system.io.file.appendalltext(servicepath, $"execstart=/usr/bin/dotnet {system.io.path.getfilename(filepath)}{environment.newline}");
                    system.io.file.appendalltext(servicepath, $"restart=always{environment.newline}");
                    system.io.file.appendalltext(servicepath, $"[install]{environment.newline}");
                    system.io.file.appendalltext(servicepath, $"wantedby=multi-user.target{environment.newline}");
                    console.writeline(startprocess("/usr/bin/systemctl", $"enable {servicename}.service"));
                    console.writeline(startprocess("/usr/bin/systemctl", $"start {servicename}.service"));
                    console.writeline($"unix 下安装服务完成,如果失败请手动执行以下命令完成安装:");
                    console.writeline($"systemctl enable {servicename}.service  //使自启动生效");
                    console.writeline($"systemctl start {servicename}.service  //立即启动项目服务");
                    console.writeline($"systemctl status {servicename}.service -l //查看服务状态");
                    return true;
                }
                else if (args[0].equals("-u", stringcomparison.ordinalignorecase))
                {
                    var servicepath = $"/etc/systemd/system/{servicename}.service";
                    console.writeline(startprocess("/usr/bin/systemctl", $"disable {servicename}.service"));
                    if (system.io.file.exists(servicepath))
                    {
                        system.io.file.delete(servicepath);
                    }
                    console.writeline($"unix 下卸载服务完成,如果失败请手动执行以下命令完成卸载");
                    console.writeline($"systemctl disable {servicename}.service  //使自启动失效");
                    console.writeline($"rm -y {servicepath}  //删除服务文件");
                    return true;
                }
            }
            startrun(args);
            system.threading.thread.sleep(system.threading.timeout.infinite);
            return false;
        }
        /// <summary>
        /// 运行程序,如果有命令-i或者-u则执行安装或卸载,否则执行<paramref name="startrun"/>
        /// <para>请在main函数中调用,服务显示名称请在main函数增加[displayname()]特性,服务说明[description]特性。</para>
        /// <para>windiows下需要依赖system.serviceprocess.servicecontroller</para>
        /// <para>-i 表示安装服务</para>
        /// <para>-u 表示卸载服务</para>
        /// </summary>
        /// <param name="servicename">服务名称</param>
        /// <param name="args">启动程序的参数</param>
        /// <param name="startrun">实际程序运行的函数</param>
        public static void run(string servicename, string[] args, action<string[]> startrun)
        {
            bool finish = false;
            string servicedescription = servicename;
            string displayname = servicename;
            string filepath = string.empty;
            if (args.length == 1)
            {
                stackframe frame = new stackframe(1);
                if (string.isnullorwhitespace(servicename))
                {
                    servicename=frame.getmethod().declaringtype.assembly.getname().name;
                }
                var displaynames = frame.getmethod().getcustomattributes(typeof(displaynameattribute), true);
                if (displaynames.length > 0)
                {
                    displayname = (displaynames[0] as displaynameattribute).displayname;
                }
                var descriptions = frame.getmethod().getcustomattributes(typeof(descriptionattribute), true);
                if (descriptions.length > 0)
                {
                    servicedescription = (descriptions[0] as descriptionattribute).description;
                }
                filepath = frame.getmethod().declaringtype.assembly.location;
            }
            if (environment.osversion.platform == platformid.win32nt)
            {
                finish = runwin(filepath, servicename, displayname, servicedescription, args, startrun);
            }
            else
            {
                finish = rununix(filepath, servicename, servicedescription, args, startrun);
            }
        }
        static string startprocess(string filename, string arguments)
        {
            string output = string.empty;
            using (system.diagnostics.process process = new system.diagnostics.process())
            {
                process.startinfo = new processstartinfo
                {
                    useshellexecute = false,
                    arguments = arguments,
                    redirectstandardinput = true,
                    redirectstandardoutput = true,
                    redirectstandarderror = true,
                    createnowindow = true,
                    workingdirectory = environment.currentdirectory,
                    filename = filename,
                };
                process.start();//启动程序
                process.waitforexit();//等待程序执行完退出进程
                output = process.standardoutput.readtoend();
                process.close();
            }
            return output;
        }
        static bool adminrestartapp(string filepath,string[] args)
        {
            if (!isadmin())
            {
                console.writeline("重新已管理员启动" + filepath);
                processstartinfo startinfo = new processstartinfo
                {
                    useshellexecute = true,
                    arguments = string.join(" ", args),
                    workingdirectory = environment.currentdirectory,
                    filename = filepath,
                    verb = "runas"
                };
                try
                {
                    process.start(startinfo);
                }
                catch (exception ex)
                {
                    console.writeline($"重新已管理员启动失败:{ex}");
                }
                return false;
            }
            return true;
        }
        /// <summary>
        /// 判断是否是处于administrator下允许
        /// </summary>
        /// <returns></returns>
        static bool isadmin()
        {
            using (system.security.principal.windowsidentity wi = system.security.principal.windowsidentity.getcurrent())
            {
                system.security.principal.windowsprincipal wp = new system.security.principal.windowsprincipal(wi);
                return wp.isinrole(system.security.principal.windowsbuiltinrole.administrator);
            }
        }
    }
}

最后把dll 上转到nuget 上面 dotnetcn.install

源代码放到github上面:https://github.com/hnlyf/dotnet.install

 

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网