使用ASP.NET Core Razor Pages 构建网站
sqlite 北风数据库
1. Northwind.Common.DataContext.Sqlite
是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
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、Customer、Employee、ShipViaNavigation、OrderDetails |
订单详情 | OrderDetail.cs | OrderId、ProductId、UnitPrice、Quantity、Discount、Order、Product |
产品 | Product.cs | ProductId、ProductName、SupplierId、CategoryId、QuantityPerUnit、UnitPrice、UnitsInStock、UnitsOnOrder、ReorderLevel、Discontinued、Category、Supplier、OrderDetails |
托运人 | 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 类库
雇员查询网页razor page.
<!--单个雇员_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, NorthwindContextnamespace 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
双击项目在编辑器中打开.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 delegateawait next();//我们可以在调用下一个委托后修改响应 we could modify the response after calling the next delegate});app.UseHttpsRedirection();//添加用于将 HTTP 请求重定向到 HTTPS 的中间件。app.UseDefaultFiles(); //在当前路径上启用默认文件映射 index.html, default.html, and so onapp.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/bootstrap@5.1.0/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 © 2021 - @ViewData["Title"]</p><!-- @ViewData["Title"],使用该布局的页面的变量 --></footer></div><!-- JavaScript to enable features like carousel 启用轮播等功能的 JavaScript --><script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/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
@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文件
@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 供应商
页面显示供应商表格
@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], IActionResultnamespace 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 函数计算器页面
@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 Tableif (int.TryParse(HttpContext.Request.Query["timesTableNumberInput"], out int i)){TimesTableNumberInput = i;//取得乘法表参数}// Calculate Taxif (decimal.TryParse(HttpContext.Request.Query["calculateTaxAmountInput"], out decimal amount)){Amount = amount;RegionCode = HttpContext.Request.Query["calculateTaxRegionCodeInput"];//取得税金计算参数:区域代码TaxToPay = CalculateTax(amount: amount, twoLetterRegionCode: RegionCode);}// Factorialif (int.TryParse(HttpContext.Request.Query["factorialNumberInput"], out int fact)){FactorialNumber = fact;//阶乘计算参数try{FactorialResult = Factorial(fact);}catch (Exception ex){FactorialException = ex;}}// Fibonacciif (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 expressionswitch (twoLetterRegionCode){case "CH": // Switzerland rate = 0.08M;break;case "DK": // Denmark case "NO": // Norwayrate = 0.25M;break;case "GB": // United Kingdomcase "FR": // Francerate = 0.2M;break;case "HU": // Hungaryrate = 0.27M;break;case "OR": // Oregoncase "AK": // Alaskacase "MT": // Montanarate = 0.0M;break;case "ND": // North Dakotacase "WI": // Wisconsincase "ME": // Mainecase "VA": // Virginiarate = 0.05M;break;case "CA": // Californiarate = 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 消费者页面
@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="customerorders?id=@c.CustomerId"> <!-- 链接到订单页面 customerorders id 作为请求信息 被 订单页面检索-->@c.CompanyName</a></li>}</ul></div></div></div>}}</div>
</div>
using Microsoft.AspNetCore.Mvc.RazorPages; // PageModel
using Packt.Shared; // Customernamespace 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消费者的订单页面
@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; // Customernamespace 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