I've been trying to change the routing for my website for the past few hours and I just can't find out what ASP.net wants from me!
This is my default routing:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{Id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional, }
);
It successfully brings up Home/Index whenever I go to these URLs:
/
/Home
/Home/Index
However, I have an action called "K" like below which receives a parameter "name":
public ActionResult K(string name)
I want to define a route that will redirect me to /Home/K/{name} with this template:
website.com/K/{name}
I tried this route below but It doesn't work:
routes.MapRoute(
"OnlyK",
"K/{id}",
new { controller = "Home", action = "K", id = UrlParameter.Optional }
);
Also even without this route config, if I go to website.com/Home/K/something It will not recognize "something" as id (controller parameter == null)!
What am I doing wrong?
The url website.com/Home/K/something results in a null value for argument name in the K action method ActionResult K(string name) because the argument names don't match.
This method is being served via the the route Default, which
declares a parameter with name id (via {controller}/{action}/{id}), whereas action method K has an argument named name.
You can solve this by overruling the argument name on the action method, via the BindAttribute so that both match.
ActionResult K([Bind(Prefix ="id")] string name)
To do a redirect from website.com/K/{name} to website.com/Home/K/{name} you can set up a custom IRouteHandler that takes care of this redirect.
Register a route that handles any request that match route K/{id} and redirect these to a route with a wellknown name (here: K).
Because of the argument name mismatch discussed about we'll use {id} instead of {name} in our routes.
routes.Add(new Route("K/{id}", new RedirectRouteHandler("K")));
Define this route K as below.
routes.MapRoute(
name: "K",
url: "Home/K/{id}",
defaults: new { controller = "Home", action = "K", id = UrlParameter.Optional }
);
The RouteHandler and RedirectHandler doing the redirect.
The HttpResponse class has a RedirectToRoute method that can deal with route names and route values, without having to construct urls ourselves.
class RedirectRouteHandler : IRouteHandler
{
private readonly string _routeName;
public RedirectRouteHandler(string routeName)
{
_routeName = routeName;
}
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
return new RedirectHandler(this._routeName, requestContext.RouteData.Values);
}
}
class RedirectHandler : IHttpHandler
{
private readonly string _routeName;
private readonly RouteValueDictionary _routeValues;
public RedirectHandler(string routeName, RouteValueDictionary routeValues)
{
this._routeName = routeName;
this._routeValues = routeValues;
}
public bool IsReusable { return false; }
public void ProcessRequest(HttpContext context)
{
context.Response.RedirectToRoute(this._routeName, this._routeValues);
}
}
Note that the order of the registered routes matters; RegisterRoutes looks like.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.Add(new Route("K/{id}", new RedirectRouteHandler("K")));
routes.MapRoute(
name: "K",
url: "Home/K/{id}",
defaults: new { controller = "Home", action = "K", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Related
I have this in my RouteConfig:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "StoreSearch",
url: "{storeName}",
defaults: new { controller = "Search", action = "Store" }
);
Basically I have a 2nd route so if I type in localhost:9000/facebook there is no such controller by the name of facebook so my 2nd router should pickup facebook as the storeName and hit my Search controller's Store action. But at the moment I get 404.
Any ideas how do I fix this?
If you have specific set of stores or a way to verify them you can add a constraint to the route.
To add a generic constraint with match predicate
public class ServerRouteConstraint : IRouteConstraint
{
private readonly Func<Uri, bool> _predicate;
public ServerRouteConstraint(Func<Uri, bool> predicate)
{
this._predicate = predicate;
}
public bool Match(HttpContextBase httpContext, Route route, string parameterName,
RouteValueDictionary values, RouteDirection routeDirection)
{
return this._predicate(httpContext.Request.Url);
}
}
and then in the route add a paramater
routes.MapRoute(
name: "StoreSearch",
url: "{storeName}",
defaults: new { controller = "Search", action = "Store" }, constraints:
//this could be new { controller ="pattern" }
new {
serverRoute = new ServerRouteConstraint(url =>
{
//this will check that the route starts with a specific string in this case Settings
return url.PathAndQuery.StartsWith("/Settings",
StringComparison.InvariantCultureIgnoreCase);
})
});
For examples check: https://www.c-sharpcorner.com/UploadFile/dacca2/route-constraints-in-mvc/
Also, routes should be added from most specific to most general.
You should place any custom route above the Default route.
Just swap the order and you good to go
//before default route
routes.MapRoute(
name: "StoreSearch",
url: "{storeName}",
defaults: new { controller = "Search", action = "Store" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
I am working with MVC5 where I am unable to put dashes in the URL. What I want is to put a dash between the words.Kindly view my working code.
My Route Config is:
routes.Add(
new Route("{MyApple}/{page}",
new RouteValueDictionary(
new { controller = "MyApple", action = "Index", page = "" }),
new HyphenatedRouteHandler())
);
And My controller is :
public ActionResult Index(string page)
{
if (System.IO.File.Exists(Server.MapPath("/Views/MyApple/" + page + ".cshtml")))
{
string userId = "";
if (Session["AppId"] != null)
userId = Session["AppId"].ToString();
Session["ReturnUrl"] = Url.Action("EmptyTemplate");
IBaseViewModel model = new BaseViewModel();
return View(page, model);
}
}
This is my controller where the parameters go to page.
Example: devpage = aspdotnet then it will render the view = aspdotnet.html
Please help with this edited content.
I want to dash to the URL with lowercases.
Example: Suppose I have perfectsolution.html page then i
localhost/case-study/perfect-solution
(Don't mind my English).Help will be appreciated. Thanks
Note: in the index page, I` am using "perfect solution" to pass to the view but I want in URL, perfect-solution.
I want this type URL /case-studies/san-Diego-veg-festival ,
casestudies is controller and san-diego-veg-festival is parameter.
As per your comments , I made a guess that you are trying to pass parameter value in CaseStudies controller's Index method.
Two types of Routing to choose from, you can choose anyone as required:
1. Convention-based Routing
In Your RouteConfig.cs file make these changes:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "CaseStudiesRoute",
url: "case-studies/{devPage}",
defaults: new { controller = "CaseStudies", action = "Index", devPage = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Controller:
public class CaseStudiesController : Controller
{
public ActionResult Index(string devPage)
{
return View();
}
}
Now using your browser give a GET request to URL , /case-studies/san-Diego-veg-festival , It should work with Convention-based Routing.
2. Attribute Routing
In Your RouteConfig.cs enable Attribute Routing , by adding routes.MapMvcAttributeRoutes(); , Now RouteConfig.cs looks like:
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 = "Index", id = UrlParameter.Optional }
);
}
Controller:
public class CaseStudiesController : Controller
{
[Route("case-studies/{devPage?}")]
public ActionResult Index(string devPage)
{
return View();
}
}
Now using your browser give a GET request to URL , /case-studies/san-Diego-veg-festival , It should work with attribute routing.
References
1.
2.
Try using Routing Attribute functionality
[Route("study/perfect-solution")]
eg:
[Route("study/perfect-solution")]
public ActionResult PerfectSolution()
{
// code here
}
If you want to pass parameters it need to be specified
Eg:
[Route("study/perfect-solution/{parameter}")]
public ActionResult PerfectSolution(string parameter)
{
// code here
}
I want my route to look like:
/product/123
I have an action GET but I don't want that in the URL, it is currently:
/product/get/123
How to get this?
Global.asax.cs
RouteConfig.RegisterRoutes(RouteTable.Routes);
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new[] { "MyApp.Web.Controllers" }
);
}
You can use the Route attribute to define your path like this:
[Route("product")]
public class ProductController {
[Route("{productId}"]
public ActionResult Get(int productId) {
// your code here
}
}
Which provides you the full route definition for "/product/{productId}" which is "/product/123" in your case. More details there: https://blogs.msdn.microsoft.com/webdev/2013/10/17/attribute-routing-in-asp-net-mvc-5/
Add this code in routes.MapRoute before the default route.
routes.MapRoute(
name: "Product",
url: "Product/{id}",
defaults: new { controller = "product", action = "get"}
My url: http:///Home/addorders //Working Fine
Need to hit like this: http:///addorders
I have added my customized route in RouteConfig: But it does not works for me
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 }
);
routes.MapRoute(
"addorders", // Route name
"addorders/{id}/{str}", // URL with parameters
new { controller = "Home", action = "addorders", id = UrlParameter.Optional, str = UrlParameter.Optional },// Parameter defaults
new[] { "AngularJsExample.Controllers" }
);
}
}
MVC5 provides new feature called Attribute Routing. Instead of registering your routes in Routing Config, You can directly specify routing controller level or action level.
For example
RouteConfig.cs
using System.Web.Routing;
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();// New feature
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Home Controller code
[RoutePrefix("Test")]
[Route("{action=Index}")]// Default Route
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
[Route("HelloAbout")] //Test/Users/About
public ActionResult About()
{
ViewBag.Message = "Your application description page.";
return View();
}
[Route("~/NewTest/Contact")] //To override the Route "Test" with "NewTest".... NewTest/Contact
public ActionResult Contact()
{
ViewBag.Message = "Your contact page.";
return View();
}
//[Route("home/{id?}")]
public ActionResult Emp(int id)
{
return View();
}
}
This code will change the controller and action name and also change the routing.
Add the new, more specific route before the default in the file (which determines the order it is added to the route dictionary). This is because routes are evaluated for a match to an incoming URL in order. The default MVC route is pretty general, and if route order is not carefully considered when adding additional routes to your project, the default route may inadvertently match a URL intended for a different handler.
Modified code:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"addorders", // Route name
"addorders/{id}/{str}", // URL with parameters
new { controller = "Home", action = "addorders", id = UrlParameter.Optional, str = UrlParameter.Optional },// Parameter defaults
new[] { "AngularJsExample.Controllers" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
I need do put a new home in new area but im have a error:
Multiple types were found that match the controller named 'Home'. This can happen if the route that services this request ('{controller}/{action}/{id}') does not specify namespaces to search for a controller that matches the request. If this is the case, register this route by calling an overload of the 'MapRoute' method that takes a 'namespaces' parameter.
my new area
Areas/Administrativo/Controllers/HomeController
Areas/Administrativo/Views/Home
my AdministrativoAreaRegistration
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Administrativo_default",
"Administrativo/{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
in Global i have
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }, new[] { "Preparacao.Gerenciar.Web.Controllers" } // Parameter defaults
);
}
You should specify the namespace constraint in your area route registration (check if the namespace is correct):
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Administrativo_default",
"Administrativo/{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new[] { "Preparacao.Gerenciar.Web.Areas.Administrativo.Controllers" }
);
}
the same way you did with your main route registrations:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
new[] { "Preparacao.Gerenciar.Web.Controllers" }
);
}