ASP.NET Core 3.x 入门(二)建立 Controller ,使用 Tag Helper

此入门教程是记录下方参考资料视频的学习过程
开发工具:Visual Studio 2019

参考资料:https://www.bilibili.com/video/BV1c441167KQ
API文档:https://docs.microsoft.com/zh-cn/dotnet/api/?view=aspnetcore-3.1

目录

ASP.NET Core 3.x 入门(一)创建项目 和 部署

ASP.NET Core 3.x 入门(二)建立 Controller ,使用 Tag Helper

ASP.NET Core 3.x 入门(三)View Component

ASP.NET Core 3.x 入门(四)Razor Page

ASP.NET Core 3.x 入门(五)SignalR

ASP.NET Core 3.x 入门(六)Blazor

ASP.NET Core 3.x 入门(七)Web API

ASP.NET Core 3.x 入门(八)gRPC - Protocol Buffer

ASP.NET Core 3.x 入门(九)gRPC in ASP.NET Core 3.x

小例子

学这个应该就不是初学者了,所以就没有太多注解和说明了
这次的例子是和基本的全栈教程类似,但是这个例子不使用数据库

  • 主页,查询所有数据
  • 添加页面,添加数据

使用 MVC 相关技术

  1. Controller
  2. Tag Helper
  3. Settings
  4. View Component
  5. Razor Page

Models

项目下新建 Models 文件夹,在该目录中添加 Model
部门:Department.cs
员工:Employee.cs
一个部门有多个员工,是一对多的关系

public class Department
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Location { get; set; }
    public int EmployeeCount { get; set; }
}
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,统计数量

public class CompanySummary
{
    public int EmployeeCount { get; set; }
    public int AverageDepartmentEmployeeCount { get; set; }
}

Service

Service 在 Services 文件夹下建立
IDepartmentService.cs

public interface IDepartmentService
{
    //获取所有部门
    Task<IEnumerable<Department>> GetAll();
    //根据Id获取部门
    Task<Department> GetById(int id);
    //获取公司情况
    Task<CompanySummary> GetCompanySummary();
    //添加部门
    Task Add(Department department);
}

DepartmentService.cs

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

    public DepartmentService()
    {
        this._departments.Add(new Department
        {
            Id = 1,
            Name = "HR",
            EmployeeCount = 16,
            Location = "Beijing"
        });
        this._departments.Add(new Department
        {
            Id = 2,
            Name = "R&D",
            EmployeeCount = 52,
            Location = "Shanghai"
        });
        this._departments.Add(new Department
        {
            Id = 3,
            Name = "Sales",
            EmployeeCount = 200,
            Location = "China"
        });
    }

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

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

    public Task<CompanySummary> GetCompanySummary()
    {
        return Task.Run(() =>
        {
            return new CompanySummary
            {
                EmployeeCount = this._departments.Sum(x => x.EmployeeCount),
                AverageDepartmentEmployeeCount = (int)this._departments.Average(x => x.EmployeeCount)
            };
        });
    }
    public Task Add(Department department)
    {
        department.Id = this._departments.Max(x => x.Id) + 1;
        this._departments.Add(department);
        return Task.CompletedTask;
    }

}

IEmployeeService.cs

public interface IEmployeeService
{
    //添加员工
    Task Add(Employee employee);
    //根据部门Id获取该部门所有员工集合
    Task<IEnumerable<Employee>> GetByDepartmentId(int departmentId);
    //解雇员工
    Task<Employee> Fire(int id);
}

EmployeeService.cs

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

    public EmployeeService()
    {
        this._employees.Add(new Employee
        {
            Id = 1,
            DepartmentId = 1,
            FirstName = "Nick",
            LastName = "Carter",
            Gender = Gender.男
        });
        this._employees.Add(new Employee
        {
            Id = 2,
            DepartmentId = 1,
            FirstName = "Michael",
            LastName = "Jackson",
            Gender = Gender.男
        });
        this._employees.Add(new Employee
        {
            Id = 3,
            DepartmentId = 1,
            FirstName = "Mariah",
            LastName = "Carey",
            Gender = Gender.女
        });
        this._employees.Add(new Employee
        {
            Id = 4,
            DepartmentId = 2,
            FirstName = "Axl",
            LastName = "Rose",
            Gender = Gender.男
        });
        this._employees.Add(new Employee
        {
            Id = 5,
            DepartmentId = 2,
            FirstName = "Kate",
            LastName = "Winslet",
            Gender = Gender.女
        });
        this._employees.Add(new Employee
        {
            Id = 6,
            DepartmentId = 3,
            FirstName = "Rob",
            LastName = "Thomas",
            Gender = Gender.男
        });
        this._employees.Add(new Employee
        {
            Id = 7,
            DepartmentId = 3,
            FirstName = "Avril",
            LastName = "Lavigne",
            Gender = Gender.女
        });
        this._employees.Add(new Employee
        {
            Id = 8,
            DepartmentId = 3,
            FirstName = "Katy",
            LastName = "Perry",
            Gender = Gender.女
        });
        this._employees.Add(new Employee
        {
            Id = 9,
            DepartmentId = 3,
            FirstName = "Michelle",
            LastName = "Monaghan",
            Gender = Gender.女
        });
    }
    public Task Add(Employee employee)
    {
        employee.Id = this._employees.Max(x => x.Id) + 1;
        this._employees.Add(employee);
        return Task.CompletedTask;
    }

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

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

            return null;
        });
    }
}

