【ASP.NET Core笔记】 使用razor pages构建网站

使用ASP.NET Core Razor Pages 构建网站

sqlite 北风数据库

1. Northwind.Common.DataContext.Sqlite

d32927bd1447fd1558a30bcc85eb295b.png


是Sqlite的数据库上下文,有三个类:
ConsoleLogger.cs
NorthwindContext.cs
NorthwindContextExtensions.cs

1.1 NorthwindContext 继承自 Microsoft.EntityFrameworkCore.DbContext

1.1.1 定义了表结构实例

表结构 表实例
类别表 DbSet<Category> Categories
消费者表 DbSet<Customer> Customers
雇员表 DbSet<Employee> Employees
员工地域 DbSet<EmployeeTerritory> EmployeeTerritories
订单表 DbSet<Order> Orders
订单详情表 DbSet<OrderDetail> OrderDetails
产品表 DbSet<Product> Products
托运人 DbSet<Shipper> Shippers
供应商 DbSet<Supplier> Suppliers
地域表 DbSet<Territory> Territories

1.1.2模型创建 OnModelCreating() 函数

protected override void OnModelCreating(ModelBuilder modelBuilder)//模型创建
{ //订单详情:多个主键,用FLUENT API 来定义
    modelBuilder.Entity<OrderDetail>(entity =>
    {   //两个主键
        entity.HasKey(e => new { e.OrderId, e.ProductId }); //订单ID、产品ID
        //一个订单有多个订单详情
        entity.HasOne(d => d.Order)
            .WithMany(p => p.OrderDetails)
            .HasForeignKey(d => d.OrderId)//外键:订单ID
            .OnDelete(DeleteBehavior.ClientSetNull);
        //1个产品可以有多个订单详情
        entity.HasOne(d => d.Product)
            .WithMany(p => p.OrderDetails)
            .HasForeignKey(d => d.ProductId)//外键:产品ID
            .OnDelete(DeleteBehavior.ClientSetNull);//配置删除主体或切断关系时应用于关系中依赖实体的操作。
    });
    //产品
    modelBuilder.Entity<Product>() //产品单价转为double
        .Property(product => product.UnitPrice)
        .HasConversion<double>(); 

    OnModelCreatingPartial(modelBuilder);
}

1.2 ConsoleLogger.cs

控制台日志输出功能

1.3 NorthwindContextExtensions.cs

将 NorthwindContext 添加到指定的 IServiceCollection。使用 Sqlite 数据库提供程序。

2. Northwind.Common.EntityModels.Sqlite

8cd76f7c9cf0f01bbd4c3bca9e13ca03.png


2.1 实体的C#类

实体模型表 加粗字段为实体集合需要在类的构造函数中初始化,例如:Customer 类的 Orders

public Customer()
        {   //初始化订单
            Orders = new HashSet<Order>();
        }

粗斜体 为实体对象

实体 文件 成员
类别 Category.cs CategoryId、CategoryName、Description、Picture 、Products
消费者 Customer.cs CustomerId、CompanyName、ContactName、ContactTitle、Address、City、Region、PostalCode、Country、Phone、 Fax、Orders
雇员 Employee.cs EmployeeId、LastName、FirstName、Title、TitleOfCourtesy、BirthDate、HireDate、Address、City、Region、PostalCode、Country、HomePhone、Extension、Photo、Notes、ReportsTo、PhotoPath、Orders
员工地域 EmployeeTerritory.cs EmployeeId、TerritoryId
订单 Order.cs OrderId、CustomerId、EmployeeId、OrderDate、RequiredDate、ShippedDate、ShipVia、Freight、ShipName、ShipAddress、ShipCity、ShipRegion、ShipPostalCode、ShipCountry、CustomerEmployeeShipViaNavigationOrderDetails
订单详情 OrderDetail.cs OrderId、ProductId、UnitPrice、Quantity、Discount、OrderProduct
产品 Product.cs ProductId、ProductName、SupplierId、CategoryId、QuantityPerUnit、UnitPrice、UnitsInStock、UnitsOnOrder、ReorderLevel、Discontinued、CategorySupplierOrderDetails
托运人 Shipper.cs ShipperId、CompanyName、Phone、Orders
供应商 Suppliers.cs SupplierId、CompanyName、ContactName、ContactTitle、Address、City、Region、PostalCode、Country、Phone、Fax、HomePage、Products
地域 Territory.cs TerritoryId、TerritoryDescription、RegionId

