Изучение методов Edit и представления Edit (VB)
В этом руководстве описаны основы создания веб-приложения ASP.NET MVC с помощью Microsoft Visual Web Developer 2010 Express с пакетом обновления 1 (SP1), который является бесплатной версией Microsoft Visual Studio. Перед началом работы убедитесь, что вы установили необходимые компоненты, перечисленные ниже. Вы можете установить все из них, щелкнув следующую ссылку: Установщик веб-платформы. Кроме того, предварительные требования можно установить по отдельности, используя следующие ссылки:
- Предварительные требования для Visual Studio Web Developer Express с пакетом обновления 1 (SP1)
- ASP.NET обновление средств MVC 3
- SQL Server Compact 4.0 (поддержка среды выполнения и средств)
Если вы используете Visual Studio 2010 вместо Visual Web Developer 2010, установите необходимые компоненты, щелкнув следующую ссылку: Предварительные требования Для Visual Studio 2010.
В этом разделе доступен проект Visual Web Developer с VB.NET исходным кодом. Скачайте версию VB.NET. Если вы предпочитаете C#, переключитесь на версию этого руководства на C# .
В этом разделе вы изучите созданные методы действий и представления для контроллера фильма. Затем вы добавите настраиваемую страницу поиска.
Запустите приложение и перейдите к контроллеру Movies
, добавив параметр /Movies к URL-адресу в адресной строке браузера. Наведите указатель мыши на ссылку Изменить , чтобы увидеть URL-адрес, на который она ссылается.
Ссылка "Изменить " была создана методом Html.ActionLink
в представлении Views\Movies\Index.vbhtml :
@Html.ActionLink("Edit", "Edit", New With {.id = currentItem.ID}) |
Объект Html
является вспомогательным объектом, предоставляемым с помощью свойства WebViewPage
базового класса. Метод ActionLink
вспомогательного средства упрощает динамическое создание html-гиперссылок, ссылающихся на методы действий на контроллерах. Первым аргументом ActionLink
метода является текст ссылки для отрисовки (например, <a>Edit Me</a>
). Второй аргумент — это имя вызываемого метода действия. Последним аргументом является анонимный объект , который создает данные маршрута (в данном случае идентификатор 4).
Созданная ссылка, показанная на предыдущем изображении, — http://localhost:xxxxx/Movies/Edit/4
. Маршрут по умолчанию принимает шаблон {controller}/{action}/{id}
URL-адреса . Таким образом, ASP.NET преобразуется http://localhost:xxxxx/Movies/Edit/4
в запрос к методу Edit
действия контроллера Movies
с параметром ID
, равным 4.
Вы также можете передать параметры метода действия с помощью строки запроса. Например, URL-адрес http://localhost:xxxxx/Movies/Edit?ID=4
также передает параметр ID
4 методу Edit
действия контроллера Movies
.
Movies
Откройте контроллер. Ниже приведены два Edit
метода действия.
'
' GET: /Movies/Edit/5
Function Edit(id As Integer) As ViewResult
Dim movie As Movie = db.Movies.Find(id)
Return View(movie)
End Function
'
' POST: /Movies/Edit/5
<HttpPost()>
Function Edit(movie As Movie) As ActionResult
If ModelState.IsValid Then
db.Entry(movie).State = EntityState.Modified
db.SaveChanges()
Return RedirectToAction("Index")
End If
Return View(movie)
End Function
Обратите внимание на второй метод действия Edit
, которому предшествует атрибут HttpPost
. Этот атрибут указывает, что перегрузку Edit
метода можно вызывать только для запросов POST. Атрибут можно применить HttpGet
к первому методу edit, но это необязательно, так как он используется по умолчанию. (Мы будем называть методы действий, которым атрибут неявно назначается HttpGet
как HttpGet
методы.)
Метод HttpGet
Edit
принимает параметр movie ID, ищет фильм с помощью метода Entity Framework Find
и возвращает выбранный фильм в представление Правка. Если в представлении редактирования создана система формирования шаблонов, она проверяет класс Movie
и создает код для отображения элементов <label>
и <input>
для каждого свойства класса. В следующем примере показано созданное представление Правка:
@ModelType MvcMovie.Movie
@Code
ViewData("Title") = "Edit"
End Code
<h2>Edit</h2>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
@Using Html.BeginForm()
@Html.ValidationSummary(True)
@<fieldset>
<legend>Movie</legend>
@Html.HiddenFor(Function(model) model.ID)
<div class="editor-label">
@Html.LabelFor(Function(model) model.Title)
</div>
<div class="editor-field">
@Html.EditorFor(Function(model) model.Title)
@Html.ValidationMessageFor(Function(model) model.Title)
</div>
<div class="editor-label">
@Html.LabelFor(Function(model) model.ReleaseDate)
</div>
<div class="editor-field">
@Html.EditorFor(Function(model) model.ReleaseDate)
@Html.ValidationMessageFor(Function(model) model.ReleaseDate)
</div>
<div class="editor-label">
@Html.LabelFor(Function(model) model.Genre)
</div>
<div class="editor-field">
@Html.EditorFor(Function(model) model.Genre)
@Html.ValidationMessageFor(Function(model) model.Genre)
</div>
<div class="editor-label">
@Html.LabelFor(Function(model) model.Price)
</div>
<div class="editor-field">
@Html.EditorFor(Function(model) model.Price)
@Html.ValidationMessageFor(Function(model) model.Price)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
End Using
<div>
@Html.ActionLink("Back to List", "Index")
</div>
Обратите внимание, что шаблон представления имеет @ModelType MvcMovie.Models.Movie
оператор в верхней части файла. Это указывает, что представление ожидает, что модель для шаблона представления будет иметь тип Movie
.
Шаблонный код использует несколько вспомогательных методов для упрощения разметки HTML. В Html.LabelFor
вспомогательном средстве отображается имя поля ("Title", "ReleaseDate", "Genre" или "Price"). Во Html.EditorFor
вспомогательном элементе отображается элемент HTML <input>
. Вспомогательное Html.ValidationMessageFor
средство отображает все сообщения проверки, связанные с этим свойством.
Запустите приложение и перейдите по URL-адресу /Movies . Щелкните ссылку Edit (Изменить). Просмотрите исходный код страницы в окне браузера. HTML-код на странице выглядит так, как показано в следующем примере. (Разметка меню была исключена для ясности.)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Edit</title>
<link href="/Content/Site.css" rel="stylesheet" type="text/css" />
<script src="/Scripts/jquery-1.5.1.min.js" type="text/javascript"></script>
<script src="/Scripts/modernizr-1.7.min.js" type="text/javascript"></script>
</head>
<body>
<div class="page">
<header>
<div id="title">
<h1>MVC Movie App</h1>
</div>
...
</header>
<section id="main">
<h2>Edit</h2>
<script src="/Scripts/jquery.validate.min.js" type="text/javascript"></script>
<script src="/Scripts/jquery.validate.unobtrusive.min.js" type="text/javascript"></script>
<form action="/Movies/Edit/4" method="post"> <fieldset>
<legend>Movie</legend>
<input data-val="true" data-val-number="The field ID must be a number."
data-val-required="The ID field is required." id="ID" name="ID" type="hidden" value="4" />
<div class="editor-label">
<label for="Title">Title</label>
</div>
<div class="editor-field">
<input class="text-box single-line" id="Title" name="Title" type="text" value="Rio Bravo" />
<span class="field-validation-valid" data-valmsg-for="Title" data-valmsg-replace="true"></span>
</div>
<div class="editor-label">
<label for="ReleaseDate">ReleaseDate</label>
</div>
<div class="editor-field">
<input class="text-box single-line" data-val="true" data-val-required="The ReleaseDate field is required."
id="ReleaseDate" name="ReleaseDate" type="text" value="4/15/1959 12:00:00 AM" />
<span class="field-validation-valid" data-valmsg-for="ReleaseDate" data-valmsg-replace="true"></span>
</div>
<div class="editor-label">
<label for="Genre">Genre</label>
</div>
<div class="editor-field">
<input class="text-box single-line" id="Genre" name="Genre" type="text" value="Western" />
<span class="field-validation-valid" data-valmsg-for="Genre" data-valmsg-replace="true"></span>
</div>
<div class="editor-label">
<label for="Price">Price</label>
</div>
<div class="editor-field">
<input class="text-box single-line" data-val="true" data-val-number="The field Price must be a number."
data-val-required="The Price field is required." id="Price" name="Price" type="text" value="9.99" />
<span class="field-validation-valid" data-valmsg-for="Price" data-valmsg-replace="true"></span>
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
</form>
<div>
<a href="/Movies">Back to List</a>
</div>
</section>
<footer>
</footer>
</div>
</body>
</html>
Элементы <input>
находятся в элементе HTML <form>
, атрибут которого action
имеет значение post в URL-адресе /Movies/Edit . Данные формы будут отправляться на сервер при нажатии кнопки Изменить .
Обработка запроса POST
В следующем листинге демонстрируется версия HttpPost
метода действия Edit
.
'
' POST: /Movies/Edit/5
<HttpPost()>
Function Edit(movie As Movie) As ActionResult
If ModelState.IsValid Then
db.Entry(movie).State = EntityState.Modified
db.SaveChanges()
Return RedirectToAction("Index")
End If
Return View(movie)
End Function
Связыватель модели платформы ASP.NET принимает опубликованные значения формы и создает Movie
объект, передаваемый в movie
качестве параметра . Проверка ModelState.IsValid
в коде проверяет, можно ли использовать данные, отправленные в форме, для изменения Movie
объекта. Если данные допустимы, код сохраняет данные фильма в Movies
коллекции экземпляра MovieDBContext
. Затем код сохраняет данные нового фильма в базе данных путем вызова SaveChanges
метода MovieDBContext
, который сохраняет изменения в базе данных. После сохранения данных код перенаправляет пользователя к методу Index
MoviesController
action класса , что приводит к отображению обновленного фильма в списке фильмов.
Если опубликованные значения недопустимы, они повторно отображаются в форме. Вспомогательные Html.ValidationMessageFor
функции в шаблоне представления Edit.vbhtml помогают отображать соответствующие сообщения об ошибках.
Примечание о языковых стандартах Если вы обычно работаете с языковым стандартом, отличным от английского, см. раздел Поддержка проверки ASP.NET MVC 3 с языковыми стандартами, не на английском языке.
Обеспечение надежности метода Edit
МетодHttpGet
Edit
, созданный системой формирования шаблонов, не проверка, что переданный ему идентификатор является допустимым. Если пользователь удаляет сегмент идентификатора из URL-адреса (http://localhost:xxxxx/Movies/Edit
), отображается следующая ошибка:
Пользователь также может передать идентификатор, который не существует в базе данных, например http://localhost:xxxxx/Movies/Edit/1234
. Чтобы устранить это ограничение, HttpGet
Edit
в метод действия можно внести два изменения. Сначала измените ID
параметр на нулевое значение по умолчанию, если идентификатор не передается явным образом. Вы также можете проверка, что Find
метод на самом деле нашел фильм, прежде чем возвращать объект movie в шаблон представления. Обновленный Edit
метод показан ниже.
Public Function Edit(Optional ByVal id As Integer = 0) As ActionResult
Dim movie As Movie = db.Movies.Find(id)
If movie Is Nothing Then
Return HttpNotFound()
End If
Return View(movie)
End Function
Если фильм не найден, HttpNotFound
вызывается метод .
Все методы HttpGet
следуют аналогичному шаблону. Они получают объект фильма (или список объектов, в случае Index
) и передают модель в представление. Метод Create
передает пустой объект movie в представление Create. Все методы, которые создают, редактируют, удаляют или иным образом изменяют данные, делают это в перегрузке метода HttpPost
. Изменение данных в методе HTTP GET представляет угрозу безопасности, как описано в записи блога ASP.NET совет MVC No 46. Не используйте удаление ссылок, так как они создают брели в системе безопасности. Изменение данных в методе GET также нарушает рекомендации по HTTP и архитектурный шаблон REST, который указывает, что запросы GET не должны изменять состояние приложения. Иными словами, выполнение операции GET должно быть безопасной операцией без побочных эффектов.
Добавление метода поиска и представления поиска
В этом разделе вы добавите SearchIndex
метод действия, который позволяет искать фильмы по жанру или имени. Это будет доступно по URL-адресу /Movies/SearchIndex . В запросе отобразится HTML-форма, содержащая входные элементы, которые пользователь может заполнить для поиска фильма. Когда пользователь отправляет форму, метод действия получает значения поиска, опубликованные пользователем, и использует их для поиска в базе данных.
Отображение формы SearchIndex
Начните с SearchIndex
добавления метода действия в существующий MoviesController
класс. Метод возвращает представление, содержащее HTML-форму. Вот этот код:
Public Function SearchIndex(ByVal searchString As String) As ActionResult
Dim movies = From m In db.Movies
Select m
If Not String.IsNullOrEmpty(searchString) Then
movies = movies.Where(Function(s) s.Title.Contains(searchString))
End If
Return View(movies)
End Function
В первой строке SearchIndex
метода создается следующий запрос LINQ для выбора фильмов:
Dim movies = From m In db.Movies Select m
На этом этапе запрос определен, но еще не был выполнен в хранилище данных.
searchString
Если параметр содержит строку, запрос movies изменяется для фильтрации по значению строки поиска с использованием следующего кода:
If Not String.IsNullOrEmpty(searchString) Then
movies = фильмы. Where(Function(s) s.Title.Contains(searchString))
Окончание при
Запросы LINQ не выполняются при их определении или изменении путем вызова метода, Where
например или OrderBy
. Вместо этого выполнение запроса откладывается, что означает, что вычисление выражения откладывается до тех пор, пока его реализованное значение не будет фактически перетерировано или ToList
до вызова метода . SearchIndex
В примере запрос выполняется в представлении SearchIndex. Дополнительные сведения об отложенном и немедленном выполнении запросов см. в разделе Выполнение запроса.
Теперь можно реализовать SearchIndex
представление, которое будет отображать форму для пользователя. Щелкните правой кнопкой мыши внутри SearchIndex
метода и выберите команду Добавить представление. В диалоговом окне Добавление представления укажите, что вы собираетесь передать Movie
объект в шаблон представления в качестве класса модели. В списке Шаблон шаблонов выберите Список и нажмите кнопку Добавить.
При нажатии кнопки Добавить создается шаблон представления Views\Movies\SearchIndex.vbhtml . Так как вы выбрали Список в списке шаблонов , Visual Web Developer автоматически создает (формирует шаблон) содержимое по умолчанию в представлении. Формирование шаблонов создало HTML-форму. Он изучил Movie
класс и создал код для отрисовки <label>
элементов для каждого свойства класса. В приведенном ниже списке показано созданное представление Создания:
@ModelType IEnumerable(Of MvcMovie.Movie)
@Code
ViewData("Title") = "SearchIndex"
End Code
<h2>SearchIndex</h2>
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th>
Title
</th>
<th>
ReleaseDate
</th>
<th>
Genre
</th>
<th>
Price
</th>
<th></th>
</tr>
@For Each item In Model
Dim currentItem = item
@<tr>
<td>
@Html.DisplayFor(Function(modelItem) currentItem.Title)
</td>
<td>
@Html.DisplayFor(Function(modelItem) currentItem.ReleaseDate)
</td>
<td>
@Html.DisplayFor(Function(modelItem) currentItem.Genre)
</td>
<td>
@Html.DisplayFor(Function(modelItem) currentItem.Price)
</td>
<td>
@Html.ActionLink("Edit", "Edit", New With {.id = currentItem.ID}) |
@Html.ActionLink("Details", "Details", New With {.id = currentItem.ID}) |
@Html.ActionLink("Delete", "Delete", New With {.id = currentItem.ID})
</td>
</tr>
Next
</table>
Запустите приложение и перейдите в папку /Movies/SearchIndex. Добавьте в URL-адрес строку запроса, например ?searchString=ghost
. Отображаются отфильтрованные фильмы.
Если изменить сигнатуру SearchIndex
метода на параметр с именем id
, id
параметр будет соответствовать {id}
заполнителю для маршрутов по умолчанию, заданных в файле Global.asax .
{controller}/{action}/{id}
Измененный SearchIndex
метод будет выглядеть следующим образом:
Public Function SearchIndex(ByVal id As String) As ActionResult
Dim searchString As String = id
Dim movies = From m In db.Movies
Select m
If Not String.IsNullOrEmpty(searchString) Then
movies = movies.Where(Function(s) s.Title.Contains(searchString))
End If
Return View(movies)
End Function
Теперь можно передать заголовок поиска в качестве данных маршрута (сегмент URL-адреса) вместо значения строки запроса.
Тем не менее пользователи вряд ли будут каждый раз изменять URL-адрес для поиска фильмов. Теперь вы добавите пользовательский интерфейс, чтобы помочь им фильтровать фильмы. Если вы изменили сигнатуру SearchIndex
метода для проверки способа передачи параметра идентификатора, привязанного к маршруту, измените его обратно, чтобы SearchIndex
метод принимает строковый параметр с именем searchString
:
Откройте файл Views\Movies\SearchIndex.vbhtml и сразу после @Html.ActionLink("Create New", "Create")
добавьте следующее:
@Code
ViewData("Title") = "SearchIndex"
Using (Html.BeginForm())
@<p> Title: @Html.TextBox("SearchString")
<input type="submit" value="Filter" /></p>
End Using
End Code
Вспомогатель Html.BeginForm
создает открывающий <form>
тег. Вспомогающая Html.BeginForm
функция приводит к публикации формы, когда пользователь отправляет форму, нажимая кнопку Фильтр .
Запустите приложение и попробуйте найти фильм.
Перегрузка метода отсутствует HttpPost
SearchIndex
. Он вам не нужен, так как метод не изменяет состояние приложения, а просто фильтрует данные. Если вы добавили следующий HttpPost
SearchIndex
метод, вызов действия будет соответствовать методу HttpPost
SearchIndex
HttpPost
SearchIndex
, и метод будет выполняться, как показано на рисунке ниже.
<HttpPost()>
Public Function SearchIndex(ByVal fc As FormCollection, ByVal searchString As String) As String
Return "<h3> From [HttpPost]SearchIndex: " & searchString & "</h3>"
End Function
Добавление поиска по жанру
Если вы добавили HttpPost
версию SearchIndex
метода, удалите ее сейчас.
Далее вы добавите функцию, которая позволит пользователям искать фильмы по жанру. Замените метод SearchIndex
следующим кодом:
Public Function SearchIndex(ByVal movieGenre As String, ByVal searchString As String) As ActionResult
Dim GenreLst = New List(Of String)()
Dim GenreQry = From d In db.Movies
Order By d.Genre
Select d.Genre
GenreLst.AddRange(GenreQry.Distinct())
ViewBag.movieGenre = New SelectList(GenreLst)
Dim movies = From m In db.Movies
Select m
If Not String.IsNullOrEmpty(searchString) Then
movies = movies.Where(Function(s) s.Title.Contains(searchString))
End If
If String.IsNullOrEmpty(movieGenre) Then
Return View(movies)
Else
Return View(movies.Where(Function(x) x.Genre = movieGenre))
End If
End Function
Эта версия SearchIndex
метода принимает дополнительный параметр, а именно movieGenre
. Первые несколько строк кода создают List
объект для хранения жанров фильмов из базы данных.
Следующий код определяет запрос LINQ, который извлекает все жанры из базы данных.
Dim GenreQry = From d In db.Movies
Order By d.Genre
Select d.Genre
Код использует AddRange
метод универсальной List
коллекции для добавления всех различных жанров в список. (Без модификатора Distinct
будут добавлены дублирующиеся жанры— например, комедия будет добавлена дважды в нашем примере). Затем код сохраняет список жанров в объекте ViewBag
.
В следующем коде показано, как проверка movieGenre
параметр . Если он не пуст, код дополнительно ограничивает запрос фильмов, чтобы ограничить выбранные фильмы указанным жанром.
If String.IsNullOrEmpty(movieGenre) Then
Return View(movies)
Else
Return View(movies.Where(Function(x) x.Genre = movieGenre))
End If
Добавление разметки в представление SearchIndex для поддержки поиска по жанрам
Добавьте вспомогатель Html.DropDownList
в файл Views\Movies\SearchIndex.vbhtml непосредственно перед вспомогательным файлом TextBox
. Завершенная разметка показана ниже:
<p>
@Html.ActionLink("Create New", "Create")
@Code
ViewData("Title") = "SearchIndex"
Using (Html.BeginForm())
@<p> Genre: @Html.DropDownList("movieGenre", "All")
Title: @Html.TextBox("SearchString")
<input type="submit" value="Filter" /></p>
End Using
End Code
</p>
Запустите приложение и перейдите в папку /Movies/SearchIndex. Попробуйте выполнить поиск по жанру, по имени фильма и по обоим критериям.
В этом разделе вы изучили методы и представления действий CRUD, созданные платформой. Вы создали метод и представление действия поиска, которые позволяют пользователям выполнять поиск по названию фильма и жанру. В следующем разделе вы узнаете, как добавить свойство в Movie
модель и как добавить инициализатор, который автоматически создаст тестовую базу данных.
Обратная связь
https://aka.ms/ContentUserFeedback.
Ожидается в ближайшее время: в течение 2024 года мы постепенно откажемся от GitHub Issues как механизма обратной связи для контента и заменим его новой системой обратной связи. Дополнительные сведения см. в разделеОтправить и просмотреть отзыв по