Tải bản đầy đủ - 0 (trang)
Chapter 42: ASP.NET Dynamic Data and MVC

Chapter 42: ASP.NET Dynamic Data and MVC

Tải bản đầy đủ - 0trang


ChaPTer 42 Asp.net dynAmic dAtA And mvc

Both dynamic data and MVC make use of another methodology that was introduced in .NET 3.5, routing.

This makes it possible for URLs to be simplified and to include additional information, and is the fi rst thing

you will look at in this chapter. After routing, this chapter moves on to dynamic data and MVC in turn,

with a fi nal section about how to combine these technologies.

Both dynamic data and MVC are large subjects to cover and would require multiple

chapters to cover in depth. This chapter gives a general overview of using these

frameworks, which will hopefully give you enough information to get started before

fi nding more in - depth resources if you want to use them in more depth.


ASP.NET routing is a technology that enables you to assign sensible, human-readable URLs to web pages.

Essentially, this means that the URL for a web page that a user sees in the address bar of a browser doesn’t

necessarily match the physical location of a web page. Instead, the URL will include information that your

web site can use to map to a page that you defi ne, and can pass parameters to that page.

At fi rst glance, this may seem a little counterintuitive. Why wouldn’t you want users to see the address of

a web page? Surely not exposing this information will make it more difficult to locate resources. In fact,

as you will see in this section, mapping URLs can make it much easier for users, and it has several other

benefits as well.

As an example, consider the following URL:


Without knowing anything about the web site that uses this URL, you can probably take a good guess at

what you’d fi nd on the page. From the words in the URL, you would expect to see a product page for a kite

called “Red Dragon.”

The advantages of this type of URL are as follows:

Users can see at a glance what pages are.

URLs are easy for users to remember, even without creating bookmarks.

Users can modify URLs manually to navigate (for example, a user might replace the last section of the

above URL with /products/balloons).

Search engine results are optimized for these descriptive URLs, so the page ranking will be higher.

There are essentially two ways to implement URLs of this form. You can either create a page for every possible URL, or you can use a framework that maps URLs to pages that can display data for multiple URLs.

This fi rst possibility is worth mentioning, as it isn’t necessarily out of the question — it is possible

to create static HTML sites that are generated from back- end data. However, this requires a fair amount of

maintenance and, in most situations, can be more trouble than it’s worth. Now that the tools have matured

the second scenario is more practical.

In fact, ASP.NET has included the capability to use URLs like this for some time, although “URLrewriting” (as it was known in earlier versions of ASP.NET) required an in-depth knowledge of the ASP

.NET architecture and could be quite tricky to implement. With the advent of ASP.NET routing, things

have become much easier.

In this section, you will look at the following:

Query string parameters — Before looking at routing specifically, it is worth understanding the case

for including additional data in URLs in more detail. Query string parameters provide an alternative

way of doing this, and have existed since the very beginnings of the web. However, while simpler than

routing, they do not include all of the advantages.



❘ 1245

Defining routes — ASP.NET routing requires you to define the routes that are available in your web

site so that they can be used.

Using route parameters — Once a route has been detected in a URL, the target page can make use of

routing parameters.

The downloadable code for this chapter includes a simple solution called PCSRoutingDemo that will be

referred to from this section to illustrate the techniques.

query string Parameters

While surfing the web, you’ve probably noticed that a lot of web pages include information in their URLs in

addition to their location. For example, in an e-commerce web site, you might see a URL that looks a little

like the following:


In this URL the target page is products.aspx, but after the identifier for this page, you can see additional

information in the form of a query string. The ? character indicates the start of the query string, and the

remainder of the URL consists of a name/value pair, with an equals character (=) separating the name (id)

from the value (4). In fact, URLs can contain several query string name/value pairs, separated by & symbols.

When users navigate to an ASP.NET page with a query string (perhaps by clicking on a link that you have

rendered from database data), you can write code to render the page accordingly. In this example, you

might use the value of the id query string parameter to extract data from a database, for a product with the

corresponding ID. This means that you don’t have to create a page for every product in your database; you

can, instead, create a single page that can show the details for any product.

In practice, ASP.NET pages receive query string information in the form of a NameValueCollection object.

This is passed in the QueryString property of the HttpRequest object that is available in code-behind

through the inherited Request property. The query string collection is indexed by name and index, so to get

the value of the id query string parameter shown above, you could use either of the following lines of code:

string idValue = Request.QueryString[0];


