In my layout page, the links to the main sections that make up my site are rendered with a call like this:
#SiteSectionLink("index", "blog", "blog")
Where SiteSectionLink is a helper that looks like this:
#helper SiteSectionLink(string action, string controller, string display)
{
<li>
<h1>
<a class="site-section" href="#Url.Action(action, controller)">#display</a></h1>
</li>
}
On the actual blog page, all links also refer to the "Index" action but also specify either a date parameter (such as "blog/4-2011" or "blog/2010") that is used to filter the posts by a date period. In addition to that, there's also an optional postID parameter that is used to refer to a specific post.
To accomplish that, I have the following routes:
routes.MapRoute(
"Blog",
"blog/{date}/{postID}",
new
{
controller = "blog",
action = "index",
date = UrlParameter.Optional,
postID = UrlParameter.Optional
}
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
Now, the problem is that when I have clicked a link that is something like "blog/11-2010" or "blog/11-2010/253" then the link in my layout page that refers to my blog in general now also refers to that same URL when I want it to just link to "blog/", not "blog/11-2010".
If I change the SiteSectionLink helper to explicitly pass in null for date and postID like this:
<a class="site-section" href="#Url.Action(action, controller,
new { date = (string)null, postID = (int?)null})">#display</a></h1>
The current route values are still used but now it looks like "blog?date=11-2010".
I saw this similar question but the accepted answer doesn't work for me, and I don't use ActionLink in the first place and I suspect that ActionLink would use Url.Action under the hood.
While the issue you are experiencing is not quite the behavior detailed by Phil Haack in this blog post regarding a bug with MVC3 routing and a route with two optional parameters, I would suggest applying the fix described in Phil's post.
I also would suggest never creating a route with two optional parameters, and instead follow the pattern of breaking the desired routing into two separate routes.
Yes Url.Action method puts the parameters in the querystring.
You can change your helper like this:
#helper SiteSectionLink(string action, string controller, string display, string date = null, string id=null)
{
<li>
#if (date == null)
{
<h1><a class="site-section" href="~/blog/#controller/#action">#display</a></h1> // simple workaround or better use P. Haack workaround
}
else
{
<h1><a class="site-section" href="#Url.RouteUrl("blog", new { action = #action, controller = #controller, date = #date, id = #id })">#display</a></h1>
}
</li>
}
So you can use SiteSelectionLink like these:
#SiteSectionLink("Index", "Blog", "test", "2011", "4")
#SiteSectionLink("Index", "Blog", "test2", "2011")
#SiteSectionLink("Index", "Blog", "test3")
Related
I am writting simple web page (kind of blog) and I am blocked with following issue.
In Views/Shared in _Layout.cshtml I have defined layout of page.
My routing rules looks like that
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"paging", // Route name
"Home/GetArticleListForCategory/{id}/{pageNo}", // URL with parameters
new { controller = "Home", action = "GetArticleListForCategory", id = UrlParameter.Optional, pageNo = UrlParameter.Optional } // Parameter defaults
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
When I run action from link
http://localhost:3282/Home/GetArticleListForCategory/1
the page is displayed properly
When I run action from link
http://localhost:3282/Home/GetArticleListForCategory/1/1
the page looks 'raw' (there is no layout on page, no images etc.) I have compared html returned by pages from two links but they are identical.
Controller action looks like that:
public ActionResult GetArticleListForCategory(int id,int pageNo = 1)
{
int articlesPerPageNo = ConfigurationHelper.NoOfArticlePerPage;
int totalNoOfArticles;
List<PostShort> listOfPostforCategory = GetListOfShortArticles(pageNo,articlesPerPageNo ,out totalNoOfArticles);
int totalPagesNo = (totalNoOfArticles + articlesPerPageNo - 1) / articlesPerPageNo;
ViewData["PageTotal"] = totalPagesNo;
ViewData["PageNo"] = pageNo;
return View("CategoryPosts",listOfPostforCategory);
}
Note that parameters are properly passed to action (tested in debug).
Does anybody have idea what is the source of such behaviour and how to solve it ?
Thanks in advace for help.
Best Regards
<link href="../../Content/style.css" rel="stylesheet" type="text/css" />
here are my doubts in _layout.cshtml image is declared as follows
<img src="../../Content/img02.jpg" width="1000" height="300" alt="" />
when such link is used
http://localhost:3282/Home/GetArticleListForCategory/1
the link to one of images looks like that http://localhost:3282/Content/img02.jpg
but when I add one more parameter to link:
http://localhost:3282/Home/GetArticleListForCategory/1/1
where first number is category and second is page number whe link to same image looks like that http://localhost:3282/Home/Content/img02.jpg
why same action return view located in other place ?
I am working on an ASP.NET mvc 3 site that contains several project entities, and then each project has several associated subpages, each that works with a component of the project.
So for instance, I could have a project with several photos, milestones, user info, etc. I have a Project Index view, as well as a Project Home which links to several component pages. Most of the components have two views, Index, and Edit/View.
So I set up a route for the edits and views. Note that my route is in an AREA called ProjectManagement
context.MapRoute(
"ProjectManagement_ProjectPageSingle",
"ProjectManagement/{controller}/{action}/{projectNumber}/{projectChildId}",
new { controller = "Project", action = "Home" }
);
and my controller actions all look similar to this:
public ActionResult Edit(string projectNumber, string projectChildId)
This works well and good when I type in the URL directly in the browser. For instance:
~/ProjectManagement/Milestone/Edit/39999P110175/1
however, when I generate an action link using:
<a href="#Url.Action("Edit", new { projectNumber = Model.Project.ProjectNumber, projectChildId = entry.Id})">
the action URL ends up looking like this:
~/ProjectManagement/Milestone/Edit/39999P110175?projectChildId=1
So the route sorta works...but the action link generator doesn't? Not sure where to go from here. Any advice would be much appreciated.
Note that the same thing occurs while using #Html.ActionLink instead of #Url.Action.
Thanks!
You don't seem to have specified the area name:
#Url.Action(
"Edit",
new {
projectNumber = Model.Project.ProjectNumber,
projectChildId = entry.Id,
area = "ProjectManagement"
}
)
Also make sure that there aren't any other routes that might conflict with this one in your area registration which should look like this:
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"ProjectManagement_default",
"ProjectManagement/{controller}/{action}/{projectNumber}/{projectChildId}",
new { controller = "Project", action = "Home" }
);
}
Thanks to Michael for the response. Here's the answer for others.
I had:
context.MapRoute(
"ProjectManagement_ProjectPage",
"ProjectManagement/{controller}/{action}/{projectNumber}",
new { controller = "Project", action = "Home"}
);
///more routes
context.MapRoute(
"ProjectManagement_ProjectPageSingle",
"ProjectManagement/{controller}/{action}/{projectNumber}/{projectChildId}",
new { controller = "Project", action = "Home" }
);
The URL matched the ProjectPage route as well, so it took that one first. Had to flip the order, so the more specific route came first.
Thanks.
Has anyone been able to get the Areas in ASP.NET MVC 2 to work?
I created a new Area called "Secure" and placed a new controller in it named HomeController. I then Created a new Home/Index.aspx view. However, when I browse to http://localhost/myapp/Secure/ it gives a 404 resource cannot be found. http://localhost/myapp/Secure/Home gives the same error.
My area registration looks like this:
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Secure_default",
"Secure/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
I also tried this:
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Secure_default",
"Secure/{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Thanks,
Justin
I am pretty sure it was because your area registration class was in a different namespace that the project it was hosted in. It would explain why your solution worked - you registered it with the overload that takes in the namespace. I had a similar issue and it was fixed by correcting the namespace.
Sure, i've got Areas working with ASP.NET MVC 2.
Its hard for people to debug routes over SO, the easiest way is for you to use Phil Haacks Route Debugger. It'll tell you what routes (and areas) are being resolved for a particular URL. Extremely handy.
However ill take a stab, try changing your route to this:
context.MapRoute(
"Secure_default",
"Secure",
new { action = "Index", controller = "Home", id = UrlParameter.Optional }
);
The url (<yourhost>/Secure) will find your area Secure but not know which controller you hand the request to, as you have not specified a default value for controller in your areas route.
Here's my setup:
Areas
Albums
Controllers
AlbumsController.cs (namespace Web.Areas.Albums.Controllers)
Models
Views
Albums
Index.aspxx
AlbumsAreaRegistration.cs
context.MapRoute(
"Albums_Default",
"Albums",
new { controller = "Albums", action = "Index", id = UrlParameter.Optional)
The URL: http://localhost/Albums triggers the "Index" action of my "AlbumsController" in my "Albums" area.
What does you structure look like?
I got it working, the answer was to change the area registration class to this:
context.MapRoute(
"Secure_Default", // Route name
"Secure/{controller}/{action}/{id}", // URL with parameters
new { area="Secure", controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
new[] { typeof(Controllers.HomeController).Namespace }
);
I have no idea why it worked for another developer and not for me, also I feel like it should "just work" out of the box when you create a new Area, you shouldn't have to fiddle with the route mapping.
Anyway, thanks all for the help and I'm giving the answer to RPM for all his hard work.
Are you calling AreaRegistration.RegisterAllAreas() in your global.asax?
Sub Application_Start()
AreaRegistration.RegisterAllAreas()
RegisterRoutes(RouteTable.Routes)
End Sub
Have you tried using http://localhost/myapp/Secure/Home/index ? I find so many times that when I use index as the view name and don't specify it in the path it never works. It should work but it never works for me.
I don't like calling my views index anyways so not a big deal for me.
In global.asax
routes.MapRoute(
"Test_Default", // Route name
"test/{controller}/{action}", // URL with parameters
new { }
);
routes.MapRoute(
"Default",
"{universe}",
new { controller = "notfound", action = "error"}
);
I have a controller: Home, containing an action: Index
Enter the url in browser: h**p://localhost:53235/test/home/index
Inside the index.aspx view in <body> tag: I want to link to the second route.
<%=Html.RouteLink("Link", new { universe = "MyUniverse" })%>
Shouldn't this generate a link to the second route in Global.asax? The generated url from the above is: h**p://localhost:53235/test/home/index?universe=MyUniverse. I can only get it to work, if I specify the name of the route: <%=Html.RouteLink("Link", "default", new { universe = "MyUniverse" })%>
Am I missing something?
As you've discovered you need to use the route name if you want to generate a link to the second route. The first route will always be evaluated because even if the universe parameter doesn't exist in the route definition it is just passed as query string argument.
I have a problem with the RC1 version of ASP.Net MVC. Whenever I add a Route before the "Default" route, the resulting Urls created are for the first Route added.
Here is my Routing in Global.asax.cs
routes.MapRoute(
"product-detailed",
"Products/{controller}/{action}/{id}",
new { controller = "ProductSubType", action = "Index", id = "" }
);
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = "" }
);
My Url creation:
<%= Html.ActionLink("Bikes", "Index", "Bikes") %><br />
<%= Html.RouteLink("Bikes", "product-detailed", new { controller = "Bikes", action = "Index" }) %>
I would expect the first ActionLink to create a Url like "/Bikes/Index" and the second RouteLink to create "/Products/Bikes/Index", but both Urls end up as "/Products/Bikes/Index".
What am I missing here on the routing?
Thanks.
You're not missing anything. It's working as designed.
Since the controller and action are both variable in the top route, with no limitations on valid values, then that route is valid for all values of controller and action.
Potential work-arounds:
Fix the controller and/or action values so that they're not part of the URL
Add restrictions for the top route for values of controller and/or action
Always use route links instead of action links, since they unambiguously state which route is the correct route.