Поделиться через


Проверка с помощью интерфейса IDataErrorInfo (VB)

Стивен Уолтер

Стивен Вальтер (Stephen Walther) показывает, как отображать пользовательские сообщения об ошибках проверки, реализовав интерфейс IDataErrorInfo в классе модели.

Цель этого руководства — объяснить один из подходов к выполнению проверки в ASP.NET приложении MVC. Вы узнаете, как запретить пользователям отправлять HTML-форму, не предоставляя значения для обязательных полей формы. В этом руководстве описано, как выполнить проверку с помощью интерфейса IErrorDataInfo.

Предположения

В этом руководстве мы будем использовать базу данных MoviesDB и таблицу базы данных Movies. Эта таблица имеет следующие столбцы.

Имя столбца Тип данных Разрешить значения NULL
Идентификатор Int Неверно
Заголовок Nvarchar(100) Неверно
Директор Nvarchar(100) Неверно
DateReleased Дата и время Неверно

В этом руководстве я использую Microsoft Entity Framework для создания классов модели базы данных. Класс Movie, созданный Entity Framework, показан на рис. 1.

Сущность Movie

Рис. 01. Сущность Movie(Щелкните для просмотра полноразмерного изображения)

Примечание

Дополнительные сведения об использовании Entity Framework для создания классов модели базы данных см. в руководстве Создание классов моделей с помощью Entity Framework.

Класс контроллера

Мы используем контроллер Home для вывода списка фильмов и создания новых фильмов. Код для этого класса содержится в листинге 1.

Листинг 1. Controllers\HomeController.vb

Public Class HomeController
Inherits Controller

Private _db As New MoviesDBEntities()

Public Function Index() As ActionResult
    Return View(_db.MovieSet.ToList())
End Function

Public Function Create() As ActionResult
    Return View()
End Function

<AcceptVerbs(HttpVerbs.Post)> _
Public Function Create(<Bind(Exclude := "Id")> ByVal movieToCreate As Movie) As ActionResult
        ' Validate
        If (Not ModelState.IsValid) Then
        Return View()
        End If

    ' Add to database
    Try
        _db.AddToMovieSet(movieToCreate)
        _db.SaveChanges()

        Return RedirectToAction("Index")
    Catch
        Return View()
    End Try
End Function

End Class

Класс контроллера Home в листинге 1 содержит два действия Create(). Первое действие отображает HTML-форму для создания нового фильма. Второе действие Create() выполняет фактическую вставку нового фильма в базу данных. Второе действие Create() вызывается при отправке на сервер формы, отображаемой первым действием Create().

Обратите внимание, что второе действие Create() содержит следующие строки кода:

' Validate
If (Not ModelState.IsValid) Then
Return View()
End If

Свойство IsValid возвращает значение false при возникновении ошибки проверки. В этом случае представление Create, содержащее HTML-форму для создания фильма, будет переиграно.

Создание разделяемого класса

Класс Movie создается Entity Framework. Вы увидите код для класса Movie, разверните файл MoviesDBModel.edmx в окне Обозреватель решений и откройте MoviesDBModel.Designer. VB-файл в редакторе кода (см. рис. 2).

Код для сущности Movie

Рис. 02. Код для сущности Movie(Щелкните для просмотра полноразмерного изображения)

Класс Movie является разделяемым классом. Это означает, что мы можем добавить еще один разделяемый класс с тем же именем, чтобы расширить функциональные возможности класса Movie. Мы добавим логику проверки в новый разделяемый класс.

Добавьте класс из листинга 2 в папку Models.

Листинг 2. Models\Movie.vb

Public Partial Class Movie

End Class

Обратите внимание, что класс в листинге 2 включает модификатор partial . Все методы или свойства, добавляемые в этот класс, становятся частью класса Movie, созданного Entity Framework.

Добавление разделяемых методов OnChanging и OnChanged

Когда Entity Framework создает класс сущности, Entity Framework автоматически добавляет разделяемые методы в класс. Entity Framework создает разделяемые методы OnChanging и OnChanged, соответствующие каждому свойству класса .

В случае с классом Movie Entity Framework создает следующие методы:

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

Метод OnChanging вызывается непосредственно перед изменением соответствующего свойства. Метод OnChanged вызывается сразу после изменения свойства.

Вы можете воспользоваться преимуществами этих разделяемых методов, чтобы добавить логику проверки в класс Movie. Класс обновления Movie в листинге 3 проверяет, назначены ли свойствам Title и Director непустые значения.

Примечание

Разделяемый метод — это метод, определенный в классе, который не требуется реализовывать. Если разделяемый метод не реализован, компилятор удаляет сигнатуру метода и все вызовы метода, чтобы не было затрат времени выполнения, связанных с разделяемым методом. В редакторе Visual Studio Code можно добавить разделяемый метод, введя ключевое слово partial и пробел для просмотра списка разделяемых элементов для реализации.

Листинг 3. Models\Movie.vb

Imports System.ComponentModel

