0% ont trouvé ce document utile (0 vote)
20 vues137 pages

MVC4 Razor V2

Le document présente la programmation web avec MVC4 et Razor, en expliquant la philosophie MVC et la syntaxe de Razor pour intégrer du code C# dans des pages HTML. Il décrit comment mettre en place des contrôleurs, des vues et des modèles, ainsi que la gestion des formulaires pour l'édition et la validation des données. Enfin, il aborde les liaisons entre contrôleurs, modèles et vues pour une application web dynamique.

Transféré par

richezatr
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PPT, PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
20 vues137 pages

MVC4 Razor V2

Le document présente la programmation web avec MVC4 et Razor, en expliquant la philosophie MVC et la syntaxe de Razor pour intégrer du code C# dans des pages HTML. Il décrit comment mettre en place des contrôleurs, des vues et des modèles, ainsi que la gestion des formulaires pour l'édition et la validation des données. Enfin, il aborde les liaisons entre contrôleurs, modèles et vues pour une application web dynamique.

Transféré par

richezatr
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PPT, PDF, TXT ou lisez en ligne sur Scribd

MVC4 RAZOR

Wilfart Emmanuel
Programmation WEB
3ième informatique
Introduction
 La philosophie MVC
Introduction
 Le moteur de vue RAZOR
Dans la partie ASP.NET (WebForms), nous avons abordé l'existence du style
imbriqué sous la forme suivante

<!DOCTYPE html>
<%@ Page Language="C#" %>
<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<title>Ma premiere application en asp.net</title>
</head>
<body>
<h1>ceci est ma page ecrite en asp.net</h1>
<% Response.Write("ceci est du code imbriqué"); %>
<br>
La date d'aujoud'hui est: <% =System.DateTime.Now %>
</body>
</html>
Introduction
 Le moteur de vue RAZOR
RAZOR apporte une autre syntaxe plus claire et plus simple à mettre en
oeuvre dans une page HTML

<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>title>Ma premiere application en MVC Razor</title>
</head>
<body>
<div>
<h1>ceci est ma page ecrite en asp.net MVC Razor</h1>
@Html.Raw("ceci est du code imbriqué")<br/>
La date d'aujoud'hui est: @System.DateTime.Now
</div>
</body>
</html>
Syntaxe de Razor
 Les instructions uniques
L'exemple précent La date d'aujoud'hui est: @System.DateTime.Now
correspond à une instruction unique. Elle est précédée du symbole @.
Chaque instruction doit être précédée de ce symbole.

 Les blocs de code


Un bloc de code débute par les symboles @{ et se termine par le symbole }
Le code écrit dans ce bloc respectera la syntaxe du C# ou celle du VB.NET.
Dans le cas du C#, les intructions se termineront par un ;
Razor supporte la plupart des structures conditionnelles utilisables dans le C#

@{ var WelcomMsg = "bienvenue";


var weekDay = DateTime.Now.DayOfWeek;
var DisplayMsg = WelcomMsg + " Nous sommes le: " + weekDay; }
<h2>Message: @DisplayMsg</h2>
Syntaxe de Razor
 Les instructions de boucle
 Instruction foreach
@{
string[] Courses = {"Csharp", "Linux", "Advanced Network"};
}
<ul>
@foreach (var course in @Courses)
{
<li>@course</li>
}
</ul>
Syntaxe deRazor
 Les instructions de boucle
 Instruction for
@{
string[] Courses = {"Csharp", "Linux", "Advanced Network"};
}
<ul>
@for (int i = 0; i < @Courses.Length;i++ )
{
<li>@Courses[i]</li>
}
</ul>
Syntaxe de Razor
 Les instructions de boucle
 Instruction while
@{
string[] Courses = {"Csharp", "Linux", "Advanced Network"};
}
<ul>
@{
int i=0;
while(i < @Courses.Length)
{
<li>@Courses[i]</li>
i++;
}
}
</ul>
Syntaxe de Razor
 Les instructions de contrôle
 Instruction if (else)
@{
float[] Points = { 10, 8, 15, 13, 9 };
}
<ul>
@foreach (var point in @Points)
{
<li>@point/20
@if (@point<10)
{
<span>en echec</span>
}
</li>
}
</ul>
Syntaxe de Razor
 Les instructions de contrôle
 Instruction switch
@{ string[] Evals = { "A", "B", "C", "E", "A" }; }
<ul>
@foreach (var eval in @Evals) { <li>
@switch(@eval)
{
case "A":
<span>Excellent</span>
break;
case "D":
<span>Passable</span>
break;
case "E":
<span>Echec</span>
break;
} </li> } </ul>
Syntaxe de Razor
 Le contenu statique
Dans un bloc de code, il est parfois nécessaire de placer du texte qui sera
reproduit tel quel sur le flux de sortie en HTML.

@{
Debut de ma page
var WelcomMsg = "bienvenue";
var weekDay = DateTime.Now.DayOfWeek;
var DisplayMsg = WelcomMsg + " Nous sommes le: " + weekDay;

}
Cette syntaxe produira un erreur. Pour éviter cette erreur, il suffit de
placer ce texte dans un conteneur
@{
<text>Debut de ma page</text>
}
Syntaxe de Razor
 Le contenu statique
Une autre syntaxe consiste à utiliser les symboles @: en début de texte

@{
@:Debut de ma page
}

 Les commentaires
Tout bloc de code peut contenir des commentaires qui seront placés
entre les symbôles suivants @* et *@

@{
@* commentaire *@
}
Accès à la vue
 Mise en place d'un contrôleur

L'accès à la vue passe obligatoirement par un contrôleur qui recevra la


requête en provenance du navigateur
Accès à la vue
 Mise en place d'un contrôleur

Le contrôleur ajouté devra posséder un nom, dans notre cas, Home,


postfixé du mot controller. Nous envisagerons en l'absence de modèle, le
choix d'un contrôleur MVC vide.
Accès à la vue
 Mise en place d'un contrôleur
Une fois le contrôleur ajouté, nous pouvons éditer le fichier correspondant et
nous obtenons alors le contenu d'écran suivant

public class HomeController : Controller


{
public ActionResult Index()
{
return View();
}
}

Dans le controleur, nous retrouvons une action associée Index() qui


correspondra à la vue portant le même nom. Il nous suffit de créer
maintenant la vue Index dans le dossier Home (nom du contrôleur)
Accès à la vue
 Mise en place de la vue
Dans le dossier vue, il faudra ajouter le dossier Home dans lequel nous
placerons la vue Index

Le fichier Index.cshtml sera alors créé correspondant à la page HTML


Accès à la vue
 Mise en place du routage
L'utilisateur n'accède pas directement à une page mais l'URL renseignée
pointe vers une ressource qui devra correspondre à un contrôleur et une
action. C'est le rôle du routage de faire correspondre la requête générée
par le client à un contrôleur/action et des paramètres optionnels dont nous
parlerons par la suite
Dans app_start, nous retrouvons le fichier RouteConfig.cs

routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id =
UrlParameter.Optional }
);

http://localhost/Home/Index ou http://localhost/
Mise en place d'un modèle
 Introduction
Dans la partie précédente propre à la vue, nous avons vu comment insérer du
code Razor C# dans une page HTML. La grand majorité des applications WEB
doivent cependant présenter des données extraites d'une source externe. Elles
doivent être modifiables et d'éventuelles nouvelles données doivent pouvoir
être ajoutées.
MVC offre la possibilité de transmettre des données du contrôleur vers une vue
pour le rendu tandis que les données seront transmises de la vue au contrôleur
lors de l'édition. Les données seront représentées sous forme d'un modèle
Nous allons à titre d'exemple mettre en place deux classes, l'une représentant
les caractéristiques d'un livre dans une librairie et l'autre la librairie.
Mise en place d'un modèle
 Introduction
public class Livre {
public int ID { get; set; }
public string Titre { get; set; }
public string Editeur { get; set; }
public string Genre { get; set; } }

La librairie respectera le pattern CRUD (Create, Retreive, Update et Delete)


Mise en place d'un modèle
 Introduction
