AnthoDingo.Update
1.0.0
dotnet add package AnthoDingo.Update --version 1.0.0
NuGet\Install-Package AnthoDingo.Update -Version 1.0.0
<PackageReference Include="AnthoDingo.Update" Version="1.0.0" />
<PackageVersion Include="AnthoDingo.Update" Version="1.0.0" />
<PackageReference Include="AnthoDingo.Update" />
paket add AnthoDingo.Update --version 1.0.0
#r "nuget: AnthoDingo.Update, 1.0.0"
#:package AnthoDingo.Update@1.0.0
#addin nuget:?package=AnthoDingo.Update&version=1.0.0
#tool nuget:?package=AnthoDingo.Update&version=1.0.0
AnthoDingo.Update
Français · English
Garde de mise à niveau de base de données pour ASP.NET Core + Blazor.
Tant que des migrations EF Core sont en attente, toute requête est redirigée vers une
page /update fournie par la bibliothèque, qui liste les migrations restantes et
permet à un administrateur de confirmer leur application. Le schéma n'est donc jamais
migré silencieusement au démarrage, et aucune page ne s'exécute sur un schéma obsolète.
- Page Blazor intégrée : composant routable
/update, mise en page vide, styles et icône portés par le composant — ni Bootstrap ni feuille de style de l'hôte requis. - Agnostique du DbContext :
AddDatabaseUpdate<TDbContext>(), ou votre propreIMigrationManagersi vos migrations ne viennent pas d'EF Core. - Pas de round-trip inutile : une fois la base à jour, la garde se désactive pour la durée de vie du processus.
- Tolère une installation différée : si le DbContext n'est pas encore enregistré (assistant de premier démarrage type AnthoDingo.Setup), la garde laisse passer les requêtes.
Cible : net8.0 et net10.0. Dépendance : Microsoft.EntityFrameworkCore.Relational
(le provider reste le choix de l'application).
Une application de démonstration complète — Blazor Web App sur SQLite, livrée avec deux
migrations en attente — se trouve dans
src/AnthoDingo.Update.Sample :
dotnet run --project src/AnthoDingo.Update.Sample
Utilisation
1. Enregistrer et brancher
using AnthoDingo.Update;
builder.Services.AddDbContext<AppDbContext>(o => o.UseSqlServer(connectionString));
builder.Services.AddDatabaseUpdate<AppDbContext>(options =>
{
options.ProductName = "Mon Application";
// Chemins nécessaires pour atteindre /update, que la garde ne doit pas intercepter.
options.ExemptPathPrefixes.Add("/Account");
// Fortement recommandé : réserver la confirmation à un utilisateur authentifié,
// et éventuellement à une politique d'autorisation.
options.RequireAuthentication = true;
options.SignInPath = "/Account/Login";
// options.AuthorizationPolicy = "AdminOnly";
});
var app = builder.Build();
app.UseMigrationsGate(); // avant UseRouting
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
2. Rendre la page routable
Le composant vit dans l'assembly de la bibliothèque : il faut le déclarer au routeur.
Blazor Web App (.NET 8+) — au point de montage des composants :
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode()
.AddAdditionalAssemblies(ServiceCollectionExtensions.UpdateAssembly);
Blazor Server classique (App.razor portant le Router) :
@using AnthoDingo.Update
<Router AppAssembly="@typeof(App).Assembly"
AdditionalAssemblies="@(new[] { ServiceCollectionExtensions.UpdateAssembly })">
...
</Router>
3. Mode de rendu
⚠️ Le bouton Confirmer la mise à niveau exige un mode de rendu interactif côté serveur. Dans une Blazor Web App, le rendu statique (SSR) est le défaut : la page s'affiche et liste les migrations, mais le bouton ne déclenche rien.
Deux façons de le garantir :
// a) interactivité globale, déclarée sur App.razor
<Routes @rendermode="InteractiveServer" />
// b) ou, si l'interactivité est décidée page par page, activez-la au moins pour /update
Le mode WebAssembly n'est pas supporté : la page applique les migrations en appelant
IMigrationManager, qui n'existe que côté serveur.
Chemins exemptés
La garde laisse toujours passer /update, /_blazor, /_framework, /_content, le
options.SignInPath s'il est renseigné, et les requêtes portant une extension de fichier
statique connue (.css, .js, .png, .woff2…, voir
UpdateOptions.DefaultExemptFileExtensions, complétable via options.ExemptFileExtensions).
La liste d'extensions est volontairement fermée : une route applicative peut contenir un
point (/utilisateurs/jean.dupont, /api/v1.0/articles) sans être un fichier statique, et
doit rester derrière la garde.
Ajoutez-y les chemins d'authentification de votre application. La garde s'exécute avant
UseAuthentication et ne peut pas distinguer une requête d'authentification d'une requête
applicative : sans exemption, l'accès à /update boucle quand la page est protégée par
[Authorize] — la redirection vers la page de connexion est elle-même renvoyée vers
/update. Pour un fournisseur externe (OIDC), pensez aussi aux chemins de callback :
options.ExemptPathPrefixes.Add("/Account");
options.ExemptPathPrefixes.Add("/authorization-code/callback");
options.ExemptPathPrefixes.Add("/signout-callback-oidc");
Comportement de la redirection
| Requête | Réponse de la garde |
|---|---|
GET / HEAD |
302 vers {PathBase}/update?returnUrl=... — l'utilisateur est ramené à l'URL demandée une fois la mise à niveau appliquée |
POST, PUT, DELETE… |
503 avec un en-tête Location — une redirection transformerait la requête en GET et perdrait son corps |
| Base injoignable | 302 vers /update, qui affiche l'erreur ; le détail part dans les journaux |
Le PathBase est préservé : l'application peut être hébergée dans un répertoire virtuel.
Qui peut appliquer les migrations
Deux réglages, cumulables, décident si le bouton Confirmer la mise à niveau est proposé :
options.RequireAuthentication = true; // il faut être connecté
options.SignInPath = "/Account/Login"; // lien proposé pour se connecter
options.AuthorizationPolicy = "AdminOnly"; // et satisfaire cette politique
RequireAuthentication |
AuthorizationPolicy |
Visiteur anonyme | Connecté, hors politique | Connecté, dans la politique |
|---|---|---|---|---|
false |
null (défaut) |
✅ peut appliquer | ✅ | ✅ |
true |
null |
🔑 invité à se connecter | ✅ | ✅ |
false |
"AdminOnly" |
🔑 invité à se connecter | ⛔ refus | ✅ |
true |
"AdminOnly" |
🔑 invité à se connecter | ⛔ refus | ✅ |
Dans tous les cas la liste des migrations en attente reste visible : seul le bouton de confirmation disparaît. L'authentification est vérifiée avant la politique, et un visiteur anonyme qui échoue la politique est invité à se connecter plutôt qu'éconduit — c'est presque toujours la cause du refus.
⚠️ Le défaut (
RequireAuthentication = false,AuthorizationPolicy = null) ne fait aucune vérification : toute personne capable d'atteindre/updatepeut déclencher la migration. Ce n'est acceptable que si l'accès à la page est déjà restreint par l'hôte. La garde journalise un avertissement au démarrage tant qu'aucune des deux options n'est configurée.
SignInPath est optionnel mais recommandé avec RequireAuthentication : sans lui, un
visiteur anonyme est informé qu'il doit se connecter mais n'a aucun chemin pour le faire. Le
chemin renseigné est automatiquement exempté de la garde (inutile de l'ajouter à
ExemptPathPrefixes) et reçoit un paramètre ReturnUrl qui ramène à /update, laquelle
conserve elle-même l'URL demandée à l'origine.
La politique est réévaluée au moment du clic, pas seulement à l'affichage.
Les confirmations sont sérialisées dans le processus : deux administrateurs qui cliquent en
même temps ne lancent pas deux migrations concurrentes. En déploiement multi-instance,
cette garantie ne suffit pas — EF Core ne pose un verrou côté base qu'à partir de la
version 9, et dotnet ef database update reste la voie sûre.
Migrations hors EF Core
public sealed class DbUpMigrationManager : IMigrationManager
{
public Task<IReadOnlyList<string>> GetPendingMigrationsAsync(CancellationToken ct = default) => ...;
public Task ApplyPendingMigrationsAsync(CancellationToken ct = default) => ...;
}
builder.Services.AddDatabaseUpdateWith<DbUpMigrationManager>();
L'enregistrement d'IMigrationManager est idempotent : une implémentation déjà enregistrée
par l'application n'est jamais supplantée.
Apparence
options.ShowIcon = false; // aucune icône
options.IconCssClass = "bi bi-database-gear"; // icône de fonte, si l'hôte la charge
Par défaut la page dessine sa propre icône SVG, sans dépendre d'aucune feuille de style externe.
Localisation
options.Texts porte tous les libellés de la page ; UpdateTexts.French (défaut) et
UpdateTexts.English sont fournis, et le record se recopie au besoin :
options.Texts = UpdateTexts.English with { Continue = "Go to app" };
Licence
MIT — usage, modification, distribution et usage commercial libres, y compris dans un logiciel propriétaire. La seule obligation est de conserver la mention de copyright et le texte de la licence ; le logiciel est fourni sans garantie.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.EntityFrameworkCore.Relational (>= 10.0.12)
-
net8.0
- Microsoft.EntityFrameworkCore.Relational (>= 8.0.11)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0 | 99 | 9/12/2026 |