Dynamic Data

Works at runtime to extract info from data context and apply to template pages for handling CRUD (CREATE, RETRIEVE, UPDATE, DELETE) operations.

Uses info from model (e.g. table relations, field names) to create meaningful pages.

To start:

  1. Create scaffold site that includes default presentation layer templates used by ASP.NET Dynamic Data
  2. Define data context representing data source and model via LINQ to SQL, LINQ to Entities or custom model.
  3. Register data context with websites MetaModel inside Global.asax
  4. Optionally customise URL routing, page and field templates, business logic and validation.

Creating Dynamic Data Website

Can create ASP.NET Dynamic Data website or add to existing site.

Two templates in Visual Studio - ASP.NET Dynamic Data Entities and ASP.NET Dynamic LINQ to SQL.

Data source not specified when creating site - done at later step.

Website Structure

At root of site:

  • Default.aspx - displays tables in data context. Includes GridView bound to MetaModel.VisibleTables collection. MetaModel exposed through application variable called DefaultModel (defined in Global.asax)
  • Global.asax - code executed for application events. Calls RegisterRoutes at Application_start which connects data context to meta model and uses ASP.NET routing to handle page requests for tables and actions (List, Details, Edit, etc.)
  • Site.css - style sheet used by master page and related page templates
  • Site.master - defines site navigation, ScriptManager control and main ContentPlaceHolder
  • Web.config - site configuration

The DynamicData folder has several subfolders and another web.config (which registers handler for System.Web.HttpNotFoundHandler).

The folders (and their naming convention) define pattern used by DynamicData to route requests.

The folders are:

  • Content - content used by Dynamic Data including images for pager control and custom GridViewPage user control
  • CustomPages - by defaul empty. Use this folder to create custom templates for displaying / editing data. Create new sub folder with same name as item in data model to be customised. Then copy page template (from PageTmeplates folder) to new folder and customise as appropriate. Dynamic Data routing will look in CustomPages folder for items following this naming convention before going to default PageTemplates.
  • EntityTempaltes - user controls used by page templates for displaying / editing data, e.g. Default_Edit.ascx
  • FieldTemplates - user controls defining UI for displaying table fields (in both edit and view mode). User controls based on type of data, e.g. boolean, DateTime, Text, etc. Can create custome templates to display and edit data.
  • Filters - UI user controls used to filter data
  • PageTemplates - default temlates for working with data. Can show data in list (List.aspx), insert new records (Insert.aspx), edit records (Edit.aspx), view record details (Details.aspx) and show list of data and selected record's details (ListDetails.aspx)

Defining Data Context

Create data context by adding LINQ to SQL Classes (DBML) or ADO.NET Entity Data Model (EDMX) file to project.

Registering Data Context with MetaModel

MetaModel defines connectivity between scaffold templates and the data layer.

Register data context inside Global.asax

At top of Global.asax it is defined as application variable and read-only property:

private static MetaModel s_defaultModel = new MetaModel();

public static MetaModel DefaultModel { get { return s_defaultModel; } }

The RegisterRoutes method is called at application start. This method is used to connect data source to MetaModel. The DefaultModel.RegisterContext() method takes type name of data context, setting ScaffoldAllTables to true ensure site will return all tables in data context.

A DynamicDataRoute should be added, specifying the form that URIs should take and any action constraints that are appropriate.

public static void RegisterRoutes(RouteCollection routes) (DefaultModel.RegisterContext(typeof(NorthwindDataContext), new ContextConfiguration() { ScaffoldAllTables = true });

routes.Add(new DynamicDataRoute("{table}/{action}.aspx") {  
    Constraints = new RouteValueDictionary( new action="List|Details|Edit|Insert"}),  Model= DefaultModel });  
}

Can then access data pages, for example to list contents of Products table issue:

http://localhost/myApp/Products/List.aspx

Custom Routing

Uses same routing features from System.Web.Routing as ASP.NET MVC.

Routing engine maps URIs base don user action to actual pages in site - makes URIs easier to understand for users and search engines.

For example a DynamicDataRoute class indicates URI should be mapped to table/action.aspx:

routes.Add(new DynamicDataRoute("{table}/{action}.aspx")  
{
    Constraints = new RouteValueDictionary( new action="List|Details|Edit|Insert"}),Model= DefaultModel })

will ensure that call to http://mysite/Products/Edit.aspx?ProductID=1 will be routed to /DynamicData/PageTemplates/Edit.aspx with the page knowing to edit the Products table and its record with a ProductID of 1.

Editing URI structure

Could switch table and action {action}/{table} and get same results for the URI, e.g.: http://mysite/Edit/Products?ProductID=1

Editing Route Table To Show List And Details On Same Page

Dynamic Data page templates include ListDetails.aspx that supports viewing a list of items and details for one selected item. Also supports insertion and deletion of items. By default this page nit used, but can activate it by removing existing routing and adding the following for List and Details:

