UNDERSTANDING SEGMENT VARIABLE REUSE

Một phần của tài liệu Giáo trình lập trình ASP.NET Apress pro ASP NET MVC3 framework pre release (Trang 334 - 339)

When we described the way that routes are matched for outbound URLs, we mentioned that when trying to find values for each of the segment variables in a route’s URL pattern, the routing system will look at the values from the current request. This is a behavior that confuses many

programmers and cause hours of confusionlead to a lengthy debugging session. Imagine our application has a single route, as follows:

routes.MapRoute("MyRoute", "{controller}/{action}/{color}/{page}");

Now imagine that a user is currently at the URL /Catalog/List/Purple/123, and we render a link as follows:

@Html.ActionLink("Click me", "List", "Catalog", new {page=789}, null)

You might expect that the routing system would be unable to match the route, because we have not supplied a value for the color segment variable and there is no default value defined. You would, however, be wrong – the routing system will match against the route we have defined and it will generate the following HTML:

<a href="/Catalog/List/Purple/789">Click me</a>

The routing system is keen to make a match against a route, to the extent that it will reuse segment variables values from the incoming URL. In this case, we end up with the value Purple for the color variable, because of the URL that our imaginary user started at. This is not a behavior of last resort – the routing system will apply this technique as part of its regular assessment of routes, even if there is a subsequent route that would match without requiring values from the current request to be reused. The routing system will only reuse values for segment variables which occur earlier in the URL pattern than any parameters that are supplied to the Html.ActionLink method.

So, for example, we tried to create a link like this:

@Html.ActionLink("Click me", "List", "Catalog", new {color="Aqua"}, null)

We have supplied a value for color, but not for page. But color appears before page in the URL pattern, and so the routing system won’t reuse the values from the incoming URL and the route will not match. The best way to deal with this behavior is to prevent it from happening – and that means supplying values for all of the segment variables in a URL pattern. We strongly recommend that you do not rely on this behavior – not only will it make your code harder to read, but you end up making assumptions about the order in which your users make requests – something that will ultimately bite you as your application enters maintenance.

When we supply values for properties which do not correspond to segment variables, the values are appended to the outgoing URL as the query string. For example, this call to the ActionLink helper method:

@Html.ActionLink("About this application", "About", new { id = "MyID", myVariable = "MyValue" })

generates the following HTML:

<a href="/Home/About/MyID?myVariable=MyValue">About this application</a>

If we supply a value for a variable that happens to match the default value we specified in the route, then the routing system omits the variable from the outgoing URL. As an example, consider the following call to the ActionLink method:

@Html.ActionLink("About this application", "Index", "Home")

The values we have passes as parameters for the action method and controller match the default values for the route shown in Listing 11-27. The HTML that this call to the helper methods generates is as follows:

<a href="/">About this application</a>

The routing system omits the default values to generate the outbound URL with the fewest segments that will match the same route when the link has been clicked and the URL is incoming again.

Specifying HTML Attributes

We’ve focused on the URL that the ActionLink helper method generates, but remember that the method generates a complete HTML anchor element. We can set attributes for this element by providing an anonymous type whose properties correspond to the attributes we require. Listing 11-34 provides a demonstration that sets an id attribute and assigns a CSS class to the HTML element.

Listing 11-34. Generating an anchor element with attributes

41

@Html.ActionLink("About this application", "Index", "Home", null, new {id = "myAnchorID", @class = "myCSSClass"})

We have created a new anonymous type that has id and class properties and passed it as a parameter to the ActionLink method. We passed null for the additional segment variable values, indicating that we don’t have any values to supply.

Tip Notice that we prepended the class property with a @ character – this is a C# language feature that lets us use reserved keywords as the names for class members.

When this call to ActionLink is rendered, we get the following HTML:

<a class="myCSSClass" href="/" id="myAnchorID">About this application</a>

Generating Fully Qualified URLs in Links

All of the links that we have generated so far have contained relative URLs, but we can also use the ActionLink helper method to generate fully-qualified URLs, as shown by Listing 11-35.

Listing 11-35. Generating a fully qualified URL

@Html.ActionLink("About this application", "Index", "Home", "https", "myserver.mydomain.com", " myFragmentName", new { id = "MyId"},

new { id = "myAnchorID", @class = "myCSSClass"})

This is the ActionLink overload with the most parameters, and it allows us to provide values for the protocol (https, in our example), the name of the target server

(myserver.mydomain.com), and the URL fragment (myFragmentName) – as well as all of the other options we saw previously. When rendered in a view, the call in the listing generates the following HTML:

<a class="myCSSClass" href="https://myserver.mydomain.com/Home/Index/MyId#myFragmentName"

id="myAnchorID">About this application</a>

We recommend using relative URLs wherever possible. Fully-qualified URLs create dependencies on the way that your application infrastructure is presented to your users. We have seen many large applications that have rely on absolute URLs broken by uncoordinated changes to the network infrastructure or domain name policy, which are often outside of the control of the programmers.

