ASP.NET MVC和Web API中的Angular2 - 第1部分

内容

第1部分:Visual Studio 2017中的Angular2设置,基本CRUD应用程序,第三方模态弹出控件

第2部分:使用Angular2管道进行过滤/搜索,全局错误处理,调试客户端

介绍

由于Angular2广泛应用于Web和移动开发的客户端框架,在本文中,我将尝试解释一步一步的指导,使用Angular2和MVC Web API创建基本的CRUD(创建,读取,更新和删除)应用程序作为后端RESTful API 。我将创建空白的ASP.NET MVC应用程序,然后设置Angular2环境,然后创建将有两个页面的Web应用程序,一个仅用于一个图像的主页,另一个将是用户管理页面,其中将从SQL加载数据服务器数据库和用户可以选择添加新用户,更新和删除现有用户。对于所有数据库操作,Anguar2将调用使用ASP.NET MVC Web API开发的RESTful API。

这是一个初级文章,目的是为初学者和具有编程基础知识的学生撰写,并希望从头开始学习Angular2,C#和RESTful API。如果您是经验丰富的开发人员,只需要概述,您可以下载附件项目并进行浏览。您需要Visual Studio和SQL Server Management Studio在文章中开发项目并编译附加的项目。下载Visual Studio 2017社区SQL Server Management Studio

开始吧

设置Angular2环境

  1. 打开Visual Studio,我正在使用Visual Studio 2017社区,您可以使用Visual Studio 2015社区和更新3安装Node.jsTypeScript 包。(阅读更多关于Visual Studio 2015更新3)
  2. 转到文件菜单,然后选择 File -> New -> Project
  1. 输入项目名称并选择所需的.Net框架(我正在.Net Framework 4.6 为本文使用 )。点击 OK 按钮:
  1. MVC 从下一个屏幕中选择并检查Web API 添加文件夹和核心参考选项,因为我们将为CRUD操作创建RESTful API。点击OK 按钮:
  1. 创建基本的ASP.NET MVC项目,下一步是为Angular2应用程序做准备。我们来做下一步。
  2. 右键单击项目Angular2MVC 并选择Add -> New Item
  1. 输入package.json右上角的搜索文本框,npm Configuration File将被过滤。点击Add 按钮添加package.json项目:
  1. 我们将使用NPM (Node Package Manager)配置文件来管理所有Angular2包。要了解有关NPM的更多信息,请查看此链接
  2. 接下来,从Angular2 Quick Start GitHub链接复制Package.json,并将其粘贴package.jsonAngular2MVC 项目中新增的文件中:
  1. package.json文件的依赖部分,我们可以看到所有Angular2相关的软件包,看看这里有什么区别^~ 签名。
  2. 右键单击package.json文件并选择选项Restore Packages,Visual Studio Node.js工具将下载package.json文件中提到的所有相关软件包,将来如果您需要任何其他软件包,只需将其添加到DevDepnedencies 部分并将其还原,这将使生活更轻松:
  1. 您将node_modules在项目中找到包含所有下载的软件包的新文件夹:
  1. 下一步让我们的项目知道如何获取这些包,我们将添加systemjs.config.js文件。右键单击Angular2MVC 项目并选择Add -> JavaScript file
  1. systemjs.config.jsItem name 字段中输入名称,然后单击OK 按钮:
  1. systemjs.config.js从Angular2快速启动GitHub 复制文件的内容,并将其粘贴systemjs.config.jsAngular2MVC 项目中新添加的文件中:
  1. 接下来,我们TypeScript JSON Configuration File 通过右键单击Angular2MVC 项目和Add -> New Item。选择TypeScript JSON Configuration File 并点击OK 按钮:
  1. tsconfig.js从Angular2快速启动GitHub 复制文件的内容,并将其替换tsconfig.jsAngular2MVC 项目中新添加的文件:
  1. 如果您在尝试构建时遇到编译错误,请不用担心。一旦我们开始添加任何typescript file,这些错误就会消失。
  2. 现在,我们在ASP.NET MVC中的Angular2设置几乎完成了,现在是开发应用User Management程序的时候了,但是首先我们需要一个数据库,一个表将保存用户信息。

创建用户数据库和实体框架模型

  1. 右键单击App_Data 文件夹并选择Add -> New item。在数据部分,您可以找到该SQL Server Database选项。选择它并指定名称UserDB
  1. 创建数据库后,双击UserDB.mdf数据库文件打开Tables
  1. 右键单击UserDB.mdf并选择New Query。粘贴以下SQL查询来创建TblUser 表,单击Execute 按钮创建表:

隐藏 复制代码

<span >CREATE TABLE [dbo].[TblUser] (
  [Id]     INT       IDENTITY (1, 1) NOT NULL,
  [FirstName] NVARCHAR (250) NULL,
  [LastName]  NVARCHAR (250) NULL,
  [Gender]   NVARCHAR (250) NULL,
  PRIMARY KEY CLUSTERED ([Id] ASC)
);</span>
  1. 右键单击Tables 文件夹并选择选项Refresh
  1. 接着让开发ASP.NET MVC,其包括设置侧LayoutIndex 页面加载Angular2主页沿MVC控制器加载索引视图和Web API 2.0控制器,用于基于REST CRUD( ,,Create 和)用户的API。ReadUpdateDelete
  2. 我们首先去App_Start 文件夹并配置路由以接受任何URL,因为我们可以在Angular2中定义我们的自定义路由(将在以后的步骤中进行)。双击RouteConfig.cs文件进行编辑,并按默认路径更改URL,如下所示:
  1. 接下来,我们打开我们的_Layout.cshtml, 清理一点,并添加重要JavaScripts 文件来运行Angular2应用程序。打开Views -> Shared -> _Layout.cshtml 文件 删除预先添加的顶层菜单和页面链接。system.import在标题部分中添加以下JS文件和语句:

隐藏 复制代码

<span ></script>
  <script src="/node_modules/zone.js/dist/zone.js"></script>
  <script src="/node_modules/systemjs/dist/system.src.js"></script>
  <script src="/systemjs.config.js"></script>
  <script>
   System.import('app').catch(function(err){ console.error(err); });
  </script></span>
只是一个简短的介绍这些JS文件是什么。

Zone.js:区域是一个持续异步任务的执行上下文。欲了解更多信息,请点击这里

System.src.js & system.import(‘app’):可配置模块加载器,可在浏览器和NodeJS中启用动态ES模块工作流程。欲了解更多信息,请点击这里

  1. 你的决赛_Layout.cshtml应该如下所示:
  1. 接下来我们来创建ADO.NET Entity Data Modalfor UserDB 数据库。右键单击Angular2MVC 项目并选择Add -> New Folder,指定名称DBContext 或任何您想要的:
  1. 右键单击新创建的文件夹DBContext ,然后选择Add -> New Item
  1. 从左侧面板下方Visual C#选择Data。在右侧选择ADO.NET Entity Data Model。输入名称UserDBEntities 或您选择的任何一种。点击Add 按钮。
  1. 从下一个屏幕,选择EF Designer for Data,点击Next 按钮:
  1. 点击New Connection下一个屏幕上的按钮:
  1. 在下一个屏幕上,如果未选择“数据源” Microsoft SQL Server Database file (SqlClient),请单击Change 按钮并选择它:
  1. Database file name,点击Browse 按钮:
  1. 浏览到UserDB 在早期步骤中创建并保存在App_Data 文件夹中的数据库,单击OK 两者Select SQL Server Database FileConnection Properties窗口上的按钮:
  1. 选中该Save Connection Settings in Web.Config as复选框,然后单击Next 按钮:
  1. 在下一个屏幕中,您可以选择Entity Framework版本,我正在使用6.x,可以根据您的选择使用:
  1. 在下一个屏幕上单击Tables 复选框,您将看到唯一的一个表TblUser,点击Finish 按钮结束向导:
  1. 这将需要几秒钟,最后你会看到我们的数据库实体模型有一个表:
  1. 仍然在这一点上,如果你尝试编译你的项目,你可能会收到很多typescript 错误,为了解决它,创建名称的文件夹app,右键单击它并选择Add -> TypeScript File
  1. 输入名称main.ts并单击OK (我们将在以后的步骤中使用此文件)。现在重建项目,应该成功建成。

开发用户管理RESTful API

  1. 下一步是创建ASP.NET MVC Web APIsreadaddupdatedelete 用户。
  2. 首先,我们将创建具有所有API控制器共享的常用方法的Parent API控制器,因为现在我们将只有一种方法将类对象序列化为Angular2前端的JSON字符串,也可以为 UserDB 数据库DBContext 对象执行数据库操作子控制器。右键单击Controllers 文件夹,然后选择Add -> Controller…
  1. 选择Web API 2 Controller – Empty并点击Add 按钮:
  1. 输入名称BaseAPIController 并点击Add 按钮:
  1. 在下列代码中添加BaseAPIController

隐藏 复制代码

<span >protected readonly UserDBEntities UserDB = new UserDBEntities();
    protected HttpResponseMessage ToJson(dynamic obj)
    {
      var response = Request.CreateResponse(HttpStatusCode.OK);
      response.Content = new StringContent(JsonConvert.SerializeObject(obj), Encoding.UTF8, "application/json");
      return response;
    }</span>
  1. 以上给出的代码是非常不言自明的,我们正在创建UserDBEntities 名为的类对象, UserDB 通过它可以调用加载,添加,更新和删除用户的方法。ToJson 方法是使用任何类对象, HTTP Response object使用OK HttpStatusCode 创建并通过JsonConvertNewtonsoft.json库调用方法将对象序列化为JSON字符串。最终代码应如下所示:

  1. 接下来,我们来创建RESTful Web APIs用户管理,即加载数据库中的所有用户,添加新用户,更新和删除现有用户。我们正在创建以下方法:
    1. GET 方法来读取所有用户。
    2. POST 创建新用户的方法。
    3. PUT 方法来更新现有用户。
    4. DELETE 方法删除现有用户。
  2. 要了解更多关于HTTP Verbs和方法,请点击这里
  3. 右键单击Controllers 文件夹并选择Add -> Controller…
  1. 选择Web API 2 Controller – Empty并点击Add 按钮:
  1. 输入名称UserAPIController 并点击Add 按钮:
  1. 将UserAPIController类代码替换为以下内容:

隐藏 复制代码

<span >public class UserAPIController : BaseAPIController
    {
        public HttpResponseMessage Get()
        {
            return ToJson(UserDB.TblUsers.AsEnumerable());
        }

       public HttpResponseMessage Post([FromBody]TblUser value)
        {
            UserDB.TblUsers.Add(value);             
            return ToJson(UserDB.SaveChanges());
        }

        public HttpResponseMessage Put(int id, [FromBody]TblUser value)
        {
            UserDB.Entry(value).State = EntityState.Modified;
            return ToJson(UserDB.SaveChanges());
        }
        public HttpResponseMessage Delete(int id)
        {
            UserDB.TblUsers.Remove(UserDB.TblUsers.FirstOrDefault(x => x.Id == id));
            return ToJson(UserDB.SaveChanges());
        }
    }</span>
    1. UserAPIController 继承自BaseAPIController 使用UserDB 对象和ToJson 方法将User 实体转换为JSON字符串并将其保存在HTTP响应消息中。
    2. Get():从数据库加载所有用户,并将包含用户实体的HTTP响应消息转换为JSON 字符串。
    3. Post([FromBody]TblUser value):从前端取出用户信息并保存到数据库。返回1成功保存。
    4. Put(int id, [FromBody]TblUser value):取现有的用户ID和更新的信息并将其更新到数据库。返回1成功更新。
    5. Delete(int id):取现有用户ID,通过id加载用户并删除它。返回1成功删除。
  1. 最终UserAPIController 课程应如下所示:

开发Angular2应用程序

  1. 现在让我们开始编写Angular2 代码的令人兴奋的部分。在编写代码之前,了解架构是非常重要的Angular2 ,因为我不是专注于写Angular2,因为您可以找到大量的教程和免费的视频,让我们修改基本的结构,Angular2 如果你懒得到从这里转到angular.io网站:
    1. Modules:每个Angular应用程序至少有一个Angular模块类,该root 模块。该应用程序bootstrapping 由其根模块启动。在开发过程中,您可能会在随后的步骤中创建AppModulemain.ts文件中引导。根模块通常命名AppModule。在AppModule 我们指定所有componentsservices 或自定义pipe 使用的应用程序过滤器。
    2. Components:组件控制屏幕上的视图,您可以定义propertiesmethods 控制视图。如果你曾经使用ASP.NET表单,我会说组件就像aspx.cs文件中的代码一样,通过方法和属性来交互aspx文件。
    3. Templates:您可以使用其伴随模板定义组件的视图。A template 是一种HTML形式,它告诉Angular如何渲染组件。它就像aspx ASP.NET表格中的一个文件,根据我之前的步骤的例子。
    4. Metadata:元数据告诉Angular如何处理一个类。如果您看到该组件,它只是一个类,MetaData告诉您与该组件,任何样式表关联的模板(代码在后面或可以是HTML),或者如何使用通过Selector 属性指定的组件。
    5. Data binding:简单来说,信息或控件之间如何在模板中单击任何按钮之间传播templatecomponent 例如,如何click 在组件中获取事件并执行逻辑。Angular2提供以下类型的数据绑定:
      1. {{}} interpolation 显示组件中声明的任何变量值。
      2. [ ] property binding用于将值从父组件发送到子组件。我们将在未来的章节中使用它。
      3. ( ) event binding用于从模板到组件获取任何事件。例如(点击)。
    6. Directives:两种指令的存在:structuralattribute 指令。
      1. Structural directives 通过添加,删除和替换DOM中的元素来改变布局。例如*ngFor*ngIf用于循环HTML元素并显示/隐藏元素。
      2. Attribute directives改变现有元素的外观或行为。在模板中,它们看起来像常规的HTML属性,因此名称。例如ngStyle 用于样式表,ngModel 用于双向数据绑定。
    7. Services:服务是一个广泛的类别,涵盖您的应用程序需要的任何价值,功能或功能。关于服务没有什么具体的Angular2。Angular2没有定义服务。没有服务基础类,没有注册服务的地方。服务的例子是ErrorLogHTTPComponent 只能起到模板和用户之间的调解人角色。它应该委托其他功能,例如从服务器获取数据,删除或更新,记录,显示错误等等。
    8. Dependency injection:依赖注入是一种提供一个新实例的方法,它class 具有所需的完全形成的依赖关系。大多数依赖是服务。Angular2使用依赖注入为新组件提供所需的服务。例如,对于HTTP 服务,我们将使用依赖注入来为即将到来的步骤中的组件提供服务实例。
    9. 欲了解更多信息,请点击此处
  2. 希望你已经有大约Angular2建筑的基本理念,让创造用户管理页面(AddUpdateDeleteView 在ASP.NET MVC使用角2使用RESTful API中作为后端服务的用户)。
  3. 在我们的项目中,我们将在app 文件夹中创建所有Angular2相关代码,如下所示,如果您尚未创建app 文件夹,请继续创建。如果您遵循以前的步骤,应该main.ts在应用程序文件夹中有一个typescript文件,我们将用于引导AppModule
  1. 在进一步移动之前,让我展示我们的最终应用程序将如何,它将有两个页面,一个是只有大图像的主页,第二个将具有与用户信息一样的表格,每个记录旁边的编辑和删除按钮一个添加按钮在表的顶部添加新用户。每个按钮将打开模式弹出窗口,您可以在其中执行相应的功能,以下是两页和每个功能的屏幕截图:
  1. 现在,您已经有了关于我们最终应用程序的基本想法,让我们开始研究Angular2应用程序,让我们牢记Angular2架构并创建应用程序的基本架构。
  2. 首先让我们创建An​​gular2 Module ,这将是应用程序的入口点。右键单击app 文件夹,然后选择Add -> TypeScript File
  1. 如果没有看到TypeScript File第二个菜单,右键单击app 文件夹,选择Add -> New Item,搜索TypeScrript 并选择TypeScript file,输入名称并选择OK 按钮:
  1. 输入新的TypeScript文件的名称,app.module.ts然后单击OK 按钮:
  1. 在新添加的代码中添加以下代码app.module.ts

隐藏 复制代码

