Angular Http Module MVC6 ASP.NET Core Web api Restiful Service
(From http://ppt.cc/47Hq0)
▌Introduction
Remember that
in the previous tutorials, we mocked the customer data in the frontend but not
the database. We will use Angular2 Http module and ASP.NET core – web api to
fulfill the CRUD functions with data stored in database (in this example, it’s sql
server).
▋Related articles
▌Environment
▋Visual Studio 2015
Update 3
▋Sql Server 2012 R2
▋NPM: 3.10.3
▋Microsoft.AspNetCore.Mvc
1.0.0
▋angular 2: 2.1.0
▌Web api
Create an ASP.NET core Web application as Web api. What
we will do before implementing the CRUD functions in frontend:
1.
Enable NLog logging
2.
Enable CORS
3.
Set global json options
4.
Support Entity framework core
5.
Create CRUD api in web api
▋Install packages
▋NLog logging
Please refer to this article:
▋CORS
We will enable the global CORS settings in Startup.cs.
▋Startup.cs
public void ConfigureServices(IServiceCollection services)
{
//Step1. Enable CORS
services.AddCors(options =>
{
options.AddPolicy("AllowSpecificOrigin",
builder =>
builder.WithOrigins("http://localhost:4240") //Or AllowAnyOrigin()
.WithMethods("GET", "POST", "PUT", "DELETE") //Or AllowAnyMethod()
);
});
//Step2. Enable CORS for every MVC actions
services.Configure<MvcOptions>(options =>
{
options.Filters.Add(new CorsAuthorizationFilterFactory("AllowSpecificOrigin"));
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
//…
app.UseCors("AllowSpecificOrigin");
}
|
If you don’t want to enable a policy on every web api
action (http method), ignore step 2. And specify the CORS policy on an action
with [EnableCors] attribute
like this.
[EnableCors("AllowSpecificOrigin")]
public async Task<HttpResponseMessage> Create([FromBody]Customer cust)
{}
|
Or use [DisableCors] for security issue.
▋Set global json options
Web api will
default return the json object with lower-Camel-case property names, even if the properties
are in Pascal case.
For example, my class’s properties are Pascal case,
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public string Phone { get; set; }
public int Age { get; set; }
public string Description { get; set; }
}
|
But web api returns lower Camel case.
So we add the following configuration to solve this case.
▋Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().AddJsonOptions(options =>
{
options.SerializerSettings.ContractResolver = new
Newtonsoft.Json.Serialization.DefaultContractResolver();
options.SerializerSettings.Formatting = Formatting.None; //or Formatting.Indented for readability;
});
//…
}
|
See the updated result.
▋Support Entity framework core
Have a look at these related articles.
▋DAO
public class Customer
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[StringLength(100)]
[Required]
public string Name { get; set; }
[StringLength(100)]
public string Phone { get; set; }
public int Age { get; set; }
[StringLength(200)]
public string Description { get; set; }
}
|
▋DbContext
public class NgDbContext : DbContext
{
public NgDbContext(DbContextOptions options) : base(options)
{}
public DbSet<Customer> Customers { get; set; }
}
|
▋DAO CRUD methods in CustomerService
public class CustomerService:IDisposable
{
private NgDbContext _dbContext = null;
public CustomerService(NgDbContext dbContext)
{
this._dbContext =
dbContext;
}
public IQueryable<Customer> GetAll()
{
return this._dbContext.Customers;
}
public IQueryable<Customer> Get(Expression<Func<Customer, bool>> filter)
{
return this._dbContext.Customers.Where(filter);
}
public void Add(Customer entity)
{
this._dbContext.Customers.Add(entity);
this._dbContext.SaveChanges();
}
public void Update(Customer entity)
{
this._dbContext.SaveChanges();
}
public void Remove(Customer entity)
{
this._dbContext.Customers.Remove(entity);
this._dbContext.SaveChanges();
}
}
|
Okay, everything is done. We are going to implement the
CRUD http methods in web api.
▋Create CRUD api in web api
Okay, the following is a normal web api controller.
Notice in ASP.NET core MVC model binding, we MUST specify the binding source, like
[FromBody], [FromHeader] , [FromForm], [FromQuery] , [FromRoute].
PS. I was stuck in this issue for hours L
[Route("api/Basic/[controller]")]
public class CustomerController : BaseController
{
[HttpGet("GetAll")]
public IQueryable<Customer> GetAll()
{
throw new NotImplementedException();
}
[HttpGet("Get/{id}")]
public Customer Get(int id)
{
throw new NotImplementedException();
}
[HttpPost("Create")]
public async Task<HttpResponseMessage> Create([FromBody]Customer cust)
{
throw new NotImplementedException();
}
[HttpPut("Update")]
[CustomExceptionFilter]
public async Task<HttpResponseMessage> Update([FromBody]Customer cust)
{
throw new NotImplementedException();
}
[HttpDelete("Remove/{id}")]
[CustomExceptionFilter]
public async Task<HttpResponseMessage> Remove(int id)
{
throw new NotImplementedException();
}
}
|
▌Angular2 : Http
Module
Now we have
everything in backend, we will start implementing the CRUD functions in
frontend.
▋Create CRUD Service
▋/app/Basic/Customer/customer.app.module.ts
//...
import { HttpModule } from '@angular/http';
@NgModule({
imports: [
BrowserModule,
FormsModule,
CustomerRoutes,
HttpModule
],
//...
})
export class CustomerAppModule { }
|
▋/app/Basic/Customer/customer.service.ts
import {Injectable} from '@angular/core';
import { Http, Headers, RequestOptions } from '@angular/http';
import {Customer} from '../../class/Customer';
import {ICrudService} from '../../interface/ICrudService';
import {RestUriService} from '../../service/resturi.service';
@Injectable()
export class CustomerService implements ICrudService {
private customers:
Customer[];
private httpOptions:
RequestOptions;
constructor(
private http: Http,
private resturiService:
RestUriService
) {
this.customers = [];
let headers = new Headers({ 'Content-Type': 'application/json' });
this.httpOptions = new RequestOptions({ headers: headers });
}
//Get all customers
public getAll() {
return new
Promise<Customer[]>(
resolve
=> {
this.http.get(this.resturiService.customerGetAllUri)
.subscribe(value => {
Object.assign(this.customers,
value.json());
resolve(value.json());
});
});
}
//Get a customers with Id
public get(id: number) {
return new
Promise<Customer>(
resolve
=> {
this.http.get(this.resturiService.customerGetUri.concat(id.toString()))
.subscribe(value => {
resolve(value.json());
});
});
}
//Create a new customer
public create(item:
Customer) {
var entity =
JSON.stringify(item);
return new Promise(
resolve
=> {
this.http.post(this.resturiService.customerCreateUri,
entity, this.httpOptions)
.subscribe(() => {
resolve();
});
});
}
//Update a customer
public update(item:
Customer) {
return new Promise(
resolve
=> {
this.http.put(this.resturiService.customerUpdateUri,
item, this.httpOptions)
.subscribe(value => {
resolve();
});
});
}
//Remove a customer
public remove(item:
Customer) {
return new Promise(
resolve
=> {
this.http.delete(this.resturiService.customerRemoveUri.concat(item.Id.toString()))
.subscribe(value => {
resolve();
});
});
}
|
PS. In angular
2, the standard http client functions is written like this:
▋Http GET
public get(id: number) {
return new
Promise<Customer>(
resolve
=> {
this.http.get("http://localhost:7856/api/Basic/Customer/Get/"+id.toString()))
.subscribe(value => {
resolve(value.json());
});
});
}
|
▋Http Post
let headers = new Headers({ 'Content-Type': 'application/json' });
let httpOptions = new RequestOptions({
headers: headers });
var entity =
JSON.stringify(item);
return new Promise(
resolve =>
{
this.http.post("http://localhost:7856/api/Basic/Customer/Create", entity, httpOptions)
.subscribe(() => {
resolve();
});
});
|
▋Read (Inquery)
Remove the
const customers’ data and we are going to get the customers’ data with our new
CustomerService.
▋/app/Basic/Customer/customer.index.component.ts
import
{CustomerService} from './customer.service';
//...
@Component({
selector: 'customer-index',
providers: [CustomerService],
templateUrl: '/app/Basic/Customer/customer-index.component.html'
})
export class CustomerIndexComponent
implements OnInit {
//...
customers:
Customer[];
constructor(
private router: Router,
private custService:
CustomerService) {
}
ngOnInit() {
this.initCustomers();
}
private initCustomers() {
this.custService.getAll().then(
data => {
this.customers =
data
});
}
}
|
▋Delete
▋/app/Basic/Customer/customer.index.component.ts
Add the
following function for deleting a customer.
//Remove customer
private deleteCustomer(item:
Customer) {
this.custService.remove(item).then(
() => {
//Remove item in Front-end
var index =
customers.indexOf(item);
this.customers.splice(index, 1);
});
}
|
▋Create
▋/app/Basic/Customer/customer.create.component.ts
Complete the
create function in Customer Create component.
private save() {
this.custService.create(this.customer).then(
() =>
{
//Return to Index after finished
this.router.navigate(['Basic/Customer/Index']);
});
}
|
▋Update
▋/app/Basic/Customer/customer.edit.component.ts
Complete the
Customer Edit component by querying cutomer when ngOnInit and update customer
on saving.
//...
import
{CustomerService} from './customer.service';
@Component({
selector: 'customer-edit',
providers:
[CustomerService, RestUriService],
templateUrl: '/app/Basic/Customer/customer-edit.component.html',
styleUrls: ['/app/Basic/Customer/customer-edit.component.css']
})
export class CustomerEditComponent
implements OnInit {
title:
string;
customer:
Customer;
selectedCustomer: Customer;
constructor(
private router: Router,
private route:
ActivatedRoute,
private custService:
CustomerService) {
this.title = "Customers - Edit";
this.customer = new Customer();
}
ngOnInit() {
this.route.params.subscribe(params => {
let custIdValue = params['id'];
let custId =
+custIdValue; //Equales to parseInt
this.custService.get(custId).then(
data => {
this.customer = data
});
});
}
//Save!
private save() {
this.custService.update(this.customer);
}
}
|
▌Demo
▋What’s next?
▌Github
▌Reference
沒有留言:
張貼留言