Ger Stark Ger Stark - 3 months ago 115
AngularJS Question

WebApi + AngularJS: 405 Method Not Allowed

I'm having a problem and although I've seen plenty of answers to the same topic nothing really worked.. I have a WebAPI project and an MVC one where I have Angular.

From the Angular project, I'm trying to post something like this:

var promise = $http.post("http://localhost:55692/api/users", user)
.success(function (data) {
debugger;
console.log(data);
return data;
});

$http(
{
url: "http://localhost:55692/api/users",
method: "POST",
headers: { 'Content-Type': 'application/json' },
data: { "user": user }
})
.then(function (response) {
debugger;
console.log(data);
return data;
});
return promise;


If you see, I'm calling the same API twice in case it's an Angular thing but to me, it's not..

I have this controller in my API project:

[RoutePrefix("api/users")]
public class ValuesController : ApiController
{
[Route("")]
[HttpPost]
public HttpResponseMessage LoginOrRegister(RegisterUserViewModel user)
{
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, true);
return response;
}
}


This is the response I have:

Response

And this is my WebConfig

<system.webServer>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
<!--<validation validateIntegratedModeConfiguration="false" />-->
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type, Accept, X-Token, X-Acting-As" />
<add name="Access-Control-Allow-Methods" value="GET,POST,PUT,DELETE,OPTIONS,PATCH" />
</customHeaders>
</httpProtocol>
</system.webServer>


EDIT
My WebApiConfig looks like this:

public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Attribute routing enabled
config.MapHttpAttributeRoutes();

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

config.Formatters.JsonFormatter.SerializerSettings.NullValueHandling = NullValueHandling.Include;

// Uncomment the following line of code to enable query support for actions with an IQueryable or IQueryable<T> return type.
// To avoid processing unexpected or malicious queries, use the validation settings on QueryableAttribute to validate incoming queries.
// For more information, visit http://go.microsoft.com/fwlink/?LinkId=279712.
//config.EnableQuerySupport();

// To disable tracing in your application, please comment out or remove the following line of code
// For more information, refer to: http://www.asp.net/web-api
config.EnableSystemDiagnosticsTracing();
}
}


Finally, the only thing "weird" is that I'm using IISExpress as these are the first steps of my project..

Does anyone know what could be happening?

Answer

Well after a lot of struggle, this was it...

    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Attribute routing enabled
            config.MapHttpAttributeRoutes();

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

            config.Formatters.JsonFormatter.SerializerSettings.NullValueHandling = NullValueHandling.Include;
            config.MessageHandlers.Add(new PreflightRequestsHandler()); 
}
    }

And the preflight class:

public class PreflightRequestsHandler : DelegatingHandler
    {
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            if (request.Headers.Contains("Origin") && request.Method.Method.Equals("OPTIONS"))
            {
                var response = new HttpResponseMessage { StatusCode = HttpStatusCode.OK };
                // Define and add values to variables: origins, headers, methods (can be global)               
                response.Headers.Add("Access-Control-Allow-Headers", "accept, content-type");

                var tsc = new TaskCompletionSource<HttpResponseMessage>();
                tsc.SetResult(response);
                return tsc.Task;
            }
            return base.SendAsync(request, cancellationToken);
        }

    }

I hope this helps anyone else!