Back to "Assicurare il vostro IHostedService (o l'IHostedLifecycleService) è un singolo esempio."

This is a viewer only at the moment see the article on how this works.

To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk

This is a preview from the server running through my markdig pipeline

ASP.NET

Assicurare il vostro IHostedService (o l'IHostedLifecycleService) è un singolo esempio.

Thursday, 22 August 2024

Introduzione

Questo è un stupido piccolo articolo perché ero un po' confuso su come assicurarmi che il mio IHostedService Era un singolo esempio. Pensavo fosse un po' più complicato di quello che era in realtà. Quindi pensai di scrivere un piccolo articolo su questo argomento . Solo per caso qualcun altro ne fosse confuso.

Nell'università. articolo precedente, abbiamo spiegato come creare un servizio di base usando il IHostedService L'interfaccia per spedire email. Questo articolo vi dirà come assicurarvi che il vostro IHostedService è un singolo esempio. Potrebbe essere ovvio per alcuni, ma non per altri.

Perché questo è un problema?

Beh, è un problema perché la maggior parte degli articoli mostrano come usare una macchina. IHostedService Ma non si tratta di come assicurare che il servizio sia un singolo esempio.

Cosa intendo? Beh, nell' ASP.NET il modo di registrare un IHostedService o IHosedlifeCycleService M SK2 fondamentalmente lo stesso con più overrides per la gestione del ciclo di vita ) usate questo

  services.AddHostedService(EmailSenderHostedService);

Quello che fa è chiamare in questo codice di backend:

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

            return services;
        }

Che è bene e carino, ma se volete mandare un nuovo messaggio direttamente a questo servizio dal dire: Controller azione?


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

O avete bisogno di creare un'interfaccia che implementi da sé. IHostedService poi chiamate il metodo su quello o dovete assicurarvi che il servizio sia un singolo esempio. Questo è il modo più facile di farlo ( dipende dal vostro scenario anche seM SK2 per testare il metodo Interface potrebbe essere preferito

IHostedService

Voi' noterete qui che registra il servizio come un IHostedService, questo ha a che fare con la gestione del ciclo di vita di questo servizio, perché il sistema ASP.NET userà questa registrare per attivare gli eventi di questo service.StartAsync e StopAsync per IHostedService). Vedete sotto, IHostedlifeCycleService è solo una versione più dettagliata di IHostedService.

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

Come assicurare che il vostro IHostedService sia un singolo esempio

Approach dell'interfaccia

L'approccio dell'interfaccia potrebbe essere più semplice a seconda del vostro scenario. Qui 'd aggiungete un interfaccia che eredita da IHostedService E poi aggiungete un metodo all'interfaccia che potete chiamare dal vostro controller.

NOTA: Dovete ancora aggiungerlo come un HostedService in ASP.NET per far funzionare il servizio.

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

Tutto quello che dobbiamo fare è registrarlo come un singolo tono e usarlo nel nostro controller.

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

ASP.NET vedrà che questo ha l'interfaccia corretta decorata e userà questa registrazione per far funzionare IHostedService.

Approache della tecnica della fabbrica

Un altro per assicurarsi che il vostro IHostedService un singolo esempio è quello di usare il AddSingleton Il metodo per registrare il vostro servizio e poi passare il IHostedService Registrazione come 'metto di fabbrica'. Questo ensure che solo un'instance del vostro servizio sia creata e usata durante la vita dell'applicazioneM SK2

    1. La fabbrica. il metodo è solo un modo fantasioso di dire un metodo che crea un'instance di un oggetto.
        services.AddSingleton<EmailSenderHostedService>();
        services.AddHostedService(provider => provider.GetRequiredService<EmailSenderHostedService>());

Come vedete qui, per la prima volta ho registrato i miei dati. IHostedService (o IHostedLifeCycleService) come un singolo tono e poi uso il AddHostedService metodo per registrare il servizio come una fabbrica metodo. Questo ensure che solo un'instance del servizio sia creata e usata durante la vita dell'applicazione.

Conclusione

Come di solito, c'è un paio di modi per far pelle al gatto. L'approccio della tecnica fabbrica è anche un buon modo per assicurare che il vostro servizio sia un unico esempio. IHostedService è un singolo esempio.

logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.