注册服务

进入 Startup.cs ,ConfigureServices() 中添加

services.AddSingleton<IDepartmentService, DepartmentService>();
services.AddSingleton<IEmployeeService, EmployeeService>();

Controller

Controller 在 Controllers 文件夹下建立
DepartmentController.cs

public class DepartmentController : Controller
{
    private readonly IDepartmentService _departmentService;

    public DepartmentController(IDepartmentService departmentService)
    {
        this._departmentService = departmentService;
    }

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

    //返回添加部门页面和空的Model,通过表单设置Model
    [HttpGet]//默认就是Get,可以不写
    public IActionResult Add()
    {
        ViewBag.Title = "Add Department";
        return View(new Department());
    }

    //添加部门页面提交
    [HttpPost]
    public async Task<IActionResult> Add(Department model)
    {
        if(ModelState.IsValid)
        {
            await this._departmentService.Add(model);
        }
        //使用nameof利于重命名
        return RedirectToAction(nameof(Index));
    }

}

EmployeeController.cs

public class EmployeeController : Controller
{
    private readonly IDepartmentService _departmentService;
    private readonly IEmployeeService _employeeService;

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

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

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

        var employees = await this._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 this._employeeService.Add(model);
        }

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

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

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

View

项目下新建一个 Views 文件夹,视图都放在这个路径
新建视图模板,选择 Razor Layout ,模板都放在 Views/Shared 目录下
_Layout.cshtml

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>@ViewBag.Title</title>
    @* 开发环境加载完整的css *@
    <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="true",不缓存图片 *@
                <img asp-append-version="true" alt="Logo" src="~/images/logo.png" style="height60px;" />
            </div>
            <div class="col-md-10">
                <span class="h2">@ViewBag.Title</span>
            </div>
        </div>
        <div class="row">
            <div class="col-md-12">
                @RenderBody()
            </div>
        </div>
    </div>
</body>
</html>

让 _Layout 页面作为其它所有页面默认的母页面
Views 目录下新建 Razor View Start
_ViewStart.cshtml

@{
    Layout = "_Layout";
}

asp-append-version="true" 就是一个 Tag Helper

启用 Tag Helper

Views 文件夹下新建 Razor View Imports
_ViewImports.cshtml,这里写的代码会添加到所有 View 里

@addTagHelper "*,Microsoft.AspNetCore.Mvc.TagHelpers"

如果不想添加全局 Tag Helper 可以在对应的 View 里写
也可以创建自己的 Tag Helper ,创建一个类,继承 TagHelpers

具体视图

Views 目录下新建与控制器名一致的文件夹
在对应的文件夹下新建 Razor View ,视图名称对应控制器中的方法名称

建立列表和表单 View

Views/Department/Index.cshtml

@using My_ASP_NET_Core_Program.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>

@Html.DisplayForModel() 是一个模板,在 Views/控制器 目录下新建 DisplayTemplates 目录
再新建 Razor View Department.cshtml

@model My_ASP_NET_Core_Program.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/Employee/Index.cshtml

@using My_ASP_NET_Core_Program.Models
@model IEnumerable<Department>

<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">Add</a>
    </div>
</div>

Views/DisplayTemplates/Employee.cshtml

@model My_ASP_NET_Core_Program.Models.Employee

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

    <td>
        @if (!Model.Fired)
        {
            //EmpolyeeController 的 Fire(int employeeId) 方法
            <a asp-action="Fire" asp-route-employeeId="@Model.Id">
                Fire
            </a>
        }
    </td>
</tr>

效果图

Add 视图

Views/Department/Add.cshtml

@using My_ASP_NET_Core_Program.Models
@model Department

