Separate MVC and webAPI controller route - asp.net-mvc

I have created a WebApi project, which has multiple WebApi controllers. As per my requirement I have to add an MVC controller to my WebApi project. My client side code is making an ajax request to that MVC controller with {ControllerName/ActionMethodName}. I have multiple routes in my global.asax file:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
routes.MapHttpRoute(
name: "ActionRoute",
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 }
);
Below is my ReportServiceBaseController:
protected virtual ReportServiceBase CreateReportService();
[HttpPost]
public JsonResult LoadDocumentInfo(LoadDocumentInfoRequest request);
[HttpPost]
public JsonResult LoadDocumentMapInfo(LoadDocumentMapInfoRequest request);
[HttpPost]
public JsonResult LoadDocumentMapInfoFull(LoadDocumentMapInfoFullRequest request);
[HttpPost]
public JsonResult LoadPageInfo(LoadPageInfoRequest request);
I am inheriting that controller in a ReportService controller:
public class ReportServiceController : ReportServiceBaseController
{
protected override PerpetuumSoft.Reporting.WebViewer.Server.ReportServiceBase CreateReportService()
{
return new ServiceClass();
}
}
The client side URL which is making the request:
"http://" + hostName + "/ReportService/LoadDocumentInfo"
I think the WebApi route is suppressing the MVC Controller route. How can I separate the MVC Controller route from the WebApi route?

You can create a new config class of WebApi, ApiRouteConfig.cs, within App_Start.
namespace Mvc4App
{
public class ApiRouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.MapHttpRoute(
name: "ActionRoute",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
}
Then, edit Global.asax.cs, to call ApiRouteConfig.RegisterRoutes(RouteTable.Routes);

Related

MVC.NET Routing

I want to add a new route to my Web Api, which will read various ids and then filter a bunch of books.
So the final url should read something like http://localhost/api/books/1/1/1/1
Now I have added a route to my RouteConfig as follows :-
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "BookFilter",
url: "api/books/{author}/{title}/{genre}/{isbn}",
defaults: new { controller = "Books", action = "BookFilter" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
I also added the following in my BooksController:-
[HttpGet]
public IQueryable<BookDTO> BookFilter(int authorId, int titleId, int genreId, int isbn)
{
//filter books here
return db.Books.ProjectTo<BookDTO>();
}
However when I try to reach the page, I get a 404.
What do I need to do to reach my page?
Thanks for your help and time
Web API and MVC are independent frameworks which each have separate types. The likely reason your route is not working is that you are confusing the two. Specifically, for it to work as you configured, you would need an MVC controller (that is, a controller that inherits System.Web.Mvc.Controller).
So, assuming you want to go with Web API as your question would indicate, you first need to ensure the correct definition of your controller. It should inherit from System.Web.Http.ApiController.
public class BooksController : ApiController
{
[HttpGet]
public IHttpActionResult BookFilter(string author, string title, string genre, string isbn)
{
return Ok("Successful result");
}
}
Next, you need to put your routing in the WebApiConfig.cs file, not in the RouteConfig.cs file. Don't forget to remove your route from the RouteConfig.cs file.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "BookFilter",
routeTemplate: "api/books/{author}/{title}/{genre}/{isbn}",
defaults: new { controller = "Books", action = "BookFilter" });
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
You also need to ensure that the call to GlobalConfiguration.Configure(WebApiConfig.Register); is in your application startup path (by default in Global.asax).
public class MvcApplication : 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);
}
}
Make sure to use the same parameter name in your action (eg. change author to authorId):
Optionally, you can also specify default values for these parameters at your RouteConfig, as follows:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "BookFilter",
url: "api/books/{authorId}/{titleId}/{genreId}/{isbn}",
defaults: new { controller = "Books", action = "BookFilter", authorId= UrlParameter.Optional, titleId = UrlParameter.Optional, genreId = UrlParameter.Optional, isbn = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Controller:
[HttpGet]
public IQueryable<BookDTO> BookFilter(int authorId, int titleId, int genreId, int isbn)
{
//filter books here
return db.Books.ProjectTo<BookDTO>();
}

WebAPI MVC Areas with same controller name

The structure of webapi is as follows:
App
-Area
-MyArea1
- ControllerA (Route('api/myarea1/controllera'))
-MyArea2
- ControllerA (Route('api/myarea2/controllera'))
Problem is that the route api/myarea1/controllera and api/myarea2/controllera are not being resolved. It comes are 404.
I read somewhere we need to implement IHttpControllerSelector but not sure what is the simplest way to implement this. If there is any other way it can be done?
Any idea.
Edit:
RouteConfig.cs
public class RouteConfig
{
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 }
);
}
}
WebApiConfig.cs
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
Edit 2:
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapHttpRoute(
name : "MyArea1_default",
routeTemplate : "MyArea1{controller}/{action}/{id}",
defaults : new { action = "Index", id = UrlParameter.Optional }
);
}
If you want to use controllers with the same name, you need to specify the namespace for each route configuration.
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapHttpRoute(
name : "MyArea1_default",
routeTemplate : "MyArea1{controller}/{action}/{id}",
defaults : new { action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "Your.Controller.Namespace.Here" }
);
}
For your reference:
http://haacked.com/archive/2010/01/12/ambiguous-controller-names.aspx/

