Archive

Archives d’un auteur

Limiter l’exécution d’une action uniquement aux requêtes AJAX

En ASP.Net MVC nous manipulons entre autres des vues. Parmi ces vues certaines représentent des pages complètes et d’autres ne sont que des parties de page. Ces parties ou zones appartenant à une vue sont appelées des vues partielles et elles sont renvoyées elles aussi par des actions du contrôleur. Ces vues partielles ne devant être utilisées qu’à l’intérieur d’une vue alors le framework ASP.Net MVC nous permet de protéger l’appel à ces actions partielles en les décorant avec l’attribut ChildActionOnly. Cet attribut permet d’être sûr que l’action :

  • ne pourra pas être utilisée comme une vue entière et que les développeurs de l’application l’exécuteront toujours en passant par les méthodes HtmHelper.Action ou HtmlHelper.RenderAction.
  •  a une URL qui ne sera pas accessible via la barre d’adresse si un utilisateur, je ne sais par quel moyen, serait au courant de l’existence de cette URL.

Cependant comme tout site dynamique nous aurons des requêtes AJAX qui pourront faire elles aussi des demandes de contenu HTML sans qu’on ait besoin de charger la page de façon complète. Ce contenu aussi représente une partie puis qu’à la réception de la réponse du serveur Web nous devons incorporer ce bout de HTML quelque part dans la page. La requête AJAX envoyée au serveur invoquera certainement une action du contrôleur. Cette action comme celles marquées avec l’attribut ChildActionOnly doit possèder des restrictions soient :

  • obligation de passer par une requête faite en AJAX.
  • inaccessible via la barre d’adresse du navigateur.

Cependant le framework ASP.Net MVC n’offre aucun attribut nous permettant d’appliquer ces restrictions sur une action mais il nous fournit les outils pour en créer. Pour cela nous devons coder un filtre qui sera exécuté juste avant l’exécution de l’action concernée. Si la requête entrante respecte les conditions d’une requête faite en AJAX alors on laisse l’action continuer son chemin. Dans le cas où les conditions ne seraient pas respectées nous envoyons une page 404 (comme quoi l’URL est inexistante).

Le code du nouveau filtre que je nommerai AjaxOnlyAttribute, classe dérivée de la classe ActionFilterAttribute, est le suivant :

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
public class AjaxOnlyAttribute : ActionFilterAttribute
{
	public override void OnActionExecuting(ActionExecutingContext filterContext)
	{
		if (filterContext.HttpContext.Request.IsAjaxRequest())
		{
			base.OnActionExecuting(filterContext);
		}
		else
		{
			filterContext.HttpContext.Response.StatusCode = 404;
			filterContext.Result = new HttpNotFoundResult();
		}
	}
}

La nouvelle classe ne fait que surcharger la méthode qui nous intéresse. C’est à dire la méthode OnActionExecuting qui est appelée juste avant le début de l’exécution de l’action demandée par la requête entrante. L’attribut peut être posé sur le contrôleur pour atteindre l’ensemble des actions ou unitaire sur chaque action où la requête AJAX est obligatoire.

Pour éviter des soucis de pertes de quelques petites minutes qui peuvent arriver dans le cas où l’un des développeurs ayant rejoint l’équipe en cours de route et qui ne comprendrait pas pourquoi sa requête renvoie du 404 alors je pense que ce serait un avantage d’avoir un mode DEBUG activé par défaut pour les codeurs. Le code de notre classe ressemblerait finalement à celui-ci :

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
public class AjaxOnlyAttribute : ActionFilterAttribute
{
	public override void OnActionExecuting(ActionExecutingContext filterContext)
	{
		if (filterContext.HttpContext.Request.IsAjaxRequest())
		{
			base.OnActionExecuting(filterContext);
		}
		else
		{
			#if DEBUG
				filterContext.Result = new ViewResult { ViewName = "AjaxOnly" };
			#else
				filterContext.HttpContext.Response.StatusCode = 404;
				filterContext.Result = new HttpNotFoundResult();
			#endif
		}
	}
}

Etant donné que les développeurs sont amenés à compiler l’application la plupart du temps en mode DEBUG du coup la vue AjaxOnly contenant le texte qui va bien leur expliquera ce qu’il faut faire. Il faut noter que cette version de la classe fonctionne uniquement si une vue AjaxOnly.[cs|vb]html a été ajoutée dans le répertoire Views\Shared de l’application. Aussi on n’est pas obligé de renvoyer une vue partielle. On peut tout simplement remplacer le code suivant :

filterContext.Result = new ViewResult { ViewName = "AjaxOnly" };

par juste du contenu textuel :

