kullanarak bir Windows hizmeti oluşturmaBackgroundService

.NET Framework geliştiriciler, Windows hizmeti uygulamalarıyla tanıdık olabilir. .net Core ve .net 5 + öncesinde, .NET Framework 'e bağlı olan geliştiriciler arka plan görevleri gerçekleştirmek veya uzun süreli işlemleri yürütmek için Windows hizmetleri oluşturabilir. bu işlevsellik hala kullanılabilir ve bir Windows hizmeti olarak çalışan çalışan hizmetleri oluşturabilirsiniz.

Bu öğreticide aşağıdakilerin nasıl yapılacağını öğreneceksiniz:

  • .NET Worker uygulamasını tek bir dosya yürütülebilir dosyası olarak yayımlayın.
  • Windows bir hizmet oluşturun.
  • BackgroundServiceuygulamayı bir Windows hizmeti olarak oluşturun.
  • Windows hizmeti 'ni başlatın ve durdurun.
  • Olay günlüklerini görüntüleyin.
  • Windows hizmetini silin.

İpucu

".NET 'teki çalışanlar" örnek kaynak kodu, indirmek üzere Samples Browser 'da bulunabilir. Daha fazla bilgi için bkz. kod örneklerine gözatıyor: .net Içindeki çalışanlar.

Önkoşullar

Yeni proje oluşturma

Yeni bir Çalışan Hizmeti projesi oluşturmak Visual Studio Dosya Yeni Proje... seçeneğini > > belirtirsiniz. Yeni proje oluştur iletişim kutusunda "Çalışan Hizmeti" araması yazın ve Çalışan Hizmeti şablonunu seçin. .NET CLI kullanmak yerine sık kullanılan terminali bir çalışma dizininde açın. komutunu dotnet new çalıştırın ve yerine <Project.Name> istediğiniz proje adını yazın.

dotnet new worker --name <Project.Name>

.NET CLI yeni çalışan hizmeti projesi komutu hakkında daha fazla bilgi için bkz. dotnet new worker.

İpucu

Visual Studio Code kullanıyorsanız tümleşik terminalden .NET CLI komutlarını çalıştırabilirsiniz. Daha fazla bilgi için bkz. Visual Studio Code: Tümleşik Terminal.

NuGet paketi 'ni yükler

.net uygulamalarından yerel Windows hizmetleriyle birlikte çalışabilmek için IHostedService Microsoft.Extensions.Hosting.WindowsServices NuGet paketiniyüklemeniz gerekir.

bunu Visual Studio yüklemek için, NuGet paketlerini yönet... iletişim kutusunu kullanın. "Microsoft. Extensions. Hosting. WindowsServices" ifadesini arayın ve bu dosyayı yükler. .NET CLı 'yı kullanmayı tercih ediyorsanız, şu dotnet add package komutu çalıştırın:

dotnet add package Microsoft.Extensions.Hosting.WindowsServices

bu öğreticinin örnek kaynak kodunun bir parçası olarak, Microsoft.Extensions.Http NuGet paketinide yüklemeniz gerekir.

dotnet add package Microsoft.Extensions.Http

.NET CLı Add Package komutu hakkında daha fazla bilgi için bkz dotnet add package ..

Paketler başarıyla eklendikten sonra, proje dosyanızda aşağıdaki paket başvuruları bulunmalıdır:

<ItemGroup>
  <PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.0" />
  <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" />
  <PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
</ItemGroup>

Proje dosyasını güncelleştir

Bu çalışan proje, C# ' nin null yapılabilir başvuru türlerinikullanımını sağlar. Tüm projeyi etkinleştirmek için proje dosyasını uygun şekilde güncelleştirin:

<Project Sdk="Microsoft.NET.Sdk.Worker">

  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>true</ImplicitUsings>
    <RootNamespace>App.WindowsService</RootNamespace>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.0" />
    <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" />
    <PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
  </ItemGroup>
</Project>