public void InitLibrairie() {
this.Add(new Models.Livre {
ID = 1,
Titre = "Csharp Facile",
Genre = "Education",
Editeur = "Wilfart"});

public Livre Select(int id) {


Livre livre = null;
livre = this.Find(x => x.ID == id);
return livre; }

public List<Livre> Select()


{
return this;
}
Lien Contôleur-Modèle-Vue
 Contrôleur Home - Action Index
public Models.Librairie MyLib;
public HomeController()
{
MyLib = new Models.Librairie();
}
public ActionResult Index()
{
return View(MyLib.Select());
}

L'action Index permet de retourner un ActionResult qui sera une énumération


des livres présents dans la librairie.
Lien Contôleur-Modèle-Vue
 Contrôleur Home - Action Detail
public Models.Librairie MyLib;
public HomeController()
{
MyLib = new Models.Librairie();
}
public ActionResult Details(int id)
{
return View(MyLib.Select(id));
}

L'action Index permet de retourner un ActionResult qui sera une énumération du


livre présent dans la librairie et ayant l'id passé en argument.
Lien Contôleur-Modèle-Vue
 Liaison Vue Index - Model (récupéré du controleur)
<table>
<tr>
<td>Titre</td>
<td>Détails</td>
</tr>
@foreach (var livre in Model)
{
<tr>
<td>@livre.Titre</td>
<td><a href="/Home/Details/@livre.ID.ToString()">detail</a></td>
</tr>
}
</table>

Le controleur retourne une collection de livres parcourue par l'instruction foreach.


Pour chaque item, on accède au titre et à l'ID pour le lien
Lien Contôleur-Modèle-Vue
 Liaison Vue Index - Model (récupéré du controleur)
<tr>
<td>Csharp Facile</td>
<td><a href="/Home/Details/1">detail</a></td>
</tr>
<tr>
<td>Linux Facile</td>
<td><a href="/Home/Details/2">detail</a></td>
</tr>
<tr>
<td>Asp.Net Facile</td>
<td><a href="/Home/Details/3">detail</a></td>
</tr>

La configuration des ancrages respecte bien les informations de routage sous la


forme: url: "{controller}/{action}/{id}"
Lien Contôleur-Modèle-Vue
 Liaison Vue Details - Model
<div>
<h3>Titre du livre</h3>
@Model.Titre
<h3>Genre du livre</h3>
@Model.Genre
<h3>Editeur</h3>
@Model.Editeur
</div>

Le controleur retourne un livre. Nous pouvons directement accéder au titre, au


genre et à l'éditeur en passant par l'object Model
Lien Contôleur-Modèle-Vue
 Html-Helper et les liens
Comme nous pouvons le constater, la mise en place d'un lien est plus compliqué.
C'est une des raisons de la présence d'un générateur de code html qui sur base de
la syntaxe suivante, simplifiera le code.

<td><a href="/Home/Details"/@livre.ID>Details</a></td>
<td>@Html.ActionLink("Details","Details",new {id=livre.ID})</td>

Le générateur de code HTML offre encore plus de possibilités notamment dans


la création des formuliaires abordés ci après.
Les formulaires
 Introduction

Les formulaires offrent la possibilité d'éditer des données en vue de les modifier
ainsi que celle d'ajouter une nouvelle donnée.
Nous retrouverons donc une vue spécifique à ce formulaire, les actions associées
dans le contrôleur mais aussi les méthodes associées dans le modèle pour
l'insertion ou l'ajout d'un nouvel enregistrement dans la source de données.
Nous allons donc créer la vue Edit avec l'action correspondante Edit comprenant
l'argument de l'enregistrement qui doit être éditer.
Les formulaires
 Edition des données - Lien dans la page d'index
@foreach (var livre in Model)
{
<tr>
<td>@livre.Titre</td>
<td><a href="/Home/Details/@livre.ID">Details</a></td>
<td>@Html.ActionLink("Edit","Edit",new {id=livre.ID})</td>
</tr>
}

Nous retrouvons l'HTML Helper Action link reprenant l'action Edit avec
comme paramètre l'identifiant du livre. L'action Edit permettra de démarrer
la vue Edit avec comme model l'objet Livre associé à la sélection faite dans la
page d'index
Les formulaires
 Edition des données - Appel de l'action
public ActionResult Edit(int? id)
{
if (id != null)
{
Models.Livre livre = MyLib.Select(id.Value);
return View(livre);
}
return View("Index",MyLib.Select());
}

Si aucun argument n'est renseigné, l'id aura la valeur null. Pour acepter cette
valeur, il faudra le renseigner au niveau de l'argument de la fonction int? id
Si l'id n'est pas null, nous retrournons vers la vue Edit le livre correspondant
Les formulaires
 Edition des données - Liaison de la vue au modèle
<form method="post" action="/Home/Update">
<input id="Uid" name="ID" type="hidden" value="@Model.ID" />
<span class="label">Titre:</span><input id="Titre" name="Titre"
type="text" value="@Model.Titre" /><br />
<span class="label">Editeur:</span><input id="Editeur"
name="Editeur" type="text" value="@Model.Editeur" /><br />
<span class="label">Genre:</span><input id="Genre" name="Genre"
type="text" value="@Model.Genre" /><br />
<input type="submit" value="valider" />
</form>

<form method="post" action="/Home/Update"> correspond à la technique


classique HTML de gestion des formulaires. Le formulaire sera envoyé par la
méthode post vers l'url /Home/Update
value="@Model.Titre" Chaque zone d'édition aura un attribut name
correspondant au nom du champ de l'enregistrement tandis que la valeur
sera récupérée du modèle fourni par le contrôleur.
Les formulaires
 Mise à jour des données - Modèle
public void UpdateLivre(Livre tmp)
{
Livre Mod = Select(tmp.ID);
Mod.Titre = tmp.Titre;
Mod.Genre = tmp.Genre;
Mod.Editeur = tmp.Editeur;
}

Cette méthode reçoit un livre en argument permettant d'effectuer une mise à


jour de la source de données du livre ayant l'identifiant correspondant
Les formulaires
 Mise à jour des données - Action Update
public ActionResult Update(int? id)
{
if (id != null)
{
Models.Livre test = new Models.Livre();
UpdateModel<Models.Livre>(test);
MyLib.UpdateLivre(test);
return View("edit",test);
}
return View("Index", MyLib.Select());
}

L'utilisation de UpdateModel permet de mettre à jour un objet de type Livre


dont les valeurs sont récupérées du formulaire. L'action Update n'a pas de
vue correspondante. Nous devrons donc renseigner cette vue de la façon
suivante: return View("edit",test);
Les formulaires
 Validation des données

Un formulaire n'est pas aussi simple. Il va nécessiter que certains champs soient
obligatoires, que certains champs soient contrôlés avec un double encodage tel
que la confirmation d'une adresse mail par exemple, que des champs soient
validés par des expressions régulières et finalement validés éventuellement côté
serveur. MVC Razor met en place des mécanismes grace au HTML helper.
Reprenons notre code et adaptons le pour utiliser ce mécanisme de génération
automatique d'HTML.
Les formulaires
 Validation des données Attributs du côté Model

public class Livre


{
[HiddenInput]
public int ID { get; set; }
[Display (Name = "Titre")]
[Required (ErrorMessage="Le {0} est requis")]
[StringLength(100)]
public string Titre { get; set; }
[Display(Name = "Editeur")]
[StringLength(100)]
public string Editeur { get; set; }
[Display(Name = "Genre")]
[StringLength(100)]
public string Genre { get; set; }
}
Les formulaires
 Liste des attributs disponibles

HiddenInput ex: [HiddenIput]


Permet d'indiquer que le champ HTML généré doit être caché
Display ex: [Display (Name = "Titre")]
Spécifie le nom affiché comme label pour un champ.
DataType ex: [DataType (DataType.MultilineText)]
Spécifie le format d'affichage pour le champ.
DisplayFormat ex:[DisplayFormat (DataFormatSring = "{0:C}")]
Spécifie le format d'affichage pour le champ.
Required ex: [Required]
Indique qu'un champ est obligatoire.
ReqularExpression ex: [RegularExpression ("^0[1-68][0-9]{8}$")]
Expression régulière permettant de valider la structure du texte du champ
Les formulaires
 Liste des attributs disponibles
Range ex: Range(0, double.MaxValue)
Valide la valeur d'un champ dans une plage de valeurs données.
Compare ex: [Compare ("Email")]
Valide le contenu du champ avec le contenu d'un autre.
StringLength ex: [StringLength(100, MinimumLength = 5)]
Spécifie le nombre de caractères maximum et minimum accepté dans le champ
Remote ex: [Remote ("Valider","index",AdditionalFields = "ID")]
Cet appel se fait via une requête GET en Ajax, l'action appelée devant retourner
un booléen sous la forme JSON

Les attributs de validation peuvent se voir affecter un message d'erreur


personnalisé sous la forme suivante: [Required (ErrorMessage="Le {0} est
requis")]
Les formulaires
 Attribut remote avec action (AJAX - JSON)

Un exemple simple est par exemple l'enregistrement d'un utilisateur avec le choix
laissé à l'utilisateur de prendre un identifiant unique.
Il faut pouvoir avertir l'utilisateur que l'identifiant est déjà utilisé ou pas. Pour ce
faire, la vérification doit se faire du côté serveur via un accès à la base de données.
Les routes
 les paramètres dans les routes
Dans un des exemples précédents, nous avions les configurations suivantes.

routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id =
UrlParameter.Optional });

public ActionResult Details(int id)


{
Models.Livre livre = MyLib.Select(id);
return View(livre);
}

<a href="/Home/Details/2">Details</a>
Les routes
 les paramètres dans les routes
Si nous prenons l'url du mappage et celle du lien hypertexte, nous retrouvons
une similitude

href="/Home/Details/2"
url: "{controller}/{action}/{id}"

Le controleur est bien associé à Home


L'action est bien associée à Détails
Le paramètre correspondra à la valeur 2

Dans le controleur HomeController, nous retrouvons bien l'action ( la méthode)


Details qui aura la structure suivante
public ActionResult Details(int id) {
Models.Livre livre = MyLib.Select(id);
return View(livre); }

Le paramètre dans l'URL est récupéré par l'argument de la méthode


Les routes
 Paramètre optionnel
Une route peut être associée à plusieurs vues dont certaines ne nécessitent pas
d'argument et d'autres oui. La vue Index ne réclame pas d'argument tandis que
la vue Details réclame un argument. Ces deux vues peuvent être validées par la
même route

routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id =
UrlParameter.Optional });

