Monday, May 30, 2011

ASP.NET Dynamic Data - Part 6 - Customize Field Templates For Non-Intrinsic Types

Sometimes it is necessary to assign a type more specific than the data field inferred by Dynamic Data. For example a text field which contains an e-mail address, could be defined as a specific type of text. The template that processes the field can generate special UI for displaying and editing the e-mail type.
All this is done by using a DataTypeAttribute on the data-model field.
In this post I'll change the type of the Price field in the Products table, from the default double to a currency datatype, which displays the price correctly.

Add the Currency datatype to the Price field

  1. Defined the tables metadata as described in part 3.
  2. Create a property for the data field to customize.
  3. Add the DataType attribute to the property and set the data type to DataType.Currency.
[ScaffoldTable(true)]
[MetadataType(typeof(ProductsMetadata))]
public partial class Products
{
}

public class ProductsMetadata
{
    [UIHint("StockCustom")]
    public object Stock { get; set; }

    [DataType(DataType.Currency)]
    public object Price { get; set; }
}
Now the price are displayed correctly, with the currency defined in windows.
Now what to do if this is still not good enough? What if the currency defined in Windows are incorrect? Well, read on and you'll get the answer.

Modify the field template

If the default behavior for the datatype aren't enough you can customize it. To do this create a a custom field template as described in part 3 and modify it to support you needs.
In my case I need to use USD instead of DKK. I'll create a custom field template for the Price field, and edit the code to look like this.
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Collections.Specialized;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Xml.Linq;
using System.Web.DynamicData;
using System.ComponentModel.DataAnnotations;
using System.Globalization;

public partial class DynamicData_FieldTemplates_PriceCustom : System.Web.DynamicData.FieldTemplateUserControl {
    public override Control DataControl {
        get {
            return Label1;
        }
    }

    protected override void OnDataBinding(EventArgs e)
    {
        base.OnDataBinding(e);

        var metadata = MetadataAttributes.OfType().FirstOrDefault();
        if (String.IsNullOrEmpty(FieldValueString) || metadata == null)
            return;

        if (metadata.DataType == DataType.Currency)
        {
            Label1.Text = ((double)FieldValue).ToString("C", new CultureInfo("en-US"));
        }
    }
}
The reason for me to choose this rather explicit way to check the datatype, is to show how to handle this when the field template are used by multiple data fields with different data types, for example customizing the default template.
You also need to indicate in the tables metadata that the custom field template should be used instead of the default, this is done by adding the attribute to the data field UIHint, just as described in part 3.
The custom field template looks like this.
PriceCustom.ascx:
<%@ Control Language="C#"  AutoEventWireup="true" CodeFile="PriceCustom.ascx.cs" Inherits="DynamicData_FieldTemplates_PriceCustom" %>
PriceCustome.ascx.cs:
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Collections.Specialized;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Xml.Linq;
using System.Web.DynamicData;
using System.ComponentModel.DataAnnotations;
using System.Globalization;

public partial class DynamicData_FieldTemplates_PriceCustom : System.Web.DynamicData.FieldTemplateUserControl {
    public override Control DataControl {
        get {
            return null;
        }
    }

    protected override void OnDataBinding(EventArgs e)
    {
        base.OnDataBinding(e);

        var metadata = MetadataAttributes.OfType().FirstOrDefault();
        if (String.IsNullOrEmpty(FieldValueString) || metadata == null)
            return;

        if (metadata.DataType == DataType.Currency)
        {
            Label label = new Label();
            label.Text = ((decimal)FieldValue).ToString("C", new CultureInfo("en-US"));
            Controls.Add(label);
        }
    }
}
The new page looks like this

ASP.NET Dynamic Data - Part 5 - Customize Page Templates

Another way to customize a table's layout is custom page templates, the other way, entity templates are described in part 3.

