65.9K
CodeProject 正在变化。 阅读更多。
Home

ASP.Net Core2.0, Angular6 - SPA

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.48/5 (9投票s)

2018年5月20日

CPOL

7分钟阅读

viewsIcon

29691

downloadIcon

525

在本文中,我们将从头开始探索如何使用 ASP.Net Core 和 Angular 构建一个单页应用程序 (SPA) 示例。

目录

  • 引言
  • 工作计划
  • 开发环境
  • 核心描述
  • 摘要

引言

我们将在前端使用 Angular6、TypeScript,在后端使用 ASP.NET Core WebAPI 并结合 Entity Framework 进行数据库操作。

工作计划

  • 创建新的 ASP.Net Core 项目
  • 配置新创建的项目
    • 提供静态页面
  • 安装 Node 包
  • 管理已安装的包
  • 创建前端应用程序
    • HTML 模板
    • 文件夹结构
    • Angular 依赖
    • TypeScript 配置
    • 根组件
    • 根模块
    • 启动 Clientapp
  • 创建数据库
  • 安装 Entity Framework Core
  • 脚手架 MSSQL 数据库
  • 配置中间件
  • 创建 ASP.Net Core WebAPI
  • 创建客户端服务
  • 执行 CRUD 操作
  • 在浏览器中测试

开发环境

开发我们的 SPA 示例需要具备以下先决条件。

  • Visual Studio 2017
  • NET Core 2.0 或更高版本
  • NodeJS 和 NPM

Visual Studio 2017:如果您已经安装了 Visual Studio 2017,请不用担心,否则请免费下载 Visual Studio Community 2017

.NET Core 下载:安装 .NET Core SDK (软件开发工具包) 2.0 或更高版本。

NodeJS 和 NPM:安装最新的 NodeJS 和 NPM。在开始之前,请确保环境已就绪。

创建 ASP.Net Core 项目

让我们使用 Visual Studio 2017 > 文件 > 新建 > 项目来创建一个新项目

选择空模板,然后点击 > 确定。

这是我们带有初始组件的新的 ASP.Net Core 空项目。

配置 ASP.Net Core 项目:

在此示例中,我们将从 app 根文件夹提供 index.html 页面作为我们的主页面。要提供该页面,我们需要在 Startup.cs 文件中进行配置。以下代码片段将提供该页面。

DefaultFilesOptions options = new DefaultFilesOptions();
options.DefaultFileNames.Clear();
options.DefaultFileNames.Add("/index.html");
app.UseDefaultFiles(options);
app.UseStaticFiles();

用于处理客户端路由回退的中间件:为避免在 AngularJS SPA 应用中重新加载页面时出现 404 错误,我们需要添加一个中间件来处理客户端路由回退。以下代码片段将处理此问题。原始帖子:https://code.msdn.microsoft.com/How-to-fix-the-routing-225ac90f

app.Use(async (context, next) =>
{
    await next();
    if (context.Response.StatusCode == 404 && !Path.HasExtension(context.Request.Path.Value))
    {
        context.Request.Path = "/index.html";
        context.Response.StatusCode = 200;
        await next();
    }
});

在此处获取有关中间件的更多详细信息:https://docs.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?tabs=aspnetcore2x

更多关于 ASP.Net Core Startup: https://codeproject.org.cn/Articles/1158377/NET-Core-Startup

安装 Node 包

让我们将前端包添加到我们的应用程序。我们需要添加一个名为 package.json 的 npm 配置文件。为此,请右键单击项目,然后转到 > 添加 > 新项。在新的项添加窗口中,选择 npm 配置文件。

这是我们的前端包依赖项列表。