2.2 特性

[Key]
设置主键
[Required]
非空,必须有
[Column(TypeName = "nvarchar (15)")]
设置与数据库列对应的属性,数据格式
[StringLength(15)]
自定字段允许的最小和最大字符长度
[InverseProperty(nameof(Product.Supplier))]
指定表示同一关系另一端的导航属性的反转
[Index(nameof(CompanyName), Name = "CompanyNameSuppliers")]
指定要在数据库中生成的索引。
[ForeignKey(nameof(CategoryId))]
外键:类别ID
[Table("Order Details")]
指定类映射到的数据库表。

3. Northwind.Razor.Employees 类库

1f0db8a3268f3caa1c92cf910b82ecf8.png


雇员查询网页razor page.

ef185548253ef79cada32a3db18f225f.png

<!--单个雇员_Employee.cshtml-->
@model Packt.Shared.Employee
<div class="card border-dark mb-3" style="max-width: 18rem;">
  <div class="card-header">@Model?.LastName, @Model?.FirstName</div>
  <div class="card-body text-dark">
    <h5 class="card-title">@Model?.Country</h5>
    <p class="card-text">@Model?.Notes</p>
  </div>
</div>
<!--_ViewStart.cshtml 指定共享布局-->
@{
  Layout = "_Layout";
}
<!-- Employees.cshtml 雇员列表-- >
@page
@using Packt.Shared
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 
@model PacktFeatures.Pages.EmployeesPageModel
<div class="row">
  <h1 class="display-2">Employees</h1>
</div>
<div class="row">
@foreach(Employee employee in Model.Employees)
{
  <div class="col-sm-3">
    <partial name="_Employee" model="employee" />
  </div>
}
</div>
//查询雇员
using Microsoft.AspNetCore.Mvc.RazorPages; // PageModel
using Packt.Shared; // Employee, NorthwindContext


namespace PacktFeatures.Pages;


public class EmployeesPageModel : PageModel
{
  private NorthwindContext db;


  public EmployeesPageModel(NorthwindContext injectedContext)
  {
    db = injectedContext;
  }


  public Employee[] Employees { get; set; } = null!;


  public void OnGet()
  {
    ViewData["Title"] = "Northwind B2B - Employees";
    Employees = db.Employees.OrderBy(e => e.LastName)
      .ThenBy(e => e.FirstName).ToArray();
  }
}

4. Northwind.Web

c361e3fa1831b9d3a05a5d442e7014e2.png


双击项目在编辑器中打开.csproj 文件可看到Web SDK已引用:
<Project Sdk="Microsoft.NET.Sdk.Web">

添加项目引用

  • Northwind.Common.DataContext.Sqlite\Northwind.Common.DataContext.Sqlite.csproj

  • 1Northwind.Razor.Employees\Northwind.Razor.Employees.csproj

4.1 Program.cs 有一个Main方法作为入口点

使用默认值配置 Microsoft.Extensions.Hosting.IHostBuilder 以托管 Web 应用程序。这应该在应用程序特定配置之前调用,以避免它覆盖提供的服务、配置源、环境、内容根等。

一个 ASP.NET Core 项目就像一个顶级控制台应用程序,以一个隐藏的 Main 方法作为其入口点,该方法有一个使用名称 args 传递的参数。

//对 Run 方法的调用是一个阻塞调用,因此隐藏的 Main 方法在 web 服务器停止运行之前不会返回,如以下代码所示:
    Host.CreateDefaultBuilder(args).ConfigureWebHostDetails(webBuilder => 
    {
        webBuilder.UseStartup<Startup>();//指定 Web 主机要使用的启动类型。
    }).Build().Run();

4.2 Startup.cs 进一步配置网页