string idValue = Request.QueryString["id"];

Note that all query string values are passed as strings, so to get an integer value for id you’d need to parse

the value.

The use of query string parameters is illustrated in the PCSRoutingDemo web site for this chapter. If you

view the web site in a browser and click the “Navigation with query string” link, you will see the query

string parameters displayed, as shown in Figure 42-1.

figure 42-1



ChaPTer 42 Asp.net dynAmic dAtA And mvc

The code that displays these values is in the code-behind for the master page and is as follows:

if (Request.QueryString.Count == 0)


this.NoQuerystringLabel.Text = "None.";




GridView1.DataSource = from string key in Request.QueryString.Keys




Name = key,

Value = Request.QueryString[key]




code snippet PCSRoutingDemo/MasterPage.master.cs

Here, the collection of query string parameters is transformed into a collection of objects with Name and

Value properties that can be data bound to a GridView control and displayed.

This method of passing data with query string parameters is well established and extremely useful, but ASP

.NET routing achieves the same results in a much neater way, with all of the advantages.

defining routes

In order to use ASP.NET routing, you need to configure the routes that are available in your web site. Once

you have done this, typically in the HttpApplication.Application_Start event handler, users will be

able to use those routes and your web site can make use of the parameters passed.

A route definition consists of the following:

A name for the route (which can be omitted)

A URL pattern for the route, including parameter specifications where required

A handler for the route, which determines which target URL the route is mapped to

An optional collection of default values to use for route parameters if they are not included in the URL

An optional collection of constraints for parameters, which are used to determine if a route is valid

As you might expect, ASP.NET includes classes that make it easy to specify all of this.

An ASP.NET web site maintains a collection of route specifications that are checked when a URL

is requested to see if there is a match. This collection is accessible in your code through the static

RouteTable.Routes property. This property is a collection of routes defined by an optional name and an

object that derives from the abstract RouteBase class. Unless you want to create your own class to represent

a route, you can add instances of the Route class to this collection.

The Route class has a number of constructors that you can use to define a route, the simplest of which

includes a path and a route handler. The path is specified as a string, with parameters included and

delimited with curly braces. The route handler is an object that implements the IRouteHandler interface,

such as the system-defined PageRouteHandler class. When instantiating PageRouteHandler you specify a

target page path, and, optionally, whether to check the physical path for authorization with the ASP.NET

security model (more on this later). The simplest way to add a route is, therefore, as follows:


new Route("path/{pathparameter}",

new PageRouteHandler("target.aspx")));

Here, a route called RouteName is added to the route definitions. This route matches URLs of the form:




❘ 1247

Any matching URLs will be mapped to the target.aspx file.

For example, if a user requested the following URL:


The web site would detect this as a matching URL for the RouteName route, and the user would be

redirected to the target.aspx page. If the code for this page requested the value of the pathparameter

parameter, it would receive the value oranges.

In the sample PCSRoutingDemo web site for this chapter, you can see a route in action by clicking the

“Navigation with routing” link, which results in the display shown in Figure 42-2.

figure 42-2

This route is defined in Global.cs in App_Code (the code-behind file used for Global.asax) as follows:


new Route("Target/{targetparameter}",

new PageRouteHandler("~/Target.aspx")));

code snippet PCSRoutingDemo/App_Code/Global.cs

You’ll see how the parameter is rendered on the page shortly.

route authorization

Since there are effectively two URLs taking part in routing — the one requested by the user and the one that

is used for the physical file location that generates the page — ASP.NET authorization can take place in two

places. The default behavior is to check both of these URLs to determine whether the user has access to the

page. You can override this in the constructor for PageRouteHandler with a second parameter as follows:


new Route("path/{pathparameter}",

new PageRouteHandler("~/target.aspx", false)));

If you do this, then only the requested URL will be checked for authorization, not the physical URL. By

doing this, you can place the physical URL in a location that is not directly accessible to the user, which can

be useful if you want to prevent direct navigation to that URL.

Default Parameter Values

The default behavior for routes is that all parameters must be specified in order to match the requested URL

to a route path. In the preceding example, this means that the following URL is invalid:




ChaPTer 42 Asp.net dynAmic dAtA And mvc

However, you can if you wish specify default values for route parameters, in which case this URL would be

valid and the default value for pathparameter would be used.

To do this, you supply a RouteValueDictionary collection, which is a collection of name/value pairs of

route parameters and default values. You can pass this collection to the Route constructor; for example:


new Route("path/{pathparameter}",

new RouteValueDictionary


{ "pathparameter", "defaultValue" }


new PageRouteHandler("~/target.aspx")));

In this code a default value of defaultvalue is specified for the pathparameter parameter, which will be

used if no value is matched in the URL.

Parameter Constraints

Route parameters will accept any value from the user by default, but sometimes you might want to restrict

the allowed values. Then, if the user passes a value that isn’t allowed, the path will not match.

Parameter constraints are also defined with a RouteValueDictionary collection, in this case containing

a collection of name/value pairs of route parameters and constraints. A constraint can either be a regular

expression or an object that implements the IRouteConstraint interface. As with defaults, constraints can

be specified in the Route constructor, for example:


new Route("path/{pathparameter}",

new RouteValueDictionary


{ "pathparameter", "yes" }


new RouteValueDictionary


{ "pathparameter", "yes|no" }


new PageRouteHandler("~/target.aspx")));

Here, only the values yes and no are valid values for pathparameter. If a different value is specified the

route won’t be matched.

route order and Data Tokens

When you define routes, the order in which you add them to the RouteTable.Routes collection is

important. This is because ASP.NET will attempt to match URLs to routes in the order that they appear in

the collection. If no match is found after looking at all the routes, then the URL is used directly. If a single

match is found, then that route is used. If more than one route matches the URL, then the first one is used.

This can be used to good effect in combination with constraints. For example, you could add two routes,

the first being the constrained route shown in the previous section, and the second as follows:


new Route("path/{pathparameter}",

new PageRouteHandler("~/alternatetarget.aspx")));

This would mean that a URL containing a pathparameter value of yes or no would map to target

.aspx as before, but if any other parameter value was passed, then the URL would map instead to

alternatetarget.aspx, rather than returning a 404 not found error.

However, if these two routes were added in reverse order, then all values of pathparameter would result in

a call to alternatetarget.aspx, as this route would always provide a match before the constrained route

was checked.



❘ 1249

If you have two routes that map to the same URL, you may want to determine which route was matched. To

do so, you can include additional data that is passed to the page as a data token. Data tokens are supplied

with another RouteValueDictionary collection, containing a collection of name/value pairs of route

parameters and data tokens. For example:


new Route("path/{pathparameter}",

new RouteValueDictionary


{ "pathparameter", "yes" }


new RouteValueDictionary


{ "pathparameter", "yes|no" }


new RouteValueDictionary


{ "customdatatoken", "yesnomatch" }


new PageRouteHandler("~/target.aspx")));

If this route is matched a data token called customdatatoken with a string value of yesnomatch is passed

to the target URL, so that pages can identify that this route was used.

You can pass whatever data you like as a data token for a parameter, so this is only one example of how you

might use it.

using route Parameters

Reading and using parameter values that are passed to pages through ASP.NET routing is very similar

to doing the same for query string parameters. Instead of using Request.QueryString, you use Page

.RouteData, which is populated by ASP.NET when your page is loaded. This contains all of the

information you need to extract route parameters or data tokens.

Parameter values are also available for use in ASP.NET markup, through expression builders and data query

parameter values.

routeData Values

The route parameters are available in code through the Page.RouteData.Values property, which is

another instance of the RouteValueDictionary class. Similarly, data tokens are available through Page

.RouteData.DataTokens. In the example web site, values are extracted from the Values property and

displayed through a DataGrid with the following code:

if (Page.RouteData.Values.Count == 0)


this.NoRoutingLabel.Text = "None.";




GridView2.DataSource = from entry in Page.RouteData.Values




Name = entry.Key,

Value = entry.Value




code snippet PCSRoutingDemo/MasterPage.master.cs



ChaPTer 42 Asp.net dynAmic dAtA And mvc

Alternatively, you can extract parameters by name as they are indexed in the collection; for example:

string parameterValue = Page.RouteData.Values["pathparameter"] as string;

expression Builders

There are two expression builders that you can use in ASP.NET markup files to extract and use route

parameter values: RouteValue and RouteUrl.

RouteValue can be used inline to output the value of a parameter, as follows:

<%$ RouteValue:parameterName %>

For example, in the PCSRoutingDemo web site, the Target.aspx file includes the following line of markup code:

targetparameter =
Text="<%$ RouteValue:targetparameter %>" />

code snippet PCSRoutingDemo/Target.aspx

This sets the Text property of a Label control to the value of the targetparameter parameter.

