모든 Controller는 IController interface를 구현한다.

* Mvc.Controller의 특징
1. ActionMethods
  : Controller의 동작이 여러개의 method로 분할된다. 각 Action method는 서로다른 URL로 노출되며,
  들어오는 요청에서 추출된 매개변수를 가지고 있다.
2. ActionResult
  : Action의 의도된 결과를 나타내는 개체를 선택해서 반환할 수 있다. 결과를 지정하는 것과 실행하는
  것이 분리되기 때문에 자동화된 테스트가 상당히 간단하게 구성될 수 있다.
3. Filter
  : 재사용 가능한 동작들을 Filter로 캡슐화할 수 있다.

* Controller의 입력 처리
Mvc.Controller에서 사용 가능한 속성들
1. Request.QueryString : 요청과 함께 전송된 GET 변수들
2. Request.Form : 요청과 함께 전송된 POST 변수들
3. Request.Cookie : 요청과 함께 전송된 Cookie
4. Request.HttpMethod : 요청을 위해 사용된 Http method
5. Request.Headers : 요청과 함께 전송된 HTTP Header
6. Request.Url : 요청된 Url
7. Request.UserHostAddress : 요청을 보내온 사용자의 Ip Address
8. RouteData.Route : 요청에 대해 선택된 RouteTable.Routes Entry
9. RouteData.Values : 현재의 Route 매개 변수(URL에서 추출된 값이거나 기본 값)
10. HttpContext.Application : Application state 저장소
11. HttpContext.Cache : Application cache 저장소
12. HttpContext.Items : 현재 요청에 대한 상태저장소
13. User : 로그인 한 사용자의 인증정보
14. TempData : Session 내에서 이전 HTTP 요청을 처리하는 동안에 저장된 임시 Data

* Controller의 출력 처리
a. View를 Rendering하는 것으로 HTML 반환
b. HTTP 재전송 호출(311, 312 code 반환)
c. 응답의 출력 스트림에 다른 데이터 전송(xml, json, file)

* Action method 안에서의 직접적으로 Response를 다루는 일은 절대로 하지 않아야지 된다. 대신에 특정한 응답을 나타낼 수 있는 ActionResult를 상속한 객체를 반환하도록 한다.

* ActionResult 형식들
1. ViewResult : 지정된 View Template이나 기본 View Template을 Rendering 한다. [Mvc.Controller.View() method]
2. PartialViewResult : 지정된 Partial View Template이나 기본 Partial View Template을 Rendering한다.(Mvc.Controller.PartialView()]
3. RedirectToRouteResult : Routing 구성 설정에 따라 URL을 생성하면서 302 재전송을 하게 한다.[Mvc.Controller.RedirectToAction()]
4. RedirectResult : 임의의 URL로 HTTP 302 재전송을 하게 한다. RedirectToRouteResult와 다른 점은 RedirectResult는 외부의 URL을 사용가능하다는 차이점을 가지고 있다.
5. ContentResult : 브라우저로 text 데이터를 반환할 수 있다. 선택적으로 Content Header를 지정 가능하다.
6. FileResult : 이진 데이터를 브라우저로 직접 전달한다.
7. Jsonresult : .NET 객체를 Json 포멧으로 직렬화하고 이를 응답으로 전송한다.
8. JavascriptResult : 브라우저에 의해 실행될 수 있는 javascript 소스코드의 일부를 전송한다.
9. HttpUnauthorizedResult : Http 응답코드를 401로 설정한다.
10. EmptyResult : 아무 일도 하지 않는다.

사용자 지정 ActionResult를 만들고 싶은 경우(Image를 가공해서 반환한다던지 등의 Action이 가능하다)에는 ActionResult를 상속받아서 ExecuteResult를 재정의해서 사용하면 된다. 다음은 그 예제 코드이다.


