How to use MVC route in ASP.NET WebAPI project - c#

I have a web API and i want to add a few asp.net pages to manage aspects of the API.
In the WebApiConfig.cs file i have a couple of routes, with the following being used as my catch all route for the API.
config.Routes.MapHttpRoute(name: "CatchAll",routeTemplate: "{controller}/{action}/{id}",defaults: new { id = RouteParameter.Optional });
I want to add a new section that is prefixed by /control to push to the asp.net side of things. To do this i have added the following to RouteConfig.cs
routes.MapRoute(
name: "Default",
url: "control/{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
I have then added a standard controller that i will use to manage things.
public class ManageController : Controller
{
public ActionResult Index()
{
return Content("Works");
}
}
When i visit /control/manage in the browser i get the following error.
No type was found that matches the controller named 'control'
It looks like the route is being completely bypassed or at best, the catch all from the api route is catching it and giving it priority. IS there a way i can make the request catch this route without having to create a separate project?

The order of registration is matter
You need to register
public class RouteConfig {
public static void RegisterRoutes(RouteCollection routes) {
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "DefaultMVC",
url: "control/{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
//..other routes.
}
}
in the RouteConfig.cs before
config.Routes.MapHttpRoute(name: "CatchAll",routeTemplate: "{controller}/{action}/{id}",defaults: new { id = RouteParameter.Optional });
in the WebApiConfig.cs file.
What happens in your case is that the /control/manage url is handled by CatchAll route thus mapping control to a controller and manage to an action
In order to do that register them in Global.asax in the following order:
RouteConfig.RegisterRoutes(RouteTable.Routes);
GlobalConfiguration.Configure(WebApiConfig.Register);

Related

Why does an ASP.NET MVC route have a name?

In an ASP.NET MVC 5 web application, there is a RouteConfig class that registers many routes. In all of the examples I have seen so far, only the "Default" route has a non-empty name. The URL pattern and default route values seem to be sufficient to correctly associate any URL to the controller and action to execute. So, is there any benefit to naming a route? For debugging or logging? Just for self-documenting the code?
For example:
public class RouteConfig
{
public static void RegisterRoutes( RouteCollection routes )
{
routes.IgnoreRoute( "{resource}.axd/{*pathInfo}" );
// Most pages.
routes.MapRoute( name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "home", action = "index", id = UrlParameter.Optional }
// A special page.
// Should the route have a name?
routes.MapRoute( name: "",
url: "special",
defaults: new { controller = "special", action = "index", HttpVerbs = HttpVerbs.Get } );
}
}
The main reason to name a route is so that if you need a link to a route from somewhere in the app, you can reference the name. That way if the actual URL/path changes you don't break everywhere in the code that references that route.

How can I implement routing for an extended routes in the RouteConfig file without creating a route error

I implemented a logout link in an ASP.NET MVC 5 application (C#), and it works perfectly with the current routing of my application:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Login", id = UrlParameter.Optional });
When I log in, I see the logout button and it works seamlessly.
However, I have other areas of the app that are designated for registered users (for which I have not considered the routing), and after going to an area designed for authorized users and I attempt to log out, I get the following path returned when the browser displays an error:
/Managers/Home/LogOff
I have a home controller with an action link of Logoff, but I'm uncertain how to represent my Managers folder (along with others on that level). And I could not find (and really, I have not searched exhaustively) readily available documentation of routing beyond what I implement in my routes.MapRoute file (seen above). I would appreciate it if someone can steer me in the right direction or tell me the correct pattern to use. I can't imagine the issue being anything other than routing. Thanks!
RouteConfig.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
namespace HRCoreUS
{
using System.Web.UI.WebControls;
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Login", id = UrlParameter.Optional });
}
}
}
I see two options for you to define a route that suits you.
Fist one, if you want to log off all users from a specific folder, you can use a route like the following one. The keyword 'allusers' prevents you to have a conflict with your Default route. This also make your route more 'readable'.
config.Routes.MapHttpRoute(
"LogOffAllUserFromFolder",
"{controller}/{action}/allusers/{folder}",
new { controller = "Home", action = "Logoff", folder = RouteParameter.Optional });
This endpoint would then looks like :
/home/logoff/allusers/Managers
Second one, if you want to log off a specific user (for example user with id 124) from a 'Managers' folder, you can try the following route that won't conflict with Default since there are 4 arguments
config.Routes.MapHttpRoute(
"LogOffSpecificUserFromFolder",
"{controller}/{action}/{id}/{folder}",
new { controller = "Home", action = "Logoff", id = RouteParameter.Optional, folder = RouteParameter.Optional },
new { id = #"\d+" });
The endpoint would then looks like
/home/logoff/124/Managers
As you're id is an int I suppose, you can tell it by adding that to your route definition
new { id = #"\d+" }
And as {folder} is a string you don't need any other definition as it is the default type.
If I missunderstand your point, I hope this will gives you tips on how to declare MVC routes.
Take care.
If you want to use Attribute routing inside your Controllers folder Simply create a ManagersController
[RoutePrefix("managers")]
public class ManagerController
Then simply add a [Route("")] attribute on every function inside the controller.
Depending on any URL parameters you need define them in the Route attribute.
[HttpGet, Route("logoff}")]
public HttpResponseMessage LogOff() //route would be Managers/logoff
[HttpGet, Route("{id:int/view-profile}")]
public HttpResponseMessage ViewProfile(int id) //route would be Managers/4/view-profile
[HttpPost, Route("{id:guid/save-profile}")]
public HttpResponseMessage ViewProfile(Guid id) //route would be Managers/405750C8-0B3F-4EF2-A2A2-17A1EFBCDA39/save-profile
More info on attributes -
https://blogs.msdn.microsoft.com/webdev/2013/10/17/attribute-routing-in-asp-net-mvc-5/
or for general catchall maproute in Routeconfig you would want something like this:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { action = "Index", id = UrlParameter.Optional }
);
Make sure this is the last route defined in your RouteConfig.
Then inside a ManagersController.cs create a
public HttpResponseMessage LogOff()
This Route would be localhost.com/managers/logoff
But from how I interpreted your question it seems as if your Authentication logic is tied to a specific controller (Home)? You should have all that logic encapsulated in something like a AuthenticationController which could handle your login / logoff logic. This way its not dependent on anything else and you could have a route like this:
routes.MapRoute(
name: "Authentication",
url: "authentication/{action}",
defaults: new { controller = "Authentication", action = "Index"}
);
with a Login / LogOff Function. These would route to /authentication/login and /authentication/logoff

Not receiving get parameters

I'm using ASP.NET MVC 5
I'm having issues with both routes and parameters.
I have this function in my ControllerBase
[HttpGet]
[Route("~/obtenerAngulos/{Conex_AT}/{Conex_BT}")]
public JsonResult obtenerAngulos(string Conex_AT, string Conex_BT)
{
return Json(
new
{
AT = Conex_AT,
BT = Conex_BT
}
, JsonRequestBehavior.AllowGet);
}
And I start having problems receiving the second parameter Conex_BT the Url.Action() returns this route http://localhost:53645/Base/obtenerAngulos?Conex_AT=Y&Conex_BT=y the problem, is Conex_BT is always null
Then I try to work with route and add the Data Anotation for it [Route("~/obtenerAngulos/{Conex_AT}/{Conex_BT}")] but with Url.Action() I keep getting the same route as before.
Even if I try to write it manually like http://localhost:53645/Base/obtenerAngulos/AA/BB I get
HTTP Error 404.0 - Not Found
I mention both problems because I'm pretty sure they are relationated.
Here is the route configuration
RouteConfig.cs
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 }
);
}
Make sure you have enabled attribute routing on the route collection.
//enable attribute routes
routes.MapMvcAttributeRoutes();
//convention-based routes
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
This now means that the following should match obtenerAngulos/y/x
public class ControllerBase: Controller {
//Matches obtenerAngulos/y/x
[HttpGet]
[Route("~/obtenerAngulos/{Conex_AT}/{Conex_BT}")]
public JsonResult obtenerAngulos(string Conex_AT, string Conex_BT) {
//...
}
}
The tilde (~) on the method attribute is used to override any route prefixes if needed.
Routes are matched in the route table in the same order they are added. In your example you had convention based routes registered before attribute routes. Once a route is matched it no longer looks for other matches.
Reference Attribute Routing in ASP.NET MVC 5

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 :)

Custom Route in ASP.NET MVC

I'm trying to setup a custom route in ASP.NET MVC 4. I want my route accessible via
http://www.mydomain.com/high-school/student/1
In an attempt to setup this route, I've added the following in RouteConfig.cs
routes.MapRoute(
name: "HSStudentProfile",
url: "high-school/student",
defaults: new { controller = "Students", action = "HSStudentProfile" }
);
StudentsController.cs
public class StudentsController : Controller
{
public ActionResult HSStudentProfile()
{
return View("~/Views/Shared/Course/Index.cshtml");
}
}
If I visit the url mentioned above, I get a 403.14 error. If I update the route config to use
routes.MapRoute(
name: "HSStudentProfile",
url: "{controller}/high-school/student",
defaults: new { controller = "Students", action = "HSStudentProfile" }
);
It works, however, I have to change the URL path to
http://www.mydomain.com/Students/high-school/student/1
Is there a way to do this without having to have {controller} in my RouteConfig?

Categories

Resources