How to create a custom page template

  1. Create the subfolder named according to the table accessor in the data-context class.
  2. Copy an existing page template from /DynamicData/PageTemplates to the newly created subfolder.
  3. If you're project is a Web Application, the namespace must be changed in the copied template, in order to avoid name collision.
Now just customize the copied template, as needed.
Again building on the previous project in the series, my example for the page template for the Categories table looks like this.
Details.aspx:
<%@ Page Language="C#" MasterPageFile="~/Site.master" CodeFile="Details.aspx.cs" Inherits="Details" %>

<asp:Content ID="headContent" ContentPlaceHolderID="head" Runat="Server">
</asp:Content>

<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
    <asp:DynamicDataManager ID="DynamicDataManager1" runat="server" AutoLoadForeignKeys="true">
        <DataControls>
            <asp:DataControlReference ControlID="FormView1" />
        </DataControls>
    </asp:DynamicDataManager>

    <h2 class="DDSubHeader">Details for <%= table.DisplayName %> entry</h2>

    <asp:UpdatePanel ID="UpdatePanel1" runat="server">
        <ContentTemplate>
            <asp:ValidationSummary ID="ValidationSummary1" runat="server" EnableClientScript="true"
                HeaderText="List of validation errors" CssClass="DDValidator" />
            <asp:DynamicValidator runat="server" ID="DetailsViewValidator" ControlToValidate="FormView1" Display="None" CssClass="DDValidator" />

            <asp:FormView runat="server" ID="FormView1" DataSourceID="DetailsDataSource" OnItemDeleted="FormView1_ItemDeleted" RenderOuterTable="false">
                <ItemTemplate>
                    <table id="detailsTable" class="DDDetailsTable" cellpadding="6">
                        <asp:DynamicEntity runat="server" />
                        <tr class="td">
                            <td colspan="2">
                                <asp:DynamicHyperLink runat="server" Action="Edit" Text="Edit" />
                                <asp:LinkButton runat="server" CommandName="Delete" Text="Delete"
                                    OnClientClick='return confirm("Are you sure you want to delete this item?");' />
                            </td>
                        </tr>
                    </table>
                </ItemTemplate>
                <EmptyDataTemplate>
                    <div class="DDNoItem">No such item.</div>
                </EmptyDataTemplate>
            </asp:FormView>

            <asp:EntityDataSource ID="DetailsDataSource" runat="server" EnableDelete="true" />

            <asp:QueryExtender TargetControlID="DetailsDataSource" ID="DetailsQueryExtender" runat="server">
                <asp:DynamicRouteExpression />
            </asp:QueryExtender>

            <br />

            <div class="DDBottomHyperLink">
                <asp:DynamicHyperLink ID="ListHyperLink" runat="server" Action="List">Show all items</asp:DynamicHyperLink>
            </div>
        </ContentTemplate>
    </asp:UpdatePanel>
</asp:Content>
Details.aspx.cs:
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Web.DynamicData;
using System.Web.Routing;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.Expressions;

public partial class Details : System.Web.UI.Page {
    protected MetaTable table;

    protected void Page_Init(object sender, EventArgs e) {
        table = DynamicDataRouteHandler.GetRequestMetaTable(Context);
        FormView1.SetMetaTable(table);
        DetailsDataSource.EntityTypeFilter = table.EntityType.Name;
    }

    protected void Page_Load(object sender, EventArgs e) {
        Title = table.DisplayName;
        DetailsDataSource.Include = table.ForeignKeyColumnsNames;
    }

    protected void FormView1_ItemDeleted(object sender, FormViewDeletedEventArgs e) {
        if (e.Exception == null || e.ExceptionHandled) {
            Response.Redirect(table.ListActionPath);
        }
    }
}
I've just changed the page headline from Entry from table Categories to Details for Categories entry. I haven't made any changes to the default Details code-behind or markup other than the change described above.
The details page for the Categories table now looks like this:

Entity Template vs. Page Template

The page template allows control over the page layout and contents, the entity template only allows control on the table contents itself. Whether to use entity templates or page templates depends on the use case. Both templates are very easy to create and modify. Also page templates required zero code, except on the template itself, if more advanced functionality are required.

