# Varmistetaan, että IHostedService ( tai IHosedLifecycleService) on yksi ainoa tapaus

<!--category-- ASP.NET -->
<datetime class="hidden">2024-08-22T16:08</datetime>

## Esitys

Tämä on typerä pieni artikkeli, koska olin hieman sekaantunut siihen, miten varmistaa `IHostedService` oli yksi tapaus. Luulin, että se oli hieman monimutkaisempi kuin se itse asiassa oli.

Siinä [edellinen artikla](/blog/addingasyncsendingforemails), käsittelimme, miten luoda taustapalvelu `IHostedService` yhteys sähköpostien lähettämiseen. Tässä artiklassa käsitellään sitä, miten varmistetaan `IHostedService` on yksi tapaus.
Tämä saattaa olla itsestään selvää joillekin, mutta se ei ole itsestään selvä muille.

[TOC]

## Miksi tämä on ongelma?

No se on ongelma, koska suurin osa artikloista näitä kattaa, miten käyttää `IHostedService` mutta niissä ei käsitellä sitä, miten varmistetaan, että palvelu on yksi instanssi. Tämä on tärkeää, koska te ette halua, että palvelujen useat instansit toimivat samanaikaisesti.

Mitä tarkoitan?

```csharp
  services.AddHostedService(EmailSenderHostedService);
```

Se kutsuu tähän backend-koodiin.

```csharp
public static IServiceCollection AddHostedService<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] THostedService>(this IServiceCollection services)
            where THostedService : class, IHostedService
        {
            services.TryAddEnumerable(ServiceDescriptor.Singleton<IHostedService, THostedService>());

            return services;
        }

```

Se on hienoa ja hienoa, mutta mitä jos haluatte lähettää uuden viestin suoraan tähän palveluun sanoen `Controller` toiminta?

```csharp

public class ContactController(EmailSenderHostedService sender,ILogger<BaseController> logger) ...
{
   [HttpPost]
    [Route("submit")]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Submit([Bind(Prefix = "")] ContactViewModel comment)
    {
        ViewBag.Title = "Contact";
        //Only allow HTMX requests
        if(!Request.IsHtmx())
        {
            return RedirectToAction("Index", "Contact");
        }
      
        if (!ModelState.IsValid)
        {
            return PartialView("_ContactForm", comment);
        }

        var commentHtml = commentService.ProcessComment(comment.Comment);
        var contactModel = new ContactEmailModel()
        {
            SenderEmail = string.IsNullOrEmpty(comment.Email) ? "Anonymous" : comment.Email,
            SenderName = string.IsNullOrEmpty(comment.Name) ? "Anonymous" : comment.Name,
            Comment = commentHtml,
        };
        await sender.SendEmailAsync(contactModel);
        return PartialView("_Response",
            new ContactViewModel() { Email = comment.Email, Name = comment.Name, Comment = commentHtml });

        return RedirectToAction("Index", "Home");
    }
   }
```

Ei tarvitse perustaa liittymää, joka itse panee toimeen `IHostedService` sitten kutsutte menetelmään sen perusteella tai teidän on varmistettava, että palvelu on yksi ainoa tapaus. jälkimmäinen on helpoin tapa tehdä tämä ( riippuu skenaariostanne, vaikka, Interface-menetelmän testaamista varten voi suosia

### IHostedService

Teidän on huomattava, että se rekisteröi palvelun `IHostedService`, tämä liittyy tämän palvelun elinkaaren hallintaan, sillä ASP: n järjestelmässä käytetään tätä rekisteröintiä kyseisen palvelun tapahtumien sammuttamiseksi.`StartAsync` ja `StopAsync` IHostedService:lle). Ks. jäljempänä, `IHostedlifeCycleService` on vain yksityiskohtaisempi versio IHostedServicesta.

