.Net5/6提供新的创建Windows服务
创建项目选择:
在.Net5及之后的版本使用新的创建Windows服务
在创建项目后,在nuget安装:Microsoft.Extensions.Hosting.WindowsServices
在Nuget种安装Microsoft.Extensions.Hosting.WindowsServices
这里主要是通过服务定时修改cpu的型号信息,是因为我的台式机当时买的是es(当时主要图便宜),在任务管理器中cpu型号是0000的.对于有强迫症的,可以对es的cpu忽略了.
没修改cpu型号信息
服务启动代码:
usingMicrosoft.Extensions.DependencyInjection;usingMicrosoft.Extensions.Hosting;usingIHosthost=Host.CreateDefaultBuilder(args)//使用在Microsoft.Extensions.Hosting.WindowsServices提供的中间件UseWindowsService.UseWindowsService(options=>{//指定服务名称options.ServiceName="UpdateCPUService";}).ConfigureServices(services=>{//将UpdateCPUService注入到容器中services.AddHostedService<UpdateCPUService.UpdateCPUService>();}).Build();awaithost.RunAsync();
具体服务代码:
usingSystem.Runtime.Versioning;usingMicrosoft.Extensions.Hosting;usingMicrosoft.Extensions.Logging;usingMicrosoft.Win32;namespaceUpdateCPUService{publicclassUpdateCPUService:BackgroundService{privatereadonlyILogger<UpdateCPUService>_logger;publicUpdateCPUService(ILogger<UpdateCPUService>logger){this._logger=logger;}//只支持Windows[SupportedOSPlatform("windows")]protectedoverrideasyncTaskExecuteAsync(CancellationTokenstoppingToken){//while(!stoppingToken.IsCancellationRequested)//{//_logger.LogInformation("Workerrunningat:{time}",DateTimeOffset.Now);//awaitTask.Delay(1000,stoppingToken);//}while(!stoppingToken.IsCancellationRequested){_logger.LogInformation("Workerrunningat:{time}",DateTimeOffset.Now);try{//注册表路径:计算机\HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\CentralProcessorRegistryKeyroot=Registry.LocalMachine;RegistryKey?hardware=root.OpenSubKey("HARDWARE",true);if(hardware!=null){vardescription=hardware!.OpenSubKey("DESCRIPTION",true);varsystem=description!.OpenSubKey("System",true);//获取CentralProcessor节点varcentralProcessor=system!.OpenSubKey("CentralProcessor",true);//子节点对应cpu核心数(包含超线程)for(inti=0;i<centralProcessor!.SubKeyCount;i++){RegistryKey?cpuNode=centralProcessor.OpenSubKey($"{i}",true);//修改cpu型号信息,这里不考虑灵活性,写死,可以加配置文件cpuNode!.SetValue("ProcessorNameString","Intel(R)Core(TM)i9-10900CPU@2.50GHz");}}}catch(Exceptionex){_logger.LogError("Workerrunningat:{message}",ex.Message);}//测试为1分钟,正式为30分钟awaitTask.Delay(TimeSpan.FromMinutes(1),stoppingToken);}}}}
创建Windows服务相关命令:
#通过sccreate创建Windows服务sc.execreate"UpdateCPUService"binpath="D:/codes/csharp/UpdateCPUService/bin/Release/net6.0/UpdateCPUService.exe"#通过scdelete删除Windows服务sc.esedelete"UpdateCPUService"#启动服务netstartupdatecpuservice#停止服务netstopupdatecpuservice
服务运行后:
Windows服务修改cpu型号信息
注意:因为操作注册表程序要有权限..Net程序要提高权限的话,可以添加应用程序清单文件(app.maniftest)
在.Net程序中添加应用程序清单文件,将程序提升权限为管理员权限
<!--使用管理员权限--><requestedExecutionLevellevel="requireAdministrator"uiAccess="false"/>
新的实现方式是新瓶装老酒
先看看UseWindowsService源码:
publicstaticIHostBuilderUseWindowsService(thisIHostBuilderhostBuilder){returnUseWindowsService(hostBuilder,_=>{});}publicstaticIHostBuilderUseWindowsService(thisIHostBuilderhostBuilder,Action<WindowsServiceLifetimeOptions>configure){if(WindowsServiceHelpers.IsWindowsService()){//Host.CreateDefaultBuilderusesCurrentDirectoryforVSscenarios,butCurrentDirectoryforservicesisc:\Windows\System32.hostBuilder.UseContentRoot(AppContext.BaseDirectory);hostBuilder.ConfigureLogging((hostingContext,logging)=>{Debug.Assert(RuntimeInformation.IsOSPlatform(OSPlatform.Windows));logging.AddEventLog();}).ConfigureServices((hostContext,services)=>{Debug.Assert(RuntimeInformation.IsOSPlatform(OSPlatform.Windows));services.AddSingleton<IHostLifetime,WindowsServiceLifetime>();//将WindowsServiceLifetime添加到容器中services.Configure<EventLogSettings>(settings=>{Debug.Assert(RuntimeInformation.IsOSPlatform(OSPlatform.Windows));if(string.IsNullOrEmpty(settings.SourceName)){settings.SourceName=hostContext.HostingEnvironment.ApplicationName;}});services.Configure(configure);});}returnhostBuilder;}
中间件源码:
usingSystem;usingSystem.Runtime.Versioning;usingSystem.ServiceProcess;usingSystem.Threading;usingSystem.Threading.Tasks;usingMicrosoft.Extensions.Logging;usingMicrosoft.Extensions.Options;namespaceMicrosoft.Extensions.Hosting.WindowsServices{//WindowsServiceLifetime实现ServiceBase//可以看到还是基于ServiceBase的封装[SupportedOSPlatform("windows")]publicclassWindowsServiceLifetime:ServiceBase,IHostLifetime{privatereadonlyTaskCompletionSource<object>_delayStart=newTaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);privatereadonlyManualResetEventSlim_delayStop=newManualResetEventSlim();privatereadonlyHostOptions_hostOptions;publicWindowsServiceLifetime(IHostEnvironmentenvironment,IHostApplicationLifetimeapplicationLifetime,ILoggerFactoryloggerFactory,IOptions<HostOptions>optionsAccessor):this(environment,applicationLifetime,loggerFactory,optionsAccessor,Options.Options.Create(newWindowsServiceLifetimeOptions())){}publicWindowsServiceLifetime(IHostEnvironmentenvironment,IHostApplicationLifetimeapplicationLifetime,ILoggerFactoryloggerFactory,IOptions<HostOptions>optionsAccessor,IOptions<WindowsServiceLifetimeOptions>windowsServiceOptionsAccessor){Environment=environment??thrownewArgumentNullException(nameof(environment));ApplicationLifetime=applicationLifetime??thrownewArgumentNullException(nameof(applicationLifetime));Logger=loggerFactory.CreateLogger("Microsoft.Hosting.Lifetime");if(optionsAccessor==null){thrownewArgumentNullException(nameof(optionsAccessor));}if(windowsServiceOptionsAccessor==null){thrownewArgumentNullException(nameof(windowsServiceOptionsAccessor));}_hostOptions=optionsAccessor.Value;ServiceName=windowsServiceOptionsAccessor.Value.ServiceName;CanShutdown=true;}privateIHostApplicationLifetimeApplicationLifetime{get;}privateIHostEnvironmentEnvironment{get;}privateILoggerLogger{get;}publicTaskWaitForStartAsync(CancellationTokencancellationToken){cancellationToken.Register(()=>_delayStart.TrySetCanceled());ApplicationLifetime.ApplicationStarted.Register(()=>{Logger.LogInformation("Applicationstarted.Hostingenvironment:{envName};Contentrootpath:{contentRoot}",Environment.EnvironmentName,Environment.ContentRootPath);});ApplicationLifetime.ApplicationStopping.Register(()=>{Logger.LogInformation("Applicationisshuttingdown...");});ApplicationLifetime.ApplicationStopped.Register(()=>{_delayStop.Set();});Threadthread=newThread(Run);//创建一个后台线程thread.IsBackground=true;thread.Start();//OtherwisethiswouldblockandpreventIHost.StartAsyncfromfinishing.return_delayStart.Task;}privatevoidRun(){try{Run(this);//Thisblocksuntiltheserviceisstopped._delayStart.TrySetException(newInvalidOperationException("Stoppedwithoutstarting"));}catch(Exceptionex){_delayStart.TrySetException(ex);}}publicTaskStopAsync(CancellationTokencancellationToken){//AvoiddeadlockwherehostwaitsforStopAsyncbeforefiringApplicationStopped,//andStopwaitsforApplicationStopped.Task.Run(Stop,CancellationToken.None);returnTask.CompletedTask;}//Calledbybase.Runwhentheserviceisreadytostart.protectedoverridevoidOnStart(string[]args){_delayStart.TrySetResult(null);base.OnStart(args);}//Calledbybase.Stop.ThismaybecalledmultipletimesbyserviceStop,ApplicationStopping,andStopAsync.//That'sOKbecauseStopApplicationusesaCancellationTokenSourceandpreventsanyrecursion.protectedoverridevoidOnStop(){ApplicationLifetime.StopApplication();//Waitforthehosttoshutdownbeforemarkingserviceasstopped._delayStop.Wait(_hostOptions.ShutdownTimeout);base.OnStop();}protectedoverridevoidOnShutdown(){ApplicationLifetime.StopApplication();//Waitforthehosttoshutdownbeforemarkingserviceasstopped._delayStop.Wait(_hostOptions.ShutdownTimeout);base.OnShutdown();}protectedoverridevoidDispose(booldisposing){if(disposing){_delayStop.Set();}base.Dispose(disposing);}}}
总结
- 老的方式,单一继承ServiceBase,通用性特好,支持.NetFramework/.NetCore及.Net5/6/7,简单的Windows服务直接使用.
- 新的中间件方式,只能在.Net5及更高的版本使用,在复杂的Windows服务要好一些.可以使用容器,进行依赖注入