Skip to content

Home

Validator Application Block and ASP.NET

The Validation Application Block (VAB) of the upcoming Enterprise Library v3, uses attributes to describe validations. This gives us for example the opportunity to generate ASP.NET validators based on the attributes decorated on the properties.

Take for example the NotNullValidator of VAB, this can be translated to a RequiredFieldValidator, whereas the RegexValidator can be translated to RegularExpressionValidator. You can go further with the NotNullValidator and mark required fields with a different backcolor and adding an asterix (*) to the end of the control.

I am big fan of the DetailsView control, you can simply bind a DataSource control to it, and it will automatically provide you with a caption to each control and two-way binding. Below you find an example how you can extend the BoundField control, that investigates the NotNullValidator attribute of VAB. Note that I am currently extending it for the other set of validators and in a more OO way. More info will follow later.

public class BoundFieldEx : System.Web.UI.WebControls.BoundField
{
    public override void InitializeCell(
        DataControlFieldCell cell, DataControlCellType cellType,
        DataControlRowState rowState, int rowIndex)
    {
        base.InitializeCell(cell, cellType, rowState, rowIndex);

        if ((((rowState & DataControlRowState.Edit) != DataControlRowState.Normal) && !this.ReadOnly) ||
             ((rowState & DataControlRowState.Insert) != DataControlRowState.Normal))
        {
            TextBox textBox = null;

            if (cell != null && cell.Controls.Count > 0)
                textBox = cell.Controls[0] as TextBox;

            if (textBox != null)
            {
                Type dataItemType = null;

                if (DataBinder.GetDataItem(base.Control) != null)
                    dataItemType = DataBinder.GetDataItem(base.Control).GetType();

                if (dataItemType != null)
                {
                    ValidatorAttribute attribute = IsRequired(dataItemType, base.DataField);

                    if (attribute != null)
                    {
                        string textBoxID = this.DataField;
                        textBox.ID = textBoxID;

                        RequiredFieldValidator validator = new RequiredFieldValidator();
                        validator.ControlToValidate = textBoxID;
                        validator.ID = string.Concat("RequiredValidatorOf", textBoxID);
                        validator.Display = ValidatorDisplay.Dynamic;
                        validator.ErrorMessage = attribute.MessageTemplate;
                        cell.Controls.Add(validator);
                    }
                }
            }
        }
    }

    private ValidatorAttribute IsRequired(Type dataType, string property)
    {
        PropertyInfo propertyInfo = dataType.GetProperty(property);

        if (propertyInfo != null)
        {
            foreach (Attribute attribute in propertyInfo.GetCustomAttributes(true))
            {
                if (attribute is NotNullValidatorAttribute)
                    return attribute as ValidatorAttribute;
            }
        }

        return null;
    }
}

Now you create a custom business object, called Customer, and bind it to the DetailsView through an ObjectDataSource.

public class Customer
{
    private string _firstName;
    private string _lastName;

    [NotNullValidator(MessageTemplate="Firstname cannot be empty")]
    public string FirstName
    {
        get { return _firstName; }
        set { _firstName = value; }
    }

    [NotNullValidator(MessageTemplate="Lastname cannot be empty")]
    public string LastName
    {
        get { return _lastName; }
        set { _lastName = value; }
    }

    public Customer Fill()
    {
        Customer customer = new Customer();
        customer.FirstName = "Christoph";
        customer.LastName = "De Baene";
        return customer;
    }
}

Inside your aspx page you have something like

<asp:ObjectDataSource id="customerDataSource" TypeName="IStaySharp.Business.Customer, IStaySharp.Business" DataObjectTypeName="IStaySharp.Business.Customer, IStaySharp.Business" SelectMethod="Fill" runat="server">
</asp:ObjectDataSource>

<asp:ValidationSummary runat="server"/>

<asp:DetailsView DataSourceID="customerDataSource" DefaultMode="Edit" AutoGenerateRows="false" runat="server">
    <Fields>
        <rfx:BoundField HeaderText="Firstname"  DataField="FirstName"/>
        <rfx:BoundField HeaderText="Lastname"   DataField="LastName"/>
    </Fields>
