Boost Productivity Using DynamicData - how to add to an existing asp.net application

It is hard for a customer to trust a software development company located in the other side of the globe (even when it is a nearshore one like our company), so some customers request some proof of concept before investing in a long term and expensive project.

Thanks to DynamicData, we can go beyond our customer requests and improve these small prototypes with almost no development effort.

DynamicData enables the creation of data driven web pages during runtime, with almost no code required.

In this post we will describe how to add pages (in this case administration pages for some of our prototype model objects), to an existing ASP.NET 3.5 application. It means that we first developed the prototype using basically ASP.NET 3.5, WF, Linq and EntityFramework, themes and master pages, among others, and then a few hours before delivering it, we improved the demo through adding some more links in the existing menu (using sitemaps), with new customized pages for users, roles, workflow steps and other entities administration. As we were using Enumerations for some handling a few object members, we also describe how to extend DynamicData to support them.  

Let's summarize the steps we followed:

Step 1: Create a dummy DynamicData Web Application project.

This one is not mandatory but if you do it, you will have the folder structure and some keys added to the config required for DynamicData to work.

 

 

By default DynamicData directory is created where stands Page Templates and Fields Templates.

Copy this folder into PresentationLayer web application.

 

   

Next, change copied files namespaces to match the PresentationLayer namespace and change Page Templates master page to be "MasterPage.master".

Step 2: Register the data model and url routes.

We must specify DynamicData the data model to use. For this, first add a reference to BusinessEntities in PresentationLayer project. Then at Global.asax add the next code to register data  model and routing, we are going to register DbDataContext created in BusinessEnities project:

public static void RegisterRoutes(RouteCollection routes)

{

MetaModel model = new MetaModel();

           

                model.RegisterContext(typeof(DbDataContext), new ContextConfiguration() { ScaffoldAllTables = true });

 

                routes.Add(new DynamicDataRoute("{table}/{action}.aspx")

{

                                Constraints = new RouteValueDictionary(new { action = "List|Details|Edit|Insert" }),

                Model = model

                });

}

 

void Application_Start(object sender, EventArgs e)

{

RegisterRoutes(RouteTable.Routes);

}

 

Step 3: Add references to DynamicData assemblies.

 

To enable DynamicData we must add the following references to PresentationLayer project:

  • System.ComponentModel.DataAnnotations
  • System.Web.Abstractions
  • System.Web.DynamicData
  • System.Web.Routing

In the compilation section in the web.config add the following assemblies:

<add assembly="System.Web.Abstractions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
<add assembly="System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
<add assembly="System.ComponentModel.DataAnnotations, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
<add assembly="System.Web.DynamicData, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

In the pages-controls section add the following tag prefix:

<add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> 

To enable ASP.NET new routing feature:

In the httpModules section add the following

<remove name="UrlRoutingModule" />

<add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />

 

In the System.WebServer - modules add the following

<add name="UrlRoutingHandler" preCondition="integratedMode" verb="*" path="UrlRouting.axd" type="System.Web.HttpForbiddenHandler, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />

Creating new field template for Enum types.

Something that we faced when adapting our asp.net solution was that there is no template for Enum types, so columns like Roles, Status and Actions won't show.

This is how we fixed it:

First, we create the ascx template file for Enum types. Right click FieldTemplates - Add new Item and select Dynamic Data Field, name it "Enumeration".

  

Notice that two ascx templates are created: one for display "Enumeration.ascx" and other for edition "Enumeration_Edit.ascx".

 

Change Enumeration_Edit template source to be:

<%@ Control Language="C#" CodeBehind="Enumeration_Edit.ascx.cs" Inherits="UruIT.BalanceSheetModule.PresentationLayer.DynamicData.FieldTemplates.Enumeration_EditField" %>

<asp:DropDownList runat="server" ID="DropDownList1" CssClass="droplist" OnDataBound="DropDownList1_DataBound">

</asp:DropDownList>

 

Change Enumeration_Edit template code behind to be:

protected void Page_Load(object sender, EventArgs e)

{}

 

protected override void OnDataBinding(EventArgs e)

{

// When overriding OnDataBinding be sure to call the base class's

// OnDataBinding method so that registered delegates receive the event.

base.OnDataBinding(e);

 

// get a data bindable list of permissions for the DDL

var enumList = Enum.GetValues(Column.ColumnType);

 

DropDownList1.DataSource = enumList;

DropDownList1.DataBind();

}

 

protected override void ExtractValues(System.Collections.Specialized.IOrderedDictionary dictionary)

{

dictionary[Column.Name] = ConvertEditedValue(DropDownList1.SelectedValue);

}

 

protected void DropDownList1_DataBound(object sender, EventArgs e)

{

// make sure we are in edit mode

if (Mode == DataBoundControlMode.Edit)

{

// try to get an item in the list that matched the FieldValueString

ListItem item = DropDownList1.Items.FindByValue(FieldValueString);

if (item != null)

{

// if we get the value set the drop down list to FieldValueString

DropDownList1.SelectedValue = FieldValueString;

}

}

}

 

// This is one of those needed things I think it allows   

// access to the actual control through Controls property

public override Control DataControl

{

get

{

return DropDownList1;

}

}

 

Step 5: Map Enum type columns to the correct template.

Once the template field for Enum types is created, we must map the columns of type Enum to the correct template.

For this, open "db.designer.cs" on BusinessEntities project. As an example search for BalanceSheet partial class and under status property add the following attribute:

 

[UIHint("Enumeration")]

 

It should look like this:

 

[Column(Storage="_Status", DbType="Int NOT NULL", CanBeNull=false)]

[UIHint("Enumeration")]

public Status Status

{

get

{

return this._Status;

}

 

set

{

if ((this._Status != value))

{

this.OnStatusChanging(value);

this.SendPropertyChanging();

this._Status = value;

this.SendPropertyChanged("Status");

this.OnStatusChanged();

}

}

}

 

Do this for all Enum type properties.

 

Step 5: Generate links to the new pages for administration.

Open "MasterPage.master" and under links add the following:

<tr>

<td class="menuSectionLink">

<a href="/Users/List.aspx">Users</a>

</td>

</tr>

<tr>

<td class="menuSectionLink">

<a href="/Companies/List.aspx">Company</a>

</td>

</tr>

<tr>

<td class="menuSectionLink">

<a href="/BalanceSheetFormats/List.aspx">Balance Sheets Formats</a>

</td>

</tr>

<tr>

<td class="menuSectionLink">

<a href="/BalanceSheetItems/List.aspx">Balance Sheets Items</a>

</td>

</tr>

Notice how the links matches the routes defined in "Global.asax" ({table}/{action}.aspx). We can change the List.aspx for any of this views: Details, Edit, Insert, ListDetails (all defined in PageTemplates directory).

 We get the following result:

List View:

 Details / Add View: 

 

Notice how Role which is an Enum displays now as a DropDownList. This has been specified in the Enumeration_Edit.ascx.

Edit View

So in a nutshell we have created admin pages for some of our entities, with almost no code. We also extended it to allow Enumerations in the edit pages.

So DynamicData really boosted the development in this small project!

 

Post written by: Esteban Freyre. .NET developer @ UruIT

No Comments