filterContext.Result = new ContentResult
{
     Content = $"Cette action '{filterContext.HttpContext.Request.RawUrl}' a été conçue pour être utilisée uniquement via des requêtes AJAX"
};

La version utilisant la vue AjaxOnly a l’avantage de prendre en compte automatiquement le rendu _Layout par défaut défini au niveau de l’application.

Catégories :ASP.Net MVC Étiquettes : , , ,

Entity Framework et C# 6 : Utilisation des propriétés automatiques en lecture seule au niveau de vos entités

Avec C# 6 nous avons vu l’apparition de pas mal d’améliorations au niveau de la syntaxe. Ces nouveautés syntaxiques sont souvent mises dans la catégorie sucre syntaxique et comme exemple nous avons la propriété automatique en lecture seule permettant d’avoir juste un accesseur Get et qu’il est possible d’assigner via le constructeur.

Supposons que nous ayons la classe ci-dessous utilisée comme entité Entity Framework :

public class Product
{
	[Key]
	public Guid Reference { get; private set; }

	public string Name { get; set; }

	public string Description { get; set; }

	public Product()
	{
		this.Reference = Guid.NewGuid();
	}
}

Avec un contexte très simple :

public class MyDbContext : DbContext
{
	public DbSet<Product> Products { get; set; }

	public MyDbContext() : base("name=MyDbContext")
	{
	}
}

Avec C# 6 et les propriétés automatiques en lecture seule nous pouvons changer la définition de la propriété Reference en supprimant le modificateur Set. D’ailleurs si vous utilisez Resharper, cet outil vous incitera à changer la syntaxe comme le montre la capture d’écran ci-dessous :

ReadonlyAutoProperty

Au final nous aurons le code suivant :

public class Product
{
	[Key]
	public Guid Reference { get; }

	public string Name { get; set; }

	public string Description { get; set; }

	public Product()
	{
		this.Reference = Guid.NewGuid();
	}
}

Sauf qu’avec cette dernière version de l’entité Product en essayant de mettre les fichiers de migrations de la base de données à jour via la commande suivante : add-migration ProductUpdated nous rencontrons l’erreur suivante dans le Package Manager Console :

EntityType ‘Product’ has no key defined. Define the key for this EntityType.
Products: EntityType: EntitySet ‘Products’ is based on type ‘Product’ that has no keys defined.

Bien que notre propriété est toujours décorée de l’attribut Key, l’entité Product est quand même considérée comme n’ayant pas défini une clé primaire d’après Entity Framework. Il faut se rappeler que la plomberie d’Entity Framework veut que toutes les propriétés définies au niveau de l’entité qui sont mappées à des colonnes d’une table de la base données soient définies avec un accesseur Get et un modificateur Set. Le modificateur doit être présent dans tous les cas même si sa visibilité est restreinte en utilisant le mot-clé private.

Ce n’est parce qu’on a une propriété automatique écrite avec la syntaxe { get; private set; } puis remplacée avec l’utilisation d’une propriété automatique en lecture seule { get; } que l’objectif initial reste inchangé et qu’un modificateur Set sera créé automatiquement une fois le code compilé. On peut le croire vu que l’assignation de la propriété existe toujours au niveau du constructeur.

Pour preuve la propriété Reference  définie en tant que propriété automatique avec { get; private set; } est générée comme suit en IL :

PrivateSet

La version IL de la propriété lorsqu’on utilise la propriété automatique en lecture seule avec la syntaxe C# 6 { get; } et avec toujours la présence de l’assignation de la propriété dans le constructeur :

Readonly auto-prop

Dans la dernière image on note l’absence d’un modificateur Set.

En conclusion, bien qu’on soit bien tenté par l’utilisation de la propriété automatique en lecture seule (surtout quand des outils comme ReSharper nous les proposent) on doit toujours se rappeler qu’Entity Framework a bien besoin de la présence d’un modificateur quelle que soit la visibilité de ce dernier pour les propriétés mappées aux tables de la base de données et ne manquera pas de vous le rappeler. Pour éviter à d’autres développeurs, qui seraient amenés à faire évoluer le modèle Entity Framework, de modifier toutes les propriétés { get; private set; } et les remplacer par { get; }, il faudra veiller à bien configurer les outils d’aide à la programmation.

Dans le cas de ReSharper, certaines propositions peuvent être désactivées au niveau du fichier comme dans l’image ci-dessous :

DisableReSharper

On peut aussi configurer la version de C# sur laquelle ReSharper doit se baser pour les différentes propositions en faisant F4 sur le projet concerné :

DisableReSharperProjectProperties

J’espère que ce billet vous a été utile 😉

