Walidacja z użyciem interfejsu IDataErrorInfo (C#)

Autor: Stephen Walther

Stephen Walther pokazuje, jak wyświetlać niestandardowe komunikaty o błędach weryfikacji przez zaimplementowanie interfejsu IDataErrorInfo w klasie modelu.

Celem tego samouczka jest wyjaśnienie jednego podejścia do przeprowadzania walidacji w aplikacji MVC ASP.NET. Dowiesz się, jak uniemożliwić komuś przesyłanie formularza HTML bez podawania wartości wymaganych pól formularza. Z tego samouczka dowiesz się, jak przeprowadzić walidację przy użyciu interfejsu IErrorDataInfo.

Założenia

W tym samouczku użyję bazy danych MoviesDB i tabeli bazy danych Filmy. Ta tabela zawiera następujące kolumny:

Nazwa kolumny Typ danych Zezwalaj na wartości null
Id int Fałsz
Tytuł Nvarchar(100) Fałsz
Dyrektor Nvarchar(100) Fałsz
Data wydania DateTime Fałsz

W tym samouczku używam programu Microsoft Entity Framework do generowania klas modelu bazy danych. Klasa Movie wygenerowana przez program Entity Framework jest wyświetlana na rysunku 1.

Jednostka Movie

Rysunek 01. Jednostka Movie (Kliknij, aby wyświetlić obraz pełnowymiarowy)

Uwaga

Aby dowiedzieć się więcej o korzystaniu z platformy Entity Framework do generowania klas modelu bazy danych, zobacz mój samouczek zatytułowany Tworzenie klas modeli za pomocą platformy Entity Framework.

Klasa kontrolera

Używamy kontrolera home do wyświetlania listy filmów i tworzenia nowych filmów. Kod dla tej klasy znajduje się na liście 1.

Lista 1 — Controllers\HomeController.cs

using System.Linq;
using System.Web.Mvc;
using MvcApplication1.Models;

namespace MvcApplication1.Controllers
{

    public class HomeController : Controller
    {
        private MoviesDBEntities _db = new MoviesDBEntities();

        public ActionResult Index()
        {
            return View(_db.MovieSet.ToList());
        }

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

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Create([Bind(Exclude = "Id")] Movie movieToCreate)
        {
            // Validate
            if (!ModelState.IsValid)
                return View();

            // Add to database
            try
            {
                _db.AddToMovieSet(movieToCreate);
                _db.SaveChanges();

                return RedirectToAction("Index");
            }
            catch
            {
                return View();
            }
        }

    }
}

Klasa Kontrolera domu w liście List 1 zawiera dwie akcje Create(). Pierwsza akcja wyświetla formularz HTML do utworzenia nowego filmu. Druga akcja Create() wykonuje rzeczywiste wstawianie nowego filmu do bazy danych. Druga akcja Create() jest wywoływana, gdy formularz wyświetlany przez pierwszą akcję Create() jest przesyłany do serwera.

Zwróć uwagę, że druga akcja Create() zawiera następujące wiersze kodu:

// Validate
if (!ModelState.IsValid)
    return View();

Właściwość IsValid zwraca wartość false w przypadku wystąpienia błędu walidacji. W takim przypadku widok Utwórz zawierający formularz HTML do tworzenia filmu jest odtwarzany ponownie.

Tworzenie klasy częściowej

Klasa Movie jest generowana przez program Entity Framework. Kod klasy Movie można wyświetlić, jeśli rozwiń plik MoviesDBModel.edmx w oknie Eksplorator rozwiązań i otwórz plik MoviesDBModel.Projektant. plik cs w Edytorze kodu (zobacz Rysunek 2).

Kod jednostki Movie

Rysunek 02. Kod jednostki Film (kliknij, aby wyświetlić obraz pełnowymiarowy)

Klasa Movie jest klasą częściową. Oznacza to, że możemy dodać kolejną klasę częściową o tej samej nazwie, aby rozszerzyć funkcjonalność klasy Movie. Dodamy naszą logikę walidacji do nowej klasy częściowej.

Dodaj klasę na liście 2 do folderu Models.

Lista 2 — Models\Movie.cs

using System.Collections.Generic;
using System.ComponentModel;

namespace MvcApplication1.Models
{

    public partial class Movie 
    {

    }
}

Zwróć uwagę, że klasa w liście 2 zawiera modyfikator częściowy . Wszystkie metody lub właściwości dodane do tej klasy stają się częścią klasy Movie wygenerowanej przez platformę Entity Framework.

Dodawanie metod częściowych OnChanging i OnChanged

Gdy program Entity Framework generuje klasę jednostki, program Entity Framework automatycznie dodaje metody częściowe do klasy. Struktura Entity Framework generuje metody częściowe OnChanging i OnChanged odpowiadające każdej właściwości klasy.

W przypadku klasy Movie struktura Entity Framework tworzy następujące metody:

  • OnIdChanging
  • OnIdChanged
  • OnTitleChanging
  • OnTitleChanged
  • OnDirectorChanging
  • OnDirectorChanged
  • OnDateReleasedChanging
  • OnDateReleasedChanged

Metoda OnChanging jest wywoływana bezpośrednio przed zmianą odpowiedniej właściwości. Metoda OnChanged jest wywoływana bezpośrednio po zmianie właściwości.

Możesz skorzystać z tych częściowych metod, aby dodać logikę walidacji do klasy Movie. Aktualizacja klasy Movie w liście List 3 sprawdza, czy właściwości Tytuł i Reżyser są przypisane żadne wartości.

Uwaga

Metoda częściowa to metoda zdefiniowana w klasie, której nie trzeba implementować. Jeśli nie zaimplementujesz metody częściowej, kompilator usunie sygnaturę metody i wszystkie wywołania metody, aby nie było żadnych kosztów czasu wykonywania skojarzonych z metodą częściową. W edytorze Visual Studio Code możesz dodać metodę częściową, wpisując słowo kluczowe częściowe, a następnie spację, aby wyświetlić listę częściowych do zaimplementowania.

Lista 3 — Models\Movie.cs

using System.Collections.Generic;
using System.ComponentModel;

namespace MvcApplication1.Models
{

    public partial class Movie : IDataErrorInfo
    {
        private Dictionary<string, string> _errors = new Dictionary<string, string>();

        partial void OnTitleChanging(string value)
        {
            if (value.Trim().Length == 0)
                _errors.Add("Title", "Title is required.");
        }

        partial void OnDirectorChanging(string value)
        {
            if (value.Trim().Length == 0)
                _errors.Add("Director", "Director is required.");
        }

    }
}

Jeśli na przykład spróbujesz przypisać pusty ciąg do właściwości Title, do słownika o nazwie _errors zostanie przypisany komunikat o błędzie.

W tym momencie nic się nie dzieje po przypisaniu pustego ciągu do właściwości Title i do pola prywatnego _errors jest dodawany błąd. Musimy zaimplementować interfejs IDataErrorInfo, aby uwidocznić te błędy weryfikacji w strukturze ASP.NET MVC.

Implementowanie interfejsu IDataErrorInfo

Interfejs IDataErrorInfo jest częścią platformy .NET Framework od pierwszej wersji. Ten interfejs jest bardzo prostym interfejsem:

public interface IDataErrorInfo
{
    string this[string columnName] { get; }

    string Error { get; }
}

Jeśli klasa implementuje interfejs IDataErrorInfo, platforma ASP.NET MVC będzie używać tego interfejsu podczas tworzenia wystąpienia klasy. Na przykład akcja Utwórz() kontrolera głównego akceptuje wystąpienie klasy Movie:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Exclude = "Id")] Movie movieToCreate)
{
    // Validate
    if (!ModelState.IsValid)
        return View();

    // Add to database
    try
    {
        _db.AddToMovieSet(movieToCreate);
        _db.SaveChanges();

        return RedirectToAction("Index");
    }
    catch
    {
        return View();
    }
}