Series about logging errors with ELMAH

ELMAH (Error Logging Modules and Handlers) is an error-logging facility, that can be added to ASP.NET applications without need for recompilation or deployment. It is very extensible and can do a lot of very advanced logging, to several different back-end storages, including MSSQL, Orcale, MySQL, SQLite, XML, memory and others.
It can be difficult to setup correctly, because of this a very comprehensive series about ELMAH has been posted on joel.net. Currently the series consists of 5 parts.

Sunday, May 29, 2011

C# 5: Async from the compilers view

As many may know, one of the main features in the next version of C#, C# 5, is the new keywords, async and wait. But how does the compiler handle these new keywords? After all they're only syntactic sugar.
Jon Skeet has an excellent blog series called Eduasync about this, so far it consists of 8 parts, and are definitely recommended reading, if you are interested in the internals of the asynchronous functionality.
Eduasync part 1: introduction
Eduasync part 2: the shape of the caller / async method boundary
Eduasync part 3: the shape of the async method / awaitable boundary
Eduasync part 4: Filling in AsyncTaskMethodBuilder
Eduasync part 5: making Task awaitable
Eduasync part 6: using the infrastructure manually
Eduasync part 7: generated code from a simple async method
Eduasync part 8: generated code from a complex async method
The Async CTP are available from MSDN for everyone to try.

Update
Eduasync part 9: generated code for multiple awaits

ASP.NET Dynamic Data - Part 4 - Customize Entity Templates

The next topic in my series on ASP.NET Dynamic Data, I'll focus on how to customize the table layout using entity templates. I'll continue to work on my project described in part 3. The only thing changed from part 3 is instead of the custom field template which changed the background color, based on the stock count, now changes for foreground color instead.
At the moment the Web Site uses the default details table layout, which looks like this:
This is a very basic template, are a very often not what you need. In this case I would like something different, something like this:

I'm not a designer so no fancy colors or anything here, but this could be added easily.

Create the custom entity template

First we need to create the custom entity template, this template will be used for all entities in the Products table. We need to Add New Item, on the /DynamicData/EntityTemplates folder and choose the Web User Control item, the name of the control must be the same as the data model entity that represents the table, in my case it must be Products.ascx.
The markup for the new table contents are easily added, and could look like this:
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="Products.ascx.cs" Inherits="DynamicData_EntityTemplates_Products" %>
<tr>
    <td class="DDLightHeader" colspan="4">Producy Entry</td>
</tr>
<tr>
 <td class="DDLightHeader">Id:</td>
 <td>
        <asp:DynamicControl runat="server" DataField="Id" />
    </td>
 <td class="DDLightHeader">Name:</td>
 <td>
        <asp:DynamicControl ID="DynamicControl1" runat="server" DataField="Name" />
    </td>
</tr>
<tr>
 <td class="DDLightHeader">Stock:</td>
 <td>
        <asp:DynamicControl ID="DynamicControl2" runat="server" DataField="Stock" />
    </td>
 <td class="DDLightHeader">Price:</td>
 <td>
        <asp:DynamicControl ID="DynamicControl3" runat="server" DataField="Price" />
    </td>
</tr>
<tr>
 <td class="DDLightHeader" colspan="4">Description:</td>
</tr>
<tr>
 <td colspan="4">
        <asp:DynamicControl ID="DynamicControl4" runat="server" DataField="Description" />
    </td>
</tr>
After the markup are written, you need to change to base class from UserControl to EntityTemplateUserControl, this is done in the usercontrol's code-behind file. The code looks like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.DynamicData;

public partial class DynamicData_EntityTemplates_Products : EntityTemplateUserControl
{
    protected void Page_Load(object sender, EventArgs e)
    {

    }
}

Test the Web Site

This is all that needs to be done in order to create a custom entity template, easy right? When the Web Site is tested in looks like this:

ASP.NET Dynamic Data - Part 3 - Customize Field Templates

Now it's time for part 3 in the series about ASP.NET Dynamic Data, how to customize the appearance and behavior of default field templates.
All changes in the default template will affect all pages and controls where the template is used.
All templates used by the Dynamic Data framework are placed in /DynamicData, for example field templates are placed in the /DynamicData/FieldTemplates.
The default field templates are all usercontrols, which you are free to edit as you like, they are all named descriptively, making it easy to quickly recognize the place where it is used.
For example, the display control for text are called, Text.ascx, the edit template are called, Text_Edit.ascx.
Since all these controls are using familiar technology they can be easily customized to fit you own needs.

Creating a custom template

If needed a custom field template can easily be created. In my example if got a data model which looks like this:
The custom data field template I need, is a template which displays the stock count with a red background in below 10, a yellow background in between 10 and 20, otherwise the default background color will be used.
To create the custom template a add a new item to the /DynamicData/FieldTemplates folder, the new item is a Dynamic Data Field item, available from the Add New Item dialog.
In my case the default markup needs to be changed from a literal control to a label control, as literal controls, don't allow me to change the background color.
Markup:
<%@ Control Language="C#"  AutoEventWireup="true" CodeFile="StockCustom.ascx.cs" Inherits="DynamicData_FieldTemplates_StockCustom" %>
<asp:Label runat="server" ID="Label1" Text="<%# FieldValueString %>" />
To change the background color based on the value, you need to override the OnDataBinding method. The code-behind file for my custom field template are shown below. The value of the field are available in the FieldValue property on the base class.
Code-behind:
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Collections.Specialized;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Xml.Linq;
using System.Web.DynamicData;
using System.Drawing;

public partial class DynamicData_FieldTemplates_StockCustom : System.Web.DynamicData.FieldTemplateUserControl {
    public override Control DataControl {
        get {
            return Label1;
        }
    }

    protected override void OnDataBinding(EventArgs e)
    {
        int currentValue = (int)FieldValue;
        if (currentValue < 10)
            Label1.BackColor = Color.Red;
        else if (currentValue < 20)
            Label1.BackColor = Color.Yellow;
    }
}
Now the last thing we need to do is to associate the field template with a data field. First we need to modify the partial class from part 2. The new code looks like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using DatabaseModel;
using System.ComponentModel.DataAnnotations;

namespace DatabaseModel
{
    [ScaffoldTable(true)]
    [MetadataType(typeof(ProductsMetadata))]
    public partial class Products
    {
    }

    public class ProductsMetadata
    {
        [UIHint("StockCustom")]
        public object Stock;
    }

    [ScaffoldTable(true)]
    public partial class Categories
    {
    }
}
The MetadataTypeAttribute indicates which class contains the necessary metadata for the table. The metadata class, contains a field which has the same name as the field in the database, the field itself has another attribute, the UIHintAttribute, which defines the name of the field template to used instead of the default.
When I view my products table in the web interface now, it indicates the stock count in red if the count is less than 10, yellow if the count is between 10 and 20, and default color if greater than 20.

Wednesday, May 25, 2011

ASP.NET Dynamic Data - Part 2 - Create a Web Site From Scratch

Part 1 in the serie about ASP.NET Dynamic Data gave a very quick overview over the Dynamic Data framework. Now how do you create a Dynamic Data Web Site from scratch using in built-in scaffolding support?

Create the Web Site

It's very easy to create a Dynamic Data Web Site from scratch. In Visual Studio just choose File -> New -> Web Site -> ASP.NET Dynamic Data Entities.
Dynamic Data can of course also be create using Linq to SQL, and as a Web Application.
The structure of the project looks like this

Create and use the DataContext

