共用方式為


ASP.NET Web Pages簡介 - 使用表單輸入資料庫資料

作者:Tom FitzMacken

本教學課程說明如何建立專案表單,然後在您使用 ASP.NET Web Pages (Razor) 時,將表單中的資料輸入資料庫資料表。 它假設您已透過ASP.NET Web Pages 中的 HTML 表單基本概念來完成系列。

您將學到什麼:

  • 深入瞭解如何處理輸入表單。
  • 如何在資料庫中新增 (插入) 資料。
  • 如何確定使用者已以表單輸入必要的值, (如何驗證使用者輸入) 。
  • 如何顯示驗證錯誤。
  • 如何從目前頁面跳至另一個頁面。

討論的功能/技術:

  • Database.Execute 方法
  • SQL Insert Into 語句
  • 協助 Validation 程式。
  • Response.Redirect 方法

您要建置的內容

在稍早示範如何建立資料庫的教學課程中,您會直接在 WebMatrix 中編輯資料庫,在 [資料庫 ] 工作區中編輯資料庫來輸入資料庫資料。 不過,在大部分應用程式中,這不是將資料放入資料庫中的實際方式。 因此在本教學課程中,您將建立 Web 型介面,讓您或任何人輸入資料並將其儲存至資料庫。

您將建立一個頁面,您可以在其中輸入新的電影。 頁面將包含欄位 (文字方塊的專案表單,) 您可以在其中輸入電影標題、內容類型和年份。 頁面看起來會像這個頁面:

瀏覽器中的 [新增電影] 頁面

文字方塊將會是類似此標記的 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 方法。 (如需 和 POST 作業之間的差異 GET 的詳細資訊,請參閱上一個教學課程中的GET、POST 和 HTTP 動詞安全提要欄。)

請注意,每個文字方塊都有元素 name (titlegenreyear) 。 如您在上一個教學課程中所見,這些名稱很重要,因為您必須擁有這些名稱,以便稍後取得使用者的輸入。 您可以使用任何名稱。 使用有意義的名稱有助於記住您正在使用的資料。

value每個 <input> 元素的 屬性都包含一些 Razor 程式碼 (, Request.Form["title"] 例如,) 。 您已在上一個教學課程中學到此訣竅的版本,以在提交表單之後保留輸入至文字方塊的值, () 。

取得表單值

接下來,您會新增處理表單的程式碼。 在大綱中,您將執行下列動作:

  1. 檢查是否已在提交 (張貼頁面) 。 只有當使用者按一下按鈕,而不是第一次執行頁面時,才想要讓程式碼執行。
  2. 取得使用者輸入文字方塊的值。 在此情況下,因為表單正在使用 POST 動詞,所以您會從 Request.Form 集合中取得表單值。
  3. Movies 資料庫資料表中,將值插入為新記錄。

在檔案頂端,新增下列程式碼:

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

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

前幾行會建立變數 (titlegenreyear) ,以保存文字方塊中的值。 這一行 if(IsPost) 可確保只有在使用者按一下 [新增電影]按鈕時才會設定變數,也就是在表單張貼時。

如先前教學課程中所見,您會使用類似 Request.Form["name"] 的運算式取得文字方塊的值,其中 name 是元素的名稱 <input>

(、 genreyear) 變數的名稱 title 是任意的。 就像您指派給 <input> 元素的名稱一樣,您可以呼叫任何您想要的名稱。 (變數的名稱不需要符合 form.) 上的專案名稱屬性 <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 不區分大小寫,但有些人會將關鍵字大寫,讓讀取 command.)

您要插入的資料行已經列在命令中 - (Title, Genre, Year) 。 有趣的部分是從文字方塊取得值到 VALUES 命令的一部分。 除了實際值外,您會看到 @0@1 、 和 @2 ,當然是預留位置。 當您在行) 上 db.Execute 執行命令 (時,您會傳遞您從文字方塊取得的值。

重要! 請記住,您應該在 SQL 語句中包含使用者線上輸入資料的唯一方式是使用預留位置,如這裡所示 (VALUES(@0, @1, @2)) 。 如果您將使用者輸入串連至 SQL 語句,您可以自行進入 SQL 插入式攻擊,如上一個教學課程) ASP.NET Web Pages (中的表單基本概念中所述。

仍在 區塊內 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頁面,或再次執行。 輸入另一部電影,但這次只輸入標題,例如,在雨中輸入 「Singin'」。 然後按一下 [新增電影]。

系統會再次重新導向至 [電影] 頁面。 您可以找到新的電影,但不完整。

顯示遺漏某些值之新電影的電影頁面

當您建立 Movies 資料表時,您明確表示沒有任何欄位可以是 Null。 在這裡,您有新電影的專案表單,而且您會將欄位保留空白。 這是錯誤。

在此情況下,資料庫實際上不會引發 (或 回) 錯誤。 您未提供內容類型或年份,因此 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"] 其中會有空字串。

為什麼這項區別很重要? 當您建立 Movies 資料表時,您明確表示沒有任何欄位可以是 Null。 但在這裡,您有新電影的專案表單,而且您會將欄位保留空白。 當您嘗試儲存沒有內容類型或年份值的新電影時,您會合理地預期資料庫會抱怨。 但這是一點,即使您將這些文字方塊保留空白,這些值也不會是 Null;它們是空字串。 因此,您可以將新的電影儲存到資料庫,這些資料行空白,但不是 Null! — 值。 因此,您必須確定使用者不會提交空字串,您可以藉由驗證使用者的輸入來執行此動作。

驗證協助程式

ASP.NET Web Pages包含協助程式 — 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) ,使用 && (邏輯 AND) 來新增另一個測試 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> 轉譯元素,但其中沒有文字。)

變更頁面中的標記,使其包含頁面上三 <input>Html.ValidationMessage 元素的方法,如下列範例所示:

<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 顯示之個別錯誤訊息的樣式,請建立名為 的 field-validation-error CSS 樣式類別。 若要定義驗證摘要的尋找,請建立名為 的 validation-summary-errors CSS 樣式類別。

若要查看這項技術的運作方式,請在頁面的 區段內 <head> 新增 <style> 元素。 然後定義名為 field-validation-errorvalidation-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 頁面。

再次開啟 [電影] 頁面。 在協助程式後面的 WebGrid 結尾 </div> 標記之後,新增下列標記:

<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.)

當您完成時,請執行 Movies 頁面。 此頁面看起來會像這樣:

連結為 [新增電影] 頁面的電影頁面

按一下 [ 新增電影 ] 連結,確定該連結會移至 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>

其他資源