coding/asp.net

[asp.net] MVC 이해- 간단한 RsvpForm 프로젝트

사과키라임파이 2022. 4. 26. 01:03

응용프로그램에서 아주 중요한 부분인 Model,

Model은 보통 Domain으로 알려짐, app의 주제를 정의하는 실제 세계의 개체들과 절차들, 그리고 규칙들을 나타냄.

 

모델은 종종 도메인 모델이라고도 불리는데, 응용프로그램의 세계를 구성하는 C#개체(=Domain Object)들과 이 개체를 조작할 수 있는 메서드로 구성됨.

그리고 뷰와 컨트롤러는 이런 도메인을 일관된 방식으로 사용자에게 노출시킴.

잘 설계된 mvc는 잘 설계된 모델로부터 비롯하며 잘 설계된 모델은 컨트롤러와 뷰를 추가하기 위한 중추이다.

namespace PartyInvites.Models
{
    public class GuestResponse
    {
        public string Name { get; set; }
        public string Email { get; set; }
        public string Phone { get; set; }
        public bool? WillAttend { get; set; }
    }
}
@{
    ViewBag.Title = "Home Page";
}

<div>

    <h2>@ViewBag.Greeting! 반갑다.</h2>
    <p>파티할게. 오길 바람.</p>
    
    @Html.ActionLink("RSVP Now", "RsvpForm")

</div>

Html.ActionLink -> Html 헬퍼메서드.

첫번째 매개변수는 출력될 문자열, 두번째 매개변수는 사용자가 링크를 클릭했을 때 실행될 액션의 이름. (현재는 Home컨트롤러 내의 index에서 작성했기에, /Home/RsvpForm 위치로 이동한다는 뜻이 됨)

 

폼 작성하기

@model PartyInvites.Models.GuestResponse

@{
    ViewBag.Title = "RsvpForm";
}

<h2>RsvpForm</h2>

@using (Html.BeginForm())
{
    <p>이름 : @Html.TextAreaFor(x=>x.Name)</p>
    <p>email : @Html.TextBoxFor(x=>x.Email)</p>
    <p>전화번호 : @Html.TextBoxFor(x=>x.Phone)</p>
    <p>
        옴?
        @Html.DropDownListFor(x=>x.WillAttend,
       new []
       { 
       new SelectListItem() {Text = "응 감.", Value =bool.TrueString},
       new SelectListItem() {Text ="못 감.",Value=bool.FalseString}
        },
       "선택해!!"
        )
    </p>
    <input type="submit" value="Submit RVSP"/>
}

@Html.TextBoxFor(x=>x.Name)

<input id="Name" name="Name" type="text" value="" />

동일함.

람다식을 사용하면 모델형식의 속성 이름을 자동으로 띄워줌,

 

@Html.BeingForm()은 @using문에 둘러싸여 있음.

보통 using문은 특정 개체가 범위를 벗어날 때, 해당 개체가 정리되는 것을 보장해줌.

보통 DB 연결 관리에서 쿼리 완료 후 확실히 DB를 닫기 위해 사용하는 경우가 많음.

하지만 이처럼 Html 헬퍼 메서드와 함께 사용한 경우는 

Html Form을 닫아주는 역할을 함.

 

시작 URL VS에서 설정하기

여기서 특정 페이지를 추가로 작성할 필요는 없다.

왜냐?
지정되지 않은 값일 경우, VS가 프로젝트의 기본 url, 즉 Home 컨트롤러의 Index 메서드를 가리키는 URL을 요청해주기 때문임.

 

폼 제어하기

현재 상태에서 폼을 서버로 전송 시, 어떤 작업을 수행할 것인지 알리지 않음

= 폼 전송 시 다시 Home컨트롤러의 RsvpFrom 액션 메서드로 전달되기에 RsvpFrom는 그냥 뷰를 렌더하도록 한다.

 

Http Get 요청에 대응하는 메서드:

일반적으로 get은 브라우저 링크를 클릭하여 방문할 때마다 발생함. 현재 초기의 빈 폼을 보여주는 역할

Http Post 요청에 대응하는 메서드:

