Qual è il .NET Generic Host? - La base per DI, configurazione e registrazione

· Aggiornato il: · · C#, .NET, Generic Host, Worker, Progettazione

Quando inizi a scrivere un’app console o un lavoratore in .NET, all’inizio puoi cavartela solo con un piccolo codice in Main. Ma man mano che cresce, anche leggermente, queste cose tendono ad accumularsi.

  • Vuoi leggere appsettings.json
  • Vuoi sovrascrivere i valori con variabili di ambiente
  • Vuoi accedere con ILogger
  • Non vuoi che l’edilizia di servizi sia una catena di new ovunque
  • Vuoi eseguire un loop in background
  • Vuoi uscire in modo pulito su Ctrl+C o su una fermata del servizio

È qui che entra in gioco Generic Host. Ma il nome stesso è un po’ soggetto a confusione.

  • Qual è la differenza tra Host.CreateApplicationBuilder e Host.CreateDefaultBuilder?
  • IHost è la stessa cosa di un contenitore DI?
  • Come è collegato a BackgroundService?
  • È qualcosa di separato da WebApplicationBuilder di ASP.NET Core?
  • Vale la pena utilizzarlo anche in un’app per console?

Quando questi si confondono, il Generic Host inizia ad assomigliare a “qualcosa di apparentemente solo web-app” o, al contrario, a “qualcosa in cui tutto dovrebbe essere ospitato”. Entrambi i punti di vista sono un po’ approssimativi.

In questo articolo, presupponendo l’attuale panorama pratico di .NET 6 e versioni successive, risolviamo innanzitutto queste quattro cose.

  • Cos’è veramente il Generic Host
  • Di cosa si prende cura per te, tutto in un unico posto
  • Il rapporto tra Host.CreateApplicationBuilder / Host.CreateDefaultBuilder / WebApplication.CreateBuilder
  • Da dove cominciare per un ingresso delicato

Sommario

  1. Prima la conclusione (in una riga)
    • 1.1. Prima i termini
  2. Le tabelle da guardare per prime
    • 2.1. Cosa contiene il Generic Host
    • 2.2. Le differenze tra i costruttori
  3. Il quadro generale del Generic Host (diagramma)
  4. Cosa ti offre Generic Host
    • 4.1. La logica di avvio converge in un unico posto
    • 4.2. DI / Configurazione / Registrazione sono collegati dall’inizio
    • 4.3. L’arresto regolare e il funzionamento residente diventano gestibili
  5. Configurazione minima
    • 5.1. Un esempio minimo in un’app console
    • 5.2. appsettings.json
    • 5.3. Aggiunta di un BackgroundService
  6. Modelli tipici
    • 6.1. Strumenti della console di breve durata
    • 6.2. Lavoratori / Servizi in background
    • 6.3. Vive anche sotto ASP.NET Core
  7. Casi in cui si adatta
  8. Casi in cui non si adatta / è eccessivo
  9. Insidie
  10. Riepilogo
  11. Riferimenti

1. Prima la conclusione (in una riga)

  • Generic Host è la base che gestisce l’avvio e la durata di un’app .NET in un unico posto.
  • Al suo interno vivono DI, configurazione, registrazione, IHostedService / BackgroundService e gestione dell’arresto dell’applicazione.
  • Per le nuove app non Web, a partire da Host.CreateApplicationBuilder(args) è la scelta naturale.
  • Anche WebApplicationBuilder di ASP.NET Core non è un mondo separato: è lo stesso concetto di host ampliato fino a diventare un punto di ingresso per il web.
  • In altre parole, Generic Host non è semplicemente un contenitore DI: è il meccanismo che riunisce il punto di assemblaggio dell’app e la gestione della durata.

In breve, nel momento in cui la tua app diventa troppo grande per “leggi gli argomenti, stampa una volta, esci”, Generic Host inizia a dare i suoi frutti considerevolmente. Al contrario, non è qualcosa che devi includere in ogni piccolo strumento che non sia cresciuto così lontano.

1.1. Prima i termini

Dato che da qui in poi useremo parecchie metafore, mettiamo prima le definizioni precise.

Termine Cosa significa esattamente Metafora usata in questo articolo
DI (Dependency Injection / inserimento delle dipendenze) Un modo di progettare in cui una classe riceve i propri collaboratori dall’esterno invece di crearli con new. Il contenitore che memorizza le registrazioni è il DI container (IServiceProvider), che Generic Host fornisce fin dall’inizio Cablaggio
Builder (HostApplicationBuilder) L’oggetto con cui si assembla l’host. Ha proprietà come Services, Configuration, Logging su cui si registrano i componenti. L’app non gira finché non viene chiamato Build() Tavolo di montaggio
Host (IHost) Il risultato di Build(): l’app assemblata e pronta. Contiene il DI container, la configurazione, il logging e i servizi ospitati, e gestisce avvio e arresto con Run() / RunAsync() Piattaforma
Hosted service (IHostedService / BackgroundService) Contenitore di logica che parte all’avvio e si ferma allo stop dell’host. Con BackgroundService, ExecuteAsync viene chiamato dopo StartAsync Lavoro residente
Lifetime Gestione dell’intero ciclo di vita dell’app, dalla partenza alla chiusura, coordinando Ctrl+C, SIGTERM, arresto servizio e simili Durata

La coppia più facile da confondere è Builder e Host. Builder è il lato che assembla, Host è il risultato assemblato, e Build() è il confine tra i due. Se si tiene a mente questo, le metafore “piattaforma”, “scatola”, “finestra” e “ingresso” usate più avanti non si confondono.

Se il DI è nuovo, pensa così: invece di scrivere a mano una catena di new, registri all’avvio “quando serve questo tipo, passagli questa implementazione”, e chi riceve si limita a prenderla come parametro del costruttore. Il posto dove si registrano le dipendenze è builder.Services.

2. Le tabelle da guardare per prime

2.1. Cosa contiene Generic Host

Separare in anticipo il contenuto di questa scatola rende tutto molto più semplice.

Elemento Di cosa si occupa Generic Host Perché aiuta
DI Costruisce servizi da IServiceCollection Più facile ridurre le catene di new
Configurazione Riunisce appsettings.json, variabili di ambiente, argomenti della riga di comando e altro Più facile gestire le differenze in base all’ambiente
Registrazione Imposta le basi per l’utilizzo di ILogger<T> Facile scambio delle destinazioni dei registri in un secondo momento
Servizio ospitato Gestisce l’avvio e l’arresto IHostedService / BackgroundService Facile separazione dell’elaborazione residente dal corpo dell’app
A vita Gestisce l’avvio / arresto attraverso IHostApplicationLifetime, IHostEnvironment e altro Facile standardizzare il modo in cui l’app termina il Ctrl+C, SIGTERM o una fermata del servizio

Il punto importante è che il Generic Host non è “un unico pratico involucro DI.” In realtà, l’inquadratura che meno rischia di trarre in inganno è: una scatola che collega l’intera area del punto di ingresso dell’app in un colpo solo.

2.2. Le differenze tra i costruttori

Anche questo è più veloce da assorbire come un’unica tabella.

Punto di ingresso Uso principale Stile di codifica Prima scelta
Host.CreateApplicationBuilder(args) Nuove app non Web come console / worker Scrivi direttamente contro builder.Services / builder.Configuration / builder.Logging Questo, per qualsiasi cosa nuova
Host.CreateDefaultBuilder(args) Codice esistente o configurazioni basate sui metodi di estensione precedenti Catena ConfigureServices e amici Questo, se disponi di risorse esistenti
WebApplication.CreateBuilder(args) ASP.NET Core app web / API Il Generic Host plus riguarda specificamente il web Questo, per il web

CreateApplicationBuilder e CreateDefaultBuilder non sono un caso di uno è una nuova funzionalità e l’altro è una cosa diversa.

Entrambi hanno le stesse funzionalità principali e il comportamento predefinito. Ciò che differisce è principalmente lo stile di codifica.

Per una nuova app non Web, la voce naturale oggi è Host.CreateApplicationBuilder(args). Pensa a WebApplication.CreateBuilder(args) come a quello stesso flusso che si è ampliato fino a diventare un punto di ingresso per il web e le cose rimangono in ordine.

3. Il quadro generale del Generic Host (diagramma)

Approssimativamente abbozzato, il quadro generale appare così.

args / variabili di ambiente / appsettings.jsonHost.CreateApplicationBuilder(args)builder.Configurationbuilder.Servicesbuilder.LoggingIHostedService / BackgroundServicebuilder.Build()IHostRun / RunAsyncAvvia / interrompi / Ctrl+C / SIGTERM

In genere, crei il builder in Program.cs, aggiungi servizi a builder.Services, regolare builder.Configuration e builder.Logging secondo necessità, quindi chiama Build() per ottenere un IHost ed eseguilo con Run() / RunAsync().

Ciò che è discretamente significativo è quanto è già in atto nel momento in cui chiami Host.CreateApplicationBuilder(args). Per impostazione predefinita, ottieni cose come le seguenti.

  • La radice del contenuto è la directory corrente
  • La configurazione dell’host proviene da variabili di ambiente con prefisso DOTNET_ e argomenti della riga di comando
  • La configurazione dell’app proviene da appsettings.json, appsettings.{Environment}.json, segreti utente in Sviluppo, variabili di ambiente e argomenti della riga di comando
  • La registrazione va a Console / Debug / EventSource / EventLog (solo Windows)
  • Nell’ambiente Development, la convalida dell’ambito e la convalida delle dipendenze sono abilitate

In altre parole, non stai cablando da zero senza pensarci — fin dall’inizio sono già poste le basi “ampiamente sufficienti per l’uso ordinario”.

4. Cosa ti dà Generic Host

4.1. La logica di avvio converge in un unico posto

Il vantaggio più discreto ma più grande del Generic Host è che il punto di ingresso dell’app diventa difficile da disperdere.

Man mano che un’app cresce un po’, le cose che si accumulano intorno a Main sono solitamente queste.

  • Caricamento dei file di configurazione
  • Scambio di impostazioni per ambiente
  • Inizializzazione del registratore
  • Assemblaggio di HttpClient, repository e servizi
  • Avvio dell’elaborazione in background
  • Pulizia sui segnali di uscita

Collega tutto questo insieme a mano senza un host e anche se all’inizio è leggero, il punto di ingresso diventa gradualmente appiccicoso.

Con Generic Host, Program.cs diventa chiaramente definito come “il luogo in cui le dipendenze vengono assemblate in una volta sola”. Questa organizzazione da sola cambia considerevolmente la facilità con cui diventa la revisione del codice.

4.2. DI / Configurazione / Registrazione sono collegati dall’inizio

Con Generic Host, DI, la configurazione e la registrazione poggiano sulla stessa base fin dall’inizio.

Per quanto riguarda la classe, ad esempio, puoi ricevere cose come queste come una cosa ovvia.

  • ILogger<T>
  • IConfiguration
  • IHostEnvironment
  • IOptions<T>

Ciò che ripaga qui è che il modo in cui leggi la configurazione e il modo in cui costruisci i servizi raramente si spostano in stili separati.

Se hai solo una o due impostazioni, la lettura diretta di IConfiguration["Section:Key"] funziona correttamente. Ma man mano che le impostazioni crescono nei progetti reali, raggruppare ogni sezione in una classe tramite IOptions<T> è più tranquillo.

Lo stesso vale per il disboscamento: invece di fare ILoggerFactory a mano ovunque, l’inserimento di ILogger<T> nelle classi che ne hanno bisogno mantiene le cose molto più leggibili.

Ciò che rende conveniente il Generic Host è che non tratta queste storie come storie separate — li gestisce insieme come base dell’intera app.

4.3. L’arresto regolare e il funzionamento residente diventano gestibili

Il Generic Host si occupa non solo di “come iniziare”, ma anche di “come fermarsi”.