routes.Add(new DynamicDataRoute("{table}/ListDetails.aspx")  
{  
    Action = PageAction.List,  
    ViewName = "ListDetails",  
    Model = DefaultModel  
}

routes.Add(new DynamicDataRoute("{table}/ListDetails.aspx")
{
    Action = PageAction.Details,
    ViewName = "ListDetails",
    Model = DefaultModel
}

Custom routes to specific pages

Create new folder in CustomPages folder and name folder with entity name from model.

Place appropriate action pages (List.aspx, Edit.aspx, etc.) into folder.

Default routing will pick these pages up in preference to those in PageTemplates folder.

Adding MetaData to Data Context

Data Context made up of partial classes.

Can extend these partial classes with metadata defining how fields are to be displayed and validated.

Start by adding partial class to App_Code directory and give it same name as a class in data context.

Then create related metadata class (using EntityMetadata naming convention).

Inside metadata class redefine properties contained in data context class - note these should be simple object types because the underlying type has already strongly typed them.

Mark properties with appropriate MetadataType attributes.

[MetadataType(typeof(ProductMetatdata}]
public partial class Product {}

public class ProductMetaData
{
    public object ProductID { get; set; }

    // Hide column from display
    [ScaffoldColumn(false)]
    public object QuantityPerUnit{ get; set; }

    //// Rename column to price and display as currency when not editing
    [DisplayFormat(ApplyFormatInEditMode=false, DataFormatString="{0:C}")]
    [DisplayName="Price"]
    public object UnitPrice { get; set; }
}

Custom Validation

Can also apply validation attributes such as Range, StringLength, Required, RegularExpression in similar fashion, e.g.:

[Range(1, 144, ErrorMessage = "Quantity between 1 and 144")]  
public object ReorderLevel { get; set; }

Custom Validation With Partial Methods

Data content model includes partial methods within the Extensible Method Definitions region of code generated by LINQ to SQL

For each property there is a OnChanging and OnChanged partial method.

Can use these partial methods to write customised validation rules.

Besides having access to all fields within record the OnChanging method is passed the value to which the property is being changed.

If encounter problem throw ValidationExcpetion.

Custom Field Templates

FieldTemplates used to render apperance and functionality of data context properties.

Controls named as either edit or display controls for specific data type, e.g. DateTime.ascx and DateTime_Edit.ascx

Can edit existing field template controls or create new ones.

If creating new control use metadata to specify which properties in data model use the new control.

Customise Existing Field Templates

Can modify like any other control, e.g. adding client side code, appearance, processing logic, etc.

Creating New Field Template Control

Copy existing control in Dynamic Data / Field Templates folder or select Dynamic Data Field template from Add New Item dialogue.

When using Dynamic Data Field template two controls are generated; one for display (ControlName.ascx) and the other for editing (ControlName_Edit.ascx).

By default display is a Literal control whilst edit includes a TextBox and validation controls.

For example may want to use Calendar control when in edit mode. Leave display control alone, but edit control modified so that the markup includes a calendar control and the code behind file overrides OnDataBinding to setup Calendar control.

<asp:Calendar ID="Calendar1" runat="server"/>

protected override void OnDataBinding(EventArgs e)
{
    base.OnDataBinding(e);
    DateTime dte = DateTime.Parse(this.FieldValue.ToString());
    Calendar1.SelectedDate = dte;
    Calendar1.VisibleDate = dte;
}

Then apply the control to fields via metatdata.

public class EmployeeMetadata
{
    [UIHint("CalendarPicker")]
    public object HireDate { get; set; }
}

Custom Page Templates

Specific to single entity in data context.

Create new folder under CustomPages with same name as entity object.

Copy one or more templates from PageTemplates folder into new folder.

Dynamic Data routing will look first in CustomPages/EntityName for action pages such as Edit.aspx, List.aspx, etc. If no action page found then version in PageTemplates folder used.

A common edit is to bind the GridView control more tightly with specific entity. Do this by setting AutoGenerateColumns property to false and then adding a series of DynamicField properties that represent the bound data.

Adding Dynamic Data Scaffolding To Existing Website

First define data context for site - can be LINQ to SQL, ADO.NET Entity Frameework or a custom data context.

Edit Global.asax to register context and enable routing - can copy from Global.asax for blank Dynamic Data site.

Copy DynamicData folder from blank Dynamic Data site into existing site.

Enabling Dynamic Data Inside Webpage

Can use Dynamic Data inside pages that do not use scaffolding or routing.

Have standard ASP.NET website that includes ADO.NET Entity Data Model for working with database.

Can add EntityDataSource to Default.aspx. This control can be used for selecting, inserting, updating and deleting.

<asp:EntityDataSource ID="EntityDataSource1" runat="server" ConnectionString="name=northwindEntities" DefaultContainerName="northwindEntities" EnableDelete="True" EnableFlattening="False" EnableInsert="True" EnableUpdate="True" EntitySetName="Products" />

Next add data display control to page.

<asp:GridView ID="GridView1" runat="server" DataSourceID="EntityDataSource1" AllowPaging="True" AllowSorting="True" AutoGenerateColumns="True">

<Columns>

<asp:CommandField ShowEditButton="True" />

</Columns>

</asp:GridView>

Finally add code to Page_Init to enable Dynamic Data:

protected void Page_Init(object sender, EventArgs e)
{
    GridView1.EnableDynamicData(typeof(northwndModel.Product));
}

Download