Html.BeingForm() 메서드를 통해서 렌더된 폼은 기본적으로 브라우저에 의해 Post 요청으로 제출된다.제출된 데이터를 받아서 그 데이터로 수행할 작업을 결졍하는 역할을 담당함.

 

각각의 C# 메서드를 이용해서 GET과 POST 요청을 처리하면 두 메서드가 서로 다른 역할을 담당해 컨트롤러 코드를 깔끔히 유지시킴. 두 메서드는 동일한 URL에 의해 호출되지만 요청이 GET 요청인지 Post 요청인지에 따라 MVC가 적절한 메서드를 호출해줌.

 

public ViewResult RsvpForm() { 
            return View();
        }
        [HttpPost]
        public ViewResult RsvpForm(GuestResponse guestResponse) { 
            return View("Thanks",guestResponse);
        }

HttpGet, HttpPost 어트리뷰트에 따라 MVC에게 어떤 요청을 받았을 때 어떤 메서드로 가야하는지 알려준다.

get은 기본값이기에 생략 가능.

 

 

 

현재 오버로드된 메서드에는 httpPost가 어트리뷰트로 지정되어, 해당 메서드는 post 요청을 받아야만 메서드가 호출된다는 것을 알림.

 

*모델 바인딩 사용하기

RsvpForm 액션 메서드의 첫번째 오버로드는 여전히 같은 뷰, Rsvp.cshtml을 렌더한다.

두번째 오버로드는 특별한데, 메서드에 전달되는 매개변수가 GuestResponse라는 평범한 C# 클래스일 뿐인 것이다.

 

Http Post 요청과 GuestResponse 형식이 연결되는 방법

= 모델 바인딩(Model Binding)

모델 바인딩은 전달된 데이터를 분석하고, http 요청에 포함된 키/값의 쌍들을 이용해서 도메인 모델 형식의 속성들을 채워주는 MVC의 유용한 기능이다.

 

이 처리과정은 Html 헬퍼 메서드를 사용할 때와 정반대로 진행됨.

앞에서는 모델의 속성들로 html input 요소의 id와 name 속성을 채움.

모델 바인딩에서는 input 요소의 이름이 모델 클래스의 인스턴스 속성값을 설정하는데 사용됨, 그 뒤에 모델 클래스의 인스턴스가 Post 대응 액션 메소드에 매개변수로 전달됨.

 

모델 바인딩은 Http 요청을 다루는 작업을 줄여주고, Request.Form[]이나 Request.QueryString[]의 값들 대신 C# 개체를 이용해서 작업을 수행할 수 있도록 도와주면서 사용자 지정이 가능한 기능이다.

액션 메서드에 전달되는 GuestResponse 개체는 자동으로 폼 필드들의 데이터가 채워진다.

 

다른 뷰 렌더하기

두번째 오버로드는 또한 요청에 대한 응답으로, 기본 뷰 대신 특정 뷰를 렌더하도록 MVC에 지시하는 방법도 보여줌.

return View("Thanks", guestResponse);

 

@model PartyInvites.Models.GuestResponse
@{
    ViewBag.Title = "View";
}

Thanks! @Model.Name~

@if (Model.WillAttend == true)
{
    @: 고마워~ 곧 보자.            
}
else 
{
    @: 알았다 다음에 보자~
}

이 Thanks 뷰는 Razor 를 통해서 RsvpFrom 액션 메서드가 Post로 View 메서드에 전달해준 GuestResponse 개체의 속성값에 기반한 내용이 출력됨.

Razor의 @model 표현식은 뷰에 강력하게 지정된 형식의 도메인 모델 형식을 지정한다.

도메인 개체에 존재하는 속성 값에 접근하려면 Model.[속성명] 구문을 사용하면 된다.

ex) Model.WillAttend

 

유효성 검사 추가하기.

이제 응용 프로그램에 유효성을 추가할 차례..

유효성 검사를 추가하지 않으면 사용자가 값을 입력하지 않거나, 말도 안되는 값을 입력할 수 있음.

MVC 응용프로그램의 유효성 검사는 대부분 사용자 인터페이스가 아닌 도메인 모델에 적용된다.