ASP.Net MVC : Eviter de polluer le modèle de la vue avec des messages d’erreurs

22 avril 2017 1 commentaire

J’ai récemment eu à répondre à une question posée sur le site StackOverflow. Je pose le contexte. Nous avons un modèle suivant:

public class ForgotPasswordMV
{
    [Display(Name = "Enter your email"), Required]
    public string Email { get; set; }
}

Ce modèle est utilisé dans l’action d’un contrôleur comme suit :

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Search(ForgotPasswordMV viewModel)
{
	if (Temp.Check(viewModel.Email))
		return RedirectToAction("VerifyToken", new { query = viewModel.Email });
	else
	{
		ViewBag.ErrorMessage = "Email not found or matched";
		return View();
	}
}

La question était de savoir si le fait d’utiliser la propriété dynamique ViewBag du contrôleur pour exposer le message d’erreur était une bonne pratique et que les recherches effectuées par le questionneur lui ont fait savoir qu’il fallait exposer une propriété au niveau du modèle.

Evidemment il est fortement recommandé de ne pas utiliser la propriété ViewBag étant donné qu’on ne bénéficie pas du typage fort. Si on veut communiquer avec la vue il faut toujours passer par un modèle typé. La solution proposée est donc légitime mais n’est pas une bonne pratique dans le cas de la gestion des erreurs du modèle dans le framework ASP.Net MVC.

La solution pour exposer les messages d’erreurs (comme dans l’exemple précédent qui n’utilise pas les attributs d’annotations de données) vient par l’utilisation de la méthode AddModelError de la classe ModelStateDictionary.  Nous n’avons pas besoin d’instancier cette classe étant donné qu’une propriété ModelState contenant une instance de cette classe existe déjà au niveau du contrôleur.

Du coup la bonne solution est de faire comme suit:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Search(ForgotPasswordMV viewModel)
{
    // ...
    else
    {
        this.ModelState.AddModelError("Email", "Email not found or matched");
        return View(viewModel);
    }
}

Il faut noter que cette méthode reçoit en premier paramètre le nom de la propriété du modèle à laquelle le message d’erreur est associé. Ainsi pour que pour ce message d’erreur soit affiché dans la vue à côté du champ Email il faut ajouter juste à côté de ce dernier la ligne suivante :

@Html.ValidationMessageFor(m => m.Email)

Cependant il est possible d’avoir un message d’erreur général à l’ensemble du modèle c’est à dire que ce message d’erreur n’est rattaché à aucune propriété du modèle. Pour cela il faudra utiliser une chaîne vide comme premier paramètre :

ModelState.AddModelError(String.Empty, "Email not found or matched");

Dans la vue Razor, il faudra utiliser la ligne suivante :

@Html.ValidationSummary(true, "The following error has occured:")

Le premier paramètre booléen indique qu’on ne veut pas afficher les messages d’erreur déjà rattachés à des propriétés du modèles.

Dans ce billet nous avons vu qu’on n’a pas besoin de polluer notre modèle et d’exposer des propriétés spécifiques aux messages d’erreur. Il suffit juste d’utiliser ce que nous offre le framework ASP.Net MVC pour nous faciliter la tâche.

J’espère que ce billet vous a été utile.

Héro du mois de juillet sur AfricaApp

J’écris de moins en moins de billets 😦 J’espère que la donne changera sur le courant du mois d’août 😀

J’écris ce billet pour vous informer que j’ai été élu héro du mois de juillet pour le magazine AfricaApp.

J’ai surtout été choisi à la suite de la publication de mon application Windows Phone Awalé. Awalé, pour ceux qui ne connaissent pas, est la version Windows Phone du jeu de semailles le plus répandu en Afrique. Ce jeu appartient à la famille des Mancala. Il s’agit d’un jeu de stratégie qui se joue à 2 et où on distribue des graines dans des trous parfois creusés à même le sol. Plusieurs règles existent suivant les régions ou pays et celle utilisée par mon application est la règle commune aux Akan et aux Diolas.

Si vous possédez un Windows Phone alors je ne peux que vous récommander de télécharger cette app 🙂

Catégories :Perso

WCF 4.5 – Récupérer tout le contenu WSDL en un seul et unique fichier

