Deborah's Developer MindScape






         Tips and Techniques for Web and .NET developers.

August 12, 2015

"Angular Front to Back with Web API" Problem Solver

Angular and ASP.NET Web API are like chocolate and peanut butter, they are GREAT together! But there are lots of intricacies and many, many things that can go wrong when putting these two technologies together. This problem solver covers some of the most common things that can go wrong and how to fix them.

The_Creation_Michelangelo

Using Angular as the client technology in the front-end and an ASP.NET Web API service in the back-end is a common requirement. So much so, that I developed a Pluralsight course to help developers tackle all of the touch points between an Angular client application and a back-end ASP.NET Web API service: Angular Front to Back with Web API.

As of this writing, there have been over 400 posts associated with that course, many of which identify problems that developers have had in merging these two technologies. This post summarizes the most common issues and identifies locations in the course where solutions to these issues can be found

 

No Access-Control-Allow-Origin Header is Present

This issue first appears in module 3 (Retrieving Data) clip 6 (Calling the Web API from Angular). We created the ASP.NET Web API code in a project separate from the Angular code. So when the solution is executed:

When the Angular code calls the ASP.NET Web API, it will work in Internet Explorer but *not* in Chrome. In Chrome, pressing the F12 tools will show the error: No “Access-Control-Allow-Origin” header is present, Status Code: 500 Internal Server Error.

This is a problem with cross-origin requests. Since the origin of the call is from http://localhost:52436 and the endpoint is at http://localhost:52293, the request is considered to be a cross-origin request. In other words, the request is originating at a different URL than the service. By default, cross-origin requests are denied. (This works in debug mode with IE because IE does not consider the difference in port numbers to be a cross-origin request.)

The solution to this problem is CORS, or cross-origin resource sharing. Wikipedia states that CORS “allows many resources … on a web page to be requested from another domain outside the domain from which the resource originated.” In other words, CORS defines a way that a service can interact safely with a browser application that originates on a different domain or different server.

To enable CORS in the ASP.NET Web API, start by downloading the CORS package using NuGet Package Manager.

image

Once CORS is installed, there are two additional steps:

1) Call the EnableCors method.

Open the WebApiConfig.cs file in the App_Start folder. Add this line to the Register method:

config.EnableCors();

2) Set the EnableCorsAttribute.

Set this attribute on any controller class that wants to allow cross origin requests. For example, on the ProductsController, it might look like this:

[EnableCorsAttribute(“http://localhost:52436″, “*”, “*”)]
public class ProductsController : ApiController
{}

Note that the port shown in red is the port for the Angular application. This code tells the PrioductsController class that it should allow cross-origin requests only from the defined location, which is from our Angular client application. Alternatively, use “*” to allow access from any cross-origin request.

These steps are covered in detail in module 4 (CORS and Formatters) clip 3 (Enabling CORS in a Web API service).

OData Does Not Work

This issue appears in Module 6 (Using OData Queries) and often takes the form of a problem with the contains method of the OData $filter. This problem is due to confusion on the multiple OData packages that are available in Visual Studio.

The course requires version 4 of OData, so be sure to select the NuGet package that says “OData v4.0” in the description.

NOTE: There are many similarly named NuGet packages, such as “Microsoft.Data.OData” and “Microsoft.AspNet.WebApi.OData”. Be sure to select the one shown below.

image

User Login Generates a CORS Error

This issue appears in module 10 (User Registration and Login). It often only occurs in Chrome (not IE).

There are two possible issues here:

1) There is one line of code that is missing from the demo in the course.

[EnableCorsAttribute(“http://localhost:52436″, “*”, “*”)]
public class AccountController : ApiController
{ }

This line of code enables CORS for the AccountController just as we did for the ProductsController earlier in the course (module 3)

2) There is one line of code added during the demo, but is sometimes missed when coding along.

In the Providers folder, ApplicationOAuthProvider.cs file, GrantResourceOwnerCredentials method, add the following line:

context.OwinContext.Response.Headers.Add(“Access-Control-Allow-Origin”,
    new[] { “
http://localhost:52436″ });

Where the defined URL shown in red is the location of the Angular application that this code is granting access to.

This code is explained and demoed in module 10 (User Registration and Login) clip 4 (Logging the User In) starting around 9:32 with showing the error and the line of code is added at 10:13.

User Registration Network Methods

Several questions have come up regarding the network methods that occur when the Register button is selected to register a new user. I entered a new user name and password, then clicked the Register button. The results are shown below when using Chrome on Windows:

image

Hope this answers the questions.

Save Issues

I have not been able to reproduce any specific issue here … but if you have problems with the Save operation … Try changing this in productResource.js:

‘save’: {
    headers: { ‘Authorization’: ‘Bearer ‘ + currentUser.getProfile().token }
},

With this:

‘save’: {
    method: ‘POST’,
    headers: { ‘Authorization’: ‘Bearer ‘ + currentUser.getProfile().token }
},

Cannot Read Property ‘exceptionMessage’ of Null

This is most likely caused by the exception handling in mainCtrl.js. Change this:

function (response) {
    vm.password = “”;
    vm.message = response.statusText + “\r\n”;
    if (response.data.exceptionMessage)
        vm.message += response.data.exceptionMessage;

    if (response.data.error) {
        vm.message += response.data.error;
    }
});

To this:

function (response) {
    vm.password = “”;
    vm.message = response.statusText + “\r\n”;
    if (response.data && response.data.exceptionMessage)
        vm.message += response.data.exceptionMessage;

    if (response.data && response.data.error) {
        vm.message += response.data.error;
    }
});

Please let me know if you have run into anything else that should be added to this list.

Enjoy!

21 Comments

  1.   Krishna K — August 1, 2016 @ 2:45 pm    Reply

    Hi Deborah,

    For some reason my Request Header is missing the ‘Authorization’ header part –

    Accept:application/json, text/plain, */*
    Accept-Encoding:gzip, deflate, sdch
    Accept-Language:en-US,en;q=0.8
    Connection:keep-alive
    Host:localhost:49588
    Origin:http://localhost:56472
    Referer:http://localhost:56472/
    User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36

    Here is my productResource:
    ///////////////
    function productResource($resource, appSettings, currentUser) {

    return $resource(appSettings.serverPath + “api/evals”, null,
    {

    ‘get’: {
    method: ‘GET’,
    headers: { ‘Authorization’: ‘Bearer ‘ + currentUser.getProfile().token }
    },
    ‘save’: {
    headers: { ‘Authorization’: ‘Bearer ‘ + currentUser.getProfile().token }
    },
    ‘update’: {
    method: ‘PUT’,
    headers: { ‘Authorization’: ‘Bearer ‘ + currentUser.getProfile().token }
    }

    });

    }
    /////////////////

    I have tested the Web API part and has no issues and the Token in also getting generated and passed from the ‘currentUser.getProfile().token’.

    Please help.

    Thanks.

  2.   Mario Mont — January 4, 2017 @ 1:49 pm    Reply

    I’m currently studying the course using angular 2 thanks to what I learned on the Angular 2 – Getting Started course and so far so good :),
    until I got to the exception handling chapter of the tutorial and found out I have no response.data.exceptionMessage, well not even response.data.
    I’ve checked using postman and chrome dev tools and I get the whole json back with the info, but unfortunately not from the response object itself in angular 2.
    Please help!
    Thanks in advance.

RSS feed for comments on this post. TrackBack URI

Leave a comment

© 2020 Deborah's Developer MindScape   Provided by WPMU DEV -The WordPress Experts   Hosted by Microsoft MVPs