ASP NET CORE MVC - правильный способ передачи данных из представления в контроллер? - PullRequest
0 голосов
/ 22 января 2019

Я изучаю ASP Net Core 2.2 MVC. Я прочитал несколько статей, касающихся передачи данных с контроллера для просмотра и наоборот. В какой-то момент я хотел передать более 1 модели для представления.

Тогда я понял, что не могу и должен использовать то, что называется 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">&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, потому что это не очень хорошая практика, чтобы обойти доменные модели. Теперь моя функция работает отлично, но в данном случае я передаю View Model, как storeCategory(InfoViewModel infoViewModel), не будут ли другие свойства id, title, property, categories избыточными? Потому что все, что мне нужно для этой функции - это объект категории.

Пожалуйста, объясни мне все эти образцы и условные обозначения.

Спасибо.

1 Ответ

0 голосов
/ 22 января 2019

Это вопрос самоуверенный, так что вот мой самоуверенный ответ.

Вы должны следовать этим принципам и соглашениям, если:

  1. Проект, который вы строите, предназначен для вашей собственной практики.(Практика передовой практики h3h3)
  2. Проект, который вы создаете, будет поддерживаться кем-то другим.(Проект будет проще поддерживать в будущем)
  3. Проект масштабный.(Структура будет чище, проще в обслуживании)

Вам не стоит беспокоиться об этом, если:

  1. Это одноразовый проект.(Вы быстро разберетесь с ним, используйте его немного и выбросите, в этом случае вы цените время выше всего остального)

Теперь, чтобы конкретно ответить на ваш случай отображения модели предметной области вПосмотреть.Почему это плохо?

При работе с объектами важно знать их место в программе (где я могу разместить свой код?).Почему бы просто не создать один объект со 100 полями и просто использовать его в каждом представлении / методе, потому что вы забудете, каков контекст методов и для чего они предназначены и какие поля принадлежат где.Помимо того, что у нас есть объект типа DataModel.cs, мы знаем модель данных, но что она представляет?каков контекст?о чем эта программа?Так что теперь вы можете назвать BlogPost.cs, чтобы внести ясность.

Единая ответственность является ключевой, объект / класс / функция отвечает только за 1 вещь и только 1 вещь.

  • BlogPost - Сообщение в блоге DTO.
  • BlogPostViewModel - Данные, которые мы хотели бы показать пользователям.
  • BlogPostInputModel - Данные, которые мы хотели бы захватить, чтобы создать этоПост в блоге.
  • CreateBlogPost(BlogPostInputModel im) - Создать BlogPost из BlogPostInputModel
  • SaveBlogPost(BlogPost bp) - Сохранить BlogPost в базе данных.

Надеюсь, вы понимаете, что эта дополнительная работа выполняется для создания самодокументируемого кода.

Если вам нужно отобразить BlogPostViewModel, но захватить только BlogPostInputModel, хорошо, что BlogPostViewModel имеет некоторые свойства, которые BlogPostInputModel, потому что они нужны нам для представления.

Обновление, дополнительные объяснения:

CreateBlogPost (BlogPostInputModel im) - Это чистая функция, которая принимает и вводит A и выплевывает B, чистая означает, что нет никаких побочных эффектов и не зависит от состояния.Итак, говоря, что если функция зависит от состояния, например, от времени, то если мы предоставим A, она может выплеснуть C или F в зависимости от того, какое сейчас время.Таким образом, его проще тестировать, и он всегда возвращает действительный BlogPost.

SaveBlogPost (BlogPost bp) - это функция с побочным эффектом: запись в базу данных.Он просто использует действительный BlogPost и сохраняет его в базе данных.Такая функция будет в вашем репозитории, по сути, все управление вашим состоянием содержится в объекте репозитория.

Если мы сохраним BlogPost в базе данных внутри CreateBlogPost, если мы напишем тест, то потребуетсядля заполнения, а затем отменить изменения в базе данных для каждого теста.Это проблематично.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...