如何在ASP.NET Core 2.0中使用Razor页面

 DotNetCore2017-11-22 14:49

问题

如何在ASP.NET Core 2.0中使用Razor页面

创建一个空的项目并修改Startup.cs文件以为MVC添加服务和中间件。

  1. publicvoid ConfigureServices(

  2. IServiceCollection services)

  3. {

  4. services.AddSingleton<IMovieService, MovieService>();

  5. services.AddMvc();

  6. }

  7. publicvoid Configure(

  8. IApplicationBuilder app,

  9. IHostingEnvironment env)

  10. {

  11. app.UseMvc();

  12. }

添加一个服务和域模型(IMovieService的实现只是示例源代码中的内存列表),

  1. publicclass Movie

  2. {

  3. publicint Id { get; set; }

  4. public string Title { get; set; }

  5. publicint ReleaseYear { get; set; }

  6. public string Summary { get; set; }

  7. }

  8. publicinterface IMovieService

  9. {

  10. List<Movie> GetMovies();

  11. Movie GetMovie(int id);

  12. void AddMovie(Movie item);

  13. void UpdateMovie(Movie item);

  14. void DeleteMovie(int id);

  15. bool MovieExists(int id);

  16. }

添加输入和输出模型(通过属性绑定接收和发送数据)。

  1. publicclass MovieInputModel

  2. {

  3. publicint Id { get; set; }

  4. [Required]

  5. public string Title { get; set; }

  6. publicint ReleaseYear { get; set; }

  7. public string Summary { get; set; }

  8. }

  9. publicclass MovieOutputModel

  10. {

  11. publicint Id { get; set; }

  12. public string Title { get; set; }

  13. publicint ReleaseYear { get; set; }

  14. public string Summary { get; set; }

  15. public DateTime LastReadAt { get; set; }

  16. }

添加一个名为Pages的文件夹,并为其添加Index,_Layout,_ViewImports和_ViewStart页面。这些页面与MVC没有区别。另外,为您的CRUD页面添加一个文件夹Movies。

添加4个新的RazorPage项目到电影文件夹 - 称为索引,创建,编辑和删除。这些将添加.cshtml和.cshtml.cs文件。

这些页面中的每一个都将通过构造器注入来注入我们的 IMovieService ,例如,

  1. private readonly IMovieService service;

  2. public IndexModel(IMovieService service)

  3. {

  4. this.service = service;

  5. }

修改Index.cshtml。

  1. @page

  2. @model IndexModel

  3. @{

  4. }

  5. <strong>Movie Listing</strong>

  6. <div>

  7. <a asp-page="/Index">Home</a> |

  8. <a asp-page="./Create">Add New</a>

  9. </div>

  10. <table>

  11. <thead>

  12. <tr>

  13. <th>Title</th>

  14. <th>Year</th>

  15. <th></th>

  16. <th></th>

  17. <th></th>

  18. </tr>

  19. </thead>

  20. <tbody>

  21. @foreach (var item in Model.Movies)

  22. {

  23. <tr>

  24. <td>@item.Title</td>

  25. <td>@item.ReleaseYear</td>

  26. <td><a asp-page="./Edit" asp-route-id="@item.Id">Edit</a></td>

  27. <td><a asp-page="./Delete" asp-route-id="@item.Id">Delete</a></td>

  28. </tr>

  29. }

  30. </tbody>

  31. </table>

修改Index.cshtml.cs。

  1. public List<MovieOutputModel> Movies { get; set; }

  2. publicvoid OnGet()

  3. {

  4. this.Movies = this.service.GetMovies()

  5. .Select(item => new MovieOutputModel

  6. {

  7. Id = item.Id,

  8. Title = item.Title,

  9. ReleaseYear = item.ReleaseYear,

  10. Summary = item.Summary,

  11. LastReadAt = DateTime.Now

  12. })

  13. .ToList();

  14. }

修改Create.cshtml。

  1. @page

  2. @model CreateModel

  3. @{

  4. }

  5. <strong>New Movie</strong>

  6. <form method="post">

  7. <div asp-validation-summary="All"></div>

  8. <label asp-for="Movie.Id"></label>

  9. <input asp-for="Movie.Id" /><br />

  10. <label asp-for="Movie.Title"></label>

  11. <input asp-for="Movie.Title" />

  12. <span asp-validation-for="Movie.Title"></span><br />

  13. <label asp-for="Movie.ReleaseYear"></label>

  14. <input asp-for="Movie.ReleaseYear" /><br />

  15. <label asp-for="Movie.Summary"></label>

  16. <textarea asp-for="Movie.Summary"></textarea><br />

  17. <button type="submit">Save</button>

  18. <a asp-page="./Index">Cancel</a>

  19. </form>