01.public class WatermarkedImageResult : ActionResult
02.{
03.    public string ImageFileName { get; private set; }
04.    public string WatermarkText { get; private set; }
05. 
06.    public WatermarkedImageResult(string imageFileName, string watermarkText)
07.    {
08.        ImageFileName = imageFileName;
09.        WatermarkText = watermarkText;
10.    }
11. 
12.    public override void ExecuteResult(ControllerContext context)
13.    {
14.        using(var image = Image.FromFile(ImageFileName))
15.        using(var graphics = Graphics.FromImage(image))
16.        using(var font = new Font("Arial", 10))
17.        using(var memoryStream = new MemoryStream())
18.        {
19.            var textSize = graphics.MeasureString(WatermarkText, font);
20.            graphics.DrawString(WatermarkText, font, Brushes.White, 10, image.Height - 10 - textSize.Height);
21. 
22.            image.Save(memoryStream, ImageFormat.Png);
23.            var response = context.RequestContext.HttpContext.Response;
24.            response.ContentType = "image/png";
25.            response.BinaryWrite(memoryStream.GetBuffer());
26.        }
27.    }
28.}

* TempData와 Session과의 비교
기본적으로 TempData의 저장소는 Session이 된다. 그렇기 때문에 TempData를 사용하고 싶으면 반드시 Session을 enable 시켜야지 된다. 하지만 TempData의 고유한 특징은 이것이 매우 작은 데이터라는 것이다. 각 entry는 오직 한번의 이전 요청을 저장하고 난 다음 없어진다. 처리 후에 자동으로 청소가 되니 RedirectToAction()에 걸쳐 개체를 유지하는데 적합하다.

* 재 사용가능한 Filter 처리하기
Filter를 이용해서 Controller와 ActionMethod에 추가적인 동작을 지정할 수 있다.
Filter는 요청 처리 PipeLine에 별도의 단계를 추가하는 .NET Attribute로 Action method의 실행 전후에, ActionResult가
실행 전후에 추가적인 로직을 삽입할 수 있다.

Action method의 실행 전후는 IController.Execute method의 실행 전, 후를 의미하며,
ActionResult의 실행 전후는 ActionResult.ExecuteResult method의 실행 전, 후를 의미한다.
따라서 실행 순서는 OnActionExecuting, OnActionExecuted, OnResultExecuting, OnResultExecuted 순서로 실행된다.

ex) HandleError : HandleErrorAttribute는 Controller의 Action method가 실행될 때에 예외가 발생되면 HandleError에 지정된 View가 Render된다.이때에 web.config에 customError mode가 on이 되어있어야지 된다. 이때 지정된 View는 HandleErrorInfo data model이 전달되며, 이는 불려진 Controller와 ActionName, Exception의 정보를 담게 된다. 이 상태는 Error를 처리된 상태로 만들게 되며 따라서 Http 응답코드는 에러가 아닌 200이전달되게 된다.


Controller Test Code
* Controller의 Unit Code는 의미있는 단위 테스트를 작성하기 위해서 많은 사람들이 AAA Pattern을 따른다. Arrange-Act-Assert로 이루어지는
이 방법은 대부분의 Controller 테스트에 유용하다.

01.[TestClass]
02.public class HomeControllerTest
03.{
04.    [TestMethod]
05.    public void CheckViewName()
06.    {
07.        HomeController controller = new HomeController();
08.        ViewResult viewResult = controller.Index();
09. 
10.        Assert.IsNotNull(viewResult);
11.        Assert.AreEqual(viewResult.ViewName, "index");
12.    }
13. 
14.    [TestMethod]
15.    public void CheckViewData()
16.    {
17.        HomeController controller = new HomeController();
18.        ViewResult viewResult = controller.Index();
19. 
20.        Assert.IsNotNull(viewResult);
21.        Assert.AreEqual(6, viewResult.ViewData["age"]);
22.    }
23. 
24.    [TestMethod]
25.    public void CheckRedirection()
26.    {
27.        HomeController controller = new HomeController();
28.        RedirectToRouteResult result = controller.Index();
29. 
30.        Assert.IsNotNull(result);
31.        Assert.AreEqual("RedirectActionName", result.RouteValues["action"]);
32.    }
33.}
Posted by 철냄비짱
,

