Saturday, 31 October 2015

ASP.NET 5 and AngularJS Part 2, Using the MVC 6 Web API


This is the second part in a multiple part blog series on building ASP.NET 5 (ASP.NET vNext) apps with AngularJS. In this series of blog posts, I show how you can create a simple Movie app using ASP.NET 5, MVC 6, and AngularJS.
You can download the code discussed in this blog post from GitHub:
In this blog post, I explain how to expose data from your server using the MVC 6 Web API. We’ll retrieve a list of movies from the Web API and display the list of movies in our AngularJS app by taking advantage of an AngularJS template.

Enabling ASP.NET MVC

The first step is to enable MVC for our application. There are two files that we need to modify to enable MVC.
First, we need to modify the project.json file so it includes MVC 6:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
    "webroot": "wwwroot",
    "version": "1.0.0-*",
    "exclude": [
        "wwwroot"
    ],
    "packExclude": [
        "**.kproj",
        "**.user",
        "**.vspscc"
    ],
    "dependencies": {
        "Microsoft.AspNet.Server.IIS": "1.0.0-beta1",
        "Microsoft.AspNet.Mvc": "6.0.0-beta1"
    },
    "frameworks" : {
        "aspnet50" : { },
        "aspnetcore50": { }
    }
}
The project.json file is used by the NuGet package manager to determine the packages required by the project. We’ve indicated that we need the MVC 6 (beta1) package.
We also need to modify the Startup.cs file in the root of our MovieAngularJS project. Change the contents of the Startup.cs file so it looks like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using System;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Http;
using Microsoft.Framework.DependencyInjection;
 
namespace MovieAngularJSApp
{
    public class Startup
    {
 
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
        }
 
        public void Configure(IApplicationBuilder app)
        {
            app.UseMvc();
        }
 
    }
}
The ConfigureServices() method is used to register MVC with the built-in Dependency Injection framework included in ASP.NET 5. The Configure() method is used to register MVC with OWIN.

Creating the Movie Model

Let’s create a Movie model class that we can use to pass movies from the server to the browser (from the Web API to AngularJS). Create a Models folder in the root of the MovieAngularJS project:
Models Folder
Notice that you create the Models folder outside of the wwwroot folder. Source code does not belong in wwwroot.
Add the following C# class named Movie.cs to the Models folder:
1
2
3
4
5
6
7
8
9
10
11
12
13
using System;
 
namespace MovieAngularJSApp.Models
{
    public class Movie
    {
        public int Id { get; set; }
 
        public string Title { get; set; }
 
        public string Director { get; set; }
    }
}

Creating the Web API Controller

Unlike earlier versions of ASP.NET, the same controller base class is used for both MVC controllers and Web API controllers. Because we’ve pulled in the NuGet package for MVC 6, we are now ready to start creating Web API controllers.
Add an API folder to the root of your MovieAngularJS project:
API Folder
Notice that you don’t add the API folder inside of your wwroot folder. All of your source code – including source code for your controllers – should be located outside of the wwwroot folder.
Next, add a Web API controller by right-clicking the API folder and selecting Add, New Item. Choose the Web API Controller Class template and name the new controller MoviesController.cs:
Add MVC Controller
Enter the following code for the Web API controller:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNet.Mvc;
using MovieAngularJSApp.Models;
 
 
namespace MovieAngularJSApp.API.Controllers
{
    [Route("api/[controller]")]
    public class MoviesController : Controller
    {
        // GET: api/values
        [HttpGet]
        public IEnumerable<Movie> Get()
        {
            return new List<Movie> {
                new Movie {Id=1, Title="Star Wars", Director="Lucas"},
                new Movie {Id=2, Title="King Kong", Director="Jackson"},
                new Movie {Id=3, Title="Memento", Director="Nolan"}
            };
        }
 
    }
}
In the code above, the Get() action returns a list of movies. You can test whether the action is working by starting your app and navigating to /api/movies in your browser. In Google Chrome, you’ll get an XML representation of the movies:
XML Results

Creating the AngularJS App

We are going to display the list of movies using an AngularJS template. First, we need to create our AngularJS app.
Right-click on the Scripts folder and select Add, New Item. Select the AngularJS Module template and click the Add button.
AngularJS Module
Enter the following code for the new AngularJS module:
1
2
3
4
5
6
7
(function () {
    'use strict';
 
    angular.module('moviesApp', [
        'moviesServices'
    ]);
})();
The code above defines a new AngularJS module named moviesApp. The moviesApp has a dependency on another AngularJS module named moviesServices. We create the moviesServices below.

Creating the AngularJS Controller

Our next step is to create a client-side AngularJS controller. Create a new Controllers folder under the Scripts folder:
AngularJS Controller
Right-click the Controller folder and select Add, New Item. Add a new AngularJS Controller using $scope named moviesController.js to the Controllers folder. Enter the following content for the moviesController.js file:
1
2
3
4
5
6
7
8
9
10
11
12
13
(function () {
    'use strict';
 
    angular
        .module('moviesApp')
        .controller('moviesController', moviesController);
 
    moviesController.$inject = ['$scope', 'Movies'];
 
    function moviesController($scope, Movies) {
        $scope.movies = Movies.query();
    }
})();
The AngularJS controller above depends on a Movies service that supplies the list of movies. The Movies service is passed to the controller using dependency injection. The Movies service is passed as the second parameter to the moviesController() function.
The moviesController.$inject() method call is required to enable the moviesController to work with minification. AngularJS dependency injection works off the name of parameters. In the previous blog post, I setup Grunt and UglifyJS to minify all of the JavaScript files. As part of the process of minification, all function parameter names are shortened (mangled). The $inject() method call enables dependency injection to work even when the parameter names are mangled.

Creating the AngularJS Movies Service

We’ll use an AngularJS Movies service to interact with the Web API. Add a new Services folder to the existing Scripts folder. Next, right-click the Services folder and select Add, New Item. Add a new AngularJS Factory named moviesService.js to the Services folder:
Enter the following code for moviesService.js:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
(function () {
    'use strict';
 
    var moviesServices = angular.module('moviesServices', ['ngResource']);
 
    moviesServices.factory('Movies', ['$resource',
      function ($resource) {
          return $resource('/api/movies/', {}, {
              query: { method: 'GET', params: {}, isArray: true }
          });
      }]);
 
 
})();
The movieServices depends on the $resource object. The $resource object performs Ajax requests using a RESTful pattern.
In the code above, the moviesServices is associated with the /api/movies/ route on the server. In other words, when you perform a query against the moviesServices in your client code then the Web API MoviesController is invoked to return a list of movies.

Creating the AngularJS Template

The final step is to create the AngularJS template that displays the list of movies. Right-click the wwwroot folder and add a new HTML page named index.html.
Add HTML
Modify the contents of index.html so it looks like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<!DOCTYPE html>
<html ng-app="moviesApp">
<head>
    <meta charset="utf-8" />
    <title>Movies</title>
 
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.8/angular.min.js"></script>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.8/angular-resource.js"></script>
    <script src="app.js"></script>
</head>
<body ng-cloak>
    <div ng-controller="moviesController">
 
        <table>
            <thead>
                <tr>
                    <th>Title</th>
                    <th>Director</th>
                </tr>
            </thead>
            <tbody>
                <tr ng-repeat="movie in movies">
                    <td>{{movie.Title}}</td>
                    <td>{{movie.Director}}</td>
                </tr>
            </tbody>
        </table>
 
    </div>
</body>
</html>
There are several things that you should notice about this HTML file:
  • Notice that the <html> element includes an ng-app directive. This directive associates the moviesApp with the HTML file.
  • Notice that <script> tags are used to add the angular and angular-resource JavaScript libraries from the Google CDN.
  • Notice that the <body> element includes an ng-controller directive. This directive associates the moviesController with the contents of the <div> element.
  • Notice that the movies are displayed by using an ng-repeat directive. The title and the director are displayed for each movie.
  • Notice that the <body> element includes an ng-cloak directive. The ng-cloak directive hides an AngularJS template until the data has been loaded and the template has been rendered.
When you open the index.html page in your browser, you can see the list of movies displayed in the HTML table.
The Results

Summary

In this blog post, we created an AngularJS app that calls a Web API action to retrieve a list of movies. We displayed the list of movies in an HTML table by taking advantage of an AngularJS template.
In the next blog post, I discuss how you can take advantage of AngularJS routing to divide a client-side AngularJS app into multiple virtual pages.

No comments:

Post a Comment

Angular Tutorial (Update to Angular 7)

As Angular 7 has just been released a few days ago. This tutorial is updated to show you how to create an Angular 7 project and the new fe...