404 when calling Web API v2

I have a Web Api controller which returns 404 when I call it.
public class ValuesController : ApiController
{
[HttpGet]
public static string Test()
{
return "Hola!";
}
}
Heres the Route Config
config.Routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
And here's the Route Debugger info.
I get 404 for below requests
http://localhost:8081/api/values/test
http://localhost:8081/api/values/get
Any ideas why its failing?
Your action is defined as a static method. Actions cannot be static.
[HttpGet]
public static string Test()
{
return "Hola!";
}
Make it an instance method and your code will work.
[HttpGet]
public string Test()
{
return "Hola!";
}

MVC 3 Web API Routing Not Working

I'm fighting issues with routing in an MVC 3 Web API. It seems like it should be pretty simple, but I'm not making any headway.
My error is:
<Error>
<Message>The request is invalid.</Message>
<MessageDetail>
The parameters dictionary contains a null entry for parameter 'id' of non-nullable type 'System.Int32' for method 'Boolean NewViolationsPublished(Int32)' in 'BPA.API.Controllers.CacheManagementController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.
</MessageDetail>
</Error>
My RegisterRoutes is such:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapHttpRoute(
name: "NukeAllItemsFromCache",
routeTemplate: "api/CacheManagement/NukeAllItemsFromCache");
routes.MapHttpRoute(
name: "ControllerAndAction",
routeTemplate: "api/{controller}/{action}"
);
routes.MapHttpRoute(
name: "ControllerAndActionAndId",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional, action = "Get" },
constraints: new { id = #"^\d+$" } // Only integers
);
routes.MapHttpRoute(
name: "ControllerAndId",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional },
constraints: new { id = #"^\d+$" } // Only integers
);
}
And my controller is (i took out the code for ease of reading):
public class CacheManagementController : ApiController
{
public CacheManagementController()
[HttpGet]
public bool NewViolationsPublished(int id)
[HttpGet]
public bool IsCached(CachedItemLabels label, int clientId)
[HttpGet]
public void RemoveItemFromCache(int clientId, CachedItemLabels cacheLabel, string test)
[HttpGet]
public string NukeAllItemsFromCache()
}
I get the error when I try to call:
http://localhost/api/CacheManagement/NukeAllItemsFromCache
TIA
Are you sure you're defining your routes in the right place? Web API routes should be configured using System.Web.Http.GlobalConfiguration.Configuration.Routes.MapHttpRoute (normally in a WebApiConfig.cs file in App_Start), as shown on http://www.asp.net/web-api/overview/extensibility/configuring-aspnet-web-api, which is different from the route configuration used by vanilla MVC.
I think you may just be hitting the default Web API route, which is api/{controller}/{id}, with ID optional. The action is determined by the HTTP verb, which in this case is GET, and all of your methods match that by virtue of the [HttpGet].
Edit: example
Global.asax
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
GlobalModifiers.ApplyGlobalConfiguration(this, true);
}
WebApiConfig.cs
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "action-specific",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
I beleave your problem is in this route:
routes.MapHttpRoute(
name: "ControllerAndActionAndId",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional, action = "Get" },
constraints: new { id = #"^\d+$" } // Only integers
);
You specify id as an optional parameter and at the same time constrain it to actually be a non-nullable number. If /api/CacheManagement/NukeAllItemsFromCache is an exception, then add additional route for it, otherwise ease a constraint to something like #"^\d*$" if possible.
You are missing the default action for the route you configured:
routes.MapHttpRoute(
name: "NukeAllItemsFromCache",
routeTemplate: "api/CacheManagement/NukeAllItemsFromCache");
should be
routes.MapHttpRoute(
name: "NukeAllItemsFromCache",
routeTemplate: "api/CacheManagement/NukeAllItemsFromCache",
defaults: new { action = "NukeAllItemsFromCache" }
);
You tried to put parameter id as nullable like:
[HttpGet]
public bool NewViolationsPublished(int? id)
or
[HttpGet]
public bool NewViolationsPublished(Nullable<Int32> id)
Maybe this works...
Double check that your controller extends ApiController rather than Controller
public class CacheManagementController : ApiController
rather than
public class CacheManagementController : Controller

WebApi does not accept post (404 error)

I have a MVC4 web project with WebAPI enabled.
I want to post data to the API controller but the post is not working, I am getting a 404 every time (breakpoint inside the Add method is not hit)....
Here is the code:
public class IncidentSessionLogController : ApiController
{
[HttpPost]
public void Add(MyInputDTO inputData)
{
}
}
I use action based routing:
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "ControllerAndAction",
routeTemplate: "api/{controller}/{action}");
config.Routes.MapHttpRoute(
name: "ControllerAndActionAndId",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional });
}
I use Fiddler to post the data:
http://localhost:42901/api/IncidentSessionLog/Add
My site is hosted in IIS express for development currently, I add the JSON object literal in the request body in Fiddler.
Fixed it, thanks to my collegue !
The MVC routing(which I forgot to post originally), was interfering with the API routing, so I have to add a constraint to the MVC routing :
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Game", action = "Start", id = UrlParameter.Optional },
constraints: new { controller = #"^((?!(api)).)*$" });

Resources