그렇기 때문에 유효성 검사의 기준을 한 장소에 정의하더라도 모델 클래스가 사용되는 모든 곳에서 그 효과를 얻을 수 있음.

ASP.NET MVC는 System.ComponenModel.DataAnnotations 네임스페이스의 어트리뷰트들을 이용한 선언적 유효성 검사규칙을 지원하기에 C# 표준 어트리뷰트 기능을 이용해서 유효성 검사 규칙들을 표현할 수 있다.

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;

namespace PartyInvites.Models
{
    public class GuestResponse
    {
        [Required(ErrorMessage ="필수로 적어주세요.")]
        public string Name { get; set; }
        [RegularExpression(".+\\@.+\\..+"), 
            Required(ErrorMessage = "필수로 적어주세요.")]
        public string Email { get; set; }
        [Required(ErrorMessage = "필수로 적어주세요.")]
        public string Phone { get; set; }
        [Required(ErrorMessage = "필수로 적어주세요.")]
        public bool? WillAttend { get; set; }
    }
}

MVC는 자동으로 이 어트리뷰트들을 감지해서 모델 바인딩이 진행되는 동안 데이터 유효성 검사에 이용한다.

그리고 유효성 검사 관련 어트리뷰트를 포함하고 있는 네임페이스를 임포트했기에 해당 어트리뷰트들의 이름을 한정하지 않고도 참조할 수 있는 것이라는 것에 주의할 것.

 

여기서

 public bool? WillAttend { get; set; }

이것은 boo?로 NullAble 값으로 작성해야 한다.

일반적인 bool 작성 시 모델 바인딩을 통해서 true와 false(입력 안한 건지, 안 온다는 건지 모름)를 받게되기 때문.

null은 사용자가 선택하지 않은 것이므로 Required의 유효성 검사에 어긋난다.

 

우리가 보낸 모델
소스로 변한 모델 데이터
요청 헤더
실제로 브라우저에 만들어진 소스, input 보안

[HttpPost]
        public ViewResult RsvpForm(GuestResponse guestResponse)
        {
            if (ModelState.IsValid)
            {
                return View("Thanks", guestResponse);
            }
            else
            {
                // 유효성 오류가 남
                return View();
            }
        }

 

오류 발생 시 다시 폼으로 이동하도록 함.

그리고 RsvpForm 페이지에 가서 왜 오류났는지 코드를 추가해줌.

@Html.ValidationSummary()

<h2>RsvpForm</h2>

@using (Html.BeginForm())
{
    @Html.ValidationSummary()
    <p>이름 : @Html.TextBoxFor(x=>x.Name)</p>
    <p>email : @Html.TextBoxFor(x=>x.Email)</p>
    <p>전화번호 : @Html.TextBoxFor(x=>x.Phone)</p>
    <p>
        옴?
        @Html.DropDownListFor(x=>x.WillAttend,
       new []
       { 
       new SelectListItem() {Text = "응 감.", Value =bool.TrueString},
       new SelectListItem() {Text ="못 감.",Value=bool.FalseString}
        },
       "선택해!!"
        )
    </p>
    <input type="submit" value="Submit RVSP"/>
}

유효하지 않은 필드 강조하기

텍스트 박스, 드롭다운 리스트같은 Html 헬퍼 메소드는 모델 바인딩과 함께 사용할 수 있는 멋진 기능이 있음

사용자가 입력했던 값을 유지해주는 매커니즘이 유효성 검사에 실패한 각각의 필드를 강조하는 용도로 사용 가능함.

 

모델 클래스의 특정 속성이 유효성 검사에 실패했다면 html 헬퍼는 input class에 input-validation-error를 추가해 줌

 

https://docs.microsoft.com/ko-kr/aspnet/web-pages/overview/ui-layouts-and-themes/validating-user-input-in-aspnet-web-pages-sites

 

추후 js 및 css 스타일 시트를 병합하고 단일 http 요청으로 브라우저에 배포할 수 있게 하는 번들(Bundles) 기능에 관해 확인 할 것임

 

꾸미기 및 마무리