NancyFx est un framework web open-source minimaliste pour la plateforme .NET. Il permet de construire des services HTTP sans dépendre d'infrastructures lourdes. Le projet officiel est accessible à l'adresse nancyfx.org.
Principales caractéristiques
NancyFx se distingue par sa philosophie « zéro configuration » : aucun fichier XML à éditer, aucune modification du web.config n'est requise. Son indépendance vis-à-vis de l'hôte permet de l'exécuter dans divers environnements : IIS, WCF, service Windows, application console autonome, etc.
Le framework est également compatible avec Mono, ce qui autorise un déploiement multiplateforme sur Linux et macOS.
Premiers pas avec NancyFx sous .NET Core
Après création d'une application .NET Core, installez le package Nancy via NuGet ou la CLI :
dotnet add package Nancy
Dans Startup.cs, branchez Nancy au pipeline OWIN :
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
app.UseDeveloperExceptionPage();
app.UseOwin(pipe => pipe.UseNancy());
}
Créez ensuite votre premier module en héritant de NancyModule :
public class GreetingModule : NancyModule
{
public GreetingModule()
{
Get("/", args => "Bienvenue sur Nancy !");
}
}
Le premier argument définit le pattern d'URL, le second une fonction lambda retournant la réponse. Lancez l'application : le message s'affiche.
Architecture des modules
Toute classe dérivant de NancyModule est automatiquement détectée par le framwork. Vous pouvez définir un préfixe de route via le constructeur de base :
public class GreetingModule : NancyModule
{
public GreetingModule() : base("/accueil")
{
Get("/", args => "Page d'accueil");
}
}
L'URL d'accès devient alors /accueil/.
Système de routage
Nancy propose plusieurs types de segments de route :
Segments littéraux
Un chemin fixe comme /accueil correspond à un segment littéral.
Segments avec variable capturée
public GreetingModule()
{
Get("/etudiants/{id?}", args =>
args.id == null ? "Aucun identifiant fourni" : $"Étudiant #{args.id}");
}
Le suffixe ? rend le paramètre optionnel.
Segments avec expression régulière
public GreetingModule()
{
Get(@"/produits/(?`^[0-9]{4}$)", args => $"Code produit : {args.code}");}`
Segments gloutons (Greedy)
L'astérisque en fin de variable capture toute la suite de l'URL :
public class CatalogModule : NancyModule
{
public CatalogModule()
{
Get("/catalogue/{chemin*}", args => args.chemin);
}
}
Contraintes de type
public class CatalogModule : NancyModule
{
public CatalogModule()
{
Get("/produits/{reference:int}", args => $"Référence : {args.reference}");
}
}
Seules les valeurs entières déclencheront cette route.
Pour renvoyer une vue statique :
public GreetingModule()
{
Get("/", args => View["etudiants/liste.html"]);
}
Nancy possède ses propres conventions de localisasion des vues. Pour les personnaliser, implémentez IRootPathProvider :
public class PersonnaliseCheminRacine : IRootPathProvider
{
public string GetRootPath()
{
return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Vues");
}
}
Activez ensuite ce provider via un bootstrapper personnalisé :
public class DemarrageCustom : DefaultNancyBootstrapper
{
protected override IRootPathProvider RootPathProvider =>
new PersonnaliseCheminRacine();
public override void Configure(INancyEnvironment env)
{
env.Tracing(enabled: true, displayErrorTraces: true);
base.Configure(env);
}
}
Moteur de vues SSVE (Super Simple View Engine)
SSVE est le moteur de templates intégré à Nancy. Il traite les fichiers .sshtml, .html et .htm via des subtsitutions par expressions régulières.
Substitution de variables
Bonjour @Model.Nom, vous avez @Model.Utilisateur.Age ans
Boucles d'itération
@Each.liste
<li>@Current.Titre</li>
@EndEach
Côté module :
public class EtudiantModule : NancyModule
{
private static readonly List<etudiant> _etudiants = new()
{
new Etudiant { Id = 1, Nom = "Dupont", Visible = true },
new Etudiant { Id = 2, Nom = "Martin", Visible = false },
new Etudiant { Id = 3, Nom = "Bernard", Visible = true }
};
public EtudiantModule()
{
Get("/liste", args => View["liste.html", new { _etudiants }]);
}
}
public class Etudiant
{
public int Id { get; set; }
public string Nom { get; set; }
public bool Visible { get; set; }
}</etudiant>
Template liste.html :
<table>
<tbody>
@Each._etudiants
@If.Visible
<tr>
<td>@Current.Id</td>
<td>@Current.Nom</td>
</tr>
@EndIf
@EndEach
</tbody>
</table>
Conditions
Les balises @If et @IfNot acceptent un paramètre booléen. Elles ne peuvent pas être imbriquées :
@IfNot.PossedeUtilisateurs
Aucun utilisateur enregistré.
@EndIf
Vues partielles
Syntaxe : @Partial['nom_vue'[, Model.Propriete]]
<!-- Sans modèle -->
@Partial['pied_de_page.sshtml']
<!-- Avec propriété du modèle -->
@Partial['detail_etudiant.sshtml', Model.Nom]
Fichier pied_de_page.html :
<footer>Vue partielle : @Model</footer>
Utilisation dans une vue principale :
<table>
@Each._etudiants
<tr>
<td>@Current.Id</td>
<td>@Partial['pied_de_page.html', Model.Nom]</td>
</tr>
@EndEach
</table>
Cycle de vie d'une requête
À l'arrivée d'une requête HTTP, Nancy la fait transiter par son pipeline interne : résolution de la route correspondante, invocation via IRouteInvoker, génération de la réponse, passage par les hooks du bootstrapper pour la gestion des erreurs, puis renvoi au client.
Le projet Nancy n'est plus maintenu depuis 2016. Son approche déclarative du routage reste néanmoins élégante, bien que le moteur de vues SSVE soit plus limité que des solutions comme Razor.