Why isn't my ASP.NET API route being called, is my URL not correct? - asp.net

I have a new ASP.NET MVC 5 application.
I added an /api folder in my controllers folder and added a MVC2 API controller.
My global.asax has:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
GlobalConfiguration.Configure(WebApiConfig.Register);
}
My controller looks like:
public class UsersController : ApiController
{
[HttpGet]
[ActionName("User")]
public IToken GetUser()
{
return new User();
}
}
Now I get a 404 resource cannot be found error when I go to:
http://localhost:53323/api/users/user
http://localhost:53323/api/users/getuser
What could the problem be?
Update
My MVC route config:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
My API route config:
config.MapHttpAttributeRoutes();
//config.Routes.MapHttpRoute(
// name: "DefaultApi",
// routeTemplate: "api/{controller}/{id}",
// defaults: new { id = RouteParameter.Optional }
//);
config.Routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);

Seems like you are missing correct registration in your Application_Start().
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration); // This should be above the default route registration.
RouteConfig.RegisterRoutes(RouteTable.Routes);
//GlobalConfiguration.Configure(WebApiConfig.Register); // Remove this line.
}

Try using attribute routing on your controller and action methods.
Example
[RoutePrefix("api/users")]
public class UsersController : ApiController
{
[HttpGet]
[Route("user")]
public IToken GetUser()
{
return new User();
}
}

Related

Disable Session state per-request in ASP.Net Web Api (ApiController)

I have ApiControllers that access the session and by default has SessionState required. Therefore I am getting the requests serialized and would like to disable session state for specific requests.
In this post I have seen a solution for normal Controllers but I have no idea how to do it on ApiControllers.
This is my WebApiConfig
public static void Register(HttpConfiguration config)
{
RouteTable.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
).RouteHandler = new SessionRouteHandler();
config.Routes.MapHttpRoute(
name: "Default2",
routeTemplate: "api/{controller}"
);
}
And this is the SessionControllerHandler
public class SessionControllerHandler : HttpControllerHandler, IRequiresSessionState
{
public SessionControllerHandler(RouteData routeData)
: base(routeData)
{ }
}
public class SessionRouteHandler : IRouteHandler
{
IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext)
{
return new SessionControllerHandler(requestContext.RouteData);
}
}
Any help will be appreciated. Thank you
In order to not get the requests serialized, generate a new SessionControllerHandler for SessionState in ReadOnly mode
public class SessionControllerHandlerReadOnly : HttpControllerHandler, IReadOnlySessionState
{
public SessionControllerHandlerReadOnly(RouteData routeData)
: base(routeData)
{ }
}
public class SessionRouteHandlerReadOnly : IRouteHandler
{
IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext)
{
return new SessionControllerHandlerReadOnly(requestContext.RouteData);
}
}
Then in the WebApiConfig add a new route that uses that handler
RouteTable.Routes.MapHttpRoute(
name: "DefaultApiReadOnly",
routeTemplate: "apireadonly/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
).RouteHandler = new SessionRouteHandlerReadOnly();
Done, when you need a specific request going through that handler you specify it in the RouteUrl when making the request
#Url.RouteUrl("DefaultApiReadOnly", new { httproute = true, controller = "controller", action = "action" })

add web api route to exists web site cannot modify global asax

