Almost all MVC Web applications allow users to navigate from one View to another, usually relying on including links in the first View which eventually targets the action method that generates the second. Using simple anchor HTML elements “a” and targeting it’s “href” attribute to a specific controller’s action, maybe seems a good and an obvious solution but it can be dangerous choice. Imagine you have an anchor element like this:
<a href="/Simple/MySegmentVariable">Link</a>
Clicking the link will cause a “MySegmentVariable” action in a “SimpleController” controller process the URL request. But what if in some point you decide to change your URL schema? What if you decide to delete the entire “SimpleController” class and replace it with a new one? All anchor links that used to target this controller will crash. MVC Framework provides you with a much better approach where you use your URL Routing system to generate and produce URLs dynamically in a way that is guaranteed to reflect the URL schema of the application. Let’s create a simple MVC application and take a look at these features.
Open Visual Studio 2012 and create an ASP.NET MVC 4 Web Application, choosing the Basic template and the Razor as my View engine. Add a simple controller named “SimpleController” to the “controllers” folder.
namespace UrlRouting.Controllers { public class SimpleController : Controller { public ActionResult Index() { ViewBag.Controller = "Simple"; ViewBag.Action = "Index"; return View("DisplayActionController"); } public ActionResult MySegmentVariable(string id ="MyDefaultIdValue") { ViewBag.Controller = "Simple"; ViewBag.Action = "MySegmentVariable"; ViewBag.CustomVariable = id; return View(); } } }
The controller has two action methods which pass both the controller’s and action’s name using a ViewBag object. Create a “DisplayActionController” View inside the Views/Shared folder.
@{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>DisplayActionController</title> </head> <body> <div>Controller Invoked: @ViewBag.Controller</div> <div>Action Invoked: @ViewBag.Action</div> <div> @Html.ActionLink("This is an outgoing URL", "MySegmentVariable") </div> </body> </html>
This is the View rendered when the Index action of the Simple controller is invoked. Right click inside the MySegmentVariable action and select “Add view..”. Leave the default values and change the new’s View contents to the following.
@{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>MySegmentVariable</title> </head> <body> <div>Controller processed the URL: @ViewBag.Controller</div> <div>Controller action invoked: @ViewBag.Action</div> <div>The custom segment variable is: @ViewBag.CustomVariable</div> </body> </html>
This is the View rendered when “MySegmentVariable” action method is invoked. Before start running the application and explaining what are we doing, add a custom route in the “RegisterRoutes” function in the RouteConfig.cs file, where we define application’s URL schema.
public static void RegisterRoutes(RouteCollection routes) { routes.MapRoute("MyRoute", "{controller}/{action}/{id}", new { controller = "Simple", action = "Index", id = UrlParameter.Optional }); }
If you don’t know what the above code means, read this post where an MVC Routing System introduction is described. Build and run your application.
This is the “DisplayActionController” View render by the Index action in the SimpleController. Notice the link generated by the following line inside the View’s code
@Html.ActionLink("This is an outgoing URL", "MySegmentVariable")
The simplest way to generate an outgoing URL in a view is to call the Html.ActionLink helper method. The above overload has two parameteres. The first one is the text being displayed and the second one, the action method that the link should target. If you hover over the link you can see that the target URL is
http://localhost:"your_port"/Simple/MySegmentVariable
To see Html.ActionLink capabilities, add a new route above the old one and run the application again.
public static void RegisterRoutes(RouteCollection routes) { routes.MapRoute("NewRoute", "Web/app{action}", new { controller = "Simple" }); routes.MapRoute("MyRoute", "{controller}/{action}/{id}", new { controller = "Simple", action = "Index", id = UrlParameter.Optional }); }
Hover over the link and see how it’s new target URL reflects the new route we added before.
The default Html.ActionLink overload method assumes that you want to target an action method in the same controller that has caused the view to be rendered. If you wish to target another controller’s action you can use a different overload. Create a new controller named “ProductController” in the controllers folder.
namespace UrlRouting.Controllers { public class ProductController : Controller { public ActionResult Index() { ViewBag.Controller = "Product"; ViewBag.Action = "Index"; return View("DisplayActionController"); } public ActionResult ListProducts() { ViewBag.Controller = "Product"; ViewBag.Action = "ListProducts"; return View("DisplayActionController"); } } }
In the “DisplayActionController” View add a new Html.ActionLink passing this time both the action’s and the controller’s name you want to invoke.
<div> @Html.ActionLink("This is an outgoing URL", "MySegmentVariable") </div> <div> @Html.ActionLink("This targets another controller", "ListProducts", "Product") </div>
Build and run your application. Notice the difference at the two generated links in your page.
The first outgoing URL was generated using the first route we defined in the “RouteConfig.cs” file, since it requires only an action to be matched. It’s URL is the same we saw before. The second ActionLink though, matched the second route “MyRoute” because it passed a controller’s name as parameter too. If you want, you can pass the extra value for the “Id” segment in the second route too. Comment the first route in the RouteConfig.cs and change the second ActionLink to this.
@Html.ActionLink("This targets another controller", "MySegmentVariable", new { id = "ValueFromActionLink!" })
http://localhost:49529/Simple/MySegmentVariable/ValueFromActionLink!
passing an extra value for the id segment. It may seems little confusing how ActionLink works with the URL Routing system, but since you understand it you have a powerful tool to dynamically generate outgoing URLs in you MVC application.
Categories: ASP.NET
Great article. You help me to manage URL to be more user friendly. Thanks again.
Nice post. I was checking continuously this blog andd I am impressed!
Extremely useful information particularly the
last part 🙂 I care for such information a lot. I was seeking this particular info for a very long
time. Thank you and good luck.