La version 4.5 de WCF a introduit une nouvelle manière de récupérer le contenu des métadonnées. Auparavant si vous avez activé l’exposition des métadonnées vous y accéder en utilisant une url du genre http://addresipdemonservice?wsdl. Le hic avec cette méthode est que cela posait des soucis d’interopérabilités si on était amené à travailler avec des clients pas développés avec la technologie .Net. En effet ces clients n’arrivent pas à lire contenu du wsdl. Pourquoi ? Il suffit d’observer le contenu du wsdl, vous verrez que tout n’y est pas par exemple les métadonnées sur les types utilisés par votre service. Les métadonnées concernant les types sont en effet importées via la balise xsd:import et l’attribut schemaLocation spécifie où chercher ces données. Bref ce procédé n’est pas compréhensible par les clients faits en Java, Php etc…

Pour récupérer toutes les métadonnées dans un seul et unique fichier vous pouvez au lieu de mettre ?wsdl utiliser ?singleWsdl à la place donc http://addresipdemonservice?singlewsdl pour assurer l’interopérabilité.

J’espère que ce post vous a servi 🙂

Catégories :WCF Étiquettes :

Code First : Entity Framework Reverse POCO Generator

9 décembre 2012 1 commentaire

Dans un précédent article j’ai expliqué comment faire du reverse engeneering Code First en utilisant l’extension Visual Studio Entity Framework Power Tools. Dans ce billet je parlerai d’une autre extension qui permet de faire la même chose : Entity Framework Reverse POCO Generator.

Vous pouvez installer cette extension à partir de la galerie ou via le gestionnaire d’extensions de Visual Studio. Une fois installé vous aurez un template de fichier qui sera ajouté à la liste de templates déjà existants.

Pour utiliser la fonctionnalité de reverse engeneering de cet outil, créer d’abords votre projet de préférence une bibliothèques de classes. Après vous faîtes un clic-droit sur le projet puis « Ajouter un élément ». Dans la boîte de dialogue qui apparaît choisissez le template suivant :
EF Generator
Donnez un nom à votre élément. Dans mon cas vu que j’utilise la base de données AdventureWorksLT2008 j’ai mis AdventureWorksLT.tt. Après validation, vous aurez 3 fichiers de template T4 (fichiers d’extensions .tt) qui seront ajoutés à votre projet :
EF Generator T4

Le seul fichier T4 que vous aurez à toucher et modifier est AdventureWorksLT.tt. Ouvrez ce fichier et suivre les étapes suivantes :

  • Configuration de la chaine de connexion : en début de fichier trouvez le paramètre ConnectionStringName et mettez le nom de la chaîne de connexion à utiliser. Notez que cette chaîne de connexion doit exister dans le fichier de configuration App.config.
    ConnectionStringName = "AdventureWorksLT2008Context";
  • Configuration du nom du contexte : trouvez le paramètre DbContextName et attribuez lui le nom que vous voudriez avoir comme nom de contexte (la clasese dérivant de DbContext)
    DbContextName = "AdventureWorksContext";
  • Rendre vos classes partielles : trouvez le paramètre MakeClassesPartial et attribuez lui la valeur true. Cela à pour but de rendre les classes partielles par défaut elles ne le sont pas.
    MakeClassesPartial = true;

La sauvegarde du fichier vous génère automatiquement le fichier AdventureWorksLT.cs. Ce fichier continent toutes les classes pour utiliser l’approche Code First. Dans ce fichier ces classes sont groupées en 3 catégories. D’abords nous avons le contexte de la base de données (AdventureWorksLT), suivi de toutes les classes POCO et enfin viennent les classes de configuration de nos classes POCO. Les classes de configuration ont pour but, à travers l’API FLuent, de définir les tables, colonnes, clefs et relations entre ces classes et tables existantes dans votre base de données.

Cette extension n’effectue qu’une tâche : faire du reverse engeneering alors que Entity Framework Power Tools en offre d’autres comme visualiser le modèle EDM, le XML de ce dernier ou générer des vues pré-compilées. Mais il faut noter qu’EF Power Tools ne permet pas de filtrer ou exclure les tables qu’on veut ou qu’on ne veut pas utiliser dans notre projet alors Entity Framework Reverse POCO Generator permet de le faire à travers des expressions régulières que vous devez configurer en modifiant les paramètres TableFilterExclude et TableFilterInclude du template T4 AdventureWorksLT.tt.

Bon code 😉

Catégories :Entity Framework Étiquettes :

Des bases de données exemples : AdventureWorks !

Si comme moi, vous lisez pas mal de tutoriels vous verrez que pas mal de ces tutoriels (du moins ceux portant sur la plateforme .Net et utilisant une base de données SQL Server) utilisent souvent les bases de données AdeventureWorks comme exemple. Par défaut ces bases de données ne sont pas fournies avec le setup de SQL Server 2008, 2008 R2 ou 2012. Vous pouvez les récupérer sur Codeplex sur cette page 🙂

Catégories :.Net, Outils
%d blogueurs aiment cette page :