RouteUrl is used to construct URLs to match a route. This is a great feature when you are putting links in

your ASP.NET code, as a URL created in this way will change if the route definition ever changes. To use

this expression builder, you use markup inline as follows:

<%$ RouteUrl:parameterName=parameterValue %>

You can include more than one parameter by separating name/value pairs with commas. The expression

builder will attempt to match the parameters you specify to a route by the names of the parameters you use.

In some cases, you might have more than one route that uses the same parameters, in which case you can

identify the specific route to use by name as follows:

<%$ RouteUrl:parameterName=parameterValue,routename=routeName %>

In PCSRoutingDemo, there are two separate links in the master page, one of which uses this expression builder:

>Navigation with routing

NavigateUrl="<%$ RouteUrl:targetparameter=Reginald,routename=TestRoute %>"

>Navigation with routing and expression builder

code snippet PCSRoutingDemo/MasterPage.master

The second version of this link shows the best way to include links in your markup, as it allows you to

change the route specification later, as noted above.

Data Query Parameters

Another way to use route parameters in your code is to supply them directly to data queries. This technique

enables you to fetch data from a database directly from markup code, rather than having to extract

parameter values and use them in the code-behind.

To do this, you use an in the parameters for a query. For example, you could use

the following in an data source:

connectionstring="<%$ ConnectionStrings:ProductDatabase %>"

selectcommand="SELECT ProductName,ProductId,ProductDescription FROM Products

WHERE ProductName = @productname"


Dynamic Data

❘ 1251

This code extracts the value from a route parameter called productnameparameter and passes this value to

the @productname parameter in a SQL query.

dynamiC daTa

If you think about data-driven web sites (which these days includes most web sites), you will probably

realize that a lot of their functionality is very similar. Such a web site is likely to include one or more of the

following concepts:

Render HTML that is shaped dynamically based on data in an underlying data source (such as

a database table or individual database row)

Include pages in a site map that map directly or indirectly to entries in a data source (such as a

database table)

Have a structure that relates directly or indirectly to the structure of the underlying data source

(a section of the site may map to a database table, such as About or Products, for example)

Allow modification to the underlying data source that will be reflected on pages

If you wanted to build a data-driven site, you would probably use fairly standardized code to achieve the

above. You might bind ASP.NET elements such as tables of data directly to a database table, or you might

include an intermediate layer of data objects to represent data in the database and bind to those. You have

seen a lot of the code you would use for that in earlier chapters.

However, because this situation is so common, there is an alternative. You could instead use a framework

that provides a lot of the code for you to save yourself a lot of tedious coding. ASP.NET dynamic data is just

such a framework, and it makes creating a data-driven web site much easier. As well as giving you the code

outlined above (referred to in dynamic data web sites as scaffolding), dynamic data web sites provide a lot of

additional functionality, as you will see shortly.

In this section, you will see how to create a dynamic data site and look at some of the features that it offers.

Creating dynamic data Web sites

The best way to get a taste of what dynamic data web

sites have to offer is to build one in Visual Studio, which

is a surprisingly simple thing to do. In order to create

a dynamic data web site you need to have some source

data. You can use whatever data you like, but if you

want you can use the sample data that is included in the

downloadable code for this chapter. This data is a SQL

Server Express database with the filename MagicShop

.mdf. Figure 42-3 shows the tables that are included in

this database.

The MagicShop.mdf database represents a simple

structure that you could use in an e-commerce web site.

The types of and relationships between data will serve

to illustrate how dynamic data sites work.

figure 42-3

Choosing a Data access Model

When you create a dynamic data site through the File ➪ New ➪ Web Site… menu item, you will notice that

there are two templates available:

Dynamic Data Linq to SQL Web Site

Dynamic Data Entities Web Site



ChaPTer 42 Asp.net dynAmic dAtA And mvc

These two templates are identical, apart from the way your data will be accessed: through LINQ to SQL or

the ADO.NET Entity Framework, respectively. Which of these templates you choose depends entirely on

personal preference. The core functionality of a dynamic data web site is the same for both templates.

The downloadable code for this chapter includes two web sites, PCSDynamicDataDemoLinq and PCSDynamic

DataDemoEntities, that contain uncustomized versions of sites that use the MagicShop.mdf database.

adding a Data source

Once you have created a site using either of the templates that are available, the next thing to do is to add

a data source. This means adding a new item to your project, using either the LINQ to SQL classes or

