it-swarm.com.de

.Net Core 2.0 Windows-Dienst

Ich versuche, einen Windows-Dienst in .Net Core 2.0 zu erstellen, aber ich habe einen ganzen Tag lang meinen Kopf gegen die Wand geschlagen und überhaupt keine Fortschritte erzielt. Alles scheint Core 1.0/1.1 zu verwenden, auch die Microsoft-Dokumentation:

Hosten Sie eine ASP.NET Core-App in einem Windows-Dienst

TopShelf unterstützt nicht auch 2.0 für das, was ich gesehen habe.

Ich habe einige seltsame Lösungen gesehen, die den gesamten Code in eine .Net-Standardklassenbibliothek stellen und dann eine .Net Framework-Anwendung zum Hosten des Windows-Dienstes verwenden, aber dies sieht in meinen Augen nicht elegant aus und ich versuche es zu bekommen Befreien Sie sich von.Net Framework insgesamt.

Ist das, was ich machen möchte, im Moment überhaupt möglich? Vermisse ich etwas wirklich Grundlegendes?

46
DGaspar

Dank der Veröffentlichung des Windows Compatibility Pack (zum Zeitpunkt des Schreibens noch in der Vorabversion) ist es jetzt möglich, einen Windows-Dienst in .NET Core 2.0 ohne Bibliotheken von Drittanbietern zu schreiben. Wie die Seite selbst warnt:

Bevor Sie jedoch mit der Portierung beginnen, sollten Sie wissen, was Sie mit der Migration erreichen möchten. Nur auf .NET Core zu portieren, da es sich um eine neue .NET-Implementierung handelt, ist kein guter Grund (es sei denn, Sie sind ein echter Fan).

Insbesondere das Schreiben eines Windows-Dienstes in .NET Core ist jetzt möglicherweise möglich. Sie erhalten jedoch keine plattformübergreifende Kompatibilität, da die Assemblys für andere Plattformen als Windows nur ein PlatformNotSupportedException auslösen, wenn Sie dies wünschen Versuchen Sie, den Servicecode zu verwenden. Es ist möglich, dies zu umgehen (z. B. mit RuntimeInformation.IsOSPlatform), Aber das ist insgesamt eine andere Frage.

Bibliotheken von Drittanbietern bieten möglicherweise noch eine schönere Oberfläche für die Installation des Dienstes: Zum Zeitpunkt des Schreibens unterstützt die aktuelle Version des Kompatibilitätspakets (2.0.0-preview1-26216-02) Den Namespace System.Configuration.Install Nicht. Daher funktioniert der Standardansatz mit einer ServiceProcessInstaller -Klasse und installutil nicht. Dazu später mehr.

Angenommen, Sie haben aus der Projektvorlage einen brandneuen Windows-Dienst (Service1) Erstellt (nicht unbedingt erforderlich, da er nichts Interessantes enthält, außer eine Klasse, die von ServiceBase erbt). . Alles, was Sie tun müssen, um es auf .NET Core 2.0 aufzubauen, ist das Editieren und Ersetzen des .csproj Durch das neue Format:

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

Löschen Sie dann properties\AssemblyInfo.cs, Da dies nicht mehr erforderlich ist und mit den Versionsinformationen im Projekt selbst in Konflikt steht.

Wenn Sie bereits einen Service haben und dieser Abhängigkeiten aufweist, ist die Konvertierung möglicherweise komplizierter. Siehe hier .

Jetzt sollten Sie in der Lage sein, dotnet publish Auszuführen und eine ausführbare Datei zu erhalten. Wie bereits erwähnt, können Sie den Dienst nicht mit der Klasse ServiceProcessInstaller installieren, sodass Sie ihn manuell installieren müssen

  • registrieren Sie die Ereignisquelle, die der Dienst verwendet.
  • erstellen Sie den eigentlichen Service.