Les deux URL suivantes seront validées par la même route:

http://localhost/Home/Index
et
http://localhost/Home/Details/2
Les routes
 Paramètre optionnel

Prenons le cas de ces deux URLS correspondant à la même action:

http://localhost/Home/Details/2
et
http://localhost/Home/Details

Dans un cas, l'argument devra récupérer un entier tandis que dans le second
cas, l'argument aura la valeur nulle.

Soit nous définissons deux actions avec le même nom mais l'un sans argument
et l'autre avec un argument, soit nous définissons une même action acceptant
un argument null
Les routes
 Paramètre optionnel

public ActionResult Details(int? id) {


if (id != null) {
Models.Livre livre = MyLib.Select(id.value);
return View(livre); }
return View("Index"); }

public ActionResult Details(int id) { ... }


et
public ActionResult Details() { ... }
Les routes
 Valeur par défaut
On peut imaginer que, dans le cas de la vue Details de l'exercice précédent, si
aucun choix n'est fait, ce soit la fiche d'id 1 qui soit affichée.

routes.MapRoute(
name: "Details",
url: "Details/{id}",
defaults: new { controller = "Home", action = "Details", id=1 });

L'URL mappée par cette route pourrait être:

http://localhost/Details
Les routes
 Paramètres multiples - Multiples segments
Un exemple de paramètres multiples pourrait être:

routes.MapRoute(
name: "Details",
url: "Details/{langue}/{id}",
defaults: new { controller = "Home", action = "Details", id=1 });

Si un paramètre par défaut doit être défini, il est préférable qu'il soit placé en
dernière position. Nous entendons par segment, le paramètre identifié par les
séparateurs '/'
Les routes
 Paramètres multiples - Segment unique
Un exemple de paramètres multiples pourrait être:

routes.MapRoute(
name: "Details",
url: "Details/{langue}/{idA}-{idB}",
defaults: new { controller = "Home", action = "Details"});

Il faudra choisir un caractère de séparation permettant d'identifier dans un même


segment les différents paramètres. Nous avons choisi dans notre exemple le
caractère '-'
Les routes
 Paramètres, les contraintes
Imaginons une page de recherche permettant de fixer comme critères la date et
le mois de l'édition. Nous imaginerons une URL suivante:
http://localhost/Recherche/1998/12/
Nous imposerons une contrainte sur les deux segments devant être numérique.

routes.MapRoute(
name: "Recherche",
url: "Recherche/{annee}/{mois}/",
defaults: new { controller = "Home", action = "Recherche" },
constraints: new
{
annee = @"\d{4}",
mois = @"\d{2}"
} );
Les routes
 Routes vers une page WebForms
Cette possibiluté est offerte pour passer à MVC4 Razor en conservant
d'anciennes parties du site qui sont en Asp.Net WebForms

routes.MapPageRoute(
routeName: "Route Legacy",
routeUrl: "Commande",
physicalFile: "Commande.aspx",
default: new RouteValueDictionnary ()
{
{ "id", "1" }
},
checkPhysicalUrlAccess: true
);
Les actions
 Le retour d'exécution d'une action
Jusqu'à présent, nous avons utilisé la syntaxe suivante pour retourner une vue
dans la déclaration de la méthode d'action... return View(...);
Nous retrouvons également les retours d'objects suivants nécessitant donc une
instanciation avec l'opérateur new. Toutes les classes dérivent de la classe
Actionesult

 EmptyResult
 HttpStatusCodeResult - HttpNotFoundResult - HttpUnauthorizedResult
 RedirectResult
 RedirectToRouteResult
 JavascriptResult
 JsonResult
 FileResult
 ViewResultBase - ViewResult - PartialViewResult
Les actions
 EmptyResult
Le code HTTP de retour correspond bien à 200 mais la page renvoyée est vide

public ActionResult Recherche(int annee, int mois)


{
return new EmptyResult();
}

 HttpStatusCodeResult
Ce retour correspond en général à un code d'erreur HTTP (ressource on trouvée,
accès non authorisé ). Exemple d'accès à un livre n'existant pas

Models.Livre livre = MyLib.Select(id.Value);


if (livre == null) return new HttpStatusCodeResult(HttpStatusCode.NotFound);
else return View(livre);
Les actions
 RedirectResult
Le code HTTP de retour correspondra à une redirection vers une autre page
envoyée vers le client (code 301 pour une redirection permanente ou 302 pour
une redirection temporaire)

return new RedirectResult("http://www.google.be");

 RedirectToRouteResult
Le code HTTP de retour correspondra à une redirection vers une autre route.
L'URL associée sera envoyée vers le client (code 301 pour une redirection
permanente ou 302 pour une redirection temporaire)

return new RedirectToRouteResult("Details", new RouteValueDictionary()


{
{"id",1}
});
Les actions
 FileResult
Cette classe est abstraite dont dérive les trois classes suivantes:
FileContentResult (tableau de bytes), FilePathResult (chemin physique) et
FileStreamResult ( flux).
Ces classes peuvent être utilisées au travers de la méthode File du contrôleur

public ActionResult GetImage(Guid id)


{
bibliothequeEntities db = new bibliothequeEntities();
var livre = db.livres.Find(id);
return new FileContentResult(livre.image, "image/jpeg");
}

L'image est récupérée sous forme d'un tableau de byte de la db et retournée


avec un type mime "image/jpeg". La dernière ligne de code peut être
remplacée par return File(livre.image, "image/jpeg");
Les actions
 FileResult
Cette classe est abstraite dont dérive les trois classes suivantes:
FileContentResult (tableau de bytes), FilePathResult (chemin physique) et
FileStreamResult ( flux).
Ces classes peuvent être utilisées au travers de la méthode File du contrôleur

public ActionResult GetImage(Guid id)


{
bibliothequeEntities db = new bibliothequeEntities();
var livre = db.livres.Find(id);
return new FileContentResult(livre.image, "image/jpeg");
}

L'image est récupérée sous forme d'un tableau de byte de la db et retournée


avec un type mime "image/jpeg". La dernière ligne de code peut être
remplacée par return File(livre.image, "image/jpeg");
Les actions
 Stockage d'une image dans une db
Pour dupliquer le test précédent, il est nécessaire d'uploader une image dans la
db sous forme d'un tableau de byte. Nous retrouverons le formulaire
@using (Html.BeginForm("FileUpload", "Home", FormMethod.Post, new
{ enctype = "multipart/form-data" }))
{
<fieldset>
<legend>Upload a file</legend>
<div class="editor-field">
@Html.TextBox("file", "", new { type = "file" })
</div>
<div class="editor-field">
<input type="submit" value="Upload" />
</div>
</fieldset>
}
Les actions
 JsonResult
Des données au format Json peuvent être envoyées vers un action via Ajax.
L'action pourra retrourner un résultat dans le même format vers une fonction
javascript.
Reprenons notre gestion de bibliotheque avec la gestion d'un caddy . Il est clair
que l'envoi d'un livre dans le caddy stocké coté serveur ne se fera pas en postant
à chaque fois l'entierté du formulaire. Nous utiliserons un envoi asynchrone

<td><input type="button" value="ajouter"


onclick="@(Html.Raw(String.Format("AddToCart({0})",
livre.ID)))"/></td>

Dans le code HMTL généré, nous obtiendrons


<td>Csharp Facile</td>
<td><a href="/Home/Details/1">Details</a></td>
<td><a href="/Home/Edit/1">Edit</a></td>
<td><input type="button" value="ajouter"
onclick="AddToCart(1)"/></td>
Les actions
 JsonResult
La fonction javascript AddToCart permettra l'envoi de l'article commandé vers
une action d'un contrôleur de façon asynchrone
function AddToCart(id) {
var dataString = { itemid: id };
$.ajax({
type: "POST",
url: "home/AddToCart",
data: dataString,
cache: false,
dataType: "json",
success: UpdateCart });
return false; }
function UpdateCart(data) {
alert(data.count); }