Struktura ASP.NET MVC tworzy wystąpienie akcji Movie przekazane do akcji Create() przy użyciu powiązania modelu (DefaultModelBinder). Powiązanie modelu jest odpowiedzialne za utworzenie wystąpienia obiektu Movie przez powiązanie pól formularza HTML z wystąpieniem obiektu Movie.

Parametr DefaultModelBinder wykrywa, czy klasa implementuje interfejs IDataErrorInfo. Jeśli klasa implementuje ten interfejs, binder modelu wywołuje indeksator IDataErrorInfo.this dla każdej właściwości klasy. Jeśli indeksator zwraca komunikat o błędzie, powiązanie modelu automatycznie dodaje ten komunikat o błędzie do stanu modelu.

Właściwość DefaultModelBinder sprawdza również właściwość IDataErrorInfo.Error. Ta właściwość jest przeznaczona do reprezentowania błędów weryfikacji specyficznych dla właściwości skojarzonych z klasą. Na przykład możesz wymusić regułę weryfikacji, która zależy od wartości wielu właściwości klasy Movie. W takim przypadku zostanie zwrócony błąd weryfikacji z właściwości Error.

Zaktualizowana klasa Movie na liście 4 implementuje interfejs IDataErrorInfo.

Lista 4 — Models\Movie.cs (implementuje IDataErrorInfo)