Dies kann mit einer PowerShell durchgeführt werden. Von einer Eingabeaufforderung mit erhöhten Rechten an dem Ort, an dem sich Ihre veröffentlichte ausführbare Datei befindet:

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

Dies ist in mehrfacher Hinsicht nicht ideal: Dadurch wird der Pfad der Nachrichtenressourcendatei hartcodiert (wir sollten wirklich feststellen, wo er sich in der ausführbaren Datei und den Laufzeitpfaden in der Registrierung befindet) und der Dienstname und die ausführbare Datei hartcodiert Name. Sie können Ihrem Projekt eigene Installationsfunktionen zuweisen, indem Sie eine Befehlszeilenanalyse in Program.cs Durchführen oder eine der in Cocowallas Antwort genannten Bibliotheken verwenden.

26
Jeroen Mostert

So hosten Sie die .NET Core 2.0-Web-API als Windows-Dienst Ich habe diese Anleitung befolgt Host ASP.NET Core in einem Windows-Dienst . Der Teil Voraussetzungen ist mir unklar. Nach einigen Fehlern habe ich Folgendes getan: Quellcode

  1. Erstellen Sie eine ASP.NET Core-Webanwendung enter image description here
  2. Wähle API enter image description here
  3. Bearbeiten Sie die .csproj-Datei, und ändern Sie das Zielframework von netcoreapp2.0 in net461 , listen Sie explizit alle Paketreferenzen auf, anstatt Microsoft.AspNetCore.All wie folgt zu verwenden
<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 [Lösungsordner] dotnet publish -o "[Veröffentlichungsordner]"
  2. power Shell [Lösungsordner] sc.exe create CoreApi binpath = "[Veröffentlichungsordner]\CoreApiHostedAsWindowsService.exe"
  3. power Shell [solution-folder] sc.exe CoreApi starten
  4. standard-API-Power-Shell aufrufen [Lösungsordner] Invoke-WebRequest http: // localhost: 5000/api/values
14
Chenger

Ich werde einige Optionen zusammenfassen:

  1. Verschieben Sie Ihren Code in eine .NET Standard-Bibliothek und hosten Sie ihn in einer .NET Framework-App, sodass Sie ServiceBase verwenden können. Dazu muss das .NET Framework natürlich auf dem Zielcomputer installiert sein
  2. Verwenden Sie NSSM (den Non-Sucking Service Manager), um eine .NET Core-Konsolen-App zu verwalten (sie verfügt über eine Public Domain-Lizenz).
  3. Verwenden Sie Windows-API-Aufrufe, um sich in Windows-Dienstmethoden einzuklinken. Dies ist der Ansatz von DotNetCore.WindowsService und dotnet-win32-service (beide sind MIT lizensiert)

Ich denke, @ JeroenMosterts Kommentar ist ein bisschen hart - ich sehe den Reiz, nicht von einer bestimmten .NET Framework-Version abhängig zu sein, die auf den Zielcomputern verfügbar ist. Viele andere fühlen sich offensichtlich genauso, da die 2 Repos, mit denen ich verbunden bin, ziemlich beliebt sind.

12
Cocowalla

In .NET Core 2.1 können Sie Host und HostBuilder verwenden, um eine Konsolenanwendung abzurufen, die als Dienst ausgeführt wird. Wenn Sie Ihre Konsolenanwendung containerisieren, können Sie den Container überall bereitstellen, und er wird genauso ausgeführt wie ein Dienst. Sie können den Host und HostBuilder verwenden, um DI, Protokollierung, ordnungsgemäßes Herunterfahren usw. in Ihrer Konsolen-App zu verwalten. Schauen Sie sich an:

Hostingdienste in .NET Core-Konsolenanwendung

8
Peter

Eine einfache Möglichkeit, einen .NET Core Windows-Dienst zu erstellen, ist die Verwendung von Peter Kottas ' DotNetCore.WindowsService-Bibliothek .