</asp:DetailsView>

Here is the result if you leave the properties empty:

VABDetailsView

New VISUG site and events

VISUG has a brand new website. All the necessary features are already available and more functionality is coming soon. The two last VISUG events for year 2006 are announced. One of the events is a panel discussion about exception handling and logging, and it will take place at Real Software (my home). The other event is a geek dinner where we can discuss about... you know what I mean ;).

Topic: Discussion on Enterprise Exception Handling and Logging Description: This is a session where you (yes, you!) can discuss exception handling and logging in enterprise applications. Bring your tips and tricks, problems and exception handling frustrations with you, and we'll all learn about best practices together! No slides or preparation required! Don't want to discuss? No problem, you're not required to say anything, but we hope you will. To help with a smooth discussion, it will be lead by a panel of 3 to 4 people. If you're interested to sit on this panel, you're invited (First-come, First-served basis). When: Monday 11 December, 18:30 - 20:30 Where: Real Software (Prins Boudewijnlaan, 2550 Kontich, Route) Register: VISUG website

See you on both events!

Validation Application Block – Part of Enterprise Library v3

Tom Hollander revealed some features/scenarios about the upcoming Validation Application Block that will be included in Enterprise Library v3. There are already some validation libraries available, for example

The fact that you can define rules through configuration is really cool. I can't wait for the CTP!

Visual Studio .NET Macro for nesting project items

This macro enables you to nest project items inside Visual Studio .NET. Until now, there is no easy way to nest project items through the Visual Studio IDE, you can only do it by manipulating the project (.csproj or .vbproj) file and adding the DependentUpon element.

CreateDepedency

Inside the IStaySharp.vsmacros file there is a macro called 'Create Dependency' which allows you to nest two selected items. I have even created a video to illustrate how to configure and use the macro.

Pimp my command prompt

One of the oldest and most basic programs is certainly the command prompt (cmd.exe). One thing is certain, you still can't do without the command prompt, and certainly being a developer.  I came across a nice tool, called Console, which enhances the command prompt. I have been using it for a couple of months now, and I really like it.

One of the things you should really customize is your PROMPT. More information about changing the PROMPT can be found here. Having, for example, your current directory path on a separate line is really useful. You can customize it through the environment variable called PROMPT, like Scott is doing, but I prefer passing it as a parameter to the cmd.exe. This way I can easily copy the application and no reboot is required. This can be done by the /k argument of the cmd.exe.

Here is a snippet of my XML configuration file for Console.

<tab title="Console">
    <console shell="cmd /k PROMPT $p$_$+$g" init_dir=""/>
    <cursor style="11" r="255" g="255" b="255"/>
    <background type="2" r="0" g="0" b="0">
        <image file="" relative="0" extend="0" position="0">
            <tint opacity="190" r="0" g="0" b="0"/>
        </image>
    </background>
</tab>
<tab title="cmd">
    <console shell="cmd.exe /k PROMPT $p$_$+$g" init_dir=""/>
    <cursor style="11" r="255" g="255" b="255"/>
    <background type="0" r="0" g="0" b="0">
        <image file="" relative="0" extend="0" position="0">
            <tint opacity="0" r="0" g="0" b="0"/>
        </image>
    </background>
</tab>
<tab title="VS.NET 2005">
    <console shell="cmd /k PROMPT $p$_$+$g &amp;&amp; C:PROGRA~1MID05A~1VCvcvarsall.bat" init_dir=""/>
    <cursor style="0" r="255" g="255" b="255"/>
    <background type="2" r="0" g="0" b="0">
        <image file="" relative="0" extend="0" position="0">
            <tint opacity="188" r="0" g="0" b="0"/>
        </image>
    </background>
</tab>
<tab title="PowerShell">
    <console shell="C:WINDOWSsystem32windowspowershellv1.0powershell.exe" init_dir=""/>
    <cursor style="0" r="255" g="255" b="255"/>
    <background type="2" r="0" g="0" b="0">
        <image file="" relative="0" extend="0" position="0">
            <tint opacity="189" r="0" g="0" b="0"/>
        </image>
    </background>
