C#

MVC Controller

MVC에서 Controller는 사용자의 웹 Request를 받아들여 처리하는 첫 관문에 해당한다. 웹 Request로부터 필요한 파라미터나 POST 데이타를 사용하여 Models에서 데이타를 가져오거나 저장할 수 있으며, 필요한 결과를 사용자에게 보내는 역활을 한다. 일반적으로 컨트롤러는 HTML 결과를 리턴하는데, 이때 컨트롤러는 데이타를 View에 전달하여 랜더링된 HTML을 생성한다. 이와 같이 Controller는 Model 및 View와 긴밀하게 상호작용하면서 전체 흐름을 제어하게 된다.

MVC의 폴더

MVC에서 컨트롤러, 모델, 뷰는 MVC Framework에서 지정한 폴더 밑에 생성하여야 한다. 컨트롤러는 /Controllers 폴더에, 모델은 /Models 폴더에, 그리고 뷰는 /Views 폴더에 생성해야 한다. 예를 들어, 아래 그림에서는 HomeController.cs이 /Controllers 폴더 안에 생성되어 있다. 사용자가 생성한 컨트롤러는 System.Web.Mvc.Controller 클래스로부터 상속되어 Framework에서 제공하는 다양한 기능들을 사용하게 된다. 아래 그림에서 HomeController 클래스 안의 각 메서드는 하나의 웹 페이지에 해당한다. 각 웹페이지는 /{컨트롤러명}/{메서드명} 와 같이 접근할 수 있는데, 이때 컨트롤러명 HomeController 에서 뒤의 Controller는 빼고 쓰게 된다. 또한 메서드명은 ActionResult (혹은 그 파생클래스)를 리턴하는 public 메서드에 대한 이름이다. MVC는 이와 같이 개발자가 일일이 모든 것을 Configuration하게 하지 않고 프레임워크가 정한 관례를 그냥 따르도록 하고 있는데, 이를 "Convention over Configuration"이라 한다.
아래 그림에서 웹사이트의 상대경로 /Home/Index는 HomeController.cs 안의 Index() 메서드를 호출하게 된다.

MVC 컨트롤러 추가

MVC에서 새로운 Controller를 추가하기 위해서는 Controllers 폴더에서 마우스 우클릭하여 Add -> Controller 메뉴를 선택하면 된다. 이때 아래 그림과 같이 여러 컨트롤러 템플릿이 나오는데, 이를 사용하면 기본적인 코드를 미리 생성해 준다하여 Scaffold 라 부른다.

Action 메서드

MVC에서 Controller의 메서드 중 외부 요청에 반응하여 결과를 리턴하는 메서드를 Action 메서드라 한다. Action 메서드는 웹 Request를 받아들여 어떤 처리를 한 후 출력물인 ActionResult 객체를 리턴한다. 아래 코드 예제에서 Index()는 return View() 라는 하나의 문장으로 구성되어 있는데, 이는 MVC의 Controller 베이스클래스의 View() 메서드를 호출한 것으로, Controller.View() 메서드는 (MVC Framework에서 미리 지정한) /Views/Home 폴더 (/Views/{컨트롤러명}) 밑에서 메서드와 동일한 이름인 Index.cshtml (C#의 경우) 파일을 HTML 랜더링하여 결과인 ViewResult (ActionResult의 파생클래스) 객체를 리턴한다.

using System.Web.Mvc;

namespace WebApplication1.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }

        public ActionResult About()
        {
            ViewBag.Message = "Your application description page.";

            return View();
        }
    }
}
Controller에서 Model 클래스를 사용하는 방법은 C#에서 임의의 클래스를 사용하는 것과 같으며, Controller에서 View로 데이타를 전달하기 위해서는 ViewBag, ViewData 혹은 Model 객체를 넘기는 방법을 사용한다. 위의 예제에서 About() 메서드는 ViewBag을 사용한 예를 보여주는데, ViewBag은 dynamic 타입이므로 임의의 속성을 생성해서 지정할 수 있다. 위의 경우는 ViewBag.Message 속성에 값을 지정하였는데, 이 ViewBag은 View (/Views/Home/About.cshtml) 로 넘어가 View 안에서 사용하게 된다.

