WHAT’S IN THIS CHAPTER?
WROX.COM CODE DOWNLOADS FOR THIS CHAPTER
Please note that all the code examples in this chapter are available as a part of this chapter’s code download on the book’s website at www.wrox.com on the Download Code tab.
ASP.NET offers a feature that enables you to dynamically create data-driven web applications. ASP.NET Dynamic Data is more than purely a code generator, and although it can provide a base application, it is completely modifiable by you. This feature allows you to quickly and easily create data entry or applications that allow your end users to work with and view the backend database.
You can also easily integrate Dynamic Data into your applications and build a rich UI layer that’s driven by model binding and data annotation attributes.
This chapter illustrates how to build an ASP.NET Dynamic Data application and use the Dynamic Data features with model binding.
ASP.NET Dynamic Data’s capabilities were introduced with the .NET Framework 3.5 SP1. They have since been enhanced to work with Entity Framework in .NET Framework 4.5. To get started you can create a new Dynamic Data Entities Web Site project.
Visual Studio 2012 will create a base application that is not connected to any database or object model from the start. It’s your job to make these connections. Before doing this, however, take a look at what Visual Studio has created for you.
Before you even assign the pre-generated Dynamic Data application to a database, much of the core application is created for you through the Visual Studio process just mentioned.
The items that are generated for you and what is presented here in the Visual Studio Solution Explorer are generally referred to as scaffolding. Even though a lot of code seems to be generated for you, rest assured you are not locked into a specific data-driven application. What is generated is termed “scaffolding” because it is a framework that can be taken holistically or modified and extended for any purpose. This framework is the presentation and database layer support that you will need for the autogeneration of your application. You are in no way locked into a specific set of models, looks-and-feels, or even an approach that you are unable to modify to suit your specific needs.
Even though you will find a lot of pre-generated code in your Solution Explorer, you are not even required to use this code to work with ASP.NET Dynamic Data. In fact, you can even add ASP.NET Dynamic Data to preexisting applications and you don’t have to start from the ASP.NET Dynamic Data project template.
Next, this chapter looks at the pre-generated application that enables you to work with your backend database.
One of the biggest additions to this application operation that is dramatically different from the standard ASP.NET application is a folder called DynamicData. This folder contains the pre-generated ASP.NET application that enables you to work with your database through a browser.
The goal of this application is to enable you to work with your database through the entire CRUD process (Create, Read, Update, and Delete). Again, you can limit the amount of interactivity you provide from your application.
To view how this application works against a database, you must dig further into the controls and pages that make up the application. Expanding the DynamicData folder, you find the following folders:
In addition to these folders, you will find a web.config file that is specific to this application.
The Content folder in this part of the application includes a user control that is used in the Page Templates, as well as the underlying images that are used by the style sheet of the application.
The CustomPages folder is a separate folder that allows you to put any custom pages that you might include in the data-driven web application. When you create an application from scratch, you will not find any file in this folder. It is intentionally blank.
The EntityTemplates folder makes getting the layout you want quite easy, thereby not requiring you to build a custom page. Initially, there is a Default.ascx (user control), and the edit and insert versions of this control are found in the folder.
The FieldTemplates folder is interesting because it has some of the more granular aspects of the application. The entire application is designed to work off a database, but it really does not have any idea what type of database it is going to be working from. The FieldTemplates folder is a way that the application can present any of the underlying data types that are coming from the database.
The Filters folder is used to create drop-down menus for Booleans (true/false values), foreign keys, and enumerations. These menus enable the end user to filter tables based upon keys within the database.
The PageTemplates folder contains the core pages that you use to bring the application together. Notice that pages exist for many of the core constructs that you will use in representing your tables in the application. The PageTemplates folder includes the following pages:
You use the List.aspx page for the tables in your connected database. You use the Details.aspx pages when you are examining a single row from the table, and you use the ListDetails.aspx page for examining master details views of the table and row relationships. You use the Edit.aspx and Insert.aspx pages, in turn, for the types of operations that they describe.
The Global.asax file has the definition of all the routes used by the Dynamic Data application. This means that you can change the URLs without changing the page contents. Since the routes are generic, they work for all the tables in the application.
You can use Data Annotations to customize the column names that will be displayed on the UI and also use them to add validation to the column names being inputted by the users. You’ll learn about this in more detail when you read about model binding later in this chapter.
Once the DynamicDataWebSite is created, you need to incorporate a database that you are able to work with. For this example, you need to include the Northwind database. After the database is in place, the next step is to establish a defined entity data model layer that will work with the underlying database.
You can register the NorthwindEntities object in the overall solution. NorthwindEntities is the data model that was built using the LINQ to Entities. You register this NorthwindEntities context in the Global.asax file, which was created with the project. Listing 12-1 shows how to register the context in Global.asax.
LISTING 12-1: Registering the context in Global.asax
VB
DefaultModel.RegisterContext(GetType(NORTHWNDModel.NORTHWNDEntities),
New ContextConfiguration() With {.ScaffoldAllTables = true})
C#
DefaultModel.RegisterContext(typeof(NORTHWNDModel.NORTHWNDEntities),
new ContextConfiguration() { ScaffoldAllTables = true });
The model is registered as a DataContext object of type NorthwindEntities, and the ScaffoldAllTables property is set to True (the default is set to False), signifying that you want all the table representations in the model to be included in the generated application.
As you run the application, notice that the first page allows you to see all the tables that you made a part of your data model, as illustrated in Figure 12-1.
As an application that reads the contents of your database, it works quite simply. Clicking a table name (which is a hyperlink in the application) provides the contents of the table. Figure 12-2 shows this view.
The table view is nicely styled and includes the ability to edit, delete, or view the details of each row in the database. In cases where a one-to-many relationship exists, you can drill down deeper into it. Another interesting part of the page is the navigation through the table. Pagination appears through the table, as shown at the bottom of the table in Figure 12-2.
In addition to using the edit, delete, or detail view of the row of information in the table, you can insert new rows into the database by clicking the Insert New Item link below the table. A view similar to that shown in Figure 12-3 appears.
Editing a row makes the same type of page appear, as shown in Figure 12-4. This page resulted from clicking the Edit link next to one of the rows in the Territories table.
Another interesting aspect of this application is how it works with the one-to-many relationships of the elements in the data model. For example, clicking the Orders table link produces the view shown in Figure 12-5.
Here, in addition to the table and its contents, you are presented with a filtering capability via the various drop-down menus at the top of the page. In this case, you can filter the orders by customer, employee, or shipper. You can even use a combination of these elements to filter items. The other aspect to notice in Figure 12-5 about the contents of the table is that instead of a CustomerID, an EmployeeID, or a ShipperID, you see the names of these items, and the application is making the reference to the identifier for these items when drilling further into the views.
The final aspect to understand about this application is that because it is an ASP.NET 4 application, it makes proper use of AJAX. For example, when filtering items in the table, notice that the page makes partial refreshes without refreshing the entire page.
When ASP.NET Dynamic Data was introduced with the .NET Framework 3.5 SP1, it took a bit of setup in order to get dynamic aspects on your pages. With the release of the .NET Framework 4.5, it is a lot easier to add dynamic data functionality to portions to your Web Forms pages.
This is now possible by using the new DynamicDataManager server control or EnablingDynamicData in the Page_Init call. For an example of this in action, take a look at Listing 12-2.
LISTING 12-2: Adding DynamicData to an existing GridView control
<%@ Page Language="C#" %>
<script runat="server">
protected void Page_Init()
{
GridView1.EnableDynamicData(typeof(Customer));
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>DynamicDataManager Example</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:GridView ID="GridView1" runat="server" AllowPaging="True"
DataSourceID="EntityDataSource1"
AutoGenerateColumns="False" DataKeyNames="RegionID">
<Columns>
<asp:BoundField DataField="RegionID" HeaderText="RegionID" ReadOnly="True"
SortExpression="RegionID"></asp:BoundField>
<asp:BoundField DataField="RegionDescription"
HeaderText="RegionDescription"
SortExpression="RegionDescription">
</asp:BoundField>
</Columns>
</asp:GridView>
<asp:EntityDataSource ID="EntityDataSource1" runat="server"
EntitySetName="Regions"
ConnectionString="name=NORTHWNDEntities"
DefaultContainerName="NORTHWNDEntities"
EnableDelete="True" EnableFlattening="False" EnableInsert="True"
EnableUpdate="True">
</asp:EntityDataSource>
</div>
</form>
</body>
</html>
Using the same Northwind object context from the previous examples, you will find that a basic EntityDataSource control has been added to the page to work with the GridView1 server control. The EntityDataSource has also been assigned to work off the Regions table in this example. What you want is a grid that shows a list of the customers.
In .NET Framework 4.0, you could finally add Dynamic Data functionality to an existing website, but it was still hard to take full advantage of the rich support in Dynamic Data. With the introduction of model binding in .NET Framework 4.5, it is really easy to integrate these features into your application. This integration provides a developer experience that’s similar to ASP.NET MVC in terms of model binding. This section looks at some of the ways you can integrate Dynamic Data with model binding. All this is also possible without starting from a Dynamic Data Web Application project template as well. To use model binding with Dynamic Data, you just have to use model binding with the data-bound controls. If you want to customize the look-and-feel of the columns and tables, you need to have the FieldTemplates and EntityTemplates folders in your application.
This section explains how you can leverage the Field and Entity Templates along with Data Annotation attributes to customize the look of a particular column or table. Table 12-1 lists some of the common attributes that you can use to customize the UI. You can find all these attributes in System.ComponentModel.DataAnnotations.dll.
ATTRIBUTE NAME | DESCRIPTION |
DataType | Specifies the type that should be associated with this column |
Display | Specifies how the columns are displayed by Dynamic Data, such as the name of the column |
DisplayFormat | Specifies how data fields are formatted by ASP.NET Dynamic Data |
Enum | Enables a .NET Framework enumeration to be mapped to a data column |
ScaffoldColumn | Specifies whether the column should be scaffolded by the system |
UIHint | Specifies the field template that Dynamic Data uses to display a data field |
As you learned earlier, the Field Templates folder contains user controls that map to a particular type of column. For example, DateTime.ascx is used by the Dynamic Data system to display a column of type DateTime. These user controls are reusable. This means if there are two tables that have the DateTime column, you can use the same user control for both tables.
Listing 12-3 shows how you can change the column name that will display the LastName column using the Display attribute. When you run the page, you will see “Last Part of Name.”
LISTING 12-3: Using the Display attribute to change the UI of a column
VB
Protected Sub SqlDataSource1_Updated(ByVal sender As Object,
ByVal e As Systelm.Web.UI.WebControls.SqlDataSourceStatusEventArgs)
If (e.Exception IsNot Nothing) Then
Me.lblMessage.Text = e.Exception.Message
e.ExceptionHandled = True
End If
End Sub
C#
[Display(Name="Last Part of Name")]
public string LastName { get; set; }
Now assume that you want to change the look-and-feel of the edit/insert view of the LastName column. You can do this by creating a new Dynamic Data Field Template user control and using it to change the UI. Listing 12-4 shows how to use the custom field template called LastName. The LastName user control has to exist in the Field Templates folder.
To add a new field template, right-click the website and choose the Dynamic Data field item template. Figure 12-6 shows how this template looks.
LISTING 12-4: Using the UIHint attribute to change the FieldTemplate being used
VB
Protected Sub SqlDataSource1_Updated(ByVal sender As Object,
ByVal e As System.Web.UI.WebControls.SqlDataSourceStatusEventArgs)
If (e.Exception IsNot Nothing) Then
Me.lblMessage.Text = e.Exception.Message
e.ExceptionHandled = True
End If
End Sub
C#
[UIHint("LastName")]
public string LastName { get; set; }
So far, you have learned how to customize the columns in a table. Say you now want to customize the look-and-feel of the entire table while using the autogeneration of columns with Dynamic Data. Entity templates can be used to achieve this. Entity templates are user controls that Dynamic Data uses to show all the columns in a table.
Listing 12-5 shows the markup of an entity template for an insert scenario. This is used by the FormView control, as shown in Listing 12-6.
LISTING 12-5: Typical EntityTemplate for inserting a table
<asp:EntityTemplate runat="server" ID="EntityTemplate1">
<ItemTemplate>
<tr class="td">
<td class="DDLightHeader">
<asp:Label runat="server" OnInit="Label_Init" OnPreRender=
"Label_PreRender" />
</td>
<td>
<asp:DynamicControl runat="server" ID="DynamicControl" Mode="Insert"
OnInit=
"DynamicControl_Init" />
</td>
</tr>
</ItemTemplate>
</asp:EntityTemplate>
LISTING 12-6: FormView control using EntityTemplate for inserting
<asp:FormView runat="server" ID="FormView1" DefaultMode="Insert"
ItemType="Customer" InsertMethod="InsertCustomer">
<InsertItemTemplate>
<table>
<asp:DynamicEntity ID="DynamicEntity1" runat="server" Mode=
"Insert" />
<tr>
<td>
<asp:LinkButton ID="Insert" runat="server"
CommandName="Insert" Text="Insert" />
<asp:LinkButton ID="Cancel" runat="server"
CommandName="Cancel" Text="Cancel"
CausesValidation="false" />
</td>
</tr>
</table>
</InsertItemTemplate>
</asp:FormView>
You can share the entity templates to create a common look-and-feel for all the tables in the database. If you want to customize the view for a particular table, you can create a custom entity template for that particular table. You can do this by creating a subfolder under DynamicData\EntityTemplates. The subfolder should be named after the name of the table, Customer in this case.
Attribute driven validation is a way to add some validation logic to your application by using Data Annotations. You saw some of the attributes that can be used for UI customization, and Table 12-2 shows some of the validation attributes.
ATTRIBUTE NAME | DESCRIPTION |
Key | Denotes one or more properties that uniquely identify an entity |
Range | Specifies the numeric range constraints for the value of a data field |
RegularExpression | Specifies that a data field value in ASP.NET Dynamic Data must match the specified regular expression |
Required | Specifies that a data field value is required |
StringLength | Specifies the minimum and maximum length of characters that are allowed in a data field |
One of the behaviors that you get out of the box, when you start using data-bound controls with model binding, is validation. When model binding binds the data, the model binding system uses Dynamic Data to handle validation for the columns in the table. This means that the application gets client-side as well as server-side validation for the columns and any validation errors can be viewed in the ValidationSummary control.
You can also customize the type of validation that happens on columns. Listing 12-7 shows how you can add some regular expression validation rules to the column LastName. If you then enter a last name that does not start with a, you will get the following validation error in the validation summary:
The field LastName must match the regular expression 'a*'
Note that because you also set the DisplayName attribute to change the name of the column, you get the new DisplayName in the error message as follows:
The field Last Part of Name must match the regular expression 'a*'
This is a very compelling use of Dynamic Data, because it customizes your application UI without changing your model.
LISTING 12-7: Using RegularExpression validation
VB
Protected Sub SqlDataSource1_Updated(ByVal sender As Object,
ByVal e As System.Web.UI.WebControls.SqlDataSourceStatusEventArgs)
If (e.Exception IsNot Nothing) Then
Me.lblMessage.Text = e.Exception.Message
e.ExceptionHandled = True
End If
End Sub
C#
[Display(Name = "Last Part of Name")]
[RegularExpression("a*")]
public string LastName { get; set; }
This chapter explored the capabilities in ASP.NET for building Dynamic Data-driven applications quickly and easily. These capabilities, in conjunction with Visual Studio, enable you to build a reporting application that provides full CRUD capabilities in less than five minutes.
At the same time, you can use all of these features with model binding and provide a rich consistent experience for your application.