using System.Collections.Generic;
using System.ComponentModel;

namespace MvcApplication1.Models
{

    public partial class Movie : IDataErrorInfo
    {
        private Dictionary<string, string> _errors = new Dictionary<string, string>();

        partial void OnTitleChanging(string value)
        {
            if (value.Trim().Length == 0)
                _errors.Add("Title", "Title is required.");
        }

        partial void OnDirectorChanging(string value)
        {
            if (value.Trim().Length == 0)
                _errors.Add("Director", "Director is required.");
        }

        #region IDataErrorInfo Members

        public string Error
        {
            get
            {
                return string.Empty;
            }
        }

        public string this[string columnName]
        {
            get
            {
                if (_errors.ContainsKey(columnName))
                    return _errors[columnName];
                return string.Empty;
            }
        }

        #endregion
    }
}

Na liście 4 właściwość indeksatora sprawdza kolekcję _errors, aby sprawdzić, czy zawiera klucz odpowiadający nazwie właściwości przekazanej indeksatorowi. Jeśli nie ma błędu walidacji skojarzonego z właściwością, zwracany jest pusty ciąg.

Nie musisz modyfikować kontrolera home w żaden sposób, aby używać zmodyfikowanej klasy Movie. Strona wyświetlana na rysunku 3 ilustruje, co się stanie, gdy dla pól formularza Tytuł lub Dyrektor nie zostanie wprowadzona żadna wartość.

Automatyczne tworzenie metod akcji

Rysunek 03. Formularz z brakującymi wartościami (kliknij, aby wyświetlić obraz pełnowymiarowy)

Zwróć uwagę, że wartość DateReleased jest sprawdzana automatycznie. Ponieważ właściwość DateReleased nie akceptuje wartości NULL, właściwość DefaultModelBinder generuje błąd walidacji dla tej właściwości automatycznie, gdy nie ma wartości. Jeśli chcesz zmodyfikować komunikat o błędzie dla właściwości DateReleased, musisz utworzyć niestandardowy binder modelu.

Podsumowanie

W tym samouczku przedstawiono sposób używania interfejsu IDataErrorInfo do generowania komunikatów o błędach walidacji. Najpierw utworzyliśmy częściową klasę Movie, która rozszerza funkcjonalność częściowej klasy Movie wygenerowanej przez platformę Entity Framework. Następnie dodaliśmy logikę walidacji do metod częściowych Klasy Movie OnTitleChanging() i OnDirectorChanging(). Na koniec zaimplementowaliśmy interfejs IDataErrorInfo w celu uwidocznienia tych komunikatów weryfikacji na platformie ASP.NET MVC.