Visual Studio 2010 - MVC 2.0 프로젝트로 작업을 하던중...

 

Visual Studio 2010 MVC - 잠재적 위험이 있는 Request.Form 값을 발견했습니다.

 

 

 

다음과 같은 에러가 났다.

 

열심히 구글링도 해보고, 이것저것 찾아봤다.

 

해결책은,

 

기존의 WebForm 에서는

ValidateRequest="false"

 

이런 내용을 페이지에 추가하라고 한다.

 

하지만 MVC에서는

액션함수 속성으로,

 

[AcceptVerbs(HttpVerbs.Post), ValidateInput(false)]

 

(포스트일때 주로 이런일이 일어나니까..)

 

이걸 추가하면 된다고 여기저기 블로그나 게시판에 있다.

 

하지만, .NET Framework 4.0에서는 이역시 안된다.

 

Web.Config 파일에 다음 내용을 추가해줘야 한다.

 

<system.web>  
<httpRuntime requestValidationMode="2.0"/>
 
Posted by 철냄비짱
,

간혹 사용자 정의 컨트롤(.ascx) 파일에서 처리한 내용을 Page에 바로 출력하는 것이 아니라, 문자열로 받아야 할 경우가 있습니다.
ASP.NET 웹 폼의 경우에는 Page.LoadControl() 과 Control.RenderControl() 메서드를 이용하여 아래와 같은 코드로 사용자 정의 컨트롤이 처리한 내용을 문자열로 받아올 수 있습니다.

Control control = LoadControl("~/MailTemplate.ascx");

 

((MailTemplate)control).DestinationName = "Whistle";

 

StringBuilder stringBuilder = new StringBuilder();

using (StringWriter sw = new StringWriter(stringBuilder))

{

    using (HtmlTextWriter tw = new HtmlTextWriter(sw))

    {

        control.RenderControl(tw);

    }

}

 

string messageContent = stringBuilder.ToString();

ASP.NET 웹 폼은 자체가 Page 클래스를 상속받으므로, TemplateControl.LoadControl() 메서드를 사용할 수 있으므로, 사용자 정의 컨트롤을 로드하고 HtmlTextWriter를 이용하여 컨트롤의 실행된 내용을 문자열로 받아 올 수 있습니다.

ASP.NET MVC는 사용자 정의 컨트롤이 ViewUserContol을 상속받게 되며, MVC Controller는 자체적으로 ViewUserControl에 대한 LoadControl을 제공하지 않습니다,
ViewUserControl 클래스의 인스턴스를 생성은 ViewPage 클래스의 인스턴스 상에서만 가능합니다.

즉, MVC에서 사용자 정의 컨트롤이 생성하는 HTML을 문자열로 받기 위해서는, 가상의 ViewPage의 인스턴스를 생성하고, 그 ViewPage를 기반으로 사용자 정의 컨트롤을 생성한 후 ASP.NET 웹 폼에서와 같은 방법으로 문자열을 받아 올 수 있습니다.

ViewData["UserName"] = "Whistle";

 

ViewPage viewPage = new ViewPage() { ViewContext = new ViewContext() };

 

viewPage.ViewData = new ViewDataDictionary(ViewData);

viewPage.Controls.Add(viewPage.LoadControl("~/Views/Shared/MailTemplate.ascx"));

 

StringBuilder sb = new StringBuilder();

using (StringWriter sw = new StringWriter(sb))

{

    using (HtmlTextWriter tw = new HtmlTextWriter(sw))

    {

        viewPage.RenderControl(tw);

    }

}

 

string message = sb.ToString();

위와 같은 형식으로 MVC에서도 사용자 정의 컨트롤의 출력 내용을 문자열로 받아와서 처리가 가능합니다.



출처 : http://blog.ntils.com/50

Posted by 철냄비짱
,