MVC Controller의 Action 메서드는 HTML을 리턴하는 것 이외에 파일, 문자열, JSON, 자바스크립트 등을 리턴할 수 있고, 또한 다른 URL로 리디렉트할 수도 있다. 모든 Action 메서드는 ActionResult 객체를 리턴하는데, ActionResult 클래스는 실제 추상클래스로서 아래와 같은 파생된 클래스들을 갖는다.

ActionResult 파생클래스 설명 Controller상의 메서드
ViewResult
PartialViewResult
HTML을 리턴 View()
PartialView()
EmptyResult 빈 결과
ContentResult 문자열을 리턴 Content()
FileContentResult,
FilePathResult,
FileStreamResult
파일을 리턴 File()
JavaScriptResult 자바스크립트 리턴 JavaScript()
JsonResult JSON 리턴 Json()
RedirectResult
RedirectToRouteResult
새 URL 혹은 Action으로 Redirect Redirect()
RedirectToRoute()
HttpUnauthorizedResult HTTP 403 리턴
예를 들어, 문자열을 리턴하기 위해선 ContentResult 객체를 사용하면 된다. 아래 예제 A 처럼 ContentResult 객체를 생성하고 Content 속성을 지정하여 리턴하면 문자열이 리턴된다. 그런데 이렇게 자주 사용되는 Result들에 대해 Mvc.Controller 베이스클래스에서 이미 Wrapper 메서드로 갖고 있는데, 위 테이블에 표시되어 있듯이 Content() 라는 메서드를 직접 사용하면 된다. 아래 예제 B는 이러한 Controller.Content() 메서드를 사용하여 간략하게 표현한 예이다.
// 예제 A
public ActionResult NewGuid()
{
    string guid = Guid.NewGuid().ToString();
            
    var result = new ContentResult();
    result.Content = guid;
    return result;
}

// 예제 B : 위 표현을 더 간단히
public ActionResult NewGuid()
{
    string guid = Guid.NewGuid().ToString();

    return Content(guid);
}

파일 다운로드 및 업로드

파일을 다운로드하기 위해서는 위의 ActionResult 타입들 중 FileResult 객체를 리턴하면 된다. 아래 파일 다운로드 예제에서 처럼 먼저 웹서버 상의 파일 절대 경로를 구한 후, 해당 파일을 바이트 배열로 읽어서, 이를 Controller.File() 메서드의 첫번째 파라미터에 전달하면 된다.

// 파일 다운로드 예제
[HttpGet]
public FileResult DownloadSample()
{
    // 웹서버 상의 파일 절대 경로 구함
    string filePath = HttpContext.Server.MapPath("~/Downloads/Sample.dll");

    // 파일 읽기
    byte[] fileBytes = System.IO.File.ReadAllBytes(filePath);
    
    // FileResult 리턴
    return File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, Path.GetFileName(filePath));
}

// 파일 업로드 예제
[HttpPost]
public HttpResponseMessage Upload()
{
    var req = HttpContext.Request;

    //string authVal = req.Headers["Authorization"];            
    //if (authVal != "BASIC SGVsbG8=")
    //{
    //    return new HttpResponseMessage(HttpStatusCode.BadRequest);
    //}

    if (req.Files.Count < 1)
    {
        return new HttpResponseMessage(HttpStatusCode.BadRequest);
    }

    foreach (string file in req.Files)
    {
        var uploadFile = req.Files[file];
        var outputFilePath = HttpContext.Server.MapPath("~/Uploads/" + uploadFile.FileName);
        uploadFile.SaveAs(outputFilePath);                
    }

    return new HttpResponseMessage(HttpStatusCode.OK);
}
웹서버에서 파일을 업로드 받기 위해서는 기본적으로 HttpContext.Request.Files의 내용을 서버상에 저장하면 된다. 위 파일 업로드 예제에서 Request.Files는 파일정보와 파일데이타를 가지고 있는데, 복수 파일들이 업로드될 수 있으며, 각 파일당 다른 이름으로 웹서버에 저장한다. 위 예제에서는 웹서버의 /Uploads 폴더에 업로드한 파일명 그대로 저장하고 있지만, 동일한 파일명이 다른 사람에 의해 다시 업로드 될 수 있으므로 Unique한 이름으로 저장하는 것이 좋다.

본 웹사이트는 광고를 포함하고 있습니다. 광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.

Previous Next Print