我现在有几次学习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);
}
Run Code Online (Sandbox Code Playgroud)
所以在这里,我将看到一个由两件事组成的视图模型:
视图模型将传递给视图以跟随视图模型模式.
在我的详细视图中:
@model WebUI.ViewModels.DetailPostViewModel
@{
ViewBag.Title = "Detail";
}
<h2>Detail</h2>
@Html.Partial("_DetailPost", Model.Post)
@Html.Partial("_Comments", Model.Comments)
Run Code Online (Sandbox Code Playgroud)
所以在这里,我使用了我的DetailPostViewModel.对于我的部分观点,我传递了必要的信息,即实体!?我不知道这是正确的方式,还是我必须在这里通过视图模型呢?
在我的_DetailPost视图中:
@model Domain.Entities.Post
@Html.DisplayForModel()
...
Run Code Online (Sandbox Code Playgroud)
所以在我的部分视图中,我使用en实体作为模型.是好还是坏?
在我的_Comments视图中:
@model IEnumerable<Domain.Entities.Comment>
@foreach (var item in Model)
{
@Html.DisplayFor(Model => item.Title)
@Html.DisplayFor(Model => item.Username)
}
Run Code Online (Sandbox Code Playgroud)
所以在我的部分视图中,我使用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; }
...
}
Run Code Online (Sandbox Code Playgroud)
以下是视图模型:
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; }
...
}
Run Code Online (Sandbox Code Playgroud)
这是我的控制器:
// I would like to list all posts in the DB.
public ViewResult Index()
{
PostVM viewModel = new PostVM
{
...
}
return View(viewModel);
}
Run Code Online (Sandbox Code Playgroud)
如何将我的(实体)帖子对象列表映射到我的视图模型对象和所有子对象(注释,用户)?
谢谢!
你很接近,但对我来说这不是视图模型的正确用法.你有以下几点:
public class DetailPostViewModel
{
public Post Post { get; set; }
public IEnumerable<Comment> Comments { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
这是某种混合伪视图模型.真实视图模型不应该引用任何域模型.
一个更正确的例子如下:
public class DetailPostViewModel
{
public PostViewModel Post { get; set; }
public IEnumerable<CommentViewModel> Comments { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
其中PostViewModel和CommentViewModel当然是各自域实体的相应视图模型.
而不是部分我会使用显示模板:
@model WebUI.ViewModels.DetailPostViewModel
@{
ViewBag.Title = "Detail";
}
<h2>Detail</h2>
@Html.DisplayFor(x => x.Post)
@Html.DisplayFor(x => x.Comments)
Run Code Online (Sandbox Code Playgroud)
然后你将拥有相应的显示模板(~/Views/Shared/DisplayTemplates/PostViewModel.cshtml
):
@model WebUI.ViewModels.PostViewModel
... some properties of a post
Run Code Online (Sandbox Code Playgroud)
和(~/Views/Shared/DisplayTemplates/CommentViewModel.cshtml
):
@model WebUI.ViewModels.CommentViewModel
@Html.DisplayFor(x => x.Title)
@Html.DisplayFor(x => x.Username)
Run Code Online (Sandbox Code Playgroud)
显然,由于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);
}
Run Code Online (Sandbox Code Playgroud)
甚至更好:
public class PostViewModel
{
... some properties of a Post
public IEnumerable<CommentViewModel> Comments { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
然后:
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);
}
Run Code Online (Sandbox Code Playgroud)
然后你的视图将强烈输入PostViewModel:
@model WebUI.ViewModels.PostViewModel
@{
ViewBag.Title = "Detail";
}
<h2>Detail</h2>
... some properties of a post
@Html.DisplayFor(x => x.Comments)
Run Code Online (Sandbox Code Playgroud)
根据评论部分的要求,域模型和视图模型之间的映射如下所示:
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)
);
Run Code Online (Sandbox Code Playgroud)
备注:ForMemeber
如果在视图模型中以相同的方式命名属性,则不需要进行两次调用:User
和Comments
.AutoMapper依赖于标准命名约定,您也可以编写自己的自定义约定策略,以避免单独映射每个成员.然后,您需要的是在定义视图模型时保持一致并遵循惯例.
然后在控制器中:
IEnumerable<Post> posts = ...
IEnumerable<PostVm> postVms = Mapper.Map<IEnumerable<Post>, IEnumerable<PostVM>>(posts);
return View(postVms);
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1538 次 |
最近记录: |