加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

asp.net-mvc – 遵循视图模型模式的最佳实践

发布时间:2020-12-16 06:30:09 所属栏目:asp.Net 来源:网络整理
导读:我现在有几次学习ASP.NET MVC了.我遵循在互联网或书籍中找到的一些指导原则,我希望确保我遵循关于视图模型模式的开发中的良好实践.以下是博客实施的简单示例.能否请你确认我是在正确的方式.假设我想在视图上显示帖子标题描述,并在此帖子上显示评论.所以我有
我现在有几次学习ASP.NET MVC了.我遵循在互联网或书籍中找到的一些指导原则,我希望确保我遵循关于视图模型模式的开发中的良好实践.以下是博客实施的简单示例.能否请你确认我是在正确的方式.假设我想在视图上显示帖子标题描述,并在此帖子上显示评论.所以我有一个视图有2个部分视图.

在我的控制器中:

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)

所以在这里,我使用了我的DetailPostViewModel.对于我的部分观点,我传递了必要的信息,即实体!?我不知道这是正确的方式,还是我必须在这里通过视图模型呢?

在我的_DetailPost视图中:

@model Domain.Entities.Post

@Html.DisplayForModel()
...

所以在我的部分视图中,我使用en实体作为模型.是好还是坏?

在我的_Comments视图中:

@model IEnumerable<Domain.Entities.Comment>

@foreach (var item in Model)
{
    @Html.DisplayFor(Model => item.Title)
    @Html.DisplayFor(Model => item.Username)
}

所以在我的部分视图中,我使用en实体作为模型.是好还是坏?

感谢您的建议/意见.

编辑

我尝试在Automapper的帮助下实现我的视图模型模式,但是我遇到了一些问题,如下所述.我理解将一个对象映射到另一个对象的原理.在基本情况下,它运作良好.现在,让我们看一个更复杂的情况:我有一个由一些属性(id,title,…)组成的帖子,每个帖子可以附加一些注释(对象),每个注释只能附加一个用户(对象) .我希望得到一个包含我所有帖子的视图模型,并获取所有评论,并为每个评论获得用户附加.

以下是域实体:

public class Post
{
    public int    PostID    { get; set; }
    public string Title     { get; set; }
    ...
    public virtual ICollection<Comment> Comments { get; set; }
}

public class Comment
{
    public int    CommentID   { get; set; }
    public string CommentText { get; set; }
    ...
    public virtual <User> User { get; set; }
}

public class User
{
    public int UserID      { get; set; }
    public string Username { get; set; }
    ...
}

以下是视图模型:

public class PostVM
{
    public int    PostID    { get; set; }
    public string Title     { get; set; }
    ...
    public virtual ICollection<CommentVM> CommentsVM { get; set; }
}

public class CommentVM
{
    public int    CommentID   { get; set; }
    public string CommentText { get; set; }
    ...
    public virtual <UserVM> UserVM { get; set; }
}

public class UserVM
{
    public int UserID      { get; set; }
    public string Username { get; set; }
    ...
}

这是我的控制器:

// I would like to list all posts in the DB.
public ViewResult Index()
{
    PostVM viewModel = new PostVM 
                           {
                               ...
                           }

    return View(viewModel);
}

如何将我的(实体)帖子对象列表映射到我的视图模型对象和所有子对象(注释,用户)?

谢谢!

解决方法

你很接近,但对我来说这不是视图模型的正确用法.你有以下几点:

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; }
}

其中PostViewModel和CommentViewModel当然是其各自域实体的相应视图模型.

而不是部分我会使用显示模板:

@model WebUI.ViewModels.DetailPostViewModel

@{
    ViewBag.Title = "Detail";
}

<h2>Detail</h2>

@Html.DisplayFor(x => x.Post)
@Html.DisplayFor(x => x.Comments)

然后你将拥有相应的显示模板(?/ Views / Shared / DisplayTemplates / PostViewModel.cshtml):

@model WebUI.ViewModels.PostViewModel
... some properties of a post

和(?/ Views / Shared / DisplayTemplates / CommentViewModel.cshtml):

@model WebUI.ViewModels.CommentViewModel
@Html.DisplayFor(x => x.Title)
@Html.DisplayFor(x => x.Username)

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

就控制器逻辑而言,我个人喜欢使用AutoMapper来映射域实体和视图模型.

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

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);
}

然后你的视图将强烈输入PostViewModel:

@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)
);

备注:如果在视图模型中以相同的方式命名属性,则不需要两个ForMemeber调用:User和Comments. AutoMapper依赖于标准命名约定,您也可以编写自己的自定义约定策略,以避免单独映射每个成员.然后,您需要的是在定义视图模型时保持一致并遵循惯例.

然后在控制器中:

IEnumerable<Post> posts = ...
IEnumerable<PostVm> postVms = Mapper.Map<IEnumerable<Post>,IEnumerable<PostVM>>(posts);
return View(postVms);

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读