[asp.net-mvc] ViewModel 모범 사례

에서 이 질문에 , 그것은 컨트롤러가 만들도록하는 것이 합리적 것 같습니다 뷰 모델 보다 정확하게보기를 표시하려고하고있는 모델을 반영하지만, 나는 (내가 MVC 패턴에 새로운 해요 규칙의 일부에 대해 궁금 해요 아직 명확하지 않은 경우).

기본적으로 다음과 같은 질문이 있습니다.

  1. 나는 보통 하나의 클래스 / 파일을 갖고 싶습니다. 로모그래퍼이 메이크업 감각을합니까 뷰 모델 이 만 볼 수있는 컨트롤러에서 데이터 떨어져 손에 작성되는 경우?
  2. 경우 뷰 모델은 자체 파일에 속하지 않는, 당신은, 일을 분리 유지하기 위해 디렉토리 / 프로젝트 구조를 사용하는 곳 수행 뷰 모델에 속하는 파일을? 에서 컨트롤러 디렉토리?

그것은 기본적으로 지금입니다. 몇 가지 질문이 더 나올 수도 있지만 지난 한 시간 동안 저를 괴롭 히고 다른 곳에서 일관된 지침을 찾을 수 있습니다.

편집 : CodePlex
의 샘플 NerdDinner 앱 을 보면 ViewModels가 Controllers의 일부인 것처럼 보이지만 여전히 자신의 파일에 있지 않은 것이 불편합니다.



답변

각 뷰에 대해 “ViewModel”이라고하는 것을 만듭니다. MVC 웹 프로젝트의 ViewModels 폴더에 넣었습니다. 나는 컨트롤러와 그들이 나타내는 행동 (또는보기)의 이름을 따서 명명합니다. 따라서 멤버쉽 컨트롤러의 SignUp보기에 데이터를 전달해야하는 경우 MembershipSignUpViewModel.cs 클래스를 만들어 ViewModels 폴더에 넣습니다.

그런 다음 컨트롤러에서보기로 데이터를 쉽게 전송할 수 있도록 필요한 속성과 방법을 추가합니다. Automapper를 사용하여 ViewModel에서 도메인 모델로 이동하고 필요한 경우 다시 돌아옵니다.

이것은 다른 ViewModel 유형의 속성을 포함하는 복합 ViewModel에도 효과적입니다. 예를 들어 멤버쉽 컨트롤러의 인덱스 페이지에 5 개의 위젯이 있고 각 부분 뷰에 대해 ViewModel을 만든 경우 인덱스 작업에서 부분으로 데이터를 어떻게 전달합니까? MyPartialViewModel 유형의 MembershipIndexViewModel에 속성을 추가하고 부분을 렌더링 할 때 Model.MyPartialViewModel에 전달합니다.

이렇게하면 인덱스 뷰를 전혀 변경하지 않고도 부분 ViewModel 속성을 조정할 수 있습니다. 여전히 Model.MyPartialViewModel을 전달하기 때문에 부분 ViewModel에 속성을 추가하는 것이 무엇이든 할 때 무언가를 해결하기 위해 전체 부분 체인을 거치지 않아도됩니다.

또한 네임 스페이스 “MyProject.Web.ViewModels”를 web.config에 추가하여 각 뷰에 명시적인 import 문을 추가하지 않고도 모든 뷰에서 참조 할 수 있도록합니다. 좀 더 깨끗하게 만듭니다.


답변

범주 (컨트롤러, 뷰 모델, 필터 등)별로 클래스를 분리하는 것은 의미가 없습니다.

웹 사이트의 홈 섹션 (/)에 대한 코드를 작성하려면 Home이라는 폴더를 만들고 HomeController, IndexViewModel, AboutViewModel 등 및 홈 작업에 사용되는 모든 관련 클래스를 저장하십시오.

ApplicationController와 같은 클래스를 공유 한 경우 프로젝트의 루트에 놓을 수 있습니다.

왜 관련이있는 것들 (HomeController, IndexViewModel)을 분리하고 전혀 관계가없는 것들 (HomeController, AccountController)을 유지 하는가?


이 주제에 관한 블로그 게시물을 작성했습니다 .


답변

응용 프로그램 클래스를 “Core”(또는 별도의 클래스 라이브러리)라는 하위 폴더에 보관하고 KIGG 샘플 응용 프로그램 과 동일한 방법을 사용 하지만 약간 더 변경하여 응용 프로그램을 더 건조하게 만듭니다.

일반적인 사이트 전체 속성을 저장하는 / Core / ViewData /에 BaseViewData 클래스를 만듭니다.

이 후에도 동일한 폴더에 모든 View ViewData 클래스를 만든 다음 BaseViewData에서 파생하여 특정 뷰 속성을 갖습니다.

그런 다음 모든 컨트롤러에서 파생되는 ApplicationController를 만듭니다. ApplicationController에는 다음과 같은 일반적인 GetViewData 메소드가 있습니다.

