파트 11: Details 메서드 및 Delete 메서드 살펴보기

등록일시: 2015-06-22 08:00,  수정일시: 2016-09-02 09:05
조회수: 6,981
이 문서는 ASP.NET MVC 기술을 널리 알리고자 하는 개인적인 취지로 제공되는 번역문서입니다. 이 문서에 대한 모든 저작권은 마이크로소프트에 있으며 요청이 있을 경우 언제라도 게시가 중단될 수 있습니다. 번역 내용에 오역이 존재할 수 있고 주석은 번역자 개인의 의견일 뿐이며 마이크로소프트는 이에 관한 어떠한 보장도 하지 않습니다. 번역이 완료된 이후에도 대상 제품 및 기술이 개선되거나 변경됨에 따라 원문의 내용도 변경되거나 보완되었을 수 있으므로 주의하시기 바랍니다.

이번 마지막 단계에서는 자동으로 생성된 Details 메서드와 Delete 메서드를 조금 더 자세히 살펴보도록 하겠습니다.

Details 메서드 및 Delete 메서드 살펴보기

먼저 Movie 컨트롤러를 열고 Details 메서드를 살펴보시기 바랍니다.

// 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);
}

이 코드의 주석을 살펴보면 MVC 스캐폴딩 엔진이 액션 메서드를 생성하면서 이 메서드를 호출할 수 있는 HTTP 요청의 한 가지 사례를 기록해 놓은 것을 볼 수 있습니다. 여기에서는 Movies 컨트롤러와 Details 액션 메서드, 그리고 ID 값, 이렇게 세 가지 URL 세그먼트들로 구성된 GET 요청이 바로 그것입니다.

그리고 이 예제 코드에서 볼 수 있는 것처럼 Code First를 사용하면 Find 메서드를 이용해서 데이터를 손쉽게 검색할 수 있습니다. 보안과 관련해서 Details 메서드에 구현된 중요한 기능 한 가지는 검색된 영화 정보를 이용해서 무언가 작업을 수행하기 전에 항상 Find 메서드의 검색 결과가 존재하는지부터 먼저 확인한다는 점입니다. 만약 이 검사를 수행하지 않는다면 링크를 통해서 목록 페이지로부터 얻어진 URL인 http://localhost:xxxx/Movies/Details/1 을 악의적인 사용자가 http://localhost:xxxx/Movies/Details/12345 등의 URL로 변조해서 (즉, 실제로 존재하지 않는 엉뚱한 영화 정보나 지정해서) 사이트에 오류를 만들어낼 수 있습니다. 따라서 검색된 영화 정보가 null인지 확인하지 않는다면 이는 결국 데이터베이스 오류로 이어지게 될 것입니다.

계속해서 이번에는 Delete 메서드와 DeleteConfirmed 메서드를 살펴보겠습니다.

// 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");
}

이 코드의 HTTP Get Delete 메서드는 지정된 영화 정보를 삭제하는 것이 아니라 단지 영화 정보를 제출해서 (HttpPost) 삭제 작업을 실제로 수행할 뷰를 반환할 뿐이라는 점에 주의하시기 바랍니다. 이런 방식으로 작업하는 이유는 삭제 작업을 (또는 수정이나 생성 작업을 비롯한 데이터 변경이 발생하는 모든 작업을) GET 요청에서 수행하면 보안상의 취약점이 발생하기 때문입니다. 이 문제점에 대한 보다 자세한 정보는 Stephen Walther의 블로그 포스트인 ASP.NET MVC Tip #46 — Don't use Delete Links because they create Security Holes를 참고하시기 바랍니다.

그리고 실제로 데이터를 삭제하는 HttpPost 메서드의 이름이 DeleteConfirmed라고 지정되어 있는 것을 알 수 있는데, 이는 HTTP POST 메서드에 고유한 시그니처 및 이름을 부여하기 위한 것입니다. 이 두 메서드들의 시그니처를 비교해보면 다음과 같습니다:

// GET: /Movies/Delete/5
public ActionResult Delete(int? id)

