I have controller: DoomPlaceController
In route: I have used: doom-place/{parameter} // no action
and In controller :
[Route("doom-place/{parameter}")]
public ActionResult Index(string parameter)
{
return View();
}
What I want: when I hit URL: www.xyz.com/doom-place
it should open Doom-Place/index page.
But right now, I am able to access the page with doom-place/index but I want when I hit www.xyz.com/doom-place, it will automatically open index page.
Help will be appreciated.
You can make the parameter optional
[RoutePrefix("doom-place")]
public class DoomPlaceController : Controller {
//Matches GET /doom-place
//Matches GET /doom-place/some_parameter
[HttpGet]
[Route("{parameter?}")]
public ActionResult Index(string parameter) {
return View();
}
}
Given that attribute routing is being used, the assumption is that attribute routing has been enabled in RouteConfig.RegisterRoutes
public static void RegisterRoutes(RouteCollection routes) {
routes.IgnoreRoute(“{resource}.axd/{*pathInfo}”);
//enable attribute routing
routes.MapMvcAttributeRoutes();
//covention-based routes
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Reference Attribute Routing in ASP.NET MVC 5
Related
I know how to create a URL friendly route and i also know how to remove index. But I'm wondering how do I combine the two together?
Using this tutorial https://www.jerriepelser.com/blog/generate-seo-friendly-urls-aspnet-mvc/ I was able to add the following code to allow for url friendly routes.
routes.Add("ProductDetails", new SeoFriendlyRoute("drink/{id}",
new RouteValueDictionary(new { controller = "Drink", action = "Index" }),
new MvcRouteHandler()));
So instead of my url being test.com/index/drink/1 it now becomes test.com/index/drink/coke
The next set of code I have is to remove the index from the url.
routes.MapRoute("DrinkRoute",
"drink/{id}",
new { controller = "Drink", action = "Index" });
This will succesfully convert test.com/index/drink/1 to test.com/drink/1
May I ask how do I combine the two together so that I can have a route that will lead me to the correct controller action and display test.com/drink/coke
RouteConfig
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
You can also achieve the same using attribute routing which would provide more control of the desired routes.
Reference Attribute Routing in ASP.NET MVC 5
First you would need to enable attribute routing by calling routes.MapMvcAttributeRoutes(); in your RouteConfig. Make sure it is registered before convention-based routes.
public class RouteConfig {
public static void RegisterRoutes(RouteCollection routes) {
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
//Attribute routes
routes.MapMvcAttributeRoutes();
//Default convention-based routes
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
With attribute routing enabled you can specify your routes by annotating your actions and controllers.
[RoutePrefix("drink")]
public class DrinkController : Controller {
[HttpGet]
[Route("{name}")] // GET drink/coke
public ActionResult Index(string name) {
//...use name to get model
return View();
}
//..
}
The above DrinkController.Index action is now mapped to GET drink/coke assuming test.com is the host of the controller as shown in your example.
Any controllers or actions not annotated by routing attributes will default back to the convention based routes (if any) registered in the routing table.
This means that you can have a mix of convention-based and attribute-based routes defined for your controllers.
Note however that once you use the attribute routes on a controller that you will have to use it on all its public actions.
If I understand you correctly, you can achieve desired behavior with RouteConfig.cs:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "DrinkRoute",
url: "drink/{id}",
defaults: new { controller = "Drink", action = "Index" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
In that case the url test.com/drink/coke will be hit with the controller DrinkController.cs and the action method Index. Id will be coke. Source code of this controller:
public class DrinkController : Controller
{
public ActionResult Index(string id)
{
return View();
}
}
You can remove the SEO Routes and give your action or controller full control:
public class DrinkssController : Controller
{
[Route("drink/{drinkName}")]
public ActionResult Index(string drinkName)
{
var model = _drinks.First(x => x.name == drinkName);
return View(model);
}
}
I have a view which lists some data. I want to make it sortable. The problem is that with my route configured
routes.MapRoute(
name: "Sort",
url: "Cars/Index/SortBy/{column}",
defaults: new { controller = "Cars", action = "Index", column = UrlParameter.Optional }
);
I am always getting null parameter in my controller class. I try opening /Cars/SortBy/columnname or /Cars/Index/SortBy/columnname it doesn't work. Only /Cars/Index?sortBy=columnname works
public ActionResult Index(string SortBy)
{
switch (SortBy) // SortBy is null
{
case "manufactuer":
return View(db.Cars.OrderBy(c => c.Model.Manufacturer.Name));
break;
case "model":
return View(db.Cars.OrderBy(c => c.Model.Name));
}
return View(db.Cars);
}
How to make it work?
You should change your action method parameter name to column as that is what you used in defining the route.
public ActionResult Index(string column)
{
return View();
}
Then it will work for the url Cars/Index/SortBy/model
If you want it to work for the url Cars/SortBy/model (without the Index), You can use this route definition.
routes.MapRoute(
name: "Sort",
url: "Cars/SortBy/{column}",
defaults: new { controller = "Cars", action = "Index", column = UrlParameter.Optional }
);
// Your other default route definition goes below this
Or if you are using Attribute routing,
[Route("Cars/SortBy/{column}")]
public ActionResult Index(string column)
{
return View();
}
Make sure to enable attribute routing in your RegisterRoutes method for attribute routing to work.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
//Custom and default route definitions goes here
}
i have an MVC .Net C# project. have Plan Action under Home Controller.
but i dont want to access this page as http://....../Home/Plans
but i want to access it as http://....../Plans
but i dont want to create Plans Controller. so i dont want to do a redirectToAction.
i am trying to use the Route Annonation as the following:
[Route("plans/")]
public ActionResult Plans()
[Route("plans/{actions}")]
public ActionResult Plans()
[Route("plans/index")]
public ActionResult Plans()
but none of the above worked for me. can you guys help me in this.
Updated:
this is my action under HomeController
[Route("plans")]
public ActionResult Plans()
{
var servicePlansDto = SubscriberApiManager.SubscriptionSellingService.GetServicePlans(ServiceId).FindAll(sp => !sp.HasPromotionCode);
List<ServicePlanVm> servicePlansVm = Mapper.Map<List<ServicePlanDto>, List<ServicePlanVm>>(servicePlansDto);
return View(servicePlansVm);
}
and this is my configurations
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 }
);
}
First of all remember to configure attribute routing:
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 }
);
}
Then take care that each controller function has to have a different name. In the example they have the same name and this is not accepted by the compiler.
Lat but not least, what's the need of the {actions} parameter in the routing attribute? When you define an attribute routing you don't need to define an action, as you your attribute is already decorating an action / method. You can have required / optional parameters in your routing but they usually correspond to a matching parameter in the method's sugnature:
//Example http://www.domain.com/plans/123
[Route("plans/{productId}")]
public ActionResult Plans(string productId)
{
...
}
How can i do like this url (http://www.domain.com/friendly-content-title) in Asp.Net MVC 4.
Note: This parameter is always dynamic. URL may be different: "friendly-content-title"
I try to Custom Attribute but I dont catch this (friendly-content-title) parameters in ActionResult.
Views:
Home/Index
Home/Video
ActionResult:
// GET: /Home/
public ActionResult Index()
{
return View(Latest);
}
// GET: /Home/Video
public ActionResult Video(string permalink)
{
var title = permalink;
return View();
}
RouteConfig:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Home Page",
url: "{controller}/{action}",
defaults: new { controller = "Home", action = "Index" }
);
routes.MapRoute(
name: "Video Page",
url: "{Home}/{permalink}",
defaults: new { controller = "Home", action = "Video", permalink = "" }
);
}
What should I do for catch to url (/friendly-content-title)?
To enable attribute routing, call MapMvcAttributeRoutes during configuration. Following are the code snipped.
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
}
}
In MVC5, we can combine attribute routing with convention-based routing. Following are the code snipped.
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 }
);
}
It is very easy to make a URI parameter optional by adding a question mark to the route parameter. We can also specify a default value by using the form parameter=value. here is the full article.
Radim Köhler's solution is a good one.
But another option if you want more control over routing is using a custom constraint.
Here's an example
RouteConfig.cs
routes.MapRoute(
"PermaLinkRoute", //name of route
"{*customRoute}", //url - this pretty much catches everything
new {controller = "Home", action = "PermaLink", customRoute = UrlParameter.Optional},
new {customRoute = new PermaLinkRouteConstraint()});
So then on your home controller you could have action like this
HomeController.cs
public ActionResult PermaLink(string customRoute)
{
//customRoute would be /friendly-content-title..do what you want with it
}
The magic of this happens in the IRouteConstraint that we specified as the 4th argument in the MapRoute call.
PermaLinkRouteConstraint.cs
public class PermaLinkRouteConstraint : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values,
RouteDirection routeDirection)
{
var permaRoute = values[parameterName] as string;
if (permaRoute == null)
return false;
if (permaRoute == "friendly-content-title")
return true; //this indicates we should handle this route with our action specified
return false; //false means nope, this isn't a route we should handle
}
}
I just wanted to show a solution like this to show you can basically do anything you want.
Obviously this would need to be tweaked. Also you'd have to be careful not to have database calls or anything slow inside the Match method, as we set that to be called for every single request that comes through to your website (you could move it around to be called in different orders).
I would go with Radim Köhler's solution if it works for you.
What we would need, is some marker keyword. To clearly say that the url should be treated as the dynamic one, with friendly-content-title. I would suggest to use the keyword video, and then this would be the mapping of routes:
routes.MapRoute(
name: "VideoPage",
url: "video/{permalink}",
defaults: new { controller = "Home", action = "Video", permalink = "" }
);
routes.MapRoute(
name: "HomePage",
url: "{controller}/{action}",
defaults: new { controller = "Home", action = "Index" }
);
Now, because VideoPage is declared as the first, all the urls (like these below) will be treated as the dynamic:
// these will be processed by Video action of the Home controller
domain/video/friendly-content-title
domain/video/friendly-content-title2
while any other (controllerName/ActionName) will be processed standard way
So I am trying to do this:
http://localhost:43751/api/doWork/asdfasfsaf
And here is Controller:
public class DoWorkController : ApiController
{
public User GetWork(String input) {
Dictionary<int, Work> users = DataObjects.Work.find(input);
return users.Values.First<Work>();
}
}
I run it and it doesn't work:
No HTTP resource was found that matches the request URI 'http://localhost:43751/api/doWork/asdfasfsaf'.
and
No action was found on the controller 'DoWork' that matches the request.
What am I doing wrong?
Here is my Routing Configuration:
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 seem that all I needed to do to get this to work is this:
public class DoWorkController : ApiController{
public User GetDoWork(String ID) {
Dictionary<int, Work> users = DataObjects.Work.find(input);
return users.Values.First<Work>();
}
}
Because MVC believes you're referring to a different URL. You need to either define a method that is listening to your requests of type HttpGet or HttpPost:
[HttpGet]
public ActionResult doWork(string input) {
// do processing and return the selected user as a model back to the view
User user = YourGetUserMethod(input);
return View(user);
}
so you could invoke it as: /api/doWork?input=asdfasfsaf
Or if what you want is to change your URL routing to accept the last portion of your URL as a parameter, you'd need to add something like this to your RouteConfig.cs file:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "DoWork", action = "doWork", id = UrlParameter.Optional }
);
You might want to follow this post for additional information regarding route mapping