url: "home/AddToCart" correspond à l'action AddToCart du contrôleur home


dataType: "json" envoi des données au format json
Les actions
 JsonResult
L 'action récupère les données en ayant soin de choisir un paramètre possédant
le même nom que la variable dans le format Json
public ActionResult AddToCart(string itemid)
{
return Json(new { count = 1 });
}

La fonction javascript appelée en cas de succès récupére alors la donnée


transmise
function UpdateCart(data)
{
alert(data.count);
}
Les actions
 ViewResultBase - ViewResult - PartialViewResult
L 'instanciation des deux classes ViewResult et PartialViewResult est simplifiée
grâce aux méthodes View et PartialView présentes dans la classe controller .
Avant d'aborder les actions retournant des vues partielles, nous aborderons les
vues partielles elles-mêmes.
Les vues partielles sont l'équivalent des UserControl en Asp.Net WebForms
Reprenons notre vue Index.cshtml et adaptons la pour utiliser les vues partielles

@foreach (var livre in Model) {


<table style="border:1px solid black;width:200px;margin:5px;">
<tr>
<td rowspan="4"><img style="width:50px"
src="~/images/castagnettes.png" /></td>
</tr>
<tr> <td>Titre:@livre.Titre</td> </tr>
<tr> <td>Genre:@livre.Genre </td> </tr>
<tr> <td>Editeur:@livre.Editeur</td> </tr>
</table> }
Les actions
 ViewResultBase - ViewResult - PartialViewResult
Sur base du code précédent, nous créons notre vue partielle que nous
appellerons _livre.cshtml

@model MvcApplication3.Models.Livre

<table style="border:1px solid black;width:200px;margin:5px;">


<tr>
<td rowspan="4"><img style="width:50px"
src="~/images/castagnettes.png" /></td>
</tr>
<tr><td>Titre:@Model.Titre</td> </tr>
<tr><td>Genre:@Model.Genre </td></tr>
<tr> <td>Editeur:@Model.Editeur</td> </tr>
</table>
Les actions
 ViewResultBase - ViewResult - PartialViewResult
Dans la vue index.cshtml, nous pouvons maintenant intégrer la vue partielle de
la façon suivante

@foreach (MvcApplication3.Models.Livre livre in Model)


{
@Html.Partial("_livrepartial", livre);
}

Dans ce cas de figure, la vue partielle est intégrée dans la vue principale. Nous
pouvons placer cette vue dans une variable et la transmettre de façon
asynchrone au travers d'un mécanisme Ajax

La méthode @Html.Partial transmet le contenu de la vue sur le flot de réponse


La méthode @Html.RenderPartial permet de placer le contenu dans une
variable
Les actions
 ViewResultBase - ViewResult - PartialViewResult
Imaginons un bouton permettant l'envoi d'une requête Ajax vers une action
retournant une vue partielle. Le contenu html correspondant sera alors placé
dans une bloc DIV en utilisant le Jquery

<script type="text/javascript">
$(function() {
$('#ViewPartialBt').click( function() {
var datastring = { "itemid": 1 };
$.ajax({
url: '/Home/GetLib',
data: datastring,
dataType: 'html',
success: function(data) {
$('#partial').html(data); },
}); }); });
</script>
Les actions
 ViewResultBase - ViewResult - PartialViewResult
L'action GetLib définie dans le contrôleur Home retournera la vue partielle.

public ActionResult GetLib(int ? itemid)


{
Models.Livre livre = MyLib.Select(itemid.Value);
return PartialView("_livrepartial", livre);
}

La fonction Javascript sera appelée à la réception de la donnée html

success: function(data) {
$('#partial').html(data); },
La vue
 Dossier Shared - Layout
Dans l'explorateur de solution, nous retrouvons un dossier Shared qui contiendra
les éléments partagés entre les différentes vues tels que une vue partielle ou un
layout.
Chaque vue peut comprendre un lien vers un fichier de mise en page. Ce fichier
étant généralement global, il pourra être placé dans le fichier ViewStart.cshtml,
fichier analysé par l'ensemble des vues de l'application. Voici le contenu type de
ce fichier
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}

Il est également possible d'ajouter d'autres variables dans ce fichier, qui seront
alors effectives dans les autres vues. Tout Layout défini dans une vue
surchargera celui renseigné dans le fichier _ViewStart.cshtml. Dans la syntaxe
suivante, aucun Layout ne sera utilisé. @{ Layout=null;}
La vue
 Dossier Shared - Layout
<html> <head>
<meta charset="utf-8" />
<title>@Page.Title Mon application MVC</title>
<link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
<script src="@Url.Content("~/Scripts/jquery-2.1.1.min.js")"></script>
<script src="@Url.Content("~/Scripts/modernizr-2.7.2.js")"></script>
</head> <body>
<ul id="menu">
<li>@Html.ActionLink("Home", "Index", "Home")</li>
<li>@Html.ActionLink("About", "About", "Home")</li>
</ul>
<section id="main">
@RenderBody()
<p>Copyright HELHA 2014. All Rights Reserved.</p>
</section> </body></html>
La vue
 Dossier Shared - Layout
@RenderBody() correspond au rendu de la vue elle même. C'est à l'emplacement
de cette instruction que le contenu de la vue se trouve insérée. Dans notre
exemple, le Lauout comprend le menu et le pied de page avec le copyright. Voici
un exemple de contenue de vue

@{
Page.Title = "Home Page";
}
<div>
@foreach (MvcApplication3.Models.Livre livre in Model)
{
@Html.Partial("_livrepartial", livre);
}
</div>

Page.Title = "Home Page"; permet de définir une variable qui sera utilisée pour
paersonnaliser le Layout <title>@Page.Title Mon application MVC</title>
La vue
 ViewBag - ViewData
ViewBag et ViewData correspondent au même dictionnaire, accessible depuis le
contrôleur ou la vue et donc utile pour partager quelques données utiles
ViewBag représente la partie dynamique de ViewData.

Exemple: ViewBag.Title="Mon applicaion MVC" ou ViewData["Title"]="Mon


application MVC". Dans le contrôleur, nous auron par exemple

public ActionResult Index()


{
ViewBag.Title = "Mon application MVC";
return View(MyLib.Select());
}

Dans la partie Layout (également possible dans le partie vue)

<title>@Page.Title @ViewBag.Title</title>
La vue
 @Styles.Render et @Scripts.render
Ces instructions permettent d'inclure automatiquement un bundle dans une page.
Les bundles permettent de contourner la limite des navigateurs dans le nombre de
téléchargements parallèles (8 à 10). Des scripts et feuilles de style peuvent être
concaténés et fournis en une seule requête. Lors de la création d'une application
web de modèle "Application Internet", l assemblage nécessaire aux Bundles est
référencé: System.Web.optimization.dll
Dans le dossier App_start, nous retrouvons le fichier BundleConfig.cs dont voici un
exemple de contenu (limité)
public static void RegisterBundles(BundleCollection bundles) {
bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
"~/Scripts/jquery-{version}.js"));
bundles.Add(new ScriptBundle("~/bundles/jqueryui").Include(
"~/Scripts/jquery-ui-{version}.js"));
bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
"~/Scripts/jquery.unobtrusive*",
"~/Scripts/jquery.validate*")); /*....*/ }
La vue
 @Styles.Render et @Scripts.render
Dans le fichier Global.asax, la méthode Application_start comprendra notamment
le code suivant

protected void Application_Start()


{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
AuthConfig.RegisterAuth();
}
La vue
 @Styles.Render et @Scripts.render
Il suffira maintenant d'utiliser ces bundles au travers des deux syntaxes. Reprenons
le Layout généré automatiquement lors de la création d'un projet

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta charset="utf-8" />
<title>@ViewBag.Title - Mon application ASP.NET MVC</title>
<link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
<meta name="viewport" content="width=device-width" />
@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/modernizr")
</head>
La vue
 @RenderSection
RenderSection donne la possibilité de placer un contenu spécifique à une vue. On
peut imaginer inclure du code Javascript additionnelle uniquement utile dabs la
vue associée. Un paramètre Required permettra de préciser si la vue doit
obligatoirement définir cette section

@section MesScripts { <script type="text/javascript">


$(function () {
$('#ViewPartialBt').click(function () {
var datastring = { "itemid": 1 };
$.ajax({
url: '/Home/GetLib',
data: datastring,
dataType: 'html',
success: function (data) {
$('#partial').html(data);
},
}); });}); </script> }
La vue
 @RenderSection
<section id="main">
@RenderBody()
@RenderSection("MesScripts",false)
<p>Copyright HELHA 2014. All Rights Reserved.</p>
</section>

@RenderSection("MesScripts",false) false indique que la section "MesScripts"


n'est pas obligatoire dans la vue. De ce fait, ce Layout autorise les vues qui ne
comprenent pas cette section.
Le contrôleur
 Les filtres d'action
