AngularJS CRUD Application with ASP.NET Core Web API

AngularJS CRUD Application with ASP.NET Core Web API

I have been delving more into ASP.NET Core lately and I wanted to see how different things were from the .NET 4.6 version, so I decided to see what it would be like to code a very simple Web API using ASP.NET Core and Entity Framework 7. Bear in mind that I decided to base the UI off of a sample article created by Sandeep Panda on SitePoint, mainly because I thought it was an effectively simple and intuitive UI. I also wanted to use the most minimal way that something would work so I could try out the ASP.NET Web API from end to end. So if you want to read up more about how the UI is setup just head over to that article and follow the link to the source code posted on Sandeep’s GitHub profile, it’s all there for you to do a deep dive if you so desire.  So all props to Sandeep and SitePoint on the front end UI piece.

One more thing that I should mention is that I did add a significant change from the original AngularJS code in the fact that I decided to use the AngularJS $http provider instead of the $resource one like the article explains. The reason for that is that I found the use of $resource very limiting in terms of how the Web API needed to be setup. In order to use the $resource you have to add an id to all the requests to the Web API, this is because the $resource object instance abstracts the code needed for API calls quite a bit more than the $http provider, which is perfectly fine if you stick to that required format, however I opted for sending the actual request object during API calls such as PUT and POST without an id, therefore using the $resource approach would not have worked well for me. This is however simply an implementation detail and you can decide what approach fits best for your application needs. So if you want to use the $resource approach then go for it, just be aware of the trade-offs needed for essentially using a higher level of abstraction.

Setting up and replacing $resource with $http

First I added a new AngularJS factory that leverages the $http provider, I simply attached it to the current services.js file right after the ‘popupservice’:

The data access factory, called **moviebus **(Note: this is not a service bus, I just named it moviebus because I liked that name at the time, that is all, just having a bit of fun with naming; you can name yours movieDataFactory or whatever you like, it’s just sample code, have some fun with it) in this example, contains the basic methods you would need for doing a simple CRUD operation:

.factory('moviebus', function ($http) {

        var apiEndpoint = "http://localhost:1479/"; // TODO: Update to use the root location of your Web API

        $http.defaults.useXDomain = true;
        delete $http.defaults.headers.common['X-Requested-With'];

        return {
            getItems: function () {
                var request = $http({
                    method: 'GET',
                    url: apiEndpoint + 'api/movies'
                });
                return (request
                    .then(function success(response) {
                        return (response.data);
                    }, function error(response) {
                        return ($q.reject(response.data.message));
                    }));
            },

            getItem: function (id) {
                return $http.get(apiEndpoint + 'api/movies/' + id)
                    .then(function success(response) {
                        return (response.data);
                    }, function error(response) {
                        return ($q.reject(response.data.message));
                    });
            },

            postItem: function (item) {
                var request =
                    {
                        Title: item.title,
                        ReleaseYear: item.releaseYear,
                        Director: item.director,
                        Description: item.description,
                        Genre: item.genre
                    };

                return $http.post(apiEndpoint + 'api/movies/', request)
                    .then(function success(response) {
                        return (response.data);
                    }, function error(response) {
                        return ($q.reject(response.data.message));
                    });
            },

            putItem: function (item) {
                var request =
                    {
                        Id: item.id,
                        Title: item.title,
                        ReleaseYear: item.releaseYear,
                        Director: item.director,
                        Description: item.description,
                        Genre: item.genre
                    };

                return $http.put(apiEndpoint + 'api/movies/', request)
                    .then(function success(response) {
                        return (response.data);
                    }, function error(response) {
                        return ($q.reject(response.data.message));
                    });
            },

            deleteItem: function (id) {
                return $http({
                    method: 'DELETE',
                    url: apiEndpoint + 'api/movies/' + id,
                }).then(
                    function success(response) {
                        return (response.data);
                    }, function error(response) {
                        return ($q.reject(response.data.message));
                    });
            }
        };
    }

This essentially requires writing more code than the $resource object would need, but it is a bit more flexible in my opinion. In any case, you are free to implement the abstraction that makes more sense for your needs. Let’s move on to the Web API implementation.

Setting up the backend Web API

Setting up the initial Web API project

If you have read some of my previous posts, you would by now be familiar with setting up an ASP.NET Core project using Yeoman. All you need to generate the Web API project is to navigate to the directory of your choice and issue a few commands:

Choose Web API Application and then give your application a name:

You can then navigate to that folder using File Explorer (Windows) and open the application using something like Visual Studio Code or Visual Studio 2015 Community. However, for this exercise I recommend using Visual Studio 2015 to run the Web API, simply because you might want to debug the application which by default runs using IIS Express in Visual Studio. Keep in mind that you can do all of this using Visual Studio Code and you can run the basic Kestrel server from the command line, nevertheless, I still find that for things like Web API and such Visual Studio offers a more pleasant debugging experience. But this is a personal preference rather than strict guidance, so use the tool that best works for you.

Entity Framework 7 (In Memory Provider)

Once again, since I wanted to get the simplest thing to work, I decided to re-use the movie model and leveraged Entity Framework 7 In-Memory provider. In this case I simply added a new model to the Web API project:

    public class Movie
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public string ReleaseYear { get; set; }
        public string Director { get; set; }
        public string Genre { get; set; }
    }

