ASP.NET Core Razor 页面开发应用指南

在这里插入图片描述

如果您一直在使用 ASP.NET MVC 开发 Web 应用程序,那么您会同意我的观点,要创建一个简单的页面,您必须创建一个控制器类、一个操作方法、一个模型类、一个 Razor 视图以及可选的自定义路由和所有这些对于一个简单的页面来说似乎太过仪式了。更糟糕的是,您通常会在 Controllers 文件夹中创建一个 Controller 类,在 Models 文件夹中创建一个 Model 对象,在 Views 文件夹中创建一个 Razor 视图,并且您需要在 Visual Studio 解决方案资源管理器中从一个文件夹跳转到另一个文件夹。一整天。微软在 ASP.NET Core 2.0 中引入了一种名为 Razor Pages 的新编程模型,它减少了所有这些仪式并简化了实现页面焦点场景的过程。在本教程中,我将详细介绍 Razor Pages,希望如果您跟随我的脚步,您将能够更有信心地在您的应用程序中使用 Razor Pages。

下载:Download Source Code

什么是Razor页面?

Razor 页面是类似于 PHP 文件、XAML 控件或 ASP.NET Web 窗体的自包含文件,与 MVC 相比,它们采用不同的方法来使用 ASP.NET Core 构建网页。它们允许开发人员直接在单个文件中混合 HTML 和服务器端 C#,而无需创建控制器、视图模型等。这些页面可以与同一项目中的传统 MVC 和 Web API 控制器共存,可用于以下场景:您需要构建没有太多逻辑的简单页面。理想的候选人可以是关于我们、联系我们和站点地图页面。如果您不喜欢在单个文件中混合 HTML 和 C#,或者您的页面逻辑变得越来越复杂,那么您还可以将 C# 代码放在附加到 Razor 页面的单独文件中。这与我们过去在 ASP.NET Web Forms 中的想法几乎相似,我们将所有 C# 代码添加到代码隐藏文件中。

Razor 页面与 MVC

ASP.NET MVC 应用程序基于传统的模型-视图-控制器 (MVC) 模式,该模式要求您将所有代码放在控制器中,在控制器中构建模型,然后将这些模型传递给我们可以呈现或使用它们的视图根据我们的要求。在大多数情况下,您最终会在不同的文件夹中创建多个文件(与一个页面或功能相关),从一个文件导航到另一个文件以在某个页面上实现功能会降低您的工作效率。这并不意味着您需要完全转储 MVC 并将您的完整应用程序迁移到 Razor Pages。 Razor Pages 仅适用于简单的以页面为中心的场景,如果您正在构建具有大量功能的复杂页面,您仍然必须坚持 MVC 模式。
在这里插入图片描述
您可能在 MVC 应用程序中注意到的另一个常见做法是在几乎所有控制器中对类似操作进行分组。这些操作的数量也会随着您的应用程序的增长而增加,我见过人们在单个控制器中拥有近 100 多个操作的示例。典型的 AccountController 通常具有以下操作。在这里插入图片描述
您可以在上面的 AccountController 中轻松看到单个页面,例如登录页面通常需要两个具有不同 HTTP 动词 GET 和 POST 的操作。这些操作也是高度耦合的,因为大多数时候它们需要类似的初始化逻辑、相同的视图模型,甚至是相同的 Razor 视图。 Razor Pages 允许您在单个页面代码隐藏类中组合 GET 和 POST 方法(在 Razor Pages 术语中称为页面处理程序),您还可以根据需要创建其他处理程序。在这里插入图片描述
MVC 和 Razor Pages 之间的一些常见区别如下:

MVC Razor Pages
MVC 控制器继承自控制器类。 公共类 HomeController : 控制器 Razor Pages Page Model(代码隐藏)类继承自 PageModel 类。 公共类 HomePageModel : PageModel
当 Razor 视图与控制器一起使用时,它们中没有 @page 指令 当 Razor 视图用作 Razor 页面时,它们需要在其中包含 @page 指令。
在 MVC 模式中,我们通常创建一个单独的 View Model 类,然后将该类从 Controller 传递给 Razor View 在 Razor 视图中,我们不必创建单独的视图模型。我们可以在 Page Model 类中创建属性,并且可以将 Page Model 类同时用作迷你 Controller 和 View Model。
当您的内容围绕实际页面的想法构建并且您不想将完整的 MVC 框架用于简单页面(例如联系我们、关于我们等)时,Razor 页面是不错的选择。 MVC 控制器更适合繁重和更复杂的任务,例如产品目录和数据库相关任务。

Razor 页面入门

Razor 页面是物理 .cshtml 文件,要创建 Razor 页面,您需要在项目中创建一个 Pages 文件夹。这是惯例,但如果您想创建一个具有其他名称的文件夹,则必须告诉 ASP.NET Razor 页面所在的位置。如果您使用的是 Visual Studio 2019,则只需右键单击解决方案资源管理器中的 Pages 文件夹,然后从上下文菜单中选择 Razor Pages... 选项。在这里插入图片描述
系统会要求您提供一个名称和一些其他选项,这些选项将允许您使用您的页面生成页面模型(代码隐藏)类,指定页面的布局等。在这里插入图片描述
Visual Studio 将生成以下 .cshtml 文件