Un filtre d'action est un attribut que vous pouvez appliquer à une action d'un
contrôleur - ou un contrôleur entier - qui modifie la façon dont l'action est
exécutée. ASP.NET MVC comprend de façon native plusieurs filtres d'action tels
que ResultFilter, ExceptionFilter, AuthorizationFilter, AuthenticationFilter. A ces
filtres seront associés des attributs tels que par exemple
 OutputCache. Gestion de la cache de sortie pour Resultfilter
 HandleError. Cette attribut permet de spécifier que dans le cas d'une erreur non
capturée dans une action doit provoquer l'affichage de la page Error pour
Exceptionfilter
 Authorize. Ce filtre permet de restreindre les accès aux utilisateurs authentifiés
(tous, certains, ou ayant un rôle determiné) pour Authorizationfilter
 AllowAnonymous. Ce filtre permet d'autoriser les accès aux utilisateurs non
authentifiés pour AuthenticationFilter
Nous retrouvons également dans les filtres d'action, les
ActionMethodSelectorAttribute tels que HttpGet et HttpPost définisant le "verb"
autorisé pour l'accès à l'action concernée.
Le contrôleur
 Les filtres d'action - OutputCache
public class HomeController : Controller {
[OutputCache(Duration=10, VaryByParam="none")]
public ActionResult Index()
{
return View();
}}

Pour des questions de centralisation et donc de maintenance, nous pouvosn


également créer un profil de cache dans le fichier web.config
<caching> <outputCacheSettings> <outputCacheProfiles> <add
name="Cache1Hour" duration="3600" varyByParam="none"/>
</outputCacheProfiles> </outputCacheSettings> </caching>

[OutputCache(CacheProfile="Cache1Hour")] public string Index() { return


DateTime.Now.ToString("T"); }
Le contrôleur
 Les filtres d'action - OutputCache
Il y a d'autres options disponibles pouvant faire varier la sortie en cache. Nous
citerons notamment:

 VaryByContentEncoding
 VaryByCustom
 VaryByHeader
 Location

Nous pouvons également utiliser un SqlDependency pour invalider la cache


lorsque une donnée change au niveau de la base de données
Le contrôleur
 Les filtres d'action - Authorize - AllowAnonymous
L'accès à un site peut être public mais peut aussi comprendre certaines actions qui
ne pourront être accessible que si un utilisateur est authentifié

[Authorize]
public class AccountController : Controller
{
[AllowAnonymous]
public ActionResult Login() { // ... }
public ActionResult Index() { return View();}
}

Si une action est protégée par un attribut [Authorize], une redirection devra être
prévue vers une page de login pour permettre une authentification
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" timeout="2880"
defaultUrl="~/Home/Index"></forms></authentication>
Le contrôleur
 Les filtres d'action - Authorize - AllowAnonymous
L'action Login a été placée dans un autre controleur qui autorise par défaut les
accès anonymes. Une des actions login (reprise ci après) correspond au
chargement de la vue comprenant les demandes d'identifiant.

public ActionResult Login(string ReturnUrl)


{
ViewBag.ReturnUrl = ReturnUrl;
return View();
}

L'action Login de la dia suivante est celle correspondant à la récupération des


informations d'authentification et leur validation. Pour des question de sécurité,
cette action est limitée à une requête de type post
Le contrôleur
 Les filtres d'action - Authorize - AllowAnonymous
[HttpPost]
public ActionResult Login(User tempUser, string ReturnUrl) {
WPFTutorialEntities1 WPFUsers = new WPFTutorialEntities1();
if (ModelState.IsValid) {
int result = WPFUsers.ValidateUser(tempUser.UserName,
tempUser.Passwd).FirstOrDefault() ?? 0;
if (result==1) {
Session["User"] = tempUser;
FormsAuthentication.SetAuthCookie(tempUser.UserName, false);
if (ReturnUrl != null) return Redirect(ReturnUrl);
else return Redirect(FormsAuthentication.DefaultUrl); }
else {
ModelState.AddModelError("", "Log In Failed"); } }
else {
ModelState.AddModelError("", "Log In Failed"); }
return View(); }
Le contrôleur
 Les filtres d'action - HandleError
Nous allons générer une erreur dans une des actions présente dans le contrôleur
"Home". Voici le code à la base de l'erreur
public object TestError() {
throw new Exception("Une erreur est générée"); }

L'accès à cette action porvoquera l'affichage suivant


Le contrôleur
 Les filtres d'action - HandleError
Il faudra modifier le contenu du fichier web.config pour y insérer la configuration
suivante
<system.web>
<customErrors mode="On"/>
</system.web>

Par défaut, le fichier d'erreur Error.aspx sera utilisé dans le même dossier associé
au contrôleur dont l'action a provoqué l'erreur. Si ce fichier est absent, c'est dans
le dossier Shared que la recherche se fera.

[HandleError (View="Error")]
public object TestError()
{
throw new Exception("Une erreur est générée");
}
Le contrôleur
 Les filtres d'action - HandleError
Voici le contenu du fichier Error.aspx

<html>
<head><title>Page d'erreur</title></head>
<body>
<h2>Une erreur s'est produite lors de l'accès à la page</h2>
</body>
</html>
Le contrôleur
 Les filtres d'action personnalisé
Nous pouvons créer nos propres filtres tels que par exemple d'enregistrer un
événement dans une base de données lorsque un utilisateur accède à une action.
Une autre idée de filtre serait de limiter l'accès à une action donnée en fonction de
l'adresse IP source du client (Cette dernière proposition sera proposée en exercice)

public class LogFilter : ActionFilterAttribute, IActionFilter


{
void IActionFilter.OnActionExecuting(ActionExecutingContext filterContext)
{
WPFTutorialEntities1 WPFLogs = new WPFTutorialEntities1();
WPFLogs.InsertLog(
filterContext.ActionDescriptor.ControllerDescriptor.ControllerName,
filterContext.ActionDescriptor.ActionName,
filterContext.HttpContext.Request.UserHostAddress,
filterContext.HttpContext.Timestamp);
}}
Le contrôleur
 Les filtres d'action personnalisé
[LogFilter]
[Authorize]
public ActionResult Index()
{
ViewBag.Title = "Mon application MVC";
return View(MyLib.Select());
}
Envoi de données
 Formulaire de login (post)
Nous allons envisager l'envoi des données en prenant un formulaire de login

public ActionResult Login(string ReturnUrl) {


ViewBag.ReturnUrl = ReturnUrl;
return View(); }
Envoi de données
 Formulaire de login (post)
Nous allons reprendre quelques aspects du fichier Login.cshtml
@using (Html.BeginForm(new { ReturnUrl = Request.QueryString["ReturnUrl"] }))
{
@Html.AntiForgeryToken()
(...)
}

Html.BeginForm permet de générer le conteneur <form> html. Par défaut, c'est la


même action d'origine qui recevra les données, auxquelles sera ajoutée la donnée
ReturnUrl = Request.QueryString["ReturnUrl"]

Request.QueryString["ReturnUrl"] permet de récupérer le champ passé en url


quee nous retrouvons dans la barre URL du navigateur:
http://localhost:61775/Account/Login?ReturnUrl=%2f
Envoi de données
 Formulaire de login (post)
@model MvcApplication3.User
@using (Html.BeginForm(new { ReturnUrl = Request.QueryString["ReturnUrl"] }))
{
(...)
@Html.Label("Nom",new { @class = "Label" })
@Html.TextBoxFor(m=>m.UserName, new { placeholder =
"Nom",@class="tb" })
@Html.ValidationMessageFor(m => m.UserName,"obligatoire") (...)
}

@model MvcApplication3.User Le modèle de données associé à la vue est


MvcApplication3.User, une classe comprenant des propriétés. Cette classe est dans
notre cas, générée automatiquement par le designer de modèle entity framework
pour l'accès à notre base de données
Envoie de données
 Formulaire de login (post)
public partial class User {
public System.Guid UserID { get; set; }
[Required]
public string UserName { get; set; }
[Required]
public string Passwd { get; set; } }

Chaque propriété peut être associée dans le formulaire à une zone d'édition nous
permettant ainsi de pouvoir récupérer le nom et le mot de passe
@Html.TextBoxFor(m=>m.UserName, new { placeholder = "Nom" })
Envoi de données
 Formulaire de login (post)
public partial class User {
public System.Guid UserID { get; set; }
[Required]
public string UserName { get; set; }
[Required]
public string Passwd { get; set; } }

Nous retrouvons l'attrubut [Required] qui a été ajouté par nos soins pour signaler
un critère de validation qui dans notre cas est la présence obligatoire de ce champ
@Html.ValidationMessageFor(m => m.UserName,"obligatoire")
Envoi de données
 Formulaire de login (post)
Le bouton Submit permettra l'envoie du formulaire si les validations côté client
sont valides. Un message d'erreur sera affiché si le formulaire est réaffiché mais
avec une authentification qui a échoué

@{Html.EnableClientValidation(true);}

<input type="submit" value="Validation" />


(...)
@if (!ViewData.ModelState.IsValid) {
<p> id="message">Authentification erronée</p> }

Une autre façon d'afficcher un message d'erreur est de travailler avec


@Html.ValidationSummary ainsi que dans l'action du contrôleur
ModelState.AddModelError("", "Authentification erronée");
Envoi de données
 Formulaire de login (post)
[HttpPost]
public ActionResult Login(User tempUser, string ReturnUrl)
{
(...)
else
{
ModelState.AddModelError("", "Authentification erronée");
}
}

<input id="saveButton" type="submit" value="Validation" />


</div>
@Html.ValidationSummary(false)
</div>
</div>
Envoi de données
 Formulaire de login (post)
Une fois les champs remplis, le formulaire peut donc être envoyé vers l'action
Login. Nous recevrons donc deux arguments que sont l'utilisateur avec son nom et
mot de passe ainsi que le ReturnUrl.
[HttpPost]
public ActionResult Login(User tempUser, string ReturnUrl) {
WPFTutorialEntities1 WPFUsers = new WPFTutorialEntities1();
if (ModelState.IsValid) {
int result = WPFUsers.ValidateUser(tempUser.UserName,
tempUser.Passwd).FirstOrDefault() ?? 0;
if (result==1) {
Session["User"] = tempUser;
FormsAuthentication.SetAuthCookie(tempUser.UserName, false);
if (ReturnUrl != null) return Redirect(ReturnUrl);
else return Redirect(FormsAuthentication.DefaultUrl); }
else ModelState.AddModelError("", "Erreur d'authentification"); }
else ModelState.AddModelError("", "Erreur d'authentification");
return View(); }
Envoi de données
 Formulaire de login (post)
ModelState.IsValid permet de vérifier que le contenu du formulaire est valide

int result = WPFUsers.ValidateUser(tempUser.UserName,


tempUser.Passwd).FirstOrDefault() ?? 0; est un appel à une procédure stockée
correspondant à une fonction importée dans entity framework. Elle vérifie qu'il y a
bien dans la db un utilisateur avec le nom et le mot de passe fournis

if (ReturnUrl != null) return Redirect(ReturnUrl);


else return Redirect(FormsAuthentication.DefaultUrl); } permet de
rediriger l'utilisateur vers la page d'origine qu'il tentait d'accéder ou la page par
défaut définie dans le fichier web.config si la page accédée était immédiatement la
page de login
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" timeout="2880"
defaultUrl="~/Home/Index"></forms>
</authentication>
Envoi de données
 Formulaire de login (ajax)
