파트 6: Edit 메서드와 Edit 뷰 살펴보기
- 본 번역문서의 원문은 Examining the Edit Methods and Edit View www.asp.net 입니다.
- 본 번역문서는 ASP.NET MVC 4 자습서 - 만들면서 배우기 (III) www.taeyo.net 에서도 함께 제공됩니다.
이번에는 MoviesController
클래스에 생성된 나머지 액션 메서드와 뷰들을 살펴보고, 사용자 정의 검색 페이지도 추가해보도록 하겠습니다.
다시 응용 프로그램을 실행시킨 다음, 브라우저 주소 표시줄의 URL에 /Movies를 추가해서 Movies
컨트롤러로 이동합니다.
그리고, 마우스 포인터를 Edit 링크 위에 올려 놓은 상태 그대로, 링크가 가리키는 URL을 살펴보십시요.
이 Edit 링크는 Html.ActionLink
메서드를 통해서 Views\Movies\Index.cshtml 뷰에서 만들어진 링크입니다:
@Html.ActionLink("Edit", "Edit", new { id=item.ID })
여기에서 사용된 Html
개체는 System.Web.Mvc.WebViewPage 기본 클래스의 속성을 통해서 노출된 도우미(Helper)입니다.
도우미에서 제공되는 ActionLink
메서드를 사용하면 손쉽게 컨트롤러의 액션 메서드를 링크하는 HTML 하이퍼링크를 동적으로 생성할 수 있습니다.
ActionLink
메서드의 첫 번째 매개변수에는 렌더 될 링크의 텍스트(<a>Edit Me</a>
)를 지정합니다.
두 번째 매개변수에는 호출될 액션 메서드의 이름을 지정합니다.
그리고, 마지막 매개변수에는 라우트 데이터로 사용될 (이 예제의 경우, ID 값인 4) 익명 개체를 지정합니다.
이번 절의 첫 번째 그림에 나타난 링크의 URL은 http://localhost:xxxxx/Movies/Edit/4 인 것을 확인할 수 있습니다.
Global.asax.cs 파일에 지정되어 있는 기본 라우트는 {controller}/{action}/{id}
구조의 URL 패턴을 따르므로, ASP.NET은 http://localhost:xxxxx/Movies/Edit/4 에 대한 요청을 Movies
컨트롤러의 Edit
액션 메서드에 대해 ID
매개변수 값이 4인 요청으로 변환해줍니다.
쿼리스트링을 통해서도 액션 메서드 매개변수를 전달할 수 있습니다.
즉, http://localhost:xxxxx/Movies/Edit?ID=4 형태의 URL도 Movies
컨트롤러의 Edit
액션 메서드에 ID
매개변수 값 4를 전달합니다.
계속해서 다시 Movies
컨트롤러를 열어 보십시요.
그러면, 다음과 같은 두 개의 Edit
액션 메서드를 확인할 수 있을 것입니다.
// // GET: /Movies/Edit/5 public ActionResult Edit(int id = 0) { Movie movie = db.Movies.Find(id); if (movie == null) { return HttpNotFound(); } return View(movie); } // // POST: /Movies/Edit/5 [HttpPost] public ActionResult Edit(Movie movie) { if (ModelState.IsValid) { db.Entry(movie).State = EntityState.Modified; db.SaveChanges(); return RedirectToAction("Index"); } return View(movie); }
두 번째 Edit
액션 메서드 앞에 HttpPost
어트리뷰트가 지정되어 있는 것을 주의해서 살펴보시기 바랍니다.
이 어트리뷰트를 지정하면, 이 Edit
메서드의 오버로드는 오직 POST 요청인 경우에만 호출됩니다.
물론, 명확하게 구분하기 위해서 첫 번째 Edit
액션 메서드에 HttpGet
어트리뷰트를 지정해도 무방하겠지만, 이는 기본값이므로 굳이 그럴 필요는 없습니다.
(다만, 본문에서는 설명 상의 편의를 위해, 암시적으로 HttpGet
어트리뷰트가 지정되었다고 간주하고 이 첫 번째 액션 메서드를 HttpGet
메서드라고 부르도록 하겠습니다.)
이 HttpGet
Edit
메서드는 영화 정보의 ID를 매개변수로 받아서, Entity Framework의 Find
메서드를 이용해서 영화 정보를 찾은 다음, 검색된 영화 정보를 Edit 뷰로 반환합니다.
Edit
메서드는 매개변수 없이 호출되는 경우, ID 매개변수에 기본값인 0 이 지정됩니다.
그리고, 지정된 ID에 해당하는 영화가 존재하지 않는 경우에는, HttpNotFound가 반환됩니다.
스캐폴딩 시스템은 Edit 뷰를 생성할 때, Movie
클래스를 분석해서 각각의 속성들에 대한 <label>
요소와 <input>
요소들을 렌더하는 코드를 생성해줍니다.
다음 예제는 그렇게 생성된 Edit 뷰를 보여주고 있습니다.
@model MvcMovie.Models.Movie
@
ViewBag.Title = "Edit";
}
<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(model => model.ID)
<div class="editor-label">
@Html.LabelFor(model => model.Title)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Title)
@Html.ValidationMessageFor(model => model.Title)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.ReleaseDate)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.ReleaseDate)
@Html.ValidationMessageFor(model => model.ReleaseDate)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Genre)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Genre)
@Html.ValidationMessageFor(model => model.Genre)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Price)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Price)
@Html.ValidationMessageFor(model => model.Price)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
뷰 템플릿 파일의 가장 상단에 작성되어 있는 @model MvcMovie.Models.Movie
구문에 주목하시기 바랍니다.
이 구문은 뷰가 이 뷰 템플릿의 모델 형식으로 Movie
형식을 기대하고 있다는 것을 나타냅니다.
그리고, HTML 마크업을 구성하는 스캐폴딩 코드에 몇 가지 도우미 메서드가 사용되고 있는 것을 볼 수 있습니다.
가령, Html.LabelFor
도우미를 사용해서 필드들의 이름을 ("Title", "ReleaseDate", "Genre", "Price"), 그리고 Html.EditorFor
도우미를 사용해서 HTML <input>
요소들을 렌더합니다.
Html.ValidationMessageFor
도우미는 각 속성들에 대한 유효성 검사 메시지를 출력해줍니다.
다시 응용 프로그램을 실행시킨 다음, /Movies URL로 이동하고, Edit 링크를 클릭해서 브라우저에서 페이지의 소스를 살펴봅니다. 그러면, 다음과 비슷한 모습의 폼 요소 HTML을 확인할 수 있을 것입니다.
<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-date="The field ReleaseDate must be a date." 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="2.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>
이 소스의 <input>
요소들은 /Movies/Edit URL로 게시되도록 action
어트리뷰트가 설정된 HTML <form>
요소 내부에 존재합니다.
그리고, 당연한 얘기지만 Save 버튼이 클릭되면 폼 데이터가 서버로 전송됩니다.
POST 요청 처리하기
다음 목록은 Edit
액션 메서드의 HttpPost
버전을 보여주고 있습니다.
[HttpPost] public ActionResult Edit(Movie movie) { if (ModelState.IsValid) { db.Entry(movie).State = EntityState.Modified; db.SaveChanges(); return RedirectToAction("Index"); } return View(movie); }
ASP.NET MVC 모델 바인더가 전송된 폼의 값들을 받아서 Movie
개체를 생성한 다음, 생성된 개체를 movie
매개변수에 전달해줍니다.
그러면, ModelState.IsValid
메서드를 호출해서 제출된 폼의 데이터가 Movie
개체 수정에 적합한 유효한 데이터인지 검사합니다.
만약 제출된 데이터가 유효하다면, db
(MovieDBContext
클래스의 인스턴스)의 Movies
컬랙션에 저장되었다가, MovieDBContext
의 SaveChanges
메서드가 호출되는 시점에 데이터베이스에 저장됩니다.
그런 다음, 다시 사용자를 MoviesController
클래스의 Index
액션 메서드로 재전송하여 방금 변경한 데이터를 비롯한 영화 컬랙션을 보여줍니다.
그러나, 전송된 폼의 데이터가 유효하지 않은 경우에는 Edit 뷰의 폼이 다시 출력됩니다.
그러면, Edit.cshtml 뷰 템플릿에 작성되어 있는 Html.ValidationMessageFor
도우미가 적절한 오류 메시지를 출력해줍니다.
<system.web> <globalization culture ="en-US" /> <!--명확성을 위해 다른 요소들은 제거했습니다.--> </system.web>
다른 HttpGet
메서드들도 모두 HttpPost
버전의 Edit
액션 메서드와 비슷한 패턴을 갖고 있습니다.
다시 말해서, Movie
개체를 가져온 다음 (Index
메서드의 경우는 개체들의 목록을), 뷰로 이 모델을 전달하는 식입니다.
다만, Create
메서드의 경우는 빈 Movie
개체를 Create 뷰로 전달합니다.
그리고, 데이터를 생성하거나, 수정하거나, 삭제하는 등의 모든 데이터 변경 작업은 각 메서드의 HttpPost
버전에서 수행됩니다.
HTTP GET 메서드에서 데이터를 변경하면 ASP.NET MVC Tip #46 – Don’t use Delete Links because they create Security Holes 블로그 포스트에서 설명하고 있는 것처럼 보안상의 위험 요소가 만들어지게 됩니다.
더불어, HTTP의 모범 사례와, GET 요청은 응용 프로그램의 상태를 변경해서는 안된다는 REST 패턴 아키텍처를 위배하는 일이기도 합니다.
간단하게 정리하자면, GET 작업은 부작용을 발생시키지 않고 영속화 데이터를 변경하지 않는 안전한 작업만을 수행해야 합니다.
Search 메서드와 Search 뷰 추가하기
그러면 이번에는, 사용자들이 장르와 제목으로 영화를 검색할 수 있도록 SearchIndex
액션 메서드를 추가해보겠습니다.
이 메서드는 /Movies/SearchIndex URL을 통해서 접근할 수 있을 것입니다.
사용자가 이 URL을 요청하면 검색할 영화를 입력할 수 있는 input 요소가 포함된 HTML 폼이 나타나게 됩니다.
이 폼에 검색할 영화 정보를 입력하고 전송하면, 액션 메서드가 사용자가 입력한 검색값을 받아서 이를 이용하여 데이터베이스를 검색하게 됩니다.
SearchIndex 폼 출력하기
먼저 기존의 MoviesController
클래스에 SearchIndex
액션 메서드부터 추가하겠습니다.
이 메서드는 HTML 폼을 담고 있는 뷰를 반환하게 될 것입니다.
다음은 SearchIndex
액션 메서드의 코드입니다:
public ActionResult SearchIndex(string searchString) { var movies = from m in db.Movies select m; if (!String.IsNullOrEmpty(searchString)) { movies = movies.Where(s => s.Title.Contains(searchString)); } return View(movies); }
이 SearchIndex
메서드의 첫 번째 코드 라인은 영화 정보들을 가져오는 다음과 같은 LINQ 질의를 생성합니다:
var movies = from m in db.Movies select m;
그러나, 아직 이 시점에는 질의가 정의만 되었을 뿐, 데이터 저장소에 대해 실제로 수행된 것은 아니라는 점에 주의하십시요.
계속해서 searchString
매개변수에 검색할 문자열이 담겨 있다면, 다음 코드와 같이 검색 문자열 값으로 필터링되도록 movies 질의가 변경됩니다:
if (!String.IsNullOrEmpty(searchString)) { movies = movies.Where(s => s.Title.Contains(searchString)); }
이 코드에 사용된 s => s.TitleTitle.Contains(searchString)
구문은 람다식(Lambda Expression)입니다.
메서드 기반의 LINQ 질의에서 이 코드에 사용된 Where 메서드 등의 표준 질의 연산자 메서드의 매개변수로 람다식이 사용됩니다.
LINQ 질의는 해당 질의가 정의된 시점이나, Where
나 OrderBy
등의 메서드를 호출해서 변경하는 바로 그 시점에는 질의가 실행되지 않습니다.
그대신, 질의의 실제 값이 루프문 등을 통해서 구체적으로 접근되거나, ToList
등의 메서드가 호출될 때까지 표현식의 평가가 미뤄지고 질의의 실행이 지연됩니다.
가령, SearchIndex
예제의 경우, 질의가 실행되는 곳은 SearchIndex 뷰입니다.
지연된 질의 실행(Deferred Query Execution)에 관한 보다 자세한 정보는 Query Execution을 참고하시기 바랍니다.
이제 폼을 사용자에게 제공하기 위한 SearchIndex
뷰를 작성해보겠습니다.
SearchIndex
메서드를 마우스 오른쪽 버튼으로 클릭한 다음, Add View를 클릭합니다.
Add View 대화 상자가 나타나면, 뷰 템플릿의 모델 클래스로 Movie
개체의 목록를 전달하고자 한다는 것을 지정합니다.
그리고, Scaffold template 목록에서 List를 선택한 다음, Add를 클릭합니다.
그러면, Views\Movies\SearchIndex.cshtml 뷰 템플릿이 생성되는데, Scaffold template 목록에서 List를 선택했으므로 자동으로 Visual Studio Express가 기본적인 마크업을 뷰에 생성해줍니다.
이 스캐폴딩은 HTML 폼의 형태로 만들어지게 되며, Movie
클래스를 분석한 결과에 따라 각각의 속성들에 대한 <label>
요소들을 렌더해주는 코드가 만들어집니다.
다음 목록은 생성된 SearchIndex 뷰를 보여주고 있습니다:
@model IEnumerable<MvcMovie.Models.Movie> @{ ViewBag.Title = "SearchIndex"; } <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> @foreach (var item in Model) { <tr> <td> @Html.DisplayFor(modelItem => item.Title) </td> <td> @Html.DisplayFor(modelItem => item.ReleaseDate) </td> <td> @Html.DisplayFor(modelItem => item.Genre) </td> <td> @Html.DisplayFor(modelItem => item.Price) </td> <td> @Html.ActionLink("Edit", "Edit", new { id=item.ID }) | @Html.ActionLink("Details", "Details", new { id=item.ID}) | @Html.ActionLink("Delete", "Delete", new { id=item.ID }) </td> </tr> } </table>
다시 응용 프로그램을 실행시킨 다음, /Movies/SearchIndex로 이동합니다.
그리고, URL의 쿼리스트링에 ?searchString=ghost
와 같은 문자열을 추가합니다.
그러면, 필터링 된 목록이 출력될 것입니다.
매개변수의 이름을 id
로 변경해서 SearchIndex
메서드의 시그니처를 변경하면, Global.asax 파일에 정의된 기본 라우트 설정의 {id}
플레이스홀더와 이 id
매개변수가 일치하게 됩니다.
{controller}/{action}/{id}
본래의 SearchIndex
메서드는 다음과 같았습니다:
public ActionResult SearchIndex(string searchString) { var movies = from m in db.Movies select m; if (!String.IsNullOrEmpty(searchString)) { movies = movies.Where(s => s.Title.Contains(searchString)); } return View(movies); }
그리고, 변경된 SearchIndex
메서드는 다음과 비슷할 것입니다:
public ActionResult SearchIndex(string id) { string searchString = id; var movies = from m in db.Movies select m; if (!String.IsNullOrEmpty(searchString)) { movies = movies.Where(s => s.Title.Contains(searchString)); } return View(movies); }
메서드를 이렇게 변경하고 나면 검색 타이틀을 쿼리스트링 대신 라우트 데이터(URL의 일부)로 전달할 수 있습니다.
그렇지만, 그 어떤 개발자도 영화를 검색할 때마다 사용자들이 이런식으로 매번 URL을 수정하기를 바라지는 않을 것입니다.
따라서, 이번에는 사용자들이 영화를 필터링 할 때 편리하게 사용할 수 있도록 UI를 추가해보도록 하겠습니다.
라우트-바운드 ID 매개변수 전달 방식을 살펴보기 위해서 방금 전에 변경했던 SearchIndex
메서드의 시그니처를 다시 원래대로 되돌려서, 본래대로 searchString
문자열 매개변수를 받도록 변경합니다:
public ActionResult SearchIndex(string searchString) { var movies = from m in db.Movies select m; if (!String.IsNullOrEmpty(searchString)) { movies = movies.Where(s => s.Title.Contains(searchString)); } return View(movies); }
그리고, Views\Movies\SearchIndex.cshtml 파일을 열어서, @Html.ActionLink("Create New", "Create")
라인 바로 뒤에 다음과 같은 코드를 추가합니다:
@using (Html.BeginForm()){ <p> Title: @Html.TextBox("SearchString")<br /> <input type="submit" value="Filter" /></p> }
다음은 필터링 관련 마크업이 추가된 Views\Movies\SearchIndex.cshtml 파일의 일부를 보여주고 있습니다.
@model IEnumerable<MvcMovie.Models.Movie> @{ ViewBag.Title = "SearchIndex"; } <h2>SearchIndex</h2> <p> @Html.ActionLink("Create New", "Create") @using (Html.BeginForm()){ <p> Title: @Html.TextBox("SearchString") <input type="submit" value="Filter" /></p> } </p>
이 코드에서 Html.BeginForm
도우미는 열린 <form>
태그를 생성하고, 사용자가 Filter 버튼을 클릭해서 폼을 제출하면, 폼을 현재 페이지 자신으로 전송되도록 만듭니다.
이제 다시 응용 프로그램을 시작한 다음, 영화 정보를 검색해봅니다.
이 SearchIndex
메서드의 경우 HttpPost
오버로드는 필요가 없습니다.
그 이유는, 이 메서드는 데이터를 필터링하기만 할 뿐, 어떠한 응용 프로그램의 상태도 변경하지는 않기 때문입니다.
물론, 다음과 같은 HttpPost SearchIndex
메서드를 추가한다고 해도 문제는 되지 않습니다.
그러면, 액션 호출자(Action Invoker)가 HttpPost SearchIndex
메서드를 인식해서 실행한 다음, 아래 그림과 같은 결과를 보여주게 될 것입니다.
[HttpPost] public string SearchIndex(FormCollection fc, string searchString) { return "<h3> From [HttpPost]SearchIndex: " + searchString + "</h3>"; }
그러나, 비록 이런 SearchIndex
메서드의 HttpPost
버전을 추가해서 실제 코드를 모두 구현했다고 하더라도 여기에는 한계가 존재할 수 밖에 없습니다.
가령, 특정 검색 결과를 북마크 해두거나, 친구에게 링크를 보내서 그 친구가 이 링크를 클릭했을 때, 필터링 된 동일한 영화 목록이 나타나기를 원한다고 상상해보십시요.
그런데, 주목해야 할 점은 HTTP POST 요청의 URL이 GET 요청의 URL(localhost:xxxxx/Movies/SearchIndex)과 동일하고, 이 URL에는 검색에 관한 정보가 전혀 포함되어 있지 않다는 것입니다.
그 이유는 검색 문자열 정보가 서버에 폼 필드 값의 형태로 전달되기 때문입니다.
결과적으로, 여러분은 북마크나 친구에게 보낼 URL에 결코 검색 정보를 담을 수가 없는 셈입니다.
이 문제를 해결할 수 있는 방법은 BeginForm
메서드의 오버로드를 사용해서, URL에 검색 정보가 추가되어 SearchIndex
메서드의 HttpGet
버전으로 라우트되도록 만드는 것입니다.
기존의 매개변수가 지정되지 않은 BeginForm
메서드를 다음 코드와 같이 변경합니다:
@using(Html.BeginForm("SearchIndex", "Movies", FormMethod.Get))
이제 검색을 수행해보면 URL에 검색 쿼리스트링이 포함됩니다.
그리고, HttpPost SearchIndex
메서드가 존재하더라도 HttpGet SearchIndex
액션 메서드가 실행됩니다.
장르 검색 추가하기
먼저, 앞에서 SearchIndex
메서드의 HttpPost
버전을 추가했었다면 제거합니다.
이번에는 사용자들이 장르로 영화 정보를 검색할 수 있는 기능을 추가해 볼 것입니다.
SearchIndex
메서드를 다음의 코드로 대체합니다:
public ActionResult SearchIndex(string movieGenre, string searchString) { var GenreLst = new List<string>(); var GenreQry = from d in db.Movies orderby d.Genre select d.Genre; GenreLst.AddRange(GenreQry.Distinct()); ViewBag.movieGenre = new SelectList(GenreLst); var movies = from m in db.Movies select m; if (!String.IsNullOrEmpty(searchString)) { movies = movies.Where(s => s.Title.Contains(searchString)); } if (string.IsNullOrEmpty(movieGenre)) return View(movies); else { return View(movies.Where(x => x.Genre == movieGenre)); } }
이 버전의 SearchIndex
메서드는 movieGenre
라는 이름의 추가적인 매개변수를 받습니다.
코드의 처음 몇 라인은 데이터베이스로부터 가져온 장르들을 저장할 List
개체를 생성하는 코드입니다.
그리고, 다음 코드는 데이터베이스로부터 모든 장르를 가져오는 LINQ 질의입니다.
var GenreQry = from d in db.Movies orderby d.Genre select d.Genre;
제네릭 List
컬랙션의 AddRange
메서드를 이용해서 유일한 모든 장르들을 목록에 추가합니다.
(Distinct
수정자를 지정하지 않으면 중복된 장르들이 추가될 것입니다. 가령, 이 예제의 경우 코메디 장르가 반복됩니다.)
그리고, ViewBag
개체에 이 장르들의 목록을 저장합니다.
다음 코드는 movieGenre
매개변수를 점검하는 방법을 보여주고 있습니다.
이 매개변수가 비어있지 않으면, 지정된 장르로 검색된 영화 정보를 제한하는 제약조건을 다시 한 번 추가합니다.
if (string.IsNullOrEmpty(movieGenre)) return View(movies); else { return View(movies.Where(x => x.Genre == movieGenre)); }
SearchIndex 뷰에 장르 검색 지원을 위한 마크업 추가하기
마지막으로 Views\Movies\SearchIndex.cshtml 파일을 열고, 다음 코드와 같이 TextBox
도우미 라인 직전에 Html.DropDownList
도우미 라인을 추가합니다.
작업이 마무리 된 완전한 마크업은 다음과 같습니다:
<p> @Html.ActionLink("Create New", "Create") @using (Html.BeginForm("SearchIndex","Movies",FormMethod.Get)) { <p>Genre: @Html.DropDownList("movieGenre", "All") Title: @Html.TextBox("SearchString") <input type="submit" value="Filter" /></p> } </p>
응용 프로그램을 실행하고, /Movies/SearchIndex로 이동한 다음, 장르 검색, 영화 제목 검색, 그리고, 두 가지 모두를 이용한 검색을 테스트 해보십시요.
지금까지 프레임워크가 자동으로 생성해준 CRUD 액션 메서드와 뷰들을 살펴봤습니다.
그리고, 사용자들에게 영화 제목과 장르로 검색할 수 있는 기능을 제공해주기 위한 검색 액션 메서드와 뷰를 작성해봤습니다.
다음 단계에서는 Movie
모델에 속성을 추가하는 방법과 자동으로 테스트 데이터베이스를 생성하는 이니셜라이저(Initializer)를 추가하는 방법을 살펴보도록 하겠습니다.
- 파트 1: ASP.NET MVC 4 및 Visual Studio 2011 소개 2012-06-08 10:47
- 파트 2: 컨트롤러 추가하기 2012-06-08 10:54
- 파트 3: 뷰 추가하기 2012-06-13 09:48
- 파트 4: 모델 추가하기 2012-06-13 09:48
- 파트 5: 컨트롤러에서 모델의 데이터에 접근하기 2012-06-19 11:48
- 파트 6: Edit 메서드와 Edit 뷰 살펴보기 2012-06-19 11:48
- 파트 7: Movie 모델과 테이블에 새로운 필드 추가하기 2012-07-03 10:49
- 파트 8: 모델에 유효성 검사 추가하기 2012-07-03 11:04
- 파트 9: Details 메서드 및 Delete 메서드 살펴보기 2012-07-03 11:07