Next the DataContext used to scaffold the database should be created. If you don't know how to create the entity model, see the How to: Create a New .edmx File (Entity Data Model Tools) from MSDN.
To use the generated open the Global.asax file, and find the line on the picture below, the line should be uncommented and YourDataContext should be changed to the name of you own DataContext, in my case the context in DatabaseEntities.
The line also allows you to control if all tables should be scaffoleded, the default is not to scaffold all tables. In my case I could scaffold all tables, but for the sake for this tutorial, I'll defined which tables to scaffold using partial classes.

Choose the tables to scaffold

My database consists of two tables named Products and Categories, the entity classes have the same name, this means that my two partial classes looks like this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using DatabaseModel;
using System.ComponentModel.DataAnnotations;

namespace DatabaseModel
{
    [ScaffoldTable(true)]
    public partial class Products
    {
    }

    [ScaffoldTable(true)]
    public partial class Categories
    {
    }
}
The ScaffoldTable attribute indicates that the table should be scaffolded. Remember to place the partial classes in the same namespace as the original entity classes, otherwise this won't work.

Test the site

You can know publish the Web Site, are it is now possible to view, edit, create and delete data from the database. This is how easy Dynamic Data allows you to create a basic web interface to you database.
It the next part of this serie, I'll show you how to customize the default field templates.

ASP.NET Dynamic Data - Part 1 - Introduction

ASP.NET Dynamic Data has been out for a while, but good tutorials about it, can be hard to find. In this and a couple of future post, I'll try to introduce you to some of the framework and how to use it.

Overview of ASP.NET Dynamic Data

ASP.NET Dynamic Data lets you create extensible data-driven Web applications by inferring at run time the appearance and behavior of data entities from the database schema and deriving UI behavior from it. - ASP.NET Dynamic Data Overview (Microsoft MSDN)
The quote above, quickly summarizes the purpose of Dynamic Data. As Dynamic Data supports scaffolding, to automatically generate Web Pages for the tables in a database, both for editing and viewing data. After this has been done, you can customize the elements or create new ones to change the default behavior, to suite you needs.
Of course this can also be done without using scaffolding, which makes it easy to use Dynamic Data in an existing Web Site.

Architecture

Dynamic Data obtains data entities information from an underlying framework use to represent data entities as CLR types.

Presentaion layer elements

All the template types can be customize, new can be created, etc.

Page Templates

Are pages that render data from a table in the database. Templates for different data views are included in the framework. Among others listing a whole table, displaying master/detail tables, end editing data.

Entity Templates

Templates for a data entity, such as data row and table. Very useful for customizing a custom UI, as it is more flexible than customizing the individual field.

Field Templates

UI templates for the individual data fields. A lot of default templates exists, such as Boolean and text. Normally a different template for displaying and editing data are used.

Filter Templates

Templates for UI filtering, for example displaying tables rows based on another value. Default templates are Boolean, foreign-key and enumeration templates.

A more complete overview can be found the corresponding MSDN page, ASP.NET Dynamic Data Overview.

The next post will be how to create a new Dynamic Data Web Site from scratch using scaffolding.

Friday, May 20, 2011

How to choose between ASP.NET Web Forms, MVC, Dynamic Data, etc.

I've just been attending TechEd 2011 North America, and there was a lot of interesting stuff. Among all the sessions I've attended was a Birds-of-a-Feather (BOF) session called "Choosing between WebForms, MVC, WebPages, Dynamic Data and More", which wasn't a success. The whole point in a BOF session is interactivity and almost none were present, as almost no one in the audience had tried MVC. Because of all the buzz around MVC, this was the most asked question, "Why should I convert my Web Forms page to MVC? What do I get out of it?".
Almost everyone looks for a compelling reason to change, but in fact this question aren't answer easily. There are several reasons for this:
  1. It depends on the project.
  2. Even though the industry are moving towards MVC, Web Forms are still actively developed, and will continue to be.
  3. Most things you can do in MVC, you can also do in Web Forms.
I'll try to address each of these points in this blog post, but first lets start with the difference between Web Forms and MVC.