Önceki proje dosyası değişiklikleri <Nullable>enable<Nullable> düğümü ekler. Daha fazla bilgi için bkz. Nullable bağlamı ayarlama.

Hizmeti oluşturma

Jokeservice. cs adlı projeye yeni bir sınıf ekleyin ve Içeriğini aşağıdaki C# koduyla değiştirin:

using System.Net.Http.Json;
using System.Text.Json;

namespace App.WindowsService;

public class JokeService
{
    private readonly HttpClient _httpClient;
    private readonly JsonSerializerOptions _options = new()
    {
        PropertyNameCaseInsensitive = true
    };

    private const string JokeApiUrl =
        "https://karljoke.herokuapp.com/jokes/programming/random";

    public JokeService(HttpClient httpClient) => _httpClient = httpClient;

    public async Task<string> GetJokeAsync()
    {
        try
        {
            // The API returns an array with a single entry.
            Joke[]? jokes = await _httpClient.GetFromJsonAsync<Joke[]>(
                JokeApiUrl, _options);

            Joke? joke = jokes?[0];

            return joke is not null
                ? $"{joke.Setup}{Environment.NewLine}{joke.Punchline}"
                : "No joke here...";
        }
        catch (Exception ex)
        {
            return $"That's not funny! {ex}";
        }
    }
}

public record Joke(int Id, string Type, string Setup, string Punchline);

Önceki şaka hizmeti kaynak kodu, yöntemi tek bir işlev gösterir GetJokeAsync . Bu, Task<TResult> T bir olan string ve rastgele programlama şaka temsil eden bir döndüren yöntemdir. HttpClientOluşturucuya eklenir ve sınıf kapsamı _httpClient değişkenine atanır.

İpucu

Şaka API 'SI GitHub açık kaynaklı bir projem. Bu, tanıtım amacıyla kullanılır ve gelecekte kullanılabilir olacağını garanti etmez. API 'yi hızlı bir şekilde test etmek için aşağıdaki URL 'YI bir tarayıcıda açın:

https://karljoke.herokuapp.com/jokes/programming/random.

Sınıfı yeniden yazın Worker

WorkerŞablondan varolanı aşağıdaki C# koduyla değiştirin ve dosyayı Windowsbackgroundservice. cs olarak yeniden adlandırın:

namespace App.WindowsService;

public sealed class WindowsBackgroundService : BackgroundService
{
    private readonly JokeService _jokeService;
    private readonly ILogger<WindowsBackgroundService> _logger;

    public WindowsBackgroundService(
        JokeService jokeService,
        ILogger<WindowsBackgroundService> logger) =>
        (_jokeService, _logger) = (jokeService, logger);

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            string joke = await _jokeService.GetJokeAsync();
            _logger.LogWarning(joke);

            await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken);
        }
    }
}

Önceki kodda, JokeService bir ile birlikte eklenir ILogger . Her ikisi de alan olarak sınıf için kullanılabilir hale getirilir private readonly . ExecuteAsyncYönteminde, şaka hizmeti bir şaka ister ve bunu günlükçü öğesine yazar. bu durumda, günlükçü Windows olay günlüğü tarafından uygulanır Microsoft.Extensions.Logging.EventLog.EventLogLogger . Günlükler öğesine yazılır ve Olay Görüntüleyicisi görüntülenmek üzere kullanılabilir.

Not

Varsayılan olarak, olay günlüğü önem derecesi ' dir Warning . Bu yapılandırılabilir, ancak tanıtım amacıyla WindowsBackgroundService LogWarning uzantı yöntemiyle Günlükler için. Düzeyi özellikle hedeflemek için EventLog appSettings 'e bir giriş ekleyin . { Environment}. JSON veya bir değer sağlayın EventLogSettings.Filter .

"Logging": {
  "EventLog": {
    "LogLevel": {
      "Default": "Information"
    }
  }
}

günlük düzeylerini yapılandırma hakkında daha fazla bilgi için bkz. .net 'te günlüğe kaydetme sağlayıcıları: Configure Windows EventLog.