{
  "version": "1.0.0",
  "name": "asp.net",
  "private": true,
  "dependencies": {
    "@angular/common": "^6.0.2",
    "@angular/compiler": "^6.0.2",
    "@angular/core": "^6.0.2",
    "@angular/forms": "^6.0.2",
    "@angular/http": "^6.0.2",
    "@angular/platform-browser": "^6.0.2",
    "@angular/platform-browser-dynamic": "^6.0.2",
    "@angular/router": "^6.0.2",
    "@angular/upgrade": "^6.0.2",
    "bootstrap": "^4.1.1",
    "core-js": "^2.5.6",
    "reflect-metadata": "^0.1.12",
    "rxjs": "^6.1.0",
    "systemjs": "^0.21.3",
    "zone.js": "^0.8.26"
  },
  "devDependencies": {
    "@types/core-js": "^0.9.46",
    "typescript": "^2.8.3",
    "typings": "^2.1.1",
    "@types/node": "^10.0.4",
    "concurrently": "^3.5.1",
    "json-server": "^0.12.2",
    "gulp": "^3.9.1",
    "gulp-concat": "^2.6.1",
    "gulp-rename": "^1.2.2",
    "gulp-cssmin": "^0.2.0",
    "gulp-uglify": "^3.0.0",
    "gulp-htmlclean": "^2.7.20",
    "rimraf": "^2.6.2"
  }
}

安装完所有包后,让我们将所需的库从 node_modules 文件夹转移到 "wwwroot/lib" 文件夹,以便在主 html 页面中调用它们。

管理已安装的包

我们需要添加一个任务运行器,如 gulp 文件,然后复制下面的代码片段并粘贴到新添加的文件中。

/// <binding AfterBuild='build-all' />

var gulp = require("gulp"),
    rimraf = require("rimraf"),
    concat = require("gulp-concat"),
    cssmin = require("gulp-cssmin"),
    uglify = require("gulp-uglify"),
    rename = require("gulp-rename");

var root_path = {
    webroot: "./wwwroot/"
};

//library source
root_path.nmSrc = "./node_modules/";

//library destination
root_path.package_lib = root_path.webroot + "lib/";

gulp.task('copy-lib-js', function () {

    gulp.src('./node_modules/core-js/**/*.js')
        .pipe(gulp.dest(root_path.package_lib + 'core-js'));
    gulp.src('./node_modules/@angular/**/*.js')
        .pipe(gulp.dest(root_path.package_lib + '@angular'));
    gulp.src('./node_modules/zone.js/**/*.js')
        .pipe(gulp.dest(root_path.package_lib + 'zone.js'));
    gulp.src('./node_modules/systemjs/**/*.js')
        .pipe(gulp.dest(root_path.package_lib + 'systemjs'));
    gulp.src('./node_modules/reflect-metadata/**/*.js')
        .pipe(gulp.dest(root_path.package_lib + 'reflect-metadata'));
    gulp.src('./node_modules/rxjs/**/*.js')
        .pipe(gulp.dest(root_path.package_lib + 'rxjs'));
});

gulp.task("copy-all", ["copy-lib-js"]);
//Copy End

gulp.task('min-js', function () {
    gulp.src(['./clientapp/**/*.js'])
        .pipe(uglify())
        .pipe(gulp.dest(root_path.webroot + 'app'))
});

gulp.task('copy-html', function () {
    gulp.src('clientapp/**/*.html')
        .pipe(gulp.dest(root_path.webroot + 'app'));
});

gulp.task("build-all", ["min-js", "copy-html"]);
//Build End

右键单击 gulpfile.js,然后转到 "任务运行器资源管理器"。

在新窗口中刷新任务,然后右键单击任务以如下屏幕所示运行它。

正如我们所见,所需的库已加载到 "wwwroot/lib" 文件夹中。

前端应用程序

HTML 模板

在本节中,我们将为我们的主 html 页面添加一个基本的引导模板。

文件夹结构

下面是我们的示例应用程序的文件夹结构。正如我们所见,'clientapp' 是根文件夹,它包含入口点文件和根模块。根模块拥有 app 组件,其他组件通过 app 组件与根模块相关联。

Angular 依赖

要启用 ES6 新功能,我们需要解决以下依赖项。

SystemJS 导入:我们的应用程序通过 System.import() 函数加载到浏览器中。

System.import('app/main.js').catch(function (err) { console.error(err); });

在导入模块之前,我们需要使用 System.config() 函数配置 SystemJS,我们将定义要加载的包/文件。

SystemJS 配置:systemjs.config.js

/**
 * System configuration for Angular samples
 * Adjust as necessary for your application needs.
 */
(function (global) {
    System.config({
        paths: {
            // paths serve as alias
            'npm:': '/lib/'
        },
        // map tells the System loader where to look for things
        map: {
            // our app is within the app folder
            'app': 'app',

            // angular bundles
            '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
            '@angular/common': 'npm:@angular/common/bundles/common.umd.js',
            '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
            '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
            '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
            '@angular/http': 'npm:@angular/http/bundles/http.umd.js',
            '@angular/router': 'npm:@angular/router/bundles/router.umd.js',
            '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',

            // other libraries
            'rxjs': 'npm:rxjs',
            'rxjs-compat': 'npm:rxjs-compat',
            'rxjs/operators': 'npm:rxjs/operators'
        },
        // packages tells the System loader how to load when no filename and/or no extension
        packages: {
            'app': {
                main: 'main.js',
                defaultExtension: 'js',
                meta: {
                    '': {
                        format: 'cjs'
                    }
                }
            },
            'rxjs': {
                main: 'index.js',
                defaultExtension: 'js'
            },
            'rxjs/operators': {
                main: 'index.js',
                defaultExtension: 'js'
            }
        }
    });
})(this);

TypeScript 配置

我们需要将我们的 typescript 代码转换为 JavaScript 以支持浏览器,方法是配置 TypeScript 编译器。下面的代码片段是 tsconfig.json 文件的内容。

配置 TypeScript:tsconfig.json

{
  "compileOnSave": false,
  "compilerOptions": {
    "baseUrl": "./",
    "sourceMap": true,
    "declaration": false,
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "target": "es5",
    "typeRoots": [
      "node_modules/@types"
    ],
    "lib": [
      "es2017",
      "dom"
    ],
    "types": [
      "core-js"
    ]
  },
  "includes": [
    "/**/*.ts"
  ]
}

根组件: 

每个应用程序都有一个根组件,它包含注释和定义两部分。它有一个选择器,可以与主 html 页面匹配以进行渲染。

import { Component } from '@angular/core';
@Component({
    selector: 'my-app',
    templateUrl: './app/component/app/app.html'
})

根模块

这里定义了我们的应用程序组件,一个模块可以包含多个组件。每个应用程序都有一个根模块。

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { Routes, RouterModule } from '@angular/router';
import { LocationStrategy, HashLocationStrategy } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';

//Components
import { AppComponent } from './component/app/component';
import { HomeComponent } from './component/home/component';
import { AboutComponent } from './component/about/component';
import { UserComponent } from './component/user/component';

//Routes
const routes: Routes = [
    { path: '', redirectTo: 'home', pathMatch: 'full' },
    { path: 'home', component: HomeComponent },
    { path: 'about', component: AboutComponent },
    { path: 'user', component: UserComponent }
];

@NgModule({
    declarations: [AppComponent, HomeComponent, AboutComponent, UserComponent],
    imports: [BrowserModule, FormsModule, ReactiveFormsModule, RouterModule.forRoot(routes)],
    bootstrap: [AppComponent]
})

export class AppModule { }

启动 Clientapp

让我们创建一个主入口文件,命名为 main.ts。复制下面的代码片段并粘贴到新创建的typescript文件中。

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './module';
const platform = platformBrowserDynamic();
platform.bootstrapModule(AppModule);

此时,我们的应用程序已启动并在浏览器中启动根模块。这是我们在 index.html 页面中启动应用程序的方式。

主 HTML 页面

<my-app>
    <img src="img/ajax_small.gif" />  Please wait ...
</my-app>
<!-- Core JS Files   -->
<script src="/js/jquery/jquery-1.10.2.js" type="text/javascript"></script>
<script src="/js/bootstrap/tether.min.js"></script>
<script src="/js/bootstrap/bootstrap.min.js" type="text/javascript"></script>

