1. Traduction▲
Cet article est la traduction la plus fidèle possible de l'article original : Creating Page Layouts with View Master Pages
2. Introduction▲
Le but de cet article est d'expliquer comment passer des données d'un Controller à une View Master Page. Pour cela, nous allons examiner deux stratégies. Premièrement, nous allons voir une solution facile, mais qui a pour inconvénient de rendre notre application difficilement maintenable. Ensuite, nous allons voir une meilleure solution qui demande un peu plus de travail au début mais qui donne une application plus facilement maintenable.
3. Le problème▲
Imaginez que vous vouliez créer une application affichant des films, et que vous vouliez afficher la liste des catégories sur chaque page de votre application (voir ci-dessous). Imaginez de plus que la liste des films soit stockée dans une base de données. Dans ce cas, il serait logique de récupérer la liste à partir de la BDD et de l'afficher dans une View Master Page.
Ici se trouve le problème. Comment récupérer la liste des catégories dans la Master Page? Il est tentant d'appeler des méthodes de votre Model MVC dans la Master Page directement. En d'autres mots, il est tentant d'inclure du code pour retrouver les données de notre DBB dans notre Master Page. En revanche, contourner votre Controller MVC pour accéder à une BDD violerai la séparation des modèles qui est l'un des gros avantages des applications MVC.
Dans une application MVC, vous voulez que l'interaction entre les Views MVC et votre Model MVC soit réalisée par vos Controllers MVC. Cette séparation conduit à une application plus facilement maintenable, adaptable et testable.
Dans une application MVC; toutes les données passées à une View - View Master Page comprise - doivent passer par un Controller. Nous allons examiner deux méthodes afin de passer des données à un View Master Page.
4. La solution simple▲
Commençons par la solution la plus simple. Elle consiste à passer les données pour notre Master Page dans chaque action de chaque Controller.
Imaginons le Controller ci-dessous. Il expose deux actions nommées Index() et Details(). L'action Index() retourne chaque film dans notre BDD. L'action Details() retourne chaque film dans une catégorie particulière.
using
System.
Linq;
using
System.
Web.
Mvc;
using
MvcApplication1.
Models;
namespace
MvcApplication1.
Controllers
{
[HandleError]
public
class
HomeController :
Controller
{
private
MovieDataContext _dataContext =
new
MovieDataContext
(
);
///
<
summary
>
/// Show list of all movies
///
<
/summary
>
public
ActionResult Index
(
)
{
ViewData[
"categories"
]
=
from
c in
_dataContext.
MovieCategories
select
c;
ViewData[
"movies"
]
=
from
m in
_dataContext.
Movies
select
m;
return
View
(
);
}
///
<
summary
>
/// Show list of movies in a category
///
<
/summary
>
public
ActionResult Details
(
int
id)
{
ViewData[
"categories"
]
=
from
c in
_dataContext.
MovieCategories
select
c;
ViewData[
"movies"
]
=
from
m in
_dataContext.
Movies
where
m.
CategoryId ==
id
select
m;
return
View
(
);
}
}
}
Notez que les deux actions ajoutent deux items à la View Data. L'action Index() ajoute deux clés : categories et movies. La clé categories représente la liste des catégories affichée dans la View Master Page. La clé movies représente la liste des films affichée dans la View Page Index.
L'action Details() ajoute également deux clés nommées categories et movies. La clé categories représente, une fois de plus, la liste des catégories affichée dans la View Master Page. La clé movies représente la liste des films dans une catégorie particulière affichée dans la View Page Details (voir ci-dessous).
La View Index contient le code ci-dessous. Une simple itération sur la liste des films.
<%
@ Page Title=
""
Language=
"C#"
MasterPageFile=
"~/Views/Shared/Site.Master"
AutoEventWireup=
"true"
CodeBehind=
"Index.aspx.cs"
Inherits=
"MvcApplication1.Views.Home.Index"
%>
<%
@ Import Namespace=
"MvcApplication1.Models"
%>
<asp:Content ID
=
"Content1"
ContentPlaceHolderID
=
"ContentPlaceHolder1"
runat
=
"server"
>
<ul>
<%
foreach (
var m in
(
IEnumerable<
Movie>
)ViewData["movies"
])
{ %>
<li><%
=
m.Title
%></li>
<%
} %>
</ul>
</asp:Content>
La View Master Page contient le code ci-dessous. Elle itère et affiche toutes les catégories.
<%
@ Master Language=
"C#"
AutoEventWireup=
"true"
CodeBehind=
"Site.Master.cs"
Inherits=
"MvcApplication1.Views.Shared.Site"
%>
<%
@ Import Namespace=
"MvcApplication1.Models"
%>
<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
>
<html xmlns
=
"http://www.w3.org/1999/xhtml"
>
<head id
=
"Head1"
runat
=
"server"
>
<title></title>
<asp:ContentPlaceHolder ID
=
"head"
runat
=
"server"
>
</asp:ContentPlaceHolder>
</head>
<body>
<div>
<h1>
My Movie Website</h1>
<%
foreach (
var c in
(
IEnumerable<
MovieCategory>
)ViewData["categories"
])
{%>
<%
=
Html.ActionLink
(
c.Name
, "Details"
, new
{id=
c.Id
} ) %>
<%
} %>
<asp:ContentPlaceHolder ID
=
"ContentPlaceHolder1"
runat
=
"server"
>
</asp:ContentPlaceHolder>
</div>
</body>
</html>
Toutes les données sont passées à notre View et View Master Page à travers notre View Data.
Donc, qu'est-ce qui ne va pas avec cette solution ? Le problème est qu'il viole le principe DRY (Don't Repeat Yourself). Chaque action de tous les Controllers doivent ajouter la même liste de catégorie à la View Data. Avoir du code dupliqué dans votre application la rend difficilement maintenable, adaptable et modifiable.
5. La bonne solution▲
Dans cette partie, nous allons voir une meilleure solution pour passer des données à partir d'un Controller jusqu'à une View Master Page. Au lieu d'ajouter les catégories pour la Master Page dans chaque Controller, nous n'allons l'ajouter à notre View Data qu'une seule fois. Toutes les View Data utilisées par notre Master Page sont ajoutées dans notre Controller Application.
using
System.
Linq;
using
System.
Web.
Mvc;
using
MvcApplication1.
Models;
namespace
MvcApplication1.
Controllers
{
public
abstract
class
ApplicationController :
Controller
{
private
MovieDataContext _dataContext =
new
MovieDataContext
(
);
public
MovieDataContext DataContext
{
get
{
return
_dataContext;
}
}
public
ApplicationController
(
)
{
ViewData[
"categories"
]
=
from
c in
DataContext.
MovieCategories
select
c;
}
}
}
Il y a trois choses que vous devez noter à propos de ce code. Premièrement, la classe hérite de System.Web.Mvc.Controller. Le Controller Application est un Controller.
Deuxièmement, le Controller Application est une classe abstraite. Une classe abstraite est une classe qui doit être implémentée par une autre classe. Parce que le Controller Application est une classe abstraite, vous ne pouvez pas appeler les méthodes définies dans la classe directement. Si vous essayez d'appeler la classe Application directement, vous obtiendrais une erreur Resource Cannot Be Found.
Troisièmement, notez que le Controller Application contient un constructeur qui ajoute la liste des catégories au View Data. Chaque Controller qui hérite du Controller Application appelle son constructeur automatiquement. Chaque fois que vous appelez une action d'un Controller qui hérite du Controller Application, la liste des catégories sera automatiquement ajoutée au View Data.
using
System.
Linq;
using
System.
Web.
Mvc;
namespace
MvcApplication1.
Controllers
{
public
class
MoviesController :
ApplicationController
{
///
<
summary
>
/// Show list of all movies
///
<
/summary
>
public
ActionResult Index
(
)
{
ViewData[
"movies"
]
=
from
m in
DataContext.
Movies
select
m;
return
View
(
);
}
///
<
summary
>
/// Show list of movies in a category
///
<
/summary
>
public
ActionResult Details
(
int
id)
{
ViewData[
"movies"
]
=
from
m in
DataContext.
Movies
where
m.
CategoryId ==
id
select
m;
return
View
(
);
}
}
}
Le Controller Movies, comme le Controller Home vu un peu plus haut, expose deux actions, Index() et Details(). Notez que la liste des catégories affichée par la View Master Page n'est ni ajoutée dans Index() ni dans Details(). Parce que ce Controller hérite du Controller Application, la liste est automatiquement ajoutée au View Data.
Notez que cette solution ne viole pas le principe DRY (Don't Repeat Yoursel). Le code pour ajouter la liste des catégories au View Data se trouve à un seul endroit : le constructeur du Controller Application.
6. Conclusion▲
Dans cet article, nous avons vu deux approches pour passer des données d'un Controller à une View Master Page. Dans la première section, nous avons vu comment ajouter des données au View Data, pour notre View Master Page dans chaque Controller. Nous avons vu que ceci était une mauvaise approche puisqu'il violait le principe DRY (Don't Repeat Yoursel).
Ensuite, nous avons vu une meilleure stratégie pour ajouter des données pour notre View Master Page à notre View Data. Au lieu de le faire dans chaque Controller, nous le faisons une seule fois dans le Controller Application. Cette façon de faire évite la duplication de code pour passer des données à une View Master Page dans une application ASP.NET MVC.