Configure routes for MVC and API in same project - c#

I just merged an existing API project into another existing MVC project. The API controllers have the same name as the MVC controllers but they're in 2 different namespaces (MyApp.Web.MyController and MyApp.API.MyController, respectively).
Now, I don't really know how to configure the routes so that I can access the API controllers :(
I read this post : Mixing Web Api and ASP.Net MVC Pages in One Project and would like the achieve what #Mike Wasson suggested there, but I don't know how to configure the routes.
This is what I currently have in 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 }
);
}
}

It looks like you already have it working, but should you ever wish to use your API controllers in an area, you can enable it simply by adding an additional route.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultAreaApi",
routeTemplate: "api/{area}/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
// Application_Start
GlobalConfiguration.Configure(WebApiConfig.Register);
AreaRegistration.RegisterAllAreas();

Related

Routes and the dreaded 405

I've got a simple web API that registers on one route. At the moment I've got two because only one of them does what I need.
My application only has one controller and one Post method in that Controller. I've registered a single Route which always returns a 405 (method not allowed)
The two routes are configured in the RouteConfig.cs:
routes.MapHttpRoute(
name: "app-events",
routeTemplate: "events",
defaults: new { controller = "Events" },
handler: new GZipToJsonHandler(GlobalConfiguration.Configuration),
constraints: null
);
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
The Controller method is essentially this...
public class EventsController : ApiController
{
public EventsController()
{
_sender = new EventHubSender();
}
public async Task<HttpResponseMessage> Post(HttpRequestMessage requestMessage)
{
// doing fun stuff here…
return new HttpResponseMessage(HttpStatusCode.OK);
}
}
If I only configure the first route and post a request to http://devbox/events I will get a 405. However, if I add the second, default, route, and post to http://devbox/api/events I get back my expected 201.
With both routes configured at the same time, the same pattern, the route explicitly bound to the Controller receives a post request and fails with a 405, but the other URL will work.
I've spent a long time looking around before conceding to ask the question. Most things I read have a lot to do with Webdav and I think I've followed every one of them to fix the issue. I am not very experienced with this stack, so nothing is very obvious to me.
You mentioned RouteConfig File. This is used for configuring the MVC routes not Web API routes.
So it would appear you are configuring the wrong file which would explain why the api/... path works as it is probably mapping to the default configuration in WebApiConfig.Register, which would look like
public static class WebApiConfig {
public static void Register(HttpConfiguration config) {
// Convention-based routing.
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
You would need to update that file with the other desired route
public static class WebApiConfig {
public static void Register(HttpConfiguration config) {
// Convention-based routing.
config.Routes.MapHttpRoute(
name: "app-events",
routeTemplate: "events",
defaults: new { controller = "Events" },
handler: new GZipToJsonHandler(GlobalConfiguration.Configuration),
constraints: null
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
Web API routes are usually registered before MVC routes which explains why it was not working with your original configuration.
You should also adorn the action with the respective Http{Verb} attribute.
In this case HttpPost so that the route table knows how to handle POST requests that match the route template.
[HttpPost]
public async Task<IHttpActionResult> Post() {
var requestMessage = this.Request;
// async doing fun stuff here….
return OK();
}

Make an MVC controller the default in WebAPI project

I have created my first WebAPI project to learn, which had an index.html page in the root of the project. I set that page as Startup. All working fine. But, I want to use an MVC controller to call the View instead.
So I created a new MVC controller in my Controller folder called "DefaultController". In it, there's a method:
public ActionResult Index()
{
return View();
}
I created a View folder, and off that, a Default folder, in which, I created an Index.cshtml file.
When I start the project, it calls my old index.html. So, I changed the startup to be the index.cshtml, which is wrong - know. MVC calls a controller method. So, I'm trying to work out - how do I call the controller method in my DefaultController?
I think I need to change my routes?
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { action = "Index", id = UrlParameter.Optional }
);
}
My plan is to use cshtml pages (instead of html pages) to make use of layouts and allow controllers to initiate the views. Each view will the use an api call back to my WebApi controllers to do the data handling.
Does that seem like a good way to handle my WebAPI/KnockoutJs project?
I just need to know how to get the controller to be the default.
When removing the index.html page, I get the error:
HTTP Error 403.14 - Forbidden The Web server is configured to not list
the contents of this directory.
I think you need to add the controller name to the defaults object as in:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Default", action = "Index", id = UrlParameter.Optional }
);
}
You need to register both WebAPI routes and MVC routes:
All this should be done in Application_Start method in Global.asax.cs file:
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);
}
}
GlobalConfiguration.Configure(WebApiConfig.Register) is used to configure WebApi (and register api related routes)():
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 }
);
}
RouteConfig.RegisterRoutes(RouteTable.Routes); is used to register MVC routes:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Default", action = "Index", id = UrlParameter.Optional }
);
}
You also need verify that the DefaultController that you created is MVC controller (inherits from System.Web.Mvc.Controller) and not WebAPI controller
According to my experience, when you want to call the index.cshtml, in the route config you have to define the controller like this in the RouteConfig.cs:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
The controller supposed to be "Home", and the Action is "Index". But, this maproute is for default one. How about if you want to add another one?
routes.MapRoute(
"Article",
"articles",
new { controller = "News", action = "ArticleList" }
);
You can write freely as shown above where "Articles" is the name of maproute and the "articles" is the url. And it would become like this (http://www.domain.com/articles) if you compile controller News and Action ArticleList. And "..../articles" is something you replace (No need define controller or action) and you don't need to open www.domain.com/News/ArticleList it's enough to go to url www.domain.com/articles and the maproute would be automaticaly route to controller news and action articlelist.
That's only my point of view about how maproute works.
CMIIW :)

