簡體   English   中英

.Net Core 2.0 Windows服務

[英].Net Core 2.0 Windows Service

我正在嘗試在.Net Core 2.0中構建Windows服務,但我整整一天都在牆上敲敲打打,根本沒有任何進展。 一切似乎都使用Core 1.0 / 1.1,甚至包括Microsoft文檔:

在Windows服務中托管ASP.NET Core應用

就我所知,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 先決條件部分對我來說還不清楚。 經過一些錯誤,這就是我所做的: 源代碼

  1. 創建一個ASP.NET Core Web應用程序 在此處輸入圖片說明
  2. 選擇API 在此處輸入圖片說明
  3. 編輯.csproj文件,需要將目標框架從netcoreapp2.0更改為net461 ,顯式列出所有程序包引用,而不是使用Microsoft.AspNetCore.All ,如下所示

 <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> 

  1. Power Shell [解決方案文件夾] dotnet publish -o“ [publish-folder]”
  2. Power Shell [解決方案文件夾] sc.exe創建CoreApi binpath =“ [發布文件夾] \\ CoreApiHostedAsWindowsService.exe”
  3. 電源外殼[解決方案文件夾] sc.exe啟動CoreApi
  4. 訪問默認的api電源外殼[解決方案文件夾] Invoke-WebRequest http:// localhost:5000 / api / values

我將總結一些選擇:

  1. 將您的代碼移動到.NET Standard庫中,並將其托管在.NET Framework應用程序中,以便可以使用ServiceBase 當然,這需要將.NET Framework安裝在目標計算機上
  2. 使用NSSM (非吮吸服務管理器)來管理.NET Core控制台應用程序(它具有公共域許可證)
  3. 使用Windows API調用來掛鈎Windows服務方法。 這是DotNetCore.WindowsServicedotnet-win32-service (均已獲得MIT許可)采用的方法

我認為@JeroenMostert的評論有點苛刻-我可以看到不依賴於目標計算機上可用的特定.NET Framework版本的吸引力。 顯然其他人也有同樣的感覺,因為我鏈接到的2個回購協議相當受歡迎。

在.NET Core 2.1中,您可以使用Host和HostBuilder獲取作為服務運行的控制台應用程序。 如果您對控制台應用程序進行容器化,則可以將容器部署到任何地方,這與作為服務運行相同。 您可以在控制台應用程序中使用Host和HostBuilder來管理DI,日志記錄,正常關閉等。 看一下:

.NET Core控制台應用程序中的托管服務

創建.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
    }
}

生成並發布解決方案。

  1. 從.exe文件夾中,以管理模式打開Cmd提示符示例:\\ WindowsService101 \\ bin \\ Debug \\ netcoreapp2.1 \\ publish

  2. sc創建binPath =“”

  3. 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
  • {PATH} –應用程序文件夾的路徑。
  • {USER ACCOUNT} –用戶帳戶(SID)。
  • (OI)–“對象繼承”標志將權限傳播到下級文件。
  • (CI)–容器繼承標志將權限傳播到下級文件夾。
  • {PERMISSION FLAGS} –設置應用程序的訪問權限。
    • 寫(W)
    • 讀(R)
    • 執行(X)
    • 全(F)
    • 修改(M)
  • / 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM