ASP.NET Core 3.x 学习笔记(2)——一个简单的 MVC 项目学习

ASP.NET Core 3.x 学习笔记(2)——一个简单的 MVC 项目学习

本系列学习笔记均来源于B站UP主”软件工艺师“的学习视频,学习连接如下:

https://www.bilibili.com/video/BV1c441167KQ

MVC 相关技术

  • Controller

  • Tag Helper

  • Settings

  • View Component

  • Razor Page(不属于MVC,是微软发布的用于 Web 页面开发的一种标记语法

模型-视图-控制器 (MVC) 体系结构模式将应用程序分成 3 个主要组件组:模型、视图和控制器。 此模式有助于实现关注点分离。 使用此模式,用户请求被路由到控制器,后者负责使用模型来执行用户操作和/或检索查询结果。 控制器选择要显示给用户的视图,并为其提供所需的任何模型数据。

下图显示 3 个主要组件及其相互引用关系:

MVC 模式

视图和控制器均依赖于模型。 但是,模型既不依赖于视图,也不依赖于控制器。 这是分离的一个关键优势。 这种分离允许模型独立于可视化展示进行构建和测试。

模型责任:MVC 应用程序的模型 (M) 表示应用程序和任何应由其执行的业务逻辑或操作的状态。 业务逻辑应与保持应用程序状态的任何实现逻辑一起封装在模型中。 强类型视图通常使用 ViewModel 类型,旨在包含要在该视图上显示的数据。 控制器从模型创建并填充 ViewModel 实例。

视图责任:视图 (V) 负责通过用户界面展示内容。 它们使用 Razor 视图引擎在 HTML 标记中嵌入 .net 代码。

控制器责任:控制器 © 是处理用户交互、使用模型并最终选择要呈现的视图的组件。在 MVC 应用程序中,视图仅显示信息;控制器处理并响应用户输入和交互。 在 MVC 模式中,控制器是初始入口点,负责选择要使用的模型类型和要呈现的视图。

注意点:

  • 控制器不应由于责任过多而变得过于复杂。 要阻止控制器逻辑变得过于复杂,请将业务逻辑推出控制器并推入域模型。
  • 如果发现控制器操作经常执行相同类型的操作,可将这些常见操作移入筛选器

本博客内容主要关于一个简单的部门职员管理的 MVC 项目,在本例代码中,M 为下文的 Models + Services,V 为下文的 Views,C 为下文的 Controllers。该项目非常简单入门,仅呈现了 MVC 的相关结构。代码如下:

Models

Department.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace ASPNETCore_Learning_Three.Models
{
    public class Department
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Location { get; set; }
        public int EmployeeCount { get; set; }

    }
}

Employee.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace ASPNETCore_Learning_Three.Models
{
    public class Employee
    {
        public int Id { get; set; }
        public int DepartmentId { get; set; }

        public string FirstName { get; set; }
        public string LastName { get; set; }
        public Gender Gender { get; set; }
        public bool Fired { get; set; }
    }

    public enum Gender
    {=0,=1
    }
}

CompanySummary.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace ASPNETCore_Learning_Three.Models
{
    public class CompanySummary
    {
        public int EmployeeCount { get; set; }
        public int AverageDepartmentEmployeeCount { get; set; }

    }
}

Services

IDepartmentService.cs

using ASPNETCore_Learning_Three.Models;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace ASPNETCore_Learning_Three.Services
{
    public interface IDepartmentService
    {
        Task<IEnumerable<Department>> GetAll();
        Task<Department> GetById(int Id);
        Task<CompanySummary> GetCompanySummary();
        Task Add(Department department);
    }
}

DepartmentService.cs

using ASPNETCore_Learning_Three.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;

namespace ASPNETCore_Learning_Three.Services
{
    public class DepartmentService : IDepartmentService
    {
        private readonly List<Department> _departments = new List<Department>();

        public DepartmentService()
        {
            _departments.Add(new Department
            {
                Id = 1,
                Name = "IT",
                EmployeeCount = 16,
                Location = "xiangzhou"
            });
            _departments.Add(new Department
            {
                Id = 2,
                Name = "HR",
                EmployeeCount = 20,
                Location = "xiangzhou"
            });
            _departments.Add(new Department
            {
                Id = 3,
                Name = "LY",
                EmployeeCount = 20,
                Location = "jida"
            });

        }

        public Task Add(Department department)
        {
            department.Id = _departments.Max(x => x.Id) + 1;
            _departments.Add(department);
            return Task.CompletedTask;
        }