All’avvio dell’host, StartAsync viene chiamato su ciascun IHostedService registrato. Nei servizi di lavoro, ExecuteAsync viene eseguito su servizi ospitati tra cui BackgroundService.

“Graceful shutdown” qui significa non interrompere bruscamente l’elaborazione, ma terminarla in questo ordine:

  • propagare il segnale di stop
  • esce dai loop e attende
  • ripulire connessioni e risorse

Per le app di lunga durata, questo è molto importante. Eventi come Ctrl+C, SIGTERM e interruzioni del servizio diventano facili da gestire con un metodo di arresto coerente a livello di app.

E quando l’app stessa richiede l’arresto, IHostApplicationLifetime.StopApplication() è disponibile. Puoi emettere il segnale “il lavoro è finito, per favore scendi in modo pulito” nel contesto dell’host.

5. Configurazione minima

5.1. Un esempio minimo in un’app console

Il primo punto importante: usare il Generic Host non significa devi creare un BackgroundService.

Anche per uno strumento console che viene eseguito una volta, il Generic Host è perfettamente utilizzabile se si desidera DI, configurazione e registrazione.

Per aggiungerlo a un normale progetto di console, fare prima riferimento a Microsoft.Extensions.Hosting.

dotnet add package Microsoft.Extensions.Hosting

Un Program.cs minimo assomiglia a questo.

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);

builder.Services.AddSingleton<JobRunner>();

using IHost host = builder.Build();

try
{
    JobRunner runner = host.Services.GetRequiredService<JobRunner>();
    await runner.RunAsync();
    return 0;
}
catch (Exception ex)
{
    ILogger logger = host.Services
        .GetRequiredService<ILoggerFactory>()
        .CreateLogger("Program");

    logger.LogError(ex, "Unhandled exception occurred during job execution.");
    return 1;
}

internal sealed class JobRunner(
    ILogger<JobRunner> logger,
    IConfiguration configuration,
    IHostEnvironment hostEnvironment)
{
    public Task RunAsync()
    {
        string message = configuration["Sample:Message"] ?? "(no message)";

        logger.LogInformation("Environment: {EnvironmentName}", hostEnvironment.EnvironmentName);
        logger.LogInformation("Message: {Message}", message);

        return Task.CompletedTask;
    }
}

Se l’app non rimane residente a lungo, non è necessario arrivare fino a RunAsync(). Build(), risolvi i servizi di cui hai bisogno, fai il lavoro ed esci. Ottieni comunque molti dei vantaggi di Generic Host in questo modo.

Questo punto è sorprendentemente importante. Non è necessario trascinare il modello Worker in ogni lavoro di breve durata.

5.2. appsettings.json

Per l’esempio sopra, è sufficiente un file di configurazione così minimo.

{
  "Sample": {
    "Message": "hello from Generic Host"
  }
}

C’è un classico ostacolo. In un progetto console, anche se aggiungi appsettings.json, non viene copiato nella cartella di output. Imposta “Copia nella directory di output” su “Copia se più recente” nelle proprietà del progetto, oppure scrivilo nel csproj come segue.

<ItemGroup>
  <Content Include="appsettings.json" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>

È utile conoscere anche i sintomi del “dimenticato”. Generic Host legge appsettings.json come file opzionale, quindi se manca non solleva eccezioni: semplicemente non ottiene il valore. Nel minimo esempio sopra verrebbe mostrato Message: (no message). Quando “non dà errore ma l’impostazione non ha effetto”, controlla prima se appsettings.json è presente nella cartella di output.

Questo esempio legge configuration["Sample:Message"] raw. Se guardi solo uno o due valori, è sufficiente.

Ma man mano che le impostazioni crescono in progetti reali, si protende verso

  • dividere ogni sezione nella propria classe
  • iniezione tramite IOptions<T>
  • convalida all’avvio

rende più semplice evitare di spargere stringhe di chiavi ovunque.

Inoltre, con le impostazioni predefinite di Generic Host, non solo appsettings.json ma appsettings.{Environment}.json, le variabili di ambiente e gli argomenti della riga di comando sono tutti collegati, quindi “scambiare valori solo durante lo sviluppo” e “sostituire con variabili di ambiente in produzione” sono abbastanza naturali.

