.Net Core 在Windows上后台运行Console控制台程序
2019-01-18
张子阳
分类: .Net Core
有时候,我们需要在后台运行程序。通常,在Linux上,可以做成系统服务,使用systemctl命令来管理程序的启动和运行;也可以使用 nohup [应用程序] &
来后台运行。在Windows上,想要后台执行程序,通常只能做成Windows服务。有时候,做成Windows服务比较麻烦,当使用.Net Core时,需要将.Net Core程序托管在Windows服务中。但是,可以使用一个间接的方法,让.Net Core控制台程序后台运行。
首先新建一个.Net Core控制台程序,这个程序管它叫AppStarter,它的主要作用就是启动其他程序,然后在启动时通过配置 CreateNoWindow 和 UseShellExecute 来设置实际要启动的控制台程序的启动方式。
在这个例子中,我们的启动器将要启动的程序叫做DataSync.dll,是一个用来做数据同步的小程序,接收的参数为要同步的数据库名称。因此,可以像下面这样,编写一个配置文件appsettings.json:
{ "assembly": "/Users/zhangzy/code/dotnet/MSSQL数据库同步/DataSync/pub/DataSync.dll", "databases": ["ShopUser", "ShopLog", "ShopCenter"], "CreateNoWindow": true, "UseShellExecute": false }
- assembly: 要启动的程序位置
- databases: 启动程序的参数。上面有3个参数:ShopUser、ShopLog、ShopCenter,实际是启动3个DataSync程序,并分别传入这3个参数。
接下来,编写Program.cs:
using System; using System.Diagnostics; using System.IO; using Microsoft.Extensions.Configuration; using System.Linq; namespace DataSyncStarter { class Program { static IConfigurationRoot config; static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger (); static void Main(string[] args) { string env = Environment.GetEnvironmentVariable ("ASPNETCORE_ENVIRONMENT"); var builder = new ConfigurationBuilder () .SetBasePath (Path.Combine (AppContext.BaseDirectory)) .AddJsonFile ("appsettings.json", false) .AddJsonFile ($"appsettings.{ env }.json", optional : true); config = builder.Build (); SetLogConfig(); var databases = config.GetSection("databases").GetChildren().Select(x=> x.Value).ToArray(); var assembly = config["assembly"]; logger.Info($"控制台启动器运行, 环境:{ env }, 同步数据库:{ string.Join(", ", databases) }, CreateNoWindow:{Convert.ToBoolean(config["CreateNoWindow"])}, UseShellExecute:{Convert.ToBoolean(config["UseShellExecute"])}"); foreach(string db in databases) { int pid = StartProcess(assembly, db); var fi = new FileInfo(assembly); logger.Info($"开启应用: {fi.Name} {db},进程id:{ pid }"); } } // 开启进程 static int StartProcess (string assembly, string db) { var proc = new Process (); proc.StartInfo.FileName = "dotnet"; proc.StartInfo.Arguments = assembly + " " + db; proc.StartInfo.CreateNoWindow = Convert.ToBoolean(config["CreateNoWindow"]); proc.StartInfo.UseShellExecute = Convert.ToBoolean(config["UseShellExecute"]); proc.Start(); return proc.Id; } static void SetLogConfig(){ var nlogConf = new NLog.Config.LoggingConfiguration(); string layout = "${date:format=HH\\:mm\\:ss}|${level}|${message} ${exception}"; var logfile = new NLog.Targets.FileTarget("logfile"){ Layout = layout, FileName = "${basedir}/logs/${shortdate}.log" }; var logconsole = new NLog.Targets.ConsoleTarget("logconsole"){ Layout = layout }; nlogConf.AddRule(NLog.LogLevel.Trace, NLog.LogLevel.Fatal, logfile); nlogConf.AddRule(NLog.LogLevel.Info, NLog.LogLevel.Fatal, logconsole); NLog.LogManager.Configuration = nlogConf; NLog.LogManager.ReconfigExistingLoggers(); } } }
这里最主要的是StartProcess()方法中的参数设置,有下面几种配置方式:
CreateNoWindow | UseShellExecute | 结果 | |
---|---|---|---|
1. | false | true | 新建一个窗口,然后在新建的窗口运行子进程。主进程正常退出,子进程继续运行。 |
2. | false | false | 在当前窗口运行子进程。关闭当前窗口后,主进程退出,开启的子进程也退出。 |
3. | true | false | 当前窗口主进程正常退出。子进程在后台执行,不开启新窗口,需要通过任务管理器关闭子进程。 |
4. | true | true | 和第1种情况相同 |
从上面可见,对于这里的需求而言,第3中情况比较符合。
因为使用了NLog以及Configuration,如果要运行程序,需要在项目文件中添加一下引用的程序集:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>netcoreapp2.1</TargetFramework> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.Extensions.Configuration" Version="2.2.0"/> <PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="2.2.0"/> <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.2.0"/> <PackageReference Include="NLog" Version="4.5.10"/> </ItemGroup> <ItemGroup> <Content Include="*.json"> <CopyToOutputDirectory>Always</CopyToOutputDirectory> </Content> <Content Include="*.config"> <CopyToOutputDirectory>Always</CopyToOutputDirectory> </Content> </ItemGroup> </Project>
最后,运行程序:
# dotnet AppStarter.dll 11:58:51|Info|控制台启动器运行, 环境:Development, 同步数据库:ShopUser, ShopLog, ShopCenter, CreateNoWindow:True, UseShellExecute:False 11:58:51|Info|开启应用: DataSync.dll ShopUser,进程id:7612 11:58:51|Info|开启应用: DataSync.dll ShopLog,进程id:7316 11:58:51|Info|开启应用: DataSync.dll ShopCenter,进程id:4868
可以看到类似下面的结果:
在上图中,我后台运行了6个控制台程序(注意代码中只有3个,这里有点图文不符)。
感谢阅读,希望这篇文章能给你带来帮助!