//
// POST: /Movies/Delete/5
[HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirmed(int id)

공통 언어 런타임(CLR, Common Language Runtime)은 오버로드 된 메서드들의 시그니처가 유일할 것을 기대합니다 (즉, 메서드 이름은 같을 수 있지만 매개변수들의 목록은 달라야 합니다). 그런데 현재 상황은 두 개의 Delete 메서드(GET 버전과 POST 버전)가 필요한 경우임에 반해, 공교롭게도 두 메서드의 시그니처가 동일합니다. (즉, 두 메서드 모두 하나의 정수형 매개변수를 받습니다.)

이 문제점을 해결할 수 있는 방법에는 두 가지가 존재합니다. 첫 번째 방법은 두 메서드들의 이름을 서로 다르게 지정하는 것입니다. 본문의 예제에서 스캐폴딩 메커니즘 역시 이 같은 방식을 따르고 있음을 확인할 수 있습니다. 그러나 그럼에도 여전히 사소한 문제점이 존재하는데, ASP.NET이 URL의 세그먼트들을 액션 메서드와 맵핑할 때 메서드 이름을 기준으로 처리하기 때문에 지금처럼 메서드 이름을 변경해버리면 라우팅이 적절한 액션 메서드를 찾을 수가 없다는 점이 바로 그것입니다. 이 문제의 해결방법은 예제 코드에서도 볼 수 있는 것처럼 DeleteConfirmed 메서드에 ActionName("Delete") 어트리뷰트를 지정하는 것입니다. 이 어트리뷰트를 이용하면 /Delete/ 세그먼트가 포함된 URL에 대한 POST 요청을 라우팅 시스템을 통해서 DeleteConfirmed 메서드로 원활하게 매핑할 수 있습니다.

이 문제점을 해결할 수 있는 두 번째 일반적인 방법은 아예 인위적으로 사용하지 않는 매개변수를 POST 메서드의 시그니처에 추가하는 것입니다. 이를테면 일부 개발자들은 다음 코드처럼 POST 메서드에 전달되는 FormCollection 형식의 매개변수를 추가한 다음, 그냥 이 매개변수를 무시해버립니다:

public ActionResult Delete(FormCollection fcNotUsed, int id = 0)
{
    Movie movie = db.Movies.Find(id);
    if (movie == null)
    {
        return HttpNotFound();
    }
    db.Movies.Remove(movie);
    db.SaveChanges();
    return RedirectToAction("Index");
}

마무리

이제 여러분은 LocalDB 데이터베이스에 데이터를 저장하는 완벽한 ASP.NET 응용 프로그램을 갖게 되었습니다. 영화 정보를 생성하고, 읽고, 변경하고, 삭제할 수 있으며 검색도 가능합니다.

다음 과정

웹 응용 프로그램을 구축하고 테스트를 마쳤다면, 다음으로 할 일은 인터넷을 통해서 사람들이 응용 프로그램을 사용할 수 있도록 만드는 것입니다. 그러기 위해서는 응용 프로그램을 웹 호스팅 공급자에 배포해야만 합니다. Microsoft는 웹 사이트를 무료로 호스팅 할 수 있는 1개월 무료 평가판 Azure 계정을 제공해주므로 참고하시기 바랍니다. 그리고 배포를 위해서는 제가 집필한 다른 자습서인 Deploy a Secure ASP.NET MVC app with Membership, OAuth, and SQL Database to Azure를 참고하시기를 권해드립니다. Tom Dykstra가 집필한 훌륭한 중급 수준의 자습서인 Creating an Entity Framework Data Model for an ASP.NET MVC Application도 추천드립니다. 또한 StackoverflowASP.NET MVC 포럼도 궁금한 점을 문의할 수 있는 좋은 장소입니다. Twitter에서 저를 Follow하시면 제가 집필한 최신 자습서들에 대한 정보를 얻으실 수 있습니다.

피드백은 언제나 환영합니다.

- Rick Anderson twitter: @RickAndMSFT
- Scott Hanselman twitter: @shanselman

이 기사는 2013년 10월 17일에 최초 작성되었습니다.