Asp.net mvc 遵循视图模型模式的最佳实践

Asp.net mvc 遵循视图模型模式的最佳实践,asp.net-mvc,Asp.net Mvc,我现在正在学习ASP.NETMVC。我遵循一些在互联网上或书籍中找到的指导原则,我希望确保在开发视图模型模式时遵循良好的实践。下面是一个博客实现的简单示例。你能确认一下我走对了路吗。假设我想在一个视图上显示一个帖子标题+描述,并在该帖子的评论下方显示。所以我有一个视图,其中有两个局部视图 在我的控制器中: public ActionResult DetailPost(int postID) { // retrieve infos Post post

我现在正在学习ASP.NETMVC。我遵循一些在互联网上或书籍中找到的指导原则,我希望确保在开发视图模型模式时遵循良好的实践。下面是一个博客实现的简单示例。你能确认一下我走对了路吗。假设我想在一个视图上显示一个帖子标题+描述,并在该帖子的评论下方显示。所以我有一个视图,其中有两个局部视图

在我的控制器中:

    public ActionResult DetailPost(int postID)
    {
        // retrieve infos
        Post postModel = repository.Posts.FirstOrDefault(p => p.PostID == postID);
        IEnumerable<Comments> commentsModel = postModel.Comments;

        // prepare view model
        DetailPostViewModel detailPostViewModel = new DetailPostViewModel
                                                        {
                                                            Post = postModel,
                                                            Comments = commentsModel,
                                                        };

        return View(detailPostViewModel);
    }
@model WebUI.ViewModels.DetailPostViewModel

@{
    ViewBag.Title = "Detail";
}

<h2>Detail</h2>

@Html.Partial("_DetailPost", Model.Post)
@Html.Partial("_Comments",  Model.Comments)
@model Domain.Entities.Post

@Html.DisplayForModel()
...
@model IEnumerable<Domain.Entities.Comment>

@foreach (var item in Model)
{
    @Html.DisplayFor(Model => item.Title)
    @Html.DisplayFor(Model => item.Username)
}
所以在我的局部视图中,我使用en实体作为模型。是好还是坏

在我的评论视图中:

    public ActionResult DetailPost(int postID)
    {
        // retrieve infos
        Post postModel = repository.Posts.FirstOrDefault(p => p.PostID == postID);
        IEnumerable<Comments> commentsModel = postModel.Comments;

        // prepare view model
        DetailPostViewModel detailPostViewModel = new DetailPostViewModel
                                                        {
                                                            Post = postModel,
                                                            Comments = commentsModel,
                                                        };

        return View(detailPostViewModel);
    }
@model WebUI.ViewModels.DetailPostViewModel

@{
    ViewBag.Title = "Detail";
}

<h2>Detail</h2>

@Html.Partial("_DetailPost", Model.Post)
@Html.Partial("_Comments",  Model.Comments)
@model Domain.Entities.Post

@Html.DisplayForModel()
...
@model IEnumerable<Domain.Entities.Comment>

@foreach (var item in Model)
{
    @Html.DisplayFor(Model => item.Title)
    @Html.DisplayFor(Model => item.Username)
}
如何将(实体)发布对象列表映射到视图模型对象和所有子对象(注释、用户)中


谢谢

很接近,但对我来说,这不是视图模型的正确用法。您具有以下功能:

public class DetailPostViewModel
{
    public Post Post { get; set; }
    public IEnumerable<Comment> Comments { get; set; }
}
public class DetailPostViewModel
{
    public PostViewModel Post { get; set; }
    public IEnumerable<CommentViewModel> Comments { get; set; }
}
和(
~/Views/Shared/DisplayTemplates/CommentViewModel.cshtml
):

显然,由于Comments是一个枚举,因此将为集合的每个元素自动呈现显示模板。这样,您就不需要在视图中编写任何循环

就控制器逻辑而言,我个人喜欢使用它在域实体和视图模型之间进行映射

所以它可能看起来像这样:

public ActionResult DetailPost(int postID)
{
    // retrieve infos
    var postModel = repository.Posts.FirstOrDefault(p => p.PostID == postID);

    var viewModel = new DetailPostViewModel
    {
        Post = Mapper.Map<Post, PostViewModel>(postModel),
        Comments = Mapper.Map<IEnumerable<Comment>, IEnumerable<CommentViewModel>>(postModel.Comments)
    };
    return View(viewModel);
}

您确实在视图中使用了域模型。视图模型只是域模型的容器

就个人而言,我在视图中使用实体或域模型没有问题。我通常从他们开始。当域/实体模型不能完全满足我的需求时,我会切换到视图模型(而不是在视图中引入逻辑)


没有其他代码依赖于您的视图,这使得重构视图和随时切换模型变得很容易。

我看不出有任何问题implementation@Ankur当前位置对我来说最大的问题是关于局部观点。我的意思是,在这些视图上使用实体是一种好的做法吗?或者我也必须在这些局部视图上使用视图模型吗?我问这个问题是因为规则是:“永远不要将任何域模型传递给视图”!我个人不同意
永远不要将任何域模型传递给视图
就我而言,它只是一些需要通过视图显示的数据结构。这些规则可以让你远离真正的问题我同意Ankur的观点。。设计模式和最佳实践是一件伟大的事情,但在它们实际指导您实现可维护性和良好代码时,以及它们只是在哲学问题上自慰时,找到平衡是非常重要的。。“从不将任何域模型传递到视图”规则来自第二类,我认为,通过这种方式,您可以快速完成工作,并且在99%的情况下不会有任何负面影响。我将重构我的示例并稍后重新提交(我现在不得不离开)以征求意见/建议。您好,我更新了我的帖子(编辑部分)以尝试使用Automapper,但我遇到了一些困难,您可以检查一下吗?@Bronzato,第一个问题是:您是否需要视图中的所有属性?回答是肯定的。为了我的学习,我想知道如何做到这一点。谢谢我们在很多情况下都会遇到这个问题。@Bronzato,我已经更新了我的答案,以举例说明映射可能是什么样子。
@model WebUI.ViewModels.CommentViewModel
@Html.DisplayFor(x => x.Title)
@Html.DisplayFor(x => x.Username)
public ActionResult DetailPost(int postID)
{
    // retrieve infos
    var postModel = repository.Posts.FirstOrDefault(p => p.PostID == postID);

    var viewModel = new DetailPostViewModel
    {
        Post = Mapper.Map<Post, PostViewModel>(postModel),
        Comments = Mapper.Map<IEnumerable<Comment>, IEnumerable<CommentViewModel>>(postModel.Comments)
    };
    return View(viewModel);
}
public class PostViewModel
{
    ... some properties of a Post
    public IEnumerable<CommentViewModel> Comments { get; set; }
}
public ActionResult DetailPost(int postID)
{
    // retrieve infos
    var postModel = repository.Posts.FirstOrDefault(p => p.PostID == postID);
    var viewModel = Mapper.Map<Post, PostViewModel>(postModel);
    return View(viewModel);
}
@model WebUI.ViewModels.PostViewModel

@{
    ViewBag.Title = "Detail";
}

<h2>Detail</h2>

... some properties of a post

@Html.DisplayFor(x => x.Comments)
Mapper.CreateMap<User, UserVM>();
Mapper
    .CreateMap<Comment, CommentVM>()
    .ForMember(
        dest => dest.UserVM, 
        opt => opt.MapFrom(src => src.User)
    );
Mapper
    .CreateMap<Post, PostVM>()
    .ForMember(
        dest => dest.CommentsVM, 
        opt => opt.MapFrom(src => src.Comments)
);
IEnumerable<Post> posts = ...
IEnumerable<PostVm> postVms = Mapper.Map<IEnumerable<Post>, IEnumerable<PostVM>>(posts);
return View(postVms);