using Packt.Shared; // AddNorthwindContext extension method
using static System.Console;
namespace Northwind.Web;

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddRazorPages();//将页面的服务添加到指定的 Microsoft.Extensions.DependencyInjection.IServiceCollection。

        services.AddNorthwindContext();//将 NorthwindContext 添加到指定的 IServiceCollection。使用 Sqlite 数据库提供程序。
    }

    public void Configure(
      IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (!env.IsDevelopment())//检查当前主机环境名称是否为 Microsoft.Extensions.Hosting.EnvironmentName.Development。
        {
            app.UseHsts();//添加使用 HSTS 的中间件,它添加了 Strict-Transport-Security 标头。
        }

        app.UseRouting(); // 开始端点路由 start endpoint routing

        /*将内联定义的中间件委托添加到应用程序的请求管道。
        如果您不调用下一个函数,请改用 Microsoft.AspNetCore.Builder.RunExtensions.Run(Microsoft.AspNetCore.Builder.IApplicationBuilder,Microsoft.AspNetCore.Http.RequestDelegate)。
        更喜欢使用 Microsoft.AspNetCore.Builder.UseExtensions.Use(Microsoft.AspNetCore.Builder.IApplicationBuilder,System.Func{Microsoft.AspNetCore.Http.HttpContext,Microsoft.AspNetCore.Http.RequestDelegate,System.Threading.Tasks.Task})
         // 为了获得更好的性能,如下所示:*/
        app.Use(async (HttpContext context, Func<Task> next) =>
        {   //表示可用于 URL 匹配或 URL 生成的 Microsoft.AspNetCore.Http.Endpoint。
            RouteEndpoint? rep = context.GetEndpoint() as RouteEndpoint;//获取当前请求的 Microsoft.AspNetCore.Http.Endpoint 的扩展方法
            if (rep is not null)
            {
                WriteLine($"Endpoint name: {rep.DisplayName}");//获取此端点的信息显示名称。
                WriteLine($"Endpoint route pattern: {rep.RoutePattern.RawText}");//获取解析路由模式时提供的原始文本。可能为空。
            }

            if (context.Request.Path == "/bonjour")
            {
                // in the case of a match on URL path, this becomes a terminating
                // delegate that returns so does not call the next delegate
                // 在 URL 路径匹配的情况下,这将成为返回的终止委托,因此不会调用下一个委托
                await context.Response.WriteAsync("Bonjour Monde!");//你好世界
                return;
            }

            //我们可以在调用下一个委托之前修改请求 we could modify the request before calling the next delegate
            await next();
            //我们可以在调用下一个委托后修改响应 we could modify the response after calling the next delegate
        });

        app.UseHttpsRedirection();//添加用于将 HTTP 请求重定向到 HTTPS 的中间件。

        app.UseDefaultFiles(); //在当前路径上启用默认文件映射 index.html, default.html, and so on
        app.UseStaticFiles();//为当前请求路径启用静-态文件服务

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapRazorPages();//将 Razor Pages 的终结点添加到 Microsoft.AspNetCore.Routing.IEndpointRouteBuilder。
            //将 Microsoft.AspNetCore.Routing.RouteEndpoint 添加到与指定模式的 HTTP GET 请求匹配的 Microsoft.AspNetCore.Routing.IEndpointRouteBuilder。
            endpoints.MapGet("/", () => "Hello World!");//该网站将以纯文本响应所有 HTTP GET 请求:Hello World!。
        });
    }
}

4.3 共享布局

4.3.1 布局文件:Pages/Shared/_Layout.cshtml

<!doctype html>
    <html lang="en">

    <head>
    <!-- Required meta tags必需的元标记 -->
    <meta charset="utf-8" />
    <meta name="viewport" content=
        "width=device-width, initial-scale=1, shrink-to-fit=no" />

    <!-- Bootstrap CSS 样式 -->
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-KyZXEAg3QhqLMpG8r+8fhAXLRk2vvoC2f3B09zVXn8CA5QIVfZOJ3BCsw2P0p/We" crossorigin="anonymous">

    <title>@ViewData["Title"]</title>
    </head>

    <body>
        <div class="container">
            @RenderBody()
            <hr />
            <footer>
                <p>Copyright &copy; 2021 - @ViewData["Title"]</p><!-- @ViewData["Title"],使用该布局的页面的变量 -->
            </footer>
        </div>

        <!-- JavaScript to enable features like carousel 启用轮播等功能的 JavaScript -->
        <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-U1DAWAznBHeqEIlVSCgzq+c9gqGAJn5c/t99JyeKa9xxaYpSvHU5awsuZVVFIhvj" crossorigin="anonymous"></script>

        @RenderSection("Scripts", required: false)<!-- 在布局页,渲染名为 Scripts 的部分 -->

    </body>
    </html>

