Знакомство с веб-страницами ASP.NET — ввод данных базы данных с помощью форм

Tom FitzMacken

В этом руководстве показано, как создать форму записи, а затем ввести данные из формы в таблицу базы данных при использовании ASP.NET веб-страниц (Razor). Предполагается, что вы завершили серию по основам HTML-форм в ASP.NET веб-страниц.

Что вы узнаете:

  • Дополнительные сведения об обработке входных форм.
  • Добавление (вставка) данных в базу данных.
  • Как убедиться, что пользователи ввели требуемое значение в форме (как проверить входные данные пользователя).
  • Отображение ошибок проверки.
  • Переход на другую страницу с текущей страницы.

Рассматриваются функции и технологии:

  • Метод Database.Execute.
  • Инструкция SQL Insert Into
  • Помощник Validation .
  • Метод Response.Redirect.

Что вы будете создавать

В предыдущем руководстве, где объяснялось, как создать базу данных, вы вводили данные для базы данных, редактируя её непосредственно в WebMatrix, в рабочей области Database. В большинстве приложений это не практичный способ внесения данных в базу данных. Поэтому в этом руководстве вы создадите веб-интерфейс, который позволяет вам или любому пользователю вводить данные и сохранять его в базе данных.

Вы создадите страницу, в которой можно ввести новые фильмы. Страница будет содержать форму записи с полями (текстовыми полями), где можно ввести название фильма, жанр и год. Эта страница будет выглядеть следующим образом:

Страница

Текстовые поля будут HTML-элементами <input> , которые будут выглядеть следующим образом:

<input type="text" name="genre" value="" />

Создание базовой формы записи

Создайте страницу с именем AddMovie.cshtml.

Замените то, что находится в файле, следующей разметкой. Перезапишите всё; добавьте блок кода вверху скоро.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Add a Movie</title>
</head>
<body>
  <h1>Add a Movie</h1>
  <form method="post">
    <fieldset>
      <legend>Movie Information</legend>
      <p><label for="title">Title:</label>
         <input type="text" name="title" value="@Request.Form["title"]" />
      </p>

      <p><label for="genre">Genre:</label>
         <input type="text" name="genre" value="@Request.Form["genre"]" />
      </p>

      <p><label for="year">Year:</label>
         <input type="text" name="year" value="@Request.Form["year"]" />
      </p>

      <p><input type="submit" name="buttonSubmit" value="Add Movie" /></p>
    </fieldset>
  </form>
</body>
</html>

В этом примере показан типичный HTML-код для создания формы. Он использует <input> элементы для текстовых полей и кнопки отправки. Подписи для текстовых полей создаются с помощью стандартных <label> элементов. <fieldset> и <legend> элементы создают красивую рамку вокруг формы.

Обратите внимание, что на этой странице элемент <form> использует post в качестве значения атрибута method. В предыдущем руководстве вы создали форму, которая использовала get метод. Это было правильно, так как хотя форма отправила значения на сервер, запрос не внес никаких изменений. Оно просто получало данные различными способами. Однако на этой странице вы внесете изменения— вы добавите новые записи базы данных. Поэтому эта форма должна использовать post метод. (Дополнительные сведения о различиях между GETPOST операциями см. в боковой панелиGET, POST и HTTP Verb Safety в предыдущем руководстве.)

Обратите внимание, что каждое текстовое поле имеет элемент name (title, genre, year). Как вы видели в предыдущем руководстве, эти имена важны, так как у вас должны быть эти имена, чтобы вы могли получить входные данные пользователя позже. Вы можете использовать любые имена. Полезно использовать значимые имена, которые помогут вам вспомнить, с какими данными вы работаете.

Атрибут value каждого <input> элемента содержит немного кода Razor (например, Request.Form["title"]). Вы узнали версию этого трюка в предыдущем руководстве, чтобы сохранить значение, введенное в текстовое поле (если есть), после отправки формы.

Получение значений формы

