Programming/.NET

일반적으로는 Controller의 Action Method에서 View로 Model을 전달할때는 한가지 형식의 모델만 전달하는 것이 보통이며 아래는 그에 해당하는 예제입니다.

 

public class Member
{
    public string Id { getset}
    public string Name { getset}
    public int Level { getset}
}

public class Members
{
    private static Members mbs = new Members();

    public static Members GetMbs
    {         get { return mbs}
    }

    public List<MemberMemberList = new List<Member{
        new Member { Id = "cliel1"Name = "홍길동"Level = 10 },
        new Member { Id = "cliel2"Name = "홍길순"Level = 20 },
        new Member { Id = "cliel3"Name = "홍길남"Level = 30 },
        new Member { Id = "cliel4"Name = "홍길영"Level = 40 },
        new Member { Id = "cliel5"Name = "홍길석"Level = 50 }
    };

    public IEnumerable<MemberGetMember()
    {
        return MemberList;
    }

    public bool AddMember(Member m)
    {
        MemberList.Add(m);

        return true;
    }
}

 

Member 라는 클래스를 통해 Model을 정의했으며 Members로 이 Model에 대한 리스트를 가져오거나 추가하는 클래스를 작성하였습니다.

 

private Members mbs = Members.GetMbs;

// GET: Home
public ActionResult Index()
{
    return View((mbs.GetMember()));
}

 

Home 컨트롤러에서는 Members의 정적 멤버를 이용해 IEnumerable 형식으로 Member 리스트를 가져오도록 하였습니다.

 

@using WebApplication1.Models
@model IEnumerable<WebApplication1.Models.Member>

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
</head>
<body>
    <table>
        @foreach (Member m in Model) {
            <tr>
                <td>@m.Id</td>
                <td>@m.Name</td>
                <td>@m.Level</td>
            </tr>
        }
    </table>
</body>
</html>

 

뷰에서는 전달된 모델을 통해 요소를 순회하면서 각 Member의 리스트를 표시하고 있습니다.

 

이제 이 상태에서 새로운 Member 개체를 추가해야 한다고 가정해 보겠습니다. 우리는 이 기능의 구현을 위해 입력컨트롤 생성을 위한 TextBoxFor 와 같은 메서드를 사용하려고 합니다. 그런데 현재 Model수준에서는 이 메서드사용이 불가능합니다. 전달된 Model형식자체가 배열형식이기 때문입니다. 이 문제점을 해결하기 위해 여기서는 Tuple 클래스를 사용해 보려고 합니다.

 

public ActionResult Index()
{
    var t = new Tuple<IEnumerable<Member>, Member>(mbs.GetMember()new Member()) { };
    return View(t);
}

 

먼저 Controller를 위와 같이 수정합니다. 보시면 Tuple를 통해 IEnumerable형식의 Member와 단일 형식의 Member를 감싸고 있습니다. <>안에서는 전달하고자 하는 Model의 형식을 넣고 ()안에는 실제 전달된 Model자체를 지정하여 2가지 형식의 Model을 묶는 것입니다. 그리고 이렇게 생성된 인스턴스를 View메서드를 통해 전달하고 있습니다.

 

@model Tuple<IEnumerable<WebApplication1.Models.Member>, WebApplication1.Models.Member>

전달될 Model을 위와같이 변경하였으니 뷰에서도 그에 맞추어 model 형식선언을 변경해야 합니다. 다만 이때는 Tuple에서 <>안에 Model의 형식만을 지정합니다.

 

그렇다면 어떻게 Tuple안에 있는 형식에 접근할 수 있을까? Tuple는 이를 위해 Item이라는 속성을 제공하고 있습니다.

 

<table>
    @foreach (Member m in Model.Item1) {
        <tr>
            <td>@m.Id</td>
            <td>@m.Name</td>
            <td>@m.Level</td>
        </tr>
    }
</table>

 

기존의 foreach가 사용된 부분을 주목해 주세요. Model에서 Model.Item1로 Model지정방식이 변경되었습니다. Tuple에서 첫번째 Model형식이 IEnumerable이고 foreach안에서는 해당 형식을 다루어야 하므로 Item1속성을 통해 IEnumerable이 지정된 Model에 접근하고자 하는 것입니다.

 

@using (Html.BeginForm("AddMember""Home")) {
    <p>ID : </p>@Html.TextBoxFor(x => x.Item2.Id)<br />
    <p>NAME : </p>@Html.TextBoxFor(x => x.Item2.Name)<br />
    <p>LEVEL : </p>@Html.TextBoxFor(x => x.Item2.Level)<br />
    <input type="submit" value="추가" />
}

 

이제 위에서 처럼 Member를 추가할 Form을 만듭니다. 이때 Member의 각 속성은 Model의 Item2 속성을 통해 접근하고 있는데 이는 Tuple에서 두번째 Model이 단일 Member이기 때문입니다.

 

public ActionResult AddMember([Bind(Prefix ="Item2")]Member m)
{
    mbs.AddMember(m);

    return RedirectToAction("Index");
}

 

Member 추가에 사용될 액션메서드입니다. 특히 메서드의 매개변수에서 Bind의 Prefix속성을 통해 Item2라고 지정하고 있는데 만약 이렇게 하지 않으면 item2.id나 item2.Name과 같은 속성이름을 통해 Model을 바인딩하려고 시도할 것입니다. 하지만 이 속성값들은 실제 Member의 속성과 일치하지 않기 때문에 바인딩에 실패하게 되고 따라서 속성을 정확히 일치시키기 위해 Item2를 Prefix로 지정하여 Item2안에서의 속성만으로 Member의 Model에 바인딩될 수 있도록 해야합니다.

'Programming > .NET' 카테고리의 다른 글

[C#] Task  (0) 2017.11.01
[C#] BigInteger  (0) 2017.10.24
[ASP.NET MVC] 다중 모델 사용하기 (Tuple)  (0) 2017.10.18
[C#] dynamic 과 덕 타이핑(duck typing)  (0) 2017.10.10
[C#] 컬렉션 초기화  (0) 2017.09.26
[ASP.NET MVC] 유효성 확인 - 2  (0) 2017.09.20
0 0