I'm looking for the way to shorten the URL for getting some from DB. I've got Homecontroller and writing action, which adds rows to DB and each of them has UID. There is also search action which finds the record in DB anŠ² renders a view.
So I use localhost/Home/writing to add a record and localhost/Home/search/3456 to search a record by UID.
Is there any way to pass UID (3456) into controller's action skipping action's name, so to search a resord I can use localhost/Home/3456 or even localhost/3456?
I've tried
routes.MapRoute(
"default-action",
"{controller}/{id}",
new { action = "search", id = UrlParameter.Optional }
);
and
routes.MapRoute(
"default-action",
"{id}",
new {controller = "Home", action = "search", id = UrlParameter.Optional }
);
but got nothing.
You could try using a route constraint:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Search",
"{id}",
new { controller = "Home", action = "Search" },
new { id = #"\d+" }
);
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Now:
localhost/Home/writing will hit the Writing action on HomeController
localhost/3456 will hit the Search action on HomeController and pass it id=3456 as parameter
The numeric constrained we defined for the {id} route token is required in order for the routing engine to disambiguate between the search and the default route patterns (since action names cannot start with a number). It assumes that your identifiers are numbers.
Related
How can I replicate this default MVC route code below but to work with multiple ActionResults that are in the home controller. I want them to work just like Index where you do not need /Home/Index in the url to hit example.com/index
routes.MapRoute("Default", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
I would like to hit example.com/about and example.com/contact without needing the the controller name in the beginning.
I have tried adding that same code but replaced Index with another action method and it works but it doesn't allow you to have more than 1 existing in this structure at the same time.
Solution?
Ok so I think I got it to work after reading this thread:
ASP.NET MVC - Removing controller name from URL
In the RouteConfig I added the following right before the default route:
routes.MapRoute(
"Root",
"{action}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new { isMethodInHomeController = new RootRouteConstraint<HomeController>() }
);
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Then inside of the Controller whos name you are trying to remove from the URL you need to add this:
public class RootRouteConstraint<T> : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
var rootMethodNames = typeof(T).GetMethods().Select(x => x.Name.ToLower());
return rootMethodNames.Contains(values["action"].ToString().ToLower());
}
}
Now if I go to example.com/about , it works and I don't have to use example.com/Home/About
On each index view page which contain list, I'm using ASP.NET MVC AJAX to sort and filter the list. The list is in the partial view. Everything looks so fine until I have a view with a parameter (reference key/FK)
I don't add any routes, just using the default route:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
so the url is http://localhost:49458/TimeKeeper/New?billingID=7. If the url in that format, the AJAX sort and filter are not working. I tried to add a new route:
routes.MapRoute(
name: "TimeKeeperNew",
url: "TimeKeeper/New/{billingID}",
defaults: new { controller = "TimeKeeper", action = "New", billingID = "" }
);
so the url become: http://localhost:49458/TimeKeeper/New/7.
Now, the ajax sort and filter are working.
Is there anyone can explain me, what's the problem? Did I use the correct way (by adding a new route) or is there any other way?
I don't even understand why you are saying primary key as MVC has no concept of this.
With only (assuming for the duration of this answer until the break):
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home",
action = "Index",
id = UrlParameter.Optional }
);
Any route that does not define id will be appended to the url with the value.
Url.Action("New", "TimeKeeper", new { billingID = 7 })
Always will produce
http://localhost:49458/TimeKeeper/New?billingID=7
Because "billingID" != "id"
So your options are another MapRoute which I would not recommend, or use Id:
Url.Action("New", "TimeKeeper", new { id = 7 })
which always produces:
http://localhost:49458/TimeKeeper/New/7
Optionally:
public class TimerKeeperController
{
public ActionResult New(string id)
{
int billingId;
if (!string.TryParse(id, out billingId)
{
return RedirectToAction("BadBillingId")
}
....
}
}
BREAK
What about if there are 2 parameters, let's say billingID and clientGroupID? I don't quite understand routing in depth, could you help me to explain this in the answer?
Now you need another MapRoute:
routes.MapRoute(
name: "Default2",
url: "{controller}/{action}/{id}/{id2}",
defaults: new { controller = "Home",
action = "Index",
id = UrlParameter.Optional,
{id2} = UrlParameter.Optional }
);
And it is required to be before or after the previous MapRoute because anything that would work for this route will work for the previous route, thus this route will never be called. I can't exactly remember which way it goes at the moment, but if you test it, you'll figure it out quickly.
Then you can have:
http://localhost:49458/TimeKeeper/Copy/7/8
with:
public ActionResult Copy(string id, string id2)
{
....
}
notes
Yes you don't have to use a string and parse the values, you could use constraints on the MapRoute or just use Int and throw errors if someone manually types http://localhost:49458/TimeKeeper/New/Bacon.
Here is my code:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
"Admin", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Admin", action = "Index", id = UrlParameter.Optional }
);
}
for first link it works well if i go to:
localhost/song
localhost/date
etc. it opens all links under home controller.
But for second maproute:
localhost/admin
localhost/admin/index
- these link are not working? Can anyone please tell me what i am doing wrong?
First, your default route must be last in the list, not first.
Second, You have two default routes. There is no way for MVC to know which one to use, so it always chooses the first one that matches. Instead, your Url for the admin one should be "Admin/{action}/{id}"
I have 2 routes mapped in my mapping...
this is to allow a user to type in the url with an optional parameter to quick load their town in the home page of the website, example:
www.mysite.com/manchester
www.mysite.com/liverpool
or to simply go to the defaul home page if www.mysite.com is entered with nothing else.
With the default mapping in place to handle the controller/action/parameter i have added an additional route so the parameter is handed:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }); // Parameter defaults
routes.MapRoute(
"HomePageQuickFind",
"{quickFind}",
new { controller = "Home", action = "Index", quickFind = UrlParameter.Optional });
I am not very good with route mapping as I am struggling to understand it and my question is this a bad approach which my cause "greedy routing" and is there another way of implementing my scenario?
I think you need to replace the default route with a set of routes for each of your controllers, then add your quick find route as the last route. This should allow any unmatched routes to fall through to the quick find route. Try something like this:
// Routes for standard controllers
routes.MapRoute(
"Home",
"home/{action}/{id}",
new { controller = "home", action = "index", id = UrlParameter.Optional }
);
routes.MapRoute(
"Map",
"map/{action}/{id}",
new { controller = "map", action = "index", id = UrlParameter.Optional }
);
routes.MapRoute(
"Default",
"users/{action}/{id}",
new { controller = "users", action = "index", id = UrlParameter.Optional }
);
// Route for www.mysite.com/cityname
routes.MapRoute(
"QuickFind",
"{quickFind}",
new { controller = "home", action = "index", quickFind = UrlParameter.Optional }
);
In my global.asax I have three routes:
//MemberHome is supposed to handle urls like http://localhost/johndoe
routes.MapRoute(
"MemberHome", // Route name
"{username}",
new { controller = "PublicMember", action = "Index", username = "username" }
);
//Home is supposed to catch http://localhost/
routes.MapRoute(
"Home",
""
);
// the default way of doing things..
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
The problem is, I can get them to work separtely (just home or just MemberHome)
But when they are both activated its either Home or MemberHome which gives me a 404 resource not found..
Any idea how I can get this work?
You need to set the first part of the route to something distinct. Eg:
routes.MapRoute(
"MemberHome", // Route name
"MemberHome/{username}",
new { controller = "PublicMember", action = "Index", username = "username" }
);
or:
routes.MapRoute(
"Default",
"Home/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
That way they will be distinct. Whichever one is given the fixed part of the route should come first, as otherwise the route handler will match the wildcard one first...