.NET CORE 1.0, ANGULAR V2, WEBAPI 上的 CRUD 操作






4.94/5 (26投票s)
在上一篇文章中,我们了解了如何开始使用 .Net Core。在本文中,我们将根据之前的概念,查看与之前示例应用程序相关的数据库操作。
如果您是 .Net Core 新手,请阅读有关 .Net Core Startup 的上一篇文章。
在本文中,我们将探讨:
- 创建数据库
- 使用 Entity Framework Core(数据库优先方法),
- EF Core 概述
- 安装 Entity Framework
- 创建模型
- 配置 EF 服务
- 使用 MVC 6
- MVC6 概述
- 使用 WebAPI
- 使用 Angular V2
- 组件,
- 路线
- Service
- 配置服务器
- 在 IIS 内部/外部运行应用程序
让我们一步一步开始吧。
创建数据库 在开始使用 IDE 之前,让我们使用 SSMS2014 创建一个新数据库。将其命名为 PhoneBook。
创建一个名为 Contacts 的表,复制并运行以下脚本在 SSMS2014 中:
USE [PhoneBook]
GO
/****** Object: Table [dbo].[Contacts] Script Date: 8/7/2016 11:28:55 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Contacts](
[ContactID] [int] IDENTITY(1,1) NOT NULL,
[FirstName] [nvarchar](50) NULL,
[LastName] [nvarchar](50) NULL,
[Phone] [nvarchar](50) NULL,
[Email] [nvarchar](50) NULL,
CONSTRAINT [PK_Contacts] PRIMARY KEY CLUSTERED
(
[ContactID] 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
让我们开始吧。遵循我们之前的主题,我将使用之前的示例应用程序,用 Visual Studio 2015 打开它。
它将自动开始恢复依赖项。生成并运行它。应用程序运行正常。
安装 Entity Framework:在安装之前,让我们先了解一下 EF Core 的新功能。
- 建模: 这包括基本建模、数据注释、关系等。
- 更改跟踪: 这包括访问跟踪状态、快照、通知更改跟踪。
- SaveChanges: 这包括基本的保存功能、异步 SaveChanges、事务。
- 查询: 这包括基本的 LINQ 支持、异步查询、原始 SQL 查询。
- 数据库架构管理: 这包括数据库创建/删除 API、关系数据库迁移以及从数据库反向工程。
- 数据库提供程序: 这包括 EntityFramework.SqlServer、Sqlite、InMemory。
- 平台: 支持通用 Windows 平台 (UWP)、.NET Core、完整 .NET。
有关 EF Core 的更多详细信息,请访问 EF Core。让我们在我们的示例应用程序解决方案中为实体模型添加文件夹。
DbEntities:用于模型实体。EF 的安装非常简单。打开 project.json 文件,在 tools 部分指向,并用以下行修改该部分。
"Microsoft.EntityFrameworkCore.SqlServer": "1.0.0",
"Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final",
"Microsoft.EntityFrameworkCore.SqlServer.Design": "1.0.0"
修改后保存更改。
包将自动恢复。让我们来解释一下它们是什么。
EntityFrameworkCore.SqlServer:数据库提供程序,它允许 Entity Framework Core 与 Microsoft SQL Server 一起使用。
EntityFrameworkCore.Tools:EF Core 的命令行工具。包含命令。
对于包管理器控制台
- Scaffold-DbContext,
- Add-Migration,
- Update-Database
对于命令窗口
- dotnet ef dbcontext scaffold
我们将看到如何使用这两个命令。EntityFrameworkCore.SqlServer.Design:设计时,它允许 Entity Framework Core 功能(EF Core Migration)与 Microsoft SQL Server 一起使用。要访问命令行工具,我们需要在 project.json 的 tools 部分添加EntityFrameworkCore.Tools。
"Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final"
修改后保存更改。包管理器控制台中的命令:打开包管理器控制台。
输入以下命令然后按 Enter 键:
Scaffold-DbContext "Server=DESKTOP-4T79RA1;Database=PhoneBook;Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models/DbEntities
命令窗口中的命令:打开命令窗口,导航到项目目录,输入:
D:\Article\ASP-CORE\CRUD\CoreMVCAngular2\src\CoreMVCAngular>dotnet ef –help
这里会在命令窗口显示一个选项列表,我们将在 Commands 中使用 dbcontext。
然后输入以下命令并按 Enter 键:
D:\Article\ASP-CORE\CRUD\CoreMVCAngular2\src\CoreMVCAngular>dotnet ef dbcontext scaffold "Server=DESKTOP-4T79RA1;Database=PhoneBook;Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer --output-dir Models/CwEntities
这是执行并生成模型的两个过程的屏幕截图。我们将保留 DbEntities 文件夹进行工作,并删除另一个文件夹。
配置 EF 服务:在 PhoneBookContext 类中添加构造函数。
public PhoneBookContext(DbContextOptions<PhoneBookContext> options) :
base(options)
{
}
在 Startup 类中,我们需要启用 EF 服务,为以下内容提供连接字符串:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
var connection = @"Server=DESKTOP-4T79RA1;Database=PhoneBook;Trusted_Connection=True;";
services.AddDbContext<PhoneBookContext>(options => options.UseSqlServer(connection));
}
我们已经在应用程序中配置了 EF 服务,接下来我们将使用 ASP.NET Core 中包含的 MVC6。
MVC 6:我们在上一篇文章中已经讨论过 MVC6,让我们再次简要回顾一下 MVC6 的新功能。
- MVC + Web API + Web Pages = MVC6
- 无 System.Web
- 网页和 HTTP 服务已统一
- 内置依赖注入
- 动态代码编译(Roslyn 编译器)
- 开源 &
- 支持跨平台构建和运行。
- 可以在 IIS 中托管,也可以自托管(IIS 外部)。
好的,现在让我们添加一个 WebApi Controller 来对数据库表执行 CRUD 操作。在解决方案资源管理器中,添加一个新的 api 文件夹,右键单击它 > 添加新项 > Web API Controller Class > 添加。修改初始模板。
API 控制器
[Route("api/[controller]")]
public class ContactController : Controller
{
private PhoneBookContext _ctx = null;
public ContactController(PhoneBookContext context)
{
_ctx = context;
}
}
您可能会注意到 MVC6 属性路由中有一个新模式 [ ],即 **[RouteToken]**。这意味着路由令牌会自动获取控制器名称。
Like [Route("api/[controller]")] > [Route("api/Contact")]
另一件事是,我们知道 Web API 默认会生成 XML,现在在 MVC 6 中,我们可以通过在类标签或方法标签上放置属性来设置一个属性,以将默认生成器更改为 JSON 类型。在我们的例子中,我们将其设置在方法标签上。
[HttpGet("GetContact"), Produces("application/json")]
GET
// GET: api/Contact/GetContact
[HttpGet("GetContact"), Produces("application/json")]
public async Task<object> GetContact()
{
List<Contacts> contacts = null;
object result = null;
try
{
using (_ctx)
{
contacts = await _ctx.Contacts.ToListAsync();
result = new
{
contacts
};
}
}
catch (Exception ex)
{
ex.ToString();
}
return result;
}
POST
// POST api/Contact/PostContact
[HttpPost, Route("PostContact")]
public async Task<object> PostContact([FromBody]Contacts model)
{
object result = null; int message = 0;
if (model == null)
{
return BadRequest();
}
using (_ctx)
{
using (var _ctxTransaction = _ctx.Database.BeginTransaction())
{
try
{
_ctx.Contacts.Add(model);
await _ctx.SaveChangesAsync();
_ctxTransaction.Commit();
message = (int)responseMessage.Success;
}
catch (Exception e)
{
_ctxTransaction.Rollback();
e.ToString();
message = (int)responseMessage.Error;
}
result = new
{
message
};
}
}
return result;
}
PUT
// PUT api/Contact/PutContact/5
[HttpPut, Route("PutContact/{id}")]
public async Task<object> PutContact(int id, [FromBody]Contacts model)
{
object result = null; int message = 0;
if (model == null)
{
return BadRequest();
}
using (_ctx)
{
using (var _ctxTransaction = _ctx.Database.BeginTransaction())
{
try
{
var entityUpdate = _ctx.Contacts.FirstOrDefault(x => x.ContactId == id);
if (entityUpdate != null)
{
entityUpdate.FirstName = model.FirstName;
entityUpdate.LastName = model.LastName;
entityUpdate.Phone = model.Phone;
entityUpdate.Email = model.Email;
await _ctx.SaveChangesAsync();
}
_ctxTransaction.Commit();
message = (int)responseMessage.Success;
}
catch (Exception e)
{
_ctxTransaction.Rollback(); e.ToString();
message = (int)responseMessage.Error;
}
result = new
{
message
};
}
}
return result;
}
删除
// DELETE api/Contact/DeleteContactByID/5
[HttpDelete, Route("DeleteContactByID/{id}")]
public async Task<object> DeleteContactByID(int id)
{
object result = null; int message = 0;
using (_ctx)
{
using (var _ctxTransaction = _ctx.Database.BeginTransaction())
{
try
{
var idToRemove = _ctx.Contacts.SingleOrDefault(x => x.ContactId == id);
if (idToRemove != null)
{
_ctx.Contacts.Remove(idToRemove);
await _ctx.SaveChangesAsync();
}
_ctxTransaction.Commit();
message = (int)responseMessage.Success;
}
catch (Exception e)
{
_ctxTransaction.Rollback(); e.ToString();
message = (int)responseMessage.Error;
}
result = new
{
message
};
}
}
return result;
}
所以我们的 Web API 已经准备好处理与数据库的数据了,是时候处理客户端脚本了。
Angular V2:我们的 WebAPI 已经准备好处理来自服务器的数据。现在我们将使用 TypeScript(.ts)文件处理客户端代码。首先,我们需要创建一个主页面来展示我们的视图。
然后我们需要在应用程序启动时指向此 html 文件,因此让我们转到 startup.cs 文件添加以下代码片段。这是默认文件中间件的配置。
Startup.cs
// app-specific root page(Index.html)
DefaultFilesOptions options = new DefaultFilesOptions();
options.DefaultFileNames.Clear();
options.DefaultFileNames.Add("/Index.html");
需要添加库
using Microsoft.AspNetCore.Builder;
现在向 html 页面添加脚本库引用,并定义视图点以加载我们的应用程序组件视图。
<spa-app>
<p>
<img src="img/ajax_small.gif" /> Please wait ...
</p>
</spa-app>
然后我们需要引用我们的引导文件在页面上,它导入并启用我们的 angular 脚本到页面。
<script>
System.config({ packages: { 'app': { defaultExtension: 'js' } }, });
System.import('app/main').then(null, console.error.bind(console));
</script>
让我们将所有这些放在 Index.html 文件中。
Index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title></title>
<base href="/">
<script>document.write('<base href="' + document.location + '" />');</script>
<script src="../lib-npm/es6-shim/es6-shim.js"></script>
<script src="../lib-npm/angular2/angular2-polyfills.js"></script>
<script src="../lib-npm/systemjs/system.src.js"></script>
<script src="../lib-npm/rxjs/Rx.js"></script>
<script src="../lib-npm/angular2/angular2.js"></script>
<script src="../lib-npm/angular2/router.js"></script>
<script src="../lib-npm/angular2/http.js"></script>
<link href="../lib/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
<div class="container">
<spa-app>
<p>
<img src="img/ajax_small.gif" /> Please wait ...
</p>
</spa-app>
</div>
<script src="../lib/jquery/dist/jquery.min.js"></script>
<script src="../lib/bootstrap/dist/js/bootstrap.min.js"></script>
<script>
System.config({ packages: { 'app': { defaultExtension: 'js' } }, });
System.import('app/main').then(null, console.error.bind(console));
</script>
</body>
</html>
引导、模型、组件和路由 Main.ts
/*This is the spa bootstrap File*/
//---------Import Angular2------------
import {bootstrap} from 'angular2/platform/browser';
import {enableProdMode, provide} from 'angular2/core';
//---------Import External Components(Main Component)---------
import {MainComponent} from './app.component';
//---------Bootstrap Component---------
enableProdMode();
bootstrap(MainComponent);
App.component.ts
/*Component Default view For SpaRoute */
//---------Import Angular2------------
import {Component, provide} from 'angular2/core';
import {RouteConfig, ROUTER_DIRECTIVES,
ROUTER_PROVIDERS, LocationStrategy,
HashLocationStrategy, APP_BASE_HREF} from 'angular2/router';
//---------Import External Components---------
import {Home} from './home/home.component';
import {Contact} from './contact/contact.component';
//---------Declare Components---------
@Component({
selector: 'spa-app',
directives: [ROUTER_DIRECTIVES], //decorate link
templateUrl: 'app/main.view.html',
providers: [
ROUTER_PROVIDERS,
//provide(APP_BASE_HREF, { useValue: '/' })
provide(LocationStrategy, { useClass: HashLocationStrategy })
]
})
//---------Declare Route Config---------
@RouteConfig([
{ path: '/', name: 'Home', component: Home, useAsDefault: true },
{ path: '/Contact/...', name: 'Contact', component: Contact }
])
//---------Export This Component Class---------
export class MainComponent {
title: string;
constructor() {
this.title = 'Welcome to [.NetCore+MVC6+Angular2] SPA';
}
}
Home.ts
import {Component} from 'angular2/core';
@Component({
selector: 'home',
templateUrl: `app/home/home.view.html`
})
export class Home {
constructor() {
}
}
Contact.model.ts
export class ContactModel {
contactId: number;
firstName: string;
lastName: string;
phone: string;
email: string;
}
Contact.component.ts
//---------Import Angular2------------
import {Component} from 'angular2/core';
import {ROUTER_DIRECTIVES, RouteConfig} from 'angular2/router';
//---------Import External Components---------
import {ContactMain} from './contact.main';
//---------Declare Components---------
@Component({
selector: 'contacts',
template: `<router-outlet></router-outlet>`,
directives: [ROUTER_DIRECTIVES]
})
@RouteConfig([
{ path: '/', name: 'ManageContact', component: ContactMain, useAsDefault: true },
])
export class Contact {
constructor() { }
}
Contact.main.ts
//---------Import Angular2------------
import {Component, OnInit} from 'angular2/core';
import {HTTP_PROVIDERS, Http} from 'angular2/http';
import {ROUTER_DIRECTIVES, RouteConfig} from 'angular2/router';
import {FORM_DIRECTIVES,
FormBuilder, Control, ControlGroup, Validators} from 'angular2/common';
//---------Import External Components---------
import {ContactModel} from './contact.model';
import {ContactService} from './contact.service';
import {customvalidators} from './customvalidators';
//---------Declare Components---------
@Component({
selector: 'contact-list',
templateUrl: `app/contact/contact.view.html`,
directives: [ROUTER_DIRECTIVES, FORM_DIRECTIVES],
providers: [ContactService, HTTP_PROVIDERS]
})
//---------Export This Component Class---------
export class ContactMain implements OnInit {
public resmessage: string;
public addmessage: string;
public listmessage: string;
public contact: ContactModel;
public contacts: ContactModel[];
public editContactId: any
//Form Control
contactForm: ControlGroup;
firstName: Control;
email: Control;
phone: Control;
//Constructor
constructor(private builder: FormBuilder,
private contactService: ContactService) {
this.addmessage = 'Add New Contact';
this.listmessage = 'All Contact';
this._formGroup();
}
ngOnInit() {
this.resmessage = "";
this.editContactId = 0;
this.getContacts();
}
//Form Group
_formGroup() {
this.firstName = new Control('', Validators.required);
this.email = new Control('', Validators.compose([Validators.required, customvalidators.emailValidator]));
this.phone = new Control('');
this.contactForm = this.builder.group({
firstName: this.firstName,
email: this.email,
phone: this.phone
});
}
//Get All
getContacts() {
//debugger
this.contactService.getContacts().subscribe(
contacts => this.contacts = contacts
);
}
//Save Form
saveContact(contact) {
//debugger
this.contactService.saveContact(contact)
.subscribe(response => {
this.resmessage = response;
this.getContacts();
this.reset();
});
}
//Get by ID
editContact(e, m) {
//debugger
e.preventDefault();
this.editContactId = m.contactId;
this.contactService.getContactByID(m.contactId)
.subscribe(response => {
this.contact = response;
this.firstName.updateValue(this.contact.firstName);
this.email.updateValue(this.contact.email);
this.phone.updateValue(this.contact.phone);
});
}
//Save Form
updateContact(contact: any) {
//debugger
if (this.editContactId > 0) {
this.contactService.updateContact(contact, this.editContactId)
.subscribe(response => {
this.resmessage = response;
this.getContacts();
this.reset();
});
}
}
//Delete
deleteContact(e, m) {
//debugger
e.preventDefault();
var IsConf = confirm('You are about to delete ' + m.firstName + '. Are you sure?');
if (IsConf) {
this.contactService.deleteContact(m.contactId)
.subscribe(response => {
this.resmessage = response;
this.getContacts();
});
}
}
reset() {
this.editContactId = 0;
this._formGroup();
}
}
让我们仔细看看下面的代码片段,我们在这里调用了服务方法,但遇到了未知术语 Subscribe - 它是做什么用的?下面我们有一个简单的解释。
this.contactService.getContacts().subscribe(
contacts => this.contacts = contacts
);
Subscribe:要传递给 Observable 构造函数的订阅者函数。
服务 在我们的服务文件中,我们有 Http 服务 [Get, GetByID, Post, Put, Delete],它连接 WebAPI 来执行创建、读取、更新和删除操作。GET ALL:执行一个带有 `get` http 方法的请求。用于对象集合
/Get
getContacts(): Observable<ContactModel[]> {
//debugger
return this._http.get(this._getUrl)
.map(res => <ContactModel[]>res.json())
.catch(this.handleError);
}
GET By ID:执行一个带有 `get` http 方法的请求。用于单个对象
//GetByID
getContactByID(id: string): Observable<ContactModel> {
//debugger
var getByIdUrl = this._getByIdUrl + '/' + id;
return this._http.get(getByIdUrl)
.map(res => <ContactModel>res.json())
.catch(this.handleError);
}
POST:执行一个带有 `post` http 方法的请求。
//Post
saveContact(contact: ContactModel): Observable<string> {
//debugger
let body = JSON.stringify(contact);
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
//http.post(url: string, body: string, options ?: RequestOptionsArgs): Observable<Response>
return this._http.post(this._saveUrl, body, options)
.map(res => res.json().message)
.catch(this.handleError);
}
PUT:执行一个带有 `put` http 方法的请求。
//Put
updateContact(contact: ContactModel, id: string): Observable<string> {
//debugger
var updateUrl = this._updateUrl + '/' + id;
var body = JSON.stringify(contact);
var headers = new Headers();
headers.append('Content-Type', 'application/json');
//http.post(url: string, body: string, options ?: RequestOptionsArgs): Observable<Response>
return this._http.put(updateUrl, body, { headers: headers })
.map(response => response.json().message)
.catch(this.handleError);
}
DELETE:执行一个带有 `delete` http 方法的请求。
//Delete
deleteContact(id: string): Observable<string> {
//debugger
var deleteByIdUrl = this._deleteByIdUrl + '/' + id
//http.post(url: string, options ?: RequestOptionsArgs): Observable<Response>
return this._http.delete(deleteByIdUrl)
.map(response => response.json().message)
.catch(this.handleError);
}
Observable:[Observable<T>] 表示在任何时间段内的任何一组值。这是 RxJS 的最基本构建块。让我们将其放入 Contact.service 文件中。
Contact.service.ts
import {Injectable, Component} from 'angular2/core';
import {Http, Request, RequestMethod, Response,
RequestOptions, Headers} from 'angular2/http';
import 'rxjs/Rx';
import {Observable} from 'rxjs/Observable';
import {ContactModel} from './contact.model';
@Component({
providers: [Http]
})
@Injectable()
export class ContactService {
public headers: Headers;
constructor(private _http: Http) {
}
public _saveUrl: string = '/api/Contact/PostContact/';
public _updateUrl: string = '/api/Contact/PutContact/';
public _getUrl: string = '/api/Contact/GetContact/';
public _getByIdUrl: string = '/api/Contact/GetContactByID/';
public _deleteByIdUrl: string = '/api/Contact/DeleteContactByID/';
//Get
getContacts(): Observable<ContactModel[]> {
//debugger
return this._http.get(this._getUrl)
.map(res => <ContactModel[]>res.json())
.catch(this.handleError);
}
//GetByID
getContactByID(id: string): Observable<ContactModel> {
//debugger
var getByIdUrl = this._getByIdUrl + '/' + id;
return this._http.get(getByIdUrl)
.map(res => <ContactModel>res.json())
.catch(this.handleError);
}
//Post
saveContact(contact: ContactModel): Observable<string> {
//debugger
let body = JSON.stringify(contact);
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
//http.post(url: string, body: string, options ?: RequestOptionsArgs): Observable<Response>
return this._http.post(this._saveUrl, body, options)
.map(res => res.json().message)
.catch(this.handleError);
}
//Put
updateContact(contact: ContactModel, id: string): Observable<string> {
//debugger
var updateUrl = this._updateUrl + '/' + id;
var body = JSON.stringify(contact);
var headers = new Headers();
headers.append('Content-Type', 'application/json');
//http.post(url: string, body: string, options ?: RequestOptionsArgs): Observable<Response>
return this._http.put(updateUrl, body, { headers: headers })
.map(response => response.json().message)
.catch(this.handleError);
}
//Delete
deleteContact(id: string): Observable<string> {
//debugger
var deleteByIdUrl = this._deleteByIdUrl + '/' + id
//http.post(url: string, options ?: RequestOptionsArgs): Observable<Response>
return this._http.delete(deleteByIdUrl)
.map(response => response.json().message)
.catch(this.handleError);
}
private handleError(error: Response) {
return Observable.throw(error.json().error || 'Opps!! Server error');
}
}
让我们讨论一下 Angular2 中的表单,Angular2 表单有两种策略:
- 模板驱动
- 模型驱动
模板驱动 在模板驱动表单中,指令是声明式地添加到模板中的。
<input id="firstName" type="text"
class="form-control"
placeholder="FirstName" [ngFormControl]="firstName" required>
注意到验证器是以声明式方式与输入元素“required”一起添加的。
模型驱动 在我们的示例应用程序中,我们使用了模型驱动表单,其中包含 ngFormModel 和 ngFormControl。这里 ngFormControl 与输入元素绑定,通过控件获取输入值。
ngFormModel:将其绑定到控制器变量“contactForm”。
<form [ngFormModel]="contactForm">
ngFormControl
<input id="firstName" type="text"
class="form-control"
placeholder="FirstName" [ngFormControl]="firstName">
ControlGroup 包含多个 Controls。
//Form Control
contactForm: ControlGroup;
firstName: Control;
email: Control;
phone: Control;
注入的 FormBuilder 使用生成器创建控件组,控件组以键值对的形式传递。
private builder: FormBuilder
//Form Group
_formGroup() {
//Set Initial Values to the Control & Validators
this.firstName = new Control('', Validators.required);
this.email = new Control('', Validators.compose([Validators.required, customvalidators.emailValidator]));
this.phone = new Control('');
//Pass the grouped controls as key value pairs
this.contactForm = this.builder.group({
firstName: this.firstName,
email: this.email,
phone: this.phone
});
}
验证也在我们的组件中进行了检查。下面是我们完整的模型驱动表单。表单
<form [ngFormModel]="contactForm">
<div class="form-group" [ngClass]="{ 'has-error' : !firstName.valid }">
<label class="control-label" for="firstName">Username</label>
<em *ngIf="!firstName.valid">*</em>
<input id="firstName" type="text"
class="form-control"
placeholder="FirstName" [ngFormControl]="firstName">
</div>
<div class="form-group" [ngClass]="{ 'has-error' : !email.valid }">
<label class="control-label" for="email">Email</label>
<em *ngIf="!email.valid">*</em>
<input id="email" type="email"
class="form-control"
placeholder="Email" [ngFormControl]="email">
</div>
<div class="form-group">
<label class="control-label" for="phone">Phone</label>
<input id="phone" type="text" class="form-control" placeholder="Phone" [ngFormControl]="phone">
</div>
<div class="form-group">
<button type="submit" class="btn btn-danger" (click)="reset()">Reset</button>
<button type="submit" class="btn btn-primary" (click)="saveContact(contactForm.value)"
*ngIf="editContactId == 0"
[disabled]="!contactForm.valid">Create</button>
<button type="submit" class="btn btn-success" (click)="updateContact(contactForm.value)"
*ngIf="editContactId > 0"
[disabled]="!contactForm.valid">Update</button>
</div>
</form>
这是我们在应用程序中使用的完整的联系人视图页面。
Contact.view.html
<div class="row">
<div class="col-sm-4">
<h3>Phone Book {{addmessage}}</h3>
<form [ngFormModel]="contactForm">
<div class="form-group" [ngClass]="{ 'has-error' : !firstName.valid }">
<label class="control-label" for="firstName">Username</label>
<em *ngIf="!firstName.valid">*</em>
<input id="firstName" type="text"
class="form-control"
placeholder="FirstName" [ngFormControl]="firstName">
</div>
<div class="form-group" [ngClass]="{ 'has-error' : !email.valid }">
<label class="control-label" for="email">Email</label>
<em *ngIf="!email.valid">*</em>
<input id="email" type="email"
class="form-control"
placeholder="Email" [ngFormControl]="email">
</div>
<div class="form-group">
<label class="control-label" for="phone">Phone</label>
<input id="phone" type="text" class="form-control" placeholder="Phone" [ngFormControl]="phone">
</div>
<div class="form-group">
<button type="submit" class="btn btn-danger" (click)="reset()">Reset</button>
<button type="submit" class="btn btn-primary" (click)="saveContact(contactForm.value)"
*ngIf="editContactId == 0"
[disabled]="!contactForm.valid">Create</button>
<button type="submit" class="btn btn-success" (click)="updateContact(contactForm.value)"
*ngIf="editContactId > 0"
[disabled]="!contactForm.valid">Update</button>
</div>
</form>
<span class="warning">{{resmessage}}</span>
</div>
<div class="col-sm-8">
<h3>Phone Book {{listmessage}}</h3>
<table style="width:100%" class="table table-striped">
<tr>
<th>ID</th>
<th>Firstname</th>
<th>Email</th>
<th>Phone</th>
<th>Option</th>
</tr>
<tr *ngFor="#contact of contacts">
<td>{{ contact.contactId }}</td>
<td>{{ contact.firstName }}</td>
<td>{{ contact.email }}</td>
<td>{{ contact.phone }}</td>
<td>
<a href="javascript:void(0)"
(click)="deleteContact($event, contact)"
class="btn btn-danger btn-xs pull-right">Delete</a>
<a href="javascript:void(0)"
(click)="editContact($event, contact)"
class="btn btn-primary btn-xs pull-right">Edit</a>
</td>
</tr>
</table>
</div>
</div>
以上就是我们在示例应用程序中使用 Angular 部分的所有内容,用于执行客户端操作。现在是时候构建和运行应用程序了。接下来我们将概述服务器配置。
配置服务器:IIS 外部(Weblistener):我们可以在没有 IIS 环境的情况下托管和运行我们的应用程序,我们需要添加命令对象来告诉托管使用 HTTP 服务器 weblistener(仅限 Windows)。
"commands": {
"OutsideIIS": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.Weblistener --server.urls https://:5001"
},
确保依赖项存在。
"Microsoft.AspNetCore.Server.WebListener": "0.1.0"
现在转到解决方案资源管理器,右键单击项目 > 属性 > 调试,将配置文件更改为 OutsideIIS。 设置启动 URL,然后保存并运行应用程序。
服务器将启动并显示托管环境详细信息。
应用程序在 URL https://:5000 上运行,并提供详细的请求信息。
IIS 内部(Kestrel):Kestrel 是一个跨平台 Web 服务器,可以在 IIS 或 Nginx 后面运行。
从导航栏下拉列表中更改为 IIS Express,以使用 IIS 运行应用程序。好的,让我们运行我们的应用程序,看看它是如何工作的。
输出:在这里,我们可以看到应用程序的输出,带有欢迎消息,并且数据是通过我们的 MVC6 – WebAPI 从服务器列出的。在这里,我们可以执行具有必要验证的 CRUD 操作。
希望这会有所帮助:)