@page
@model AspNetCoreRazorPagesDemo.ProductsModel
@{
    Layout = null;
}
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Products</title>
</head>
<body>
</body>
</html>

还将为您生成相应的页面模型类。

namespace AspNetCoreRazorPagesDemo
{
    public class ProductsModel : PageModel
    {
        public void OnGet()
        {
 
        }
    }
}

如果不想为 Razor 页面使用单独的代码文件,可以从 Razor 页面视图 (cshtml) 文件中删除以下行,然后直接在视图中开始编写 C# 代码。

@model AspNetCoreRazorPagesDemo.ProductsModel

Razor 页面中的另一条重要代码是 @page 指令,它指定此视图不是普通的 Razor 视图,而是一个 Razor 页面。

@page

Razor Pages 中的路由

在幕后,Razor Pages 使用与 MVC 相同的路由基础结构,但与配置相关的差异很少。对于 MVC 和 Web API 应用程序,我们有基于约定的路由,这意味着传入的 URL 将直接与控制器和操作匹配。例如,URL /Products/Index 将与 MVC 中 Products 控制器的以下操作方法匹配。

public class ProductsController : Controller
{
    public IActionResult Index()
    {
 
    }
}

访问 Razor 页面更加简单;由于默认情况下不涉及路由,磁盘上文件的路径用于计算 URL 并决定需要在浏览器中提供哪个 Razor 页面。例如,以下 URL 将显示 /Pages 文件夹中可用的 Razor Page Products.cshtml

/Products

如果您在 Pages/Admin/Login.cshtml 中有一个 Razor 页面,那么您可以使用以下 URL 访问它。

/Admin/Login

下表将演示不同的 URL 如何在您的 Pages 文件夹中获取不同的 Razor 页面。

File or Path Matching URL
Pages/Index.cshtml /Index or /
Pages/ProductsList.cshtml /ProductsList
Pages/Products/List.cshtml /Products/List
Pages/Products/Index.cshtml /Products/Index or /Products

您可能想知道,框架如何知道 /Admin/Login 是 Razor 页面,而不是位于 AdminController 中的名称为 Login 的操作方法。这是因为您需要使用新的端点路由机制在 Startup.cs 文件中显式启用 Razor 页面的路由:

app.UseEndpoints(endpoints =>
{
    endpoints.MapRazorPages();
});

最后但并非最不重要的一点是,您还必须使用 AddRazorPages 方法在 Startup.cs 文件中注册 Razor Pages 所需的服务。

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
    services.AddRazorPages();
}

现在是在浏览器中运行页面的时候了,所以让我们在 razor 视图中添加一个简单的标题并运行您的项目。要访问我们刚刚在上面创建的 Products Razor 页面,请在您的浏览器 URL 中紧跟您站点的主 URL 之后键入 /Products,您将看到以下页面呈现在浏览器中。在这里插入图片描述
Razor 页面模型类
如上所述,有一个与 Razor 页面相关联的页面模型类,这个类同时充当迷你控制器和视图模型。此类必须从 Microsoft.AspNetCore.Mvc.RazorPages 命名空间中可用的 PageModel 类继承。此类提供以下基本属性:

  • HttpContext:这是我们常用的 HttpContext 对象,可在所有 ASP.NET Core Web 应用程序中使用。
  • ModelState:获取包含模型状态和模型绑定验证状态的 ModelStateDictionary。
  • PageContext:提供对当前处理程序方法的访问(如果 任何),加上价值提供者和视图开始工厂集合
  • Request:从HttpContext.Request 可用的常用 HttpRequest 对象
  • Response:从 HttpContext.Response可用的常用 HttpResponse 对象
  • RouteData:MVC 控制器中可用的相同 RouteData 对象
  • TempData: MVC 控制器中可用的相同 ITempDataDictionary 对象
  • ViewData:MVC 控制器中可用的相同ViewDataDictionary 对象

请注意,如果您不想使用自定义页面模型类,您仍然可以使用@function 指令直接在 .cshtml 文件中指定处理程序方法,如下所示:

@functions 
{
    public void OnGet()
    {
 
    }
    public void OnPost()
    {
 
    }
}

让我们考虑以下示例,其中我在 ProductsModel 类中声明并设置了属性“Message

public class ProductsModel : PageModel
{
    public string Message { get; set; }
 
    public void OnGet()
    {
        this.Message = "Hello World";
    }
}

以上属性“Message”现在在您的 RazorPage .cshtml 文件中可用,可以按如下方式使用:

<h2>@Model.Message</h2>

使用 Razor 页面处理程序