5.3. Aggiunta di un BackgroundService

Per lavori di lunga durata, l’utilizzo di BackgroundService è la soluzione più semplice.

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);

builder.Services.AddScoped<PollingJob>();
builder.Services.AddHostedService<PollingWorker>();

using IHost host = builder.Build();
await host.RunAsync();

internal sealed class PollingWorker(
    IServiceScopeFactory scopeFactory,
    ILogger<PollingWorker> logger) : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        using PeriodicTimer timer = new(TimeSpan.FromSeconds(30));

        while (await timer.WaitForNextTickAsync(stoppingToken))
        {
            using IServiceScope scope = scopeFactory.CreateScope();
            PollingJob job = scope.ServiceProvider.GetRequiredService<PollingJob>();

            await job.RunAsync(stoppingToken);
            logger.LogInformation("Polling completed.");
        }
    }
}

internal sealed class PollingJob(ILogger<PollingJob> logger)
{
    public Task RunAsync(CancellationToken cancellationToken)
    {
        logger.LogInformation("Do work here.");
        return Task.CompletedTask;
    }
}

Due cose da notare in questo esempio.

  1. Il corpo di un BackgroundService è ExecuteAsync
  2. Se hai bisogno di dipendenze con ambito, crea un ambito con IServiceScopeFactory

Un BackgroundService non ha un proprio ambito predefinito. Se desideri utilizzare servizi con ambito come DbContext, risolvere il lavoro all’interno di un ambito come sopra è il modello sicuro.

La scelta dello strumento giusto per l’esecuzione periodica è un argomento a sé stante, ma se stai scrivendo il primo codice async, PeriodicTimer è piuttosto delicato. Questo si collega anche al nostro articolo correlato sui timer.

6. Modelli tipici

6.1. Strumenti della console di breve durata

Per le app che svolgono il proprio lavoro una volta e poi escono (batch, convertitori, comandi di manutenzione) il Generic Host è perfettamente utilizzabile.

Si adatta a scenari come questi.

  • Vuoi leggere i file di configurazione
  • Vuoi emettere log
  • Vuoi iniettare HttpClient o repository
  • Vuoi restituire un codice di uscita

In questo tipo di app, vai direttamente a BackgroundService e RunAsync() è un po’ pesante e sfrutta eccessivamente la gestione della durata dell’host.

Per un lavoro di breve durata, è sufficiente risolvere ed eseguire un JobRunner come nell’esempio minimo precedente.

6.2. Lavoratori / Servizi in background

Per i lavoratori residenti, sondaggi, consumo code, monitoraggio e lavoro programmato, la combinazione di Generic Host e BackgroundService è molto naturale.

Le parti particolarmente belle sono queste.

  • Il flusso di avvio e arresto è standardizzato sul lato host
  • La registrazione, la configurazione e DI sono disponibili fin dall’inizio
  • La cancellazione scorre facilmente su Ctrl+C o segnali di stop
  • Il corpo del trattamento residente è facilmente separabile da Program.cs

Si collega bene anche a Windows Service e ai contesti contenitore. Se l’app diventerà un’applicazione residente, Generic Host è una base molto naturale.

Quando lo trasformi in un Windows Service, invece di individuare i file relativi alla directory corrente, pensare in termini di IHostEnvironment.ContentRootPath provoca meno incidenti — perché “il percorso di base dell’app” è determinato nel contesto dell’host.

6.3. Vive anche sotto ASP.NET Core

Le app Web / API utilizzano WebApplication.CreateBuilder(args), quindi a prima vista potrebbe sembrare un mondo separato dall’host generico.

Ma nello spirito sono fortemente connessi.

  • builder.Services
  • builder.Configuration
  • builder.Logging

Il motivo per cui lo stile di codifica sembra lo stesso è esattamente questo.