Затем добавьте код, обрабатывающий форму. Вкратце, вы будете делать следующее:

  1. Проверьте, размещена ли страница (была отправлена). Код должен выполняться только при нажатии кнопки пользователей, а не при первом запуске страницы.
  2. Получите значения, введенные пользователем в текстовые поля. В этом случае, так как форма использует POST команду, вы получаете значения формы из Request.Form коллекции.
  3. Вставьте значения в качестве новой записи в таблицу базы данных "Фильмы ".

В начале файла добавьте указанный ниже код:

@{
    var title = "";
    var genre = "";
    var year = "";

    if(IsPost){
        title = Request.Form["title"];
        genre = Request.Form["genre"];
        year = Request.Form["year"];
    }
}

Первые несколько строк создают переменные (title, genreи year) для хранения значений из текстовых полей. if(IsPost) Строка гарантирует, что переменные задаются только при нажатии кнопки "Добавить фильм", то есть при публикации формы.

Как вы видели в предыдущем руководстве, вы получите значение текстового поля с помощью выражения, например Request.Form["name"], где имя — имя<input> элемента.

Имена переменных (title, genreи year) являются произвольными. Как и имена, назначенные <input> элементам, можно вызывать их как угодно. (Имена переменных не должны соответствовать атрибутам <input> имен элементов формы.) Но как и <input> в случае с элементами, рекомендуется использовать имена переменных, которые отражают содержащиеся в них данные. При написании кода согласованные имена упрощают запоминать данные, с которыми вы работаете.

Добавление данных в базу данных

В блоке кода, который вы только что добавили, непосредственно внутри закрывающей скобки ( } ) этого блока if (а не просто внутри блока кода), добавьте следующий код:

var db = Database.Open("WebPagesMovies");
var insertCommand = "INSERT INTO Movies (Title, Genre, Year) VALUES(@0, @1, @2)";
db.Execute(insertCommand, title, genre, year);

Этот пример аналогичен коду, используемому в предыдущем руководстве для получения и отображения данных. Строка, которая начинается с db =, открывает базу данных, как и раньше, а следующая строка определяет SQL-инструкцию, как вы видели ранее. Однако на этот раз он определяет инструкцию SQL Insert Into . В следующем примере показан общий синтаксис инструкции Insert Into :

INSERT INTO table (column1, column2, column3, ...) VALUES (value1, value2, value3, ...)

Другими словами, вы указываете таблицу для вставки, а затем перечисляете столбцы для вставки, а затем перечисляете значения для вставки. (Как отмечалось ранее, SQL не учитывает регистр, но некоторые люди пишут ключевые слова заглавными буквами, чтобы упростить чтение команды.)

Столбцы, в которые вы вставляете данные, уже перечислены в команде — (Title, Genre, Year). Интересно то, как вы переносите значения из текстовых полей в VALUES часть команды. Вместо фактических значений вы видите @0@1и @2, которые, конечно, являются заполнителями. При выполнении команды (в строке db.Execute ) вы передаете значения, полученные из текстовых полей.

Важно! Помните, что единственный способ, который вы когда-либо должны включать данные, введенные пользователем в режиме онлайн, в инструкции SQL — использовать заполнители, как показано здесь (VALUES(@0, @1, @2)). Если вы объединяете входные данные пользователя в инструкцию SQL, вы открываете себя для атаки SQL-инъекции, как описано в разделе "Основы работы с формами" в веб-страницах ASP.NET (в предыдущем руководстве).

Все еще внутри if блока добавьте следующую строку после db.Execute строки:

Response.Redirect("~/Movies");

После вставки нового фильма в базу данных эта строка переходит на страницу "Фильмы ", чтобы увидеть только что введенный фильм. Оператор ~ означает "корень веб-сайта". (Оператор ~ работает только на ASP.NET страницах, а не в HTML.)

Полный блок кода выглядит следующим образом:

@{
    var title = "";
    var genre = "";
    var year = "";

    if(IsPost){
        title = Request.Form["title"];
        genre = Request.Form["genre"];
        year = Request.Form["year"];

        var db = Database.Open("WebPagesMovies");
        var insertCommand = "INSERT INTO Movies (Title, Genre, Year) Values(@0, @1, @2)";
        db.Execute(insertCommand, title, genre, year);
        Response.Redirect("~/Movies");
    }
}

Тестирование команды вставки (до сих пор)

Вы еще не закончили, но сейчас хорошее время для тестирования.

В представлении дерева файлов в WebMatrix щелкните правой кнопкой мыши страницу AddMovie.cshtml и нажмите кнопку "Запустить в браузере".

Снимок экрана: страница

(Если вы в конечном итоге используете другую страницу в браузере, убедитесь, что URL-адрес указан http://localhost:nnnnn/AddMovie), где nnnnn — номер порта, который вы используете.)

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

Введите фильм в форме— например, используйте "Гражданин Кейн", "Драма" и "1941". (Или что угодно.) Затем нажмите кнопку "Добавить фильм".

Если все идет хорошо, вы перенаправляетесь на страницу "Фильмы ". Проверьте, что ваш новый фильм указан.

Страница

Проверка входных данных пользователей

Вернитесь на страницу AddMovie или снова запустите ее. Введите другой фильм, но на этот раз только название, например, «Поющие под дождем». Затем нажмите кнопку "Добавить фильм".

Вы снова перенаправляетесь на страницу "Фильмы ". Вы можете найти новый фильм, но он не завершён.

Страница «Фильмы», на которой показывается новый фильм, в котором отсутствуют некоторые данные

При создании таблицы "Фильмы " вы явно сказали, что ни одно из полей не может быть пустым. Здесь есть форма записи для новых фильмов, и вы оставляете поля пустыми. Это ошибка.

В этом случае база данных на самом деле не выдала (или сгенерировала) ошибку. Вы не указали жанр или год, поэтому код на странице AddMovie рассматривал эти значения как так называемые пустые строки. Когда команда SQL Insert Into выполнялась, поля жанра и года не имели полезных данных в них, но они не были null.

Очевидно, что вы не хотите, чтобы пользователи вводили в базу данных полупустые сведения о фильме. Решение заключается в проверке входных данных пользователя. Изначально проверка будет просто убедиться, что пользователь ввел значение для всех полей (то есть, что ни один из них не содержит пустую строку).

Подсказка

Null и пустые строки

В программировании существует различие между различными понятиями "нет значения". Как правило, значение равно NULL , если оно никогда не было задано или инициализировано каким-либо образом. В отличие от этого, переменная, которая ожидает символьные данные (строки) может быть задана пустой строкой. В этом случае значение не равно null, оно просто было явно установлено как строка символов, длина которой равна нулю. Эти два утверждения показывают разницу:

var firstName;       // Not set, so its value is null
var firstName = "";  // Explicitly set to an empty string -- not null

Это немного сложнее, чем это, но важная точка заключается в том, что null представляет своего рода неопределенное состояние.

Время от времени важно понимать, когда значение равно NULL, а когда это просто пустая строка. В коде страницы AddMovie вы получите значения текстовых полей с помощью Request.Form["title"] и т. д. При первом запуске страницы (перед нажатием кнопки) значение Request.Form["title"] равно NULL. Но при отправке формы Request.Form["title"] получает значение текстового title поля. Это не очевидно, но пустое текстовое поле не равно NULL; В нем просто есть пустая строка. Поэтому, когда код выполняется в ответ на нажатие кнопки, Request.Form["title"] в нем есть пустая строка.

Почему это различие важно? При создании таблицы "Фильмы " вы явно сказали, что ни одно из полей не может быть пустым. У вас здесь есть форма для ввода новых фильмов, и вы оставляете некоторые поля пустыми. Вы вполне можете ожидать, что база данных выдала ошибку, когда вы пытались сохранить новые фильмы, которые не имели значений для параметров жанра или года. Но в этом и дело — даже если вы оставляете эти текстовые поля пустыми, значения не являются null; это пустые строки. В результате вы можете сохранить новые фильмы в базе данных с пустыми столбцами, но не незаполненными! — значения. Поэтому необходимо убедиться, что пользователи не могут отправлять пустую строку, которую можно сделать, проверяя входные данные пользователя.

Вспомогательный элемент проверки

ASP.NET веб-страницы включают вспомогательный элемент — Validation вспомогательный элемент, который можно использовать, чтобы убедиться, что пользователи вводят данные, соответствующие вашим требованиям. Вспомогательный компонент Validation является одним из вспомогательных компонентов, встроенных в ASP.NET Web Pages, поэтому вам не нужно устанавливать его как пакет с помощью NuGet, как вы устанавливали вспомогательный компонент Gravatar в предыдущем руководстве.

Чтобы проверить входные данные пользователя, выполните следующие действия.

  • Используйте код, чтобы указать, что необходимо требовать значения в текстовых полях на странице.
  • Поместите тест в код, чтобы сведения о фильме были добавлены в базу данных только в том случае, если все проверяется правильно.
  • Добавьте код в разметку для отображения сообщений об ошибках.

В блоке кода на странице AddMovie прямо вверху перед объявлениями переменной добавьте следующий код:

Validation.RequireField("title", "You must enter a title");
Validation.RequireField("genre", "Genre is required");
Validation.RequireField("year", "You haven't entered a year");

Вы вызываете Validation.RequireField один раз для каждого поля (<input> элемента), в котором требуется запись. Вы также можете добавить настраиваемое сообщение об ошибке для каждого вызова, как показано здесь. (Мы изменяли сообщения, чтобы показать, что вы можете поместить все, что вам нравится там.)

Если возникла проблема, вы хотите предотвратить вставку новых сведений о фильме в базу данных. В блоке используйте if(IsPost) (логическое И) для добавления другого && условия, которое проверяетValidation.IsValid(). По завершении весь if(IsPost) блок выглядит следующим образом:

if(IsPost && Validation.IsValid()){
    title = Request.Form["title"];
    genre = Request.Form["genre"];
    year = Request.Form["year"];

    var db = Database.Open("WebPagesMovies");
    var insertCommand = "INSERT INTO Movies (Title, Genre, Year) Values(@0, @1, @2)";
    db.Execute(insertCommand, title, genre, year);
    Response.Redirect("~/Movies");
}

Если возникает ошибка проверки с любым из полей, зарегистрированных с помощью вспомогательного Validation средства, Validation.IsValid метод возвращает значение false. Если так, то ни одна из строк кода в этом блоке не будет выполняться, и поэтому в базу данных не будут добавлены невалидные записи о фильмах. И, конечно, вы не перенаправляетесь на страницу "Фильмы ".

Полный блок кода, включая код проверки, теперь выглядит следующим образом:

@{
    Validation.RequireField("title", "You must enter a title");
    Validation.RequireField("genre", "Genre is required");
    Validation.RequireField("year", "You haven't entered a year");

    var title = "";
    var genre = "";
    var year = "";

    if(IsPost && Validation.IsValid()){
       title = Request.Form["title"];
       genre = Request.Form["genre"];
       year = Request.Form["year"];

       var db = Database.Open("WebPagesMovies");
       var insertCommand = "INSERT INTO Movies (Title, Genre, Year) Values(@0, @1, @2)";
       db.Execute(insertCommand, title, genre, year);
       Response.Redirect("~/Movies");
    }
}

Отображение ошибок проверки

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

Рядом с каждым <input> элементом, который вы проверяете, вызовите Html.ValidationMessage метод и передайте имя проверяемого <input> элемента. Вы помещаете метод Html.ValidationMessage прямо в то место, где вы хотите, чтобы появилось сообщение об ошибке. При выполнении страницы метод Html.ValidationMessage отрисовывает элемент <span>, в котором будет отображаться ошибка проверки. (Если нет ошибки, <span> элемент отображается, но в нем нет текста.)

Измените разметку на странице таким образом, чтобы он включает Html.ValidationMessage метод для каждого из трех <input> элементов на странице, как показано в следующем примере:

<p><label for="title">Title:</label>
     <input type="text" name="title" value="@Request.Form["title"]" />
      @Html.ValidationMessage("title")
  </p>

  <p><label for="genre">Genre:</label>
     <input type="text" name="genre" value="@Request.Form["genre"]" />
      @Html.ValidationMessage("genre")
  </p>

  <p><label for="year">Year:</label>
     <input type="text" name="year" value="@Request.Form["year"]" />
      @Html.ValidationMessage("year")
  </p>

Чтобы узнать, как работает сводка, добавьте следующую разметку и код сразу после <h1>Add a Movie</h1> элемента на странице:

@Html.ValidationSummary()

По умолчанию Html.ValidationSummary метод отображает все сообщения проверки в списке ( <ul> элемент, который находится внутри <div> элемента). Как и в случае с методом Html.ValidationMessage , разметка для сводки проверки всегда отображается; если ошибки отсутствуют, элементы списка не отображаются.

Сводка может быть альтернативным способом отображения сообщений проверки вместо использования Html.ValidationMessage метода для отображения каждой ошибки для конкретного поля. Или можно использовать как сводку, так и детали. Или можно использовать Html.ValidationSummary метод для отображения универсальной ошибки, а затем использовать отдельные Html.ValidationMessage вызовы для отображения сведений.

Теперь полная страница выглядит следующим образом:

@{
    Validation.RequireField("title", "You must enter a title");
    Validation.RequireField("genre", "Genre is required");
    Validation.RequireField("year", "You haven't entered a year");

    var title = "";
    var genre = "";
    var year = "";

    if(IsPost && Validation.IsValid()){
       title = Request.Form["title"];
       genre = Request.Form["genre"];
       year = Request.Form["year"];

       var db = Database.Open("WebPagesMovies");
       var insertCommand = "INSERT INTO Movies (Title, Genre, Year) Values(@0, @1, @2)";
       db.Execute(insertCommand, title, genre, year);
       Response.Redirect("~/Movies");
    }
}

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>Add a Movie</title>
</head>
<body>
  <h1>Add a Movie</h1>
  @Html.ValidationSummary()
  <form method="post">
    <fieldset>
      <legend>Movie Information</legend>
      <p><label for="title">Title:</label>
         <input type="text" name="title" value="@Request.Form["title"]" />
          @Html.ValidationMessage("title")
      </p>

      <p><label for="genre">Genre:</label>
         <input type="text" name="genre" value="@Request.Form["genre"]" />
          @Html.ValidationMessage("genre")
      </p>

      <p><label for="year">Year:</label>
         <input type="text" name="year" value="@Request.Form["year"]" />
          @Html.ValidationMessage("year")
      </p>

      <p><input type="submit" name="buttonSubmit" value="Add Movie" /></p>
    </fieldset>
  </form>
</body>
</html>

Вот и все. Теперь вы можете протестировать страницу, добавив фильм, но оставив один или несколько полей. При выполнении отображается следующая ошибка:

Страница добавления фильма, показывающая сообщения об ошибках проверки

Стилизация сообщений об ошибках проверки

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

Для стилизации отдельных сообщений об ошибках, отображаемых Html.ValidationMessage, создайте CSS-класс под именем field-validation-error. Чтобы определить внешний вид сводки проверки, создайте класс стилей CSS с именем validation-summary-errors.

Чтобы узнать, как работает этот метод, добавьте <style> элемент в <head> раздел страницы. Затем определите классы стилей с именем field-validation-error и validation-summary-errors содержащие следующие правила:

<head>
  <meta charset="utf-8" />
  <title>Add a Movie</title>
  <style type="text/css">
    .field-validation-error {
      font-weight:bold;
      color:red;
      background-color:yellow;
     }
    .validation-summary-errors{
      border:2px dashed red;
      color:red;
      background-color:yellow;
      font-weight:bold;
      margin:12px;
    }
  </style>
</head>

Обычно вы, вероятно, помещаете сведения о стиле в отдельный файл .css , но для простоты их можно поместить на страницу на данный момент. (Далее в этом наборе учебников вы переместите правила CSS в отдельный файл .css.)

При возникновении ошибки Html.ValidationMessage проверки метод отрисовывает <span> элемент, который включает в себя class="field-validation-error". Добавив определение стиля для этого класса, можно настроить, как выглядит сообщение. При возникновении ошибок ValidationSummary метод также динамически отрисовывает атрибут class="validation-summary-errors".

Снова запустите страницу и намеренно оставьте несколько полей. Ошибки теперь более заметны. (На самом деле, они слегка переделаны, но это просто для демонстрации того, что можно сделать.)

Страница добавления фильма, показывающая ошибки проверки, которые были стилизованы

Заключительный шаг заключается в том, чтобы сделать удобной возможность перейти на страницу AddMovie с исходной страницы фильмов.

Снова откройте страницу "Фильмы ". После закрывающего тега `</div>`, который следует за вспомогательным элементом `WebGrid`, добавьте следующую разметку:

<p>
  <a href="~/AddMovie">Add a movie</a>
</p>

Как вы видели ранее, ASP.NET интерпретирует ~ оператор как корень веб-сайта. Вам не обязательно использовать оператор ~; вы можете использовать разметку <a href="./AddMovie">Add a movie</a> или другой способ, чтобы определить путь, который понимает HTML. Оператор ~ является хорошим универсальным подходом при создании ссылок на страницы Razor, так как делает сайт более гибким — если вы переместите текущую страницу в подкаталог, ссылка по-прежнему будет вести на страницу AddMovie. (Помните, что ~ оператор работает только на страницах CSHTML . ASP.NET понимает его, но это не стандартный HTML.)

По завершении запустите страницу "Фильмы ". Эта страница будет выглядеть следующим образом:

Страница

Щелкните ссылку "Добавить фильм" , чтобы убедиться, что она перейдет на страницу AddMovie .

Далее

В следующем руководстве вы узнаете, как разрешить пользователям изменять данные, уже имеющиеся в базе данных.

Полный список для страницы AddMovie

@{

    Validation.RequireField("title", "You must enter a title");
    Validation.RequireField("genre", "Genre is required");
    Validation.RequireField("year", "You haven't entered a year");

    var title = "";
    var genre = "";
    var year = "";

    if(IsPost && Validation.IsValid()){
       title = Request.Form["title"];
       genre = Request.Form["genre"];
       year = Request.Form["year"];

       var db = Database.Open("WebPagesMovies");
       var insertCommand = "INSERT INTO Movies (Title, Genre, Year) Values(@0, @1, @2)";
       db.Execute(insertCommand, title, genre, year);
       Response.Redirect("~/Movies");
    }
}

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Add a Movie</title>
      <style type="text/css">
    .field-validation-error {
      font-weight:bold;
      color:red;
      background-color:yellow;
     }
    .validation-summary-errors{
      border:2px dashed red;
      color:red;
      background-color:yellow;
      font-weight:bold;
      margin:12px;
    }
  </style>
</head>
<body>
  <h1>Add a Movie</h1>
  @Html.ValidationSummary()
  <form method="post">
    <fieldset>
      <legend>Movie Information</legend>
      <p><label for="title">Title:</label>
         <input type="text" name="title" value="@Request.Form["title"]" />
          @Html.ValidationMessage("title")
      </p>

      <p><label for="genre">Genre:</label>
         <input type="text" name="genre" value="@Request.Form["genre"]" />
         @Html.ValidationMessage("genre")
      </p>

      <p><label for="year">Year:</label>
         <input type="text" name="year" value="@Request.Form["year"]" />
          @Html.ValidationMessage("year")
      </p>

      <p><input type="submit" name="buttonSubmit" value="Add Movie" /></p>
    </fieldset>
  </form>
</body>
</html>

Дополнительные ресурсы