8
votes

I'm building a .Net Web Api that will be consumed by Angular 6 client but for any reason I'm not being able to make it to work in my development environment.

I started with an extremely simple Web Api that just does nothing but returns a string (with communication between frontend and backend testing purposes):

// GET: api/Login
public IEnumerable<string> Get()
{
    return new string[] { "Now it works!" };
}

// POST: api/Login
public void Post([FromBody]string value)
{
    string strTest = "I'm doing just nothing";
}

and then in my Angular 6 app I have a method with the following post request:

return this.http.post<any>(`http://localhost:9810/api/Login`, { username, password })
            .pipe(map(user => {
                // login successful if there's a jwt token in the response
                if (user && user.token) {
                    // store user details and jwt token in local storage to keep user logged in between page refreshes
                    localStorage.setItem('currentUser', JSON.stringify(user));
                }

                return user;
            }));

In my first attempts all my responses were failing with response:

zone.js:2969 OPTIONS http://localhost:9810/api/Login 405 (Method Not Allowed)
login:1 Failed to load http://localhost:9810/api/Login: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4200' is therefore not allowed access.

So I after investigating I've added CORS support to my WebApi .Net project the next way:

1) Installed Nuget packages:

Microsoft.AspNet.WebApi.Cors
Microsoft.AspNet.Cors

2) In WebApiConfig Register method:

var cors = new EnableCorsAttribute("http://localhost:4200", "*", "*");
// or var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);

3) Alternatively to 2) in Api controller class header:

[EnableCors(origins: "http://localhost:4200", headers: "*", methods: "*")]

But none seems to work, the request always fails with the same error as described above in browser console.

I tried creating a self hosting WebApi listening http calls on http://localhost:9000 as well as my last attempt that was publishing the WebApi in my local Windows 10 IIS server with 9810 port.

If I access the url in browser like so "http://localhost/api/Login" then the string is returned like so:

<ArrayOfstring xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
    <string>Now it works!</string>
</ArrayOfstring>

and no error is displayed in console but as long as I try to make the request by Angular (default port 4200) the request fails with CORS error.

I'm stuck. If I cannot make it to work from Angular I won't be able to do debugging and testing.

Thanks.

Edit 1: Chrome network tab info added.

General:

Request URL: http://localhost:9000/api/Login
Request Method: OPTIONS
Status Code: 405 Method Not Allowed
Remote Address: [::1]:9000
Referrer Policy: no-referrer-when-downgrade

Response Headers:

Allow: GET,POST
Content-Length: 76
Content-Type: application/json; charset=utf-8
Date: Wed, 29 Aug 2018 10:32:36 GMT
Server: Microsoft-HTTPAPI/2.0

Request Headers:

Accept: /
Accept-Encoding: gzip, deflate, br
Accept-Language: es-ES,es;q=0.9
Access-Control-Request-Headers: content-type
Access-Control-Request-Method: POST
Connection: keep-alive
Host: localhost:9000
Origin: http://localhost:4200
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36

2
when you get the request back (look in your browser's network tools), does it contain an Access-Control-Allow-Methods headers? And does the value of that header contain OPTIONS? You might also need, if you're using IIS, to allow that method through IIS and also remove any other handlers which may be capturing OPTIONS requests.ADyson
zone.js:2969 OPTIONS http://localhost:9810/api/Login 405 (Method Not Allowed) should point you in the right location. It's telling you that the OPTIONS request to your server is being rejected somewhere. Usually this is IIS intercepting it and throwing the request out. Under <handlers> you can add <remove name="OPTIONSVerbHandler" /> and that may make it work :)Mardoxx
Hello @Mardoxx and thanks for replying. Do you mean to add this tag in WebApi web.config? Because in my Web.config I alredy have a <remove name="OPTIONSVerbHandler" /> tag.Diego Perez
Thanks for your help @ADyson. I have edited question and added information you requested.Diego Perez
"Allow: GET,POST" is the problem then. You need to make it allow OPTIONS as well.ADyson

2 Answers

6
votes

After struggling my head the whole morning and trying everything each one of you suggested here I cannot believe in the end my problem could have been resolved so easily.

Regarding @Madpop suggestion Application_BeginRequest (for any reason) was never being fired (dind't want to spend much time investigating why).

@Steveland solution involved adding dependency injection and it resulted a little bit complicated to me (I don't have much experience with that) aparte from the fact I'm not using Asp.Net Core but Asp.Net framework 4.6.

I was looking for a simple solution to a problem I thought it should have been easy to solve and the key was appending

[HttpPost]
[HttpOptions] //this was the key
[Authorize]

to Post method header. This was the only way for me to allow "Options" verb in request.

I don't know if this is the best way to accomplish this but for now it works (let me know what d'you think guys).

I appreciate ev'ry help I've received here from everybody and say thanks and as I'm not an expert on this subject (Angular + Web Api) I would like to finally ask the next:

Will I have to put this [HttpOptions] also for production when the api will be deployed to server or this is just needed for now for debugging and testing locally purposes?

Edit 1:

After testing I've noticed it works with self hosting Web Api but as I publish Web Api to my local IIS I get "415 Unsupported Media Type" in browser :(

2
votes

Regarding the cors issue i also faced the similar issue i have created a global.asax file that i have place the below code

protected void Application_BeginRequest()
{

    if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
    {
        //These headers are handling the "pre-flight" OPTIONS call sent by the browser
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "http://staging.example.com:8044");
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Accepts, Content-Type, Origin, X-My-Header");
        HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "60");
        HttpContext.Current.Response.End();
    }

}

it worked for me in angular 6 as well in ionic 3 also and before all these try to install https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi?hl=en

the above chrome plugin and activate it and then try to run the application