In ASP.NET Core, l’avvio del server HTTP è di per sé parte della vita dell’host. Quindi comprendere il Generic Host ripaga anche nel senso che, leggendo un Program.cs sul lato web, diventa chiaro “perché DI, configurazione e registrazione vengono toccati proprio qui.”

7. Casi in cui si adatta

Ecco le situazioni in cui il Generic Host tende a fare clic piacevolmente.

  • App console che utilizzano configurazione, registrazione e DI
  • Lavoratori sulla scia dei consumatori di code, dei sondaggi, dei watchdog, degli scheduler
  • App di lunga durata che necessitano di pulizia su Ctrl+C o SIGTERM
  • App che possono trasformarsi in Windows Servizi / residenti nel contenitore
  • App che desideri allineare con gli stessi idiomi del metodo di estensione di ASP.NET Core

Ciò che condividono è “non voglio essere trascurato riguardo al punto di ingresso dell’app e alla gestione della sua durata.”

8. Casi in cui non si adatta/è eccessivo

Al contrario, ci sono situazioni in cui il Generic Host non ha bisogno di prendere l’iniziativa fin dall’inizio.

  • Un piccolo strumento che legge gli argomenti una volta, stampa una volta ed esce
  • Codice di verifica usa e getta utilizzato per poche decine di minuti
  • Progetti di biblioteche
  • Casi che leggono una singola impostazione e non necessitano di DI, registrazione o gestione della durata

Lì, un’implementazione più semplice è più silenziosa che sostenere un host.

La cosa importante è: solo perché Generic Host è potente non lo rende obbligatorio per ogni eseguibile.

9. Insidie

Infine, le cose su cui è facile intervenire nel primo round con l’host generico.

  • Considerare il Generic Host solo come un contenitore DI
    • In realtà è una base che include avvio, arresto, configurazione, registrazione e servizi ospitati.
  • Avvio di una nuova app da Host.CreateDefaultBuilder per inerzia
    • A meno che non sia necessario abbinare il codice esistente, Host.CreateApplicationBuilder è la prima scelta più naturale.
  • Iniezione di servizi con ambito direttamente in un BackgroundService
    • I servizi ospitati non hanno un ambito predefinito. Creare un ambito con IServiceScopeFactory è più sicuro.
  • Un lavoratore eseguito una sola volta che non dice mai all’host di fermarsi
    • Se esegui “esegui una volta” con il modello Worker, l’host continua a funzionare a meno che non chiami IHostApplicationLifetime.StopApplication() al termine del lavoro.
  • Vorrei un’uscita elegante ma interrompo le cose con Environment.Exit
    • Se si utilizza un host, StopApplication() è la scelta più affidabile quando si desidera una sosta pulita.
  • Presupponendo che la directory corrente sia in Windows Service
    • Le ricerche dei file sono più stabili se ancorate a IHostEnvironment.ContentRootPath.
  • Racchiudere un CLI di breve durata in un BackgroundService fin dall’inizio
    • Per un lavoro one-shot, risolvere ed eseguire una normale lezione di servizio è sufficiente.
  • Inserimento casuale di un timer di richiamata in un BackgroundService per lavori periodici
    • Se stai scrivendo in un flusso async, PeriodicTimer è solitamente più leggibile e meno soggetto a confusione.

Con Generic Host, decidere in anticipo se il lavoro è di breve durata o permanente rimuove da solo la maggior parte delle esitazioni.

In una frase, Generic Host è la base che riunisce il punto di ingresso e la gestione della durata di un’app .NET.

Ricapitoliamo i punti che vale la pena tenere in considerazione.

  1. Generic Host include non solo DI ma anche configurazione, registrazione, gestione dell’arresto e servizi ospitati
  2. Per le nuove app non Web, Host.CreateApplicationBuilder(args) è l’inizio naturale
  3. Per lavori di breve durata, puoi saltare BackgroundService e semplicemente creare ed eseguire
  4. Per l’elaborazione residente, BackgroundService più la gestione della durata dell’host ripagano notevolmente
  5. BackgroundService non ha un ambito predefinito, quindi crea ambiti esplicitamente per i servizi con ambito
  6. WebApplicationBuilder di ASP.NET Core si colloca sullo stesso flusso concettuale

