Search code examples
angularjsasp.net-web-apicorsowinkatana

CORS issue with Angular $resource and self hosted WebAPI


I'm unable to overcome the CORS issue in my Angular/ Owin slef-host WebAPI app.

Here is my Angular service code:

var grmService = angular.module('grmService', ['ngResource']);

grmService.factory('Grm', ['$resource',
    function($resource){

      return  $resource('http://accountviewserver:8080/api/grm',  {
            query: {
                method: 'GET',
                isArray: true,
                headers: { 'Access-Control-Allow-Origin': "*" }
            }
        });

    }]);

Here is my Angular controller code:

 angular.module('TaskManager')
        .controller('ResourceDashboardController', ['$scope','Grm',
        function ($scope,Grm) {

            $scope.grmData = Grm.query();
...

Here is my OWIN self-host WebPipeline config:

namespace AccountView3
{
  using System.Web.Http;
  using Microsoft.Owin;
  using Microsoft.Owin.FileSystems;
  using Microsoft.Owin.StaticFiles;
  using Owin;
    using System.Web.Http.Cors;

  public class WebPipeline
  {
    public void Configuration(IAppBuilder application)
    {
      application.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
      UseWebApi(application);
      application.UseNancy(options => options.Bootstrapper = new NancyBootstrapper());

    }

    private static void UseWebApi(IAppBuilder application)
    {
      var config = new HttpConfiguration();
      config.MapHttpAttributeRoutes();


      var cors = new EnableCorsAttribute("*", "*", "*");

      config.EnableCors(cors);

      config.Routes.MapHttpRoute(
              name: "DefaultApi",
              routeTemplate: "api/{controller}/{id}",
              defaults: new { id = RouteParameter.Optional }
          ); 

      application.UseWebApi(config);
    }

    public static bool IsDevelopment()
    {
      return true;
    }
  }
}

And here is my WebAPI controller:

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.Cors;


namespace AccountView3
{
  [EnableCors(origins: "*", headers: "*", methods: "*")]
    public class GrmController : ApiController
    {


        Demand[] demand = new Demand[] 
        { 
            new Demand { PositionId = 1, Description = "Lead Architect", Account = "AON", StartDate = Convert.ToDateTime("06/06/2014"), Role = "Architect",Fte = 1 }, 
            new Demand { PositionId = 2, Description = "PTM builder", Account = "Zurich", StartDate = Convert.ToDateTime("07/07/2014"), Role = "Architect",Fte = 1}, 
            new Demand { PositionId = 3, Description = "Transition Architect", Account = "Adib", StartDate = Convert.ToDateTime("08/08/2014"), Role = "Architect",Fte = 1 } 
        };

        public HttpResponseMessage Options()
        {
            var response = Request.CreateResponse(HttpStatusCode.OK);
            response.Headers.Add("Access-Control-Allow-Origin", "*");
            response.Headers.Add("Access-Control-Allow-Methods", "POST");
            response.Headers.Add("Access-Control-Allow-Methods", "GET");
            response.Headers.Add("Access-Control-Allow-Methods", "PUT");
            response.Headers.Add("Access-Control-Allow-Methods", "DELETE");
            response.Headers.Add("Access-Control-Allow-Headers", "Content-Type");
            return response;
        }


        // GET api/values 
        public HttpResponseMessage Get()
        {
            var response = Request.CreateResponse(HttpStatusCode.OK, demand);
            response.Headers.Add("Access-Control-Allow-Origin","*");
            response.Headers.Add("Access-Control-Allow-Methods", "POST");
            response.Headers.Add("Access-Control-Allow-Methods", "GET");
            response.Headers.Add("Access-Control-Allow-Methods", "PUT");
            response.Headers.Add("Access-Control-Allow-Methods", "DELETE");
            response.Headers.Add("Access-Control-Allow-Headers", "Content-Type");
            return response;
        }

        // GET api/values/5 
        public string Get(int id)
        {
            return "value";
        }

        // POST api/values 
        public void Post([FromBody]string value)
        {
        }

        // PUT api/values/5 
        public void Put(int id, [FromBody]string value)
        {
        }

        // DELETE api/values/5 
        public void Delete(int id)
        {
        }
    }

    public class Demand
    {
        public int PositionId { get; set; }
        public string Description { get; set; }
        public string Account { get; set; }
        public DateTime StartDate { get; set; }
        public string Role { get; set; }

        public int Fte { get; set; }
    }
}

With all of this being set to allow CORS, I still get:

XMLHttpRequest cannot load http://accountviewserver/api/grm?query=%5Bobject+Object%5D. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:63342' is therefore not allowed access. The response had HTTP status code 404.

What can I do to fix this?


Solution

  • My recommendation is to do the following:

    1. Do not set the "Access-Control-Allow-Origin" from your angular resource, it is response header not request header and should be set from the server.

    2. Only allow CORS using application.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll); and remove it else where from your controllers attribute even from configuration.

    3. Check my Repo here where I've implemented CORS and the front end is AngularJS too. it is working correctly. Here is the live demo too for this repo, open developer tools and monitor the requests, you should see pre-flight request before you see your HTTP get request.