I have a web api project and i can run it locally, but when i publish dll´s to bin folder in the web site, is not taking the route config. I.ve been unable to modify or replace the global asax becasue it has its own implementation. where is the best place to set mi web api route config, how can i do it with an httpmodule?
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
}
}
UPDATE:
i added a httpmodule, and is not mapping the route, is sending http 404:
public void Init(HttpApplication context) {
try
{
AreaRegistration.RegisterAllAreas();
var routes = RouteTable.Routes;
// Controllers with Actions
// To handle routes like '/api/controller/route'
routes.MapHttpRoute(
name: "ControllerActionAndId",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional },
constraints: new { id = #"^\d+$" }
);
// Controllers with Actions
// To handle routes like '/api/controller/route'
routes.MapHttpRoute(
name: "ControllerAndAction",
routeTemplate: "api/{controller}/{action}"
);
// Controller with ID
// To handle routes like '/api/controller/1'
routes.MapHttpRoute(
name: "ControllerAndId",
routeTemplate: "api/{controller}/{id}",
defaults: null,
constraints: new { id = #"^\d+$" } // Only integers
);
// Controller Only
// To handle routes like '/api/controller'
routes.MapHttpRoute(
name: "ControllerOnly",
routeTemplate: "api/{controller}"
);
}
catch { }
}
can you change the webconfig if you can't change the global assax?
with a httpmodule you would get somthing like
<system.webserver>
<modules>
<add name="WebApiStartModule" type="myproject.WebApiStartModule, assembly"/>
</modules>
<system.webserver>
public class WebApiStartModule : IHttpModule
{
public void Init(HttpApplicationContext) {
var routes = RouteTable.Routes
routes.Clear()
//initialize routing here
}
}

How should I handle MVC and WebAPI routing for a SPA with one index.cshtml page?

I have a single page application that has one MVC file index.cshtml which
is served by the Home controller and Index method. All the logon, logoff
and data requests are served by WebAPI. Can someone confirm if I am setting up
my routing correctly. Here is what I have:
RouteConfig.cs
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.IgnoreRoute("{*favicon}", new { favicon = #"(.*/)?favicon.ico(/.*)?" });
routes.MapRoute("DefaultRedirect",
"",
new { controller = "Home", action = "Index" }
);
routes.MapRoute(
"catchall",
url: "{*url}",
defaults: new { controller = "Home", action = "Index" });
}
WebApiConfig.cs
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: ApiControllerOnly,
routeTemplate: "api/{controller}"
);
config.Routes.MapHttpRoute(
name: ApiControllerAndId,
routeTemplate: "api/{controller}/{id}",
defaults: null, //defaults: new { id = RouteParameter.Optional } //,
constraints: new { id = #"^\d+$" } // id must be all digits
);
config.Routes.MapHttpRoute(
name: ApiControllerAction,
routeTemplate: "api/{controller}/{action}"
);
config.Routes.MapHttpRoute(
name: ApiControllerActionAndId,
routeTemplate: "api/{controller}/{action}/{id}",
defaults: null, //defaults: new { id = RouteParameter.Optional } //,
constraints: new { id = #"^\d+$" }
);
}
Global.asax
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
WebApiConfig.CustomizeConfig(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
What I am not sure of is the first file that handles MVC routes. Do I need to have
just one route that makes everything go to Home Controller and Index method.
Also should I in the MVC routing ignore those requests that start with api ?
You should not serve your SPA page as index.cshtml (because that means that it is being compiled to the respective class on the server that will serve the response)
It should be served as index.html and all data that it requires should be fetched by AJAX calls to the server.

ASP.Net Web Api routing issue with ActionName

I am working with an ASP.Net Web Api project on Web Developer Express 2010. The routing config is defined in WebApiConfig.cs as:
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApi3",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { action = RouteParameter.Optional,
id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApi4",
routeTemplate: "api/{controller}/{action}",
defaults: new { action = RouteParameter.Optional }
);
}
An API Controller called "GCURObservationController" has an action as:
[HttpGet, ActionName("retrieveCuringMaps")]
public IList<SimpleCuringMapsModel> retrieveCuringMaps()
{
... ...
return jsonCuringMapModels;
}
The project was compiled and run successfully. However, I had to go to
http://localhost:2061/api/GCURObservation/retrieveCuringMaps/0
to get the action triggered (action name followed by any integer), rather than what I expected to be
http://localhost:2061/api/GCURObservation/retrieveCuringMaps
That means an arbitrary integer had to follow the action name to get it right. Otherwise, the error was returned. I don't want this action to be triggered with any param.
{"Message":"The request is invalid."}
How to get the second URL to work? Thanks
Cheers,
Alex
If you are using Web API 2, following is one solution you could use. In the below example, I am using attribute routing and conventional routing together in one controller. Here all the actions except GetCustomerOrders are reached via conventional route "DefaultApi".
In general the idea here is not new, that is...even without Web API 2's attribute routing, you could define routes for each individual action of a controller in the global route table, but attribute routing makes this process easier as you can define routes directly and near to the action.
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
[RoutePrefix("api/customers")]
public class CustomersController : ApiController
{
public IEnumerable<Customer> GetAll()
{
}
public Customer GetSingle(int id)
{
}
public void Post(Customer customer)
{
}
public void Put(int id, Customer updatedCustomer)
{
}
public void Delete(int id)
{
}
[Route("{id}/orders")]
public IEnumerable<Order> GetCustomerOrders(int id)
{
}
}

Multiple IQueryable in one controller?

I have a controller for my entire database, the code is below:
public class YogaController : DbDataController<Yoga.Models.YOGAEntities>
{
public YogaController()
{
}
public IQueryable<Yoga.Models.Action> GetActions(int BugId)
//GetActions retrieves "actions" table from the db, not Actions in MVC term
{
return DbContext.Actions.Where(x => x.FK_BugsID == BugId);
}
public IQueryable<Yoga.Models.Label> GetRequiredLabels()
{
return DbContext.Labels.Where(x => x.IsRequired == true);
}
public IQueryable<Yoga.Models.Role> GetRoles()
{
return DbContext.Roles;
}
public IQueryable<Role> GetRoles2() //TODO: finish this
{
return DbContext.Roles.Where(x => x.RoleID == 1);
}
public IQueryable<Tag> GetTags(int actionid)
{
return DbContext.Tags.Where(x => x.J_Tags.Any(y => y.FK_ActionID == actionid));
}
}
As you can see I have multiple IQueryable in one controller, each querying a different table. Is it something that's forbidden? Because when I go to localhost/api/Yoga/GetActions or localhost/api/Yoga/GetRequiredLabels I get the error message:
Multiple actions were found that match the request:
System.Linq.IQueryable`1[Yoga.Models.Label] GetRequiredLabels() on type Yoga.Controllers.YogaController
System.Linq.IQueryable`1[Yoga.Models.Role] GetRoles() on type Yoga.Controllers.YogaController
System.Linq.IQueryable`1[Yoga.Models.Role] GetRoles2() on type Yoga.Controllers.YogaController
When I disable all but one IQueryable, the results came out fine.
I have googled for similar issues and checked my routing settings, there are no conflicts in controller path and names.
My Routes (default generated):
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
//routes.MapRoute(
// name: "Default",
// url: "{controller}/{action}/{id}",
// defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Any ideas?
MVC4 is probably matching your HTTP Verb (Get) against all methods with names starting with 'Get' and no parameters. Try forcing the action name:
[ActionName("GetRequiredLabels")]
public IQueryable<Yoga.Models.Label> GetRequiredLabels()
...
[ActionName("GetActions")]
public IQueryable<Yoga.Models.Action> GetActions(int BugId)
... // etc
EDIT:
Based on the routes you pasted and your controller, I think your routes should be:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
i.e. it should have the {action} in there. The default MVC4 route would work if you only had a single 'Get' method. Since you have multiple, you'll have to force it to pick the action based on the route.

Resources