ASP.NET MVC - Strange routing issue, very simple route mismatch problem - asp.net-mvc

I'm at a loss... here's my route:
routes.MapRoute("LangOnly", "{language}",
new { controller = "Home", action = "Root", language = "en" },
new { language = #"en|ja" });
it matches www.domain.com/en, but does not match www.domain.com/ja.
huh? I've even gone so far as to comment out any other routes... kind of stuck. ;/
Update: Here's the root action on the Home controller.
[CompressFilter]
public ActionResult Root()
{
if (!IsEnglish)
return RedirectToAction("Index", "Biz", new { b = "" });
return Request.IsAuthenticated ? View("LoggedInRoot") : View("Root");
}
It doesn't take a language parameter because it's being set on the base controller in OnActionExecuting, like so:
var l = (RouteData.Values["language"] != null) ? RouteData.Values["language"].ToString() : string.Empty;
if (string.IsNullOrEmpty(l))
l = "en";
if (l.Contains("en"))
{
IsEnglish = true;
l = "en";
}
else
{
IsEnglish = false;
l = "ja";
}
ViewData["lang"] = l.ToLower();
Language = l.ToLower();

Works perfectly for me with your route. Try this simple configuration:
routes.MapRoute("LangOnly", "{language}",
new {controller = "Home", action = "Index", language = "en"},
new {language = #"en|ja"});
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
And your action:
public ActionResult Index(string language)
{
.....
(I am using "Index" as the action here, obviously change it to "Root" if that is in fact your action name.)

Related

#Html.ActionLink returning a parameterised hyperlink

I am calling:
#Html.ActionLink("Register", "Register", "Account", new {area="FrontEnd"})
expecting
www.example.com/Account/Register
but I'm getting
http://www.example.com/?action=Register&controller=Account&area=FrontEnd
I'm a little confused as to why this happening, what can I do to resolve this?
Edit
When I remove the area parameter at the end, it builds the link correctly but to my admin section instead of FrontEnd.
Edit
I've isolated it to a custom route I have setup:
routes.Add("CategoriesRoute", new CategoriesRoute()); //This is breaking ActionLink.
routes.MapRoute("Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", area = "FrontEnd", id = UrlParameter.Optional },
new[] { "CC.Web.Areas.FrontEnd.Controllers" }
);
This is the custom route.
public class CategoriesRoute : Route
{
public CategoriesRoute()
: base("{*categories}", new MvcRouteHandler())
{
}
public override RouteData GetRouteData(HttpContextBase httpContext)
{
var rd = base.GetRouteData(httpContext);
if (rd == null)
return null;
string categories = rd.Values["categories"] as string;
if (categories.IsEmpty())
return null;
string[] parts = categories.Split('/');
if (not a category) //pseudo code
return null;
rd.Values["controller"] = "Category";
rd.Values["action"] = "Index";
rd.Values["area"] = "FrontEnd";
rd.DataTokens.Add("namespaces", new string[] { "CC.Web.Areas.FrontEnd.Controllers" });
rd.Values["categoryString"] = "/" + categories; //Required to get exact match on the cache.
return rd;
}
}
Try the below. I think you're missing an attribute null at the end
#Html.ActionLink("Register", "Register", "Account", new {area="FrontEnd"}, null)
You need to add null for the 5th parameter (html attributes)
#Html.ActionLink("Register", "Register", "Account", new {area="FrontEnd"}, null)

ASP .NET MVC What's going on with my route?

I have a problem, my url is ugly smth like this:
http://localhost:43547/Admin?id=1&str=wooh
I want see the url like this one
http://localhost:43547/LOL
My routes are:
routes.MapRoute(
"MyRoute",
"LOL",
new { controller = "Admin", action = "Index",
id = UrlParameter.Optional, str = UrlParameter.Optional }
);
routes.MapRoute(
"Default",
"{controller}/{action}",
new { controller = "Home", action = "Index" }
);
and I have 2 identical views one of them is with such method
#Html.ActionLink("Click me", "Index", "Admin", new { id = 1, str = "wooh" }, null)
which moves the page...
and I have 2 controllers:
public ActionResult Index(int id = 5485, string str = "Default Value")
{
ViewBag.ID = id;
ViewBag.STR = str;
return View();
}
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Controller = "Home";
ViewBag.Action = "Index";
return View();
}
}
So what's wrong? When I type smth like /LOL
It moves me to another page with default values of id and str...
Change your MyRoute definition to include the id and str parameter values.
routes.MapRoute(
"MyRoute",
"LOL",
new { controller = "Admin", action = "Index",
id = 1, str = "wooh" }
);
That way your url will look like /LOL but will pass the values you need.

How to control routing values

Maybe I don't understand real purpose of asp mvc routing.
I created an application and now I need to fix my url's a to be more understandable.
For example I have area Cities with controller Home and action Index.
So here I need url like: localhost/London but with current routing I get localhost/cityPage/Home.
My question is can I somehow pass parameter like city name and make URL like I want?
This is my current default routing in Global.asax
routes.MapRoute(
"Default",
"{area}/{controller}/{action}/{id}",
new { area = "CityPage", controller = "Home", action = "Index", id = "" },
new string[] { "MyProject.Areas.Cities.Controllers" }).DataTokens.Add("area", "Cities");
New routing:
routes.MapRoute(null,
"CityPage/{cityName}",
new
{
area = "CityPage",
controller = "Home",
action = "Index"
}
);
routes.MapRoute(
"Default",
"{area}/{controller}/{action}/{id}",
new { area = "CityPage", controller = "Home", action = "Index", id = "" },
new string[] { "MyProject.WebUI.Areas.CityPage.Controllers" }).DataTokens.Add("area", "CityPage");
Example of link that I click
#Html.ActionLink("City London", "Index", "Home", new { cityName = "London" }, null)
In order to route the URL localhost/London to the Index action on the HomeController of the Cities area, you need a route like this:
routes.MapRoute(null,
"{id}",
new
{
area = "Cities", controller = "Home", action = "Index"
}
);
Be sure this route is declared before the "Default" route in your CitiesAreaRegistration.cs class.
However if you have a lot of other routes in your application, adding a general route like this can play havoc with other routes in the app. I suggest adding a URL prefix to separate this route from others in your application:
routes.MapRoute(null,
"cities/{id}",
new
{
area = "Cities", controller = "Home", action = "Index"
}
);
This will make your URL look like localhost/cities/London. Is that acceptable?
Update 1
Unless you completely remove your "Default" route definition, you will actually have multiple INBOUND routes that map to this action. You would have localhost/cities/London, localhost/cityPage/Home, localhost/cityPage/Home/Index, and localhost/cityPage/Home/Index/London all resolving to that action. However when MVC chooses to generate an OUTBOUND route, it will choose the first one -- localhost/cities/London.
Update 2
If you want your route parameter to be cityName, you would do this:
routes.MapRoute(null,
"cities/{cityName}",
new
{
area = "Cities", controller = "Home", action = "Index"
}
);
However you would then have to change the Index action on your Cities area's HomeController to have this signature:
public ActionResult Index(string cityName)
By changing the argument from id to cityName, you are telling MVC to pass this URL paramter / route segment to the action method.
Update 3
Is the name of your area "Cities" or "CityPage"? From previous code it looked like the name of your area was Cities.
If it is CitiesPage, try this for your action method:
#Html.ActionLink("City London", "Index", "Home",
new { area = "CityPage", cityName = "London" })
Final Answer
I just reproduced this in an MVC3 project, and it is working as expected:
Created a new area named "CityPage"
Added a HomeController with an Index action to the CityPage area
Added an Index view to the CityPage/Views/Home folder.
CityPageAreaRegistration.cs:
public class CityPageAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "CityPage";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(null,
"CityPage/{cityName}",
new { area = "CityPage", controller = "Home", action = "Index" }
);
//context.MapRoute(
// "CityPage_default",
// "CityPage/{controller}/{action}/{id}",
// new { action = "Index", id = UrlParameter.Optional }
//);
}
}
HomeController.cs:
public class HomeController : Controller
{
//
// GET: /CityPage/Home/
public ActionResult Index(string cityName)
{
return View();
}
}
Index.cshtml:
#{
ViewBag.Title = "Index";
}
<h2>
Index</h2>
#Html.ActionLink("City London", "Index", "Home",
new { area = "CityPage", cityName = "London" }, null)
Finally, here is the link generated by the action link:
City London
yes you can do this way but you have to do following thing
Make sure your route must register before generic route.
Get Information about RouteConstraint
http://www.asp.net/mvc/tutorials/controllers-and-routing/creating-a-route-constraint-cs
http://www.asp.net/mvc/tutorials/controllers-and-routing/creating-a-custom-route-constraint-cs
Just for example Try this way check your required url localhost/London
routes.MapRoute(
"Default",
"{id}",
new { area = "CityPage", controller = "Home", action = "Index", id = "" },
new string[] { "MyProject.Areas.Cities.Controllers" }).DataTokens.Add("area", "Cities");

Help me get this ASP.NET MVC2 RC ActionLink to work?

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.

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?

Resources