Partial Public Class Movie
    Implements IDataErrorInfo

    Private _errors As New Dictionary(Of String, String)()

    Private Sub OnTitleChanging(ByVal value As String)
        If value.Trim().Length = 0 Then
            _errors.Add("Title", "Title is required.")
        End If
    End Sub

    Private Sub OnDirectorChanging(ByVal value As String)
        If value.Trim().Length = 0 Then
            _errors.Add("Director", "Director is required.")
        End If
    End Sub

End Class

Например, при попытке назначить пустую строку свойству Title, словарю с именем _errors назначается сообщение об ошибке.

На этом этапе ничего не происходит при назначении пустой строки свойству Title и добавлении ошибки в частное поле _errors. Необходимо реализовать интерфейс IDataErrorInfo, чтобы предоставить эти ошибки проверки ASP.NET платформе MVC.

Реализация интерфейса IDataErrorInfo

Интерфейс IDataErrorInfo был частью платформы .NET Framework с первой версии. Это очень простой интерфейс:

Public Interface IDataErrorInfo
  Default ReadOnly Property Item(ByVal columnName As String) As String
  ReadOnly Property [Error]() As String
End Interface

Если класс реализует интерфейс IDataErrorInfo, платформа MVC ASP.NET будет использовать этот интерфейс при создании экземпляра класса . Например, действие Create() контроллера Home принимает экземпляр класса Movie:

<AcceptVerbs(HttpVerbs.Post)> _
Public Function Create(<Bind(Exclude := "Id")> ByVal movieToCreate As Movie) As ActionResult
    ' Validate
    If (Not ModelState.IsValid) Then
        Return View()
    End If

    ' Add to database
    Try
        _db.AddToMovieSet(movieToCreate)
        _db.SaveChanges()

        Return RedirectToAction("Index")
    Catch
        Return View()
    End Try
End Function

Платформа ASP.NET MVC создает экземпляр действия Movie, переданного в Create(), с помощью средства привязки модели (DefaultModelBinder). Связыватель модели отвечает за создание экземпляра объекта Movie путем привязки полей формы HTML к экземпляру объекта Movie.

DefaultModelBinder определяет, реализует ли класс интерфейс IDataErrorInfo. Если класс реализует этот интерфейс, то связыватель модели вызывает индексатор IDataErrorInfo.this для каждого свойства класса. Если индексатор возвращает сообщение об ошибке, связыватель модели автоматически добавляет это сообщение об ошибке в состояние модели.

DefaultModelBinder также проверяет свойство IDataErrorInfo.Error. Это свойство предназначено для представления ошибок проверки, не относящихся к свойствам, связанных с классом . Например, может потребоваться применить правило проверки, зависящее от значений нескольких свойств класса Movie. В этом случае вы вернете ошибку проверки из свойства Error.

Обновленный класс Movie в листинге 4 реализует интерфейс IDataErrorInfo.

Листинг 4 . Models\Movie.vb (реализует IDataErrorInfo)

Imports System.ComponentModel

Partial Public Class Movie
    Implements IDataErrorInfo

    Private _errors As New Dictionary(Of String, String)()

    Private Sub OnTitleChanging(ByVal value As String)
        If value.Trim().Length = 0 Then
            _errors.Add("Title", "Title is required.")
        End If
    End Sub

    Private Sub OnDirectorChanging(ByVal value As String)
        If value.Trim().Length = 0 Then
            _errors.Add("Director", "Director is required.")
        End If
    End Sub

#Region "IDataErrorInfo Members"

    Public ReadOnly Property [Error]() As String Implements IDataErrorInfo.Error
        Get
            Return String.Empty
        End Get
    End Property

    Default Public ReadOnly Property Item(ByVal columnName As String) As String Implements IDataErrorInfo.Item
        Get
            If _errors.ContainsKey(columnName) Then
                Return _errors(columnName)
            End If
            Return String.Empty
        End Get
    End Property

#End Region

End Class

В листинге 4 свойство индексатора проверяет коллекцию _errors, чтобы узнать, содержит ли она ключ, соответствующий имени свойства, переданного индексатору. Если ошибка проверки не связана со свойством, возвращается пустая строка.

Вам не нужно каким-либо образом изменять контроллер Home, чтобы использовать измененный класс Movie. На странице, показанной на рисунке 3, показано, что происходит, если не ввести значения для полей формы "Название" или "Директор".

Автоматическое создание методов действий

Рис. 03. Форма с отсутствующими значениями (щелкните для просмотра полноразмерного изображения)

Обратите внимание, что значение DateReleased проверяется автоматически. Так как свойство DateReleased не принимает значения NULL, DefaultModelBinder автоматически создает ошибку проверки для этого свойства, если оно не имеет значения. Если вы хотите изменить сообщение об ошибке для свойства DateReleased, необходимо создать настраиваемый связыватель модели.

Итоги

В этом руководстве вы узнали, как использовать интерфейс IDataErrorInfo для создания сообщений об ошибках проверки. Сначала мы создали разделяемый класс Movie, который расширяет функциональные возможности разделяемого класса Movie, созданного Entity Framework. Далее мы добавили логику проверки в разделяемые методы Класса Movie OnTitleChanging() и OnDirectorChanging(). Наконец, мы реализовали интерфейс IDataErrorInfo, чтобы предоставить эти сообщения проверки платформе ASP.NET MVC.