Il Generic Host non è uno strumento per cerimonie pesanti. Nel momento in cui configurazione, registrazione, dipendenze, avvio e arresto iniziano a moltiplicarsi anche leggermente, è lo strumento per raccoglierli all’ingresso invece di lasciarli filtrare nei muri.

Al contrario, per i piccoli strumenti che non ne hanno ancora bisogno, non è necessario portarli con sé. Una volta che puoi fare questa distinzione, Generic Host smette di essere “qualcosa che aggiungi per impostazione predefinita” e diventa una base pratica con un luogo chiaramente definito.

11. Riferimenti

Articoli recenti con gli stessi tag per approfondire argomenti vicini.

Queste pagine collocano l’argomento in un contesto più ampio di servizi e decisioni.

L’articolo è direttamente collegato ai servizi seguenti.

Sviluppo di applicazioni Windows

La creazione di applicazioni Windows con elaborazione residente, gestione dell'arresto, registrazione e configurazione è esattamente il tipo di lavoro di implementazione adatto al nostro servizio di sviluppo di applicazioni Windows.

Domande frequenti

Domande che ricorrono nelle consulenze sull’argomento dell’articolo.

Qual è il .NET Generic Host?
Generic Host è la base che gestisce l'avvio e la durata di un'app .NET in un unico posto. Al suo interno inserimento di dipendenze live, configurazione (appsettings.json, variabili di ambiente, argomenti della riga di comando), registrazione tramite ILogger<T>, servizi ospitati come IHostedService e BackgroundService e gestione dell'arresto dell'applicazione. Non è semplicemente un contenitore DI: il frame che meno probabilmente ti ingannerà è una scatola che collega l'intera area del punto di ingresso dell'app in una volta sola e funziona nelle app console e nei lavoratori, non solo nelle app Web.
Qual è la differenza tra Host.CreateApplicationBuilder e Host.CreateDefaultBuilder?
Entrambi hanno le stesse funzionalità principali e il comportamento predefinito; ciò che differisce è principalmente lo stile di codifica. CreateApplicationBuilder ti consente di scrivere direttamente su builder.Services, builder.Configuration e builder.Logging ed è la prima scelta naturale per le nuove app non Web. CreateDefaultBuilder concatena i vecchi metodi di estensione in stile ConfigureServices e si adatta quando è presente del codice esistente costruito attorno ad essi. WebApplication.CreateBuilder di ASP.NET Core è lo stesso concetto di host ampliato in un punto di ingresso per il web.
Ho bisogno di un BackgroundService per utilizzare Generic Host in un'app console?
No. Anche per uno strumento console che viene eseguito una volta, Generic Host è perfettamente utilizzabile se desideri DI, configurazione e registrazione: crea l'host, risolvi i servizi necessari, esegui il lavoro ed esci: non è necessario chiamare RunAsync o trascinare il modello Worker. BackgroundService è la strada più semplice solo per lavori residenti di lunga durata, come polling, consumo di code o monitoraggio, in cui la gestione della durata di avvio / arresto da parte dell'host ripaga davvero.
Posso inserire servizi con ambito direttamente in un BackgroundService?
No: un BackgroundService non ha un proprio ambito predefinito. Se desideri utilizzare servizi con ambito come DbContext, il modello sicuro consiste nell'inserire IServiceScopeFactory, creare un ambito all'interno del ciclo (ad esempio, ogni segno di spunta del timer) e risolvere il processo dal fornitore di servizi di tale ambito. Ciò mantiene corrette le durate con ambito mentre il servizio ospitato stesso rimane un singleton gestito dall'host.

Profilo dell’autore

Pagina di presentazione dell’autore dell’articolo.

Go Komura

Rappresentante di KomuraSoft LLC

Specializzato nello sviluppo di software Windows, nella consulenza tecnica e nell’analisi dei malfunzionamenti, soprattutto nei progetti con sistemi esistenti e guasti difficili da riprodurre.

Torna al blog