修改Create.cshtml.cs。

  1. [BindProperty]

  2. public MovieInputModel Movie { get; set; }

  3. publicvoid OnGet()

  4. {

  5. this.Movie = new MovieInputModel();

  6. }

  7. public IActionResult OnPost()

  8. {

  9. if (!ModelState.IsValid)

  10. return Page();

  11. var model = new Movie

  12. {

  13. Id = this.Movie.Id,

  14. Title = this.Movie.Title,

  15. ReleaseYear = this.Movie.ReleaseYear,

  16. Summary = this.Movie.Summary

  17. };

  18. service.AddMovie(model);

  19. return RedirectToPage("./Index");

  20. }

修改Edit.cshtml。

  1. @page "{id:int}"

  2. @model EditModel

  3. @{

  4. }

  5. <strong>Edit Movie - @Model.Movie.Title</strong>

  6. <form method="post">

  7. <div asp-validation-summary="All"></div>

  8. <input type="hidden" asp-for="Movie.Id" />

  9. <label asp-for="Movie.Title"></label>

  10. <input asp-for="Movie.Title" />

  11. <span asp-validation-for="Movie.Title"></span><br />

  12. <label asp-for="Movie.ReleaseYear"></label>

  13. <input asp-for="Movie.ReleaseYear" /><br />

  14. <label asp-for="Movie.Summary"></label>

  15. <textarea asp-for="Movie.Summary"></textarea><br />

  16. <button type="submit">Save</button>

  17. <a asp-page="./Index">Cancel</a>

  18. </form>

修改Edit.cshtml.cs。

  1. [BindProperty]

  2. public MovieInputModel Movie { get; set; }

  3. public IActionResult OnGet(int id)

  4. {

  5. var model = this.service.GetMovie(id);

  6. if (model == null)

  7. return RedirectToPage("./Index");

  8. this.Movie = new MovieInputModel

  9. {

  10. Id = model.Id,

  11. Title = model.Title,

  12. ReleaseYear = model.ReleaseYear,

  13. Summary = model.Summary

  14. };

  15. return Page();

  16. }

  17. public IActionResult OnPost()

  18. {

  19. if (!ModelState.IsValid)

  20. return Page();

  21. var model = new Movie

  22. {

  23. Id = this.Movie.Id,

  24. Title = this.Movie.Title,

  25. ReleaseYear = this.Movie.ReleaseYear,

  26. Summary = this.Movie.Summary

  27. };

  28. service.UpdateMovie(model);

  29. return RedirectToPage("./Index");

  30. }

修改Delete.cshtml。

  1. @page "{id:int}"

  2. @model DeleteModel

  3. @{

  4. }

  5. <strong>Delete Movie</strong>

  6. <p>Are you sure you want to delete <strong>@Model.Title</strong>?</p>

  7. <form method="post">

  8. <input type="hidden" asp-for="Id" />

  9. <button type="submit">Yes</button>

  10. <a asp-page="./Index">No</a>

  11. </form>

修改Delete.cshtml.cs。

  1. [BindProperty]

  2. publicint Id { get; set; }

  3. public string Title { get; set; }

  4. public IActionResult OnGet(int id)

  5. {

  6. var model = this.service.GetMovie(id);

  7. if (model == null)

  8. return RedirectToPage("./Index");

  9. this.Id = model.Id;

  10. this.Title = model.Title;

  11. return Page();

  12. }

  13. public IActionResult OnPost()

  14. {

  15. if (!service.MovieExists(this.Id))

  16. return RedirectToPage("./Index");

  17. service.DeleteMovie(this.Id);

  18. return RedirectToPage("./Index");

  19. }

运行并浏览到/电影。

点击时,首先编辑(注意网址是/ Movies / Edit / 1),

点击删除(注意URL将是/电影/删除/ 3),

注意

你可以下载源代码来玩它。

讨论

在ASP.NET Core 2.0中引入了Razor页面,可以更快地构建简单的Web应用程序,并且是使用各种ASP.NET Core概念(如Razor,Layout Pages和Tag Helper等)的好方法。

