Archive

Posts Tagged ‘ChildActionOnly’

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 : , , ,
%d blogueurs aiment cette page :