[英].Net Core 2.0 Windows Service
我正在嘗試在.Net Core 2.0中構建Windows服務,但我整整一天都在牆上敲敲打打,根本沒有任何進展。 一切似乎都使用Core 1.0 / 1.1,甚至包括Microsoft文檔:
就我所知,TopShelf也不支持2.0。
我已經看到了一些奇怪的解決方案,這些解決方案將所有代碼都放在.Net標准類庫中,然后使用.Net Framework應用程序托管Windows Service,但是在我看來這看起來並不優雅,我正在嘗試獲取完全擺脫了.Net Framework。
我現在想做的事可能嗎? 我錯過了一些基本的東西嗎?
由於Windows兼容包的發布(在撰寫本文時仍處於預發行版本),現在可以在沒有第三方庫的情況下用.NET Core 2.0編寫Windows服務。 當頁面本身警告時:
但是在開始移植之前,您應該了解要完成的遷移工作。 僅僅因為它是新的.NET實現而移植到.NET Core並不是一個足夠好的理由(除非您是“真正的粉絲”)。
特別是,現在可以在.NET Core中編寫Windows Service,但是您將無法立即獲得跨平台兼容性,因為如果嘗試使用服務代碼,則Windows以外的平台的程序集只會拋出PlatformNotSupportedException
。 可以解決此問題(例如,使用RuntimeInformation.IsOSPlatform
),但這是另一個問題。
此外,第三方庫在安裝服務方面可能仍提供更好的接口:截至撰寫本文時,兼容性包的當前版本( 2.0.0-preview1-26216-02
)不支持System.Configuration.Install
名稱空間,因此帶有ServiceProcessInstaller
類和installutil
的默認方法將不起作用。 以后再說。
綜上所述,讓我們假設您已經從項目模板創建了一個全新的Windows服務( Service1
)(由於它不包含任何有趣的東西(除了繼承自ServiceBase
的類),因此不是必需的)。 要使其基於.NET Core 2.0構建,您所需要做的就是編輯.csproj
並將其替換為新格式:
<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp20</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Windows.Compatibility" Version="2.0.0-*" />
</ItemGroup>
</Project>
然后刪除properties\\AssemblyInfo.cs
因為它不再需要,並且將與項目本身中的版本信息沖突。
如果您已經有服務並且它具有依賴項,則轉換可能會更加復雜。 看這里 。
現在,您應該能夠運行dotnet publish
並獲取可執行文件。 如前所述,您不能使用ServiceProcessInstaller
類來安裝服務,因此您必須手動
可以使用某些PowerShell來完成。 在包含已發布的可執行文件的位置,從提升的提示中:
$messageResourceFile = "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\EventLogMessages.dll"
New-EventLog -LogName Application -Source Service1 -MessageResourceFile $messageResourceFile
sc.exe create Service1 binPath= (Resolve-Path .\WindowsService1.exe)
這在幾種方面都不理想:硬編碼消息資源文件的路徑(我們實際上應該從可執行文件和注冊表中的運行時路徑確定它的位置),並且硬編碼服務名稱和可執行文件名稱。 您可能希望通過在Program.cs
進行一些命令行解析來為您的項目提供自己的安裝功能,或者使用Cocowalla的答案中提到的庫之一。
將.NET Core 2.0 Web API托管為Windows服務。 我遵循了本指南Windows Service中的Host ASP.NET Core 。 先決條件部分對我來說還不清楚。 經過一些錯誤,這就是我所做的: 源代碼
<Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <TargetFramework>net461</TargetFramework> <RuntimeIdentifier>win7-x64</RuntimeIdentifier> <!--<TargetFramework>netcoreapp2.0</TargetFramework>--> </PropertyGroup> <ItemGroup> <Folder Include="wwwroot\\" /> </ItemGroup> <ItemGroup> <!--<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.6" />--> <PackageReference Include="Microsoft.AspNetCore" Version="2.0.2" /> <PackageReference Include="Microsoft.AspNetCore.Hosting.WindowsServices" Version="2.0.2" /> <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.0.3" /> <PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.0.2" /> <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.0.1" /> <PackageReference Include="Microsoft.VisualStudio.Web.BrowserLink" Version="2.0.2" /> </ItemGroup> <ItemGroup> <DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.3" /> </ItemGroup> </Project>
我將總結一些選擇:
ServiceBase
。 當然,這需要將.NET Framework安裝在目標計算機上 我認為@JeroenMostert的評論有點苛刻-我可以看到不依賴於目標計算機上可用的特定.NET Framework版本的吸引力。 顯然其他人也有同樣的感覺,因為我鏈接到的2個回購協議相當受歡迎。
在.NET Core 2.1中,您可以使用Host和HostBuilder獲取作為服務運行的控制台應用程序。 如果您對控制台應用程序進行容器化,則可以將容器部署到任何地方,這與作為服務運行相同。 您可以在控制台應用程序中使用Host和HostBuilder來管理DI,日志記錄,正常關閉等。 看一下:
創建.NET Core Windows服務的一種簡單方法是使用Peter Kottas的DotNetCore.WindowsService庫 。
NuGet包是PeterKottas.DotNetCore.WindowsService 。 要使用Visual Studio軟件包管理器控制台進行安裝,只需運行
Install-Package PeterKottas.DotNetCore.WindowsService
也許這是一個完整的解決方案,但是請記住,有了更多的docker支持,您也許可以構建在容器中運行的服務。 那時,它仍將是.net core(2.0),但在Windows框中運行。 而且,您將來可以在幾乎任何地方部署。
隨着dotnet內核的成熟,假設您的服務不需要主機本地資源,這將是一個越來越好的解決方案。
我們只需要System.ServiceProcess.ServiceController NuGet包即可將.NET Core應用程序作為Windows服務運行。
以下是.csproj文件,
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
<RuntimeIdentifier>win7-x64</RuntimeIdentifier>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.ServiceProcess.ServiceController"
Version="4.5.0" />
</ItemGroup>
</Project>
Program.cs文件,
using System.ServiceProcess;
namespace WindowsService101
{
class Program
{
static void Main(string[] args)
{
using (var service = new HelloWorldService())
{
ServiceBase.Run(service);
}
}
}
}
public class HelloWorldService : ServiceBase
{
protected override void OnStart(string[] args)
{
// Code Here
}
protected override void OnStop()
{
// Code Here
}
}
生成並發布解決方案。
從.exe文件夾中,以管理模式打開Cmd提示符示例:\\ WindowsService101 \\ bin \\ Debug \\ netcoreapp2.1 \\ publish
sc創建binPath =“”
sc開始
.NET Core 2.2
Windows服務中的.NET Core 2.2
。 對現有的ASP.NET Core項目進行以下更改,以將應用程序作為服務運行:
要求: PowerShell 6.2 or later
框架相關的部署(FDD):
框架相關的部署(FDD)依賴於目標系統上是否存在共享的系統范圍的.NET Core版本。 當FDD方案與ASP.NET Core Windows Service應用程序一起使用時,SDK將生成一個可執行文件(* .exe),稱為依賴於框架的可執行文件。
將Windows 運行時標識符(RID)添加到包含目標框架的<PropertyGroup>
中。 在以下示例中,RID設置為win7-x64
。 將<SelfContained>
屬性設置為false
。 這些屬性指示SDK為Windows生成可執行文件(.exe)。
Windows Services應用程序不需要Web.config文件,該文件通常是在發布ASP.NET Core應用程序時生成的。 要禁用web.config文件的創建,請將<IsTransformWebConfigDisabled>
屬性設置為true
。
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<RuntimeIdentifier>win7-x64</RuntimeIdentifier>
<SelfContained>false</SelfContained>
<IsTransformWebConfigDisabled>true</IsTransformWebConfigDisabled>
</PropertyGroup>
自包含部署(SCD):
自包含部署(SCD)不依賴於目標系統上共享組件的存在。 運行時和應用程序的依賴關系隨應用程序一起部署到托管系統。
確認Windows運行時標識符(RID)的存在或將RID添加到包含目標框架的<PropertyGroup>
中。 通過將<IsTransformWebConfigDisabled>
屬性設置為true
來禁用web.config文件的創建。
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<RuntimeIdentifier>win7-x64</RuntimeIdentifier>
<IsTransformWebConfigDisabled>true</IsTransformWebConfigDisabled>
</PropertyGroup>
程序主
public class Program
{
public static void Main(string[] args)
{
var isService = !(Debugger.IsAttached || args.Contains("--console"));
if (isService)
{
var pathToExe = Process.GetCurrentProcess().MainModule.FileName;
var pathToContentRoot = Path.GetDirectoryName(pathToExe);
Directory.SetCurrentDirectory(pathToContentRoot);
}
var builder = CreateWebHostBuilder(
args.Where(arg => arg != "--console").ToArray());
var host = builder.Build();
if (isService)
{
// To run the app without the CustomWebHostService change the
// next line to host.RunAsService();
host.RunAsCustomService();
}
else
{
host.Run();
}
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureLogging((hostingContext, logging) =>
{
logging.AddEventLog();
})
.ConfigureAppConfiguration((context, config) =>
{
// Configure the app here.
})
.UseStartup<Startup>();
}
發布依賴於框架的部署(FDD):
dotnet publish --configuration Release --output c:\svc
發布自包含部署(SCD)
必須在項目文件的<RuntimeIdenfifier>
(或<RuntimeIdentifiers>
)屬性中指定RID。 將運行時提供給dotnet publish
命令的-r | --runtime選項。
dotnet publish --configuration Release --runtime win7-x64 --output c:\svc
通過管理PowerShell 6命令外殼,使用icacls命令授予對應用程序文件夾的寫入/讀取/執行訪問權限。
icacls "{PATH}" /grant "{USER ACCOUNT}:(OI)(CI){PERMISSION FLAGS}" /t
命令:
icacls "c:\svc" /grant "ServiceUser:(OI)(CI)WRX" /t
使用RegisterService.ps1 PowerShell腳本注冊服務。 在管理性PowerShell 6命令外殼中,使用以下命令執行腳本:
.\RegisterService.ps1
-Name MyService
-DisplayName "My Cool Service"
-Description "This is the Sample App service."
-Exe "c:\svc\SampleApp.exe"
-User Desktop-PC\ServiceUser
使用Start-Service -Name {NAME}
PowerShell 6命令Start-Service -Name {NAME}
。
Start-Service -Name MyService
處理開始和停止事件
internal class CustomWebHostService : WebHostService
{
private ILogger _logger;
public CustomWebHostService(IWebHost host) : base(host)
{
_logger = host.Services
.GetRequiredService<ILogger<CustomWebHostService>>();
}
protected override void OnStarting(string[] args)
{
_logger.LogInformation("OnStarting method called.");
base.OnStarting(args);
}
protected override void OnStarted()
{
_logger.LogInformation("OnStarted method called.");
base.OnStarted();
}
protected override void OnStopping()
{
_logger.LogInformation("OnStopping method called.");
base.OnStopping();
}
}
擴展方式:
public static class WebHostServiceExtensions
{
public static void RunAsCustomService(this IWebHost host)
{
var webHostService = new CustomWebHostService(host);
ServiceBase.Run(webHostService);
}
}
Program.Main:
host.RunAsCustomService();
將內容根路徑設置為應用程序的文件夾:
Program.Main:
var pathToExe = Process.GetCurrentProcess().MainModule.FileName;
var pathToContentRoot = Path.GetDirectoryName(pathToExe);
Directory.SetCurrentDirectory(pathToContentRoot);
CreateWebHostBuilder(args)
.Build()
.RunAsService();
資源:
https://github.com/aspnet/AspNetCore.Docs/tree/master/aspnetcore/host-and-deploy/windows-service/
https://docs.microsoft.com/zh-cn/aspnet/core/host-and-deploy/windows-service?view=aspnetcore-2.2
當Microsoft發布Microsoft.Windows.Compatibility時,我會使用它,因為它似乎最適合將來使用。
自助安裝服務的簡單示例在這里https://github.com/janantos/service_core
對於那些發現此問題但想用.NET Core 3.x實施Windows服務的人
https://csharp.christiannagel.com/2019/10/15/windowsservice/
通用主機,后台服務以及命令行工具sc的組合,您將獲得Windows服務。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.