Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

I can not access my ApiController

I am trying to create an Api controller used for logging in, which should be used before using my CustomerController (Api) to access data.

The problem is that I am getting a 404 error when I try to access my Login method on AccountController. I am trying to POST to the AccountController as shown in my screenshot below.

Funny thing is that I am able to access my CustomerController (Api) without any problem by pointing my browser to http://localhost:62655/api/customer/cvr/88888888. Am I missing a convention or something for the POST request?

My WebApi route config is:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.MapHttpAttributeRoutes();

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

And added into my Global.asax:

WebApiConfig.Register(GlobalConfiguration.Configuration);

My AccountController and CustomerController is looking like so (files merged for brevity):

public class AccountController : ApiController
{
    public UserManager<ApplicationUser> UserManager { get; private set; }
    private IAuthenticationManager AuthenticationManager
    {
        get
        {
            return HttpContext.Current.GetOwinContext().Authentication;
        }
    }

    public AccountController(UserManager<ApplicationUser> userManager)
    {
        UserManager = userManager;
    }

    public async Task<HttpResponseMessage> Login([FromBody]LoginApiViewModel model)
    {
        if (!ModelState.IsValid) return Request.CreateResponse(HttpStatusCode.BadRequest, "Username or password is not supplied");

        var user = UserManager.Find(model.Username, model.Password);
        if (user != null && UserManager.IsInRole(user.Id, "Administrator"))
        {
            var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
            AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = true }, identity);

            var response = Request.CreateResponse(HttpStatusCode.OK, "Success");
            return response;
        }

        return Request.CreateResponse(HttpStatusCode.Unauthorized, "Wrong login");
    }
}

[Authorize(Roles = "Administrator")]
public class CustomerController : ApiController
{
    private readonly ICustomerService _customerService;

    public CustomerController(ICustomerService customerService)
    {
        _customerService = customerService;
    }

    [ActionName("cvr")]
    public CustomerApiViewModel GetCustomerById(string id)
    {
       var customer = _customerService.GetByCVR(id);
       if (customer == null) throw new HttpResponseException(HttpStatusCode.NotFound);
       var customerViewModel = Mapper.Map<CustomerApiViewModel>(customer);

       return customerViewModel;
    }
}

enter image description here

The above image returns a 404 error. The program is Fiddler2.

Exception:

[HttpException]: The controller for path '/api/account/login' was not found or does not implement IController.

Based on comments, update - (complete Global.asax and RouteConfig (MVC)

 protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    GlobalConfiguration.Configure(WebApiConfig.Register);
    BundleConfig.RegisterBundles(BundleTable.Bundles);
    AutoMapperWebConfiguration.Configure();

    GlobalConfiguration.Configuration.EnsureInitialized(); 
}

public static void RegisterRoutes(RouteCollection routes)
{
    routes.LowercaseUrls = true;
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
        "DefaultOnlyAction",
        "{action}",
        new { controller = "Home", action = "Index" }
    );

    routes.MapRoute(
        "Default",
        "{controller}/{action}/{id}",
        new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );
}
like image 364
janhartmann Avatar asked Jan 06 '14 18:01

janhartmann


People also ask

What is the difference between ApiController and controller?

They work similarly in Web API, but controllers in Web API derive from the ApiController class instead of Controller class. The first major difference you will notice is that actions on Web API controllers do not return views, they return data. ApiControllers are specialized in returning data.

What is ApiController in .NET core?

ApiController attribute The [ApiController] attribute can be applied to a controller class to enable the following opinionated, API-specific behaviors: Attribute routing requirement. Automatic HTTP 400 responses. Binding source parameter inference. Multipart/form-data request inference.

Can ApiController return view?

You can return one or the other, not both. Frankly, a WebAPI controller returns nothing but data, never a view page. A MVC controller returns view pages.

How do I enable routing in Web API?

The Route attribute can be applied on any controller or action method. In order to use attribute routing with Web API, it must be enabled in WebApiConfig by calling config. MapHttpAttributeRoutes() method.


2 Answers

Change your configuration to like below...here i moved web api routes before MVC routes...this is because Web API routes are more specific than the generic MVC routes..

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    GlobalConfiguration.Configure(WebApiConfig.Register);

    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);

    RouteConfig.RegisterRoutes(RouteTable.Routes);

    BundleConfig.RegisterBundles(BundleTable.Bundles);

    AutoMapperWebConfiguration.Configure();
}
like image 51
Kiran Avatar answered Oct 02 '22 04:10

Kiran


It is because you didn't define whether the action of controller is [HttpGet] or [HttpPost]. In your case your login action should be like this

[HttpPost]
public async Task<HttpResponseMessage> Login([FromBody]LoginApiViewModel model)
{
    if (!ModelState.IsValid) return Request.CreateResponse(HttpStatusCode.BadRequest, "Username or password is not supplied");

    var user = UserManager.Find(model.Username, model.Password);
    if (user != null && UserManager.IsInRole(user.Id, "Administrator"))
    {
        var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
        AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = true }, identity);

        var response = Request.CreateResponse(HttpStatusCode.OK, "Success");
        return response;
    }

    return Request.CreateResponse(HttpStatusCode.Unauthorized, "Wrong login");
}

And also you need to provide [HttpGet] for your CVR action

like image 44
kkocabiyik Avatar answered Oct 02 '22 03:10

kkocabiyik