4.3.2 _ViewStart.cshtml设置所有 Razor 页面(和所有 MVC 视图)的默认布局文件

@{
    Layout = "_Layout";
    }

4.4 索引页面

一些按钮,以及链接href

a4fb6fc63617b900d7a22bfb037b8fb3.png

@page

    @functions
    {
        public string? DayName { get; set; } //日期参数

        public void OnGet()
        {
            ViewData["Title"] = "Northwind B2B";

            Model.DayName = DateTime.Now.ToString("dddd");
        }
    }
    <div class="jumbotron">
    <h1 class="display-3">Welcome to Northwind B2B</h1>
    <p class="lead">We supply products to our customers.</p>-
    <hr />
    <p>It's @Model.DayName! Our customers include restaurants, hotels, and cruise lines.</p>
    <p>
        <a class="btn btn-primary" href="suppliers">
        Learn more about our suppliers
        </a>
    </p>
    <p>
        <a class="btn btn-primary" href="packtfeatures/employees">
        Contact our employees
        </a>
    </p>
    <p>
        <a class="btn btn-primary" href="orders">
        How many orders have we taken?
        </a>
    </p>
    <p>
        <a class="btn btn-primary" href="customers">
        Our customers are global
        </a>
    </p>
    <p>
        <a class="btn btn-primary" href="functions">
        Play with functions
        </a>
    </p>
    </div>

4.5 订单页面

注入数据库上下文,没有cs文件

6ec8ed9848e8c75a81f65756730ec630.png

@page
@using Packt.Shared
@inject NorthwindContext db
@{
  string title = "Orders";
  ViewData["Title"] = $"Northwind B2B - {title}";
}
<div class="row">
  <h1 class="display-2">@title</h1>
  <p>
    There are @db.Orders.Count() orders in the Northwind database.
  </p>
</div>

4.6 供应商

页面显示供应商表格

94b534a8187699a18a86742437cc82db.png

@page
@using Packt.Shared
@model Northwind.Web.Pages.SuppliersModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<div class="row">
  <h1 class="display-2">Suppliers</h1>
  <table class="table">
    <thead class="thead-inverse">
      <tr>
        <th>Company Name</th>
        <th>Country</th>
        <th>Phone</th>
      </tr>
    </thead>
    <tbody>
    @if (Model.Suppliers is not null)
    {
      @foreach(Supplier s in Model.Suppliers)
      {
        <tr>
          <td>@s.CompanyName</td>
          <td>@s.Country</td>
          <td>@s.Phone</td>
        </tr>
      }
    }
    </tbody>
  </table>
</div>
<div class="row">
  <p>Enter details for a new supplier:</p>
  <form method="POST">
    <div><input asp-for="Supplier.CompanyName" placeholder="Company Name" /></div>
    <div><input asp-for="Supplier.Country" placeholder="Country" /></div>
    <div><input asp-for="Supplier.Phone" placeholder="Phone" /></div>
    <input type="submit" />
  </form>
</div>

SuppliersModel 继承自PageModel

using Microsoft.AspNetCore.Mvc.RazorPages; // PageModel
using Packt.Shared; // NorthwindContext
using Microsoft.AspNetCore.Mvc; // [BindProperty], IActionResult

namespace Northwind.Web.Pages;

public class SuppliersModel : PageModel
{
    public IEnumerable<Supplier>? Suppliers { get; set; }

    private NorthwindContext db;

    public SuppliersModel(NorthwindContext injectedContext)
    {
        db = injectedContext;
    }

    public void OnGet()
    {
        ViewData["Title"] = "Northwind B2B - Suppliers";

        Suppliers = db.Suppliers
          .OrderBy(c => c.Country).ThenBy(c => c.CompanyName);
    }

