一. MVC介绍

  MVC架构模式有助于实现关注点分离。视图和控制器均依赖于模型。 但是,模型既不依赖于视图,也不依赖于控制器。 这是分离的一个关键优势。 这种分离允许模型独立于可视化展示进行构建和测试。ASP.NET Core MVC 包括以下功能:

    路由、模型绑定、模型验证、依赖关系注入、筛选器、区域、Web API、可测试性、Razor 视图引擎、强类型视图、标记帮助程序、 视图组件。

  (1) 路由

    ASP.NET Core MVC 建立在 ASP.NET Core 的路由之上,是一个功能强大的 URL 映射组件,可用于生成具有易于理解和可搜索 URL 的应用程序。关于路由知识,请查看asp.net core 系列第5,6章。

  (2) 模型绑定(Model)

    ASP.NET Core MVC 模型绑定将客户端请求数据(窗体值(form)、路由数据、查询字符串参数、HTTP 头)转换到控制器(Controller)可以处理的对象中。 因此,控制器逻辑不必找出传入的请求数据;它只需具备作为其Action方法的参数的数据。下面的LoginViewModel就是一个模型类。

  public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)

 

  (3) 模型验证

    ASP.NET Core MVC 通过使用数据注释验证属性。 验证属性在值发送到服务端前,在客户端上进行检查。并在调用控制器action前在服务端上进行检查。

using System.ComponentModel.DataAnnotations;
public class LoginViewModel
{[Required][EmailAddress]public string Email { get; set; }[Required][DataType(DataType.Password)]public string Password { get; set; }[Display(Name = "Remember me?")]public bool RememberMe { get; set; }
}//服务端控制器action验证
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
{//验证模型 if (ModelState.IsValid){// work with the model
    }return View(model);
}

  (4) 依赖注入

    依赖关系注入除了在控制器上通过构造函数请求所需服务,还可以使用@inject 指令,应用在视图文件上。下面是视图页面上通过依赖注入获取服务对象。

@inject SomeService ServiceName
<!DOCTYPE html>
<html lang="en">
<head><title>@ServiceName.GetTitle</title>
</head>
<body><h1>@ServiceName.GetTitle</h1>
</body>
</html>

  (5) 筛选器

    筛选器帮助开发者封装,横切关注点,例如异常处理或授权。筛选器允许action方法运行自定义预处理和后处理逻辑,并且可以配置为在给定请求的执行管道内的特定点上运行。筛选器可以作为属性应用于控制器或Action(也可以全局运行)。例如MVC 授权筛选器。

    [Authorize]public class AccountController : Controller

  (6) 区域

    区域用在大型Web开发上, 是功能分组的方法。区域是应用程序内的一个 MVC 结构。  例如,具有多个业务单位(如结账、计费、搜索等)的电子商务应用。每个单位都有自己的逻辑组件视图、控制器和模型。

  (7) Web API

    除了作为生成网站的强大平台,ASP.NET Core MVC 还对生成 Web API 提供强大的支持。 可以生成可连接大量客户端(包括浏览器和移动设备)的服务,前面章节有讲过。

  (8) 可测试性

    框架对界面和依赖项注入的使用非常适用于单元测试,并且该框架还包括使得集成测试快速轻松的功能(例如 TestHost 和实体框架的 InMemory 提供程序)

  (9) Razor 视图引擎

    ASP.NET Core MVC 视图使用 Razor 视图引擎呈现视图。 Razor 是一种紧凑、富有表现力且流畅的模板标记语言,用于使用嵌入式 C# 代码定义视图。 Razor 用于在服务器上动态生成 Web 内容。 可以完全混合服务器代码与客户端内容和代码。例如下面嵌入 C#代码,循环输出5组li标记

<ul>@for (int i = 0; i < 5; i++) {<li>List item @i</li>}
</ul>

  (10) 强类型视图

    可以基于模型强类型化 MVC 中的 Razor 视图。 控制器可以将强类型化的模型传递给视图,使视图具备类型检查和 IntelliSense 支持。例如,以下视图呈现类型为 IEnumerable<Product> 的模型:

@model IEnumerable<Product>
<ul>@foreach (Product p in Model){<li>@p.Name</li>}
</ul>

  (11) 标记帮助程序

    标记帮助程序使服务器端代码可以在 Razor 文件中参与创建和呈现 HTML 元素。 例如,内置 LinkTagHelper 可以用来创建指向 AccountsController控制器中  Login的方法链接

    <p>Thank you for confirming your email.Please <a asp-controller="Account" asp-action="Login">Click here to Log in</a>.</p>

  (12) 视图组件

    通过视图组件可以包装呈现逻辑并在整个应用程序中重用它。 这些组件类似于分部视图,但具有关联逻辑。

     

