4

I have exhausted every resource I can find regarding Cors, and I still get the following error message when sending a request from Angular's $http service (via Chrome):

POST http://localhost:61459/api/LoginAuth/PostLoginByHandle 500 (Internal Server Error) 

Get requests work just fine. I have found a hundred variations of similar instructions that seem to work for other people, but I just can't crack this one. I'll post my code.

WebApiConfig:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {

        // Web API configuration and services




        // Web API routes
        config.MapHttpAttributeRoutes();

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

        //var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
        //jsonFormatter.SerializerSettings = new CamelCasePropertyNamesContractResolver();

        var cors = new EnableCorsAttribute("*", "*", "*");
        config.EnableCors(cors);




    }
}

From my understanding, this should be enough to allow any Cors request globally. In addition, I mark the controller with:

[EnableCors(origins: "*", headers: "*", methods: "*")]

I've tried modifying my web.config with various things I've found online, but I've read that it's not necessary when doing it programatically. Any idea what I'm doing wrong?

I've tagged this post as angularjs in case I'm doing something wrong there, as I'm very new to it. Here is my call:

    $http.post("http://localhost:61459/api/LoginAuth/PostLoginByHandle",this.LoginRequest).success(function(data){
  testCtrl.user = data;
  console.log("Retrieved: " + data);
});

**Edit: I am able to hit the controller with Postman when I remove the top method. Any idea why these would conflict? Postman gives this error:

"Message": "An error has occurred.",
"ExceptionMessage": "Multiple actions were found that match the request: \r\nLoginByKey on type RecruitingTool.Web.Controllers.LoginAuthController\r\nPostLoginByHandle on type RecruitingTool.Web.Controllers.LoginAuthController"

Here is the controller code. I don't get why these would conflict:

    [HttpPost]
    public LoginResult LoginByKey(LoginRequest req)
    {
        LoginResult l = new LoginResult();
        if (!string.IsNullOrEmpty(req.Key) &&
            HttpContext.Current.Cache["credentials." + req.Username.ToUpper()].ToString() == req.Key)
        {
            l.Success = true;
        }
        else
        {
            l.Success = false;
            l.ErrorMessage = "The credentials key is not valid.";
        }
        return l;
    }


    [HttpPost]
    [EnableCors(origins: "*", headers: "*", methods: "POST")]
    public LoginResult PostLoginByHandle(LoginRequest req)
    {
        LoginResult l = new LoginResult();
        if (req.Username.ToUpper() == "TESTUSER" && req.Password == "test")
        {
            //change to authenticate against DB
            l.Success = true;
            l.CredentialsKey = Guid.NewGuid().ToString();
            l.ErrorMessage = "";
            HttpContext.Current.Cache["credentials." + req.Username.ToUpper()] = Guid.NewGuid().ToString();
        }
        else
        {
            l.Success = false;
            l.ErrorMessage = "The username or password is not correct. Please check your information and try again.";
        }

        return l;
    }

**Edit 2: The problem was a conflict between the two method's default routes. I'm not sure why that would be the case, but as soon as I specify an explicit route for both of them, it is resolved. I'm still interested to know the answer if anyone knows. Thanks all!

sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
Taylor Hill
  • 1,053
  • 1
  • 14
  • 24

4 Answers4

2

If you put a breakpoint in your Web API POST controller action is it not hitting it? HTTP 500 normally indicates some issue with your code (unhandled exception).

If it's not hitting that controller action it must be earlier in the pipeline. Have you tried just posting directly to your API method from something like POSTman? Very useful extension for Chrome..

Nat Wallbank
  • 1,377
  • 12
  • 12
  • Yep. Try making the request with Postman or Fiddler so cors is out of the picture and see if it works. I agree that the problem is probably somewhere else. – Anthony Chu Oct 25 '14 at 05:52
  • It's not hitting the controller. Would Postman have the same Cors issues? I'm a little fuzzy on what exactly counts as cross-origin. I am running the front end from a WebStorm built-in server which is also Localhost with a different port number. I was surprised to be getting the error in the first place because of that. – Taylor Hill Oct 25 '14 at 05:54
  • I have hit the controller by removing the top method of the edit I just made. I'll mess with the routing, but this collision seems weird to me. – Taylor Hill Oct 25 '14 at 06:02
  • When I specify the route explicitly the problem goes away. Not sure why this is, but if anyone knows the reason, I would be very interested to know. – Taylor Hill Oct 25 '14 at 06:11
2

1- Your method parameters are missing the [FromBody] attribute, so it should be like

public LoginResult PostLoginByHandle([FromBody]LoginRequest req)

2- Also, both methods have the exact same signature, in terms of the number of parameters and the data type of req parameters.

hope that helps.

Omar.Alani
  • 4,050
  • 2
  • 20
  • 31
1

WebAPI supports Convention based routing:

To find the action, Web API looks at the HTTP method, and then looks for an action whose name begins with that HTTP method name. For example, with a GET request, Web API looks for an action that starts with "Get...", such as "GetContact" or "GetAllContacts". This convention applies only to GET, POST, PUT, and DELETE methods. You can enable other HTTP methods by using attributes on your controller. We’ll see an example of that later.

Are you sure you don't have two methods in there, one called PostXXX and one called XXX? Or perhaps the one named POSTxxx is triggering convention-based routing. I've seen mention of "the conventions can result in conflicts in the routing table, matching incorrect actions."

Try renaming your methods to something other than Postxxx, Getxxx, ...

[PS Attribute-routing is much better]

Ian Mercer
  • 38,490
  • 8
  • 97
  • 133
  • The two methods I listed are the only two I have in that controller. Really nothing to them. Perhaps there is a convention based around the Login prefix? I've learned my lesson regard-less--I will be using attributes from now on. – Taylor Hill Oct 25 '14 at 06:19
  • I am able to hit the controller then without attributes. What a weird convention side effect! – Taylor Hill Oct 25 '14 at 06:24
  • Ahhh... your default route doesn't include the action so it's looking for any method that matches. See http://stackoverflow.com/a/21153696/224370 – Ian Mercer Oct 25 '14 at 06:24
  • Fantastic. Mystery solved. Thanks. I'm an MVC developer with only 1 year under my belt in the professional world, so I appreciate the knowledge. – Taylor Hill Oct 25 '14 at 06:27
  • I agree with the earlier post: attribute routing is the way to go. – Nat Wallbank Oct 25 '14 at 06:51
0

I encountered same problem today. As it turns out the problem was in pre-flight OPTIONS request. I used this solution: Handling CORS Preflight requests to ASP.NET MVC actions

Additionally I added headers into response and removed Microsoft.AspNet.WebApi.Cors from project:

protected void Application_BeginRequest()
{
    //CORS
    if (Request.Headers.AllKeys.Contains("Origin"))
    {
        Response.Headers.Add("Access-Control-Allow-Origin", string.IsNullOrWhiteSpace(ConfigurationManager.AppSettings["CORS_ORIGIN"]) ? "*" : ConfigurationManager.AppSettings["CORS_ORIGIN"]);
        Response.Headers.Add("Access-Control-Allow-Methods", "OPTIONS, GET, POST, PUT, DELETE");
        Response.Headers.Add("Access-Control-Allow-Headers", "Access-Control-Allow-Methods, Access-Control-Allow-Origin, Content-Type, Accept, X-Requested-With, Session");
        //handle CORS pre-flight requests
        if (Request.HttpMethod == "OPTIONS")
            Response.Flush();
    }
}
Community
  • 1
  • 1
Pavle Gartner
  • 659
  • 1
  • 7
  • 21