Das NuGet-Paket ist PeterKottas.DotNetCore.WindowsService . Um es mit der Visual Studio Package Manager-Konsole zu installieren, führen Sie es einfach aus

Install-Package PeterKottas.DotNetCore.WindowsService

Es gibt auch gute Hinweise zum Einstieg .

4
Josh Withee

Wir brauchen nur das System.ServiceProcess.ServiceController NuGet-Paket, um eine .NET Core-Anwendung als Windows-Dienst auszuführen.

Es folgt die .csproj-Datei,

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

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

Erstellen und veröffentlichen Sie die Lösung.

  1. Öffnen Sie die Cmd-Eingabeaufforderung im Administratormodus aus dem EXE-Ordner. Beispiel:\WindowsService101\bin\Debug\netcoreapp2.1\publish

  2. sc create binPath = ""

  3. sc starten

2
DeviZ

Möglicherweise ist dies eine vollständige Behebung, aber denken Sie daran, dass Sie mit einer besseren Docker-Unterstützung möglicherweise einen Dienst aufbauen können, der in einem Container ausgeführt wird. Zu diesem Zeitpunkt wäre es immer noch .net core (2.0), läuft aber auf Ihrer Windows-Box. Darüber hinaus können Sie sie in Zukunft nahezu überall bereitstellen.

Wenn der Dotnet-Core ausgereift ist, ist dies eine immer bessere Lösung, vorausgesetzt, Ihr Service erfordert keine Ressourcen auf dem Host.

2
Killnine

ASP.NET Core in einem Windows-Dienst für .NET Core 2.2. Nehmen Sie die folgenden Änderungen an einem vorhandenen ASP.NET Core-Projekt vor, um die App als Dienst auszuführen:

Benötigt: PowerShell 6.2 or later

Framework-abhängige Bereitstellung (FDD):

Framework-abhängige Bereitstellung (FDD) setzt das Vorhandensein einer gemeinsam genutzten systemweiten Version von .NET Core auf dem Zielsystem voraus. Wenn das FDD-Szenario mit einer ASP.NET Core Windows Service-App verwendet wird, erstellt das SDK eine ausführbare Datei (* .exe), die als Framework-abhängige ausführbare Datei bezeichnet wird.

Fügen Sie dem <PropertyGroup>, Der das Zielframework enthält, einen Windows Runtime Identifier (RID) hinzu. Im folgenden Beispiel ist die RID auf win7-x64 Gesetzt. Fügen Sie die Eigenschaft <SelfContained> Hinzu, die auf false festgelegt ist. Diese Eigenschaften weisen das SDK an, eine ausführbare Datei (.exe) für Windows zu generieren.

Eine web.config-Datei, die normalerweise beim Veröffentlichen einer ASP.NET Core-App erstellt wird, ist für eine Windows Services-App nicht erforderlich. Fügen Sie zum Deaktivieren der Erstellung der Datei web.config die Eigenschaft <IsTransformWebConfigDisabled> Hinzu, die auf true festgelegt ist.

<PropertyGroup>
  <TargetFramework>netcoreapp2.2</TargetFramework>
  <RuntimeIdentifier>win7-x64</RuntimeIdentifier>
  <SelfContained>false</SelfContained>
  <IsTransformWebConfigDisabled>true</IsTransformWebConfigDisabled>
</PropertyGroup>

Eigenständige Bereitstellung (SCD):

Die eigenständige Bereitstellung (SCD) setzt keine gemeinsam genutzten Komponenten auf dem Zielsystem voraus. Die Laufzeit und die Abhängigkeiten der App werden mit der App auf dem Hosting-System bereitgestellt.

Bestätigen Sie das Vorhandensein eines Windows Runtime Identifier (RID) oder fügen Sie dem <PropertyGroup>, Das das Zielframework enthält, eine RID hinzu. Deaktivieren Sie die Erstellung einer web.config-Datei, indem Sie die Eigenschaft <IsTransformWebConfigDisabled> Auf true setzen.

