Help me get this ASP.NET MVC2 RC ActionLink to work? - asp.net-mvc

I could have SWORN I had this working, but somewhere along the line I apparently broke it. Maybe it was during my migration from ASP.NET MVC in VS2008 to ASP.NET MVC2 in VS2010.
My ActionLink:
Html.ActionLink(segment.TitleWithChapterNumber, "Index", "Read", new { bookCode = Model.Product.Id, segmentCode = segment.Index }, null)
The route I expect it to match:
routes.MapRoute(
"Read",
"Read/{bookCode}/{segmentCode}/{sectionCode}/{renderStrategy}",
new { controller = "Read", action = "Index", bookCode = "", segmentCode = "", sectionCode = "", renderStrategy = "" }
);
This renders a link that looks like: http://localhost/Obr/Read?bookCode=14&segmentCode=0
But I want it to look like http://localhost/Obr/Read/14/0
Clicking the link that it renders does take me to the right controller and the response is accurate. If I paste in the link I WANT it to look like, it does work. I guess it's just not matching?
Am I missing something obvious? I've stared at it so long I don't even know what I am looking for anymore.
For reference, here are ALL of my routes:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"ReadImage",
"Read/Image/{bookId}/{imageName}",
new { controller = "Read", action = "Image" }
);
routes.MapRoute(
"Read",
"Read/{bookCode}/{segmentCode}/{sectionCode}/{renderStrategy}",
new { controller = "Read", action = "Index", bookCode = "", segmentCode = "", sectionCode = "", renderStrategy = "" }
);
routes.MapRoute(
"BookReport",
"BookReport/{action}/{folder}",
new { controller = "BookReport", action = "Details", folder = "" }
);
routes.MapRoute(
"Reference",
"Reference/Details/{referenceType}/{searchText}",
new { controller = "Reference", action = "Details", referenceType = "", searchText = "" }
);
routes.MapRoute(
"PaginatedAudits", // Route name
"Audit/Page/{pageNumber}", // URL with parameters
new { controller = "Audit", action = "Index" } // Parameter defaults
);
routes.MapRoute(
"PaginatedReadLog", // Route name
"ReadLog/Page/{pageNumber}", // URL with parameters
new { controller = "ReadLog", action = "Index" } // Parameter defaults
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
The action signature looks like this:
[Authorize]
public ActionResult Index(string bookCode, string segmentCode, string sectionCode, string renderStrategy)
{
// code
}

Try a route link by explicitly giving the name of the route:
Html.RouteLink(
segment.TitleWithChapterNumber, // linkText
"Read", // routeName
new {
bookCode = Model.Product.Id,
segmentCode = segment.Index
}, // routeValues
null // htmlAttributes
)

Your route definitions should have UrlParameter.Optional instead of empty strings.
routes.MapRoute(
"Read",
"Read/{bookCode}/{segmentCode}/{sectionCode}/{renderStrategy}",
new { controller = "Read", action = "Index", bookCode = UrlParameter.Optional, segmentCode = UrlParameter.Optional, sectionCode = UrlParameter.Optional, renderStrategy = UrlParameter.Optional }
);
This will also help with redirect in controllers and form urls created through MVC extensions.

Related

UrlHelper.Action not generating pretty url

I'm generating SEO-friendly "Pretty URLs" using this custom route, inspired by posts here on stackoverflow:
// Route used for Details view
routes.Add("CarDetailsRoute", new SeoFriendlyRoute(
url: "car/{state}/{community}/{make}/{model}/{slug}-{id}",
valuesToSeo: new string[] { "state", "community", "make", "model", "slug" },
defaults: new RouteValueDictionary(new { controller = "Vehicle", action = "Details", slug = UrlParameter.Optional, state = UrlParameter.Optional, community = UrlParameter.Optional, make = UrlParameter.Optional, model = UrlParameter.Optional }),
constraints: new RouteValueDictionary(new { id = #"\d+" })
));
/// The interesting route
routes.Add("CarIndexRoute", new SeoFriendlyRoute(
url: "car/{state}/{community}/{make}/{model}/",
valuesToSeo: new string[] { "state", "community", "make", "model" },
defaults: new RouteValueDictionary(new { controller = "Vehicle", action = "Index", state = UrlParameter.Optional, community = UrlParameter.Optional, make = UrlParameter.Optional, model = UrlParameter.Optional })
));
// Unrelated routes
// Fallback default route
routes.Add("Default", new SeoFriendlyRoute(
url: "{controller}/{action}/{id}",
valuesToSeo: new string[] { "action", "controller" },
defaults: new RouteValueDictionary(new { controller = "Home", action = "Index", id = UrlParameter.Optional }))
);
However, when I'm generating the breadcrumbs from my Details view to generate generic searches on parts of the details information, somehow the custom route fails and the default route kicks in.
// RequestContext here being a full qualified with Make, Model, Community
// and State. These are inserted in to all .Action()s by default, so i have
// to "remove them" where I don't want them.
var url = new UrlHelper(Request.RequestContext);
var breadcrumbs = new List<IBreadcrumbLink>() {
new BreadcrumbLink() {
Title = vehicle.Dealer.State,
Url = url.Action("Index", new { model = string.Empty, make = string.Empty, community = string.Empty })
// Doesn't work, generates ~/vehicle/?model=aaa&make=bbb&community=ccc&state=ddd
// Expected ~/car/state/
},
new BreadcrumbLink() {
Title = vehicle.Dealer.Community,
Url = url.Action("Index", new { model = string.Empty, make = string.Empty })
// Works, generates ~/car/state/community/
},
new BreadcrumbLink(){
Title = vehicle.Make,
Url = url.Action("Index", new { model = string.Empty })
// Works, generates ~/car/state/community/make/
},
new BreadcrumbLink(){
Title = vehicle.Model,
Url = url.Action("Index")
// Works, generates ~/car/state/community/make/model/
}
};
What would cause this behavior? Visiting the expected url of ~/car/state/ works like a charm, but as stated I cannot generate this url?

Asp mvc map url with hardcoded controller and action can't be found

I have next map url definition where I want to set specific action and controller for special url:
//localhost:55321/SpecificPart/UserTextId all other routes should work in default way
but based on Route Debugger my URL is mapping to my main route rule how to handle this case ?
routes.MapRoute(
"PartnerSighUp",
"SpecificPart/{id}",
new { controller = "SpecificController ", action = "SpecificAction" },
new { id = "[A-Za-z].+" }
);
routes.MapRoute(
name: "EnglishHomePage",
url: "",
defaults: new { culture = "en", controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{culture}/{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", culture = "en", id = UrlParameter.Optional }
);
Update if SpecificPart = SpecificController (controller name) it is working but if SpecificPart != SpecificController and looks to other controller it is not working

ASP.Net MVC Routing Issue - Question Mark appears on my links

I have a public website which accepts a pagename, this then defaults to a controller and action with the pagename as the unique identifier to render the correct view. eg. http://www.mydomain.com/homepage
I also have a admin area where all CRUD stuff takes place access via a prefix of admin. eg. http://www.mydomain.com/admin/controller/action
Everything has been fine until I changed something recently and now when I got to http://www.mydomain.com/homepage the links I have such as:
<ul id="menu">
<li><%= Html.ActionLink("Home", "Details", "WebPage", new { pageName = "homepage" }, null)%></li>
<li><%= Html.ActionLink("About", "Details", "WebPage", new { pageName = "homepage" }, null)%></li>
</ul>
no longer appear as http://www.mydomain.com/homepage but instead http://www.mydomain.com/Admin/WebPage/Details?pageName=homepage
Can someone help?
Here is my Global.asax:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute("AdminRoot",
"Admin",
new { controller = "Admin", action = "Index" }
);
routes.MapRoute(
"LogOn", // Route name
"LogOn", // URL with parameters
new { controller = "Account", action = "LogOn" },
new { action = "LogOn" }
);
routes.MapRoute("Account",
"Account/{action}",
new { controller = "Account", action = "" }
);
//routes.MapRoute(
// "Default", // Route name
// "{controller}/{action}/{id}", // URL with parameters
// new { controller = "Home", action = "Index", id = "" } // Parameter defaults
//);
routes.MapRoute(
"ErrorRoute", // Route name
"Error/Error404", // URL with parameters
new { controller = "Error", action = "Error404" }
);
routes.MapRoute("Admin",
"Admin/{controller}/{action}/{id}",
new { controller = "Admin", action = "Index", id = "" }
/*,new { action = "Create|Edit|Delete" }*/
);
routes.MapRoute("EventNewsData",
"Admin/{controller}/{action}/{year}/{month}",
new { controller = "Admin", action = "Index", year = 0, month = 0 }
/*,new { action = "Create|Edit|Delete" }*/
);
routes.MapRoute(
"Default", // Route name
"{pageName}/{moreInfoID}", // URL with parameters
new { controller = "WebPage", action = "Details", pageName = "homepage", moreInfoID = 0 },
new { action = "Details" }
);
routes.MapRoute("Error", "{*url}", new { controller = "Error", action = "Error404" });
}
UPDATE: This has fixed it but not really sure why
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute("AdminRoot",
"Admin",
new { controller = "Admin", action = "Index" },
new { action = "Index" }
);
routes.MapRoute(
"LogOn", // Route name
"LogOn", // URL with parameters
new { controller = "Account", action = "LogOn" },
new { action = "LogOn" }
);
routes.MapRoute("Account",
"Account/{action}",
new { controller = "Account", action = "" }
);
//routes.MapRoute(
// "Default", // Route name
// "{controller}/{action}/{id}", // URL with parameters
// new { controller = "Home", action = "Index", id = "" } // Parameter defaults
//);
routes.MapRoute("Admin",
"Admin/{controller}/{action}/{id}",
new { controller = "Admin", action = "Index", id = "" }
, new { action = "Create|Edit|Delete|Index|DeleteFromIndex" }
);
routes.MapRoute("EventNewsData",
"Admin/{controller}/{action}/{year}/{month}",
new { controller = "Admin", action = "Index", year = 0, month = 0 }
, new { action = "GetCalendarData" }
);
routes.MapRoute(
"Default", // Route name
"{pageName}/{moreInfoID}", // URL with parameters
new { controller = "WebPage", action = "Details", pageName = "homepage", moreInfoID = 0 },
new { action = "Details" }
);
routes.MapRoute(
"ErrorRoute", // Route name
"Error/Error404", // URL with parameters
new { controller = "Error", action = "Error404" }
);
routes.MapRoute("Error", "{*url}", new { controller = "Error", action = "Error404" });
}
Maybe the problem is in action = "Details" constraint (There is no "{action}" in "{pageName}/{moreInfoID}"):
routes.MapRoute(
"Default", // Route name
"{pageName}/{moreInfoID}", // URL with parameters
new { controller = "WebPage", action = "Details", pageName = "homepage", moreInfoID = 0 },
new { action = "Details" }
);
UPDATED:
Now your code is using this route:
routes.MapRoute("Admin",
"Admin/{controller}/{action}/{id}",
new { controller = "Admin", action = "Index", id = "" }
/*,new { action = "Create|Edit|Delete" }*/
);
But you can use Html.RouteLink instead:
<ul id="menu">
<li><%= Html.RouteLink("Home", "Default", new { pageName = "homepage" })%> </li>
<li><%= Html.RouteLink("About", "Default", new { pageName = "homepage" })%> </li>
</ul>
UPDATED:
ASP.NET Routing looks for route with "Details" action and "WebPage" controller ("pageName" is optional) and match "Admin" route.
UPDATED:
Or add this route before "Admin" route:
routes.MapRoute("TheRoute",
"{pageName}/{moreInfoID}",
new { controller = "WebPage", action = "Details", moreInfoID = 0 },
new { pageName = "homepage" }
);

ASP.NET MVC custom routes with optional args

I want a Route with two optional args; I thought the following would work:
routes.MapRoute(
"ProductForm",
"products/{action}/{vendor_id}_{category_id}",
new { controller = "Products", action = "Index", vendor_id = "", category_id = "" },
new { action = #"Create|Edit" }
);
But it only works when both vendor_id and category_id are provided; using RouteDebug I see that /products/create/_3 doesn't trigger my route, so I added other two routes:
routes.MapRoute(
"ProductForm1",
"{controller}/{action}/_{category_id}",
new { controller = "Home", action = "Index", category_id = "" },
new { controller = "Products", action = #"Create|Edit" }
);
routes.MapRoute(
"ProductForm2",
"{controller}/{action}/{vendor_id}_",
new { controller = "Home", action = "Index", vendor_id = "" },
new { controller = "Products", action = #"Create|Edit" }
);
So, the questions:
Is using three routes the only way to make a route with optional args?
Are these URLs ok or not, that is, would you suggest a better way to do this?
Why don't you try to give vendor_id a default value (if it is not specified i.e 0) that would help you get away with one route
routes.MapRoute("ProductForm","products/{action}/{vendor_id}_{category_id}",
new { controller = "Products", action = "Index", vendor_id = "0", category_id = "" },
new { action = #"Create|Edit" });
looks good to me but i would do it a little different:
routes.MapRoute(
"ProductForm1",
"product/category/{category_id}",
new { controller = "Home", action = "Index", category_id = "" },
new { controller = "Products", action = #"Create|Edit" }
);
and then
routes.MapRoute(
"ProductForm1",
"product/details/{product_id}",
new { controller = "Home", action = "Index", product_id = "" },
new { controller = "Products", action = #"Create|Edit" }
);
then your class can be as follows:
ActionResults Index(){}
ActionResults Index(int category_id){// get categories}
ActionResults Index(int product_id){ // get products}
but thats just me
you could try it like this:
routes.MapRoute(
"ProductForm",
"products/{action}/{arg1}/{arg1_id}/{arg2}/{arg2_id}",
new { controller = "Products", action = "Index", arg1 = "", arg2 = "", arg1_id = "", arg2_id = "" },
new { action = #"Create|Edit" });
Then you would create some logic in your actionresult method to check arg1 and arg2 and identify wich argument has been passed in.
your actionlink urls would look like this:
/products/create/vendor/10
/products/create/category/20
/products/create/vendor/10/category/20
/products/create/category/20/vendor/10
Personally i dont like this as the route doesn't seem very clean but should give you what i think your looking to achieve?

Why does ASP.NET MVC path appear with variables?

In my MVC app, why does
Return RedirectToAction("Edit", "Forms", New With {.member = "123"})
return
http://localhost:13/Forms/Edit?member=123
insted of
http://localhost:13/Forms/Edit/123
?
And why does
<%=Html.ActionLink("MyLink", "Edit", "Forms", New With {.member = "123"}, Nothing)%>
do the same thing?
As tvanfosson says, "id" is what the default route engine is set to look for. Anything else as the 3rd param and it will be tacted on as a querystring.
Why? Because of this method in your Global.asax:
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = "" }
);
You can change this by adding an additional routes.MapRoute() line, like so:
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = "" }
);
routes.MapRoute(
"Default2",
"{controller}/{action}/{member}",
new { controller = "Home", action = "Index", member = "" }
);
The standard routing is set up to use id as the third parameter. Change "member" to "id" and you will get the route that you expect.
Return RedirectToAction("Edit", "Forms", New With { .id = "123"})

Resources