c#: Asp.net WebApi default route to index.html

I am trying to create an Asp.net WebApi / Single Page Application. I would like my server to dispense index.html if no route is given. I would like it to use a controller when one is specified in the normal "{controller}/{id}" fashion.
I realized that I can visit my index page by using http://localhost:555/index.html. How do I do the same by visiting http://localhost:555 ?
Just add a route to your WebApiConfig file for index page. Your method should look like this:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Attribute routing
config.MapHttpAttributeRoutes();
// Route to index.html
config.Routes.MapHttpRoute(
name: "Index",
routeTemplate: "{id}.html",
defaults: new {id = "index"});
// Default route
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
The solution was to create an empty DefaultRoute.
// I think this passes control through before trying to use a Controller
routes.MapHttpRoute(
"DefaultRoute", "");
routes.MapHttpRoute(
"DefaultAPI",
"{controller}/{id}",
new { Controller = "Home", Id = RouteParameter.Optional });
Another solution was to prefix my WebApi with 'api', which is not entirely what I wanted, but is a suitable solution. This was shown in Herman Guzman's answer, but is not his answer.
// Default route
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }

MVC site using WebAPI - ignore API routes in MVC Route Config

I'm using WebAPI in my MVC project and I'm facing an issue where the API routes are being handled by MVC routing. I can get around this by changing the order the routes are registered in e.g:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
// Register API routes first
WebApiConfig.Register(GlobalConfiguration.Configuration);
RouteConfig.RegisterRoutes(RouteTable.Routes);
}
But I was wondering if it's possible to do this via the IgnoreRoute() method, I've tried:
routes.IgnoreRoute("api/{controller}/{*folder}");
But I get a 404 back which seems to indicate that the request is still being handled by MVC routing and not WebAPI as before.
Here is my API route:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{folder}",
defaults: new { folder = RouteParameter.Optional }
);
Added MVC route:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Info", action = "Index", id = UrlParameter.Optional }
);
Introduce a custom constraint which says that the Controller name cannot be api.
Here is an example based on the MVC documentation
public class NoApiControllerConstraint : IRouteConstraint
{
public bool Match
(
HttpContextBase httpContext,
Route route,
string parameterName,
RouteValueDictionary values,
RouteDirection routeDirection
)
{
return values["controller"] != "api";
}
}
routes.MapRoute(
"Default",
"{controller}/{action}",
new {controller="Home"},
new {isNotForApi=new NoApiControllerConstraint()}
);

What pattern is being done in the Global.asax.cs file in ASP.NET MVC 4?

I have never come across this pattern of code right here. Would anyone care to explain it to me? (Or is there even a pattern here? Is there a reason why this was done like this? What benefits is this giving?) I'm new at general programming, and this is a very interesting one to me:
Global.asax.cs
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
//...
RouteConfig.RegisterRoutes(RouteTable.Routes);
//...
}
WebApiConfig.cs
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
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 }
);
}
}
You could easily write the code in your sample like this:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configuration.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional });
RouteTable.Routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
RouteTable.Routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new {
controller = "Home",
action = "Index",
id = UrlParameter.Optional });
}
However, as the amount of necessary configuration grows, it makes sense to split it up into several logically related chunks. ASP.NET MVC supports this fairly well, and the default project template is just trying to guide you towards doing so.
This isn't a pattern as much an example of the Single Responsibility Principle (SRP). In Global.asax, we know of the high-level tasks that are required to set things up but we leave the implementation separated.

Categories

Resources