I have two ambiguous routes, both within the same MVC area:
Default
{controller}/{action}/{id}
controller = "Home"
action = "Index"
id = Optional
SettingsRoute
Settings/{controller}/{action}
action = "Index"
I want MVC to use the Default route by default, which it does when the routes are in the order specified above. So this...
Controller: WelcomeController
Action: Login
using( Html.BeginForm() ) { }
...results in this HTML
<form action="/Welcome/Login" method="post"></form>
So far, so good.
However when I have an anchor that looks like this:
Application settings
...it gets captured by the Default route as Controller = Settings, Action = AppSettings instead of by the SettingsRoute route.
When I reorder the routes so SettingsRoute appears before Default then my Html.BeginForm() calls look like this: <form action="Settings/Welcome/Login"> which isn't what I want at all.
Is there any solution to this?
You Can mention <%:Html.ActionLink("Create Item-->this is the page you wanted to redirec ","Index","Item--> folder of the page") %>
You can Navigate from one page to another.
Related
I have a controller called TaskListsController with an action called Edit.
The Edit action accepts a nullable int parameter. If it receives null, it adds a TaskList. If it receives an int, it edits the TaskList with the same ID. The logic is almost identical in each case.
I would like to configure my routing in such a way that the URL 'TaskLists/Add' maps to the Edit action with null as the parameter, and the URL 'TaskLists/Edit/{id}' maps to Edit and passes it the ID in the URL.
I can get this to work from the point of view of entering URLs in the browser and having them routed to the action correctly, but where it's falling down is where the system generates URLs from Html.ActionLink.
I am generating 'Add' links using:
Html.ActionLink("Add task list", "Edit", "TaskLists")
And I'm generating 'Edit' links using:
Html.ActionLink(taskList.Name, "Edit", new { Id = taskList.Id })
..where taskList is an instance of the TaskList class.
If I use this routing:
routes.MapRoute(
"TaskLists/Add", // Route name
"TaskLists/Add", // URL with parameters
new { controller = "TaskLists", action = "Edit" });
routes.MapRoute(
"TaskLists/Edit/{id}", // Route name
"TaskLists/Edit/{id}", // URL with parameters
new { controller = "TaskLists", action = "Edit", id = UrlParameter.Optional });
...the 'Add' link is generated correctly ('TaskLists/Add') but the 'Edit' link comes out 'TaskLists/Add?Id=1'.
If I put the routing commands the other way around:
routes.MapRoute(
"TaskLists/Edit/{id}", // Route name
"TaskLists/Edit/{id}", // URL with parameters
new { controller = "TaskLists", action = "Edit", id = UrlParameter.Optional });
routes.MapRoute(
"TaskLists/Add", // Route name
"TaskLists/Add", // URL with parameters
new { controller = "TaskLists", action = "Edit" });
...then the 'Edit' links are generated correctly ('TaskLists/Edit/x'), but the 'Add' links comes out 'TaskLists/Edit'.
Is there a way I can have my cake and eat it?
Using named routes (Html.RouteLink("linkText", "routeName")) could be a cleaner way of defining this, as then you're dealing with a clean route in the view also. This would also mean that you will hit the correct route every time without worry.
Update the Name parameter on your routes accordingly, then add the following to your view:
Html.RouteLink("Add task list", "NewTaskList")
and
Html.RouteLink(taskList.Name, "EditTaskList", new { Id = taskList.Id })
Question -
I've noticed that some applications I test with have calls to another view/controller from an action submit, but when that page is rendered, instead of seeing:
$controller/$page
I see:
$controller/index
Is this an issue with the URL mapping configuration? Default action? Just curious, because it just appears to be the URI mapping to a default instead of the actual action.
view code:
<table>
..
<g:actionSubmit class="stats" action="stats" value="View Stats"/>
..
</table
controller:
def stats() {
def teamId = Team.get(params.id)
def allPlayers = Player.withCriteria {
eq('team', teamId)
and {
eq('isActive', true)
}
}
[allPlayers:allPlayers, teamId:params.id]
}
UrlMapping:
class UrlMappings {
static mappings = {
"/$controller/$action?/$id?"{
constraints {
// apply constraints here
}
}
}
Edit
I actually figured out what it is. Which makes me even more confused.
The grails actionSubmit has an action tied to it. That form was just a normal form, without call:
<g:form>
<g:actionSubmit class="stats" action="stats" value="View Stats"/>
<g:actionSubmit class="schedule" action="schedule" value="View Schedule"/>
<g:form>
So by default, the form redirects the action to $controller/index. If you add an action call in the g:form tag, those two buttons will direct to the correct page, but the URI will now be $controller/$g:form_action.
I guess I don't get the point of the actionSubmit's action if the g:form is needed as a wrapper.
Yes, index is the default action for all controllers. So if you do not specify one, that is the page you will land on for the controller.
It is discussed in further detail on their website. Namely, the rules are:
If only one action is present the default URI for a controller maps to
that action.
If you define an index action which is the action that
handles requests when no action is specified in the URI /book
Alternatively you can set it explicitly with the defaultAction property:
static defaultAction = "list"
I'm having problems when using this route:
routes.MapRoute("ProductIndex", "pr-{key}", new { controller = "Home", action = "Product" });
When the key contains 'pr-', the route doesn't work.
Example: http://.../pr-my-product-key-with-pr-key
Routes don't work the way you want them to work, but it's easily converted
change your route to:
routes.MapRoute(
"ProductIndex",
"pr/{key}",
new { controller = "Home", action = "Product" });
and use:
http://.../pr/my-product-key-with-pr-key
or, if you really want to use that "way" you need to override the Initialization method of your main controller are check the link with StartWith() and redirect to the proper Controller.
I've been using this some while now, but I can't seem to figure out, where could be mistake in this simple code:
<a href="<%= Url.Action("Page", new { page=(Model.PageIndex + 1) }) %>" >a</a>
With this routing table:
routes.MapRoute(
"Paging",
"Home/Page/{page}",
new { controller = "Home", action = "Index" }
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
And of course this method
public ActionResult Index(int? page)
I am getting instead of expected address http://localhost:58296/Home/Page/1 the one http://localhost:58296/Home/Page?page=1
When using
<%= Html.RouteLink("a", "Paging", new { page=(Model.PageIndex+1) }) %>
it works.. Please, where is my mistake? I want image link, so if there is a way to insert it into Html.RouteLink, I would appriciate that info too.
Thanks in advance.
There's a bunch of items to cover here for you to fully understand what's happening. Sorry, this will be a bit long.
routes.MapRoute(
"Paging",
"Home/Page/{page}",
new { controller = "Home", action = "Index" }
);
First, this is the route you want to hit. You do not include the action route parameter, '{action}', in the route path. The only action this route can possibly take is the value you have specified as the default action value "Index".
<a href="<%= Url.Action("Page", new { page=(Model.PageIndex + 1) }) %>" >a</a>
Second, in your link you are setting an action of Page. The route you are expecting does not accept action as a parameter and the only action it is aware of is Index. When Url.Action looks for possible routes in your route table, it will skip the route you want because that route does not accept an action of Page. The default route is valid though because you are implicitly supplying a controller, Home, explicitly supplying an action, Page, allowing the framework to supply a default for id, string.Empty, and any other parameters are tacked on as query parameters, page.
When you changed the Url.Action to "Index", the Url.Action method inspected the routes table and found the route with the action of Index specified for the Home controller with a parameter of page and everything is happier.
Hope that helps and isn't too confusing.
I don't know why, but
<%= Url.Action("Index", new { page=(Model.PageIndex + 1) }) %>
works and it displays and directs to /Home/Page/1 . If someone could explain it to me, I would be gratful.
I'm attempting to make a TinyURL clone in ASP.NET MVC as a learning project.
Right now, all I want is to be able to submit new URLs to my /Home/Create action via a form.
I have my LINQ expression all setup, I have my routing setup, and I have my view setup but something is wrong with my setup.
Routing:
routes.MapRoute(
"Default", // Route name
"", // URL with parameters
new { controller = "Home", action = "Index" } // Parameter defaults
);
routes.MapRoute(
"Redirect",
"{hash}",
new { controller = "Home", action = "RequestLink", hash = "" }
);
These routes allow me to be able to go to my website, www.tinyurlclone.com/ and if nothing is passed ti will simply go to my Home/Index() action. However, if you put anything after the slash, it will consider that a Link Hash and attempt to retrieve the hash.
My HomeController is as follows:
[HandleError]
public class HomeController : Controller
{
TinyGetRepository repo = new TinyGetRepository();
public ActionResult Index()
{
return View();
}
public ActionResult Create(String url)
{
String hash = repo.addLink(url);
ViewData["LinkHash"] = hash;
return View();
}
public ActionResult RequestLink(String hash)
{
String url = repo.getLink(hash);
return Redirect(url);
}
}
My repo class has all my LINQ expressions in it for dealing with the database and I don't really need to include them because it isn't relevant to this question.
Finally, my basic Home/Index() view (used for submitting urls) is as follows:
<%# Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Index</title>
</head>
<body>
<div>
<center>
<span style="font-size: 14pt">TinyGet <em>(beta)</em></span><br />
<span style="font-family: Tahoma">Reduce your long links to smaller ones to keep them more memorable....<br />
</span>
<% using(Html.BeginForm("Create", "Home")) %>
<% { %>
<%= Html.TextBox("url") %>
<input type="submit" name="submitButton" value="Shorten Link!" />
<% } %>
</center>
</div>
</body>
</html>
However, my form simply isn't firing any methods when I click submit.
Furthermore, if I view the source of my generated HTML I can see that it didn't make my Form's action correctly, it reads:
<form action="" method="post"><input id="url" name="url" type="text" value="" />
<input type="submit" name="submitButton" value="Shorten Link!" />
</form>
Why is the HTML helper putting "" as the action when it ~should~ be putting /Home/Create? Why isn't my /Home/Create action method being called? Even if I don't use the Html helpers and specify the <form> tag manually it throws errors.
What is wrong here?
Source for project: here
The problem is that you don't have a route that matches the route values (controller = Home, action = Create).
You have two routes, one is the empty string (no parameters), which matches Controller = "Home", Action = "Index". The other is your hash route, which matches Controller = "Home", Action = "RequestLink". So, when ASP.Net Routing goes to build a URL from the route values you're providing, it can't find one (since none of them have the "{controller}" and "{action}" parameters).
The simplest solution, in this case, is to create a direct route to the "Create" action, so that you can still use your "hash" route. Put this at the top of your RegisterRoutes method. NOTE: Order does matter! ASP.Net Routing checks each route, in the order added, until it finds a match.
routes.MapRoute(
"Create", // Route name
"Create", // URL with parameters
new { controller = "Home", action = "Create" } // Parameter defaults
);
Since you have that "hash" route, you can't really use the default "{controller}/{action}/{id}" technique, since the "hash" value would be consider a valid Controller name. So, if someone requested: http://www.mysite.com/fjhas82, MVC would look for a Controller called "fjhas82" and complain that it couldn't find it. Unfortunately, this means you have to manually add new routes for each new Controller Action (like I showed above), which is a pain.
The best solution (in my opinion) is to use Regex Constraints: If your hashes have a very well-defined format (say: 5 letters followed by 2 numbers, or "_" followed by any alpha-numeric characters, etc.), or if you're willing to impose such a format, you can use the Regex constraints supported by ASP.Net Routing. Then, you'd only need these two routes
routes.MapRoute(
"Redirect",
"{hash}",
new { controller = "Home", action = "RequestLink" },
new { hash = #"[a-zA-Z]{5}[0-9]{2}" } // Regex Constraints
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index" } // Parameter defaults
);
Under these routes, if MVC sees a controller name like: "Home", it will check the first route, find that it doesn't match the regular expression, and move to the next one. NOTE: My Regular Expression syntax may be a bit rusty, so I'd use something like http://regexpal.com/ to test a Regex first, to make sure it works with your hashes and controller names.
Hope that helps, I know I wrote a lot, but MVC is so flexible, you can do things in so many different ways!
I had a similar issue from what I've learned is the routing takes the last route
So its using your hash route instead so thus its putting ""
Basically you could get rid of that hash route and just have this
routes.MapRoute( "Default", // Route name "{controller}/{action}/{hash}", // URL with parameters new { controller = "Home", action = "Index", hash="" } // Parameter defaults );
It would accomplish the same thing, and when the hash isn't provided it wouldn't matter