Sınıfı yeniden yazın Program

Şablon programı. cs dosya Içeriğini aşağıdaki C# koduyla değiştirin:

using App.WindowsService;

using IHost host = Host.CreateDefaultBuilder(args)
    .UseWindowsService(options =>
    {
        options.ServiceName = ".NET Joke Service";
    })
    .ConfigureServices(services =>
    {
        services.AddHostedService<WindowsBackgroundService>();
        services.AddHttpClient<JokeService>();
    })
    .Build();

await host.RunAsync();

UseWindowsServicegenişletme yöntemi, uygulamayı bir Windows hizmeti olarak çalışacak şekilde yapılandırır. Hizmet adı olarak ayarlanır ".NET Joke Service" . Barındırılan hizmet kaydedilir ve HttpClient JokeService bağımlılık ekleme için öğesine kaydedilir.

Hizmetleri kaydetme hakkında daha fazla bilgi için bkz. .net 'Te bağımlılık ekleme.

Uygulamayı yayımlama

.net Worker hizmeti uygulamasını Windows bir hizmet olarak oluşturmak için, uygulamayı tek bir dosya yürütülebilir dosyası olarak yayımlamanız önerilir. Dosya sistemi etrafında herhangi bir bağımlı dosya olmadığından, kendi kendine dahil olan bir yürütülebilir dosya olması daha az hataya açıktır. ancak, Windows hizmeti denetim yöneticisi tarafından hedeflenebilir bir * .exe dosyası oluştururken, bu, tam olarak kabul edilebilir olan farklı bir yayımlama modülebilirliği seçebilirsiniz.

Önemli

alternatif bir yayımlama yaklaşımı, * .dll ( * .exe yerine) oluşturmak ve yayımlanan uygulamayı Windows hizmet denetimi yöneticisi 'ni kullanarak yüklediğinizde, .net clı 'ye temsilciliğini ve DLL 'yi geçitirsiniz. Daha fazla bilgi için bkz. .net CLI: DotNet komutu.

sc.exe create ".NET Joke Service" binpath="C:\Path\To\dotnet.exe C:\Path\To\App.WindowsService.dll"
<Project Sdk="Microsoft.NET.Sdk.Worker">

  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>true</ImplicitUsings>
    <RootNamespace>App.WindowsService</RootNamespace>
    <OutputType>exe</OutputType>
    <PublishSingleFile>true</PublishSingleFile>
    <RuntimeIdentifier>win-x64</RuntimeIdentifier>
    <PlatformTarget>x64</PlatformTarget>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.0" />
    <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" />
    <PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
  </ItemGroup>
</Project>

Proje dosyasının önceki vurgulanmış satırları aşağıdaki davranışları tanımlar:

  • <OutputType>exe</OutputType>: Bir konsol uygulaması oluşturur.
  • <PublishSingleFile>true</PublishSingleFile>: Tek dosya yayımlamayı mümkün.
  • <RuntimeIdentifier>win-x64</RuntimeIdentifier>: RID 'sini belirtir win-x64 .
  • <PlatformTarget>x64</PlatformTarget>: Hedef platform CPU 'SU olan 64-bit ' i belirtin.

uygulamayı Visual Studio yayımlamak için, kalıcı olan bir yayımlama profili oluşturabilirsiniz. Yayımlama profili XML tabanlıdır ve . pubxml dosya uzantısına sahiptir. Visual Studio uygulamayı örtük olarak yayımlamak için bu profili kullanır, ancak .net clı kullanıyorsanız, — kullanılacak yayımlama profilini açıkça belirtmeniz gerekir.

Çözüm Gezgini projeye sağ tıklayın ve Yayımla...' yı seçin. Ardından profil oluşturmak için bir yayımlama profili Ekle ' yi seçin. Yayımla Iletişim kutusunda hedef olarak klasör ' ü seçin.

Visual Studio yayımla iletişim kutusu