        public Task<IEnumerable<Department>> GetAll()
        {
            return Task.Run(() => _departments.AsEnumerable());
        }

        public Task<Department> GetById(int Id)
        {
            return Task.Run(() => _departments.FirstOrDefault(x => x.Id == Id));
        }

        public Task<CompanySummary> GetCompanySummary()
        {
            return Task.Run(() =>
            {
                return new CompanySummary
                {
                    EmployeeCount = _departments.Sum(x => x.EmployeeCount),
                    AverageDepartmentEmployeeCount = (int)_departments.Average(x => x.EmployeeCount)
                };
            });
        }
    }
}

IEmployeeService.cs

using ASPNETCore_Learning_Three.Models;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace ASPNETCore_Learning_Three.Services
{
    public interface IEmployeeService
    {
        Task Add(Employee employee);
        Task<IEnumerable<Employee>> GetByDepartmentId(int DepartmentId);
        Task<Employee> Fire(int id);
    }
}

EmployeeService.cs

using ASPNETCore_Learning_Three.Models;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace ASPNETCore_Learning_Three.Services
{
    public class EmployeeService : IEmployeeService
    {
        private readonly List<Employee> _employees = new List<Employee>();

        public EmployeeService()
        {
            _employees.Add(new Employee
            {
                Id = 1,
                DepartmentId = 1,
                FirstName = "Nick",
                LastName = "Carter",
                Gender = Gender.});
            _employees.Add(new Employee
            {
                Id = 2,
                DepartmentId = 1,
                FirstName = "Michal",
                LastName = "Jackson",
                Gender = Gender.});
            _employees.Add(new Employee
            {
                Id = 3,
                DepartmentId = 1,
                FirstName = "Mariah",
                LastName = "Carey",
                Gender = Gender.});
            _employees.Add(new Employee
            {
                Id = 4,
                DepartmentId = 2,
                FirstName = "Axl",
                LastName = "Rose",
                Gender = Gender.});
            _employees.Add(new Employee
            {
                Id = 5,
                DepartmentId = 2,
                FirstName = "Kate",
                LastName = "Winslet",
                Gender = Gender.});
            _employees.Add(new Employee
            {
                Id = 6,
                DepartmentId = 3,
                FirstName = "Aril",
                LastName = "Lavigne",
                Gender = Gender.});
            _employees.Add(new Employee
            {
                Id = 7,
                DepartmentId = 3,
                FirstName = "Machill",
                LastName = "Jonh",
                Gender = Gender.});
        }

        public Task Add(Employee employee)
        {
            employee.Id = _employees.Max(x => x.Id) + 1;
            _employees.Add(employee);
            return Task.CompletedTask;
        }

        public Task<Employee> Fire(int id)
        {
            return Task.Run(() =>
            {
                var employee = _employees.FirstOrDefault(x => x.Id == id);
                if (employee != null)
                {
                    employee.Fired = true;
                    return employee;
                }
                return null;
            });
        }

        public Task<IEnumerable<Employee>> GetByDepartmentId(int DepartmentId)
        {
            return Task.Run(() => _employees.Where(x => x.DepartmentId == DepartmentId));
        }
    }
}

Controllers

DepartmentController.cs

using ASPNETCore_Learning_Three.Models;
using ASPNETCore_Learning_Three.Services;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;

namespace ASPNETCore_Learning_Three.Controllers
{
    public class DepartmentController : Controller
    {
        private readonly IDepartmentService _departmentService;
        public DepartmentController(IDepartmentService departmentService) 
        {
            _departmentService = departmentService;
        }

        public async Task<IActionResult> Index()
        {
            ViewBag.Title = "Department Index";
            var departments = await _departmentService.GetAll();
            return View(departments);
        }

        //[HttpGet] //默认为 HttpGet,可以省略
        public IActionResult Add()
        {
            ViewBag.Title = "Add Index";
            return View(new Department());
        }

        [HttpPost]
        public async Task<IActionResult> Add(Department model)
        {
            if (ModelState.IsValid)
            {
                await _departmentService.Add(model);
            }
            return RedirectToAction(nameof(Index));  //这里可以直接使用字符串,但是用 nameof 比较利于重命名
        }
    }
}

EmployeeController.cs