I then referenced the Microsoft.EntityFrameworkCore.InMemory library in the project.json file, which you can find more details about on the EF7 GitHub page. The required import statement is this:

** “Microsoft.EntityFrameworkCore.InMemory”: “1.0.0”**

Now all that is needed is to create a new data context for the Movies model and setting it up with an In-Memory Database (Name it whatever you like, in my case it is “MyData”):

    public class MovieContext : DbContext
    {
        
        public DbSet<Movie> Movies { get; set; }

        protected override void     OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseInMemoryDatabase("MyData");
        }
    }

The data will be contained in the database while the application is running. I like this because it is an easy and simple way to get things going while creating a model and debugging a Web API without the added overhead of an actual database during the prototype phase of an application.

Setting Up the Web API Movies Controller

The next step is to setup the Web API controller. One of the more glaring changes in ASP.NET Core is that now when you create a new controller, be it an MVC or Web API controller, you can do so by inheriting from one single base class: Controller. The following is a snippet from the MoviesController.cs class I added to my Web API project:

[Route("api/[controller]")]
    public class MoviesController : Controller
    {
        // GET api/movies
        [HttpGet]
        public IList<Movie> Get()
        {
            IList<Movie> movies;

            using (var db = new MovieContext())
            {
                movies = db.Movies
                        .OrderBy(b => b.Title)
                        .ToList();
            }

            return movies;
        }

        // GET api/movies/5
        [HttpGet("{id}")]
        public Movie Get(int id)
        {
            Movie movie;
            using (var db = new MovieContext())
            {
                movie = db.Movies.FirstOrDefault(a => a.Id == id);
            }

            return movie;
        }

        // POST api/movies
        [HttpPost]
        public void Post([FromBody]Movie value)
        {
            using (var db = new MovieContext())
            {
                var movie = new Movie
                {
                    Title = value.Title,
                    ReleaseYear = value.ReleaseYear,
                    Director = value.Director,
                    Genre = value.Genre
                };

                db.Movies.Add(movie);
                db.SaveChanges();
            }
        }

        // PUT api/movies/5
        [HttpPut]
        public void Put([FromBody]Movie value)
        {
            using (var db = new MovieContext())
            {
                Movie movie = db.Movies.FirstOrDefault(m => m.Id == value.Id);
                if (movie != null)
                {
                    movie.Title = value.Title;
                    movie.ReleaseYear = value.ReleaseYear;
                    movie.Director = value.Director;
                    movie.Genre = value.Genre;

                    db.SaveChanges();
                }
            }
        }

        // DELETE api/movies/5
        [HttpDelete("{id}")]
        public void Delete(int id)
        {
            using (var db = new MovieContext())
            {
                Movie movie = db.Movies.FirstOrDefault(a => a.Id == id);

                if (movie != null)
                {
                    db.Movies.Remove(movie);
                    db.SaveChanges();
                }
            }
        }
    }

The endpoints on the Movies Controller (GET, POST, PUT, DELETE) have a respective factory method call in the moviebus AngularJS data access factory component, simply look for the http verb in moviebus and match it to corresponding endpoint in the Movies Controller.

Configuring CORS

One final configuration piece you need to address is the use of CORS. For this sample application, the front end is running using the node.js http-server on a different port than the Web API, which is running using IIS-Express. It is fairly common these days to run your front end application on a different server than your backend Web API, thus most likely you will have to deal with CORS at sometime. However, a full configuration tutorial on CORS is beyond the scope of this post, so you can just add this configuration code to your Startup.cs class to make things work during development:

Now, keep in mind that the following code should only be used for development/prototyping purposes, you can wrap it inside the env.IsDevelopment() section of the code if you like:

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

**Important: **Using this type of lose CORS configuration will make it so that your Web API accepts all origins, http verbs and http headers. This will most likely NOT be what you want to do in Production, since it opens up possible security holes to your application if you use these settings out in the wild. So be careful, you have been warned.

Running the Web API

Now you are ready to run your AngularJS application and connect it to an ASP.NET Core Web API with an EF7 in memory data store!

From within Visual Studio 2015, locate the IIS Express debug button and press to launch the Web API

Visual Studio will launch a new browser window showing the pre-configured localhost setting along with the port specified in the settings:

Now you can run the AngularJS application using the http-server (If you are not familiar with http-server, please head over to https://www.npmjs.com/package/http-server and install it now), since this is a basic application running over http, all you need to launch it is to spin up a new command line console and  navigate to the folder where the index.html file is and run the command: http-server

The application will start in the default URL along with the default port: http://localhost:8080 Here you can run the UI, just as before, in order to:

  • View all movies
  • View a single movie details
  • Add a movie
  • Edit a movie
  • Delete a movie

Epilogue

A number of things have changed in ASP.NET Core when it comes to writing Web APIs. Given that the framework is a complete rewrite then such a thing is of course expected. The consolidation of the Controller base class looks like a nice change, and the fact that EF7 offers an In-Memory provider for testing/prototyping makes things very simple to setup. Note that this release of ASP.NET Core is a 1.0 release, so many things that you and I expect out of the box may not be there, but so far I am liking the changes. I hope this short preview of ASP.NET Core Web API was useful to you. I will continue to dig deeper into .NET Core and its related frameworks in the coming months and share my findings.

Until next time, happy coding.

Update: I have posted the update source code for the sample on GitHub: https://github.com/jpvelasco/angular-aspnetcore-movie-crud