在上面的例子中,我在 ProductsModel 类中实现了 OnGetOnPost 方法。这些方法称为页面处理程序,按照惯例,OnGet 和 OnPost 页面处理程序将分别处理 HTTP GET 和 POST 方法。如果您想在应用程序中使用异步编程技术,这些方法还有异步版本,名称为 OnGetAsyncOnPostAsync
在项目中实现这些页面处理程序时,需要牢记以下几点:

  • 可以定义 OnGet、OnPost、OnDelete 等来处理它们对应的 HTTP 方法 GET、POST、DELETE 等。
public void OnGet()
{
 
}
public void OnPost()
{
 
}
public void OnDelete()
{
 
}
  • 这些页面处理程序中的每一个都必须以 On 字开头,后跟 HTTP 方法 GET、POST 等。如果您在开始时定义没有 On 字的页面处理程序,您的方法将不会执行。
  • 这些页面处理程序的返回类型必须是 void 或 IActionResult
  • 如果我们正在实现异步页面处理程序,则该方法必须返回 Task 或 Task 并可选择对其应用 async 关键字,并且它应以 Async 后缀结尾。
public async Task<IActionResult> OnGetAsync()
{
   
}
  • 我们不能同时定义异步和同步处理程序方法
  • 也不允许为同一个 HTTP 动词定义多个重载
  • 处理程序方法可以采用具有默认值的基本类型参​​数,也可以接受复杂类型。它们还可以采用 IFormCollection 参数。

Razor 页面中的模型绑定

如果您使用过 ASP.NET MVC 控制器,那么您可能已经知道 MVC 控制器中的那些操作方法具有内置的数据绑定机制。 action 方法的参数会自动与传入请求的查询字符串或请求参数绑定。 Razor Pages 并非如此。在 Razor Pages 中,您必须使用 [BindProperty] 属性明确指定要绑定的 PageModel 类的哪些属性。

[BindProperty]
public string Email { get; set; }

如果您的模型中有太多属性,那么您可以在整个类上使用 [BindProperties] 属性,而不是为每个属性指定 [BindProperty]。

[BindProperties]
public class UserViewModel
{
    public string Email { get; set; }
    public string Password { get; set; }
}

另请注意,使用上述任一属性绑定的属性仅在非 GET 页面处理程序(例如 OnPost、OnDelete 等)中可用。如果您想在 OnGet 页面处理程序中使用绑定,则需要将 SupportsGet 属性显式设置为如下图:

[BindProperties (SupportsGet = true)]
public class UserViewModel
{
    public string Email { get; set; }
    public string Password { get; set; }
}

以下是完整的登录页面示例,展示了页面模型类如何使用嵌套在其中的模型类以及如何绑定模型类属性

namespace AspNetCoreRazorPagesDemo
{
    public class LoginModel : PageModel
    {
        [BindProperty]
        public UserViewModel User { get; set; }
         
        public IActionResult OnGet()
        {
            return Page();
        }
 
        public IActionResult OnPost(UserViewModel model)
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }
 
            ViewData["Email"] = User.Email;
 
            return Page();
        }
 
        [BindProperties (SupportsGet = true)]
        public class UserViewModel
        {
            public string Email { get; set; }
            public string Password { get; set; }
        }
    }
}

以下代码显示了上述登录页面的 Razor 视图

@page
@model AspNetCoreRazorPagesDemo.LoginModel
@{
    Layout = "_Layout";
}
 
<!DOCTYPE html>
 
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Login</title>
</head>
<body>
 
    <form class="form-horizontal" method="post">
        @Html.AntiForgeryToken()
        <div class="form-group">
            <label for="Email" class="col-sm-2">Email</label>
            <div class="col-sm-10">
                <input type="text" class="form-control" name="Email">
            </div>
        </div>
        <div class="form-group">
            <label for="Password" class="col-sm-2">Password</label>
            <div class="col-sm-10">
                <input type="password" class="form-control" name="Password">
            </div>
        </div>
        <div class="form-group">
            <div class="col-sm-offset-2 col-sm-10">
                <input type="submit" class="btn btn-dark" value="Login" />
            </div>
        </div>
    </form>
 
<div>@ViewData["Email"]</div>
</body>
</html>

如果您将运行上面的 Razor Page 示例,您将能够在浏览器中看到以下输出。在这里插入图片描述

总结概括

您现在有两个选项可以在 ASP.NET Core 中创建 Web 应用程序,因此应该预先决定是使用 MVC 还是 Razor Pages,因为它们之间存在许多差异。使用 MVC 多年的开发人员可能不喜欢 Razor Pages,因为他们认为 Razor Pages 更适合来自以页面为中心的开发框架和编程语言(如 PHP)的开发人员。如果您正在使用 Razor 创建一个新应用程序,强烈建议您考虑将 Razor Pages 作为默认方法。在本教程中,试图为您深入介绍 Razor Pages。

posted @ 2021-07-23 09:43  cool2feel  阅读(1582)  评论(0编辑  收藏  举报