<span >import { NgModule } from '@angular/core';
import { APP_BASE_HREF } from '@angular/common';
import { BrowserModule } from '@angular/platform-browser';
import { ReactiveFormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
 
 @NgModule({
    imports: [BrowserModule, ReactiveFormsModule, HttpModule],
    declarations: [],
    providers: [{ provide: APP_BASE_HREF, useValue: '/' }],
    bootstrap: []
})

export class AppModule { }</span>
  1. 只是为了刷新你的记忆,我们正在使用TypeScipt Angular2。如果您想了解更多关于TypeScript的信息,请点击这里
  2. 如果您快速AppModule 上课,您可以看到我们正在导入所需的库,例如NgModule 从角度核心,类似地,我们将为Reactive forms用户使用,我们ReactiveFormModule 从角度格式包导入。我们将app.module.ts通过添加用户组件,服务,模式弹出等继续扩展文件。
    1. NgModule 元数据部分:
      1. Imports 包含模块列表。
      2. Declarations 包含组件列表,我们将在后续步骤中添加用户组件。
      3. Providers 包含服务列表。我们将添加HTTP 操作以执行用户读取,添加,更新和删除操作。现在,它有基本href 路径。
      4. Bootstrap 包含条目组件,我们将app.component.ts在后续步骤中创建文件,并将其添加到此处。
  3. 下一步是编辑main.tsapp 文件夹并添加下面的代码是:

隐藏 复制代码

<span >import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app.module';



platformBrowserDynamic().bootstrapModule(AppModule);</span>
  1. main.ts代码是非常不言自明的。AppModule 引用是从当前文件夹导入,将其作为模块,并使用plateformBrowserDynamic 模块的bootstrapModule 功能加载其他帮助资源(Bootstrapping)以供应用。Bootstrap 函数初始化Angular2应用程序,加载所需的组件,服务或其他帮助资源来运行应用程序。尝试构建项目以避免后续步骤中的任何错误。
  2. 接下来,创建两个TypeScripts文件app.component.ts,并app.routing.ts为主应用程序组件和路由表创建。稍后再回来,右键点击app 文件夹,选择Add -> TypeScript File
  1. 输入名称app.component.ts并点击OK 按钮:
  1. 再次点击app 文件夹并选择Add -> TypeScript File,输入名称app.routing.ts 并点击OK 按钮:
  2. 下面我们来创建Home 一个只有一个大图片的组件:
  3. 我们将在新文件夹中创建所有用户组件,右键单击app 文件夹并选择Add -> New Folder,输入名称Components
  4. 右键单击新创建的文件夹Component ,然后选择Add -> TypeScript File
  5. 输入名称home.component.ts 并点击OK按钮:
  1. 在新创建的home.component.ts文件中添加以下代码:

隐藏 复制代码

<span ;

@Component({
template: `<img src="../../images/users.png" />`
})

export class HomeComponent{
}</span>
  1. HomeComponent,您可以在MetaData的模板属性中看到,我们将users.png在屏幕上显示的根图像文件夹中显示纯HTML图像元素。您可以获取任何图片,将其保存在图像文件夹中并加载HomeComponent
  2. 右键单击Angular2MVC 项目并选择Add -> New Folder,输入文件夹名称为images
  1. 右键单击新添加的文件夹images ,然后选择Open Folder in File Explorer,在打开的位置复制下面给出的图像:
  2. 我们HomeComponent 完成了,让屏幕上看到它。我们需要做更多的步骤来做到这一点。我们首先要做的就是创建Routing 表。如果您使用ASP.NET MVC,此路由表与MVC路由表相同。我们将为不同的视图组件定义自定义路由。第二步,我们将创建我们的主要应用程序组件,我们将在此创建导航菜单并加载所有视图组件。
    1. 双击app.routing.ts应用程序文件夹进行编辑并添加以下代码:

隐藏 复制代码

<span >import { ModuleWithProviders } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { HomeComponent } from './components/home.component';

const appRoutes: Routes = [    
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{ path: 'home', component: HomeComponent }
];

export const routing: ModuleWithProviders = RouterModule.forRoot(appRoutes);</span>
  1. 在上面的代码中,我们从角度路由器包导入路由库,最近HomeComponent 从components文件夹创建。在应用路由器中,该path 属性是浏览器地址栏中可见的实际URL,例如http:// localhost:4500 / home。一旦我们创建UserComponent,我们将为它添加另一个路由。
  2. 接下来请双击app.component.tsapp 文件夹中进行编辑,并添加以下代码:

隐藏 复制代码

<span 
@Component({
     selector: "user-app",
     template: `
               <div>
                  <nav class='navbar navbar-inverse'>
                       <div class='container-fluid'>
                         <ul class='nav navbar-nav'>
                           <li><a [routerLink]="['home']">Home</a></li>
                      </ul>
                      </div>
                 </nav>    
              <div class='container'>
                <router-outlet></router-outlet>
              </div>
             </div>          
`
})

export class AppComponent {
 
}</span>
  1. AppComponent 是超薄的模板与已知的引导代码创建导航栏只有一个家庭链接。home 主页的routerlink 名称是我们在app.routing.ts路由表中定义的。您可以定义任何对您方便的内容,例如默认值,索引等router-outlet作为动态加载视图组件的占位符。我们还定义selector 属性(user-app)中的AppComponent 元数据部分,因为我们将引导AppComponentAppModule ,并使用这个selectorMVC中的视图(index.cshtml)加载它。有关router-outlet点击此处的更多信息。
  2. 所以我们创建了应用程序组件(AppComponent),让我们去AppModule 和注册HomeComponentAppComponent 沿routing 表。之后,我们将添加AppComponent 到bootstrap,为了做到这一切,根据以下更新app.module.ts

隐藏 复制代码

<span >import { NgModule } from '@angular/core';
import { APP_BASE_HREF } from '@angular/common';
import { BrowserModule } from '@angular/platform-browser';
import { ReactiveFormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { AppComponent } from './app.component';
import { routing } from './app.routing';
import { HomeComponent } from './components/home.component';

 
@NgModule({
    imports: [BrowserModule, ReactiveFormsModule, HttpModule, routing],
    declarations: [AppComponent, HomeComponent],
    providers: [{ provide: APP_BASE_HREF, useValue: '/' }],
    bootstrap: [AppComponent]
})

export class AppModule { }</span>

​​​​​​​

  1. 你可以看到,我们进口HomeComponentAppComponent还表示,它在声明和自举AppComponent 为切入点,以我们的应用程序。(Bootstrapping不仅仅是前面步骤中讨论的一个入口点,您可以在Google上进行搜索,以完全理解它。为了简单起见,我仅将其称为入口点)。
  2. 我们几乎可以运行我们的Angular2应用程序并查看主页。转到Views -> Home并双击Index.cshtml进行编辑:
  1. 删除现有代码并输入以下代码行:

隐藏 复制代码

<span >@{
    ViewBag.Title = "Index";
}

<body>
    <user-app>Loading…<user-app>
</body></span>

​​​​​​​

  1. user-appselector 为了AppComponent,这是我们如何使用HTML中的组件:
  1. 接下来,在Solution Explorer上双击systemjs.config.js,并在底部添加main.jspackages部分:
  1. 运行该项目,你应该会看到下面的Web应用程序Home 页面和大的图像,你可以在地址栏看到页面的URL与结尾home 这是我们在主页的路由表中定义相同的URL:
  1. 到目前为止,我们已经在ASP.NET MVC应用程序中为Angular2创建了一个静态页面的基础架构。下一步是创建User Management包括加载所有用户,添加新用户,更新和删除现有用户的页面:
  1. 在用户管理页面中,我们将使用TypeScript Interface (用户模型)Reactive forms和一个第三方组件Ng2-Bs3-Modal进行模态弹出。
    1. Interface:An interface 是一个抽象类型,它不包含类的任何代码。它只定义signature API的形状,这就是为什么我们将使用界面定义我们的用户模型。
    2. Reactive Forms:Angular2提供两种形式,Template 驱动和Reactive Forms(模型驱动形式)。这里有一个伟大的文章可用于这里这里。如果您是ASP.NET MVC开发人员, ReactiveForms就像MVC强类型Razor 视图。
  2. 接下来让我们创建用户interface。右键单击app 文件夹并选择Add -> New Folder。输入文件夹的名称为Models

  1. 右键单击新创建的Models 文件夹,然后选择Add -> TypeScript File,输入文件名为user.ts

  1. 在新创建的用户界面中输入以下变量:

隐藏 复制代码

<span >export interface IUser {
    Id: number,
    FirstName: string,
    LastName: string,
    Gender: string
}</span>
  1. 这些interface 属性与User 数据库中的表相同。关于Angular2的令人敬畏的是,IUser 当我们从数据库中加载数据时,用户对象将自动映射到接口数组RESTful API,在接下来的步骤中,我们将看到如何完成。
  2. 在移动之前UserComponent,让我们创建一些帮助文件,即Global 变量和Enumeration。我更喜欢保存文件中的所有端点,错误消息和其他共享变量Global ,我将为CRUD操作创建枚举。右键单击app 文件夹,然后选择Add ->New Folder,将文件夹命名为shared

  1. 右键单击新创建的shared 文件夹,然后选择Add -> TyepScript File,输入名称为global.ts

  1. 复制以下代码global.ts

隐藏 复制代码

<span >export class Global {
    public static BASE_USER_ENDPOINT = 'api/userapi/';
}</span>
  1. 这是exportable 具有单个静态属性的简单类,BASE_USER_ENDPOINT 具有用于用户管理RESTful API的基本端点。
  2. 再次右键单击shared 文件夹并选择Add -> TypeScript File,输入名称为 enum.ts

  1. 输入以下enum.ts 文件中的代码:

隐藏 复制代码

<span >export enum DBOperation {
    create = 1,
    update = 2,
    delete =3
}</span>

  1. 枚举是不言自明的,而不是用于CRUD操作(“创建”,“更新”,“删除”)的硬编码字符串,我们将使用DBOperation 枚举。
  2. 接下来,让我们创建一些重要的功能来调用ASP.NET RESTful Web API,以便使用Angular2 HTTP 服务进行用户管理。如前面的步骤所述,我们将为RESTful用户API创建GET,POST,PUT和DELETE请求,这些API已经使用ASP.NET MVC Web API在前面的步骤中创建。右键单击app 文件夹,然后选择Add -> New Folder,输入名称Service

  1. 右键单击新创建的Service 文件夹,然后选择Add -> TypeScript File,输入名称为user.service.ts

  1. 在user.service.ts文件中复制以下代码:

隐藏 收缩 复制代码

<span >import { Injectable } from '@angular/core';
import { Http, Response, Headers, RequestOptions} from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/catch';

@Injectable()
export class UserService {
  constructor(private _http: Http) { }

  get(url: string): Observable<any> {
    return this._http.get(url)
      .map((response: Response) => <any>response.json())
      // .do(data => console.log("All: " + JSON.stringify(data)))
      .catch(this.handleError);
  }

  post(url: string, model: any): Observable<any> {
    let body = JSON.stringify(model);
    let headers = new Headers({ 'Content-Type': 'application/json' });
    let options = new RequestOptions({ headers: headers });
    return this._http.post(url, body, options)
      .map((response: Response) => <any>response.json())
      .catch(this.handleError);
  }

  put(url: string, id: number, model: any): Observable<any> {
    let body = JSON.stringify(model);
    let headers = new Headers({ 'Content-Type': 'application/json' });
    let options = new RequestOptions({ headers: headers });
    return this._http.put(url+id, body, options)
      .map((response: Response) => <any>response.json())
      .catch(this.handleError);
  }

  delete(url: string, id: number): Observable<any> {
    let headers = new Headers({ 'Content-Type': 'application/json' });
    let options = new RequestOptions({ headers: headers });
    return this._http.delete(url+id,options)
      .map((response: Response) => <any>response.json())
      .catch(this.handleError);
  }

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

}</span>

为了了解上述代码,我们需要了解一下Observable,只需在Google上搜索即可轻松获取相关信息,但我希望能够快速浏览以下链接:

https://scotch.io/tutorials/angular-2-http-requests-with-observables

  1. 在几行中,Observable 更像数据流,与promise 方法(Angular 1.x)相反,Observable 不会立即返回响应,而是在流中,它提供了非常有用的方法,例如map (用于将结果映射到接口),filter(过滤器来自数据数组的任何特定记录)等Observable 也提供HTTP 请求处理。Rxjs 是一个永恒的图书馆,为我们提供所有的Observable 方法。

  2. 第一种方法是get将RESTful API URL作为参数并返回Observable<any>,还可以指定interface 返回的特定类型,Observable<IUser[]>但是我尽量保持通用。在下一行中,通过提供输入RESTful API用户来调用http get方法,调用map 方法将JSON响应映射到any 类型,您可以指定特定类型<IUser[]>response.json()。类型any 就像dynamic 在C#中,它执行编译类型检查。

  1. 关于RESTful API的一个很棒的事情是HTTP动词,如函数名称,即如果函数名是从GET,PUT,POST或DELETE开始,我们只需要基本URL(端点),通过HTTP调用,它自动确定相应的函数。很明显,一个Web API控制器应该有一个HTTP动词方法。
  2. POST,PUT和DELETE的其他方法具有几乎相同的功能体,创建http头,并IUser 在Web API控制器功能中接收正文的接口,并自动将user 列转换为实体,因为列名匹配。
  3. 现在我们创建了这个user 服务,我们把它添加到AppModule。双击app.module.ts文件app 夹中的文件夹进行编辑。UserService 通过添加以下行导入:

隐藏 复制代码

<span >import { UserService} from './Service/user.service'</span>
  1. 添加在UserService 提供AppModule 程序部分。

  1. 之后,让创建UserComponent。右键单击Components 文件夹,然后选择Add -> TypeScript File

  1. 输入名称为user.component.ts

  1. 我们将template 在单独的html文件中创建,因此右键单击Components 文件夹再次选择Add-> HTML Page

  1. 输入名称为user.component.html

  1. 之前UserComponent,请配置一个第三方组件的模式popng2 -bs3-modal。使用起来非常简单。
  2. Package.jsonAngular2MVC 项目中双击文件,并在以下devDependencies 部分添加以下包:

“ng2-bs3-modal”:“0.10.4”

  1. 现在让我们从NPM下载这个包,右键点击package.json并选择Restore Packages

  1. 双击systemjs.config.jsAngular2MVC 项目:
  2. 在以下map 部分中添加以下文本:

'ng2-bs3-modal':'npm:/ ng2-bs3-modal'

  1. 在软件包部分添加以下文本:

'NG2-BS3模态':

{main:'/bundles/ng2-bs3-modal.js',defaultExtension:'js'}

  1. 最终更新应如下所示:

  1. 现在,由于我们的模态弹出,我们创建UserComponent 将查看所有用户,添加新用户,编辑和删除现有用户。双击user.component.ts文件app -> components夹中的文件夹进行编辑:

  1. 首先添加以下import 语句:

隐藏 复制代码

<span >import { Component, OnInit, ViewChild } from '@angular/core';
import { UserService } from '../Service/user.service';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { ModalComponent } from 'ng2-bs3-modal/ng2-bs3-modal';
import { IUser } from '../Model/user';
import { DBOperation } from '../Shared/enum';
import { Observable } from 'rxjs/Rx';
import { Global } from '../Shared/global';</span>
  1. 我们正在导入组件OnInit (使用OnInit事件)ViewChild (访问Modal弹出属性)。
  2. 然后我们导入UserSerivce 执行对服务器的HTTP调用。
  3. UserComponent 我们将使用Reactive (模型驱动)表单,我发现方式比模板驱动的表单更有条理和易于使用。对我来说,它看起来像一个强力类型的ASP.NET MVC剃刀视图,它也是好的unit testing。表单域,验证和验证错误可以在TypeScript端进行管理,HTML视图具有最小的形式逻辑,这是将代码保存在一个地方的良好做法。要了解有关活动表单的更多信息,请点击此处
  4. ModalComponent 是我们以前的步骤下载的第三方模态弹出窗口。
  5. IUser 是我们将用作模型的界面,用于存储用户信息。
  6. DBOperation 并且Global 是枚举和全局变量。
  7. Observable我们在前面的步骤中简要讨论过。我们将使用subscribefilter 从Rxjs库函数。
  8. 下面复制以下元素元数据信息的import语句:

隐藏 复制代码

<span >@Component({
    
templateUrl: 'app/Components/user.component.html'

})</span>
  1. 既然User 是一个父组件,我们不会在任何其他组件中使用它,所以我们没有指定Selector 属性。用户组件的HTML将被user.component.html存档。
  2. 接下来让我们启动UserComponent 类体,并声明所需的变量:

隐藏 复制代码

<span >export class UserComponent implements OnInit 
{
    @ViewChild('modal') modal: ModalComponent;
    users: IUser[];
    user: IUser;
    msg: string;
    indLoading: boolean = false;
    userFrm: FormGroup;
    dbops: DBOperation;
    modalTitle: string;
    modalBtnTitle: string;
}</span>
  1. 我们正在开始我们的课程export ,然后与我们的UserComponent 名字,因为我们将使用onInit 事件,我们的班级应该实施这个。
  2. 下一行开头@ViewChild(‘modal’),则modal 是占位符模态弹出组件,我们将在HTML模板创建。如果您要访问TypeScript中的任何HTML元素,这是语法。:ModalComponent指定元素的类型。
  3. 接下来,我们创建一个IUser 接口数组来保存用户列表,并使用一个IUser来保存一个用户信息进行添加,编辑和删除。其他几个字符串和布尔变量,我们将在后续步骤中使用来显示一些消息。
  4. 正如我们在之前的步骤中讨论的,我们将使用Reactive(Model-driven)形式,因此我们创建了userform Formgroup类型。
  5. 接下来是constructor 为UserComponent类添加:

隐藏 复制代码

<span >constructor(private fb: FormBuilder, private _userService: UserService) { }</span>
  1. 关于Angular2的伟大事情是依赖注入,在构造函数中可以看到,我们通过DI 获取FormBuilderUserService 实例。要了解更多DI,请点击这里
  2. 到目前为止,我们UserComponent 应该如下所示:

  1. 在这一点上,您可能会收到错误,因为ngOnInit 尚未实现ngOnInit 事件,我们继续添加事件,我们将创建并初始化“活动用户”窗体:

隐藏 复制代码

<span >ngOnInit(): void {

        this.userFrm = this.fb.group({
            Id: [''],
            FirstName: ['', Validators.required],
            LastName: [''],
            Gender: ['']
        });
        
       this.LoadUsers();
    
     }</span>
  1. 我们正在初始化用户表单,指定表单元素和验证规则。现在窗体用空字符串“'初始化。
  2. 接下来让我们创建一个LoadUsers 方法,如name所示,这个方法将调用get方法UserService 从数据库中通过RESTful API加载所有用户:

隐藏 复制代码

<span >LoadUsers(): void {
           this.indLoading = true;
           this._userService.get(Global.BASE_USER_ENDPOINT)
            .subscribe(users => { this.users = users; this.indLoading = false; },
            error => this.msg = <any>error);

           }</span>
  1. SubscribeObservable 我们以前步骤讨论的一部分。一旦用户加载完成,它将保存在users 变量中。如果有任何错误,错误信息将被保存在msg 变量中。indLoading 是我们在这里使用的布尔变量来显示加载消息,直到完全响应被加载。

  2. 接下来,我们添加三种方法来显示添加,更新和删除用户的模态弹出窗口。添加以下函数的代码:

隐藏 收缩 复制代码

<span >addUser() {
       this.dbops = DBOperation.create;
       this.SetControlsState(true);
       this.modalTitle = "Add New User";
       this.modalBtnTitle = "Add";
       this.userFrm.reset();
       this.modal.open();
   }

   editUser(id: number) {
       this.dbops = DBOperation.update;
       this.SetControlsState(true);
       this.modalTitle = "Edit User";
       this.modalBtnTitle = "Update";
       this.user = this.users.filter(x => x.Id == id)[0];
       this.userFrm.setValue(this.user);
       this.modal.open();
   }

   deleteUser(id: number) {
       this.dbops = DBOperation.delete;
       this.SetControlsState(false);
       this.modalTitle = "Confirm to Delete?";
       this.modalBtnTitle = "Delete";
       this.user = this.users.filter(x => x.Id == id)[0];
       this.userFrm.setValue(this.user);
       this.modal.open();
   }
</span>
  1. 这些所有的方法都是类似的,所以让我们来看看AddUser方法并理解它。首先,我们将当前的DB操作存储在枚举类型的dpops 变量中DBOperation 。接下来,我们正在调用SetControlsState 将启用或禁用表单控件的方法。下一个变量是设置模态弹出标题和按钮标题。在AddUser函数中,我们正在重置表单以清除表单。接下来,我们调用modal.open()函数来查看模态弹出窗口。在编辑和删除用户方法中,我们获得UserID 了参数,调用了Observable的过滤方法,从用户列表中获取单个用户。过滤器语法就像C#中的匿名方法。下一行是将单个用户分配给用户表单,该值将设置为前端,一块蛋糕。

  2. 我们来创建SetControlsState 它将启用或禁用该表单。Reactive 窗体具有启用和禁用的方法,使控件只读和可编辑。

隐藏 复制代码

<span >SetControlsState(isEnable: boolean)
{
 isEnable ? this.userFrm.enable() : this.userFrm.disable();
}</span>
  1. 接下来的方法是onSubmit 实际获取表单值并基于DBOperation 枚举值,它执行添加,更新和删除操作,我们使用简单的switch语句,粘贴以下代码:

隐藏 收缩 复制代码

<span >onSubmit(formData: any) {
    this.msg = "";
  
    switch (this.dbops) {
      case DBOperation.create:
        this._userService.post(Global.BASE_USER_ENDPOINT, formData._value).subscribe(
          data => {
            if (data == 1) //Success
            {
              this.msg = "Data successfully added.";
              this.LoadUsers();
            }
            else
            {
              this.msg = "There is some issue in saving records, please contact to system administrator!"
            }
             
            this.modal.dismiss();
          },
          error => {
           this.msg = error;
          }
        );
        break;
      case DBOperation.update:
        this._userService.put(Global.BASE_USER_ENDPOINT, formData._value.Id, formData._value).subscribe(
          data => {
            if (data == 1) //Success
            {
              this.msg = "Data successfully updated.";
              this.LoadUsers();
            }
            else {
              this.msg = "There is some issue in saving records, please contact to system administrator!"
            }

            this.modal.dismiss();
          },
          error => {
            this.msg = error;
          }
        );
        break;
      case DBOperation.delete:
        this._userService.delete(Global.BASE_USER_ENDPOINT, formData._value.Id).subscribe(
          data => {
            if (data == 1) //Success
            {
              this.msg = "Data successfully deleted.";
              this.LoadUsers();
            }
            else {
              this.msg = "There is some issue in saving records, please contact to system administrator!"
            }

            this.modal.dismiss();
          },
          error => {
            this.msg = error;
          }
        );
        break;

    }
  }</span>
  1. 代码是非常简单和不言而喻的,一旦我们提交表单,它会发送我们可以通过.value属性获取的所有值。这在TypeScript方面几乎是这样。

  2. 我们来写一下HTML模板UserComponent。双击user.component.html进行编辑:

  1. 复制以下代码user.component.html

隐藏 收缩 复制代码

<span ><div class='panel panel-primary'>
  <div class='panel-heading'>
    User Management
  </div>
  <div class='panel-body'>
    <div class='table-responsive'>
      <div ><button class="btn btn-primary" (click)="addUser()">Add</button></div>
      <div class="alert alert-info" role="alert" *ngIf="indLoading"><img src="../../images/loading.gif" width="32" height="32" /> Loading...</div>
      <div *ngIf='users && users.length==0' class="alert alert-info" role="alert">No record found!</div>
      <table class='table table-striped' *ngIf='users && users.length'>
        <thead>
          <tr>
            <th>First Name</th>
            <th>Last Name</th>
            <th>Gender</th>
            <th></th>
          </tr>
        </thead>
        <tbody>
          <tr *ngFor="let user of users">
            <td>{{user.FirstName}}</td>
            <td>{{user.LastName}}</td>
            <td>{{user.Gender}}</td>
            <td>
              <button title="Edit" class="btn btn-primary" (click)="editUser(user.Id)">Edit</button>
              <button title="Delete" class="btn btn-danger" (click)="deleteUser(user.Id)">Delete</button>
            </td>
          </tr>
        </tbody>
      </table>
      <div>
      </div>
    </div>
    <div *ngIf="msg" role="alert" class="alert alert-info alert-dismissible">
      <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
      <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
      <span class="sr-only">Error:</span>
      {{msg}}
    </div>
  </div>
</div>

<modal #modal>
  <form novalidate (ngSubmit)="onSubmit(userFrm)" [formGroup]="userFrm">
    <modal-header [show-close]="true">
      <h4 class="modal-title">{{modalTitle}}</h4>
    </modal-header>
    <modal-body>

      <div class="form-group">
        <div>
          <span>Full name*</span>
          <input type="text" class="form-control" placeholder="First Name" formControlName="FirstName">
        </div>
        <div>
          <span>Full name</span>
          <input type="text" class="form-control" placeholder="Last Name" formControlName="LastName">
        </div>
        <div>
          <span>Gender*</span>
          <select formControlName="Gender" class="form-control">
            <option>Male</option>
            <option>Female</option>
          </select>
        </div>
      </div>
    </modal-body>
    <modal-footer>
      <div>
        <a class="btn btn-default" (click)="modal.dismiss()">Cancel</a>
        <button type="submit" [disabled]="userFrm.invalid" class="btn btn-primary">{{modalBtnTitle}}</button>
      </div>
    </modal-footer>
  </form>
</modal></span>
  1. 如果你看Add按钮,我们AddUser 通过使用(click)函数来调用这个函数,这个函数是event 前面步骤讨论过的绑定的例子。

  2. 接下来,我们使用*ngIfstructural directives显示基于indLoading 布尔变量的加载消息。

  3. 接下来,我们使用*ngFor结构指令来循环遍历users 数组并显示用户信息。

  4. 下一个代码是用于模态弹出,您可以看到#modal占位符,我们正在使用它来访问它在TypeScript侧通过@ViewChild访问打开和关闭功能。

  5. 接下来我们创建表单,(ngSumbit)事件将表单数据发送到TypeScript onSumit 函数。

  6. 通过[formgorup]属性绑定,我们分配userform 我们在TypeScript端创建的。我们通过formControlName 属性告诉我们的模板相应的表单控件。

  7. 添加和编辑按钮将被禁用,直到表单有效。这是通过[disabled]属性绑定处理,直到userform.invalid属性启用。

  8. 就这样UserComponent,现在让我们添加UserComponent的路由并添加它AppModule

  9. 双击app.routing.tsapp 文件夹中进行编辑:

  1. UserComponent 通过以下代码 导入:

隐藏 复制代码

<span >import { UserComponent } from './components/user.component';</span>
  1. 添加UserComponent 路线如下:

隐藏 复制代码

<span >{ path: 'user', component: UserComponent }</span>
  1. 决赛app.routing.ts应该如下所示:

  1. app.component.ts双击编辑:

  1. 在应用模块中添加用户组件:

隐藏 复制代码

<span >import { UserComponent } from './components/user.component';</span>
  1. 添加UserComponent 在声明部分中,最终AppModule 应该如下所示:

  1. 为用户管理添加菜单项,双击app.component.ts并添加以下行:

隐藏 复制代码

<span >Users Management</a></li></span>
  1. 决赛app.component.ts应该如下:

  1. 编译并运行应用程序。