Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Call web API controller using Angular 2

I am new to Angular2. I want to call an API using Angular2 in my MVC6 project. I have tried many things (including the guide at Angular2 calling ASP.NET Web API) without success.

I don’t know where I should start, or which files are needed.

like image 625
Kratika Sharma Avatar asked Aug 09 '16 12:08

Kratika Sharma


2 Answers

I'd look at some of the examples on Github to see how other people have done it. There are a number of things that have to be just right for it all to work, and the errors can be nebulous until you get it up and running.

Add a Web API Controller Class to your project. Just to make sure everything is working at first, I'd suggest hard coding your HttpGet attribute to "api/values".

ValuesController.cs. :

    public class ValuesController : Controller
    {
      [HttpGet("api/values")]
      public IActionResult Get()
      {
          return new JsonResult(new string[] { "value1", "value2" });
      }

Startup.Cs. You need the angular2 routes to not interfere with ASP.NET's routes. This means you need to serve the index.html to the client if there is a 404 error. The app.Use lambda accomplishes this. Notice that it is before the calls to app.UseDefaultFiles() and app.UseStaticFiles()

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        ...
        var angularRoutes = new[] {
             "/home"
         };

        app.Use(async (context, next) =>
        {
            if (context.Request.Path.HasValue && null != angularRoutes.FirstOrDefault(
                (ar) => context.Request.Path.Value.StartsWith(ar, StringComparison.OrdinalIgnoreCase)))
            {
                context.Request.Path = new PathString("/");
            }
            await next();
        });

        app.UseDefaultFiles();
        app.UseStaticFiles();
        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });
    }

Once you have this setup, you should test your API with Postman to make sure the routing is working as you want it to. If this doesn't work, it won't work in Angular. I have http://localhost:5001/ set as my App URL in my Visual Studio project Debug settings.

postman

If that is working correctly, move on to getting it to load with Angular 2. You'll need to use the base element just after the head tag in your html file. This tells the Angular router what the static part of the URL is:

Index.html

    <base href="/">

Next you'll need to create a Service in Angular2 to Get the values from your API: dataService.ts

import { Http, Response, Headers } from '@angular/http';
import 'rxjs/add/operator/map'
import { Observable } from 'rxjs/Observable';
import { Configuration } from '../app.constants';

@Injectable()
export class DataService { 
  private actionUrl: string;
  constructor(private _http: Http, private _configuration: Configuration) {
    this.actionUrl = 'http://localhost:5001/api/values/';
}

public GetAll = (): Observable<any> => {
    return this._http.get(this.actionUrl)
        .map((response: Response) => <any>response.json())
        .do(x => console.log(x));
}

The .do operator in RxJS is very handy. It will allow you to debug that you are correctly getting the values from your API. See Andre Staltz's blog for more details.

Finally, create a component to use the service: app.component.ts

import { Observable } from 'rxjs/Observable';
import { Component, OnInit } from '@angular/core';
import { Http } from '@angular/http';
import { DataService } from '../services/DataService';

@Component({
    selector: 'app',
    template: `My Values: <ul><li *ngFor="let value of values">
        <span>{{value.id}} </span>
      </li></ul>`,
    providers: [DataService]
})

export class AppComponent implements OnInit {
  public values: any[];
  constructor(private _dataService: DataService) {}
  ngOnInit() {
    this._dataService
        .GetAll()
        .subscribe(data => this.values = data,
        error => console.log(error),
        () => console.log('Get all complete'));
  }
}
like image 129
David Rinck Avatar answered Oct 15 '22 00:10

David Rinck


This is how I did it my application (angular2 as front-end with Web API core)-

  1. Create a controller using entity framework which provides all actions - GET, POST, PUT and DELETE. Refer this link in case you are new to web api and entity framework - https://docs.efproject.net/en/latest/platforms/aspnetcore/existing-db.html

  2. Enabled CORS in Web API

[This is done to handle cross communication from localhost:3000 (angular2) to localhost:59024 (webapi)]

First, add dependency in project.json - "Microsoft.AspNetCore.Cors": "1.0.0",

then enable CORS in startup.cs like this-

app.UseCors(builder => {
    builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader();
});

You can find more information about CORS here - https://docs.asp.net/en/latest/security/cors.html

3.In Angular2 front-end, you can write your service component like this-

@Injectable()
export class WebApiService {

    private _webApiUrl = 'http://localhost:59024/api/EmployeeMastersAPI'; 

        constructor(private _http: Http) { 

        }

    getEmployees(): Observable<{}> {
        return this._http.get(this._webApiUrl)
            .map((response: Response) => <any[]> response.json())
             .do(data => console.log('All: ' +  JSON.stringify(data)))
             .catch(this.handleError)
            ;
    }

    getEmployee(id: number): Observable<IEmployee> {
        return this.getEmployees()
            .map((emp: IEmployee[]) => emp.find(p => p.EMPID === id));
    }

    addEmployeesDetails(emp) {
        var headers = new Headers();
        headers.append('Content-Type', 'application/json; charset=utf-8');
        console.log('add emp : ' +  JSON.stringify(emp));
        this._http.post(this._webApiUrl, JSON.stringify(emp), { headers: headers }).subscribe();

    }

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

}

See if this helps.

like image 37
Sanket Avatar answered Oct 14 '22 23:10

Sanket