```csharp
  /// <summary>
  /// Defines methods for objects that are managed by the host.
  /// </summary>

  public interface IHostedService
  {
    /// <summary>
    /// Triggered when the application host is ready to start the service.
    /// </summary>

    /// <param name="cancellationToken">Indicates that the start process has been aborted.</param>
    /// <returns>A <see cref="T:System.Threading.Tasks.Task" /> that represents the asynchronous Start operation.</returns>
    Task StartAsync(CancellationToken cancellationToken);

    /// <summary>
    /// Triggered when the application host is performing a graceful shutdown.
    /// </summary>

    /// <param name="cancellationToken">Indicates that the shutdown process should no longer be graceful.</param>
    /// <returns>A <see cref="T:System.Threading.Tasks.Task" /> that represents the asynchronous Stop operation.</returns>
    Task StopAsync(CancellationToken cancellationToken);
  }

namespace Microsoft.Extensions.Hosting
{
  /// <summary>
  /// Defines methods that are run before or after
  /// <see cref="M:Microsoft.Extensions.Hosting.IHostedService.StartAsync(System.Threading.CancellationToken)" /> and
  /// <see cref="M:Microsoft.Extensions.Hosting.IHostedService.StopAsync(System.Threading.CancellationToken)" />.
  /// </summary>

  public interface IHostedLifecycleService : IHostedService
  {
    /// <summary>
    /// Triggered before <see cref="M:Microsoft.Extensions.Hosting.IHostedService.StartAsync(System.Threading.CancellationToken)" />.
    /// </summary>

    /// <param name="cancellationToken">Indicates that the start process has been aborted.</param>
    /// <returns>A <see cref="T:System.Threading.Tasks.Task" /> that represents the asynchronous operation.</returns>
    Task StartingAsync(CancellationToken cancellationToken);

    /// <summary>
    /// Triggered after <see cref="M:Microsoft.Extensions.Hosting.IHostedService.StartAsync(System.Threading.CancellationToken)" />.
    /// </summary>

    /// <param name="cancellationToken">Indicates that the start process has been aborted.</param>
    /// <returns>A <see cref="T:System.Threading.Tasks.Task" /> that represents the asynchronous operation.</returns>
    Task StartedAsync(CancellationToken cancellationToken);

    /// <summary>
    /// Triggered before <see cref="M:Microsoft.Extensions.Hosting.IHostedService.StopAsync(System.Threading.CancellationToken)" />.
    /// </summary>

    /// <param name="cancellationToken">Indicates that the start process has been aborted.</param>
    /// <returns>A <see cref="T:System.Threading.Tasks.Task" /> that represents the asynchronous operation.</returns>
    Task StoppingAsync(CancellationToken cancellationToken);

    /// <summary>
    /// Triggered after <see cref="M:Microsoft.Extensions.Hosting.IHostedService.StopAsync(System.Threading.CancellationToken)" />.
    /// </summary>

    /// <param name="cancellationToken">Indicates that the stop process has been aborted.</param>
    /// <returns>A <see cref="T:System.Threading.Tasks.Task" /> that represents the asynchronous operation.</returns>
    Task StoppedAsync(CancellationToken cancellationToken);
  }
}
```

## Miten varmistaa, että IHostedService on yksi tapaus

### Interface-lähestymistapa

Interface-lähestymistapa voi olla yksinkertaisempi riippumatta skenaariostanne. `IHostedService` ja sen jälkeen liittää menetelmän yhteenliittymään, jota voi kutsua valvontakoneeltanne.

**PANEE MERKILLE: Teidän on vielä lisättävä se ASP:n HostedService-palveluksi.NET, jotta palvelu todellakin käynnistettäisiin**

```csharp
    public interface IEmailSenderHostedService : IHostedService, IDisposable
    {
        Task SendEmailAsync(BaseEmailModel message);
    }
```

Sen jälkeen tarvitsemme vain rekisteröidä sen yhdeksi tonniksi ja käyttää sitä omassa valvontajärjestelmässämme.

```csharp
             services.AddSingleton<IEmailSenderHostedService, EmailSenderHostedService>();
        services.AddHostedService<IEmailSenderHostedService>(provider => provider.GetRequiredService<IEmailSenderHostedService>());
        
```

ASP.NET huomaa, että sillä on oikea interfejs ja käyttää tätä rekisteröintiä `IHostedService`.

### Teollisuusmenetelmän lähestymistapa

Toinen varmistaa, että `IHostedService` on vain yksi tapaus käyttää `AddSingleton` menetelmä rekisteröidä palvelunne ja sen jälkeen toimittaa `IHostedService` rekisteröinti 'teollinen menetelmäM SK1 Tämä varmistaa, että vain yksi palvelunne instanssi on luotu ja käytetty koko soveltamisen ajan

* A *tehdas* menetelmä on vain hieno tapa sanoa menetelmä, joka luo objektin instanssin.

```csharp
        services.AddSingleton<EmailSenderHostedService>();
        services.AddHostedService(provider => provider.GetRequiredService<EmailSenderHostedService>());
```

Kuten näette, rekisteröin ensin `IHostedService` ( tai `IHostedLifeCycleService`) yksitonisena ja sen jälkeen käytän `AddHostedService` menetelmä palvelun rekisteröimiseksi tehtaaksi menetelmä. Näin varmistetaan, että vain yksi palvelun instanssi luodaan ja käytetään koko soveltamisen ajan

## Päätelmissä

Kuten tavallista, on olemassa joitakin tapoja peitellä kissaa. Tehtaiden menetelmän lähestymistapa on myös hyvä tapa varmistaa, että palvelunne on yksi tapaus. `IHostedService` on yksi tapaus.