locked
{"Message":"The requested resource does not support http method 'POST'."} RRS feed

  • Question

  • User2049305227 posted

    Hi,

    Im trying to develop a controller that allows a user to authenticate via a service call. Using a GET i have no problem, however I have been totally unsuccessful in geting a POST to work.

    IT is a .net 4.5 / Webapi 2.2 based project

    In my WebApiConfig.cs i have my routing setup as below

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web.Http;
    using System.Web.Routing;
    
    namespace DirectBuy
    {
        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, action = "Get" }
                );
    
                config.Routes.MapHttpRoute(
                     name: "robtestApi",
                     routeTemplate: "api/{controller}/{action}/{Name}",
                     defaults: new { Name = RouteParameter.Optional }
                 );
    
                config.Routes.MapHttpRoute(
                     name: "robtest2Api",
                     routeTemplate: "api/{controller}/{action}/{UserName}/{Password}",
                     defaults: new { UserName = RouteParameter.Optional , Password = RouteParameter.Optional}
                 );
               
            }
        }
    }
    

    In my controller is the following code

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Web.Http;
    using System.Web.Security;
    using System.Data;
    using System.Data.SqlClient;
    using System.Configuration;
    
    
    
    
    namespace DirectBuy.Controllers
    {
        public class MembershipController : ApiController
        {
    
            [HttpGet]
            [ActionName("ValidateUser")]
            public IHttpActionResult ValidateUser(string UserName, string Password)
            {
                AuthenticatedUser au = new AuthenticatedUser();
                bool valid = Membership.ValidateUser(UserName, Password);
                if (valid) { 
                    MembershipUser membershipUser = Membership.GetUser(UserName);
                    var memberkey = (((Guid)membershipUser.ProviderUserKey).ToString("B"));
                    au = IsUserExpired(memberkey);
                    au.IsAuthenticated = valid;
                }
                else
                {
                    au.IsAuthenticated = false;
                }
                return Ok(au);
            }
    
            [System.Web.Http.AcceptVerbs("POST")]
            [System.Web.Http.HttpPost]
            [ActionName("validate")]
            public IHttpActionResult ValidateUserP([FromBody()] string UserName, [FromBody()] string Password)
            {
                AuthenticatedUser au = new AuthenticatedUser();
                bool valid = Membership.ValidateUser(UserName, Password);
                if (valid)
                {
                    MembershipUser membershipUser = Membership.GetUser(UserName);
                    var memberkey = (((Guid)membershipUser.ProviderUserKey).ToString("B"));
                    au = IsUserExpired(memberkey);
                    au.IsAuthenticated = valid;
                }
                else
                {
                    au.IsAuthenticated = false;
                }
                return Ok(au);
            }
    }
    }

    ValidateUser works perfectly ValidateUserP(validate) method always throws the post error. Any clues as to what to look for or what to change appreciated!

    Rob

    Wednesday, April 11, 2018 6:34 PM

Answers

  • User475983607 posted

    Create Model

        public class LoginViewModel
        {
            public string UserName { get; set; }
            public string Password { get; set; }
        }

    Update the controller

        [RoutePrefix("api/Membership")]
        public class MembershipController : ApiController
        {
            // GET: /api/Membership/validate?UserName=hello&Password=World
            [HttpGet]
            [Route("validate")]
            public IHttpActionResult ValidateUser(string UserName, string Password)
            {
                return Ok(UserName);
            }
    
            // POST: api/Membership/validate
            [HttpPost]
            [Route("validate")]
            public IHttpActionResult ValidateUserP(LoginViewModel vm)
            {
                return Ok(vm);
            }
    
        }

    The Html form should be find here is mine just in case.

    <div>
        <form id="form2" action="http://localhost:52803/api/Membership/validate" method="post">
            <div>
                <input name="UserName" value="Hello" />UserName<br />
                <input name="Password" value="World" />Password<br />
                <input type="submit" value="Submit" /><br />
            </div>
        </form>
    </div>

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, April 11, 2018 8:48 PM