二. 完整示例介绍(项目StudyMVCDemo)

  2.1 安装EF数据提供程序

    这里使用内存数据库Microsoft.EntityFrameworkCore.InMemory,Entity Framework Core 和内存数据库一起使用, 这对测试非常有用。

    PM> Install-Package Microsoft.EntityFrameworkCore.InMemory

  2.2 新建数据模型类(POCO )和EF上下文类

    public class MvcMovieContext : DbContext{public MvcMovieContext(DbContextOptions options): base(options){}public DbSet<Movie> Movie { get; set; }}    

    public class Movie{public int Id { get; set; }public string Title { get; set; }[DataType(DataType.Date)]public DateTime ReleaseDate { get; set; }public string Genre { get; set; }public decimal Price { get; set; }}

  2.3 初始化数据

     public static void Main(string[] args){var host = CreateWebHostBuilder(args).Build();using (var scope = host.Services.CreateScope()){var services = scope.ServiceProvider;try{//var context = services.GetRequiredService<MvcMovieContext>();//程序运行时,使用EF迁移生成数据,用在关系型数据库//context.Database.Migrate();
                    SeedData.Initialize(services);}catch (Exception ex){var logger = services.GetRequiredService<ILogger<Program>>();logger.LogError(ex, "An error occurred seeding the DB.");}}host.Run();}

    public static class SeedData{/// <summary>/// 初始化数据/// </summary>/// <param name="serviceProvider"></param>public static  void Initialize(IServiceProvider serviceProvider){using (var context = new MvcMovieContext(serviceProvider.GetRequiredService<DbContextOptions<MvcMovieContext>>())){// 如果有数据返回if (context.Movie.Any()){return;   // DB has been seeded
                }context.Movie.AddRange(new Movie{Title = "When Harry Met Sally",ReleaseDate = DateTime.Parse("1989-2-12"),Genre = "Romantic Comedy",Price = 7.99M},new Movie{Title = "Ghostbusters ",ReleaseDate = DateTime.Parse("1984-3-13"),Genre = "Comedy",Price = 8.99M},new Movie{Title = "Ghostbusters 2",ReleaseDate = DateTime.Parse("1986-2-23"),Genre = "Comedy",Price = 9.99M},new Movie{Title = "Rio Bravo",ReleaseDate = DateTime.Parse("1959-4-15"),Genre = "Western",Price = 3.99M});context.SaveChanges();}}}

View Code

  

  2.4 添加控制器类(MoviesController)

  public class MoviesController : Controller{private readonly  MvcMovieContext _MvcMovieContext;public MoviesController(MvcMovieContext MvcMovieContext){this._MvcMovieContext = MvcMovieContext;}}

  2.5 列表页Movies/index.cshtml

        // GET: /<controller>/public IActionResult Index(){var movies = _MvcMovieContext.Movie.ToList();return View(movies);}

@model IEnumerable<StudyMVCDemo.Models.Movie>@{ViewData["Title"] = "Index";
}<h1>Index</h1><p><a asp-action="Create">Create New</a>
</p>
<table class="table"><thead><tr><th>@Html.DisplayNameFor(model => model.Title)</th><th>@Html.DisplayNameFor(model => model.ReleaseDate)</th><th>@Html.DisplayNameFor(model => model.Genre)</th><th>@Html.DisplayNameFor(model => model.Price)</th><th></th></tr></thead><tbody>@foreach (var item in Model){<tr><td>@Html.DisplayFor(modelItem => item.Title)</td><td>@Html.DisplayFor(modelItem => item.ReleaseDate)</td><td>@Html.DisplayFor(modelItem => item.Genre)</td><td>@Html.DisplayFor(modelItem => item.Price)</td><td><a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |<a asp-action="Details" asp-route-id="@item.Id">Details</a> |<a asp-action="Delete" asp-route-id="@item.Id">Delete</a></td></tr>}</tbody>
</table>

  启动程序,在浏览器中输入http://localhost:18084/Movies,如下图所示:

    上图中菜单布局是在 Views/Shared/_Layout.cshtml 文件中实现的,该_Layout.cshtml页中@RenderBody()是视图页面的占位符。

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

   2.6 详细页Movies/ Details.cshtml

        /// <summary>/// 详细页 /// </summary>/// <param name="id"></param>/// <returns></returns>public async Task<IActionResult> Details(int? id){if (id == null){return NotFound();}var movie = await _MvcMovieContext.Movie.FirstOrDefaultAsync(m => m.Id == id);if (movie == null){return NotFound();}return View(movie);}

