Why does #Html.ActionLink not use RouteData - asp.net-mvc

I have the simplest setup:
An empty asp.net MVC application with one controller:
public class HomeController : Controller
{
public ActionResult Edit(int id)
{
return View();
}
public ActionResult Commit(int id)
{
return View();
}
}
My Edit.cshtml has a call to ActionLink() like so:
#Html.ActionLink("Commit Data", "Commit")
If I now access the Edit-Action through "/Home/Edit/2" I would expect that the rendered link directs the user to "/Home/Commit/2".
It does not :( ... The link is created to "Home/Commit", completely disregarding the current RouteData entries.
I am using the default routing configuration (have not added any routes).
One way to fix this would be to add an explicit route for both actions:
routes.MapRoute(
name: null,
url: "Home/Edit/{id}",
defaults: new { controller = "Home", action = "Edit" }
);
routes.MapRoute(
name: null,
url: "Home/Commit/{id}",
defaults: new { controller = "Home", action = "Commit" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
This works - but I really dont want to explicitly define every single route in the app - if I am using the "default" pattern...
The second solution would be to just add the routing-values manually like so:
#Html.ActionLink("Commit Data", "Commit", "Home", new {id = Model.Id})
But this also seems not right - ActionLink SHOULD use the current routing information, should it not?
What am I missing?

Ok, in case someone else is wondering the same thing - or just wants to have a solution that works...
I simply created my own #ActionLink() helper method on my custom ViewPage base class:
protected MvcHtmlString ActionLink(string linkText, string actionName)
{
var routeData = ViewContext.RequestContext.RouteData;
var id = routeData.Values["id"];
if (id != null)
return Html.ActionLink(linkText, actionName, new {id = id});
return Html.ActionLink(linkText, actionName);
}
This is exactly what I wanted. Now I can call
#ActionLink("Commit", "Commit")
and when I'm in the context of something with an id, the link will point to the appropriate route for this Id.

Related

MVC - Passing path to action in controller

Fairly new to MVC, I would like the URLs of my article pages to be like this:-
http://www.example.com/article1
http://www.example.com/article2
http://www.example.com/article3
How can I set up the routing such that whenever someone types in the above it calls an action called article in the controller and passes the path to it?
I tried something like this but to no avail: -
routes.MapRoute(
name: "article",
url: "{article}",
defaults: new { controller = "Home", action = "article" }
);
One solution is to add multiple routes.
routes.MapRoute(
name: "article1",
url: "article1",
defaults: new { controller = "<YourControllerName>", action = "article1" }
);
routes.MapRoute(
name: "article2",
url: "article2",
defaults: new { controller = "<YourControllerName>", action = "article2" }
);
Edit:
From OP's comment, it is understood that there would be 'n' number of articles(urls). To deal with that, we can create a custom route handler.
Step 1: Create a new custom route handler inheriting from MvcRouteHandler
public class CustomRouteHandler : MvcRouteHandler
{
protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
{
var controller = requestContext.RouteData.Values["controller"].ToString();
requestContext.RouteData.Values["controller"] = "Home";
requestContext.RouteData.Values["action"] = "Index";
requestContext.RouteData.Values["articleId"] = controller;
return base.GetHttpHandler(requestContext);
}
}
Step 2: Register the new route. Make sure to add this route before default route.
routes.Add("Article", new Route("{controller}", new CustomRouteHandler()));
In the given CustomRouteHandler class, the Controller and Action is hard coded with "Home" and "Index" respectively. You can change that to your own controller and action name. Also you would see a "articleId" setting to RouteData.Values. With that setting, you would get the articleId as a parameter in your Action method.
public ActionResult Index(string articleId)
{
return View();
}
After all the changes, for the url http://www.example.com/article1, the Index() method of HomeController gets invoked with articleId set to 'article1'.
Similarly for http://www.example.com/article2, the Index() method gets invoked with parameter articleId set to 'article2'.

Route issue with subfolder in Controllers

we have decided to use subfolders in our Controllers folder. All our controllers are working like they should, but for one reason or another it doesn't get in the Controller method when we add an {id}
Route:
routes.MapRoute(
name: "Maintenance",
url: "Maintenance/{controller}/{action}/{id}",
defaults: new { controller = "TargetAudience", action = "Index", id = UrlParameter.Optional },
namespaces: new string[] { "IstPhenix.Controllers.Maintenance" }
);
This matches URLs like
/Maintenance/Category/Index
but whenever we add the {id} like /Maintenance/Category/Edit/123456789 the Controller method cannot be found
CategoryController.cs:
[ClaimsAuthorize(PhenixPermissions = "ConsultCategory")]
public ActionResult Edit(int id)
{
ViewBag.CategoryId = id;
return View("~/Views/Maintenance/Category/Edit.cshtml", id);
}
[ClaimsAuthorize(PhenixPermissions = "ConsultCategory")]
public ActionResult Index()
{
return View("~/Views/Maintenance/Category/Index.cshtml");
}
Usefull to mention is that we also have a default route at the end of our RouteConfig:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new string[] { "IstPhenix.Controllers.Enduser", "IstPhenix.Controllers.Maintenance", "IstPhenix.Controllers.Security" }
);
And then following URLs work when we omit the subfolder:
/Category/Index
/Category/Edit/123456789
Any idea why the URL does not match the route when i have a subfolder and an id?
What am i missing?
tnx!
What if you added a Route attribute:
[Route("Maintenance/Category/Edit/{id}")]
[ClaimsAuthorize(PhenixPermissions = "ConsultCategory")]
public ActionResult Edit(int id)
{
ViewBag.CategoryId = id;
return View("~/Views/Maintenance/Category/Edit.cshtml", id);
}
That would explicitly give the route to the action.

MVC Routes with/without actions and with/without id

I have an asp.net MVC site and i would like to go to a controller without an action, but i would also like to be able to give an action on the same or other controllers.
So lets say i have Page.
I would like to be able to access the following urls
MY_URL (nothing else) - This would get another page with id = 1, or name = Home (business logic doesnt matter)
MY_URL/Page/id - This will get a page with a particular Id
MY_URL/Page/Create - Create a new page
MY_URL/Page/Delete - Delete a page
MY_URL/Page/Edit - Edit a page
I thought this would do it, but Create/Delete/Edit dont work (they just go to MY_URL/page with no id)
routes.MapRoute(
name: "PageWithId",
url: "Page/{id}",
defaults: new { controller = "Page", action = "Index" }
);
routes.MapRoute(
name: "default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Page", action = "Index", id = UrlParameter.Optional }
);
Here is my controller
public class PageController : Controller
{
private PageService _service;
public PageController(PageService service)
{
_service = service;
}
public async Task<ActionResult> Index(int? id)
{
... code to get page if id <> null
... code to get home page id id = null
// return view
return View(model);
}
public ActionResult Create()
{
return View();
}
... Delete, Edit methods implemented
}
Any help would be appreciated

Asp.Net MVC 4 routing and link generation

In ASP.NET MVC 4 I wonder about the behavior, how links are generated for me.
Imagine a simple controller with 3 actions, each taking an integer parameter "requestId", for example:
public class HomeController : Controller
{
public ActionResult Index(int requestId)
{
return View();
}
public ActionResult About(int requestId)
{
return View();
}
public ActionResult Contact(int requestId)
{
return View();
}
}
and this registered route (before the default route):
routes.MapRoute(
name: "Testroute",
url: "home/{action}/{requestId}",
defaults: new { controller = "Home", action = "Index" }
);
I call my index-view using http://localhost:123/home/index/8
On this view, I render links for the other two actions:
#Html.ActionLink("LinkText1", "About")
#Html.ActionLink("LinkText2", "Contact")
Now I expect MVC to render this links including the current route-value for "requestId", like this:
http://localhost:123/home/about/8
http://localhost:123/home/contact/8
But i get these links (without the paramter):
http://localhost:123/home/about
http://localhost:123/home/contact
...but not for the index-action if i would specify one:
#Html.ActionLink("LinkText3", "Index")
What I want to avoid is to explicitly specify the parameters in this manner:
#Html.ActionLink("LinkText1", "Contact", new { requestId = ViewContext.RouteData.Values["requestId"] })
When I move the requestId parameter before the action paramter it works like I expect it, but I don't want to move it:
routes.MapRoute(
name: "Testroute",
url: "home/{requestId}/{action}",
defaults: new { controller = "Home", action = "Index" }
);
Can someone explain me this behavior? How can I get this to work without specifying the parameter explicitly?
InController:
Replace the int to nullable int
For Routing:
set requestId as optional in routing
routes.MapRoute(
name: "Testroute",
url: "home/{action}/{requestId}",
defaults: new { controller = "Home", action = "Index" ,requestId=RouteParameter.Optional }
);

Parameter not being passed to Controller's action in ASP.NET MVC

I have two actions in a controller and yet the parameters are not being passed into one of them.
This one: /RouteStop/List/1
And this one: /RouteStop/Details/100
And my global.asax:
routes.MapRoute(
"List",
"{controller}/{action}/{id}",
new { controller = "RouteStop", action = "List", id = UrlParameter.Optional }
);
routes.MapRoute(
"Details",
"{controller}/{action}/{routeID}",
new { controller = "RouteStop", action = "Details", routeID = UrlParameter.Optional }
);
And here's the actions from my Controller:
public ActionResult List(string id)
{
return View();
}
public ActionResult Details(string routeID)
{
return View();
}
When I access this URL (/RouteStop/Details/100) the parameter gets passed just fine. But when I access the other one (/RouteStop/List/1) the parameter is null. The names match up as they should but I can't figure it out.
Try replacing {controller} with List and Details in respective routes. but for your scenario the default routing that you get when you create an MVC app should work.

Resources