我正在学习ASP Net Core 2.2 MVC。我已经阅读了几篇有关将数据从控制器传递到视图(反之亦然)的文章。有一次我想将多个模型传递给视图。
然后我意识到我不能,必须使用所谓的View Model
。我想到了这个:
我的Domain Models
:
Blog.cs:
博客可以具有许多类别,其他所有属性都是常用的title
,body
等。
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Blogspot.Datas.Models
{
public class Blog
{
[Key]
public int id { get; set; }
[Required]
[DataType(DataType.Text)]
public string title { get; set; }
[Required]
[DataType(DataType.Text)]
public string body { get; set; }
[DataType(DataType.DateTime)]
public DateTime created_at { get; set; }
[Column(TypeName = "boolean")]
public bool comments { get; set; }
public List<Category> categories { get; set; }
}
}
Category.cs:
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Blogspot.Datas.Models
{
public class Category
{
[Key]
public int id { get; set; }
[Required]
public string title { get; set; }
public int blog_id { get; set; }
[ForeignKey("blog_id")]
public Blog blog { get; set; }
}
}
在我的一种观点-Info.cshtml
中,我想显示一个blog
及其categories
。
InfoViewModel.cs:
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Blogspot.Datas.Models;
namespace Blogspot.Datas.Models.Pages
{
public class InfoViewModel
{
public InfoViewModel()
{
this.categories = new List<Category>();
this.category = new Category();
}
public int id { get; set; }
[Required]
public string title { get; set; }
[Required]
public string body { get; set; }
[Required]
public Category category { get; set; }
public List<Category> categories { get; set; }
}
}
Info.cshtml:
它显示博客的title
和body
及其类别。我还可以添加一个类别(在modal form
中)。
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@model Blogspot.Datas.Models.Pages.InfoViewModel
<section class="infos">
<form action="#">
<input type="hidden" asp-for="@Model.id">
<div class="form-group">
<label for="title">Title</label>
<input class="form-control" type="text" asp-for="@Model.title">
</div>
<div class="form-group">
<label for="body">Body</label>
<input class="form-control" type="text" asp-for="@Model.body">
</div>
</form>
<div class="categories">
<h3>Categories
<button type="button" style="float: right" class="btn btn-primary add-category">Add category</button>
</h3>
@foreach (var c in @Model.categories)
{
<div class="cat">
<p>@c.title</p>
<form asp-route="deleteCategory" asp-route-id="@c.id">
<button type="submit" class="btn btn-danger">Delete</button>
</form>
<hr>
</div>
}
</div>
</section>
<div class="modal fade category" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Modal title</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<form asp-route="storeCategory" method="post" asp-anti-forgery="true">
<div class="form-group">
<label asp-for="@Model.category.title">Title</label>
<input class="form-control" type="text" asp-for="@Model.category.title">
<span class="text-danger" asp-validation-for="@Model.category.title"></span>
</div>
<input type="hidden" asp-for="@Model.category.blog_id" value="@Model.id">
<input type="submit" value="Save category" class="btn btn-success">
</form>
</div>
</div>
</div>
</div>
现在让我想到的是将参数传递到POST store function
的正确方法是什么?
[HttpPost("categories", Name="storeCategory")]
[ExportModelState]
public async Task<IActionResult> storeCategory(Category category)
{
if (ModelState.IsValid)
{
await _context.category.AddAsync(category);
await _context.SaveChangesAsync();
TempData["success"] = true;
TempData["message"] = "Category added succesfully!";
}
return RedirectToRoute("postDetails", new { id = category.blog_id });
}
我所做的是在Category
域模型中传递的。我看到有文章说应该通过View Model
,因为绕过领域模型不是一种好的做法。现在我的函数可以正常运行,但是在实例中我传递了一个视图模型,例如storeCategory(InfoViewModel infoViewModel)
,其他属性id, title, property, categories
会不会是多余的?因为我只需要一个功能即可。
请启发我使用的所有这些模式和约定。
谢谢。
答案 0 :(得分:1)
这是一个自以为是的问题,所以这是我自以为是的答案。
在以下情况下,您应遵循以下原则和约定:
在以下情况下,您不必担心这种事情:
现在专门回答在视图中显示域模型的情况。为什么这是一件坏事?
使用对象时,重要的是要知道它们在程序中的位置(我在哪里放置代码?)。为什么不只创建一个包含100个字段的对象,然后在每个视图/方法中使用它,因为您将忘记方法的上下文,方法的含义以及字段所属的位置。除了拥有像DataModel.cs
这样的对象外,这也是我们所知道的数据模型,但是它代表什么呢?上下文是什么?这个程序是关于什么的?因此,为了清楚起见,您现在可以命名为BlogPost.cs
。
单一责任是关键,一个对象/类/功能仅负责一件事情和一件事情。
BlogPost
-博客文章DTO。BlogPostViewModel
-我们想要显示给用户的数据。BlogPostInputModel
-我们要捕获的数据以创建此Blog帖子。CreateBlogPost(BlogPostInputModel im)
-从BlogPost
创建BlogPostInputModel
SaveBlogPost(BlogPost bp)
-将BlogPost
保存到数据库。 希望您能理解,这项额外的工作已经完成,可以产生自我记录的代码。
如果您需要显示BlogPostViewModel
但仅捕获BlogPostInputModel
,则可以使用BlogPostViewModel
的某些属性,因为我们需要它们作为视图。{p>
更新,进一步的解释:
CreateBlogPost(BlogPostInputModel im)-这是一个纯函数,需要输入A并吐出B,这意味着没有副作用且不受状态的影响。所以说如果一个函数依赖于时间之类的状态(如果我们提供了A),它可能会随时间而吐出C或F。这样一来,测试起来更加容易,并且总是返回有效的BlogPostInputModel
。
SaveBlogPost(BlogPost bp)-此函数具有副作用:写入数据库。它只是消耗一个有效的BlogPost并将其保存到数据库中。这种功能将在您的存储库中,基本上所有的状态管理都包含在一个存储库对象中。
如果我们将BlogPost保存到CreateBlogPost内部的数据库中,那么如果我们编写测试,则需要为每个测试播种然后恢复数据库中的更改。这是有问题的。