Varsayılan konumu bırakın ve son' u seçin. Profil oluşturulduktan sonra tüm ayarları göster' i seçin ve profil ayarlarınızı doğrulayın.

Visual Studio profili ayarları

Aşağıdaki ayarların belirtildiğinden emin olun:

  • Dağıtım modu: kendinden bağımsız
  • Tek dosya üret: işaretlendi
  • ReadyToRun derlemesini etkinleştir: işaretlendi
  • Kullanılmayan derlemeleri Kırp (önizlemede): işaretlenmemiş

Son olarak Yayımla' yı seçin. Uygulama derlenir ve elde edilen .exe dosyası /Publish çıkış dizinine yayımlanır.

Alternatif olarak, uygulamayı yayımlamak için .NET CLı kullanabilirsiniz:

dotnet publish --output "C:\custom\publish\directory"

Daha fazla bilgi için bkz. dotnet publish.

Windows hizmetini oluşturma

Windows hizmeti oluşturmak için yerel Windows Service Control Manager 'ın (sc.exe) create komutunu kullanın. PowerShell’i Yönetici olarak çalıştırın.

sc.exe create ".NET Joke Service" binpath="C:\Path\To\App.WindowsService.exe"

İpucu

Konak yapılandırmasınıniçerik kökünü değiştirmeniz gerekiyorsa, şunu belirtirken bir komut satırı bağımsız değişkeni olarak geçirebilirsiniz binpath :

sc.exe create "Svc Name" binpath="C:\Path\To\App.exe --contentRoot C:\Other\Path"

Bir çıkış iletisi görürsünüz:

[SC] CreateService SUCCESS

Daha fazla bilgi için bkz. sc.exe oluşturma.

Windows hizmetini yapılandırma

Hizmet oluşturulduktan sonra, isteğe bağlı olarak yapılandırabilirsiniz. Hizmet varsayılanlarıyla ilgili bir sorun yaşıyorsanız, hizmet Işlevlerini doğrula bölümüne atlayın.