Lorsque le formulaire est envoyé avec une authentification erronée, le serveur doit
renvoyer l'entierté de la page avec comme seule différence, l'information d'erreur
affichée. Nous pourrions, pour une question de "beauté", envoyer les informations
par Ajax vers une action.

Attention: il est indispensable d'inclure deux ensembles de script Jquery

<script src="~/Scripts/jquery.unobtrusive-ajax.js"
type="text/javascript"></script>
<script src="~/Scripts/jquery.form.js" type="text/javascript"></script>

jquery.unobtrusive-ajax.js permet d'obtenir toutes les fonctionnalités de


@Ajax.BeginForm

jquery.form.js permet de gérer notre formulaire et notamment d'en effacer le


contenu
Envoi de données
 Formulaire de login (ajax)

@using (Ajax.BeginForm("Login2", "Account", new { ReturnUrl =


Request.QueryString["ReturnUrl"] }, new AjaxOptions
{
OnSuccess = "OnSuccess"
}))
{

@using (Ajax.BeginForm("Login2", "Account" permet de renseigner que le


formulaire doit être envoyé l'action Login2 faisant partie du conteneur Account

new AjaxOptions { OnSuccess = "OnSuccess"} permet de renseigner qu'en cas de


succes de l'appel de l'action, la méthode Javascript OnSuccess doit être appelée
Envoi de données
 Formulaire de login (ajax)
<div><p style="display:none" id="message">Authentification erronée</p></div>

<script type="text/javascript">
function OnSuccess(response) {
if (response.success == true) {
$(location).attr('href', response.ReturnUrl); //redirection
} else {
$('form').clearForm();
$('#message').css('display', 'block'); }} // affichage message d'erreur
</script>

public JsonResult Login2(User tempUser, string ReturnUrl){


(...)
if (ReturnUrl != null) return Json(new { success = true, @ReturnUrl = ReturnUrl });
else return Json(new { success = true,
@ReturnUrl=FormsAuthentication.DefaultUrl}); (...)
return Json(new { success = false, @ReturnUrl = "" });}
Envoi de données
 Formulaire - Validation server (ajax)
La validation de certains champs nécessite parfois l'accès à une base de données et
de ce fait, celle-ci doit donc se réaliser côté serveur.
On peut valider les informations lors de l'envoi du formulaire mais dans certains
cas, l'envoi par Ajax de la validation est plus agréable pour l'utilisateur.
Pour la bonne fonctionnalité au niveau de la page, il faut include le bundle Jquery-
val dans votre projet. Nous modifions notre modèle de sorte à ajouter la validation

public partial class User {


public System.Guid UserID { get; set; }
[Required]
public string UserName { get; set; }
[Required]
public string Passwd { get; set; }
[Remote ("ValidateEmail","Home")]
public string Email { get; set; } }
Envoi de données
 Formulaire - Validation server (ajax)
Nous allons envisager un formulaire d'édition de l'utilisateur en validant une
nouvelle adresse mail pour qu'elle soit unique dans la base de données

public JsonResult ValidateEmail(string Email)


{
using (var context = new WPFTutorialEntities1())
{
Guid UserGuid = Guid.Parse(Session["User"].ToString());
var UserQuery = from st in context.Users
where st.Email == Email && st.UserID != UserGuid
select st;
if (UserQuery.Count() != 0)
return Json("Adresse déjà utilisée", JsonRequestBehavior.AllowGet);
}
return Json(true, JsonRequestBehavior.AllowGet);
}
Envoi de données
 Formulaire - Validation server (ajax)
Comme nous avons besoin du UserID dans plusieures actions, celui ci sera placé
dans une variable de session lors d'un login réussi
[HttpPost]
public ActionResult Login(User tempUser, string ReturnUrl) {
WPFTutorialEntities1 WPFUsers = new WPFTutorialEntities1();
if (ModelState.IsValid)
{
Guid ? result = WPFUsers.ValidateUser(tempUser.UserName,
tempUser.Passwd).FirstOrDefault() ?? null;

if (result != null)
{
Session["User"] = result.ToString(); (.....)
Envoi de données
 Formulaire - Validation server (ajax)
Si la validation est activée lorsque la TextBox perd le focus, nous obtiendrons le
résultat suivant.
Envoi de données
 Mise à jour dynamique
Dans le cadre des envois de requêtes ajax, nous pouvons en fonction
d'événements sur une page, mettre à jour les données dans la même page.

Soit une combobox comprenant la liste des départements. Lorsque un


département est sélectionné, la combobox des utilisateurs doit être mise à jour.
Envoi de données
 Mise à jour dynamique

public ActionResult ComboTest() {


WPFTutorialEntities1 WPF = new WPFTutorialEntities1();
var items = WPF.Departement.ToList();
ViewBag.DepData = items;
return View();}

<div>
@Html.DropDownList("DepList", new SelectList(ViewBag.DepData,
"DepUID", "DepNom"))
<select id="UserList" name="UserList" style="width:150px;"></select>
</div>
Envoi de données
 Mise à jour dynamique
<script>
$(document).ready(function () {
$('#DepList').change(function (e) {
$.ajax({
type: "POST",
dataType: "json",
url: '@Url.Action("GetUserFromDep","Home")',
data: {
"DepID": $('#DepList').val()},
success: function (data){
$('#UserList').empty();
$.each(data, function (i, el)
{ $('#UserList').append(new Option(el.UserName, el.UserID)); });}
});
});
$('#DepList').trigger('change');});
</script>
Envoi de données
 Mise à jour dynamique
public JsonResult GetUserFromDep(string DepID)
{
WPFTutorialEntities1 WPF = new WPFTutorialEntities1();
var UserQuery = from st in WPF.Users
where st.DepUID.ToString()==DepID
select st;
return Json(UserQuery.ToList<User>());
}
MVC Web API
 Introduction
ASP.NET Web API est un framework permettant au travers d'un service HTTP
l'exposition de données accessibles par une large gamme de clients. De base, les
types de données supportées sont XML, JSON et les données de formulaires.
Tout service Web API supporte les types de requêtes suivants (verbs):

• GET pour la lecture de données


• POST pour l'ajout d'une nouvelle donnée
• PUT pour la mise à jour d'une donnée
• DELETE pour l'effacement d'une donnée

D'autres verbes supportés mais moins fréquemment utilisés sont:

• HEAD comportement identique à GET mais uniquement pour récupérer les


entêtes
• OPTIONS permettant de demander par exemple la liste des verbes supportés
MVC Web API
 Mise en place du service
Les WebAPI faisant partie de la technologie MVC, nous retrouverons une
similitude dans leur mise en place comparativement aux applications WEB MVC
Nous pouvons ajouter un service à une application MVC existance ou créer une
application MVC intégrant un service WebAPI
Dans le cas d'une nouvelle application, il suffira de choisir l'option Ajout d'un
nouveau projet - Application WEB ASP.NET MVC4
MVC Web API
 Mise en place du service
Dans le cas d'une application existante, il suffira de choisir l'option Ajout d'un
nouveau controleur
MVC Web API
 Routage - Controleur
Nous retrouvons un fichier de configuration des routes WebApiConfig.cs dont le
contenu de base sera le suivant
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}}

Si le controleur créé s'appelle ValuesController, l'accès au WebAPI se fera au


travers de l'URL suivante: http://xxxx/api/values
MVC Web API
 Routage - Controleur
Nous retrouvons un fichier de configuration des routes WebApiConfig.cs dont le
contenu de base sera le suivant
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}}

Si le controleur créé s'appelle ValuesController, l'accès au WebAPI se fera au


travers de l'URL suivante: http://xxxx/api/values
MVC Web API
 Routage - Controleur
Si nous choisissons la création du contrôleur non vide, certaines methodes seront
intégrées avec un exemple de code. Prenons comme exemple la méthode GET
associée au verb possédant le même nom

public IEnumerable<string> Get()


{
return new string[] { "value1", "value2" };
}

Les données seront retournées au format JSON


MVC Web API
 Association des méthodes aux verbes
 Décoration des méthodes d'un attribut HttpGet, HttpPut, HttpPost, HttpDelete

[HttpGet]
public IEnumerable<string> Liste()
{
return new string[] { "value1", "value2" };
}

 Décoration de l'attribut AcceptVerbs regroupant plusieurs verbes

[AcceptVerbs("GET", "HEAD")]
public IEnumerable<string> Liste()
{
return new string[] { "value1", "value2" };
}
MVC Web API
 Association des méthodes aux verbes
 Nommer les méthodes du contrôleur

public IEnumerable<string> Get()


{
return new string[] { "value1", "value2" };
}

public IEnumerable<string> GetStudents()


{
return new string[] { "value1", "value2" };
}
MVC Web API
 Retour des actions
Une action dans un contrôleur peut se voir affecter les types de retour suivant:

• void Web API retourne une réponse HTTP vide avec le code de status 204 (pas
de contenu).
• HttpResponseMessage Web API convertit la valeur retournée directement dans
le message HTTP en utilisant les propriétés de l'objet HttpResponseMessage pour
remplir la réponse. Cet objet est obtenu en utilisant la syntaxe suivante:
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK,
"value");
Si un modèle est utilisé dans la méthode CreateResponse, un media formatter
sera utilisé pour sérialiser ce modèle dans le corps de la réponse
• IHttpActionResult IHttpActionResult contient une méthode ExecuteAsync, qui
créera de façon asynchrone une instance HttpResponseMessage.
• Autres types Web API utilise un média formatter pour sérialiser la valeur
retournée dans le corps de la réponse. Le code de status est 200 (OK).
MVC Web API
 Retour des actions - autres types
public IEnumerable<string> GetStudents() {
return new string[] { "value1", "value2" }; }

public IEnumerable<User> GetStudents() {


WPFTutorialEntities1 WPF = new WPFTutorialEntities1();
var UserQuery = from st in WPF.Users
select st;
return UserQuery.ToList<User>(); }

Le corps de la réponse HTTP contiendra les données suivantes:


[{"UserID":"f36b22f4-0231-4454-a33d-
4a988349c880","UserName":"Dupond","Passwd":"password","Email":"Dupond@h
elha.be","DepUID":"fa5d16f9-58e0-4fd4-93ff-20aa3e3dc96e"}]
MVC Web API
 Retour des actions - autres types
Un désavantage de cette technique est de ne pas pouvoir retrourner un code de
retour. Nous pouvons soit générer une exception de type CLR ex: Exception
Le comportement par défaut sera de transmettre le code d'erreur 500.

Il est également posssible (et même coneillé) d'utiliser HttpResponseException

public IEnumerable<string> GetStudents()


{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
MVC Web API
 Retour des actions - HttpResponseMessage
public HttpResponseMessage GetStudents()
{
WPFTutorialEntities1 WPF = new WPFTutorialEntities1();
var UserQuery = from st in WPF.Users
select st;
return Request.CreateResponse(HttpStatusCode.OK, UserQuery.ToList());
}
MVC Web API
 Passage des arguments aux actions
Web API utilise les règles suivantes pour lier les paramètres:

• Si le paramètres est un type simple, WebAPI essaie de récupérer la valeur à partir


de l'URI. Les types simples vont inclure les types primitifs du .NET(int, bool,
double ...) ainsi que TimeSpan, DateTime, Guid, decimal et string.

• Pour les types complexes, WebAPI essaiera de lire la valeur à partir du coprs du
message en utilisant un media type formatter.

Dans l'exemple suivant, nous utiliserons la méthode GET pour récupérer les
données et ensuite la méthode PUT pour les mettre à jour.
La méthode GET recevra l'identifiant unique de l'utilisateur et retournera ses
données sous forme d'un objet
MVC Web API
 Passage des arguments aux actions
Nous ferons en sorte que, lorsque un étudiant est choisi dans la liste, une requête
soit envoyée vers le WebAPI (méthode GET).
Une première démarche est de gérer l'événement de changement d'item dans la
liste

$(document).ready(function () {
$('#UserList').change(function (e) {
var userid = $("#UserList").val();
if (userid != null) GetStudent(userid);
}); });

La fonction javascript GetStudent(userid); sera appelée lorsqu'il ya un chagement


de sélection d'item.
MVC Web API
 Passage des arguments aux actions
function GetStudent(Userid) {
var uri = '@Url.Action("Values","api")';
uri += '/'+Userid;
$.getJSON(uri)
.done(function (data) {
$("#Nom").val(data[0].UserName);
$("#Mdp").val(data[0].Passwd);
$("#mail").val(data[0].Email);
}); }

Dans notre application, nous retrouvons la route définie pour ce WebAPI qui est
routeTemplate: "api/{controller}/{id}" ce qui correspond bien à notre URI utilisée

var uri = '@Url.Action("Values","api")';


uri += '/'+Userid;

Nous aurons par exemple api/Value/FA5D16F9-58E0-4FD4-93FF-20AA3E3DC96E


MVC Web API
 Passage des arguments aux actions
public HttpResponseMessage GetStudents(string id)
{
WPFTutorialEntities1 WPF = new WPFTutorialEntities1();
var UserQuery = from st in WPF.Users
where st.UserID.ToString() == id
select st;
return Request.CreateResponse(HttpStatusCode.OK,UserQuery); }

La méthode Get retourne un objet de type Users qui sera sérialisé en JSON. Nous
retrouvons dans la fonction Javascript la récupération des données et
l'initialisation des différents champs

$.getJSON(uri)
.done(function (data) {
$("#Nom").val(data[0].UserName);
$("#Mdp").val(data[0].Passwd);
$("#mail").val(data[0].Email);
}); }
MVC Web API
 Passage des arguments aux actions

Nous allons maintenant envisager l'envoi des données modifiées vers le WebAPI
avec la méthode PUT. Cet envoi sera réalisé en gérant l'événement du clic sur le
bouton d'enregistrement.
MVC Web API
 Passage des arguments aux actions
$("#Save").click(function () {
var Student = new Object();
Student.UserName = $("#Nom").val();
Student.Passwd = $("#Mdp").val();
Student.Email = $("#mail").val();
Student.UserID = $("#UserList").val();
Student.DepUID = $('#DepList').val();
var uri = '@Url.Action("Values","api")';
$.ajax({
url: uri,
type: 'PUT',
data: JSON.stringify(Student),
contentType: 'application/json; charset=utf-8',
success: function (data) {
alert('Updated Successfully'); },
error: function (msg) { alert(msg); }
}); });
MVC Web API
 Passage des arguments aux actions
Dans la fonction javascript associée au clic sur le bouton d'enregistrement, un
objet javascript est créé. Cet objet, si nous respectons les mêmes membres que
ceux de la classe CLR pourra être sérialisé et déssérialisé facilement

public void PutStudent([FromBody]User item)


{
WPFTutorialEntities1 WPF = new WPFTutorialEntities1();
User UserQuery = (from st in WPF.Users
where st.UserID == item.UserID
select st).First();
UserQuery.UserName = item.UserName;
UserQuery.Passwd = item.Passwd;
UserQuery.Email = item.Email;
WPF.SaveChanges(); }

Au moyen de LINQ, nous sélectionons dans le db l'étudiant associé au GUID édité


dans la page web. Il suffit alors de modifier cet objet (ex: UserQuery.Passwd =
item.Passwd;) et ensuite sauver les modifications dans la db (WPF.SaveChanges();)
MVC Comment ajouter Identity
 Ajout des packages NUGET à un solution
Microsoft.AspNet.Identity.Owin
Microsoft.AspNet.Identity.Core
Microsoft.AspNet.Identity.EntityFramework

Pour intégrer maintenant Owin sous IIS, nous devrons installer les packages
suivant nous assurant ainsi la fonctionnalité minimale:

Microsoft.Owin.Host.SystemWeb ( ou Microsoft.Owin.Host.SelfHost si pas IIS )


Microsoft.Owin.Security.Cookies ( Utilisateur local )
MVC Comment ajouter Identity
 Ajout de la classe de démarrage

namespace WebApplication30
{
public class Startup1
{
public void Configuration(IAppBuilder app)
{
}
}
}
MVC Comment ajouter Identity
 Désactiver l'authentification par défaut

<system.web>
<authentication mode="None" />
<compilation debug="true" targetFramework="4.7" />
<httpRuntime targetFramework="4.7" />
</system.web>
<system.webServer>
<modules>
<remove name="FormsAuthentication" />
</modules>
</system.webServer>
MVC Comment ajouter Identity
 Stockage des objets dans le contexte OWIN
Nous utiliserons la méthode CreatePerOwinContext de la classe AppBuilder.
L'instance de AppBuilder est fournie par l'hôte au moment de l'exécution.

Pour pouvoir authentifier un utilisateur, nous utiliserons aurons besoin des classes
personnalisées suivantes:

class ApplicationSignInManager : SignInManager<ApplicationUser,


string>

Une des méthodes de cette classe fait référence à la classe assurant la gestion des
utilisateurs. Nous devons donc implémenter la classe suivante

class ApplicationUserManager : UserManager<ApplicationUser>

Une des méthodes de cette classe fait référence à la classe assurant la gestion du contexte lié à la
base de données. Nous devrons donc implémenter la classe suivante:

class ApplicationDbContext : IdentityDbContext<ApplicationUser>


MVC Comment ajouter Identity
 Stockage des objets dans le contexte OWIN
Il reste finalement à implémenter une classe que l'on retrouve dans les arguments des
classes génériques de base

class ApplicationUser : IdentityUser

Les trois premières classes implémentent une méthode create qui sera utiliser dans la
classe de démarrage OWIN

app.CreatePerOwinContext(ApplicationDbContext.Create);

app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserM
anager.Create);

app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSig
nInManager.Create);