Razor Pages使用 ASP.NET Core MVC ,但是编程模型不一样。与MVC不同,控制器,模型和视图是体系结构的不同组成部分,在Razor Pages中,这些概念被集中到一个页面模型的页面中。

页面模型

我喜欢将Page Model视为Controller和Models的组合。他们就像控制器,因为他们收到的HTTP请求,像一个模型,因为他们拥有视图的数据/属性。

对于.cshtml文件充当Page Model,它必须包含@page指令的第一行。.cshtml.cs(代码隐藏)类继承自PageModel抽象类。按照惯例,代码隐藏类有 模型 附加到页面的名称,例如索引页的代码隐藏是IndexModel。

路由

路由到页面取决于它们在您的项目目录结构中位于Pages文件夹下的位置(默认情况下)。如果URL中没有指定页面,则使用默认的索引。

在我们的示例中,我们导航到URL / Movies以查看位于我们的解决方案中的/ Pages / Movies / Index的页面。类似地,URL / Movies / Edit映射到/ Pages / Movies / Edit页面。

ASP.NET Core 2.0引入了用于生成URL的新构造,

  • Page()方法

  • asp页面标签助手

  • PageModel基类的RedirectToPage()方法

请注意,以/开头的URL是绝对路径并指向Pages文件夹。我们也可以使用与./或../相关的URL,或者简单的省略/。为了更好地理解,这里是从Page / Movies / Delete导航到各种URL时发生的情况,

我们可以将路由约束指定为@page指令的一部分,以指示运行时期望路由参数,或者丢失404(未找到)。在我们的编辑页面中,我们使用约束 -

  1. @page “{id:int}”

如果您希望使用不同于Pages的名称作为根文件夹,则可以通过配置页面选项来实现。

  1. services.AddMvc()

  2. .AddRazorPagesOptions(options =>

  3. {

  4. options.RootDirectory = "/MyPages";

  5. });

处理程序

如前所述,页面接收HTTP请求(即充当MVC世界中的Action),并由 处理程序方法处理。 这些处理程序返回IActionResult并使用On [verb]的约定命名。最常用的是OnGet()和OnPost()。对于异步,您可以将Async附加到名称,但是这是可选的。

PageModel基类具有RedirectToPage()方法(返回RedirectToPageResult)导航到其他页面和Page()方法(返回PageResult)返回当前页面。请注意,如果处理程序方法的返回类型为void,则运行时将返回PageResult。

为了让HTTP动词拥有多个处理器方法,我们可以使用 asp-page-handler属性来使用 命名处理器方法。这里指定的名字应该在页面类中使用约定On [动词] [处理程序]。让我们添加一个链接到我们的电影列表删除电影,

  1. <td>

  2. <a asp-page="./Index"

  3. asp-page-handler="delete"

  4. asp-route-id="@item.Id">Delete</a>

  5. </td>

在页面模型类中添加一个方法来处理这个请求(注意它的名字和参数),

  1. public IActionResult OnGetDelete(int id)

  2. {

  3. if (!service.MovieExists(id))

  4. return RedirectToPage("./Index");

  5. service.DeleteMovie(id);

  6. return RedirectToPage("./Index");

  7. }

将鼠标移到删除链接上,您会注意到像/ Movies?id = 1&handler = delete这样的URL。如果您希望用URL段替换查询参数,则将以下路由约束添加到@page指令,生成的URL将为/ Movies / delete / 1,

  1. @page "{handler?}/{id:int?}"

捆绑

页面上的@model指令指向页面模型类,因为如前所述,该类充当Razor页面的模型。这适用于读取属性,但为了在发布数据时填充它们(即,当使用除GET之外的动词时),我们需要使用属性[BindProperty]来标记要使用模型绑定的属性。

