Thư viện tri thức trực tuyến
Kho tài liệu với 50,000+ tài liệu học thuật
© 2023 Siêu thị PDF - Kho tài liệu học thuật hàng đầu Việt Nam

Pro ASP.NET MVC Framework phần 6 pps
Nội dung xem thử
Mô tả chi tiết
public class PermanentRedirectToRouteResult : ActionResult
{
public RedirectToRouteResult Redirection { get; private set; }
public PermanentRedirectToRouteResult(RedirectToRouteResult redirection)
{
this.Redirection = redirection;
}
public override void ExecuteResult(ControllerContext context)
{
// After setting up a normal redirection, switch it to a 301
Redirection.ExecuteResult(context);
context.HttpContext.Response.StatusCode = 301;
}
}
}
Whenever you’ve imported this class’s namespace, you can simply add
.AsMovedPermanently() to the end of any redirection:
public ActionResult MyActionMethod()
{
return RedirectToAction("AnotherAction").AsMovedPermanently();
}
Search Engine Optimization
You’ve just considered URL design in terms of maximizing usability and compliance with
HTTP conventions. Let’s now consider specifically how URL design is likely to affect search
engine rankings.
Here are some techniques that can improve your chances of being ranked highly:
• Use relevant keywords in your URLs: /products/dvd/simpsons will score more points
than /products/293484.
• As discussed, minimize your use of query string parameters and don’t use underscores
as word separators. Both can have adverse effects on search engine placement.
• Give each piece of content one single URL: its canonical URL. Google rankings are
largely determined by the number of inbound links reaching a single index entry, so
if you allow the same content to be indexed under multiple URLs, you risk spreading
out the “weight” of incoming links between them. It’s far better to have a single highranking index entry than several low-ranking ones.
If you need to display the same content on multiple URLs (e.g., to avoid breaking old
links), then redirect visitors from the old URLs to the current canonical URL via an
HTTP 301 (moved permanently) redirect.
• Obviously, your content has to be addressable, otherwise it can’t be indexed at all. That
means it must be reachable via a GET request, not depending on a POST request or any
sort of JavaScript-, Flash-, or Silverlight-powered navigation.
CHAPTER 8 ■ URLS AND ROUTING 257
10078ch08.qxd 3/16/09 12:40 PM Page 257
SEO is a dark and mysterious art, because Google (and the other search engines, as if anyone cares about them) will never reveal the inner details of their ranking algorithms. URL
design is only part of it—link placement and getting inbound links from other popular sites is
more critical. Focus on making your URLs work well for humans, and those URLs will tend to
do well with search engines, too.
Summary
You’ve now had a close look at the routing system—how to use it, and how it works internally.
This means you can now implement almost any URL schema, producing human-friendly
and search engine–optimized URLs, without having to hard-code a URL anywhere in your
application.
In the next chapter, you’ll explore the heart of the MVC Framework itself, gaining
advanced knowledge of controllers and actions.
258 CHAPTER 8 ■ URLS AND ROUTING
10078ch08.qxd 3/16/09 12:40 PM Page 258
Controllers and Actions
Each time a request comes in to your ASP.NET MVC application, it’s dealt with by a controller. The controller is the boss: it can do anything it likes to service that request. It can issue
any set of commands to the underlying model tier or database, and it can choose to render
any view template back to the visitor. It’s a C# class into which you can add any logic needed
to handle the request.
In this chapter, you’ll learn in detail how this centerpiece of the MVC Framework operates, and what facilities it offers. We’ll start with a quick discussion of the relevant architectural
principles, and then look at your options for receiving input, producing output, and injecting
extra logic. Next, you’ll see how as an advanced user you can customize the mechanisms for
locating and instantiating controllers and invoking their action methods. Finally, you’ll see
how all of this design fits neatly with unit testing.
An Overview
Let’s recap exactly what role controllers play in MVC architecture. MVC is all about keeping
things simple and organized via separation of concerns. In particular, MVC aims to keep separate three main areas of responsibility:
• Business or domain logic and data storage (model)
• Application logic (controller)
• Presentation logic (view)
This particular arrangement is chosen because it works very well for the kind of business
applications that most of us are building today.
Controllers are responsible for application logic, which includes receiving user input,
issuing commands to and retrieving data from the domain model, and moving the user
around between different UIs. You can think of controllers as a bridge between the Web and
your domain model, since the whole purpose of your application is to let end users interact
with your domain model.
Domain model logic—the processes and rules that represent your business—is a separate
concern, so don’t mix model logic into your controllers. If you do, you’ll lose track of which
code is supposed to model the true reality of your business, and which is just the design of the
259
CHAPTER 9
10078ch09.qxd 3/26/09 12:11 PM Page 259
web application feature you’re building today. You might get away with that in a small application, but to scale up in complexity, separation of concerns is the key.
Comparisons with ASP.NET WebForms
There are some similarities between ASP.NET MVC’s controllers and the ASPX pages in traditional WebForms. For example, both are the point of interaction with the end user, and both
hold application logic. In other ways, they are conceptually quite different—for example,
You can’t separate a WebForms ASPX page from its code-behind class—the two only work
together, cooperating to implement both application logic and presentation logic (e.g.,
when data-binding), both being concerned with every single button and label. ASP.NET
MVC controllers, however, are cleanly separated from any particular UI (i.e., view)—they
are abstract representations of a set of user interactions, purely holding application logic.
This abstraction helps you to keep controller code simple, so your application logic stays
easier to understand and test in isolation.
WebForms ASPX pages (and their code-behind classes) have a one-to-one association
with a particular UI screen. In ASP.NET MVC, a controller isn’t tied to a particular view,
so it can deal with a request by returning any one of several different UIs—whatever is
required by your application logic.
Of course, the real test of the MVC Framework is how well it actually helps you to get your
job done and build great software. Let’s now explore the technical details, considering exactly
how controllers are implemented and what you can do with one.
All Controllers Implement IController
In ASP.NET MVC, controllers are .NET classes. The only requirement on them is that they must
implement the IController interface. It’s not much to ask—here’s the full interface definition:
public interface IController
{
void Execute(RequestContext requestContext);
}
The “hello world” controller example is therefore
public class HelloWorldController : IController
{
public void Execute(RequestContext requestContext)
{
requestContext.HttpContext.Response.Write("Hello, world!");
}
}
If your routing configuration includes the default Route entry (i.e., the one matching
{controller}/{action}/{id}), then you can invoke this controller by starting up your application (press F5) and then visiting /HelloWorld, as shown in Figure 9-1.
260 CHAPTER 9 ■ CONTROLLERS AND ACTIONS
10078ch09.qxd 3/26/09 12:11 PM Page 260
Figure 9-1. Output from HelloWorldController
Hardly impressive, but of course you could put any application logic into that Execute()
method.
The Controller Base Class
In practice, you’ll very rarely implement IController directly, or write an Execute() method.
That’s because the MVC Framework comes with a standard base class for controllers,
System.Web.Mvc.Controller (which implements IController on your behalf). This is much
more powerful than a bare-metal IController—it introduces the following facilities:
Action methods: Your controller’s behavior is partitioned into multiple methods (instead
of having just one single Execute() method). Each action method is exposed on a different URL, and is invoked with parameters extracted from the incoming request.
Action results: You have the option to return an object describing the intended result of an
action (e.g., rendering a view, or redirecting to a different URL or action method), which is
then carried out on your behalf. The separation between specifying results and executing
them simplifies automated testing considerably.
Filters: You can encapsulate reusable behaviors (e.g., authentication or output caching) as
filters, and then tag each behavior onto one or more controllers or action methods by
putting an [Attribute] in your source code.
This chapter covers all of these features in more detail. Of course, you’ve already seen and
worked with many controllers and action methods in earlier chapters, but to illustrate the preceding points, consider this:
[OutputCache(Duration=600, VaryByParam="*")]
public class DemoController : Controller
{
public ViewResult ShowGreeting()
{
ViewData["Greeting"] = "Hello, world!";
return View("MyView");
}
}
CHAPTER 9 ■ CONTROLLERS AND ACTIONS 261
10078ch09.qxd 3/26/09 12:11 PM Page 261
This simple controller class, DemoController, makes use of all three features mentioned
previously.
Since it’s derived from the standard Controller base class, all its public methods are
action methods, so they can be invoked from the Web. The URL for each action method is
determined by your routing configuration. With the default routing configuration, you
can invoke ShowGreeting() by requesting /Demo/ShowGreeting.
ShowGreeting() generates and returns an action result object by calling View(). This particular ViewResult object instructs the framework to render the view template stored at
/Views/Demo/MyView.aspx, supplying it with values from the ViewData collection. The view
will merge those values into its template, producing and delivering a finished page of HTML.
It has a filter attribute, [OutputCache]. This caches and reuses the controller’s output
for a specified duration (in this example, 600 seconds, or 10 minutes). Since the attribute
is attached to the DemoController class itself, it applies to all action methods on
DemoController. Alternatively, you can attach filters to individual action methods, as
you’ll learn later in the chapter.
■Note When you create a controller class by right-clicking your project name or the /Controllers
folder and choosing Add ➤ Controller, Visual Studio creates a class that inherits from the System.Web.
Mvc.Controller base class. If you prefer, you can just manually create a class and make it inherit from
System.Web.Mvc.Controller.
As with so many programming technologies, controller code tends to follow a basic pattern
of input ➤ process ➤ output. The next part of this chapter examines your options for receiving
input data, processing and managing state, and sending output back to the web browser.
Receiving Input
Controllers frequently need to access incoming data, such as query string values, form values,
and parameters parsed from the incoming URL by the routing system. There are three main
ways to access that data. You can extract it from a set of context objects, or you can have the
data passed as parameters to your action method, or you can directly invoke the framework’s
model binding feature. We’ll now consider each of these techniques.
Getting Data from Context Objects
The most direct way to get hold of incoming data is to fetch it yourself. When your controllers are
derived from the framework’s Controller base class, you can use its properties, including Request,
Response, RouteData, HttpContext, and Server, to access GET and POST values, HTTP headers,
cookie information, and basically everything else that the framework knows about the request.1
1. All these properties are merely shortcuts into the ControllerContext property. For example, Request is
equivalent to ControllerContext.HttpContext.Request.
262 CHAPTER 9 ■ CONTROLLERS AND ACTIONS
10078ch09.qxd 3/26/09 12:11 PM Page 262