ASP NET CORE MVC-将数据从视图传递到控制器的正确方法?

时间:2019-01-22 11:49:35

标签: asp.net-core asp.net-core-mvc

我正在学习ASP Net Core 2.2 MVC。我已经阅读了几篇有关将数据从控制器传递到视图(反之亦然)的文章。有一次我想将多个模型传递给视图。

然后我意识到我不能,必须使用所谓的View Model。我想到了这个:

我的Domain Models

Blog.cs:

博客可以具有许多类别,其他所有属性都是常用的titlebody等。

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:

它显示博客的titlebody及其类别。我还可以添加一个类别(在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">&times;</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会不会是多余的?因为我只需要一个功能即可。

请启发我使用的所有这些模式和约定。

谢谢。

1 个答案:

答案 0 :(得分:1)

这是一个自以为是的问题,所以这是我自以为是的答案。

在以下情况下,您应遵循以下原则和约定:

  1. 您正在构建的项目是您自己的实践的。 (练习h3h3的良好做法)
  2. 您正在制作的项目将由其他人维护。 (该项目将来将更易于维护)
  3. 该项目规模巨大。 (结构将更清洁,更易于维护)

在以下情况下,您不必担心这种事情:

  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内部的数据库中,那么如果我们编写测试,则需要为每个测试播种然后恢复数据库中的更改。这是有问题的。