<form asp-action="Add">
    <div class="row form-group">
        <div class="col-md-2 offset-md-2">
            @* asp-for 的作用是将 Model 中使用 [Display(Name = "XX)] 的属性,在 label 中显示为 XX *@
            <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-1-md-2">
            <button type="submit" class="btn btn-primary">Add</button>
        </div>
    </div>

</form>

效果图

添加后

Views/Employees/Index.cshtml

@using My_ASP_NET_Core_Program.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">
        @* 这里的 DepartmentId 是 EmployeeController 的 Index() 传入的 *@
        <a asp-action="Add" asp-route-departmentId="@ViewBag.DepartmentId">Add</a>
    </div>
</div>

Views/Employees/Add.cshtml

@using My_ASP_NET_Core_Program.Models
@model Employee

<form asp-action="Add">
    @* 这里的 DepartmentId 在 Get 的 Add(int departmentId) 时就已经赋值,但是 Post 的 Add(Employee model) 还需要 DepartmentId *@
    <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">
                <input class="form-control" asp-for="Gender" />
            </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-1-md-2">
            <button type="submit" class="btn btn-primary">Add</button>
        </div>
    </div>

</form>

效果图

添加后

配置信息

ASP.NET Core 的配置信息

  1. 配置信息以 Key-Value 键值对的形式存在
  2. 配置信息可以从内存里、JSON、XML、INI等文件读取,或者系统环境变量
  3. 配置信息与配置系统是解耦的
  4. 具体使用,可以依赖注入

ASP.NET Core 的配置信息源

按顺序读取配置信息,相同的键将覆盖

  1. appsettings.json
    appsettings.{Environment}.json
    appsettings.Development.json
  2. Secret Manager
  3. 环境变量
  4. 命令行参数

如何使用?

appsettings.json 添加一个对象

"My_ASP_NET_Core_Program": {
//部门人数大于 30 就加粗
"BoldDepartmentEmployeeCountThreshold": 30
}

Startup.cs 添加以下代码

private readonly IConfiguration _configuration;

public Startup(IConfiguration configuration)
{
    this._configuration = configuration;
    //读取的数据类型的是字符串
    //字符串无法表达JSON对象,所以要使用冒号
    var myValue = this._configuration["My_ASP_NET_Core_Program:BoldDepartmentEmployeeCountThreshold"];
}

因为 C# 是强类型语言,所以尽量使用强类型

所以我们创建一个类,属性名要与 JSON 配置对应
项目目录下新建一个类

public class My_ASP_NET_Core_ProgramOptions
{
    public int BoldDepartmentEmployeeCountThreshold { get; set; }
}

注入

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<My_ASP_NET_Core_ProgramOptions>(this._configuration.GetSection("My_ASP_NET_Core_Program"));
}

若想在控制器中注入

private readonly IOptions<My_ASP_NET_Core_ProgramOptions> _myOptions;
public HomeController(IOptions<My_ASP_NET_Core_ProgramOptions> myOptions)
{
    this._myOptions = myOptions;
}

若想在 Razor View 中使用

@using Microsoft.Extensions.Options
@using My_ASP_NET_Core_Program

@inject IOptions<My_ASP_NET_Core_ProgramOptions> options
@* inject 是依赖注入 *@

例子

Views/Department/DisplayTemplates/Department.cshtml

@using Microsoft.Extensions.Options
@using My_ASP_NET_Core_Program

@model My_ASP_NET_Core_Program.Models.Department
@inject IOptions<My_ASP_NET_Core_ProgramOptions> options

<tr>
    @* 如果部门人数大于 30 就加粗 *@
    @if (Model.EmployeeCount > options.Value.BoldDepartmentEmployeeCountThreshold)
    {
        <td><strong>@Model.Name</strong></td>
    }
    else
    {
        <td>@Model.Name</td>
    }

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

    <td>
        @* EmployeeController 的 Index(int departmentId) 方法*@
        @* asp-route- 指定方法参数 *@
        <a asp-controller="Employee" asp-action="Index" asp-route-departmentId="@Model.Id">
            Employees
        </a>
    </td>
</tr>

效果图

补充

若不想使用 appsetting.json 作为配置源
需要在 Program.cs 中配置

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
    .ConfigureAppConfiguration((context, configuBuilder) =>
    {
        //不想使用 appsettings.json ,需要先清理掉所有源或者指定源
        configuBuilder.Sources.Clear();
        //使用另外一个 JSON 文件
        configuBuilder.AddJsonFile("myJSON.json");
    })
    .ConfigureWebHostDefaults(webBuilder =>
    {
        webBuilder.UseStartup<Startup>();
    });

ASP.NET Core 3.x 入门(二)建立 Controller ,使用 Tag Helper 结束

posted @ 2021-05-13 20:02  .NET好耶  阅读(524)  评论(0编辑  收藏  举报