Generating URLs (and not Links)

The Html.ActionLink helper method generates complete HTML a elements, which is exactly what we want most of the time. However, there are times when we just need a URL – either because we want to display the URL build the HTML for a link manually, display the value of the URL or include the URL as a data element in the HTML page being rendered.

In such circumstances, we can use the Url.Action method to generate just the URL and not the surrounding HTML, as Listing 11-36 shows.

Listing 11-36. Generating a URL without the surrounding HTML ...

My URL is: @Url.Action("Index", "Home", new { id = "MyId" }) ...

The Url.Action method works in just the same way as the Html.ActionLink method, except that it generates only the URL. The overloaded versions of the method and the parameters they accept are the same for both methods and we can do all of the things with Url.Action that we demonstrated with Html.ActionLink in the previous sections. Listing 11-36 renders the following when rendered in a view:

My URL is: /Home/Index/MyId

Generating Links and URLs from Routing Data

As we mentioned earlier, the routing system doesn’t assign any special meaning to the

controller and action segment variables when it is processing URLs – the meaning is attached by the MVC framework, allowing the routing system to be used more widely with other kinds of ASP.NET application.

Sometimes it is useful to treat controller and action just like any other variable and to generate a link or URL by providing a collection of name/value pairs. We can do this by using helper methods that are not MVC-specific, as demonstrated by Listing 11-37.

Listing 11-37. Generating a link using an anonymous type

@Html.RouteLink("Routed Link", new { controller = "Home", action = "About", id="MyID"})

There are no parameters for the RouteLink method to express the controller and action values – we have to include them as properties to the anonymous type. The call in the listing generates the following HTML when rendered in a view:

<a href="/Home/About/MyID">Routed Link</a>

We can use the Url.RouteUrl helper method to generate just the URL, as shown in Listing 11-38.

Listing 11-38. Generating a URL using an anonymous type

@Url.RouteUrl(new { controller = "Home", action = "About", id = "MyID" })

These methods are rarely needed because we generally know and want to specify the controller and action values explicitly – but it is good to know that these methods exist and they can make life a lot easier when you need them, however infrequently that might be.

Generating Outgoing URLs in Action methods

Mostly, we want to generate outgoing URLs in views – but there are times when we want to do something similar inside of an action method. If we just need to generate a URL, we can use the same helper method that we used in the view, as shown in Listing 11-39.

Listing 11-39. Generating an outgoing URL in an action method public ViewResult MyActionMethod() {

string myActionUrl = Url.Action("Index", new { id = "MyID" });

string myRouteUrl = Url.RouteUrl(new { controller = "Home", action = "Index" });

... do something with URLs...

}

A more common requirement is to redirect the client browser to another URL – we can do this by returning the result of calling the RedirectToAction method, as shown in Listing 11- 40.

Listing 11-40. Redirecting to another action public ActionResult MyActionMethod() { return RedirectToAction("Index");

}

The result of the RedirectToAction method is a RedirectToRouteResult, which instructs the MVC framework to issue a redirect instruction to a URL that will invoke the specified action – there are the usual overloaded versions of the RedirectToAction method that specify the controller and values for the segment variables in the generated URL. If you want to send a redirect using a URL generated from just object properties, then you can use the

RedirectToRoute method, as shown in Listing 11-41.

Listing 11-41. Redirecting to a URL generated from properties in an anonymous type public ActionResult MyOtherActionMethod() {

return RedirectToRoute(new { controller = "Home", action = "Index", id = "MyID" });

}

This method also returns a RedirectToRouteResult object and has exactly the same effect as calling the RedirectToAction method.

Generating a URL from a Specific Route

We have specified a name for each route we have defined in this chapter. For example, when we define a routes like this:

routes.MapRoute("MyRoute", "{controller}/{action}");

routes.MapRoute("MyOtherRoute", "App/{action}", new { controller = "Home" });

the routes we create are assigned the names we pass as the first parameter to the

MapRoute method– in this case, MyRoute and MyOtherRoute. There are two reasons for naming your routes – the first is as a reminder as to the purpose of the route. The second is so that you can select a specific route to be used to generate an outgoing URL.

We have arranged the routes so that the least specific appears first in the list – this means that if we were to generate a link using the ActionLink method like this:

@Html.ActionLink("Click me", "About");

the outgoing URL would always be generated using MyRoute. We can override the default route matching behavior by using the Html.RouteLink method, which lets us specify which route we want to use, like this:

@Html.RouteLink("Click me", "MyOtherRoute", new { action = "About" });

We can generate just the URL by using the Url.RouteUrl method. This feature can be useful if you don’t want to worry about ordering your routes.

Một phần của tài liệu Giáo trình lập trình ASP.NET Apress pro ASP NET MVC3 framework pre release (Trang 334 - 339)

Tải bản đầy đủ (PDF)

(603 trang)