DotNetCurry Logo

Multiple Async calls to ASP.NET Web API using Angular.js $q.all()

Posted by: Mahesh Sabnis , on 8/16/2016, in Category AngularJS
Views: 33764
Abstract: Using Angular.js $q.all to call multiple ASP.NET Web API services at a time

AngularJS provides components like module, service, factory, directive etc. using which we can develop client-side logic in a web application. The service component of Angular provides an encapsulation for all calls to an external REST service. This uses the $http dependency to make http calls for reading and writing data from and to REST services.

You can explore about $http and its features from this link. This object is used to perform asynchronous operations and it returns the promise object. This promise object is then used by the caller to retrieve the response from the asynchronous call. Now using $http, we can make an asynchronous call to a remote service. But what if we want to make asynchronous calls to multiple services and retrieve data when all these asynchronous calls are completed. Here we need a powerful object which will keep track of promises from $http call and return to the caller when all calls are completed.

 

In AngularJS, we have the $q object which is a service that helps to execute a function asynchronously and use values returned from these calls for further processing. This is an implementation of promise or deferred object. This object exposes various functions for performing asynchronous operations. More information about $q can be obtained from this link.

In the following steps, we will use the $q object with its all() function to combine multiple promise objects into single promise object and use it to call multiple services at a time. This functions resolve the single promise object when all promise objects passed to the function are resolved.

ASP.NET Web API implementation

The article uses an ASP.NET Web API service created using the free Visual Studio 2015 Community edition.

Step 1: Open Visual Studio and create a new solution NG_Combine_Multiple_Promises. In this solution, add a new empty ASP.NET Web API project as shown in following image:

empty-web-api-project

Step 2: In this project, in the Models folder add a class file with the following code: (Note: The Models folder can be used for EntityFramework)

using System.Collections.Generic;

namespace NG_Combine_Multiple_Promises.Models
{
    public class Courses
    {
        public int CourseId { get; set; }
        public string CourseName { get; set; }
    }
    public class CourseDatabase : List<Courses>
    {
        public CourseDatabase()
        {
            Add(new Courses() { CourseId=1,CourseName="Electronics"});
            Add(new Courses() { CourseId = 2, CourseName = "Electrical" });
            Add(new Courses() { CourseId = 3, CourseName = "Civil" });
        }
    }

    public class Student
    {
        public int StudentId { get; set; }
        public string Name { get; set; }
        public string AcadmicYear { get; set; }
    }

    public class StudentDatabase : List<Student>
    {
        public StudentDatabase()
        {
            Add(new Student() {StudentId=101,Name="MS", 
                               AcadmicYear="First" });
            Add(new Student() { StudentId = 102, Name = "TS", 
                               AcadmicYear = "Second" });
            Add(new Student() { StudentId = 103, Name = "LS", 
                               AcadmicYear = "Third" });
            Add(new Student() { StudentId = 104, Name = "VB", 
                               AcadmicYear = "First" });
            Add(new Student() { StudentId = 105, Name = "PB", 
                               AcadmicYear = "Second" });
            Add(new Student() { StudentId = 106, Name = "AB", 
                               AcadmicYear = "Third" });
            Add(new Student() { StudentId = 107, Name = "SA", 
                               AcadmicYear = "First" });
            Add(new Student() { StudentId = 108, Name = "SN", 
                               AcadmicYear = "Second" });
            Add(new Student() { StudentId = 109, Name = "SK", 
                               AcadmicYear = "Third" });
        }
    }
    
}

The above code contains Courses and Student entity classes. The CourseDatabase and StudentDatabase stores courses and students information respectively.

Step 3: In the project, add the NuGet Package Manager for Microsoft.AspNet.WebAPi.Cors. This will be used to enable calls from all domains. Add the following line in WebApiCofig class in the App_Start folder.

config.EnableCors();

Step 4: In the Controllers, add two Web API 2 Empty controller classes of name CourseAPIController and StudentAPIController. The code that goes in them is as follows:

CourseAPIController.cs

[EnableCors("*","*","*")]
public class CourseAPIController : ApiController
{
    [Route("Courses")]
    public IEnumerable<Courses> Get()
    {
        return new CourseDatabase();
    }
}

StudentAPIController.cs

[EnableCors("*", "*", "*")]
public class StudentAPIController : ApiController
{
    [Route("Students")]
    public IEnumerable<Student> Get()
    {
        return new StudentDatabase();
    }
}

The above API Controller classes contains Get () method which returns Course and Student collection.