</tab>

This is the result in Console

Console

PowerShell 1.0 released

PowerShell 1.0 has been released for Windows XP SP2 and Windows Server 2003. The bits can be downloaded here. If you already have installed a previous release of PowerShell, you need to uninstall by selecting Show Updates in the Change or Remove Programs.

PowerShellUninstall

Get running Visual Studio instances and corresponding _DTE objects

I am currently building software factories and I needed a way to have a list of running Visual Studio instances and the corresponding EnvDTE._DTE object to manipulate the solution. Windows internally keeps a list of COM objects that are currently running, called the Running Object Table (ROT). VS .NET 2005 for example, register itself in the ROT as !VisualStudio.DTE.8.0:pid where pid is the process id of the corresponding VS 2005 instance.

In .NET 1.1 you would use the the following UCOMIRunningObjectTable, UCOMIBindCtx for enumerating the ROT. In .NET 2.0 these interfaces are obsolete and are replaced by IRunningObjectTable and BIND_OPTS respectively. Note that the same code can be used for getting other instances like MS Word, IE, etc.

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using EnvDTE;

public static class DTEHelper
{
    const uint S_OK = 0;

    [DllImport("ole32.dll")]
    public static extern uint GetRunningObjectTable(uint reserved, out IRunningObjectTable ROT);

    [DllImport("ole32.dll")]
    public static extern uint CreateBindCtx(uint reserved, out IBindCtx ctx);

    static IDictionary<string, object> GetRunningObjectTable()
    {                        
        IDictionary<string, object> rotTable = new Dictionary<string, object>();

        IRunningObjectTable runningObjectTable;            
        IEnumMoniker monikerEnumerator;
        IMoniker[] monikers = new IMoniker[1];

        GetRunningObjectTable(0, out runningObjectTable);
        runningObjectTable.EnumRunning(out monikerEnumerator);
        monikerEnumerator.Reset();

        IntPtr numberFetched = IntPtr.Zero;

        while (monikerEnumerator.Next(1, monikers, numberFetched) == 0)
        {
            IBindCtx ctx;
            CreateBindCtx(0, out ctx);

            string runningObjectName;
            monikers[0].GetDisplayName(ctx, null, out runningObjectName);
            Marshal.ReleaseComObject(ctx);

            object runningObjectValue;
            runningObjectTable.GetObject(monikers[0], out runningObjectValue);

            if (!rotTable.ContainsKey(runningObjectName))
                rotTable.Add(runningObjectName, runningObjectValue);
        }

        return rotTable;
    }

    public static IDictionary<string, _DTE> GetRunningVSIDETable()
    {            
        IDictionary<string, object> runningObjects = GetRunningObjectTable();
        IDictionary<string, _DTE> runningDTEObjects = new Dictionary<string, _DTE>();            

        foreach (string objectName in runningObjects.Keys)
        {
            if (!objectName.StartsWith("!VisualStudio.DTE"))
                continue;

            _DTE ide = runningObjects[objectName] as _DTE;
            if (ide == null)
                continue;

            runningDTEObjects.Add(objectName, ide);
        }

        return runningDTEObjects;
    }        
}

Web Client Software Factory & CompositeWebUI

The Microsoft Patterns & Practices Team recently released a new version of the Web Client Software Factory that can be found on CodePlex. One of the things I noticed directly, is that they implemented a web version of the Composite UI based on the ObjectBuilder.

The goals of Web Client Software Factory are:

  • CAB for Web
    • Hiding complexity
    • Separation of infrastructure & biz logic
    • Biz logic reuse amongst different UI Technologies
    • Promoting consistent development practices
  • Navigation
  • UI Richness
  • UI Layout management
  • State management
  • Best use of technology available (Ajax, WinForms controls, ...)
  • Security
  • SaaS implications on application design

More information about the vision & scope can be found here.