    [BindProperty]
    public Supplier? Supplier { get; set; }// = null!;

    public IActionResult OnPost() //提交查询内容
    {
        if ((Supplier is not null) && ModelState.IsValid)//获取一个值,该值指示此模型状态字典中的任何模型状态值是否无效或未经验证。
        {
            db.Suppliers.Add(Supplier);//添加供应商
            db.SaveChanges();
            return RedirectToPage("/suppliers");//重定向到页面,刷新数据
        }
        else
        {
            return Page(); // return to original page
        }
    }
}

4.7 函数计算器页面

20b47c50ba77c344c6c8bbb451c93303.png

@page
@using Northwind.Web.Pages
@using Packt.Shared
@model FunctionsModel
@{
    string title = "Functions";
    ViewData["Title"] = $"Northwind B2B - {title}";//共享布局参数

    string collapsedTimesTable = Model.TimesTableNumberInput.HasValue ? string.Empty : "collapse";
    string collapsedCalculateTax = Model.Amount.HasValue ? string.Empty : "collapse";
    string collapsedFactorial = Model.FactorialNumber.HasValue ? string.Empty : "collapse";
    string collapsedFibonacci = Model.FibonacciNumber.HasValue ? string.Empty : "collapse";
}
<div class="row">
    <h1 class="display-2">@title</h1>
    <div>
        <h2>Exercise 14.3 – Practice building web pages for console apps</h2>
        <div>Provide a web user interface to output times tables, calculate tax, and generate factorials and the Fibonacci sequence.</div>
    </div>
    <div class="accordion" id="accordionFunctions"> <!--  -->
        <div class="accordion-item">
             <!-- 按钮 -->
            <h2 class="accordion-header" id="headerTimesTable">
                <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseTimesTable" aria-expanded="true" aria-controls="collapseTimesTable">
                    Times Table
                </button>
            </h2>
             <!-- 展开控件 -->
            <div id="collapseTimesTable" class="accordion-collapse @collapsedTimesTable" aria-labelledby="headingTimesTable" data-bs-parent="#accordionTimesTable">
                <div class="accordion-body">
                    <form>
                        <div class="mb-3">
                            <label for="timesTableNumberInput" class="form-label">Number</label>
                            <input type="number" class="form-control" id="timesTableNumberInput" name="timesTableNumberInput" aria-describedby="timesTableNumberHelp">
                            <div id="timesTableNumberHelp" class="form-text">Enter an integer between 1 and 100.</div>
                        </div>
                        <button type="submit" class="btn btn-primary">Submit</button>
                    </form>
                    @if (Model.TimesTableNumberInput.HasValue)
                    {
                        <div class="card" style="width: 18rem;">
                            <div class="card-body">
                                <h5 class="card-title">@Model.TimesTableNumberInput times table</h5>
                                @for (int i = 1; i <= 12; i++)
                                {
                                    <div>
                                        @i x @Model.TimesTableNumberInput = @(i * Model.TimesTableNumberInput)
                                    </div>
                                }
                            </div>

                        </div>
                    }
                </div>
            </div>
        </div>

        <div class="accordion-item">
            <!-- 税金计算  手风琴项 -->
            <h2 class="accordion-header" id="headerCalculateTax">
                <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseCalculateTax" aria-expanded="true" aria-controls="collapseCalculateTax">
                    Calculate Tax
                </button>
            </h2>
            <!-- 展开控件 -->
            <div id="collapseCalculateTax" class="accordion-collapse @collapsedCalculateTax" aria-labelledby="headingCalculateTax" data-bs-parent="#accordionCalculateTax">
                <div class="accordion-body">
                    <form>
                        <div class="mb-3">
                            <label for="calculateTaxAmountInput" class="form-label">Amount</label>
                            <input type="number" class="form-control" id="calculateTaxAmountInput" name="calculateTaxAmountInput" aria-describedby="calculateTaxAmountInputHelp">
                            <div id="calculateTaxAmountInputHelp" class="form-text">Enter a monetary value.</div>
                        </div>
                        <div class="mb-3">
                            <label for="calculateTaxRegionCodeInput" class="form-label">Region</label>
                            <!-- 选择控件:两组选项 -->
                            <select class="form-control" id="calculateTaxRegionCodeInput" name="calculateTaxRegionCodeInput" aria-describedby="calculateTaxRegionCodeInputHelp">
                                <optgroup label="Europe">
                                    <option value="DK">Denmark</option>
                                    <option value="FR">France</option>
                                    <option value="HU">Hungary</option>
                                    <option value="NO">Norway</option>
                                    <option value="CH">Switzerland</option>
                                    <option value="GB">United Kingdom</option>
                                </optgroup>
                                <optgroup label="United States">
                                    <option value="AK">Alaska</option>
                                    <option value="OR">Oregon</option>
                                    <option value="MT">Montana</option>
                                    <option value="ND">North Dakota</option>
                                    <option value="WI">Wisconsin</option>
                                    <option value="ME">Maine</option>
                                    <option value="VA">Virginia</option>
                                    <option value="CA">California</option>
                                    <option value="OT">Other</option>
                                </optgroup>
                            </select>
                            <div id="calculateTaxRegionCodeInputHelp" class="form-text">Select a European or US state.</div>
                        </div>
                        <button type="submit" class="btn btn-primary">Submit</button>
                    </form>
                    @if (Model.Amount.HasValue)
                    {
                        <div class="card" style="width: 18rem;">
                            <div class="card-body">
                                <h5 class="card-title">You must pay @Model.TaxToPay in tax.</h5>
                            </div>

                        </div>
                    }
                </div>
            </div>
        </div>

        <div class="accordion-item">
            <!-- 阶乘计算 -->
            <h2 class="accordion-header" id="headerFactorials">
                <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseFactorials" aria-expanded="true" aria-controls="collapseFactorials">
                    Factorials
                </button>
            </h2>
            <!-- 展开控件 -->
            <div id="collapseFactorials" class="accordion-collapse @collapsedFactorial" aria-labelledby="headingFactorials" data-bs-parent="#accordionFactorials">
                <div class="accordion-body">
                    <div>
                        <form>
                            <div class="mb-3">
                                <label for="factorialNumberInput" class="form-label">Number</label>
                                <input type="number" class="form-control" id="factorialNumberInput" name="factorialNumberInput" aria-describedby="factorialNumberHelp">
                                <div id="factorialNumberHelp" class="form-text">Enter an integer between 1 and 12.</div>
                            </div>
                            <button type="submit" class="btn btn-primary">Submit</button>
                        </form>
                        @if (Model.FactorialNumber.HasValue)
                        {
                            <div class="card" style="width: 18rem;">
                                <div class="card-body">
                                    <h5 class="card-title">@(Model.FactorialNumber)!</h5>
                                    <div>
                                        @(Model.FactorialNumber)! = @(Model.FactorialResult is null ? "null" : Model.FactorialResult.Value.ToString("N0"))
                                    </div>
                                </div>

                            </div>
                        }
                        @if (Model.FactorialException is not null)
                        {
                            <div class="card" style="width: 18rem;">
                                <div class="card-body">
                                    <h5 class="card-title">Exception</h5>
                                    <div>
                                        @Model.FactorialException.Message
                                    </div>
                                </div>

                            </div>
                        }
                    </div>
                </div>
            </div>
        </div>

        <div class="accordion-item">
            <!-- 斐波那契数列 -->
            <h2 class="accordion-header" id="headerFibonacciSequence">
                <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseFibonacciSequence" aria-expanded="true" aria-controls="collapseFibonacciSequence">
                    Fibonacci sequence
                </button>
            </h2>
            <!-- 展开控件 -->
            <div id="collapseFibonacciSequence" class="accordion-collapse @collapsedFibonacci" aria-labelledby="headingFibonacciSequence" data-bs-parent="#accordionCustomers">
                <div class="accordion-body">
                    <div>
                        <form>
                            <div class="mb-3">
                                <label for="fibonacciNumberInput" class="form-label">Term</label>
                                <input type="number" class="form-control" id="fibonacciNumberInput" name="fibonacciNumberInput" aria-describedby="fibonacciNumberHelp">
                                <div id="fibonacciNumberHelp" class="form-text">Enter an integer between 1 and 40.</div>
                            </div>
                            <button type="submit" class="btn btn-primary">Submit</button>
                        </form>
                        @if (Model.FibonacciNumber.HasValue)
                        {
                            <div class="card" style="width: 18rem;">
                                <div class="card-body">
                                    <h5 class="card-title">Fibonacci term @Model.FibonacciNumber</h5>
                                    <div>
                                        Term @Model.FibonacciNumber of the fibonacci sequence = @(Model.FibonacciResult is null ? "null" : Model.FibonacciResult.Value.ToString("N0"))
                                    </div>
                                </div>

                            </div>
                        }
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>