using ASPNETCore_Learning_Three.Models;
using ASPNETCore_Learning_Three.Services;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace ASPNETCore_Learning_Three.Controllers
{
    public class EmployeeController : Controller
    {
        private readonly IDepartmentService _departmentService;
        private readonly IEmployeeService _employeeService;

        public EmployeeController(IDepartmentService departmentService, IEmployeeService employeeService)
        {
            _departmentService = departmentService;
            _employeeService = employeeService;
        }

        public async Task<IActionResult> Index(int departmentId)
        {
            var department = await _departmentService.GetById(departmentId);

            ViewBag.Title = $"Employee of {department.Name}";
            ViewBag.DepartmentId = departmentId;

            var employees = await _employeeService.GetByDepartmentId(departmentId);

            return View(employees);
        }

        public IActionResult Add(int departmentId)
        {
            ViewBag.Title = "Add Employee";
            return View(new Employee
            {
                DepartmentId = departmentId
            });
        }

        [HttpPost]
        public async Task<IActionResult> Add(Employee model)
        {
            if (ModelState.IsValid)
            {
                await _employeeService.Add(model);
            }

            return RedirectToAction(nameof(Index), new { departmentId = model.DepartmentId });
        }

        public async Task<IActionResult> Fire(int employeeId)
        {
            var employee = await _employeeService.Fire(employeeId);

            return RedirectToAction(nameof(Index), new { departmentId = employee.DepartmentId });
        }
    }
}

Views

这里的 View 使用 Razor Pages。View 的结构如下:
在这里插入图片描述

在 MVC 的开发中,有以下几个固定作用的页面。

Views/_ViewStart.cshtml 文件:视图开始页。Views/_ViewStart.cshtml 文件将 Views/Shared/_Layout.cshtml 文件引入到每个视图中 。 可以使用 Layout 属性设置不同的布局视图,或将它设置为 null,这样将不会使用任何布局文件。

@{
    //设置:针对所有页面,其母版页为 _Layout
    Layout = "_Layout";
}

Views/_ViewImports.cshtml 文件:视图导入页。用于导入 Views 编写过程中需要使用的资源。如下导入 TagHelper:

@*全局取用TagHelper,不想全局取用的话可以将其添加的具体的View中*@
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

Views/Shared/_Layout.cshtml 文件:布局视图,即母版页。该视图防止于 Shared 文件夹下,用户设置页面布局。与上文 _ViewStart 视图联合使用。

其中,形似 asp-append-version 的语法为 TagHelper。

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>@ViewBag.Title</title>

    @*设置开发环境,当环境为 Development,加载以下资源*@
    <environment include="Development">
        <link rel="stylesheet" asp-href-include="css/*" asp-href-exclude="css/all.min.css" />
    </environment>

    <environment exclude="Development">
        <link rel="stylesheet" asp-href-include="css/all.min.css" />
    </environment>

</head>
<body>
    <div class="container">
        <div class="row">
            <div class="col-md-2">
                @*此处类似于 asp-append-version 就是 TagHelper*@
                @*asp-append-version 作用于 img 防止图片缓存*@
                <img asp-append-version="true" alt="Logo" src="~/images/log.jpg" style="height:60px" />
            </div>
            <div class="col-md-10">
                <span class="h2">@ViewBag.Title</span>
            </div>
        </div>
        <div class="row">
            <div class="col-md-2">
                @RenderBody()
            </div>
        </div>
    </div>
</body>
</html>

Department

Views/Department/Index.cshtml:Department 的主页。本项目中,在 ASP.NET Core 3.x 学习笔记(一)中将其设置为项目启动的默认路由,即 DepartmentController 中的 Index路由。

@using ASPNETCore_Learning_Three.Models
@model IEnumerable<Department>

<div class="row">
    <div class="col-md-10 offset-md-2">
        <table class="table">
            <tr>
                <th>Name</th>
                <th>Location</th>
                <th>Employee</th>
                <th>操作</th>
            </tr>
            @Html.DisplayForModel()
        </table>
    </div>
</div>
<div class="row">
    <div class="col-md-4 offset-md-2">
        <a asp-action="Add">Add</a>
    </div>
</div>

Views/Department/DisplayTemplates/Department.cshtml:Department 的数据展示视图。

  • 视图与 Index.cshtml 中的 @Html.DisplayForModel() 关联,展示具体数据;
  • asp-controller 关联到控制器 EmployeeController;
  • asp-action 关联到控制器 DepartmentController 中的 Index 路由;
  • asp-route-departmentId 绑定此路由需要传递的参数 departmentId 为 @Model.Id(即选中的 Department 的 Id)