ADO.NET Entity Model template (either of which should be added to the App_Code directory of a web

site as a best practice). Before you do that, you may also want to add a local copy of your database to the

App_Data directory of your web site, unless you are using a remote data source.

If you are using the MagicShop.mdf database as a test, then depending on the site template you are using,

you can do the following (after adding the database to the App_Data directory):

For LINQ to SQL, add LINQ to SQL classes with the filename MagicShop.dbml, and then once the

file is added, add all tables from the MagicShop.mdf database to the designer.

For ADO.NET Entities, add an entity model called MagicShop.edmx, and in the Add New Item

Wizard, use the default settings and add entities for all tables in the database.

Configuring scaffolding

There is one more step to perform before the initial build of your dynamic data web site is complete.

You must configure your data model for scaffolding in the Global.asax file for the web site. Apart from

differences in explanatory comments, this file is identical in both site template types. If you inspect the file,

you will see that scaffolding for the web site is configured through a model, which is defined at

the application level as follows:

private static MetaModel s_defaultModel = new MetaModel();

public static MetaModel DefaultModel




return s_defaultModel;



The Global.asax file accesses this model in the RegisterRoutes() method, called in the Application_

Start() handler. This method also configures dynamic data routing in the web site, which you’ll look at

later in this chapter. The method contains the following commented-out line of code (split over two lines

here for clarity):



new ContextConfiguration() { ScaffoldAllTables = false });

Configuring the model simply requires you to uncomment this code and supply the appropriate data context

type for your data model. You can also change the ScaffoldAllTables property to true initially to

instruct the model to provide scaffolding for all available tables. Later, you may want to revert this change,

as you will probably want a finer degree of control over exactly what scaffolding is created (including what

data is visible in the site, what is editable, and so on), as you will see later in this chapter.

The following code is required for a LINQ to SQL site accessing the MagicShop.mdf database with the

LINQ to SQL classes as described in the previous section:


new ContextConfiguration() { ScaffoldAllTables = true });

code snippet PCSDynamicDataDemoLinq/Global.asax


Dynamic Data

❘ 1253

For the ADO.NET Entities version of this site, the code is as follows:


new ContextConfiguration() { ScaffoldAllTables = true });

code snippet PCSDynamicDataDemoEntities/Global.asax

exploring the result

At this point, everything is in place to test the default dynamic data web sites. The end result is identical

regardless of which template you use. If you look at Default.aspx in a browser, the display appears as

shown in Figure 42-4.

figure 42-4

This page shows a list of links to each of the tables in the database along with some additional information,

defined in the Default.aspx page as follows:

<%@ Page Language="C#" MasterPageFile="~/Site.master" CodeFile="Default.aspx.cs"

Inherits="_Default" %>


My tables

CssClass="DDGridView" RowStyle-CssClass="td" HeaderStyle-CssClass="th"



Eval("DisplayName") %>



ChaPTer 42 Asp.net dynAmic dAtA And mvc

code snippet PCSDynamicDataDemoEntities/Default.aspx and PCSDynamicDataDemoLinq/Default.aspx

A lot of the display code is contained in the master page and the CSS file for the web site, which won’t

be listed here to save space. The important section of the preceding code is the GridView control, which

contains a DynamicHyperLink control that renders the link to a table. Data is bound to the GridView

control from code-behind as follows (reformatted slightly for clarity):

protected void Page_Load(object sender, EventArgs e)


System.Collections.IList visibleTables =


if (visibleTables.Count == 0)


throw new InvalidOperationException(

"There are no accessible tables. Make sure that at least one data"

+ " model is registered in Global.asax and scaffolding is enabled"

+ " or implement custom pages.");


Menu1.DataSource = visibleTables;



code snippets PCSDynamicDataDemoEntities/Default.aspx.cs and PCSDynamicDataDemoLinq/Default.aspx.cs

This extracts the list of visible tables from the model (in this case, all the tables, because scaffolding is

provided for all of them as discussed earlier), each of which is described by a MetaTable object. The

DynamicHyperLink controls intelligently render links to pages for the tables based on properties of these

objects. For example, the link for the Customers table is as follows:


Obviously, the web site has no such page defined; instead, routing is used as described in the first part of this

chapter to generate content for this link. If you click on the link, you’ll see a listing page for the Customers

table, as shown in Figure 42-5.

figure 42-5


Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Chapter 42: ASP.NET Dynamic Data and MVC

Tải bản đầy đủ ngay(0 tr)