<p data-line="631" class="sync-line" style="margin:0;"></p>
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace Northwind.Web.Pages;

public class FunctionsModel : PageModel
{
    public int? TimesTableNumberInput { get; set; }

    public decimal? Amount { get; set; }
    public string? RegionCode { get; set; }
    public decimal? TaxToPay { get; set; }

    public int? FactorialNumber { get; set; }
    public int? FactorialResult { get; set; }
    public Exception? FactorialException { get; set; }

    public int? FibonacciNumber { get; set; }
    public int? FibonacciResult { get; set; }

    public void OnGet()//处理请求
    {
        // Times Table
        if (int.TryParse(HttpContext.Request.Query["timesTableNumberInput"], out int i))
        {
            TimesTableNumberInput = i;//取得乘法表参数
        }

        // Calculate Tax
        if (decimal.TryParse(HttpContext.Request.Query["calculateTaxAmountInput"], out decimal amount))
        {
            Amount = amount;
            RegionCode = HttpContext.Request.Query["calculateTaxRegionCodeInput"];//取得税金计算参数:区域代码
            TaxToPay = CalculateTax(amount: amount, twoLetterRegionCode: RegionCode);
        }

        // Factorial
        if (int.TryParse(HttpContext.Request.Query["factorialNumberInput"], out int fact))
        {
            FactorialNumber = fact;//阶乘计算参数
            try
            {
                FactorialResult = Factorial(fact);
            }
            catch (Exception ex)
            {
                FactorialException = ex;
            }
        }

        // Fibonacci
        if (int.TryParse(HttpContext.Request.Query["fibonacciNumberInput"], out int fib))
        {
            FibonacciNumber = fib; //斐波那契数列计算参数
            FibonacciResult = FibImperative(term: fib);
        }
    }

