정리

ASP.NET MVC 자습서(5) - 컨트롤러에서 모델의 데이터에 엑세스

디벨로프로 2020. 3. 20. 14:00
반응형

이번 시간에는 MovieController 클래스를 만들 것이다.

MVC 패턴의 M은 Model이고 V는 View C는 Controller이다

 

M은 지난 시간에 추가하였고 C를 이번 시간에 만든다면 다음에 올 것은 V이다

View는 지난 글에서 HelloWorldController를 생성할 때 컨트롤러가 가진 함수인 Index와 Welcome과 같은 이름의 파일인 Index.cshtml, Welcome.cshtml을 생성하였다. 

 

이번 시간에는 컨트롤러를 생성하면서 뷰 페이지를 어떻게 만들어야 할지 구상을 미리 하는 연습과 함께 공부를 시작하도록 하자.

 

 

우리가 사용할 스캐폴드는 'Entity Framework를 사용하며 뷰가 포함된 MVC 5 컨트롤러'이다.

 

 

참고로 스캐폴드는 아래와 같은 것들이다.

 

 

컨트롤러를 생성하면서 추가할 내용은 위와 같다.

 

Controller.MoviesController.cs

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using MVC_Movie.Data;
using MVC_Movie.Models;

namespace MVC_Movie.Controllers
{
    public class MoviesController : Controller
    {
        private MVC_MovieContext db = new MVC_MovieContext();

        // GET: Movies
        public ActionResult Index()
        {
            return View(db.Movies.ToList());
        }

        // GET: Movies/Details/5
        public ActionResult Details(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Movie movie = db.Movies.Find(id);
            if (movie == null)
            {
                return HttpNotFound();
            }
            return View(movie);
        }

        // GET: Movies/Create
        public ActionResult Create()
        {
            return View();
        }

        // POST: Movies/Create
        // 초과 게시 공격으로부터 보호하려면 바인딩하려는 특정 속성을 사용하도록 설정하십시오. 
        // 자세한 내용은 https://go.microsoft.com/fwlink/?LinkId=317598을(를) 참조하십시오.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create([Bind(Include = "ID,Title,ReleaseDate,Genre,Price")] Movie movie)
        {
            if (ModelState.IsValid)
            {
                db.Movies.Add(movie);
                db.SaveChanges();
                return RedirectToAction("Index");
            }

            return View(movie);
        }

        // GET: Movies/Edit/5
        public ActionResult Edit(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Movie movie = db.Movies.Find(id);
            if (movie == null)
            {
                return HttpNotFound();
            }
            return View(movie);
        }

        // POST: Movies/Edit/5
        // 초과 게시 공격으로부터 보호하려면 바인딩하려는 특정 속성을 사용하도록 설정하십시오. 
        // 자세한 내용은 https://go.microsoft.com/fwlink/?LinkId=317598을(를) 참조하십시오.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit([Bind(Include = "ID,Title,ReleaseDate,Genre,Price")] Movie movie)
        {
            if (ModelState.IsValid)
            {
                db.Entry(movie).State = EntityState.Modified;
                db.SaveChanges();
                return RedirectToAction("Index");
            }
            return View(movie);
        }

        // GET: Movies/Delete/5
        public ActionResult Delete(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Movie movie = db.Movies.Find(id);
            if (movie == null)
            {
                return HttpNotFound();
            }
            return View(movie);
        }

        // POST: Movies/Delete/5
        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public ActionResult DeleteConfirmed(int id)
        {
            Movie movie = db.Movies.Find(id);
            db.Movies.Remove(movie);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                db.Dispose();
            }
            base.Dispose(disposing);
        }
    }
}

Controller가 생성되면 위와 같은 코드를 가지고 있다.

 

코드 안에는 Index, Details, Create, Edit, Delete의 함수가 View()를 리턴하는 것을 확인할 수 있다. View를 리턴하기 위해서는 View 페이지를 생성해주어야 하는데 Views 폴더에 가보면 Movies라는 폴더와 위에서 말한 함수와 같은 이름의 페이지들이 생성된 것을 확인할 수 있다.

 

실행해서 페이지가 정상적으로 동작하는지 확인해보자.

 

생성한 컨트롤러의 이름이 MoviesController 이기 때문에 Controller을 제외한 Movies를 주소에 입력하면 된다.

localhost:port/Movies

 

정상적으로 접속이 되며 페이지에 적혀있는 타이틀로 Index 페이지임을 확인할 수 있다.

아래에는 Create New 링크형 텍스트가 있는데 클릭해보자.

 

Create Movie 페이지로 이동되었다.

 

TextBox에 적절한 데이터를 입력하고 Create 버튼을 누르면

인덱스 페이지로 이동이 되며 데이터 또한 들어온 것을 확인할 수 있다.

 

좌측 상단에 위치한 서버 탐색기 항목에서 연결되어 있는 데이터 베이스 확인이 가능하다.

Movies라는 테이블이 생성되어 있고 테이블 데이터 표시를 누르면

입력한 값이 들어온것을 확인할 수 있다.

 

페이지 요청과 응답이 정상적으로 이루어지고 있지만 ASP.NET 에서 제공하는 MVC에는 숨겨져있는 마법들이 상당하다. 하나씩 개념을 파헤치기 위해서 테스트를 해보자.

 

App_Start 폴더에 있는 RouteConfig.cs 파일을 들여다 보면 url 형식이 

url: "{controller}/{action}/{id}",

로 입력된 것을 확인할 수 있다.

 

하지만 우리가 생성한 컨트롤러의 이름은 MoviesController 이고 url에 입력하는 값은 MoviesController 가 아닌 Movies 이다. 그렇다면 컨트롤러를 생성할 때, 생성한 컨트롤러 앞의 이름을 URL로 지정하는 어떤 동작이 실행되었음을 예상할 수 있고, 그러한 동작들이 어디서 진행되는지를 확인하고 싶다.

 

우선 컨트롤러의 이름을 변경해보겠다.

MoviesController 의 이름을 s 를 뺀 MovieController 로 변경하였고 실행을 하였을 때

위 사진과 같은 오류가 발생하며 접근을 할 수 없게 된다.

 

그렇다면 변경한 컨트롤러 이름인 Movie를 URL로 입력하여 보겠다.

입력한 URL 에 접근할 수 있지만 Views가 가지고 있는 파일들을 찾을 수 없어서 오류를 반환한다.

Views 폴더의 Movies 를 Movie로 변경해보겠다.

 

정상적으로 호출이 된다.

 

이로서 컨트롤러 이름이 변경됨에 따라 URL 주소가 변경이 되고 View 는 컨트롤러와 이름이 일치해야만 파일을 찾을 수 있음을 알 수 있다.

 

 

이름을 원래대로 되돌려 놓도록 하자.