Build the project and make sure that it is error free.

 

Using Angular $q.all()

Step 1: In the same solution add a new Empty ASP.NET project of the name NG_CombineCalls. In this project add references for jQuery, Bootstrap and Angular using NuGet Package manager.

The commands are as following:

Install-Package jQuery
Install-Package bootstrap -Version 3.3.6
Install-Package angularjs

Step 2: In the project add a new folder of name MyScripts. In this folder add a new JavaScript file name Logic.js with the following code in it:

//1.
var app = angular.module('mymodule', []);

//2.
app.service('courseService', function ($http) {
    this.get = function () {
        var response = $http.get("http://localhost:42490/Courses");
        return response;
    };
});

//3.
app.service('studentService', function ($http) {
    this.get = function () {
        var response = $http.get("http://localhost:42490/Students");
        return response;
    };
});

//4.
app.controller('ctrl', function ($scope, $q, courseService, studentService) {

$scope.Courses = [];
$scope.Students = [];
loadData();

//5.
function loadData() {
    var promiseCourse = courseService.get();
    var promiseStudent = studentService.get();

    $scope.combineResult = $q.all([
        promiseCourse, 
        promiseStudent 
    ]).then(function (resp) {
       $scope.Courses= resp[0].data;
       $scope.Students= resp[1].data;
    });
}
});

The above code has the following specifications: (Line numbers represents comments numbers applied on code)

1. Define Angular module of the name mymodule

2. Define Angular Service which makes a call to Courses Web API and returns promise object.

3. Define Angular service which make call to Students Web API service and returns promise object.

4. Define Angular Controller which is injected with $scope, $q, and Angular Service objects. This also contains Courses and Students arrays which will be used to bind data to View.

5. The loadData() function makes call to get() function from Course and Student service. The $q.all() function is passed with an array of promise object for each service call. When all promises are resolved then() will be called and final response will be received which is stored in Courses and Students array object.

Step 3: In the project add a new folder of name View and add a new Html page of name DataPage in it. Add the following markup in the page:

<!DOCTYPE html>
<html ng-app="mymodule">
<head>
    <title></title>
    <meta charset="utf-8" />
    <link href="../Content/bootstrap.min.css" rel="stylesheet" />
    http://../Scripts/angular.min.js
    http://../MyScripts/Logic.js
</head>
<body ng-controller="ctrl">
    <h1 class="h1">Courses</h1>
    <table class="table table-striped table-bordered table-condensed">
        <thead>
            <tr>
                <td class="text-center">Course Id</td>
                <td class="text-center">Course Name</td>
            </tr>
        </thead>
        <tbody>
            <tr ng-repeat="Course in Courses">
                <td class="text-center">{{Course.CourseId}}</td>
                <td class="text-center">{{Course.CourseName}}</td>
            </tr>
        </tbody>
    </table>
    <hr />
    <h1 class="h1">Students</h1>

    <table class="table table-striped table-bordered table-condensed">
        <thead>
            <tr>
                <td class="text-center">Student Id</td>
                <td class="text-center">Student Name</td>
                <td class="text-center">Acadmic Year</td>
            </tr>
        </thead>
        <tbody>
            <tr ng-repeat="Student in Students">
                <td class="text-center">{{Student.StudentId}}</td>
                <td class="text-center">{{Student.Name}}</td>
                <td class="text-center">{{Student.AcadmicYear}}</td>
            </tr>
        </tbody>
    </table>
</body>
</html>

The above markup defines data binding with the Courses and Students array with HTML tables using ng-repeat directive.

Run the Web API application and the Client project. The following result will be displayed

angular-q-all-multiple-calls

Conclusion

In case of Angular applications, when we expect to show data from different service calls on the UI, $q.all() comes in very handy. It accepts a collection of promises and resolves them as a single promise. It proceeds ahead in an async fashion only when all promises are resolved or when an error has occurred in which case some action can be taken.

Download the entire source code of this article (Github)

Was this article worth reading? Share it with fellow developers too. Thanks!
Share on Google+
Further Reading - Articles You May Like!
Author
Mahesh Sabnis is a DotNetCurry author and Microsoft MVP having over 17 years of experience in IT education and development. He is a Microsoft Certified Trainer (MCT) since 2005 and has conducted various Corporate Training programs for .NET Technologies (all versions). Follow him on twitter @maheshdotnet


Page copy protected against web site content infringement 	by Copyscape




Feedback - Leave us some adulation, criticism and everything in between!