La méthode CreatePerOwinContext a besoin en effet d'un délégué.


MVC Comment ajouter Identity
 Ajouter une classe utilisateur
Cette classe doit hériter de l'interface IdentityUser. Vous ajouterez dans cette
classe les différentes propriétés liées aux champs personnalisés de la table des
utilisateurs

public class ApplicationUser : IdentityUser


{
public async Task<ClaimsIdentity>
GenerateUserIdentityAsync(UserManager<ApplicationUser>
manager)
{
var userIdentity = await
manager.CreateIdentityAsync(this,
DefaultAuthenticationTypes.ApplicationCookie);
return userIdentity;
}
public MyProperty {get; set;}
}
MVC Comment ajouter Identity
 Ajouter une classe définissant le DB contexte
Cette classe doit hériter de l'interface IdentityDbContext<ApplicationUser>. Vous
ajouterez dans cette classe les différentes propriétés liées aux champs
personnalisés de la table des utilisateurs. ApplicationUser est la classe créée
précédemment
public class ApplicationDbContext :
IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("MyConnectionString2", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
MVC Comment ajouter Identity
 Ajouter une classe définissant le DB contexte

public ApplicationDbContext()
: base("MyConnectionString2", throwIfV1Schema:
false)
"MyConnectionString2" définit l'entrée dans le fichier Web.config
permettant de caractériser la chaîne de connexion d'accès à la base de données

<connectionStrings>
<add name="MyConnectionString2"
connectionString="Data Source=.\SQLEXPRESS;Initial
Catalog=IdentityTest;Integrated Security=SSPI;"
providerName="System.Data.SqlClient" />
</connectionStrings>
MVC Comment ajouter Identity
 Personnalisation de UserManager
public class ApplicationUserManager :
UserManager<ApplicationUser> {
public
ApplicationUserManager(IUserStore<ApplicationUser> store)
: base(store){}
public static ApplicationUserManager
Create(IdentityFactoryOptions<ApplicationUserManager>
options, IOwinContext context){
var manager = new ApplicationUserManager(new
UserStore<ApplicationUser>(context.Get<ApplicationDbContex
t>()));
//personalisation du manager
return manager; }
}
MVC Comment ajouter Identity
 Personnalisation de RoleManager
public class ApplicationRoleManager :
RoleManager<IdentityRole>
{
public
ApplicationRoleManager(IRoleStore<IdentityRole, string>
roleStore) : base(roleStore) {}
public static ApplicationRoleManager
Create(IdentityFactoryOptions<ApplicationRoleManager>
options, IOwinContext context)
{
return new ApplicationRoleManager(new
RoleStore<IdentityRole>(new ApplicationDbContext()));
}
}
MVC Comment ajouter Identity
 Personnalisation de SignInManager
public class ApplicationSignInManager :
SignInManager<ApplicationUser, string> {
public
ApplicationSignInManager(ApplicationUserManager
userManager, IAuthenticationManager authenticationManager)
: base(userManager, authenticationManager) { }
public static ApplicationSignInManager
Create(IdentityFactoryOptions<ApplicationSignInManager>
options, IOwinContext context)
{
return new
ApplicationSignInManager(context.GetUserManager<Applicatio
nUserManager>(), context.Authentication);
}
}
MVC Comment ajouter Identity
 Personnalisation de SignInManager
public class ApplicationSignInManager :
SignInManager<ApplicationUser, string> {
public
ApplicationSignInManager(ApplicationUserManager
userManager, IAuthenticationManager authenticationManager)
: base(userManager, authenticationManager) { }
public static ApplicationSignInManager
Create(IdentityFactoryOptions<ApplicationSignInManager>
options, IOwinContext context)
{
return new
ApplicationSignInManager(context.GetUserManager<Applicatio
nUserManager>(), context.Authentication);
}
}
MVC Comment ajouter Identity
 Personnaliser la classe de startup OWIN
public void ConfigureAuth(IAppBuilder app)
{

app.CreatePerOwinContext(ApplicationDbContext.Create);

app.CreatePerOwinContext<ApplicationUserManager>(Applicati
onUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(Applica
tionSignInManager.Create);

//....

}
MVC Comment ajouter Identity
 Personnaliser la classe de startup OWIN
public void ConfigureAuth(IAppBuilder app){
//....
app.UseCookieAuthentication(new
CookieAuthenticationOptions
{
AuthenticationType =
DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new
PathString("/Account/Login")
Provider = new CookieAuthenticationProvider
{
OnValidateIdentity =
SecurityStampValidator.OnValidateIdentity<ApplicationUserM
anager, Models.ApplicationUser>(
validateInterval:
TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) =>
user.GenerateUserIdentityAsync(manager))
MVC Comment ajouter Identity
 Classe de startup OWIN – Web.config
<appSettings>
<add key="owin:appStartup" value="StartUpConfiguration" />
</appSettings>

Nous ajouterons juste au dessus de la classe

[assembly: OwinStartup("StartUpConfiguration",
typeof(WebApplication30.Startup1))]
MVC Comment ajouter Identity
 Controller – Login action

public async Task<ActionResult> Login(LoginViewModel


model, string returnUrl)
{
if (!ModelState.IsValid)
{
return View(model);
}
ApplicationSignInManager signInManager =
HttpContext.GetOwinContext().Get<ApplicationSignInManager>
();
var result = await
signInManager.PasswordSignInAsync(model.Login,
model.Password, false, shouldLockout: false);

//....
MVC Comment ajouter Identity
 Controller – Login action
public async Task<ActionResult> Login(LoginViewModel
model, string returnUrl) {
//....
switch (result) {
case SignInStatus.Success:
return RedirectToLocal(returnUrl);
case SignInStatus.LockedOut:
return View("Lockout");
case SignInStatus.RequiresVerification:
return RedirectToAction("SendCode",
new { ReturnUrl = returnUrl, RememberMe = model.RememberMe
});
case SignInStatus.Failure:
default:
ModelState.AddModelError("", "Invalid
login attempt.");
return View(model); }}

Vous aimerez peut-être aussi