    static decimal CalculateTax(//
      decimal amount, string twoLetterRegionCode)
    {
        decimal rate = 0.0M;//税率

		// since we are matching string values a switch// 因为我们匹配字符串值一个switch
		// 语句比 switch 表达式更简单
		// statement is easier than a switch expression

		switch (twoLetterRegionCode)
        {
            case "CH": // Switzerland 
                rate = 0.08M;
                break;
            case "DK": // Denmark 
            case "NO": // Norway
                rate = 0.25M;
                break;
            case "GB": // United Kingdom
            case "FR": // France
                rate = 0.2M;
                break;
            case "HU": // Hungary
                rate = 0.27M;
                break;
            case "OR": // Oregon
            case "AK": // Alaska
            case "MT": // Montana
                rate = 0.0M;
                break;
            case "ND": // North Dakota
            case "WI": // Wisconsin
            case "ME": // Maine
            case "VA": // Virginia
                rate = 0.05M;
                break;
            case "CA": // California
                rate = 0.0825M;
                break;
            default: // most US states 
                rate = 0.06M;
                break;
        }

        return amount * rate;
    }

    static int Factorial(int number)//阶乘
    {
        if (number < 0)
        {
            throw new ArgumentException(
              message: "The factorial function is defined for non-negative integers only.",
              paramName: "number");
        }
        else if (number == 0)
        {
            return 1;
        }
        else
        {
            checked // for overflow
            {
                return number * Factorial(number - 1);
            }
        }
    }

    static int FibImperative(int term)//斐波那契数列
    {
        if (term == 1)
        {
            return 0;
        }
        else if (term == 2)
        {
            return 1;
        }
        else
        {
            return FibImperative(term - 1) + FibImperative(term - 2);
        }
    }

}

4.8 消费者页面

7085bb98b843502058dcc2ed34fb1f2b.png