All replies

  • User475983607 posted

    I imagine you need to through the routing docs.  The error is related to the URL used in the HTTP post but you did not provide this most important bit of information.  

    https://docs.microsoft.com/en-us/aspnet/web-api/overview/web-api-routing-and-actions/

    These routes are not needed and having a password parameter is not a good idea.

                config.Routes.MapHttpRoute(
                     name: "robtestApi",
                     routeTemplate: "api/{controller}/{action}/{Name}",
                     defaults: new { Name = RouteParameter.Optional }
                 );
    
                config.Routes.MapHttpRoute(
                     name: "robtest2Api",
                     routeTemplate: "api/{controller}/{action}/{UserName}/{Password}",
                     defaults: new { UserName = RouteParameter.Optional , Password = RouteParameter.Optional}
                 );

    Usually Web API controllers look similar to this...

    namespace DirectBuy.Controllers
    {
        public class AuthenticateController : ApiController
        {
    
            [HttpGet]
            public IHttpActionResult Get(string UserName, string Password)
            {
                AuthenticatedUser au = new AuthenticatedUser();
                bool valid = Membership.ValidateUser(UserName, Password);
                if (valid) { 
                    MembershipUser membershipUser = Membership.GetUser(UserName);
                    var memberkey = (((Guid)membershipUser.ProviderUserKey).ToString("B"));
                    au = IsUserExpired(memberkey);
                    au.IsAuthenticated = valid;
                }
                else
                {
                    au.IsAuthenticated = false;
                }
                return Ok(au);
            }
    
    
            [HttpPost]
            public IHttpActionResult Post(string UserName, string Password)
            {
                AuthenticatedUser au = new AuthenticatedUser();
                bool valid = Membership.ValidateUser(UserName, Password);
                if (valid)
                {
                    MembershipUser membershipUser = Membership.GetUser(UserName);
                    var memberkey = (((Guid)membershipUser.ProviderUserKey).ToString("B"));
                    au = IsUserExpired(memberkey);
                    au.IsAuthenticated = valid;
                }
                else
                {
                    au.IsAuthenticated = false;
                }
                return Ok(au);
            }
        }
    }

    The base URL is /api/Authenticate where an HTTP Get goes to the Get action and an HTTP Post goes to the Post aciton.  

    You can certainly have expressive names if you like though.

    See the following tutorial(s).

    https://docs.microsoft.com/en-us/aspnet/web-api/overview/getting-started-with-aspnet-web-api/tutorial-your-first-web-api

    Lastly, consider going with Identity as the ASP Membership provider is pretty old.

    Wednesday, April 11, 2018 7:08 PM
  • User2049305227 posted

    Sorry this is how i was submitting the post

    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
    
    <!DOCTYPE html>
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form2" action="https://SOMEKEY.ngrok.io/api/membership/validate/" method="post"> 
        <div>
            <input name="UserName" />UserName<br />
            <input name="Password" />Password<br />
            <input type="submit" value="Submit" /><br/>
        </div>
        </form>
    </body>
    </html>
            

    Wednesday, April 11, 2018 7:18 PM
  • User475983607 posted

    Create Model

        public class LoginViewModel
        {
            public string UserName { get; set; }
            public string Password { get; set; }
        }

    Update the controller

        [RoutePrefix("api/Membership")]
        public class MembershipController : ApiController
        {
            // GET: /api/Membership/validate?UserName=hello&Password=World
            [HttpGet]
            [Route("validate")]
            public IHttpActionResult ValidateUser(string UserName, string Password)
            {
                return Ok(UserName);
            }
    
            // POST: api/Membership/validate
            [HttpPost]
            [Route("validate")]
            public IHttpActionResult ValidateUserP(LoginViewModel vm)
            {
                return Ok(vm);
            }
    
        }

    The Html form should be find here is mine just in case.

    <div>
        <form id="form2" action="http://localhost:52803/api/Membership/validate" method="post">
            <div>
                <input name="UserName" value="Hello" />UserName<br />
                <input name="Password" value="World" />Password<br />
                <input type="submit" value="Submit" /><br />
            </div>
        </form>
    </div>

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, April 11, 2018 8:48 PM
  • User2049305227 posted

    Thank you very much.. I think your response has helped me with a number of issues. Setting up routing at the controller and passing variables via the post.. (I had read that api didn't like simple types, but this really drives the message home. I'm also a little surprised that the [FromBody()] wasn't needed.. I had seen a number of posts that almost indicated that that in itself was the solution.

    Again, thank you sooo much for your help on this one!

    Thursday, April 12, 2018 1:18 PM
  • User475983607 posted

    I had read that api didn't like simple types, but this really drives the message home.

    Simple types are usually querystring or URL parameters.

    I'm also a little surprised that the [FromBody()] wasn't needed.. I had seen a number of posts that almost indicated that that in itself was the solution.

    In HTTP a POST means the message content is in the HTTP message body as opposed to querystring or URL.  There is no need to add [FromBody] as the examples does not pass data in the URL.  Use the parameter binding attributes when there is a mixture of, querystring, URL, and POST parameters.

    https://docs.microsoft.com/en-us/aspnet/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api

    Thursday, April 12, 2018 2:03 PM