Is it possible to alias routes in ASP.NET MVC4 dynamically?
Basically in WebForms I was using something like this:
foreach (var rule in rules)
{
routes.MapPageRoute("_" + rule.Url, rule.Url, rule.Redirect);
}
and filling the rules from database.
I need to allow the client to rename routes (or make redirects) from the CMS.
Thank you.
Dynamic route aliasing is a difficult process in ASP.NET MVC to be frank. Creating a single route with a dynamic constraint might be a more elegant solution. This needs to set up a constraint that only matches your categories.
routes.MapRoute(
"Product",
"{alias}/{pageNumber}",
new { controller = "Products", action = "Choose", alias = UrlParameter.Optional, pageNumber = 1 },
new { alias = new ProductOptionCondition() } );
The dynamic custom paging in the above is using the dynamic route aliasing option. What have you done exactly. Could you please explain any specific requirement on this, unless its manageable with default route option available with MVC-4.
Related
I want to set up a route in my ASP.NET MVC 3 web application, that has a url fragment appended to it, in the same way as some url's on StackOverflow, e.g:
http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags/1732382#1732382
However, I can't see any (clean) way of achieving this at the moment.
Is there an 'out of the box' solution or do I need to build a helper of some description to append a url fragment to the end of a normal route?
You could use helpers. For example:
#Html.ActionLink(
"linkText",
"action",
"controller",
null,
null,
"fragment",
new { id = "123" },
new { #class = "test" }
)
or if you want only an url you could use the GenerateUrl method.
I need a feedback on a routing-related issue I've found while publishing an ASP.NET MVC 2 application.
In the global.asax file I defined the following routes:
// Thumbnails routing.
// Sample URL: resizer/resizeImage/200/200/Error/error.jpg
routes.MapRoute("Resizer","Resizer/{action}/{width}/{height}/{folder}/{file}",
new { controller = "Resizer", action = "ResizeImage", width = 100,height = 100,
folder = "Error", file = "error.jpg"
}
);
// Default routing.
// Sample URL: /Home/Index
routes.MapRoute("Default", "{controller}/{action}.aspx/{id}",
new { controller = "Home", action = "Index", id = (string)null }
);
So, firstly I had to add .aspx for the default routing otherwise the hosting server (Aruba) does not perform properly routing... so first question: is there any other workaround to maintain normal routing (i.e. without adding .aspx)?
The 'Resizer' route should allow to call a controller that should generate thumbnails images: It works locally but not when the web site is published.
It seems that the route like 'resizer/resizeImage/200/200/Error/error.jpg' is not recognized.
How can I handle this issue?
thanks for your reply.
I modified the routing adding '.aspx' to {action} also in the Resizer route.
Now it looks like:
routes.MapRoute("Resizer",
"Resizer/{action}.aspx/{width}/{height}/{folder}/{file}",
new { controller = "Resizer", action = "ResizeImage",
width = 100, height = 100, folder = "Error", file = "error" });
It seems to work properly, it is actually the only way to activate IIS routing.
I also deleted the file extension (.jpg), just to avoid problem with the Dot character.
Marco
I don't think there is another way to avoid the .aspx instead the "normal" routing.
Any how I don't think it's a big deal.
I also think that in the code that you posted (I didn't try it) the routing is not correct: to add the aspx you should put the aspx after the controller name, in the default like in the resizer one.
Something like that:
routes.MapRoute("Resizer",
"Resizer.aspx/{action}/{width}/{height}/{folder}/{file}",
new { controller = "Resizer", action = "ResizeImage",
width = 100, height = 100, folder = "Error", file = "error.jpg" });
/Stefano
I would like to have users insert and edit information about entities on the same page in a similar fashion to google alerts: http://www.google.com/alerts/manage
Any advice on how this could be achieved?
It is possible changing the routing in the method RegisterRoutes in Global.asax as indicated in the remarks section present in the same file.
Enabling this section:
routes.Add(new DynamicDataRoute("{table}/ListDetails.aspx") {
Action = PageAction.List,
ViewName = "ListDetails",
Model = DefaultModel
});
instead of the already enabled:
routes.Add(new DynamicDataRoute("{table}/{action}.aspx")
{
Constraints = new RouteValueDictionary(new { action = List|Details|Edit|Insert" }), Model = DefaultModel
});
It's also possible to enable custom routes for particular tables.
I have the following route defined
routes.MapRoute(
"ItemName",
"{controller}/{action}/{projectName}/{name}",
new { controller = "Home", action = "Index", name = "", projectName = "" }
);
This route actually works, so if I type in the browser
/Milestone/Edit/Co-Driver/Feature complete
It correctly goes to the Milestone controller, the edit action and passes the values.
However, if I try and construct the link in the view with a url.action -
<%=Url.Action("Edit", "Milestone", new {name=m.name, projectName=m.Project.title})%>
I get the following url
Milestone/Edit?name=Feature complete&projectName=Co-Driver
It still works, but isn't very clean. Any ideas?
When constructing and matching routes in ASP.NET routing (which is what ASP.NET MVC uses), the first appropriate match is used, not the greediest, and order is important.
So if you have two routes:
"{controller}/{action}/{id}"
"{controller}/{action}/{projectName}/{name}"
in that given order, then the first one will be used. The extra values, in this case projectName and name, become query parameters.
In fact, since you've provided default values for {projectName} and {name}, it's fully in conflict with the default route. Here are your choices:
Remove the default route. Do this if you don't need the default route any more.
Move the longer route first, and make it more explicit so that it doesn't match the default route, such as:
routes.MapRoute(
"ItemName",
"Home/{action}/{projectName}/{name}",
new { controller = "Home", action = "Index", name = "", projectName = "" }
);
This way, any routes with controller == Home will match the first route, and any routes with controller != Home will match the second route.
Use RouteLinks instead of ActionLinks, specifically naming which route you want so that it makes the correct link without ambiguity.
Just to clear up, here is what I finally did to solve it, thanks to the answer from #Brad
<%=Html.RouteLink("Edit", "ItemName", new { projectName=m.Project.title, name=m.name, controller="Milestone", action="Edit"})%>
You can try
Html.RouteLink("Edit","ItemName", new {name=m.name, projectName=m.Project.title});
I need to be able to construct a link in the Action on the controller to send an email. What is best practice to do this? I don't want to construct it myself in case my routes change.
Should I have a view for each email and render that and send it? That might be a good way of doing it.
If you just want to get the path to a certain action, use UrlHelper:
UrlHelper u = new UrlHelper(this.ControllerContext.RequestContext);
string url = u.Action("About", "Home", null);
if you want to create a hyperlink:
string link = HtmlHelper.GenerateLink(this.ControllerContext.RequestContext, System.Web.Routing.RouteTable.Routes, "My link", "Root", "About", "Home", null, null);
Intellisense will give you the meaning of each of the parameters.
Update from comments: controller already has a UrlHelper:
string url = this.Url.Action("About", "Home", null);
If you need the full url (for instance to send by email) consider using one of the following built-in methods:
With this you create the route to use to build the url:
Url.RouteUrl("OpinionByCompany", new RouteValueDictionary(new{cid=newop.CompanyID,oid=newop.ID}), HttpContext.Request.Url.Scheme, HttpContext.Request.Url.Authority)
Here the url is built after the route engine determine the correct one:
Url.Action("Detail","Opinion",new RouteValueDictionary(new{cid=newop.CompanyID,oid=newop.ID}),HttpContext.Request.Url.Scheme, HttpContext.Request.Url.Authority)
In both methods, the last 2 parameters specifies the protocol and hostname.
Regards.
I had the same issue, and it appears Gidon's answer has one tiny flaw: it generates a relative URL, which cannot be sent by mail.
My solution looks like this:
string link = HttpContext.Request.Url.Scheme + "://" + HttpContext.Request.Url.Authority + Url.Action("ResetPassword", "Account", new { key = randomString });
This way, a full URL is generated, and it works even if the application is several levels deep on the hosting server, and uses a port other than 80.
EDIT: I found this useful as well.
Another way to create an absolute URL to an action:
var relativeUrl = Url.Action("MyAction"); //..or one of the other .Action() overloads
var currentUrl = Request.Url;
var absoluteUrl = new System.Uri(currentUrl, relativeUrl);
I know this is an old question, but just in case you are trying to do the same thing in ASP.NET Core, here is how you can create the UrlHelper inside an action:
var urlHelper = new UrlHelper(this.ControllerContext);
Or, you could just use the Controller.Url property if you inherit from Controller.