ASP.NET Web Forms has been around from the start of ASP.NET, it has a very similar structure to ordinary Windows programming with events, but are also very different, specifically with the ASP.NET Page Life Cycle. Because of this it can be relatively hard to unit test, there is a lot of classes involved which can't be mocked easily. Even though there are several ways to make this easier, such as the MVVM and MVP pattern, it all depends on the code structure. A well formed Web Forms page can be just as easy as to maintain as a MVC page.

ASP.NET MVC is a relatively new addition to the .NET framework, but has been around for a long time. MVC stands for Model-View-Controller and works quietly different than Web Forms. It has an totally different structure, but it encourages the developer to use a cleaner separation of concerns.

It depends on the project
Choosing between all different alternatives can be very difficult, as most of it depends on the project. For example if you have a existing site in Web Forms, you create a new site or you site it mostly data driven. All of the technologies can be used in all of the situations, they all have they pros and cons. If the site is mainly data driven, such as an interface to a database, Dynamic Data could be an option. If it is a site that enables a lot of data editing, but also functions a "regular" website, I would personally prefer Web Forms. If you would like strict control over the HTML I would prefer MVC. It all depends.

Web Forms is not dead
Because of all the buzz around MVC, a lot of people starts to think "Is Web Forms dead?", and the answer is "Certinaly not". Web Forms are actively develop, and has and will get a lot of new features which only are available in MVC at the moment. The next version of ASP.NET will among others get:

  • Much better data binding, and customization of the data model, same way as in MVC.
  • JS and CSS combination and minification.
  • Better support for asynchronous operations.
Most things in MVC is possible in Web Forms too
Many people using MVC are very happy for the routing possibilities, with friendly URLs. This is also possible in ASP.NET, using MapPageRoute. Controlling the HTML are also possible in Web Forms, although it is more difficult, because of all the controls you don't know how renders HTML. But the possibility to disable the default auto generated control IDs has helped a lot, making it much easier to control the HTML and use Javascript interaction with these.

Conclusion
The conclusion is that there are now conclusion, it all depends on your project and the requirements. It should be noted that it is possible to use both Web Forms, MVC and Dynamic Data in a single web project, if you start with a Web Forms project it requires some modification to the project file, and manual creation of the folder structure, but when this is done, very things works, and you can mix as required. This is very powerful if you aren't allowed or don't have time to convert the whole web site to MVC. If you start with a MVC project, no modification are necessary, you can just start adding Web Forms pages. Personally I use a Web Forms and MVC hybrid website, and it works like a charm. If your Web Forms site works, are maintainable and you know what your doing, I see no reason to change if unless necessary for some reason. There is a learning curve to MVC, it requires a totally different mindset, but if strict control is necessary, I would say "Take a look at it!".
ASP.NET Web Pages are more hobbyist, easy website creation, but leans more towards MVC than Web Forms.
Hopes this post helps anyone to decide what to do, feel free to leave a comment, question or whatever and I'll try to answer.

Monday, May 9, 2011

Changing database when using ADO.NET

I like ADO.NET and the entity framework, but it also has it shortcomings.
Recently I discovered another shortcoming.
I have a lot databases on the same server, with identical table design, the only reason for using two databases, are for security purposes. The problem here is that the Entity Framework, doesn't allow me to change database, when I need to query all the databases. Of course you can change to connection string at runtime, but this also creates a new connection, and with 200 databases, it is alot of connections.
The solution I came up with was to use the underlying StoreProvider's ChangeDatabase method, the extension method looks like this:
public static void ChangeDatabase(this ObjectContext context, string databaseName)
{
  DbConnection connection = ((EntityConnection)context.Connection).StoreConnection;
            
  // The connection must be open before changing database.
  if (connection.State != ConnectionState.Open)
  {
    connection.Open();
  }

  connection.ChangeDatabase(databaseName);
}
A very easy to use extension method, which works as long as the underlying store provider supports changing the database. Of course you have to ensure that the table schemas are exactly alike, otherwise all kinds of errors could occur.