在此视图中,操作 Employees 连接,即可跳转查看对应 Department 下的所有 Employee 信息。

@model ASPNETCore_Learning_Three.Models.Department

<tr>
    <td>@Model.Name</td>
    <td>@Model.Location</td>
    <td>@Model.EmployeeCount</td>

    <td>
        <a asp-controller="Employee" asp-action="Index" asp-route-departmentId="@Model.Id">
            Employees
        </a>
    </td>
</tr>

在这里插入图片描述

Views/Department/Add.cshtml:用于添加 Department 的表单视图,关联到 DepartmentController 下的 Add 路由。

@using ASPNETCore_Learning_Three.Models
@model Department

<form asp-action="Add">
    <div class="row form-group">
        <div class="col-md-2 offset-md-2">
            <label asp-for="Name"></label>
        </div>
        <div class="col-md-6">
            <input class="form-control" asp-for="Name" />
        </div>
    </div>
    <div class="row form-group">
        <div class="col-md-2 offset-md-2">
            <label asp-for="Location"></label>
        </div>
        <div class="col-md-6">
            <input class="form-control" asp-for="Location" />
        </div>
    </div>
    <div class="row form-group">
        <div class="col-md-2 offset-md-2">
            <label asp-for="EmployeeCount"></label>
        </div>
        <div class="col-md-6">
            <input class="form-control" asp-for="EmployeeCount" />
        </div>
    </div>
    <div class="row">
        <div class="col-md-2 offset-md-2">
            <button type="submit" class="btn btn-primary">Add</button>
        </div>
    </div>
</form> 

在这里插入图片描述

Employee

Views/Department/Index.cshtml:Employee 的主页,关联到控制器 EmployeeController 中的 Index 路由。

代码中的 Add 连接,因为要在到对应 Deparment 下添加 Employee,故需要传递参数 DepartmentId。

@using ASPNETCore_Learning_Three.Models
@model IEnumerable<Employee>

<div class="row">
    <div class="col-md-10 offset-md-2">
        <table class="table">
            <tr>
                <th>First Name</th>
                <th>Last Name</th>
                <th>Gender</th>
                <th>Is Fired</th>
                <th>操作</th>
            </tr>
            @Html.DisplayForModel()
        </table>
    </div>
</div>
<div class="row">
    <div class="col-md-4 offset-md-2">
        <a asp-action="Add" asp-route-departmentID="@ViewBag.DepartmentId">Add</a>
    </div>
</div>

Views/Department/DisplayTemplates/Employee.cshtml:Employee 的数据视图。

@model ASPNETCore_Learning_Three.Models.Employee

<tr>
    <td>@Model.FirstName</td>
    <td>@Model.LastName</td>
    <td>@Model.Gender</td>
    <td>@(Model.Fired ? "是" : "")</td>

    <td>
        @if (!Model.Fired)
        {
            <a asp-action="Fire" asp-route-employeeId="@Model.Id">
                Fire
            </a>
        ![在这里插入图片描述](https://img-blog.csdnimg.cn/20201121184550940.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1NRV0hfU1NHUw==,size_16,color_FFFFFF,t_70#pic_center)
}
    </td>
</tr>

Views/Department/Add.cshtml:Employee 的新增表单视图。

此处使用 input 接收了参数 DepartmentId,但该参数并不需要在页面显式,故隐藏。

@using ASPNETCore_Learning_Three.Models
@model Employee

<form asp-action="Add">
    <input type="hidden" asp-for="DepartmentId"/>

    <div class="row form-group">
        <div class="col-md-2 offset-md-2">
            <label asp-for="FirstName"></label>
        </div>
        <div class="col-md-6">
            <input class="form-control" asp-for="FirstName" />
        </div>
    </div>
    <div class="row form-group">
        <div class="col-md-2 offset-md-2">
            <label asp-for="LastName"></label>
        </div>
        <div class="col-md-6">
            <input class="form-control" asp-for="LastName" />
        </div>
    </div>
    <div class="row form-group">
        <div class="col-md-2 offset-md-2">
            <label asp-for="Gender"></label>
        </div>
        <div class="col-md-6">
            <select class="form-control"
                    asp-for="Gender"
                    asp-items="Html.GetEnumSelectList<Gender>()">
            </select>
        </div>
    </div>
    <div class="row">
        <div class="col-md-2 offset-md-2">
            <button type="submit" class="btn btn-primary">Add</button>
        </div>
    </div>
</form> 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值