添加你的第一个页面

    xiaoxiao2021-03-25  271

    在本章中,我们将一步一步的开发一个列表页面,用于将所有的用户名、性别、生日作为一个表格,显示到页面上。最终的效果如下:

    前期准备

    在动手做之前,我们首先需要在自己电脑上的 ECRS 数据库中执行下面的 SQL 脚本,它会创建我们需要操作的 MyUser 表和两条测试数据,我们后面的文档将一步步实现对这张表进行增改查操作。 我们的最终目标,是通过访问 /MyUser/List 显示所有的用户列表,并可以进行查询操作;通过 /MyUser/Add 可以添加用户;/MyUser/Edit/{id} 可以修改用户。所有的数据库操作都通过 Entity Framework 来完成。

    CREATE TABLE [dbo].[MyUser]( [Id] [int] IDENTITY(1,1) NOT NULL, [Username] [varchar](50) NOT NULL, [Password] [varchar](50) NOT NULL, [Gender] [int] NOT NULL, [Birthday] [datetime] NULL, [last_login_date] [datetime] NULL, [insert_user] [varchar](50) NULL, [insert_date] [datetime] NULL, [update_user] [varchar](50) NULL, [update_date] [datetime] NULL, CONSTRAINT [PK_MyUser] PRIMARY KEY CLUSTERED ( [Id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO INSERT INTO [MyUser](Username, [Password], Gender, Birthday, last_login_date, insert_user, insert_date, update_user, update_date) VALUES ('admin', '123456', 1, '1900-01-23', NULL, NULL, NULL, NULL, NULL), ('zhangsan', '123456', 0, '1988-07-06', NULL, 'admin', '2017-01-24', NULL, NULL)

    上面的脚本会为数据库添加 MyUser 表,它的数据结构如下:

    列名数据类型允许NULL描述Idintfalse唯一标识 IdUsernamevarchar(50)false用户名Passwordvarchar(50)false密码Genderintfalse性别(0:男,1:女)Birthdaydatetimetrue生日last_login_datedatetimetrue上次登陆时间insert_uservarchar(50)true添加该记录的用户名insert_datedatetimetrue添加该记录的时间update_uservarchar(50)true最后一次修改该记录的用户名update_datedatetimetrue最后一次修改该记录的时间

    配置数据库连接

    通过 Visual Studio 打开 KunlunCCM 解决方案,打开 Web 项目中的 Web.config 文件,修改 <connectionStrings> 节点中的内容

    <connectionStrings> <add name="KunlunConnection" connectionString="Data Source=.;Initial Catalog=ECRS_20170124;Persist Security Info=True;User ID=sa;Password=369;" providerName="System.Data.SqlClient" /> </connectionStrings>

    connectionString 即为 连接字符串,程序通过读取 Web.config 中的这个属性来连接数据库。上面的示例通过 sa 用户来连接本地的 ECRS 数据库。

    Data Source数据源,本地为 .,也可以设置为 IP|HostName,Port 的格式Initial Catalog数据库的名称User ID用于连接数据库的用户名Password该用户的密码

    配置好之后,检查一下 Web 项目的名称是否为加粗显示,如果不是,则需要对 Web 项目点击右键,选择“设为启动项目”,然后按下 Ctrl + F5 启动 CCM。如果没有任何错误,应该能看到 CCM 的登陆页面。

    如果 sa 用户无法登陆,请确认你是否启用了 sa 用户。通过 SQL Server Management Studio 以 Windows 身份验证的方式连接本机的数据库服务器,连接好后在服务器名称上点击右键,选择“属性”,在弹出的“服务器属性”窗口中选择“安全性” - “SQL Server 和 Windows 身份验证模式”。

    如果你按下 Ctrl + F5 后没有任何反应,或者没有自动弹出浏览器并显示 CCM 登陆页面,说明你的 Visual Studio 的快捷键和我不同,在 Visual Studio 的菜单栏上点击 调试 - 开始执行(不调试),也能达到同样的效果。如果想知道快捷键,它会显示在“开始执行(不调试)”的后面。如果你想采用和我一样的快捷键,在 Visual Studio 的菜单栏上分别点击 工具 - 选项,在弹出的“选项”窗口中选择 环境 - 键盘,然后将“应用以下其他键盘映射方案”设为“Visual C# 2005”即可。

    创建控制器

    第一步,让我们先做一个列表页面。 在 Web 项目的 Controller 文件夹上点击右键,选择 添加 - 控制器,然后新建一个“MVC5控制器 - 空”,点击“添加”按钮,在这里我们的控制器叫做 MyUserController,控制器就被创建好了。

    根据我们的规范,首先将 MyUserController 的父类由 Controller 改为 BaseController,如果提示找不到这个类,只需要引用 Kunlun.CRS.Web.Framework.Controllers 命名空间即可。BaseController 中封装了一些常用的操作,如重定向到列表页。接着删除默认的 Index() 方法。现在的控制器看起来像这样:

    using Kunlun.CRS.Web.Framework.Controllers; using System.Web.Mvc; namespace Kunlun.CRS.Web.Controllers { public class MyUserController : BaseController { } }

    添加 Action

    依托于路由机制,我们的 URL 不再与服务器上的物理文件路径对应,我们正在制作的列表页面(/MyUser/List),实际上是通过路由,对 MyUserController 的 List() 方法进行调用来返回视图的。所以我们需要先在 MyUserController 中,新建 List() 方法。

    public ActionResult List() { return View(); }

    我们的 /MyUser/List 页面不接收任何参数,所以 List() 方法的参数列表是空的。大家可能会发现 return View() 返回的是 ViewResult,但是 List() 方法的返回类型却是 ActionResult。实际上 ASP.NET MVC 预置了许多返回类型,如视图(ViewResult)、JSON(JsonResult)等等,但它们全部都是派生自 ActionResult 的。

    添加 View

    大家已经知道,当我们访问 /MyUser/List 时,List() 方法会被调用。它会根据约定,到 /Views/MyUser/ 文件夹下,寻找 List.cshtml 文件并将它与 Action 中准备的数据组合在一起,最终变为能在用户的浏览器中显示的页面。 现在我们并没有 List.cshtml,只需在 List Action 上点击右键,选择“添加视图”,然后按照下图配置并点击“添加”按钮,Visual Studio 会自动为我们创建视图页。

    刚创建好的视图页面大致如下:

    @{ ViewBag.Title = "List"; } <h2>List</h2>

    第2行开始的 @{ } 包裹住的代码表示一个代码块,里面可以书写 C# 代码,而第6行则是 HTML 代码。通过 Razor 引擎的支持,我们得以在视图中实现 C# 代码和 HTML 代码的混合编写。现在在视图页的空白处单击右键,选择“在浏览器中查看”。如果弹出登陆页,输入用户名和密码登陆,稍后就会跳转到我们刚刚添加的 List 页面,观察浏览器的地址栏,可以看到 URL 显示为 http://localhost:57811/MyUser/List。

    添加 Service

    因为我们需要操作数据库,对于 List 页面,需要查询出 MyUser 表中的所有用户并呈现到页面上。相信大家没有忘记,业务逻辑需要写在 Service 中,并通过 Controller 来调用,那么让我们来创建 MyUserService 类,一般我们按照表(实体类)的名字来为 Service 命名。在 Services 项目的 Users 文件夹上点击右键,选择 添加-新建项;在左侧的 Visual C# 项中选择“代码”,并选中“类”文件,命名为 MyUserService。

    文件创建好之后,为 MyUserService Class 加上 public 访问修饰符,以公开我们的 Service 类。

    添加实体类和映射

    在为 Service 编写操作数据库的代码之前,我们先要准备实体类,并添加它与数据库的映射。首先让我们来添加实体类,通过 VS 解决方案资源管理器,在 Core 项目的 Domain/Users 文件夹中添加一个名为 MyUser 的类,同样为它加上 public 访问修饰符。 要编写实体类的具体代码,首先需要分析 MyUser 表所有列的数据类型。我们发现有一些类型并不是 C# 的基本类型,例如 varchar,它实际上可以映射到 C# 的 string 类型上。而 Birthday 等列的数据类型是 datetime,同时它又是可以为空的。大家应该知道,C# 的 Datetime 类型是一个值类型,要想使 Datetime 能赋值为 null,需要通过可空类型 Nullable<T> 来实现,可以通过在 DateTime 的类型后面加一个问号来表示。 这个表还有一个特殊情况,根据我们 C# 的命名规范,类属性应该采用 Pascal 命名法,即所有单词的首字母都大写,单词之间不用隔开;而表中 last_login_date 显然违背了这一原则,所以实体类中与这一列关联的属性应该命名为 LastLoginDate。

    最终我们总结出实体类的数据类型如下:

    列名数据库中的数据类型允许NULL实体类属性名对应的 C# 类型IdintfalseIdintUsernamevarchar(50)falseUsernamestringPasswordvarchar(50)falsePasswordstringGenderintfalseGenderintBirthdaydatetimetrueBirthdayDateTime?last_login_datedatetimetrueLastLoginDateDateTime?insert_uservarchar(50)trueInsertUserstringinsert_datedatetimetrueInsertDateDateTime?update_uservarchar(50)trueUpdateUserstringupdate_datedatetimetrueUpdateDateDateTime?

    其中的 InsertUser、InsertDate、UpdateUser 和 UpdateDate 列我们已经统一在 BaseEntity 中定义好了,只需要让我们的 MyUser 继承它即可。那么我们就可以如法炮制 MyUser 实体类了:

    using Kunlun.CRS.Core.Domain.Common; using System; namespace Kunlun.CRS.Core.Domain.Users { public class MyUser : BaseEntity { public int Id { get; set; } public string Username { get; set; } public string Password { get; set; } public int Gender { get; set; } public DateTime? Birthday { get; set; } public DateTime? LastLoginDate { get; set; } } }

    Entity Framework 会根据我们实体类的属性名到数据库中相应表寻找同名的列(忽略大小写),那到现在为止,通过 MyUser 类,Entity Framework 还有几样内容是不知道的:

    MyUser 实体类与哪个表关联LastLoginDate 与表中哪一列关联主、外键约束……

    回顾一下 ORM 的含义:实体-关系-映射,截至目前我们已经将关系(表)、实体(类)创建完成了,对于 Entity Framework 不知道(无法自动处理)的内容,我们就需要编写映射规则来告知 Entity Framework。 我们需要到 Data 项目的 Mapping 文件夹中添加映射规则。我们在这里新建一个名为 MyUserMap 的类,添加 public 访问修饰符,并从 EntityTypeConfiguration<MyUser> 进行派生。EntityTypeConfiguration<T> 泛型类中的 T 表示的是这个映射类(MyUserMap)是哪个实体类(MyUser)的映射规则。 Entity Framework 通过 Fluent API 提供了一系列的方法来添加规则,这些规则需要写在映射类的无参构造函数中,我们来添加无参构造函数 MyUserMap(),最终的MyUserMap会成为下面这样:

    using Kunlun.CRS.Core.Domain.Users; using System.Data.Entity.ModelConfiguration; namespace Kunlun.CRS.Data.Mapping { public class MyUserMap : EntityTypeConfiguration<MyUser> { public MyUserMap() { ToTable("MyUser"); HasKey(t => t.Id); Property(t => t.LastLoginDate).HasColumnName("last_login_date"); } } } 第 10 行的 ToTable() 方法表示当前实体类(已经定义在 EntityTypeConfiguration<T> 的泛型参数中,这里是 MyUser)映射到哪张表上第 12 行的 HasKey() 方法用于指定表的主键对应实体类的哪一个属性(t 表示的也是实体类,将鼠标放到 t 上即可看到它的类型)第 14 行的 Property() 方法首先指定要设置的实体类属性,再通过 HasColumnName() 方法来指定该属性对应数据库表中的哪一列

    之所以称之为 Fluent API 是因为它的使用方式(可以一直连续的调用方法),假设我们要将某一属性(如 string 类型的 Test 属性)映射到数据库中的 my_test 列,并且数据类型是 char(200),那我们只需要:

    Property(t => t.Test).HasColumnName("my_test") .HasColumnType("char") .HasMaxLength(200);

    在默认的映射规则中, string 类型的属性会被映射为数据库中的 nvarchar(max),而通过上面的配置,我们可以方便的、语义明确的将 Test 属性映射为数据库中的 char(200) 的 my_test 列。 至此,我们的映射也已经添加完成了,接下来可以编写 Service 了。

    实现查询功能

    我们将通过纯纯的 C# 代码来查询数据库,不需要编写任何 SQL 语句,即可查询 MyUser 表中所有的数据!让我们回到 MyUserService 来继续未完成的操作。 我们的目标是调用一个方法,返回 MyUser 表中的所有数据,也就是说,这个方法返回的应该是一个集合,我们常用 List<T> 来承载这样的数据。首先新增一个 GetAll() 方法,方法的命名一定要清晰明确,可读性强,让人一眼便知。在第一章中,我们在介绍类库层时提到了仓储类 Repository<T>,现在我们就要通过它访问数据库了。在此之前先简要介绍一下 Repository<T> 中常用的方法和属性:

    名称类型返回类型描述Table属性IQueryable<T>获取实体对应表的所有数据GetById()方法T通过主键进行查询Insert()方法void向表中插入一条数据Update()方法void更新一条数据Delete()方法void删除一条数据

    我们需要自己创建(new) Repository<T> 的实例吗?不需要!只需要在 MyUserService 中添加一个私有只读字段 Repository<MyUser> _myUserRepository。Repository<T> 的泛型参数 T 和之前添加映射时的 EntityTypeConfiguration<T> 泛型参数一样,用于指定实体类。我们是要对 MyUser 表查询,显然是通过 MyUser 实体类进行的,所以这里为 Repository<T> 传递的泛型参数是 MyUser。只要记住,要操作哪个表,就用哪个实体类的仓储类就行。

    private readonly Repository<MyUser> _myUserRepository;

    现在我们虽然有了 Repository<MyUser> 字段,但它是没有值的!我们这里先不管它,继续我们的编码。为 MyUserService 添加一个构造函数,在构造函数的参数列表中加上一个 Repository<MyUser> 类型的参数,并在构造函数中为 _myUserRepository 赋值:

    public MyUserService(Repository<MyUser> myUserRepository) { _myUserRepository = myUserRepository; }

    这里不得不介绍一个神器——AutoFac。AutoFac 是一个依赖注入框架,可以暂时理解它为一个能自动解析依赖关系并提供依赖的类库。以 MyUserService 为例,这个 Service 中需要使用 Repository<MyUser>,也就是说 MyUserService 依赖于 Repository<MyUser>。上面的代码中,我们以构造器注入的方式,为 MyUserService 提供了它依赖的 Repository<MyUser> 的实例。我们通过依赖注入框架,可以做到想用什么类,就在构造函数中写什么类。除了构造器注入,AutoFac 还提供了其他的注入方式,等我们用到再说明。通过在构造函数中赋值,我们就能在 MyUserService 的实例方法中使用 Repository<MyUser> 了。 通过浏览 Repository<T> 中提供的方法和属性后我们发现,Table 属性可以用于获取表中的数据,它的返回类型为 IQueryable<T>,虽然也是集合的一种,但与我们 GetAll() 方法期望的 List<T> 类型不一致,此时我们需要使用 System.Linq 命名空间下的 ToList() 方法,将 IQueryable<T> 转换为 List<T>,这样我们的 GetAll() 方法就完工了!

    public List<MyUser> GetAll() { return _myUserRepository.Table.ToList(); }

    接下来到 MyUserController 中,之前我们创建好了 List() 让它直接返回视图,但并没访问数据库,现在我们要在 List() 方法中执行刚刚编写好的 MyUserService 中的 GetAll() 方法。 你会发现,我们在 MyUserController 中,还没有 MyUserService 的实例,但我们依然可以通过依赖注入来获取它!添加一个构造函数,并在参数中填入 MyUserService ,并声明一个私有只读字段来缓存它,现在 MyUserController 看起来是这样的:

    using Kunlun.CRS.Services.Users; using Kunlun.CRS.Web.Framework.Controllers; using System.Web.Mvc; namespace Kunlun.CRS.Web.Controllers { public class MyUserController : BaseController { private readonly MyUserService _myUserService; public MyUserController(MyUserService myUserService) { _myUserService = myUserService; } public ActionResult List() { var users = _myUserService.GetAll(); return View(); } } }

    接下来我们按下 Ctrl + F5 到浏览器中查看一下效果,等浏览器打开后你可能会看到登陆页面或者欢迎页面,如果是登陆页面请先登陆,并选择“酒店集团”。随后将 URL 改为我们 List 页面的 URL:http://localhost:57811/MyUser/List,并按下回车键。

    在开发过程中,如果无须调试,我们可以按下 F6 来重新生成解决方案,这样如果之前通过 Ctrl + F5 打开过浏览器,并且此时浏览器没有关闭,我们就能直接刷新浏览器看到最新效果。不过此时需要留意操作系统的托盘栏中,是否有 IIS Express 存在。我们的项目运行在 IIS Express 之上,如果它被关闭了,刷新浏览器将会提示无法访问。

    此时你将看到一个错误页面,请不要惊慌,仔细阅读错误描述

    None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'Kunlun.CRS.Web.Controllers.MyUserController' can be invoked with the available services and parameters: Cannot resolve parameter 'Kunlun.CRS.Services.Users.MyUserService myUserService' of constructor 'Void .ctor(Kunlun.CRS.Services.Users.MyUserService)'.

    大意为

    DefaultConstructorFinder 在调用 MyUserController 的构造函数时,没有找到可用的服务或参数 无法解析参数 MyUserService myUserService

    通过错误信息,我们发现 AutoFac 无法解析 MyUserService,也就是说无法为 MyUserController 提供它依赖的 MyUserService 的实例。原来,要想让 AutoFac 解决依赖,必须先告诉 AutoFac 有哪些类需要它来管理!这个规则存放在 Web 项目的 Infrastructure 文件夹的 DependencyRegistrar.cs 文件中。Repository<T> 不用配置,是因为我们在搭建项目之初就已经添加好了。 打开 DependencyRegistrar.cs 文件,我们能看见 DependencyRegistrar 类,在它的 Register() 方法中添加一行

    builder.RegisterType<MyUserService>().InstancePerLifetimeScope();

    这行代码告诉 AutoFac,我需要让你来帮我管理 MyUserService,这样就能愉快的将 MyUserService 注入到 MyUserController 中了。你或许还记得 MyUserService 的构造函数并不是无参的,它依赖于 Repository<T>,不过没有关系,AutoFac 也会自动帮我们解决。 让我们重新生成解决方案,并刷新浏览器查看 List 页面,错误应该已经消失了,转而显示一个空白的页面。

    千万记住要重新生成!对于 View 之外的代码,如 Service、Controller,每次修改完成之后都需要重新生成,我们才能在下次访问网页时看到改动后的效果,因为它们会生成为 dll 文件。如果是 View 中的内容,我们修改之后就不需要重新生成了,因为 View 是动态编译的。

    接下来我们要为空白的页面增加内容了。View 页面上显示的内容,我们需要事先存放在 View Model 中 —— View Model 是一个类,我们在 Controller 里准备页面所需的数据并存入 View Model,然后才能在 View 上获取这些数据。如果你调查过作为返回值的 View() 方法,可能会发现它不止一个重载:它有一个接收 object 类型参数的重载,他就是传递给 View 的数据。

    那么我们先来建立 MyUser/List 页面所需的 View Model 类:MyUserListModel。在 Web 项目的 Models 目录里新增一个名为 MyUser 的文件夹,然后再在该文件夹中新增一个类文件 MyUserListModel.cs。 由于 List 页面应该展示一个列表,显然 MyUserListModel 类中需要有一个集合,而集合中的内容应该是 MyUser。但根据我们用于显示的内容必须使用 View Mode的原则,所以不应该在 MyUserListModel 存放 MyUser 实体类的集合,而是 MyUser 对应的 View Model 的集合。在 Web 项目的 Models/MyUser 中,新增 MyUserModel.cs,我们需要在页面上显示 MyUser 实体类中的哪些内容,就把它们定义到 MyUserModel 中。这里将 MyUser 中定义的所有属性(不含 BaseEntity 中定义的)都定义到它的 View Model 中。

    你可能已经发现,View Model 都是以其对应的实体类名 + Model 结尾的。页面的 View Model 都是以它的 Action 名 + Model 结尾的,如 MyUserListModel。当然,在一些情况下我们可以灵活的对其命名,只要本着可读、易用的原则即可。

    下面是我们定义好后的 MyUserModel:

    public class MyUserModel { public int Id { get; set; } public string Username { get; set; } public string Password { get; set; } public int Gender { get; set; } public DateTime? Birthday { get; set; } public DateTime? LastLoginDate { get; set; } }

    以及 MyUserListModel:

    public class MyUserListModel { public List<MyUserModel> MyUserList { get; set; } }

    可以看到 MyUser 的 View Model 和它自身几乎完全一样,而 List 页面使用的 View Model 只有一个简单的集合,我们将 _myUserService.GetAll() 返回的值储存到 MyUserListModel 的 MyUserList 集合中,就可以在页面上显示了!我们来改写 MyUserController 的 List() 方法:

    public ActionResult List() { var users = _myUserService.GetAll(); var model = new MyUserListModel(); model.MyUserList = users; return View(model); }

    此时可以看到 model.MyUserList = users; 一行上显示了错误,并且 F6 也无法正常生成

    无法将类型“System.Collections.Generic.List<Kunlun.CRS.Core.Domain.Users.MyUser>”隐式转换为“System.Collections.Generic.List<Kunlun.CRS.Web.Models.MyUser.MyUserModel>”

    没错,我们不能直接将实体类 MyUser 赋值给它的 View Model MyUserModel,因为这是完全没有关联的两个不同类型。但我们的最终目标,是将实体类中的值,转移到 View Model 中,这就用到另一个类库 —— Auto Mapper。顾名思义,它是一个用于自动映射的类库,它的规则也很简单,提供两个类的实例,它能把来源类中与目标类同名的属性(忽略大小写)自动赋上值。我们数据的来源类是 MyUser,目标类是 MyUserModel,这两个类虽然毫不相干,但是属性都是同名的,这是最理想的情况。与 Entity Framework、AutoFac 一样,接下来也要为 Auto Mapper 编写规则,AutoMapper 的映射规则文件位于 Web 项目的 Infrastructure/AutoMapperStartupTask.cs 中。 打开文件后我们能看到 AutoMapperStartupTask 类,在 Execute() 方法中添加一行代码,表示我们需要让 Auto Mapper 处理 MyUser -> MyUserModel 的转换:

    Mapper.CreateMap<MyUser, MyUserModel>();

    细心的你会发现, _myUserService.GetAll() 得到的是 List<MyUser>,而 model.MyUserList 需要的是 List<MyUserModel>。为什么我们为 AutoMapper 添加的是 MyUser -> MyUserModel 的转换规则,而不是 List<MyUser> -> List<MyUserModel> 呢?原来 AutoMapper 能自动识别出我们要转换的类型,对于 List<TSource> 到 List<TDestination> 实际上是对两个泛型集合进行转换,也就是对集合中的泛型类型进行转换,即 TSource -> TDestination,因此这里只需要把泛型类型的转换关系告知 AutoMapper,他就能处理不论是 MyUser -> MyUserModel 还是 List<MyUser> -> List<MyUserModel> 甚至是 IEnumerable<MyUser> -> List<MyUserModel> 的情况了。

    实体类、View Model 类,看起来一样,但是他们的用途却完全不同。虽然我们可以直接将实体类用于页面显示,但这违背了单一职责原则。而且随着开发的进行,会发现 View Model 与实体类差异会越来越大。

    修改后的 List() 方法是这样的:

    public ActionResult List() { var users = _myUserService.GetAll(); var model = new MyUserListModel(); model.MyUserList = users.MapTo<List<MyUser>, List<MyUserModel>>(); return View(model); }

    代码中 users.MapTo<TSource, TDestination>() 一行就是使用 AutoMapper,将 MyUser 转换为了 MyUserModel。TSource 表示来源数据类型,TDestination 表示目标数据类型。 View Model 的数据填充好后,我们终于迎来了收尾工作——将数据展示到 View 上。让我们在控制器的 List() 方法名上点击右键,选择“跳转到视图”,便会进入 List.cshtml。首先在 View 的第一行告知 View 应该使用哪个 View Model:

    @model Kunlun.CRS.Web.Models.MyUser.MyUserListModel

    这样才能正确的在 View 中通过 Model 属性访问到 View() 方法传递来的 View Model 的值。接下来我们要展示所有的用户到页面上,通过 foreach 来遍历 MyUserListModel 的 MyUserList 集合,并将它输出到一个 table 中

    @model Kunlun.CRS.Web.Models.MyUser.MyUserListModel @{ ViewBag.Title = "List"; } <table class="table table-hover"> <thead> <tr> <th>Id</th> <th>用户名</th> <th>性别</th> <th>生日</th> <th>上次登陆时间</th> </tr> </thead> @foreach (var user in Model.MyUserList) { <tr> <td>@user.Id</td> <td>@user.Username</td> <td>@user.Gender</td> <td>@user.Birthday</td> <td>@user.LastLoginDate</td> </tr> } </table>

    上面仍然是通过 Razor 引擎实现了 C# 代码与 HTML 的混合编写。通过 @ 符号可以书写 C# 代码、将 <tr></tr> 编写在 foreach 中,就会生成多个 <tr>。更多 Razor 语法相关的文档可以参考 MSDN Introduction to ASP.NET Web Programming Using the Razor Syntax (C#)。 编写好之后按下 F6 键,然后到浏览器中刷新 List 页面,就能看到最终效果了!

    总结

    通过 Fluent API 为 Entity Framework 的实体类配置与数据库表的映射规则通过 AutoFac 依赖注入,解决类与类之间依赖的问题要想让 AutoFac 解决依赖,必须对 AutoFac 进行配置,不然会报错:无法解析依赖AutoMapper 用于将一个类的实例的数据映射到另一个类的实例中,使用 AutoMapper 也需要编写映射规则

    下一章我们将实现对一条用户记录的修改操作,届时将会介绍有关验证、Html 帮助类等内容,敬请期待。

    扩展阅读

    Entity FrameworkAutoFacAuto Mapper
    转载请注明原文地址: https://ju.6miu.com/read-509.html

    最新回复(0)