@page
@using Northwind.Web.Pages
@using Packt.Shared
@model CustomersModel
@{
	string title = "Customers by Country";
	ViewData["Title"] = $"Northwind B2B - {title}";//浏览器选项卡页标题
}
<div class="row">
  <h1 class="display-2">@title</h1>
  <div>
	  <h2>Exercise 14.2 – Practice building a data-driven web page</h2>
  </div>
  <div class="accordion" id="accordionCustomers"><!--accordion手风琴-->
		@if (Model.CustomersByCountry is not null)
		{
			@foreach (IGrouping<string?, Customer> cbc in Model.CustomersByCountry)
			{
				<div class="accordion-item"> <!-- 手风琴项-->
				  <h2 class="accordion-header" id="header@(cbc.Key)">
					<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapse@(cbc.Key)" aria-expanded="true" aria-controls="collapse@(cbc.Key)">
							@cbc.Key has @cbc.Count() customers
					</button>
				  </h2>
				  <div id="collapse@(cbc.Key)" class="accordion-collapse collapse" aria-labelledby="heading@(cbc.Key)" data-bs-parent="#accordionCustomers">
					<div class="accordion-body">
					   <ul>  <!-- 列出消费者-->
								@foreach (Customer c in cbc)
								{
										<li><a href="[email protected]">  <!-- 链接到订单页面 customerorders  id 作为请求信息 被 订单页面检索-->
											@c.CompanyName</a></li>
								}
					  </ul>
					</div>
				  </div>
				</div>
			}
		}
  </div>
</div>
using Microsoft.AspNetCore.Mvc.RazorPages; // PageModel
using Packt.Shared; // Customer

namespace Northwind.Web.Pages;

public class CustomersModel : PageModel
{//为将键映射到 System.Collections.Generic.IEnumerable`1 值序列的数据结构定义索引器、大小属性和布尔搜索方法。
	public ILookup<string?, Customer>? CustomersByCountry;

	private NorthwindContext db;

	public CustomersModel(NorthwindContext db)
	{
		this.db = db;//初始化数据库
	}

	public void OnGet()
	{   //根据指定的键选择器函数从 System.Collections.Generic.IEnumerable`1 创建 System.Linq.Lookup`2。
		//返回:包含键和值的 System.Linq.Lookup`2。每个组中的值与源中的顺序相同。
		CustomersByCountry = db.Customers.ToLookup(c => c.Country);
	}
}

4.9 CustomerOrders消费者的订单页面

bc68a681e78260f0abd5712dfad2bc89.png

@page
@using Northwind.Web.Pages
@using Packt.Shared
@model CustomerOrdersModel
@{
  string title = "Customer and their orders";
  ViewData["Title"] = $"Northwind B2B - {title}";
}
<div class="row">
  <h1 class="display-2">@title</h1>
  <div>
    @if (Model.Customer is not null)
    {
      <div>
        <div>@Model.Customer.CompanyName</div>
      </div>
      <div>
        <table> <!-- 表-->
          <thead> <!-- 表头-->
            <tr><th>Order Id</th><th>Order Date</th></tr>
          </thead>
          <tbody> <!-- 表数据 -->
            @foreach (Order o in Model.Customer.Orders)
            { <!-- td  -->
              <tr><td>@o.OrderId</td><td>@o.OrderDate</td></tr>
            }
          </tbody>
        </table>
      </div>
    }
  </div>
</div>
using Microsoft.AspNetCore.Mvc.RazorPages; // PageModel
using Microsoft.EntityFrameworkCore; // Include extension method
using Packt.Shared; // Customer

namespace Northwind.Web.Pages;

public class CustomerOrdersModel : PageModel
{
  public Customer? Customer;

  private NorthwindContext db;

  public CustomerOrdersModel(NorthwindContext db)
  {
    this.db = db;
  }

  public void OnGet()
  {
    string id = HttpContext.Request.Query["id"];//获取http请求中的 "id"

    Customer = db.Customers.Include(c => c.Orders)
      .SingleOrDefault(c => c.CustomerId == id);
  }
}

The End

猜你喜欢

转载自blog.csdn.net/cxyhjl/article/details/130776573