Search code examples
c#asp.net-web-apiasp.net-identityasp.net-web-api-routing

Register action on API gives "No HTTP resource was found that [...]"


First time setting up a Web API, so probably very stupid question. I started my API using no authentication, and then afterwards I've added the OAuth authentication by basically copy-pasting from a standard project.

Now, the challenge I have is that when I try to create an account using Postman, I get:

{
    "Message": "No HTTP resource was found that matches the request URI 'http://api.asanoapp.com/api/Account/Register'.",
    "MessageDetail": "No action was found on the controller 'Account' that matches the request."
}

What I do is I make a POST to the following (screenshot of me calling in Postman: http://prntscr.com/gch0j9 ):

http://api.domain.com/api/Account/Register

With the following Body (raw):

{
  "Email": "mcoroklo@gmail.com",
  "Password": "1234pass",
  "ConfirmPassword": "1234pass"
}

My AccountController which is copied from a standard project, has the following declaration:

[Authorize]
[RoutePrefix("api/Account")]
public class AccountController : ApiController
{
    private const string LocalLoginProvider = "Local";
    private ApplicationUserManager _userManager;

   // 400+ lines of more standard stuff
}

My Register method looks like this:

// POST api/Account/Register
[AllowAnonymous]
[Route("Register")]
public async Task<IHttpActionResult> Register(RegisterBindingModel model)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    var user = new ApplicationUser() { UserName = model.Email, Email = model.Email };

    IdentityResult result = await UserManager.CreateAsync(user, model.Password);

    if (!result.Succeeded)
    {
        return GetErrorResult(result);
    }

    return Ok();
}

Now, I don't understand why I get the "No action was found on the controller", since I both have this method, I call with the correct body (RegisterBindingModel viewmodel from default project).

What am I missing here?

EDIT:

WebApiConfig:

 public static void Register(HttpConfiguration config)
        {
            // Web API configuration and services
            // Configure Web API to use only bearer token authentication.
            config.SuppressDefaultHostAuthentication();
            config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
            // Web API routes
            config.MapHttpAttributeRoutes();

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

            config.Formatters.JsonFormatter.SupportedMediaTypes
                .Add(new MediaTypeHeaderValue("text/html"));

        }

Startup.cs:

[assembly: OwinStartup(typeof(Asano.Websites.Api.Startup))]

namespace Asano.Websites.Api
{
    public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            ConfigureAuth(app);
        }
    }
}

Startup.Auth (where ConfigureAuth is):

 public partial class Startup
    {
        public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }

        public static string PublicClientId { get; private set; }

        // For more information on configuring authentication, please visit https://go.microsoft.com/fwlink/?LinkId=301864
        public void ConfigureAuth(IAppBuilder app)
        {
            // Configure the db context and user manager to use a single instance per request
            app.CreatePerOwinContext(AsanoWebsitesApiContext.Create);
            app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

            // Enable the application to use a cookie to store information for the signed in user
            // and to use a cookie to temporarily store information about a user logging in with a third party login provider
            app.UseCookieAuthentication(new CookieAuthenticationOptions());
            app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

            // Configure the application for OAuth based flow
            PublicClientId = "self";
            OAuthOptions = new OAuthAuthorizationServerOptions
            {
                TokenEndpointPath = new PathString("/Token"),
                Provider = new ApplicationOAuthProvider(PublicClientId),
                AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
                AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
                // In production mode set AllowInsecureHttp = false
                AllowInsecureHttp = true
            };

            // Enable the application to use bearer tokens to authenticate users
            app.UseOAuthBearerTokens(OAuthOptions);

            // Uncomment the following lines to enable logging in with third party login providers
            //app.UseMicrosoftAccountAuthentication(
            //    clientId: "",
            //    clientSecret: "");

            //app.UseTwitterAuthentication(
            //    consumerKey: "",
            //    consumerSecret: "");

            //app.UseFacebookAuthentication(
            //    appId: "",
            //    appSecret: "");

            //app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions()
            //{
            //    ClientId = "",
            //    ClientSecret = ""
            //});
        }
    }

Global.asax.cs - application start:

 public class WebApiApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            GlobalConfiguration.Configure(WebApiConfig.Register);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }
    }

Solution

  • Unfortunately the answers in this post did not help me find a working solution. Therefore I did the following to get it done:

    I added the following attribute on my register method:

    [Route("api/account/register")]
    

    And after adding this, it works. So it seems that the underlying problem is the prefix of the controller does not work.

    However, doing the thing above worked (but is a hack obviously).