protected T GetViewData<T>() where T : BaseViewData, new()
    {
        var viewData = new T
        {
           Property1 = "value1",
           Property2 = this.Method() // in the ApplicationController
        };
        return viewData;
    }

마지막으로 내 컨트롤러 작업에서 ViewData 모델을 빌드하기 위해 다음을 수행합니다.

public ActionResult Index(int? id)
    {
        var viewData = this.GetViewData<PageViewData>();
        viewData.Page = this.DataContext.getPage(id); // ApplicationController
        ViewData.Model = viewData;
        return View();
    }

나는 이것이 정말로 잘 작동한다고 생각하고 당신의 견해를 깔끔하게 유지하고 컨트롤러는 날씬하게 만듭니다.


답변

ViewModel 클래스는 클래스의 인스턴스로 표현되는 여러 데이터를 하나의 관리하기 쉬운 객체로 캡슐화하여 View에 전달할 수 있습니다.

ViewModel 클래스를 자체 파일의 자체 디렉토리에 두는 것이 좋습니다. 내 프로젝트에는 ViewModels라는 Models 폴더의 하위 폴더가 있습니다. 그것이 내 ViewModels (예 :)가 ProductViewModel.cs사는 곳입니다.


답변

모델을 보관하기에 적합한 장소는 없습니다. 프로젝트가 크고 ViewModel (데이터 전송 객체)이 많은 경우 별도의 어셈블리로 유지할 수 있습니다. 또한 사이트 프로젝트의 별도 폴더에 보관할 수 있습니다. 예를 들어, Oxite 에서는 다양한 클래스가 포함 된 Oxite 프로젝트에 배치됩니다. Oxite의 컨트롤러는 별도의 프로젝트로 이동하고 뷰도 별도의 프로젝트에 있습니다.
에서 CodeCampServer ViewModels *이 양식 명명 된 그들은 모델 폴더에 UI 프로젝트에 배치됩니다.
에서 MvcPress의 프로젝트 그들은 또한 데이터베이스와 좀 더와 작업에 대한 모든 코드를 포함하는 데이터 프로젝트에 배치됩니다 (하지만이 방법을 권장하지 않았다, 그것은 샘플은 단지)
많은 관점이 있습니다. 일반적으로 사이트 프로젝트에 내 ViewModel (DTO 객체)을 유지합니다. 그러나 10 개가 넘는 모델이있는 경우 별도의 어셈블리로 모델을 옮기는 것을 선호합니다. 일반적 으로이 경우 컨트롤러를 분리하여 어셈블리를 분리합니다.
또 다른 질문은 모델의 모든 데이터를 ViewModel에 쉽게 매핑하는 방법입니다. AutoMapper 라이브러리를 살펴 보는 것이 좋습니다 . 나는 그것을 매우 좋아한다, 그것은 나를 위해 모든 더러운 일을한다.
또한 SharpArchitecture 프로젝트 를 살펴볼 것을 제안합니다 . 프로젝트를위한 매우 훌륭한 아키텍처를 제공하며 멋진 프레임 워크와 지침 및 훌륭한 커뮤니티가 많이 포함되어 있습니다.


답변

모범 사례의 코드 스 니펫은 다음과 같습니다.

    public class UserController : Controller
    {
        private readonly IUserService userService;
        private readonly IBuilder<User, UserCreateInput> createBuilder;
        private readonly IBuilder<User, UserEditInput> editBuilder;

        public UserController(IUserService userService, IBuilder<User, UserCreateInput> createBuilder, IBuilder<User, UserEditInput> editBuilder)
        {
            this.userService = userService;
            this.editBuilder = editBuilder;
            this.createBuilder = createBuilder;
        }

        public ActionResult Index(int? page)
        {
            return View(userService.GetPage(page ?? 1, 5));
        }

        public ActionResult Create()
        {
            return View(createBuilder.BuildInput(new User()));
        }

        [HttpPost]
        public ActionResult Create(UserCreateInput input)
        {
            if (input.Roles == null) ModelState.AddModelError("roles", "selectati macar un rol");

            if (!ModelState.IsValid)
                return View(createBuilder.RebuildInput(input));

            userService.Create(createBuilder.BuilEntity(input));
            return RedirectToAction("Index");
        }

        public ActionResult Edit(long id)
        {
            return View(editBuilder.BuildInput(userService.GetFull(id)));
        }

        [HttpPost]
        public ActionResult Edit(UserEditInput input)
        {
            if (!ModelState.IsValid)
                return View(editBuilder.RebuildInput(input));

            userService.Save(editBuilder.BuilEntity(input));
            return RedirectToAction("Index");
        }
}


답변

모든 ViewModel을 Models 폴더에 넣습니다 (모든 비즈니스 로직은 별도의 ServiceLayer 프로젝트에 있음)