I have a route added by the code
routes.MapRoute("MyRoute", "TheUrl", new { controller = "MyController", action = "MyAction" });
I can then do a reverse lookup with the arguments like UrlHelper.Action("MyAction", "MyController"), and it will return a nice url like ~/TheUrl
However, for this route I want the generated URL to be ~/TheUrl?p=2354, with the parameter being some versioning parameter. Is there a way of doing this by mapping the route with some customized route handler or something? The versioning parameter will be non-standard and require some custom code to execute every time the Url is looked up.
I think a UrlHelper extension method would be most ideal and simple here specially.
public string MyRoute(this UrlHelper url)
{
string versionNumber = GetVersionNumber(); // or w/e is required to get it
return Url.Action("MyAction", "MyController") + "?p=" + versionNumber;
}
This would make calling that route much easier in html
<%= Url.MyRoute() %>
Related
I have an asp.net MVC app created using VS2015.
In my razor view, I have the following:
#Html.ActionLink(linkText: "Detail",
actionName: "Index",
controllerName: "SupportNotificationDetail",
routeValues: new { id = item.DetailFilename },
htmlAttributes: null)
The definition for my controller method is as follows:
public class SupportNotificationDetailController : Controller
{
// GET: SupportNotificationDetail
public ActionResult Index(string id)
I have made no changes to the default routing configuration.
My problem is, the action link is producing the following URL:
ESBAMPortal/SupportNotificationDetail/Index/%7B43794F0E-23AD-4A70-AF39-3364E93F5832%7D.html
For this, I get a 404 error. If I manually edit the url in the browser address bar so that the id parameter is named - then the correct page is loaded:
ESBAMPortal/SupportNotificationDetail/Index?id=%7B43794F0E-23AD-4A70-AF39-3364E93F5832%7D.html
If I can find an answer to either of the following then I will be able to sleep tonight:
Why does the url without the named id parameter give a 404?
or
How can I make the ActionLink helper give the required URL?
When you request the url yourSiteName/SupportNotificationDetail/Index/somefile.html, The request will be handled by IIS because the request url is looking for a static content html file ( The request specifically has a file extension in it). So iis will try to serve it directly without the request going through the MVC request pipeline.
But when you request yourSiteName/SupportNotificationDetail/Index?id=somefile.html, somefile.html is a querystring value. So IIS won't directly serve the response. It will be send to the MVC pipeline and since the request matches the route definition registered with the route table, it will be forwarded to the Index action method with the parameter id and it's value.
The default MVC route definition has a request url pattern of {controller}/{action}/{id} where id is an optional parameter to the action method. For this reason, the helper method generates the link to match with the above mentioned pattern , hence you are getting the url without the id parameter in it.
You can change the parameter name from Id to something else and then the ActionLink helper method will generate the target url with explicit querystring parameter name.
public class SupportNotificationDetailController : Controller
{
public ActionResult Index(string fildId)
{
return Content(fildId);
}
}
and in the view,
#Html.ActionLink("Detail", "Index", "SupportNotificationDetail",
new { fildId = Model.DetailFilename }, null)
In my view I'm using a
<img src="#Url.Action("Method", new { Model.Url })" ...
<img src="#Url.Action("Method", new { Model.Url })/1" ...
And in that method I have params:
public ActionResult Method(string url, int ids=0)
With
var book = GetBookByUrl(url);
...
switch (ids)
{
case 1:
In my global.asax I have:
routes.MapRoute(null,
"{controller}/{action}/{url}/{ids}",
new { controller = "Controller", action = "Method", url = "", ids = #"\d+" });
My view returns the correct URL's (with /1 and /2 appended), but I can't seem to get my method to retrieve the value of ids so that I can manipulate them in my action method to retrieve different results based on the Url.Action URL provided within my view, what gives?
The ids parameter seems to always be 0 (not being routed data) and the url parameter has the entire url "bla-bla/2", which I do not want.
Please note that although there are plenty of routing resources, I've read over them and can't seem to get this to work - also is this the standard way of routing data from a request to a controller?
Please show me by way of example how to solve, many thanks!
I have the following a href link:
title
That i use for showing SEO-friendly urls; i would like, instead of the anchor tag, to use the Html.ActionLink.
How can i transform the anchor in ActionLink considering that i have not the Action name on the url?
You can use Html.ActionLink even when the action is not present in the URL; you just need an appropriate route. Routes are used for both inbound URL matching and outbound URL generation.
First things first, you'll need a route in the Routes collection to be used as a template for the URLs that you want to generate
routes.MapRoute(
null, // name
"News/{id}/{title}", // URL pattern
new { controller = "News", action = "Index" }, // defaults
new { id = "\d+", title = #"[\w\-]*" }); // constraints
This route will only match if id is a number and title contains only word characters and/or hyphens. The route needs to be registered before any more "general" routes as the order of routes is important; the framework stops on the first matching route, it does not try to find a "best" match.
Now you can use Html.ActionLink to generate routes.
#Html.ActionLink("title", "Index", "News", new { id = item.id, title = item.NewsSeoTitle })
You may also want to look at T4MVC (available as a NuGet package) too as it adds some overloads that removes the need for magic strings all over the place
Assuming your controller action looks like
public class NewsController
{
public ActionResult Index(int id, string title)
{
return View();
}
}
T4MVC adds an overload that allows you to use Html.ActionLink like
#Html.ActionLink("title", MVC.News.Index(item.id, item.NewsSeoTitle))
much neater :)
If you are using the custom links which is not corresponding to the controller/action structure, maybe it's better to use your own html extension
public static string SeoLink(this HtmlHelper helper, string itemId, string title, string seoTitle)
{
return String.Format("{1}",
VirtualPathUtility.ToAbsolute(String.Format("~/News/{0}/{1}", itemId, seoTitle)),
title);
}
As for Html.ActionLink: from the name of extension you can find the it work with actions. Of course you can provide such action and controller names to fit your requirements, but it's not a good idea, especially if your code will be supported by any other developer - he will never find such action in controller which is specified in ActionLink as actionName param.
Due to factors outside my control, I need to handle urls like this:
http://www.bob.com/dosomething.asp?val=42
I would like to route them to a specific controller/action with the val already parsed and bound (i.e. an argument to the action).
Ideally my action would look like this:
ActionResult BackwardCompatibleAction(int val)
I found this question: ASP.Net MVC routing legacy URLs passing querystring Ids to controller actions but the redirects are not acceptable.
I have tried routes that parse the query string portion but any route with a question mark is invalid.
I have been able to route the request with this:
routes.MapRoute(
"dosomething.asp Backward compatibility",
"{dosomething}.asp",
new { controller = "MyController", action = "BackwardCompatibleAction"}
);
However, from there the only way to get to the value of val=? is via Request.QueryString. While I could parse the query string inside the controller it would make testing the action more difficult and I would prefer not to have that dependency.
I feel like there is something I can do with the routing, but I don't know what it is. Any help would be very appreciated.
The parameter val within your BackwardCompatibleAction method should be automatically populated with the query string value. Routes are not meant to deal with query strings. The solution you listed in your question looks right to me. Have you tried it to see what happens?
This would also work for your route. Since you are specifying both the controller and the action, you don't need the curly brace parameter.
routes.MapRoute(
"dosomething.asp Backward compatibility",
"dosomething.asp",
new { controller = "MyController", action = "BackwardCompatibleAction"}
);
If you need to parametrize the action name, then something like this should work:
routes.MapRoute(
"dosomething.asp Backward compatibility",
"{action}.asp",
new { controller = "MyController" }
);
That would give you a more generic route that could match multiple different .asp page urls into Action methods.
http://www.bob.com/dosomething.asp?val=42
would route to MyController.dosomething(int val)
and http://www.bob.com/dosomethingelse.asp?val=42
would route to MyController.dosomethingelse(int val)
Is there a way to force use of a named route in ASP.NET MVC when using Form.Begin. I'm learning more and more about routing and getting scared that it can be very fragile if you just change the order or whether or not parameters have defaults.
<% Form.Begin(...) %> <!-- no overload for providing a route name --%>
There does not seem to be an overload for a named route for beginning a form so instead the best I could come up with was this :
<form action="/Products/Command/ViewProduct" method="post">
I'm wondering if this missing overload is an oversight (Beta right now), if there is a reason for it or an alternative way to generate the URL.
I tried to use RouteLink and embed it in the Form tag, but RouteLink creates me the full HTML for an <A> tag which is no good.
action="<%= Ajax.RouteLink("Update Status", "product-route-short", new { action = "GetStatus", sku = "" }, new AjaxOptions { UpdateTargetId = "status" })%>"
What alternatives do i have to generate a URL from a named route.
Should I report this missing overload as an issue?
If you need to generate a URL to a named route, you can use Url.RouteUrl(), you just have to put the controller and action into the route values object like so:
<%= Url.RouteUrl("NamedRoute", new { controller="Controller", action="Action", foo="Bar" ... }) %>
As for adding the overload, a lot of these helpers have so many different overloads that they start to conflict and become ambiguous. For example, consider the following overloads
public string BeginForm(string actionName, string controllerName)
public string BeginForm(string actionName)
public string BeginForm(string routeName, string actionName) // Uh oh!
The 1st and 3rd have identical signatures, so they are invalid.
You could always create your own form helper as an extension method to HtmlHelper if you need to use Named Routes often.