@model StudyMVCDemo.Models.Movie@{ViewData["Title"] = "Details";
}<h1>Details</h1><div><h4>Movie</h4><hr /><dl class="row"><dt class="col-sm-2">@Html.DisplayNameFor(model => model.Title)</dt><dd class="col-sm-10">@Html.DisplayFor(model => model.Title)</dd><dt class="col-sm-2">@Html.DisplayNameFor(model => model.ReleaseDate)</dt><dd class="col-sm-10">@Html.DisplayFor(model => model.ReleaseDate)</dd><dt class="col-sm-2">@Html.DisplayNameFor(model => model.Genre)</dt><dd class="col-sm-10">@Html.DisplayFor(model => model.Genre)</dd><dt class="col-sm-2">@Html.DisplayNameFor(model => model.Price)</dt><dd class="col-sm-10">@Html.DisplayFor(model => model.Price)</dd></dl>
</div>
<div><a asp-action="Edit" asp-route-id="@Model.Id">Edit</a> |<a asp-action="Index">Back to List</a>
</div>

  启动程序,从列表页的超连接Details点击进入,如下图所示:

  

  2.7 编辑页Movies/ Edit.cshtml

    对于编辑页有二个action, 一个是Get用来提取数据填充到表单,一个是Post用来提交修改的表单数据。

    (1) post中的Bind特性是对需要的属性进行更新。

    (2) ValidateAntiForgeryToken特性用于防止请求伪造, 生成的隐藏的 XSRF 标记 Input name="__RequestVerificationToken"。用在Post提交的比如修改和删除功能等。

    (3) 模型验证asp-validation-for是指表单Post到服务器之前,客户端验证会检查字段上的任何验证规则。 如果有任何验证错误,则将显示错误消息,并且不会Post表单,内部是输入标记帮助程序使用 DataAnnotations 特性,并在客户端上生成 jQuery 验证所需的 HTML 特性。

       public async Task<IActionResult> Edit(int? id){if (id == null){return NotFound();}var movie = await _MvcMovieContext.Movie.FindAsync(id);if (movie == null){return NotFound();}return View(movie);}[HttpPost][ValidateAntiForgeryToken]public async Task<IActionResult> Edit(int id, [Bind("Id,Title,ReleaseDate,Genre,Price")] Movie movie){if (id != movie.Id){return NotFound();}if (ModelState.IsValid){try{_MvcMovieContext.Update(movie);await _MvcMovieContext.SaveChangesAsync();}catch (DbUpdateConcurrencyException){throw;}return RedirectToAction("Index");}return View(movie);}

