Qual è il .NET Generic Host? - La base per DI, configurazione e registrazione
· Aggiornato il: · Go Komura · 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
newovunque - Vuoi eseguire un loop in background
- Vuoi uscire in modo pulito su
Ctrl+Co 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.CreateApplicationBuildereHost.CreateDefaultBuilder? IHostè la stessa cosa di un contenitore DI?- Come è collegato a
BackgroundService? - È qualcosa di separato da
WebApplicationBuilderdi 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
- Prima la conclusione (in una riga)
- 1.1. Prima i termini
- Le tabelle da guardare per prime
- 2.1. Cosa contiene il Generic Host
- 2.2. Le differenze tra i costruttori
- Il quadro generale del Generic Host (diagramma)
- 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
- Configurazione minima
- 5.1. Un esempio minimo in un’app console
- 5.2.
appsettings.json - 5.3. Aggiunta di un
BackgroundService
- Modelli tipici
- 6.1. Strumenti della console di breve durata
- 6.2. Lavoratori / Servizi in background
- 6.3. Vive anche sotto ASP.NET Core
- Casi in cui si adatta
- Casi in cui non si adatta / è eccessivo
- Insidie
- Riepilogo
- 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/BackgroundServicee gestione dell’arresto dell’applicazione. - Per le nuove app non Web, a partire da
Host.CreateApplicationBuilder(args)è la scelta naturale. - Anche
WebApplicationBuilderdi 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ì.
flowchart LR
Args["args / variabili di ambiente / appsettings.json"] --> Builder["Host.CreateApplicationBuilder(args)"]
Builder --> Config["builder.Configuration"]
Builder --> Services["builder.Services"]
Builder --> Logging["builder.Logging"]
Services --> Hosted["IHostedService / BackgroundService"]
Builder --> Build["builder.Build()"]
Build --> Host["IHost"]
Host --> Run["Run / RunAsync"]
Run --> Lifetime["Avvia / interrompi / Ctrl+C / SIGTERM"]
Lifetime --> Hosted
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>IConfigurationIHostEnvironmentIOptions<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.
- Il corpo di un
BackgroundServiceèExecuteAsync - 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
HttpCliento 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+Co 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.Servicesbuilder.Configurationbuilder.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+Co 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.CreateDefaultBuilderper inerzia- A meno che non sia necessario abbinare il codice esistente,
Host.CreateApplicationBuilderè la prima scelta più naturale.
- A meno che non sia necessario abbinare il codice esistente,
- Iniezione di servizi con ambito direttamente in un
BackgroundService- I servizi ospitati non hanno un ambito predefinito. Creare un ambito con
IServiceScopeFactoryè più sicuro.
- I servizi ospitati non hanno un ambito predefinito. Creare un ambito con
- 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.
- Se esegui “esegui una volta” con il modello Worker, l’host continua a funzionare a meno che non chiami
- 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.
- Se si utilizza un host,
- Presupponendo che la directory corrente sia in Windows Service
- Le ricerche dei file sono più stabili se ancorate a
IHostEnvironment.ContentRootPath.
- Le ricerche dei file sono più stabili se ancorate a
- Racchiudere un CLI di breve durata in un
BackgroundServicefin 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
BackgroundServiceper lavori periodici- Se stai scrivendo in un flusso
async,PeriodicTimerè solitamente più leggibile e meno soggetto a confusione.
- Se stai scrivendo in un flusso
Con Generic Host, decidere in anticipo se il lavoro è di breve durata o permanente rimuove da solo la maggior parte delle esitazioni.
10. Riepilogo
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.
- Generic Host include non solo DI ma anche configurazione, registrazione, gestione dell’arresto e servizi ospitati
- Per le nuove app non Web,
Host.CreateApplicationBuilder(args)è l’inizio naturale - Per lavori di breve durata, puoi saltare
BackgroundServicee semplicemente creare ed eseguire - Per l’elaborazione residente,
BackgroundServicepiù la gestione della durata dell’host ripagano notevolmente BackgroundServicenon ha un ambito predefinito, quindi crea ambiti esplicitamente per i servizi con ambitoWebApplicationBuilderdi 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
- .NET Generic Host - .NET
- Servizi ai lavoratori in .NET
- Utilizza servizi con ambito all’interno di BackgroundService - .NET
- Configurazione in .NET
- Modello di opzioni in .NET
- .NET Generic Host in ASP.NET Core
- Crea Windows Service utilizzando BackgroundService - .NET
- Post correlato: PeriodicTimer vs. System.Threading.Timer vs. DispatcherTimer - Ordinamento dell’esecuzione periodica in .NET
- Post correlato: C# async / await Best Practices - Una tabella decisionale per Task.Run e ConfigureAwait
Articoli correlati
Articoli recenti con gli stessi tag per approfondire argomenti vicini.
Perché utilizzare .NET Generic Host e BackgroundService nelle app desktop
Come utilizzare Generic Host e BackgroundService per organizzare l'avvio, l'elaborazione periodica, l'arresto, la registrazione, la confi...
Scelta tra i tre timer di .NET - PeriodicTimer / Timer / DispatcherTimer
Quale timer .NET dovresti usare? PeriodicTimer per loop asincroni, timer per callback ThreadPool, DispatcherTimer per WPF UI, oltre a una...
Una guida pratica a FileSystemWatcher: gestire gli eventi persi e duplicati
Organizziamo come utilizzare FileSystemWatcher e le sue insidie: eventi persi, notifiche duplicate, trappole di rilevamento del completam...
Una tabella decisionale pratica per C# async / await - Task.Run e ConfigureAwait
Organizziamo le migliori pratiche asincrone / in attesa di C#: attese di I / O, lavoro della CPU, Task.Run, ConfigureAwait(false) e fire-...
Icone nella system tray e notifiche toast nelle app Windows — le insidie di NotifyIcon e come scegliere l'AppNotification giusta
Una guida pratica per mantenere un'applicazione Windows aziendale residente nella system tray (area di notifica) e avvisare l'utente tram...
Argomenti correlati
Queste pagine collocano l’argomento in un contesto più ampio di servizi e decisioni.
Argomenti tecnici Windows
Portale su sviluppo Windows, analisi dei problemi e valorizzazione delle risorse esistenti.
Generic Host e architettura dell'applicazione
Generic Host, BackgroundService, DI, configurazione, registrazione e ciclo di vita.
Servizi collegati all’argomento
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.
Consulenza tecnica e revisione del progetto
Se desideri definire DI, durata e separazione delle responsabilità prima dell'implementazione, possiamo iniziare con la definizione della direzione come consulenza tecnica e revisione del progetto.
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.