如何在ASP.NET Core 2.0中使用Razor页面的更多相关文章

  1. 避免在ASP.NET Core 3.0中为启动类注入服务

    本篇是如何升级到ASP.NET Core 3.0系列文章的第二篇. Part 1 - 将.NET Standard 2.0类库转换为.NET Core 3.0类库 Part 2 - IHostingE ...

  2. 如何在ASP.NET Core自定义中间件中读取Request.Body和Response.Body的内容?

    原文:如何在ASP.NET Core自定义中间件中读取Request.Body和Response.Body的内容? 文章名称: 如何在ASP.NET Core自定义中间件读取Request.Body和 ...

  3. 如何在ASP.NET Core Web API中使用Mini Profiler

    原文如何在ASP.NET Core Web API中使用Mini Profiler 由Anuraj发表于2019年11月25日星期一阅读时间:1分钟 ASPNETCoreMiniProfiler 这篇 ...

  4. ASP.NET Core 1.0 中的依赖项管理

    var appInsights=window.appInsights||function(config){ function r(config){t[config]=function(){var i= ...

  5. 在ASP.NET Core 1.0中如何发送邮件

    (此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 题记:目前.NET Core 1.0中并没有提供SMTP相关的类库,那么要如何从ASP.NE ...

  6. ASP.NET Core 1.0 中使用 Swagger 生成文档

    github:https://github.com/domaindrivendev/Ahoy 之前文章有介绍在ASP.NET WebAPI 中使用Swagger生成文档,ASP.NET Core 1. ...

  7. 用ASP.NET Core 1.0中实现邮件发送功能

    准备将一些项目迁移到 asp.net core 先从封装类库入手,在遇到邮件发送类时发现在 asp.net core 1.0中并示提供SMTP相关类库,于是网上一搜发现了MailKit 好东西一定要试 ...

  8. 在ASP.NET Core 2.0中使用CookieAuthentication

    在ASP.NET Core中关于Security有两个容易混淆的概念一个是Authentication(认证),一个是Authorization(授权).而前者是确定用户是谁的过程,后者是围绕着他们允 ...

  9. ASP.NET Core 3.0中使用动态控制器路由

    原文:Dynamic controller routing in ASP.NET Core 3.0 作者:Filip W 译文:https://www.cnblogs.com/lwqlun/p/114 ...

随机推荐

  1. 23-吝啬的国度(vector+深搜)

    吝啬的国度 时间限制:1000 ms  |  内存限制:65535 KB 难度:3   描述 在一个吝啬的国度里有N个城市,这N个城市间只有N-1条路把这个N个城市连接起来.现在,Tom在第S号城市, ...

  2. 用Hash Table(哈希散列表)实现统计文本每个单词重复次数(频率)

    哈希表在查找方面有非常大应用价值,本文记录一下利用哈希散列表来统计文本文件中每个单词出现的重复次数,这个需求当然用NLP技术也很容易实现. 一.基本介绍 1.Hash Key值:将每个单词按照字母组成 ...

  3. Laravel/Homestead storage:link -> symlink(): Protocol error

    I'm trying to run the following artisan command: php artisan storage:link I get this error: [ErrorEx ...

  4. Mybatis 实用篇(三)参数处理

    Mybatis 实用篇(三)参数处理 sql 语句中的参数 parameterType 可以省略不写. 一.参数封装 1.1 单个参数处理 public interface UserMapper { ...

  5. 快速完成网页设计,10个顶尖响应式HTML5网页模板助你一臂之力

    为了寻找一个优质的网页模板,网页设计师和开发者往往可能会花上大半天的时间.不过幸运的是,现在的网页设计师和开发人员已经开始共享HTML5,Bootstrap和CSS3中的免费网页模板资源.鉴于网站模板 ...

  6. http头部信息

    1.常见的返回码 100: 请服务器端继续返回 200:成功 301:永久重定向 存的地址永久的改变了  301 302 : 暂时重定向 302仍然使用老得url 401 : 无法找到资源file n ...

  7. RocketMQ 使用及常见问题

    前言 本文档是针对RocketMQ使用及常见问题的说明. 一.获取项目.安装包及文档 1. alibaba/RocketMQ https://github.com/alibaba/RocketMQ 2 ...

  8. windows7文件夹怎样默认图片大图显示?

    先打开一个含有图片的文件夹,在文件夹空白处右键选择属性,打开自定义选项卡. 确定自定义选项卡 显示的是:“优化此文件夹:图片”. 然后,选择:组织--文件夹和搜索选项--查看--文件夹视图,应用到文件 ...

  9. 苹果禁用UUID了,咋办?

    By now you have probably heard that Apple is deprecating support for attaining a UDID from an iOS de ...

  10. 打开窗口进行选择文件(txt文件),打开所选文件,读入文件

    用mfc编写项目的时候往往需要调用窗口,允许用户通过窗口进行选择文件操作 TCHAR szBuffer[MAX_PATH] = { 0 }; OPENFILENAME ofn = { 0 }; ofn ...