Angular 7 SPA CRUD 结合 ASP.NET Core 和 Entity Framework Core





5.00/5 (4投票s)
文章介绍 Angular 7、Entity Framework Core 和 .NET Core
大家好,最近 Angular 7 已经发布,让我们一起探索如何使用 Angular 创建 SPA,并以 .NET Core 和 Entity Framework Core 作为后端。
议程
- Angular 7
- 新功能
- Angular CLI 变更
- Angular Material 变更
- 升级到 Angular 7
- 添加新项目
- 使用 Angular 7 进行前端设计和实现
- 添加组件
- 添加模型和配置文件
- 添加 Bootstrap 弹出窗口
- 添加数据服务
- 使用 ASP.NET Core 和 Entity Framework Core 进行后端 Web API 开发
- 设置 .NET Core 项目
- 设置 Entity Framework Core
- 设置 CORS 以允许跨域资源共享。
- 本文的未来扩展
- 源代码链接
Angular 7
终于,Angular 7 的等待结束了!!这个版本的 Angular 为我们带来了一些令人兴奋的新功能,主要的变化集中在 Angular 核心、CLI 和 Angular Material,让我们一一探索。
Angular 核心变更
Angular 核心中增加的一些新功能可以在这里列出:
- 为 CanLoad 接口引入了新的接口 UrlSegment []
- 新的接口 DoBootStrap
- 增加了新的元素功能 - 支持 Shadow DOM v1 和插槽(slots)
- 增加了新的路由功能 - 警告在 Angular Zone 之外触发的导航
- 增加了从格式错误的 URL 中恢复的新能力
- 增加了对 import 语句中点 (.) 的新编译器支持,并避免 ngc-wrapped 崩溃
- 在提取的 XMB 中添加了新的 "original" 占位符值
- 更新了依赖项以支持 Typescript 3.1、RxJS 6.3 和 Node 10。
Angular CLI 变更
还记得之前版本的 Angular 项目设置吗?你只需要输入 ng new Project Name,然后 CLI 会在后台进行处理。在 CLI 执行的过程中,我们会看到一些输出和渲染到屏幕上的数据。Angular 7 最酷的功能之一,也是我最喜欢的功能是 Angular CLI Prompts。借助这个功能,我们只需要回答几个问题就可以设置好项目。让我们通过下面的图片快速了解一下如何做到这一点。
Angular Material 和 CDK
Angular Material 和 CDK 带来了一些新功能,例如虚拟滚动和拖放。让我们简要了解一下它们:
虚拟滚动
这允许我们利用列表的突出特点来加载和卸载页面上的 DOM 元素。也就是说,如果我们有一个大量的数据,并想在列表中显示它,那么我们就可以利用这个功能。
拖放
拖放功能得到了 CDK 的支持,包括在用户移动项目时自动渲染的功能,以及为列表中的记录或项目传输提供辅助方法。
应用程序性能
一切都围绕着应用程序,Google 投入了大量的精力和引入了一些功能来帮助我们提高性能。第一个是 Bundle Budget,它允许我们设置应用程序包的大小,并在超过限制时发出错误。默认的包预算大小为 2MB,之后可以增加。
接下来是移除 *Pollyfill.ts* 文件,该文件仅在开发期间使用,在生产环境中会自动移除。
升级到 Angular 7
我们有很多人项目是基于旧版本的 Angular 构建的。为了升级旧版本的 Angular,官方网站提供了相关的方法和详细说明,您可以在这里找到。如果我们从 Angular 6 迁移到 Angular 7,以下命令就可以完成工作:
ng update @angular/cli @angular/core
到目前为止,我们已经完成了 Angular 的功能和升级。现在让我们开始实际操作,添加项目。
添加新项目
为了添加 Angular 项目,我们需要一些先决条件来继续本文的学习:
- 安装最新的 Node.js,这将安装 NPM(Node 包管理器),然后 NPM 将下载我们应用程序的所有依赖项或包。最新版本的 Node.js 可以在这里找到。
- 获取 Angular CLI 在完成 Node.js 和 NPM 的安装后,下一步就是下载 Angular CLI,它将帮助我们快速设置。安装 CLI 需要以下命令:npm install -g @angular/cli
- 获取 Visual Studio Code 这是我们将在本文中使用的 IDE,您可以在这里找到最新版本。
创建新项目
现在是时候使用 Angular 7 添加新项目了。为此,让我们按照下图所示的步骤进行操作:
- 创建您想保存项目的目录
- 使用命令 ng New Angular7CRUDDemo
- 选择合适的选项添加路由和 CSS
注意:根据您的机器和网络速度,下载包和准备项目可能需要一些时间。
项目准备好后,我们从文件菜单打开它,可以看到如下的目录结构:
与旧版本的一个区别是添加了 app-routing 文件,该文件是在设置项目时通过 CLI 提示选项添加的。
现在的问题是,我们如何检查我们的项目是否与 Angular 7 兼容?为此,我们需要检查 package.json 文件,其结构如下:
当看到高亮部分时,我们可以说当前项目已配置为使用最新版本的 Angular 依赖项。
现在是实际编码时间了。我们将编码部分分为两部分:第一部分是 Angular 7 的 UI,然后是 .NET Core 和 Entity Framework Core 的 Web API 部分。我们先看 UI 部分,然后看 .NET Core 和 Entity Framework Core 的 Web API 部分。
使用 Angular 进行前端设计和实现
我们都知道任何 Angular 应用程序的前端都是由组件组成的。所以让我们看看应用程序的结构是什么样的,在此之前,先了解一下我们将在本文中实现什么。
在这里,我们将添加一个演示应用程序,用于列出、添加、更新和删除员工。为此,我们将有以下目录结构。
以上是应用程序的目录结构。这里我们有三个组件:
- Angular-crud.component.ts 这个组件将列出所有员工,并包含其他组件。
- employee-add.component.ts 这个组件用于创建员工记录。
- app.component.ts App 组件,所有组件都将通过 <router-outlet></router-outlet> 加载。
- Employeeupdate.component.ts 这个组件将负责处理员工记录的编辑操作。
- DataService.ts 这个服务将使用 Angular 7 中的 HttpClient 存储所有 API 调用(各种 HTTP 方法)。
- Data Models 这个文件夹包含 Employee 数据模型,它将作为所有其他模型的基础,以及 config.ts 文件,该文件将存储与配置相关的数据。
- App-routing.module.ts 这是在配置项目时添加到应用程序的路由模块。
让我们逐一探索这些组件:
代码描述
employee-Add.component.ts import { Component, OnInit,Input, ViewChild, ElementRef, EventEmitter, Output } from '@angular/core'; import { NgForm } from '@angular/forms'; import { Employee } from 'src/Models/Employee'; import { Router } from '@angular/router'; import {EmployeeDataService} from '../DataService/EmployeeDataService' @Component({ selector: 'app-employee-add', templateUrl: './employee-add.component.html', styleUrls: ['./employee-add.component.sass'] }) export class EmployeeAddComponent implements OnInit { @Input() cleardata: boolean = false; @Output() nameEvent = new EventEmitter<string>(); objtempemp:Employee; @Input() objemp :Employee=new Employee();; @ViewChild('closeBtn') cb: ElementRef; constructor(private dataservice:EmployeeDataService,private route:Router) { } ngOnInit() { // this.ResetValues(); } ResetValues(){ } Register(regForm:NgForm){ this.objtempemp=new Employee(); this.objtempemp.email=regForm.value.email; this.objtempemp.firstname=regForm.value.firstname; this.objtempemp.lastname=regForm.value.lastname; this.objtempemp.gender=regForm.value.gender; this.dataservice.AddEmployee(this.objtempemp).subscribe(res=>{ alert("Employee Added successfully"); this.TakeHome(); } ) } TakeHome(){ this.nameEvent.emit("ccc"); this.cb.nativeElement.click(); this.route.navigateByUrl(''); } }
Employee-add.component.html
<div class="container" style="border:thin"> <form #empadd='ngForm' (ngSubmit)="Register(empadd)" class="form-horizontal" style="width:50%" > <div class="form-group" > <label class="control-label col-sm-2" for="fname" >First Name:</label> <div class="col-sm-10"> <input style="width:50%" type="text" class="form-control" width="50%" id="fname" placeholder="Enter first name" name="firstname" firstname required [(ngModel)]='objemp.firstname' #firstname="ngModel"> <span class="help-bpx" *ngIf="firstname.touched && !firstname.valid ">Required</span> </div> </div> <div class="form-group" > <label class="control-label col-sm-2" for="email">Last Name:</label> <div class="col-sm-10"> <input style="width:50%" required type="text" class="form-control" width="50%" id="lastname" placeholder="Enter Last Name" name="lastname" lastname required [(ngModel)]='objemp.lastname' #lastname="ngModel"> <span class="help-bpx" *ngIf="lastname.touched && !lastname.valid ">Required</span> </div> </div> <div class="form-group" > <label class="control-label col-sm-2" for="Gender">Gender:</label> <div class="col-sm-10"> <select name="gender" gender required [(ngModel)]='objemp.gender' #gender="ngModel"> <option value="0" selected disabled>Please Select</option> <option value="1">Male</option> <option value="2">Female</option> <span class="help-bpx" *ngIf="gender.touched && !gender.valid ">required</span> </select> </div> </div> <div class="form-group" > <label class="control-label col-sm-2" for="email">Email:</label> <div class="col-sm-10"> <input #email="ngModel" style="width:50%" type="email" [(ngModel)]='objemp.email' class="form-control" width="50%" id="email" placeholder="Enter email" name="email"> <span class="help-bpx" *ngIf="email.touched && !email.valid ">**</span> </div> </div> <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <button id="btnsubmit" type="submit" class="btn btn-primary">Submit</button> </div> </div> </form> </div> <button style="display:none" type="button" #closeBtn class="btn btn-default" data-dismiss="modal">Close</button>
以上是 Employee Add Component 的代码及其模板。
代码描述
- 以上是 Employee Add Component 的代码,其中包含了应用程序所需的 import 部分。
- 在构造函数中,我们注入了数据服务和 Router。
- 我们有一个函数 `Register(regForm:NgForm )`。在这里,我们使用模板驱动的方法来添加员工,所以我们声明了一个 NgForm 类型的表单对象。
- 在这个方法中,我们订阅了 `Addemployee` 数据服务。成功后,我们将显示一个警报并重定向到 Home Component。
- 我们有一个 `TakeHome` 方法,它将发出一个方法来刷新父组件并从那里重新加载数据。在模板中,我们添加了 Form 标签,并将表单命名为 `#empadd`。在这里,在 Form 的 `NgSubmit` 事件中,我们调用 `Register()`,它将提交表单及其值。
- 为了验证目的,我们使用了基本的 HTML 验证。
- 最后一行是我们为关闭按钮添加的代码,这是一个虚拟代码,将在员工成功添加后在模板中触发。
以上是关于 Add Component 的内容。让我们看看 Update 组件及其模板,它与 Add Component 具有相同的结构和描述。
employeeupdate.component.ts
import { Component, OnInit, ViewChild, Input, EventEmitter, Output, ElementRef } from '@angular/core'; import { EmployeeDataService } from '../DataService/EmployeeDataService'; import { Router } from '@angular/router'; import { NgForm } from '@angular/forms'; import { Employee } from 'src/Models/Employee'; @Component({ selector: 'app-employeeupdate', templateUrl: './employeeupdate.component.html', styleUrls: ['./employeeupdate.component.sass'] }) export class EmployeeupdateComponent implements OnInit { constructor(private dataservice: EmployeeDataService, private route: Router) { } @Output() nameEvent = new EventEmitter<string>(); @ViewChild('closeBtn') cb: ElementRef; ngOnInit() { } @Input() reset: boolean = false; @ViewChild('regForm') myForm: NgForm; @Input() isReset: boolean = false; objtempemp: Employee; @Input() objemp: Employee = new Employee(); EditEmployee(regForm: NgForm) { this.dataservice.EditEmployee(this.objemp).subscribe(res => { alert("Employee updated successfully"); this.nameEvent.emit("ccc"); this.cb.nativeElement.click(); }, } }
employeeupdate.component.html
<div class="container" style="border:thin"> <form #EditForm='ngForm' name="editform" (ngSubmit)="EditEmployee(EditForm)" class="form-horizontal" style="width:50%"> <div class="form-group"> <label class="control-label col-sm-2" for="fname">First Name:</label> <div class="col-sm-10"> <input style="width:50%" type="text" class="form-control" width="50%" id="fname" placeholder="Enter first name" name="firstname" firstname required [(ngModel)]='objemp.firstname' #firstname="ngModel"> <span class="help-bpx" *ngIf="firstname.touched && !firstname.valid ">Required</span> </div> </div> <div class="form-group"> <label class="control-label col-sm-2" for="email">Last Name:</label> <div class="col-sm-10"> <input style="width:50%" required type="text" class="form-control" width="50%" id="lastname" placeholder="Enter Last Name" name="lastname" lastname required [(ngModel)]='objemp.lastname' #lastname="ngModel"> <span class="help-bpx" *ngIf="lastname.touched && !lastname.valid ">Required</span> </div> </div> <div class="form-group"> <label class="control-label col-sm-2" for="Gender">Gender:</label> <div class="col-sm-10"> <select name="gender" gender required [(ngModel)]='objemp.gender' #gender="ngModel"> <option value="0" selected disabled>Please Select</option> <option value="1">Male</option> <option value="2">Female</option> <span class="help-bpx" *ngIf="gender.touched && !gender.valid ">required</span> </select> </div> </div> <div class="form-group"> <label class="control-label col-sm-2" for="email">Email:</label> <div class="col-sm-10"> <input #email="ngModel" style="width:50%" type="email" [(ngModel)]='objemp.email' class="form-control" width="50%" id="email" placeholder="Enter email" name="email"> <span class="help-bpx" *ngIf="email.touched && !email.valid ">**</span> </div> </div> <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <button type="submit" class="btn btn-primary">Submit</button> </div> </div> </form> </div> <button style="display:none" type="button" #closeBtn class="btn btn-default" data-dismiss="modal">Close</button>
以上是 employee update component 的代码。这个组件的描述与 Add component 相同。为了清晰起见,让我们看看 List 组件。
Employeelist.component.ts
import { Component, OnInit, ViewChild } from '@angular/core'; import { EmployeeAddComponent } from '../employee-add/employee-add.component'; import { EmployeeDataService } from '../DataService/EmployeeDataService' import { Employee } from 'src/Models/Employee' import { Router } from '@angular/router'; import { EmployeeupdateComponent } from '../employeeupdate/employeeupdate.component'; @Component({ selector: 'app-angular-crud', templateUrl: './angular-crud.component.html', styleUrls: ['./angular-crud.component.sass'] }) export class AngularCRUDComponent implements OnInit { emplist: Employee[]; dataavailbale: Boolean = false; tempemp: Employee constructor(private dataservce: EmployeeDataService, private route: Router) { } ngOnInit() { this.LoadData(); } LoadData() { this.dataservce.getEmployee().subscribe((tempdate) => { this.emplist = tempdate; console.log(this.emplist); if (this.emplist.length > 0) { this.dataavailbale = true; } else { this.dataavailbale = false; } } ) , err => { console.log(err); } } deleteconfirmation(id: string) { if (confirm("Are you sure you want to delete this ?")) { this.tempemp = new Employee(); this.tempemp.id = id; this.dataservce.DeleteEmployee(this.tempemp).subscribe(res => { alert("Deleted successfully !!!"); this.LoadData(); }) } } @ViewChild('empadd') addcomponent: EmployeeAddComponent @ViewChild('regForm') editcomponent: EmployeeupdateComponent loadAddnew() { this.addcomponent.objemp.email = "" this.addcomponent.objemp.firstname = "" this.addcomponent.objemp.lastname = "" this.addcomponent.objemp.id = "" this.addcomponent.objemp.gender = 0 } loadnewForm(id: string, email: string, firstname: string, lastname: string, gender: number) { console.log(gender); this.editcomponent.objemp.email = email this.editcomponent.objemp.firstname = firstname this.editcomponent.objemp.lastname = lastname this.editcomponent.objemp.id = id this.editcomponent.objemp.gender = gender } RefreshData() { this.LoadData(); } }
EmployeeList.html
<div class="container"> <input type="button" class="btn btn-primary" (click)="loadAddnew()" data-toggle="modal" data-target="#myModal" value="Create New"> <hr> <div *ngIf="!dataavailbale"> <h4> No Employee Data is present Click Add new to add Data.</h4> </div> <table class="table" *ngIf="dataavailbale"> <thead> <tr> <th scope="col">Sr.No</th> <th scope="col">First name</th> <th scope="col">Last Name</th> <th scope="col">Email</th> <th scope="col">Gender</th> <th scope="col" style="align-content: center">Action</th> </tr> </thead> <tbody> <tr *ngFor="let e of emplist let i = index "> <td scope="col">{{i+1}}</td> <td scope="col">{{e.fname}}</td> <td scope="col">{{e.lname}}</td> <td scope="col">{{e.email}}</td> <td scope="col">{{e.gender=="1"?'Male':'Female'}}</td> <td style="display:none">{{e.id}}</td> <td scope="col"> <button type="button" class="btn btn-default btn-primary" (click)="loadnewForm(e.id,e.email,e.fname,e.lname,e.gender)" data-toggle="modal" data-target="#myModaledit"> <span class="glyphicon glyphicon-edit"></span> Edit </button> | <button type="button" class="btn btn-default btn-danger" (click)="deleteconfirmation(e.id)"> <span class="glyphicon glyphicon-trash"></span> Delete </button> </td> </tr> </tbody> </table> <div id="myModal" class="modal fade" role="dialog"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal">×</button> <h4 class="modal-primary">Employee Add</h4> </div> <div class="modal-body"> <app-employee-add #empadd (nameEvent)="RefreshData($event)"></app-employee-add> </div> <div class="modal-footer"> <button type="button" #closeBtn class="btn btn-danger" data-dismiss="modal">Close</button> </div> </div> </div> </div> <div id="myModaledit" class="modal fade" role="dialog"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal">×</button> <h4 class="modal-title">Edit</h4> </div> <div class="modal-body"> <app-employeeupdate (nameEvent)="RefreshData($event)" [isReset]="resetForm" #regForm></app-employeeupdate> </div> <div class="modal-footer"> <button type="button" class="btn btn-danger" data-dismiss="modal">Close</button> </div> </div> </div> </div>
代码描述
- 我们导入了组件所需的包。
- 根据需求声明变量,并在构造函数中导入了 Data service 和 Router。以下是我们获取添加到父组件(即 Employee list component)的子组件引用的内容。
@ViewChild('empadd') addcomponent: EmployeeAddComponent @ViewChild('regForm') editcomponent: EmployeeupdateComponent
- 为什么我们需要这个?让我们看看接下来的两个函数 `loadAddnew()`、`loadAddnewForm()`。我们在这里使用了 `viewChild` 元素,用于重置和设置特定表单的值。
- 接下来是 `LoadData()`。它订阅了数据服务中的 get 方法,并将数据分配给我们的 employee list 对象。
- 调用 Delete Employee,它从上面的表格中获取 id,然后调用 Data service 中的 delete 服务,如果成功从数据库中删除了 Employee 数据,则显示警报。
- 模板代码很简单,显示员工列表,并在代码中添加了 add 和 edit 组件,它们将在弹出窗口中渲染。
以上是应用程序中的组件。让我们继续探讨其余的 UI 和前端部分。
添加模型和配置文件
export class Employee{ firstname:string; lastname:string ; email:string; gender:number; id:string }
这是我们在整个应用程序中用于发送和接收数据的类。
Config.ts
这个类将存储与配置相关的数据。目前,类中只有 App URL,但未来可以添加更多数据。
添加 Bootstrap 弹出窗口
我们使用弹出窗口来显示 Add 和 Edit 表单。为此,我们在 Employee List 组件的模板中定义了代码。
<div id="myModal" class="modal fade" role="dialog"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal">×</button> <h4 class="modal-primary">Employee Add</h4> </div> <div class="modal-body"> <app-employee-add #empadd (nameEvent)="RefreshData($event)"></app-employee-add> </div> <div class="modal-footer"> <button type="button" #closeBtn class="btn btn-danger" data-dismiss="modal">Close</button> </div> </div> </div> </div>
在这里,我们使用了普通的弹出窗口代码,并在 modal-body 中渲染了我们的子组件。
添加数据服务
Data service 是我们将服务调用逻辑与应用程序其余部分分离的层。我们的 Data service 如下所示:
import { HttpClient, HttpParams, HttpHeaders } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Employee } from 'src/Models/Employee' import { ROOT_URL } from 'src/Models/Config' import { Observable } from 'rxjs'; @Injectable() export class EmployeeDataService { employees: Observable<Employee[]>; newemployee: Employee; constructor(private http: HttpClient) { } getEmployee() { return this.http.get<Employee[]>(ROOT_URL + 'Employees'); } AddEmployee(emp: Employee) { const headers = new HttpHeaders().set('content-type', 'application/json'); var body = { Fname: emp.firstname, Lname: emp.lastname, Email: emp.email, gender: emp.gender } console.log(ROOT_URL); return this.http.post<Employee>(ROOT_URL + '/Employees', body, { headers }); } /// EditEmployee(emp: Employee) { console.log(emp); const params = new HttpParams().set('ID', emp.id); const headers = new HttpHeaders().set('content-type', 'application/json'); var body = { Fname: emp.firstname, Lname: emp.lastname, Email: emp.email, ID: emp.id , gender: emp.gender } return this.http.put<Employee>(ROOT_URL + 'Employees/' + emp.id, body, { headers, params }) } DeleteEmployee(emp: Employee) { const params = new HttpParams().set('ID', emp.id); const headers = new HttpHeaders().set('content-type', 'application/json'); var body = { Fname: emp.firstname, Lname: emp.lastname, Email: emp.email, ID: emp.id } return this.http.delete<Employee>(ROOT_URL + '/Employees/' + emp.id) } }
在这个服务中,我们包含了所有将使用 `Httpclient` 的方法,并为每个基本 http 动词(如 Get、Put、Post 和 delete)返回一个 Observable。我们已经导入了顶部的基本 Http 必需项,如 HttpParams 和 HttpClient,它们是 Angular/Common/http 的一部分。
到目前为止,我们已经完成了前端的设计和实现。让我们转向服务器端设置,这是使用 .NET Core 和 Entity Framework Core 完成的,让我们来看看吧。
使用 ASP.NET Core 和 Entity Framework Core 进行后端 Web API 开发
在本节中,让我们探讨用于实现员工 CRUD 操作的 API。本节主要分为四个部分:如何设置 .NET Core 项目、设置 Entity Framework Core,然后是添加 CORS(跨域资源共享)部分,以便允许 Angular 应用程序与服务器通信。
添加 .NET Core Web API 项目
为了添加 .NET Core web api 项目,请遵循以下步骤:
完成添加项目后,让我们转向已添加的项目并进行必要的更改。
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Angular7DemoServices; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; namespace Angular6DemoServices { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddMvc(); services.AddCors(); services.AddDbContext<AppDbContext>(opt => opt.UseSqlServer(@"Your connection string")); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseMiddleware(); app.UseCors(); app.UseMvc(); } } }
这是我们的 startup 类,我们在其中配置服务并注册服务。
首先,我们需要添加数据库上下文,我们在这里使用 SQL Server 作为数据库。
接下来,我们需要配置 CORS 选项,允许来自 Angular 应用程序的跨域资源共享。除此之外,我们还添加了中间件,这将再次帮助我们解决 CORS 问题。中间件代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; namespace Angular7DemoServices { // You may need to install the Microsoft.AspNetCore.Http.Abstractions package into your project public class CorsMiddleware { private readonly RequestDelegate _next; public CorsMiddleware(RequestDelegate next) { _next = next; } public Task Invoke(HttpContext httpContext) { httpContext.Response.Headers.Add("Access-Control-Allow-Origin", "*"); httpContext.Response.Headers.Add("Access-Control-Allow-Credentials", "true"); httpContext.Response.Headers.Add("Access-Control-Allow-Headers", "Content-Type, Accept"); httpContext.Response.Headers.Add("Access-Control-Allow-Methods", "POST,GET,PUT,PATCH,DELETE,OPTIONS"); return _next(httpContext); } } // Extension method used to add the middleware to the HTTP request pipeline. public static class MiddlewareExtensions { public static IApplicationBuilder UseMiddleware(this IApplicationBuilder builder) { return builder.UseMiddleware<CorsMiddleware>(); } } }
这将是添加所需标头的中间件,用于与 API 的请求和响应。代码的其余部分只是我们大多熟悉的简单 CRUD 操作。如果不熟悉,可以在下面共享的 GitHub 上找到。
所以当我们运行 Web API 和 Angular 应用程序时,我们可以看到如下输出:
本文的未来扩展
看到输出后,您可能会想,这些注册和登录按钮在那里做什么?它们是为未来的扩展准备的。我们将拥有什么?
- 通过 Facebook、Gmail 和 Twitter 等外部身份验证进行登录和注册
- 在 Web API 端使用 Identity server
- 为员工添加新模块,让他们可以登录并记录每日工时表
- 供管理员跟踪他们的日常活动。如果有人有兴趣,可以为位于以下链接处的项目做出贡献。
源代码链接
以上文章的源代码链接如下:
参考文献
https://angular.io/