Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
di Microsoft
Nella terza iterazione viene aggiunta la convalida dei moduli di base. Microsoft impedisce agli utenti di inviare un modulo senza completare i campi modulo obbligatori. Vengono convalidati anche gli indirizzi di posta elettronica e i numeri di telefono.
Compilazione di un'applicazione MVC ASP.NET Gestione contatti (C#)
In questa serie di esercitazioni viene creata un'intera applicazione Contact Management dall'inizio alla fine. L'applicazione Contact Manager consente di archiviare le informazioni di contatto, ovvero nomi, numeri di telefono e indirizzi di posta elettronica, per un elenco di persone.
L'applicazione viene compilata su più iterazioni. Con ogni iterazione, l'applicazione viene migliorata gradualmente. L'obiettivo di questo approccio a più iterazioni è consentire di comprendere il motivo di ogni modifica.
Iterazione n. 1: creare l'applicazione. Nella prima iterazione viene creato il Contact Manager nel modo più semplice possibile. Viene aggiunto il supporto per le operazioni di base del database: Create, Read, Update e Delete (CRUD).
Iterazione n. 2: rendere l'applicazione più bella. In questa iterazione viene migliorata l'aspetto dell'applicazione modificando la pagina master della visualizzazione MVC predefinita ASP.NET e il foglio di stile css.
Iterazione n. 3: aggiungere la convalida dei moduli. Nella terza iterazione viene aggiunta la convalida dei moduli di base. Microsoft impedisce agli utenti di inviare un modulo senza completare i campi modulo obbligatori. Vengono convalidati anche gli indirizzi di posta elettronica e i numeri di telefono.
Iterazione n. 4: rendere l'applicazione ad accoppiamento libero. In questa quarta iterazione si sfruttano diversi modelli di progettazione software per semplificare la gestione e la modifica dell'applicazione Contact Manager. Ad esempio, si esegue il refactoring dell'applicazione per usare il modello repository e il modello di inserimento delle dipendenze.
Iterazione n. 5: creare unit test. Nella quinta iterazione l'applicazione risulta più semplice da gestire e modificare aggiungendo unit test. Si simulano le classi del modello di dati e si compilano unit test per i controller e la logica di convalida.
Iterazione n. 6: usare lo sviluppo basato su test. In questa sesta iterazione si aggiungono nuove funzionalità all'applicazione scrivendo prima unit test e scrivendo codice per gli unit test. In questa iterazione si aggiungono gruppi di contatti.
Iterazione n. 7: aggiungere la funzionalità Ajax. Nella settima iterazione viene migliorata la velocità di risposta e le prestazioni dell'applicazione aggiungendo il supporto per Ajax.
Iterazione
In questa seconda iterazione dell'applicazione Contact Manager viene aggiunta la convalida dei moduli di base. Si impedisce agli utenti di inviare un contatto senza immettere i valori per i campi modulo obbligatori. Vengono convalidati anche i numeri di telefono e gli indirizzi di posta elettronica (vedere la figura 1).
Figura 01: Un modulo con convalida (fare clic per visualizzare l'immagine a dimensione intera)
In questa iterazione si aggiunge la logica di convalida direttamente alle azioni del controller. In generale, questo non è il modo consigliato per aggiungere la convalida a un'applicazione MVC ASP.NET. Un approccio migliore consiste nell'inserire una logica di convalida dell'applicazione in un livello di servizio separato. Nell'iterazione successiva viene refactoring dell'applicazione Contact Manager per rendere l'applicazione più gestibile.
In questa iterazione, per semplificare le operazioni, si scrive tutto il codice di convalida manualmente. Invece di scrivere il codice di convalida, è possibile sfruttare un framework di convalida. Ad esempio, è possibile usare microsoft Enterprise Library Validation Application Block (VAB) per implementare la logica di convalida per l'applicazione MVC ASP.NET. Per altre informazioni sul blocco di applicazioni di convalida, vedere:
http://msdn.microsoft.com/library/dd203099.aspx
Aggiunta della convalida alla visualizzazione Crea
Per iniziare, aggiungere la logica di convalida alla visualizzazione Crea. Fortunatamente, poiché è stata generata la visualizzazione Crea con Visual Studio, la visualizzazione Crea contiene già tutta la logica dell'interfaccia utente necessaria per visualizzare i messaggi di convalida. La visualizzazione Crea è contenuta nell'elenco 1.
Listato 1 - \Views\Contact\Create.aspx
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<ContactManager.Models.Contact>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
<title>Create</title>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<%= Html.ValidationSummary() %>
<% using (Html.BeginForm()) {%>
<fieldset class="fields">
<legend>Create New Contact</legend>
<p>
<label for="FirstName">First Name:</label>
<%= Html.TextBox("FirstName") %>
<%= Html.ValidationMessage("FirstName", "*") %>
</p>
<p>
<label for="LastName">Last Name:</label>
<%= Html.TextBox("LastName") %>
<%= Html.ValidationMessage("LastName", "*") %>
</p>
<p>
<label for="Phone">Phone:</label>
<%= Html.TextBox("Phone") %>
<%= Html.ValidationMessage("Phone", "*") %>
</p>
<p>
<label for="Email">Email:</label>
<%= Html.TextBox("Email") %>
<%= Html.ValidationMessage("Email", "*") %>
</p>
<p class="submit">
<input type="submit" value="Create" />
</p>
</fieldset>
<% } %>
</asp:Content>
Si noti la chiamata al metodo helper Html.ValidationSummary() visualizzato immediatamente sopra il modulo HTML. Se sono presenti messaggi di errore di convalida, questo metodo visualizza i messaggi di convalida in un elenco puntato.
Si noti, inoltre, le chiamate a Html.ValidationMessage() visualizzate accanto a ogni campo modulo. L'helper ValidationMessage() visualizza un singolo messaggio di errore di convalida. Nel caso dell'elenco 1, viene visualizzato un asterisco quando si verifica un errore di convalida.
Infine, l'helper Html.TextBox() esegue automaticamente il rendering di una classe Foglio di stile css quando si verifica un errore di convalida associato alla proprietà visualizzata dall'helper. L'helper Html.TextBox() esegue il rendering di una classe denominata input-validation-error.
Quando si crea una nuova applicazione ASP.NET MVC, nella cartella Contenuto viene creato automaticamente un foglio di stile denominato Site.css. Questo foglio di stile contiene le definizioni seguenti per le classi CSS correlate all'aspetto dei messaggi di errore di convalida:
.field-validation-error
{
color: #ff0000;
}
.input-validation-error
{
border: 1px solid #ff0000;
background-color: #ffeeee;
}
.validation-summary-errors
{
font-weight: bold;
color: #ff0000;
}
La classe field-validation-error viene usata per applicare uno stile all'output di cui viene eseguito il rendering dall'helper Html.ValidationMessage(). La classe input-validation-error viene usata per applicare uno stile alla casella di testo (input) sottoposta a rendering dall'helper Html.TextBox(). La classe validation-summary-errors viene usata per applicare uno stile all'elenco non ordinato sottoposto a rendering dall'helper Html.ValidationSummary().
Nota
È possibile modificare le classi del foglio di stile descritte in questa sezione per personalizzare l'aspetto dei messaggi di errore di convalida.
Aggiunta della logica di convalida all'azione Di creazione
Al momento, la visualizzazione Crea non visualizza mai i messaggi di errore di convalida perché non è stata scritta la logica per generare messaggi. Per visualizzare i messaggi di errore di convalida, è necessario aggiungere i messaggi di errore a ModelState.
Nota
Il metodo UpdateModel() aggiunge automaticamente messaggi di errore a ModelState quando si verifica un errore durante l'assegnazione del valore di un campo modulo a una proprietà. Ad esempio, se si tenta di assegnare la stringa "apple" a una proprietà BirthDate che accetta valori DateTime, il metodo UpdateModel() aggiunge un errore a ModelState.
Il metodo Create() modificato in Listing 2 contiene una nuova sezione che convalida le proprietà della classe Contact prima che il nuovo contatto venga inserito nel database.
Listato 2 - Controllers\ContactController.cs (Crea con convalida)
//
// POST: /Contact/Create
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Exclude = "Id")] Contact contactToCreate)
{
// Validation logic
if (contactToCreate.FirstName.Trim().Length == 0)
ModelState.AddModelError("FirstName", "First name is required.");
if (contactToCreate.LastName.Trim().Length == 0)
ModelState.AddModelError("LastName", "Last name is required.");
if (contactToCreate.Phone.Length > 0 && !Regex.IsMatch(contactToCreate.Phone, @"((\(\d{3}\) ?)|(\d{3}-))?\d{3}-\d{4}"))
ModelState.AddModelError("Phone", "Invalid phone number.");
if (contactToCreate.Email.Length > 0 && !Regex.IsMatch(contactToCreate.Email, @"^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$"))
ModelState.AddModelError("Email", "Invalid email address.");
if (!ModelState.IsValid)
return View();
// Database logic
try
{
_entities.AddToContactSet(contactToCreate);
_entities.SaveChanges();
return RedirectToAction("Index");
}
catch
{
return View();
}
}
La sezione validate applica quattro regole di convalida distinte:
- La proprietà FirstName deve avere una lunghezza maggiore di zero (e non può essere costituita esclusivamente da spazi)
- La proprietà LastName deve avere una lunghezza maggiore di zero (e non può essere costituita esclusivamente da spazi)
- Se la proprietà Phone ha un valore (ha una lunghezza maggiore di 0), la proprietà Phone deve corrispondere a un'espressione regolare.
- Se la proprietà Email ha un valore (ha una lunghezza maggiore di 0), la proprietà Email deve corrispondere a un'espressione regolare.
Quando si verifica una violazione della regola di convalida, viene aggiunto un messaggio di errore a ModelState con l'aiuto del metodo AddModelError(). Quando si aggiunge un messaggio a ModelState, specificare il nome di una proprietà e il testo di un messaggio di errore di convalida. Questo messaggio di errore viene visualizzato nella visualizzazione dai metodi helper Html.ValidationSummary() e Html.ValidationMessage().
Dopo l'esecuzione delle regole di convalida, viene verificata la proprietà IsValid di ModelState. La proprietà IsValid restituisce false quando vengono aggiunti messaggi di errore di convalida a ModelState. Se la convalida non riesce, il modulo Crea viene riprodotto di nuovo con i messaggi di errore.
Nota
Ho ottenuto le espressioni regolari per convalidare il numero di telefono e l'indirizzo di posta elettronica dal repository delle espressioni regolari all'indirizzo http://regexlib.com
Aggiunta della logica di convalida all'azione di modifica
L'azione Edit() aggiorna un contatto. L'azione Edit() deve eseguire esattamente la stessa convalida dell'azione Create(). Anziché duplicare lo stesso codice di convalida, è necessario effettuare il refactoring del controller contatto in modo che le azioni Create() e Edit() chiamino lo stesso metodo di convalida.
La classe del controller Contact modificata è contenuta nell'elenco 3. Questa classe ha un nuovo metodo ValidateContact() chiamato all'interno delle azioni Create() e Edit().
Elenco 3 - Controllers\ContactController.cs
using System.Linq;
using System.Text.RegularExpressions;
using System.Web.Mvc;
using ContactManager.Models;
namespace ContactManager.Controllers
{
public class ContactController : Controller
{
private ContactManagerDBEntities _entities = new ContactManagerDBEntities();
protected void ValidateContact(Contact contactToValidate)
{
if (contactToValidate.FirstName.Trim().Length == 0)
ModelState.AddModelError("FirstName", "First name is required.");
if (contactToValidate.LastName.Trim().Length == 0)
ModelState.AddModelError("LastName", "Last name is required.");
if (contactToValidate.Phone.Length > 0 && !Regex.IsMatch(contactToValidate.Phone, @"((\(\d{3}\) ?)|(\d{3}-))?\d{3}-\d{4}"))
ModelState.AddModelError("Phone", "Invalid phone number.");
if (contactToValidate.Email.Length > 0 && !Regex.IsMatch(contactToValidate.Email, @"^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$"))
ModelState.AddModelError("Email", "Invalid email address.");
}
public ActionResult Index()
{
return View(_entities.ContactSet.ToList());
}
public ActionResult Create()
{
return View();
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Exclude = "Id")] Contact contactToCreate)
{
// Validation logic
ValidateContact(contactToCreate);
if (!ModelState.IsValid)
return View();
// Database logic
try
{
_entities.AddToContactSet(contactToCreate);
_entities.SaveChanges();
return RedirectToAction("Index");
}
catch
{
return View();
}
}
public ActionResult Edit(int id)
{
var contactToEdit = (from c in _entities.ContactSet
where c.Id == id
select c).FirstOrDefault();
return View(contactToEdit);
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Contact contactToEdit)
{
ValidateContact(contactToEdit);
if (!ModelState.IsValid)
return View();
try
{
var originalContact = (from c in _entities.ContactSet
where c.Id == contactToEdit.Id
select c).FirstOrDefault();
_entities.ApplyPropertyChanges(originalContact.EntityKey.EntitySetName, contactToEdit);
_entities.SaveChanges();
return RedirectToAction("Index");
}
catch
{
return View();
}
}
public ActionResult Delete(int id)
{
var contactToDelete = (from c in _entities.ContactSet
where c.Id == id
select c).FirstOrDefault();
return View(contactToDelete);
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Delete(Contact contactToDelete)
{
try
{
var originalContact = (from c in _entities.ContactSet
where c.Id == contactToDelete.Id
select c).FirstOrDefault();
_entities.DeleteObject(originalContact);
_entities.SaveChanges();
return RedirectToAction("Index");
}
catch
{
return View();
}
}
}
}
Riepilogo
In questa iterazione è stata aggiunta la convalida dei moduli di base all'applicazione Contact Manager. La logica di convalida impedisce agli utenti di inviare un nuovo contatto o di modificare un contatto esistente senza fornire valori per le proprietà FirstName e LastName. Inoltre, gli utenti devono fornire numeri di telefono e indirizzi di posta elettronica validi.
In questa iterazione è stata aggiunta la logica di convalida all'applicazione Contact Manager nel modo più semplice possibile. Tuttavia, la combinazione della logica di convalida nella logica del controller creerà problemi a lungo termine. L'applicazione sarà più difficile da gestire e modificare nel tempo.
Nell'iterazione successiva si eseguirà il refactoring della logica di convalida e della logica di accesso al database dai controller. Si useranno diversi principi di progettazione software per consentire di creare un'applicazione più ad accoppiamento più debole e più gestibile.