@model StudyMVCDemo.Models.Movie@{ViewData["Title"] = "Edit";
}<h1>Edit</h1><h4>Movie</h4>
<hr />
<div class="row"><div class="col-md-4"><form asp-action="Edit"><div asp-validation-summary="ModelOnly" class="text-danger"></div><input type="hidden" asp-for="Id" /><div class="form-group"><label asp-for="Title" class="control-label"></label><input asp-for="Title" class="form-control" /><span asp-validation-for="Title" class="text-danger"></span></div><div class="form-group"><label asp-for="ReleaseDate" class="control-label"></label><input asp-for="ReleaseDate" class="form-control" /><span asp-validation-for="ReleaseDate" class="text-danger"></span></div><div class="form-group"><label asp-for="Genre" class="control-label"></label><input asp-for="Genre" class="form-control" /><span asp-validation-for="Genre" class="text-danger"></span></div><div class="form-group"><label asp-for="Price" class="control-label"></label><input asp-for="Price" class="form-control" /><span asp-validation-for="Price" class="text-danger"></span></div><div class="form-group"><input type="submit" value="Save" class="btn btn-primary" /></div></form></div>
</div><div><a asp-action="Index">Back to List</a>
</div>@section Scripts {@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

    启动程序,从列表页的Edit点击进入,如下图所示:

  2.8 删除

 // 删除没有对应的页面,从列表页的Delete点击进入,下面是删除的关键代码
public async Task<IActionResult> DeleteConfirmed(int id)
{var movie = await _context.Movie.FindAsync(id);_context.Movie.Remove(movie);await _context.SaveChangesAsync();return RedirectToAction(nameof(Index));
}

  参考文献

    MVC教程

    

转载于:https://www.cnblogs.com/MrHSR/p/10509469.html

asp.net core系列 40 Web 应用MVC 介绍与详细示例相关推荐

  1. asp.net core系列 67 Web压力测试工具WCAT

    asp.net core系列 67 Web压力测试工具WCAT 原文:asp.net core系列 67 Web压力测试工具WCAT 一.介绍 最近搭建了一套CQRS框架,需要在投入开发前,进行必要的 ...

  2. asp.net core 系列 18 web服务器实现

    一. ASP.NET Core Module 在介绍ASP.NET Core Web实现之前,先来了解下ASP.NET Core Module.该模块是插入 IIS 管道的本机 IIS 模块(本机是指 ...

  3. asp.net core系列 71 Web架构分层指南

    一.概述 本章Web架构分层指南,参考了"Microsoft应用程序体系结构指南"(该书是在2009年出版的,当时出版是为了帮助开发人员和架构师更快速,更低风险地使用Microso ...

  4. asp.net core系列 38 WebAPI 返回类型与响应格式--必备

    一.返回类型 ASP.NET Core 提供以下 Web API Action方法返回类型选项,以及说明每种返回类型的最佳适用情况: (1) 固定类型 (2) IActionResult (3) Ac ...

  5. 5.1基于JWT的认证和授权「深入浅出ASP.NET Core系列」

    原文:5.1基于JWT的认证和授权「深入浅出ASP.NET Core系列」 希望给你3-5分钟的碎片化学习,可能是坐地铁.等公交,积少成多,水滴石穿,码字辛苦,如果你吃了蛋觉得味道不错,希望点个赞,谢 ...

  6. ASP.NET CORE系列【一】搭建ASP.NET CORE项目

    原文:ASP.NET CORE系列[一]搭建ASP.NET CORE项目 为什么要使用 ASP.NET Core? NET Core 刚发布的时候根据介绍就有点心里痒痒,微软的尿性都懂的,新东西bug ...

  7. 【转载】从头编写 asp.net core 2.0 web api 基础框架 (1)

    工具: 1.Visual Studio 2017 V15.3.5+ 2.Postman (Chrome的App) 3.Chrome (最好是) 关于.net core或者.net core 2.0的相 ...

  8. 从头编写 asp.net core 2.0 web api 基础框架 (1)

    工具: 1.Visual Studio 2017 V15.3.5+ 2.Postman (Chrome的App) 3.Chrome (最好是) 关于.net core或者.net core 2.0的相 ...

  9. 4.1ASP.NET Core请求过程「深入浅出ASP.NET Core系列」

    原文:4.1ASP.NET Core请求过程「深入浅出ASP.NET Core系列」 希望给你3-5分钟的碎片化学习,可能是坐地铁.等公交,积少成多,水滴石穿,谢谢关注. HTTP请求过程 这里展示整 ...

最新文章

  1. 如何在notebook中的markdown中插入截取的图片_96编辑器教你如何在文章中插入图片、视频、音频!...
  2. 美国和中国将成数据中心建设首选之地
  3. 在 Snoop 中使用 PowerShell 脚本进行更高级的 UI 调试
  4. 复述-软考网规--云计算专题
  5. File类之常用方法
  6. Oracle 数据类型,表空间、用户与权限,DDL、DML 语句、约束,exp/imp
  7. 单片机的c语言程序设计显示12,12手把手教你学单片机的C语言程序设计中断服务函数.pdf...
  8. android设置adb环境变量,如何配置android的adb环境变量
  9. Android 消息机制之深入学习MessageQueue
  10. 货币兑换java程序,Spring Cloud货币换算及货币兑换服务介绍
  11. ion-infinite-scroll上拉加载 ion-refresher下拉刷新
  12. 函数重载与参数缺省值共用可能引起两意性
  13. Win10桌面壁纸、锁屏壁纸保存位置
  14. H5 -- 自定义微信分享第三方页面链接的标题和小缩略图
  15. PHp猴子偷,这些猴子成精了!偷东西偷得很萌很认真……
  16. 推断统计学 假设检验 分布
  17. biubiu加速器下载安装包路径
  18. mldonkey安装
  19. 安卓手机开不了机_手机开不了机的原因 _手机开不了机如何解决
  20. 'static_cast': cannot convert from 'double' to 'pcl::visualization::LookUpTableRepresentationPropert

热门文章

  1. 随办——真正懂企业痛点的移动协作软件
  2. PowerDesigner 15生成数据字典
  3. 斑马打印机客户端GET和POST,以及后端两种打印方式。
  4. 关于设计模式的感悟2
  5. 微软认证学习资料大集合(软件+资料)
  6. 自定义标签之 带Body的标签库
  7. RocketMQ源码解析-Broker的HA实现
  8. 网页防篡改技术_阿里云云安全中心和web应用防火墙的网页防篡改功能有什么不同...
  9. zookeeper springboot_摊牌了!我要手写一个“Spring Boot”
  10. Mybatis的动态拼接条件