Windows hizmetleri kurtarma yapılandırma seçeneklerini sağlar. Geçerli yapılandırma sc.exe qfailure "<Service Name>" <Service Name> değerlerini okumak için (hizmetlerinizin ' adınız) komutunu kullanarak geçerli yapılandırmayı sorgulayabilirsiniz:

sc qfailure ".NET Joke Service"
[SC] QueryServiceConfig2 SUCCESS

SERVICE_NAME: .NET Joke Service
        RESET_PERIOD (in seconds)    : 0
        REBOOT_MESSAGE               :
        COMMAND_LINE                 :

Bu komut, — henüz yapılandırılmadıklarından bu yana varsayılan değerler olan kurtarma yapılandırması çıktısını alırlar.

Windows hizmeti kurtarma yapılandırması özellikleri iletişim kutusu.

Kurtarmayı yapılandırmak için, sc.exe failure "<Service Name>" hizmetinizin adı olduğu yeri kullanın <Service Name> :

sc.exe failure ".NET Joke Service" reset=0 actions=restart/60000/restart/60000/run/1000
[SC] ChangeServiceConfig2 SUCCESS

İpucu

Kurtarma seçeneklerini yapılandırmak için, Terminal oturumunuzun yönetici olarak çalıştırılması gerekir.

Başarıyla yapılandırıldığında, komutunu kullanarak değerleri bir kez daha sc.exe qfailure "<Service Name>" sorguabilirsiniz:

sc qfailure ".NET Joke Service"
[SC] QueryServiceConfig2 SUCCESS

SERVICE_NAME: .NET Joke Service
        RESET_PERIOD (in seconds)    : 0
        REBOOT_MESSAGE               :
        COMMAND_LINE                 :
        FAILURE_ACTIONS              : RESTART -- Delay = 60000 milliseconds.
                                       RESTART -- Delay = 60000 milliseconds.
                                       RUN PROCESS -- Delay = 1000 milliseconds.

Yapılandırılan yeniden başlatma değerlerini görüyorsunuz.

Yeniden Windows hizmet kurtarma yapılandırma özellikleri iletişim kutusu.

Hizmet işlevselliğini doğrulama

Windows Hizmeti olarak oluşturulan uygulamayı görmek için Hizmetler'i açın. Üst Windows (veya Ctrl + Esc)seçin ve "Hizmetler" içinde arama. Hizmetler uygulamasından hizmetinizi adıyla bulabilirsiniz.

Hizmetler kullanıcı arabirimi.

Hizmetin beklendiği gibi çalıştığını doğrulamak için şunları yapmak gerekir:

  • Hizmeti başlatma
  • Günlükleri görüntüleme
  • Hizmeti durdurma

Önemli

Uygulamada hata ayıklamak için, Windows Services işlemi içinde etkin olarak çalışan yürütülebilir dosyada hata ayıklamaya çalışmayabilirsiniz.

Program başlatılamadı.

Windows Hizmetini başlatma

Windows Service'i başlatmak için şu komutu sc.exe start kullanın:

sc.exe start ".NET Joke Service"

Aşağıdakine benzer bir çıktıyı görüyorsunuz:

SERVICE_NAME: .NET Joke Service
    TYPE               : 10  WIN32_OWN_PROCESS
    STATE              : 2  START_PENDING
                            (NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
    WIN32_EXIT_CODE    : 0  (0x0)
    SERVICE_EXIT_CODE  : 0  (0x0)
    CHECKPOINT         : 0x0
    WAIT_HINT          : 0x7d0
    PID                : 37636
    FLAGS

Hizmet Durumu, 'den START_PENDING Çalışıyor'a geçiştir.

Günlükleri görüntüleme

Günlükleri görüntülemek için Olay Görüntüleyicisi. Üst Windows (veya Ctrl + Esc)seçin ve ifadesini arayın. "Event Viewer" Günlükler Olay Görüntüleyicisi düğümünü Windows > (Yerel) > seçeneğini seçin. Uygulama ad alanıyla eşleşen bir Kaynak ile Uyarı düzeyi girişi görüyor olun. Girişe çift tıklayın veya sağ tıklar ve Olay Özellikleri'ne tıklar ve ayrıntıları görüntüler.

Hizmetten günlüğe kaydedilen ayrıntılarla birlikte Olay Özellikleri iletişim kutusu

Günlükleri Olay Günlüğünde gördükten sonra hizmeti durdurmanız gerekir. Dakikada bir rastgele rastgele bir günlük kaydı yapmak için tasarlanmıştır. Bu kasıtlı bir davranıştır ancak üretim hizmetleri için pratik değildir.

Windows Hizmetini durdurma

Windows Service'i durdurmak için şu komutu sc.exe stop kullanın:

sc.exe stop ".NET Joke Service"

Aşağıdakine benzer bir çıktıyı görüyorsunuz:

SERVICE_NAME: .NET Joke Service
    TYPE               : 10  WIN32_OWN_PROCESS
    STATE              : 3  STOP_PENDING
                            (STOPPABLE, NOT_PAUSABLE, ACCEPTS_SHUTDOWN)
    WIN32_EXIT_CODE    : 0  (0x0)
    SERVICE_EXIT_CODE  : 0  (0x0)
    CHECKPOINT         : 0x0
    WAIT_HINT          : 0x0

Hizmet Durumu, 'den STOP_PENDING Durduruldu'ya geçiştir.

Windows Service'i silme

Windows Service'i silmek için yerel Windows Service Control Manager'ın (sc.exe) delete komutunu kullanın. PowerShell’i Yönetici olarak çalıştırın.

Önemli

Hizmet Durduruldu durumda değilse hemen silinmez. Delete komutunu vermeden önce hizmetin durdurulmuş olduğundan emin olmak.

sc.exe delete ".NET Joke Service"

Bir çıkış iletisi alırsınız:

[SC] DeleteService SUCCESS

Daha fazla bilgi için bkz.sc.exe silme.

Ayrıca bkz.