Url.Action generates wrong URL when Attribute Routing - c#

Lots of similar questions and yet none quite like this problem:
I'm using attribute routing on an MVC5 project.
When trying to define a simple route like this:
[HttpGet]
[Route("Empresa/Filial/{id:int}/Editar")]
public ActionResult UpdateFilial(int id)
{
...
}
and generate a URL on the view, like this:
EDIT
I end up with something like:
http://localhost:59936/Empresa/Filial/Editar?id=1
which results a 404, since it should be:
"http://localhost:59936/Empresa/Filial/1/Editar"
What am I doing wrong here?
EDIT:
My RouteConfig looks like this:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
//Acionando rotas por atributos (annotations)
routes.MapMvcAttributeRoutes();
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
(the default on MVC5 template on VisualStudio2017)
So, I guess, attribute routing has precedence over convention based routes.

Make sure that attribute routing has been enabled in RouteConfig before convention-based routes
public class RouteConfig {
public static void RegisterRoutes(RouteCollection routes) {
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
//enable attribute routing
routes.MapMvcAttributeRoutes();
//convention-based routes
//...other routes
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}

Related

How to have route Product/a23 instead of Product/Index/a23

I try to serve the MVC request for our Products through the Index action of the ProductController.
public ActionResult Index(string id)
{
return View();
}
And I want to avoid the pattern of "http://oursite.com/Product/Index/a23" (where a23 is the unique id of the product)
Instead I need "http://oursite.com/Product/a23"
My route.config is the default of the VS mvc web-app template, like that:
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 }
);
}
What is the simplest, better way? I would rather not change the default mapRoute, as it works for other endpoints of our web-app, i.e. Order/Placement/18, Inventory/Stats etc. Any solution with adding a mapRoute or routing attributes would be most welcome.

How can I do route configuration in ASP.NET MVC?

How can I do route configuration as below?
My current url is: http://localhost:4815/Home/ByCategory/1
But I want it to be: http://localhost:4815/CategoryTitle
public ActionResult ByCategory(int? id)
{
...
}
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "ByCategory", id = UrlParameter.Optional }
);
You can use Attribute Routing. for doing this at first you must Enable it by
adding below code top of your MapRoute in RouteConfig:
routes.MapMvcAttributeRoutes(); //Enables Attribute Routing
then you can add Attribute Routing at top of your classes and methods:
[Route("CategoryTitle")]
public ActionResult ByCategory(int? id)
{
...
}
for deep dive in Routing, you can follow this link.
good luck.
If you want to parametrize a route with Category Title, you can use Attribute Routing like so
[Route("~/{categoryTitle}")]
public ActionResult ByCategory(string categoryTitle)
...
Thank you for your suggestions. I have added the following code to routeconfig. I used on the view page to go to the relevant controller
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "AddQuestion",
url: "AddQuestion",
defaults: new { controller = "Question", action = "Create" }
);

How to Create URL friendly route and remove index

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);
}
}

"Subreddit" style URL routing in ASP.NET MVC?

Reddit links are normally like this:
https://www.reddit.com/r/<subreddit>/<topic>
meaning that, the subreddit can be anything depending on how the user created it.
Usually on ASP MVC, We can do it like this:
local/controller/action?subreddit=subname&topic=topicname
but what if I want it to be something like this:
local/controller/action/subname/topicname ?
The keyword for this feature is attribute routing in ASP.NET MVC. There is a lot of information availbale in blogs etc.
With the Route-Annotation you can decorate your action and define a mapping between URL parts and parameters for the action call.
public class ExampleController : Controller
{
[Route("r/{subreddit}/{topic}")]
public ActionResult Topic(string subreddit, string topic)
{
//Logic goes here
}
}
Furthermore the attribute routing has to be activted in the RouteConfig.cs with routes.MapMvcAttributeRoutes(); like
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 = "Index", id = UrlParameter.Optional }
);
}
}
Then you can call the Topic-Action of the ExampleController by http://localhost:PORT/r/reddit/topic.

Simple Route to an action in another controller

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)
{
...
}

Categories