[c#] ASP.NET MVC Razor 모델을 레이아웃으로 전달

내가 보는 것은 문자열 레이아웃 속성입니다. 하지만 어떻게 모델을 레이아웃에 명시 적으로 전달할 수 있습니까?



답변

이 문제가 있으면 뷰 모델을 약간 잘못 모델링 한 것 같습니다.

개인적으로 레이아웃 페이지를 입력하지 않습니다. 그러나 그렇게하려면 다른 뷰 모델이 상속하는 기본 뷰 모델이 있어야하며 기본 뷰 모델에 레이아웃을 입력하고 특정 페이지로 한 번 페이지를 지정해야합니다.


답변

  1. 사용하려는 유형으로 MainLayoutViewModel (또는 기타)이라는 컨트롤러 (또는 기본 컨트롤러)에 속성을 추가합니다.
  2. 컨트롤러 (또는 기본 컨트롤러)의 생성자에서 유형을 인스턴스화하고 속성으로 설정합니다.
  3. ViewData 필드 (또는 ViewBag)로 설정합니다.
  4. 레이아웃 페이지에서 해당 속성을 유형으로 캐스팅합니다.

예 : 컨트롤러 :

public class MyController : Controller
{
    public MainLayoutViewModel MainLayoutViewModel { get; set; }

    public MyController()
    {
        this.MainLayoutViewModel = new MainLayoutViewModel();//has property PageTitle
        this.MainLayoutViewModel.PageTitle = "my title";

        this.ViewData["MainLayoutViewModel"] = this.MainLayoutViewModel;
    }

}

레이아웃 페이지 상단의 예

@{
var viewModel = (MainLayoutViewModel)ViewBag.MainLayoutViewModel;
}

이제 유형이 지정된 개체에 대한 전체 액세스 권한으로 레이아웃 페이지에서 변수 ‘viewModel’을 참조 할 수 있습니다.

개별 페이지 뷰 모델은 레이아웃에 구애받지 않고 레이아웃을 제어하는 ​​컨트롤러이기 때문에이 접근 방식을 좋아합니다.

MVC Core에 대한 참고 사항


Mvc Core는 각 작업을 처음 호출 할 때 ViewData / ViewBag의 내용을 날려 버리는 것처럼 보입니다. 이것이 의미하는 바는 생성자에서 ViewData를 할당하는 것이 작동하지 않는다는 것입니다. 그러나 작동 IActionFilter하는 것은를 사용 하고에서 똑같은 작업을 수행하는 것입니다 OnActionExecuting. 넣어 MyActionFilter당신에 MyController.

public class MyActionFilter: Attribute, IActionFilter
    {
        public void OnActionExecuted(ActionExecutedContext context)
        {
        }

        public void OnActionExecuting(ActionExecutingContext context)
        {
            var myController= context.Controller as MyController;

            if (myController!= null)
            {
                myController.Layout = new MainLayoutViewModel
                {

                };

                myController.ViewBag.MainLayoutViewModel= myController.Layout;
            }
        }
    }


답변

이것은 매우 기본적인 것입니다. 여러분이해야 할 일은 기본 뷰 모델을 만들고 모두 확인하는 것입니다! 그리고 나는 모두를 의미한다! 해당 레이아웃을 사용할 뷰 중 해당 기본 모델을 사용하는 뷰를 받게됩니다!

public class SomeViewModel : ViewModelBase
{
    public bool ImNotEmpty = true;
}

public class EmptyViewModel : ViewModelBase
{
}

public abstract class ViewModelBase
{
}

_Layout.cshtml에서 :

@model Models.ViewModelBase
<!DOCTYPE html>
  <html>
  and so on...

홈 컨트롤러의 인덱스 (예 🙂 메소드에서 :

    public ActionResult Index()
    {
        var model = new SomeViewModel()
        {
        };
        return View(model);
    }

Index.cshtml :

@model Models.SomeViewModel

@{
  ViewBag.Title = "Title";
  Layout = "~/Views/Shared/_Layout.cshtml";
}

<div class="row">

모델을 _layout에 전달하는 것이 오류라는 데 동의하지 않습니다. 일부 사용자 정보를 전달할 수 있으며 데이터를 컨트롤러 상속 체인에 채울 수 있으므로 하나의 구현 만 필요합니다.

분명히 더 고급 목적을 위해 주입을 사용하여 사용자 정의 정적 contaxt을 생성하고 해당 모델 네임 스페이스를 _Layout.cshtml에 포함해야합니다.

그러나 기본 사용자에게는 이것이 트릭을 할 것입니다.


답변

일반적인 해결책은 레이아웃 파일에 사용 된 속성을 포함하는 기본보기 모델을 만든 다음 기본 모델에서 각 페이지에서 사용되는 모델로 상속하는 것입니다.

이 접근 방식의 문제는 이제 모델의 문제가 다른 하나의 클래스에서만 상속 할 수 있다는 문제에 잠겨 있다는 것이며, 어쨌든 의도 한 모델에서 상속을 사용할 수없는 솔루션 일 수 있습니다.

내 솔루션은 기본 뷰 모델로 시작됩니다.

public class LayoutModel
{
    public LayoutModel(string title)
    {
        Title = title;
    }

    public string Title { get;}
}

그런 다음 사용하는 것은 다음과 같이 LayoutModel에서 상속하는 LayoutModel의 일반 버전입니다.

public class LayoutModel<T> : LayoutModel
{
    public LayoutModel(T pageModel, string title) : base(title)
    {
        PageModel = pageModel;
    }

    public T PageModel { get; }
}

이 솔루션을 통해 레이아웃 모델과 모델 간의 상속 필요성을 분리했습니다.

이제 다음과 같이 Layout.cshtml에서 LayoutModel을 사용할 수 있습니다.

@model LayoutModel
<!doctype html>
<html>
<head>
<title>@Model.Title</title>
</head>
<body>
@RenderBody()
</body>
</html>

그리고 페이지에서 다음과 같이 일반 LayoutModel을 사용할 수 있습니다.

@model LayoutModel<Customer>
@{
    var customer = Model.PageModel;
}

<p>Customer name: @customer.Name</p>

컨트롤러에서 LayoutModel 유형의 모델을 반환하기 만하면됩니다.

public ActionResult Page()
{
    return View(new LayoutModel<Customer>(new Customer() { Name = "Test" }, "Title");
}


답변

필요한 모델을 부분보기에 전달하는 고유 한 컨트롤러로 새 부분보기를 추가하고 마지막으로 RenderPartial 또는 RenderAction을 사용하여 Layout.cshtml에서 언급 된 부분보기를 렌더링하지 않는 이유는 무엇입니까?

이 방법을 사용하여 이름, 프로필 사진 등과 같은 로그인 한 사용자의 정보를 표시합니다.


답변

오래된 질문이지만 MVC5 개발자를위한 솔루션을 언급하기 위해 Model보기에서와 동일한 속성을 사용할 수 있습니다.

Model보기 및 레이아웃 의 속성은 동일한 ViewDataDictionary개체와 연결되어 있으므로 모델을 레이아웃 페이지로 전달하기 위해 추가 작업을 수행 할 필요가 없으며 @model MyModelName레이아웃에서 선언 할 필요가 없습니다 .

그러나 @Model.XXX레이아웃에서 사용할 때 intelliSense 상황에 맞는 메뉴가 나타나지 않습니다. Model여기에는 ViewBag.


답변

기술적으로는 그것을 처리하는 적절한 방법이 아닐 수도 있지만, 가장 간단하고 합리적인 해결책은 클래스를 만들고 레이아웃에서 인스턴스화하는 것입니다. 그렇지 않으면 올바른 방법에 대한 일회성 예외입니다. 이것이 레이아웃보다 더 많이 수행된다면, 당신이하는 일을 진지하게 재고하고 프로젝트를 더 진행하기 전에 몇 가지 튜토리얼을 더 읽어야합니다.

public class MyLayoutModel {
    public User CurrentUser {
        get {
            .. get the current user ..
        }
    }
}

그런 다음보기에서

@{
    // Or get if from your DI container
    var myLayoutModel = new MyLayoutModel();
}

.net 코어에서는이를 건너 뛰고 종속성 주입을 사용할 수도 있습니다.

@inject My.Namespace.IMyLayoutModel myLayoutModel

그것은 일종의 그늘진 영역 중 하나입니다. 그러나 내가 여기서보고있는 매우 복잡한 대안을 감안할 때 실용성의 이름으로 만드는 것은 괜찮은 예외 이상이라고 생각합니다. 특히 단순하게 유지하고 무거운 논리 (정말로 있어서는 안되지만 요구 사항은 다르다고 주장함)가 속한 다른 클래스 / 계층에 있는지 확인하십시오. 기본적으로 하나의 뷰를 위해 모든 컨트롤러 또는 모델을 오염시키는 것보다 확실히 낫습니다.