<PropertyGroup>
  <TargetFramework>netcoreapp2.2</TargetFramework>
  <RuntimeIdentifier>win7-x64</RuntimeIdentifier>
  <IsTransformWebConfigDisabled>true</IsTransformWebConfigDisabled>
</PropertyGroup>

Program.Main

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>();
}

Veröffentlichen Sie eine Framework-abhängige Bereitstellung (FDD):

dotnet publish --configuration Release --output c:\svc

Veröffentlichen einer eigenständigen Bereitstellung (SCD)

Die RID muss in der Eigenschaft <RuntimeIdenfifier> (Oder <RuntimeIdentifiers>) Der Projektdatei angegeben werden. Geben Sie die Laufzeit an die Option - r | --runtime des Befehls dotnet publish An.

dotnet publish --configuration Release --runtime win7-x64 --output c:\svc

Gewähren Sie mithilfe des Befehls icacls über eine PowerShell 6-Verwaltungsbefehlsshell Schreib-/Lese-/Ausführungszugriff auf den Ordner der App.

icacls "{PATH}" /grant "{USER ACCOUNT}:(OI)(CI){PERMISSION FLAGS}" /t
  • {PATH} - Pfad zum Ordner der App.
  • {USER ACCOUNT} - Das Benutzerkonto (SID).
  • (OI) - Das Object Inherit-Flag gibt Berechtigungen an untergeordnete Dateien weiter.
  • (CI) - Das Container Inherit-Flag gibt Berechtigungen an untergeordnete Ordner weiter.
  • {PERMISSION FLAGS} - Legt die Zugriffsberechtigungen der App fest.
    • Schreiben Sie (W)
    • Lesen Sie (R)
    • Ausführen (X)
    • Voll (F)
    • Ändern (M)
  • / t - Rekursiv auf vorhandene untergeordnete Ordner und Dateien anwenden.

Befehl:

icacls "c:\svc" /grant "ServiceUser:(OI)(CI)WRX" /t

Verwenden Sie das PowerShell-Skript RegisterService.ps1 , um den Dienst zu registrieren. Führen Sie in einer PowerShell 6-Verwaltungsbefehlsshell das Skript mit dem folgenden Befehl aus:

.\RegisterService.ps1 
    -Name MyService 
    -DisplayName "My Cool Service" 
    -Description "This is the Sample App service." 
    -Exe "c:\svc\SampleApp.exe" 
    -User Desktop-PC\ServiceUser

Starten Sie den Dienst mit dem PowerShell 6-Befehl Start-Service -Name {NAME}.

Start-Service -Name MyService

Start und Stopp von Ereignissen behandeln

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();
    }
}

Verlängerungsmethode:

public static class WebHostServiceExtensions
{
    public static void RunAsCustomService(this IWebHost Host)
    {
        var webHostService = new CustomWebHostService(Host);
        ServiceBase.Run(webHostService);
    }
}

Program.Main:

Host.RunAsCustomService();

Legen Sie den Inhaltsstammpfad zum Ordner der App fest:

Program.Main:

var pathToExe = Process.GetCurrentProcess().MainModule.FileName;
var pathToContentRoot = Path.GetDirectoryName(pathToExe);
Directory.SetCurrentDirectory(pathToContentRoot);

CreateWebHostBuilder(args)
    .Build()
    .RunAsService();

Quelle:

https://github.com/aspnet/AspNetCore.Docs/tree/master/aspnetcore/Host-and-deploy/windows-service/

https://docs.Microsoft.com/en-us/aspnet/core/Host-and-deploy/windows-service?view=aspnetcore-2.2

2
Ogglas

Als Microsoft Microsoft.Windows.Compatibility veröffentlichte, würde ich es verwenden, da es für die zukünftige Verwendung am besten zu sein scheint.

Ein einfaches Beispiel für einen selbstinstallierenden Dienst finden Sie hier https://github.com/janantos/service_core

0
Jan Antoš