zoukankan      html  css  js  c++  java
  • ASP.NET Core Razor Pages 教程五 使用数据

    使用数据

    第一次使用数据时,你将重点关注于使用 BakeryContext 检索要在主页和订购页上显示的数据, 这些数据还没有添加到应用程序中。 提醒一下,主页应该类似于此处的 ASP.NET Web Pages 版本:
    Home

    所有产品的描述、图片和价格一起显示,随机选择其中一个产品作为特色产品出现在页面的顶部。

    管理数据的显示需要少量的准备工作。首先,将以下代码添加到位于 wwwroot/css 中的现有 site.css 文件中:

    body{
      color: #696969;
    }
    a:link {
      color: #3b3420;
      text-decoration: none;
    }
    
    a:visited {
      color: #3b3420;
      text-decoration: none;
    }
    
    a:hover {
      color: #a52f09;
      text-decoration: none;
    }
    
    a:active {
      color: #a52f09;
    }
    
    a.order-button, a.order-button:hover{
      color: #fdfcf7;
    }
    
    .productInfo, .action{
      max- 200px;
    }
    
    p{
      font-size: 0.8rem;
    }
    
    #orderProcess {
      list-style: none;
      padding: 0;
      clear: both;
    }
    
    #orderProcess li {
      color: #696969;
      display: inline;
      font-size: 1.2em;
      margin-right: 15px;
      padding: 3px 0px 0px 5px;
    }
    
    .step-number {
        background-color: #edece8;
        border: 1px solid #e6e4d9;
        font-size: 1.5em;
        margin-right: 5px;
        padding: 3px 10px;
    }
    
    .current .step-number {
        background-color: #a52f09;
        border-color: #712107;
        color: #fefefe;
    } 
    
    .orderPageList{
        padding-inline-start: 20px;
    }
    
    .actions .order-button{
      margin-left:20px;
    }
    

    PageModel

    现在, 打开 Pages/Index.cshtml.cs 文件, 并替换为以下的内容:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Bakery.Data;
    using Bakery.Models;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Mvc.RazorPages;
    using Microsoft.EntityFrameworkCore;
    
    namespace Bakery.Pages
    {
        public class IndexModel : PageModel
        {
            private readonly BakeryContext db;  
    
            public IndexModel(BakeryContext db) => this.db = db;
    
            public List<Product> Products { get; set; } = new List<Product>();  
            public Product FeaturedProduct { get; set; }  
    
            public async Task OnGetAsync()
            {
                Products = await db.Products.ToListAsync();
                FeaturedProduct = Products.ElementAt(new Random().Next(Products.Count));
            }
        }
    }
    

    这是 PageModel 文件。 PageModel 充当页面控制器和视图模型的组合。 作为控制器, 它的角色是处理来自请求的信息, 然后为视图准备一个模型(视图模型)。 页面模型(PageModel)和内容页面(视图)存在一对一的映射, 因此页面模型(PageModel)本身就是视图模型(viewmodel)。

    来自请求的信息在处理程序方法(handler methods)中处理。这个 PageModel 有一个处理方法 - OnGetAsync,它是由使用 GET 谓词发出的 HTTP 请求按照约定执行的。 该 PageModel 有一个名为 dbBakeryContext 类型私有字段。它还有一个接受 BakeryContext 对象作为参数的构造方法。参数值由依赖注入系统提供。 这种模式称为构造注入。 该参数被分配给构造函数中的私有字段(使用表达式主体)。

    该 PageModel 类有两个公共属性 - 一个产品列表和一个表示显示在页面顶部的特色产品的单个产品。 该列表由 OnGetAsync 方法中的以下代码填充:

    Products = await db.Products.ToListAsync();
    

    OnGetAsync 方法中的下一行代码将其中一个产品随机分配给 FeaturedProduct 属性:

    FeaturedProduct = Products.ElementAt(new Random().Next(Products.Count));
    

    内容页面

    现在是生成UI的时候了。 将 Index 内容页面(Pages/Index.cshtml)的内容替换为以下的代码:

    @page
    @model IndexModel
    @{
        ViewData["Title"] = "Home page";
    }
    
    <h1>Welcome to Fourth Coffee!</h1>
    
    <div id="featuredProduct" class="row"> 
        <div class="col-sm-8">
            <img alt="Featured Product" src="~/Images/Products/@Model.FeaturedProduct.ImageName" class="img-fluid rounded"/>
        </div>
        <div id="featuredProductInfo" class="col-sm-4">
            <div id="productInfo">
                <h2>@Model.FeaturedProduct.Name</h2>
                <p class="price">$@string.Format("{0:f}", Model.FeaturedProduct.Price)</p>
                <p class="description">@Model.FeaturedProduct.Description</p>
            </div>
            <div id="callToAction">
                <a class="btn btn-danger order-button" asp-page="/order" asp-route-id="@Model.FeaturedProduct.Id" title="Order @Model.FeaturedProduct.Name">Order Now</a>
            </div>
        </div>
    </div>
    
    <div id="productsWrapper" class="row">
    @foreach (var product in Model.Products)
    {
        <div class="col-sm-3">
            <a asp-page="/order" asp-route-id="@product.Id" title="Order @product.Name">
                <div class="productInfo">
                    <h3>@product.Name</h3>
                    <img class="product-image img-fluid img-thumbnail" src="~/Images/Products/Thumbnails/@product.ImageName" alt="Image of @product.Name" />
                    <p class="description">@product.Description</p>
                </div>
            </a>
    
            <div class="action">
                <p class="price float-left">$@string.Format("{0:f}", product.Price)</p>
                <a class="btn btn-sm btn-danger order-button float-right" asp-page="/order" asp-route-id="@product.Id" title="Order @product.Name">Order Now</a>
            </div>
        </div>
    }
    </div>
    

    页面顶部的 @model 指令指定页面模型(IndexModel)的类型。 您可以通过内容页面的 Model 属性使用 PageModel

    HTML 的顶部显示了特色产品。 底部部分循环遍历所有产品并显示它们的缩略图。 每个产品都包含一个超链接,样式类似于按钮(使用 Bootstrap 样式)。 虽然它还没有实质的链接目标, 但是超链接是由一个锚标记助手(anchor tag helper)生成的, 其中包括一个 asp-route 属性。 此属性用于将数据作为路由值传递到目标页 。添加 Order 页面之后就可以看到它是如何工作的了,当然了,那个是下一步要做。

    同时,通过在终端上执行 dotnet run 来测试应用程序,然后浏览到 https://localhost:5001 。主页应该是这样的:
    HomePage

    移动用户
    原始的 Web Pages Bakery 模板使用设备检测或浏览器嗅探来满足移动用户的需求。如果检测到用户使用移动设备(主要是从user-agent报头中找到的值推断出来的),则站点将切换到使用不同的布局文件(sitelayout.mobile.cshtml)。这种方法有两个问题:首先,您需要使您的设备检测库保持最新,否则它的失败可能比成功更多;其次,您需要维护站点布局文件和样式表的多个版本。
    如今,处理不同设备分辨率问题的解决方案是使用响应式设计(Responsive Design), 这种技术可以检测可用的屏幕大小,并相应地对内容进行回流。这个功能内置在Bootstrap中,您可以通过调整当前打开的浏览器的大小来了解它是如何工作的。当浏览器窗口宽度降至576px以下时,显示会发生巨大变化:
    mobile

    添加 Order 页面

    在终端中执行以下命令添加一个新页面:

    dotnet new page --name Order --namespace Bakery.Pages --output Pages
    

    打开刚刚新创建的 Order.cshtml.cs 文件并替换其内容为以下代码:

    using System;
    using System.Threading.Tasks;
    using Bakery.Data;
    using Bakery.Models;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Mvc.RazorPages;
    
    namespace Bakery.Pages
    {
        public class OrderModel : PageModel
        {
            private BakeryContext db;
    
            public OrderModel(BakeryContext db) => this.db = db;
    
            [BindProperty(SupportsGet =true)]
            public int Id { get; set; }
    
            public Product Product { get; set;}
    
            public async Task OnGetAsync() =>  Product = await db.Products.FindAsync(Id);
        }
    }
    

    同样,BakeryContext 被注入到 PageModel 构造函数中。 公共属性 Product 在 OnGetAsync 方法中实例化。 FindAsync 方法接受一个值, 该值表示要返回的实体的主键。 在这种情况下, 传递给 FindAsync 方法的参数是另一个公共属性 - Id。 但是它获取的值从哪里来呢?

    Id 属性(property,类的属性)使用 BindProperty属性(attribute,注解用的属性)进行修饰。该属性(attribute)确保类的属性(property)包含在模型绑定过程中,这将导致作为HTTP请求的一部分传递的值映射到 PageModel 属性和处理程序方法参数。 默认情况下, 模型绑定只对 POST 请求中传递的值有效。 通过单击主页上的链接可以到达 Order 页面, 这将导致 GET 请求。您必须添加 SupportsGet = true 来选择对 GET 请求进行模型绑定。

    如果您还记得的话,链接到 Order 页面的主页上的锚标记助手包括一个 asp-route-id 属性, 它表示一个名为 id 的路由值。 路由值作为URL的一部分传递。 如果接收页面定义了匹配的路由参数, 该值将作为 URL 的一部分传递, 例如 order/3。 否则, 它将作为查询字符串值传递:order?id=3。 无论哪种方式, 传入的值都将绑定到 Id 属性。

    接下来,修改 Order.cshtml 的内容如以下所示代码:

    @page "{id:int}"
    @model Bakery.Pages.OrderModel
    @{
        ViewData["Title"] = "Place Your Order";
    }
    <ol id="orderProcess">
        <li><span class="step-number">1</span>Choose Item</li>
        <li class="current"><span class="step-number">2</span>Details &amp; Submit</li>
        <li><span class="step-number">3</span>Receipt</li>
    </ol>
    <h1>Place Your Order: @Model.Product.Name</h1>
    

    代码第一行包含 @page 指令, 这是该页面成为 Razor Page 的原因,它还包含以下内容: "{id:int}"。 这是一个路由模板。 这是你在页面定义路由参数的位置。 这个模板定义了一个名为 id 的参数(这将导致主页上的锚标记助手以 id 值作为段生成 url)。 你还添加了一个约束, 在本例中, 你已经指定了 id 的值必须是整数类型(:int)。 基本上,这意味着除非提供 id 路由参数的值,否则无法到达 Order 页面。

    现在如果你运行应用程序并点击主页上的的某一个按钮, Order页面将显示所选择产品的名称:
    product

    摘要

    您已成功使用 BakeryContext 连接到数据库并检索已分配 给PageModel 属性的数据。 它们通过内容页面中的 Model 属性公开,您可以在其中循环显示产品集合以显示它们。 您还在本节中看到了如何在URL中传递数据并利用 BindProperty 属性将路由值映射到 PageModel 中的公共属性。 最后,您已经了解了如何使用该值来查询特定项目,以便您可以显示它的详细信息。

    在下一部分中,您将允许用户通过表单提供订单的联系方式和发货详情。

  • 相关阅读:
    Apache Flink教程
    开发EasyRTSPServer组件时如何使用ffserver搭建一套RTSP流媒体服务器并分发RTSP视频流?
    【解决方案】用科技的力量构筑“食品安全”防火墙,明厨亮灶保护“舌尖上的安全”
    RTSP/GB28181视频智能分析人脸识别系统EasyCVR除人脸门禁外还可以运用到哪些方向?
    GB28181/RTSP/SDK/Ehome协议安防视频融合平台EasyCVR新增分组管理功能操作介绍
    【解决方案】RTSP/GB28181协议视频平台EasyCVR在烟草行业是如何搭建一套网络视频监控系统的?
    【解决方案】RTSP/GB28181协议视频融合监控平台EasyCVR在三维可视化系统中的应用
    linux 学习随记---设置日志时间戳
    服务器端口总结
    (转载)PowerShell因为在此系统中禁止执行脚本解决方法
  • 原文地址:https://www.cnblogs.com/mahidol/p/10422884.html
Copyright © 2011-2022 走看看