<!-- App JS Files   -->
<!-- load the dependencies -->
<script src="lib/core-js/client/shim.js" type="text/javascript"></script>
<script src="lib/zone.js/dist/zone.js" type="text/javascript"></script>
<script src="lib/reflect-metadata/Reflect.js" type="text/javascript"></script>

<!-- load our angular app with systemjs -->
<script src="lib/systemjs/dist/system.src.js" type="text/javascript"></script>
<script src="systemjs.config.js" type="text/javascript"></script>

<script type="text/javascript">
    System.import('app/main.js').catch(function (err) { console.error(err); });
</script>

让我们构建并运行应用程序。

我们的应用程序正在运行,正如我们从上面的屏幕截图可以看到的,它显示了欢迎消息。接下来,我们将创建表单,然后进行提交和验证,之后我们将使用 SQL 数据库执行 CRUD 操作。

创建数据库

让我们在 MSSQL Server 中创建一个数据库。这是我们存储数据的表。在查询窗口中运行以下脚本以创建新数据库。

CREATE DATABASE [dbCore]

创建表

USE [dbCore]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[User](
	[Id] [int] IDENTITY(1,1) NOT NULL,
	[FirstName] [nvarchar](250) NULL,
	[LastName] [nvarchar](250) NULL,
	[Email] [nvarchar](250) NULL,
	[Phone] [nvarchar](50) NULL,
 CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED 
(
	[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

安装 Entity Framework Core

Entity Framework (EF) Core 是一种数据访问技术,面向跨平台。让我们右键单击项目,然后转到 > 工具 > NuGet 包管理器 > 程序包管理器控制台,一个接一个地安装以下包。

  • Install-Package Microsoft.EntityFrameworkCore.SqlServer
  • Install-Package Microsoft.EntityFrameworkCore.SqlServer.Design
  • Install-Package Microsoft.EntityFrameworkCore.Tools.DotNet

EntityFrameworkCore.SqlServer:数据库提供程序,它允许 Entity Framework Core 与 Microsoft SQL Server 一起使用。

EntityFrameworkCore.SqlServer.Design:设计时,它允许 Entity Framework Core 功能 (EF Core 迁移) 与 Microsoft SQL Server 一起使用。

EntityFrameworkCore.Tools:EF Core 的命令行工具,包含命令

脚手架 MSSQL 数据库:我们将使用反向工程通过包管理器控制台中的命令从现有数据库生成 EF 模型。

命令

Scaffold-DbContext "Server=DESKTOP-7OJNKVF;Database=dbCore;Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer -Output serverapp/models

对于程序包管理器控制台

  • Scaffold-DbContext
  • Add-Migration
  • Update-Database

对于命令窗口

  • dotnet ef dbcontext scaffold

正如我们在解决方案资源管理器中看到的,模型文件夹已与 Context 和 Entities 一起创建。

现在打开 DbContext 文件,然后添加一个构造函数来将配置(如连接字符串)传递到 DbContext。

public dbCoreContext(DbContextOptions<dbCoreContext> options) : base(options)
{
}

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    //if (!optionsBuilder.IsConfigured)
    //{
    //    #warning To protect potentially sensitive information in your connection string, you should move it out of source code. See http://go.microsoft.com/fwlink/?LinkId=723263 for guidance on storing connection strings.
    //    optionsBuilder.UseSqlServer(@"Server=DESKTOP-7OJNKVF;Database=dbCore;Trusted_Connection=True;");
    //}
}

配置中间件

注册 DbContext:在 Startup.cs 中,让我们将 DbContext 添加为服务,以启用数据库连接。

//Database Connection
var connection = @"Server=DESKTOP-7OJNKVF;Database=dbCore;Trusted_Connection=True;";
services.AddDbContext<dbCoreContext>(options => options.UseSqlServer(connection));

创建 ASP.Net Core WebAPI

这是我们使用全局特定 RoutePrefix 属性的 ASP.Net Core WebAPI 控制器。通过这个 api 控制器类,我们使用 Entity Framework DbContext 执行数据库操作。

[Route("api/Values"), Produces("application/json"), EnableCors("AppPolicy")]
public class ValuesController : Controller
{
    private dbCoreContext _ctx = null;
    public ValuesController(dbCoreContext context)
    {
        _ctx = context;
    }


    // GET: api/Values/GetUser
    [HttpGet, Route("GetUser")]
    public async Task<object> GetUser()
    {
        List<User> users = null;
        object result = null;
        try
        {
            using (_ctx)
            {
                users = await _ctx.User.ToListAsync();
                result = new
                {
                    User
                };
            }
        }
        catch (Exception ex)
        {
            ex.ToString();
        }
        return users;
    }

    // GET api/Values/GetByID/5
    [HttpGet, Route("GetByID/{id}")]
    public async Task<User> GetByID(int id)
    {
        User user = null;
        try
        {
            using (_ctx)
            {
                user = await _ctx.User.FirstOrDefaultAsync(x => x.Id == id);
            }
        }
        catch (Exception ex)
        {
            ex.ToString();
        }
        return user;
    }


    // POST api/Values/Save
    [HttpPost, Route("Save")]
    public async Task<object> Save([FromBody]vmUser model)
    {
        object result = null; string message = "";
        if (model == null)
        {
            return BadRequest();
        }
        using (_ctx)
        {
            using (var _ctxTransaction = _ctx.Database.BeginTransaction())
            {
                try
                {
                    if (model.id > 0)
                    {
                        var entityUpdate = _ctx.User.FirstOrDefault(x => x.Id == model.id);
                        if (entityUpdate != null)
                        {
                            entityUpdate.FirstName = model.firstName;
                            entityUpdate.LastName = model.lastName;
                            entityUpdate.Phone = model.phone;
                            entityUpdate.Email = model.email;
                            await _ctx.SaveChangesAsync();
                        }
                    }
                    else
                    {
                        var UserModel = new User
                        {
                            FirstName = model.firstName,
                            LastName = model.lastName,
                            Email = model.email,
                            Phone = model.phone
                        };

                        _ctx.User.Add(UserModel);
                        await _ctx.SaveChangesAsync();
                    }

                    _ctxTransaction.Commit();
                    message = "Saved Successfully";
                }
                catch (Exception e)
                {
                    _ctxTransaction.Rollback();
                    e.ToString();
                    message = "Saved Error";
                }

                result = new
                {
                    message
                };
            }
        }
        return result;
    }

    // DELETE api/Values/DeleteByID/5
    [HttpDelete, Route("DeleteByID/{id}")]
    public async Task<object> DeleteByID(int id)
    {
        object result = null; string message = "";
        using (_ctx)
        {
            using (var _ctxTransaction = _ctx.Database.BeginTransaction())
            {
                try
                {
                    var idToRemove = _ctx.User.SingleOrDefault(x => x.Id == id);
                    if (idToRemove != null)
                    {
                        _ctx.User.Remove(idToRemove);
                        await _ctx.SaveChangesAsync();
                    }
                    _ctxTransaction.Commit();
                    message = "Deleted Successfully";
                }
                catch (Exception e)
                {
                    _ctxTransaction.Rollback(); e.ToString();
                    message = "Error on Deleting!!";
                }

                result = new
                {
                    message
                };
            }
        }
        return result;
    }
}

好了,我们的 WebAPI 已准备好与数据库交互。我们的下一步是准备客户端模型、组件和服务以与 WebAPI 交互。

执行 CRUD 操作

让我们开始进行表单设计。Angular6 表单有两种策略,在此示例中,我们使用了模型驱动表单。

  1. 模板驱动
  2. 模型驱动

UI:user.html

<div class="container-fluid">
    <div class="row">
        <div class="col-sm-4">
            <h3>User Details</h3>
            <form [formGroup]="userForm" #f="ngForm" (ngSubmit)="save()">
                <div class="form-group">
                    <label for="firstName">First Name</label><em *ngIf="userForm.controls['firstName'].hasError('required')" class="text-danger">*</em>
                    <input type="text" id="firstName" name="firstName" formControlName="firstName" class="form-control" placeholder="First Name" required />
                </div>
                <div class="form-group">
                    <label for="lastName">Last Name</label><em *ngIf="userForm.controls['lastName'].hasError('required')" class="text-danger">*</em>
                    <input type="text" formControlName="lastName" class="form-control" placeholder="Last Name" required />
                </div>
                <div class="form-group">
                    <label for="email">Email</label><em *ngIf="userForm.controls['email'].hasError('required')" class="text-danger">*</em>
                    <input type="email" formControlName="email" class="form-control" placeholder="Email" required />
                    <span *ngIf="userForm.controls['email'].hasError('pattern')" class="text-danger">
                        Invalid Email 
                    </span>
                </div>
                <div class="form-group">
                    <label for="phone">Phone</label><em *ngIf="userForm.controls['phone'].hasError('required')" class="text-danger">*</em>
                    <input type="text" formControlName="phone" class="form-control" placeholder="Phone" required />
                </div>
                <div class="form-group">
                    <button type="button" class="btn btn-danger" (click)="reset()">Reset</button>
                    <button type="submit" class="btn btn-primary ml-10" [disabled]="!f.valid">Save</button>
                </div>
            </form>
            <span class="warning"></span>
        </div>
        <div class="col-sm-8">
            <h3>All User</h3>
            <table style="width:100%" class="table table-striped">
                <tr>
                    <th>Sr.</th>
                    <th>Name</th>
                    <th>Email</th>
                    <th>Phone</th>
                    <th>Option</th>
                </tr>
                <tr *ngFor="let item of users;let sl = index">
                    <td>{{sl+1}}</td>
                    <td>{{item.firstName}} {{item.lastName}}</td>
                    <td>{{item.email}}</td>
                    <td>{{item.phone}}</td>
                    <td>
                        <a href="#" title="Edit Record" class="btn btn-primary btn-xs pull-right" (click)="edit($event, item)">
                            Edit
                        </a>
                        <a href="#" title="Delete Record" class="btn btn-danger btn-xs pull-right" (click)="delete($event, item)">
                            Delete
                        </a>
                    </td>
                </tr>
            </table>
        </div>
    </div>
</div>

让我们创建一个 typescript 模型类,然后通过导入如下方式在另一个组件中使用它

import { UserModel } from './model';

Typescript 模型:UserModel

export class UserModel {
    id: number;
    firstName: string;
    lastName: string;
    phone: string;
    email: string;
}

下面是与 UI 交互的 UserComponent,它验证表单,然后通过服务组件发送/接收数据。它从 Angular6 库导入 Component 函数,使用 "export" 意味着 app 组件类可以从其他组件导入。

组件:UserComponent

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, Validators, FormBuilder } from '@angular/forms';

import { UserModel } from './model';
import { UserService } from './service';

@Component({
    selector: 'user',
    templateUrl: './app/component/user/user.html',
    providers: [UserService]
})

export class UserComponent implements OnInit {
    public user: UserModel;
    public users: UserModel[];
    public resmessage: string;
    userForm: FormGroup;

    constructor(private formBuilder: FormBuilder, private userService: UserService) { }

    ngOnInit() {
        this.userForm = this.formBuilder.group({
            id: 0,
            firstName: new FormControl('', Validators.required),
            lastName: new FormControl('', Validators.required),
            email: new FormControl('', Validators.compose([
                Validators.required,
                Validators.pattern('^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+$')
            ])),
            phone: new FormControl('', Validators.required)
        });
        this.getAll();
    }
    onSubmit() {
        if (this.userForm.invalid) {
            return;
        }
    }

    //Get All User
    getAll() {
        //debugger
        this.userService.getall().subscribe(
            response => {
                //console.log(response)
                this.users = response;
            }, error => {
                console.log(error);
            }
        );
    }

    //Get by ID
    edit(e, m) {
        //debugger
        e.preventDefault();
        this.userService.getByID(m.id)
            .subscribe(response => {
                //console.log(response);
                this.user = response;
                this.userForm.setValue({
                    id: this.user.id,
                    firstName: this.user.firstName,
                    lastName: this.user.lastName,
                    email: this.user.email,
                    phone: this.user.phone
                });
            }, error => {
                console.log(error);
            });
    }

    //Save Form
    save() {
        //debugger
        this.userService.save(this.userForm.value)
            .subscribe(response => {
                //console.log(response)
                this.resmessage = response;
                this.getAll();
                this.reset();
            }, error => {
                console.log(error);
            });
    }

    //Delete
    delete(e, m) {
        //debugger
        e.preventDefault();
        var IsConf = confirm('You are about to delete ' + m.firstName + '. Are you sure?');
        if (IsConf) {
            this.userService.delete(m.id)
                .subscribe(response => {
                    //console.log(response)
                    this.resmessage = response;
                    this.getAll();
                }, error => {
                    console.log(error);
                });
        }
    }

    reset() {
        this.userForm.setValue({
            id: 0,
            firstName: null,
            lastName: null,
            email: null,
            phone: null
        });
    }
}

下面是服务组件,它将在 UserComponent 执行的每次操作时被调用。在我们的 UserService 中,我们有 Http 服务 [Get, Post, Put, Delete],它连接到 WebAPI 来执行创建、读取、更新和删除操作。

Http 客户端服务:UserService

import { Injectable, Component } from '@angular/core';
import { HttpModule, Http, Request, RequestMethod, Response, RequestOptions, Headers } from '@angular/http';
import { Observable, Subject, ReplaySubject } from 'rxjs';
import { map, catchError } from 'rxjs/operators';

//Model
import { UserModel } from './model';

@Component({
    providers: [Http]
})

@Injectable()

export class UserService {
    public headers: Headers;
    public _getUrl: string = '/api/Values/GetUser';
    public _getByIdUrl: string = '/api/Values/GetByID';
    public _deleteByIdUrl: string = '/api/Values/DeleteByID';
    public _saveUrl: string = '/api/Values/Save';

    constructor(private _http: Http) { }

    //Get
    getall(): Observable<UserModel[]> {
        return this._http.get(this._getUrl)
            .pipe(map(res => <UserModel[]>res.json()))
            .pipe(catchError(this.handleError));
    }

    //GetByID
    getByID(id: string): Observable<UserModel> {
        var getByIdUrl = this._getByIdUrl + '/' + id;
        return this._http.get(getByIdUrl)
            .pipe(map(res => <UserModel>res.json()))
            .pipe(catchError(this.handleError));
    }

    //Post
    save(user: UserModel): Observable<string> {
        let body = JSON.stringify(user);
        let headers = new Headers({ 'Content-Type': 'application/json' });
        let options = new RequestOptions({ headers: headers });
        return this._http.post(this._saveUrl, body, options)
            .pipe(map(res => res.json().message))
            .pipe(catchError(this.handleError));
    }

    //Delete
    delete(id: string): Observable<string> {
        var deleteByIdUrl = this._deleteByIdUrl + '/' + id
        return this._http.delete(deleteByIdUrl)
            .pipe(map(response => response.json().message))
            .pipe(catchError(this.handleError));
    }

    private handleError(error: Response) {
        return Observable.throw(error.json().error || 'Opps!! Server error');
    }
}

在浏览器中测试

现在是时候构建和运行应用程序了。让我们尝试使用该系统执行 CRUD 操作。正如我们从下面的截图可以看到的,数据正从数据库加载到用户页面。

摘要

在此示例中,我们将 ASP.Net Core 和 Angular 结合起来创建一个示例 SPA 应用,无需任何 CLI。学习如何从空的 ASP.Net Core 应用程序开始提供静态 html 页面。

我们还从头开始深入研究了最新的前端技术,如 Angular6,以构建一个单页应用程序。

简要概述了 Angular6 依赖项,并对模块、组件有了初步了解。然后,我们使用我们的示例应用程序执行了一些数据库操作。希望这会有所帮助。

© . All rights reserved.