HttpContext in ASP.NET MVC

A quick gotcha for ASP.NET MVC newbies (like me), the HttpContext object on the Controller are not set on construction.  I found this out when trying to capture the authenticated users IIdentity and then spent 20 minutes of my life working out why it was always null!  Good excuse to peruse the source though...

Move Service Factory projects

I have been using the Service Factory Modelling Edition a lot lately, whilst they do produce a lot of projects and may appear unwieldy at first glance, the consistency of implementation alone is worth it in some of the larger implementations.

The issue I have was a need to migrate a Service Factory project into another pre-existing solution (I am a tidy freak).  The best way I found was to manually copy and edit the sln file; all you need to do is copy the ProjectMapping.xml file along with the folders containing the implementations and the models into the new solution folder, then start to edit the new sln file!  As a word of caution remember to make copies of everything before you start, as editing the sln file can lead to splinters...

In the project section for Solution Items add the ProjectMapping.xml file:

Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{A47C9E2B-340A-4E76-AA04-EE0B0A053637}"
            ProjectSection(SolutionItems) = preProject
                        ProjectMapping.xml = ProjectMapping.xml
            EndProjectSection
EndProject

 

If there is no Solution Items section just add a file to the root of the new solution in the IDE then close and start again.

The copy all of the Project sections relating the the folders and projects for the Service Factory from the original solution into the new solution, they are quite nicely grouped together, so this should be easy.  Just be wary to ensure that any other projects added to the original solution are not copied across.

Finally (to make sure you get all the solution folders setup correctly) copy all of the relevant nesting from the section:

GlobalSection(NestedProjects) = preSolution

 

This is usually at the end of the sln file, to the same location in the new sln.  If you have done everything correctly (some luck required) the new solution should open and build correctly in the IDE!  If the solution won't build and moans about project references, the most likely cause is the NestedProjects section. This section is sensitive to non existent projects, which is easy to do if If you are moving the project from a solution that contains more than just the Service Factory. Check each identifier in the section exists in the solution file, removing all those that don't.

Type descriptors for extensibility...

The TypeDescriptor architecture is used widely within the .NET framework and allows for greater extensibility than reflection.  The msdn article Type Descriptor Overview gives a good introduction to the model.  Whilst most often used in the design time environment, there are notable examples where used at runtime (such as the PropertyGrid), and having the capability to affect the TypeDescriptor at runtime opens up many possibilities.

In this example I will walk through a simple example to demonstrate how easy it is to override the TypeDescriptor at runtime to affect display and edit capability with the PropertyGrid.  The example will be to add a TypeDescriptor to a simple data type to demonstrate how the ReadOnly attribute can be changed based on runtime state.

In this example I use a simple data item type within the application:

    public partial class DataItem
    {
        [Description("Name of the data item")]
        [ReadOnly(true)]
        public string Name { get; set;}
        [Description("Data item description")]
        public string Description { get; set; }
        [Browsable(false)]
        public bool ReadOnly { get; set; }
    }

The Name property is decorated with a ReadOnly attribute and Description is editable, for simplicity I have included a ReadOnly property within the aim being that when set to ReadOnly the Description property will also be made ReadOnly.

The code below defines the TypeDescriptor infrastructure required.

    public class DataItemDescriptionProvider : TypeDescriptionProvider
    {
        public DataItemDescriptionProvider() : this(TypeDescriptor.GetProvider(typeof(DataItem)))
        {
        }
        public DataItemDescriptionProvider(TypeDescriptionProvider parent): base(parent)
        {
        }
        public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
        {
            ICustomTypeDescriptor td = base.GetTypeDescriptor(objectType, instance);
            td = new DataItemTypeDescriptor(td, instance as DataItem);
            return td;
        }
    }
    public class DataItemTypeDescriptor : CustomTypeDescriptor
    {
        private DataItem m_instance;
        public DataItemTypeDescriptor(ICustomTypeDescriptor parent, DataItem instance) : base(parent)
        {
            m_instance = instance;
        }
        public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
        {
            PropertyDescriptorCollection properties = base.GetProperties(attributes);
            if (m_instance.ReadOnly)
            {
                var p = from property in properties.OfType<PropertyDescriptor>()
                        select new DataItemReadOnlyPropertyDescriptor(true, property);
                return new PropertyDescriptorCollection(p.ToArray());
            }
            return properties;
        }
    }
    public class DataItemReadOnlyPropertyDescriptor: PropertyDescriptor
    {
        private PropertyDescriptor m_descriptor;
        private bool m_readOnly;
        
        public DataItemReadOnlyPropertyDescriptor(bool readOnly, PropertyDescriptor descriptor) : base(descriptor)
        {
            m_descriptor = descriptor;
            m_readOnly = readOnly;
        }
        #region abstract PropertyDescriptor implementation
        public override bool CanResetValue(object component)
        {
            return m_descriptor.CanResetValue(component);
        }
        public override Type ComponentType
        {
            get { return m_descriptor.ComponentType; }
        }
        public override object GetValue(object component)
        {
            return m_descriptor.GetValue(component);
        }
        public override bool IsReadOnly
        {
            get { return m_readOnly; }
        }
        public override Type PropertyType
        {
            get { return m_descriptor.PropertyType; }
        }
        public override void ResetValue(object component)
        {
            m_descriptor.ResetValue(component);
        }
        public override void SetValue(object component, object value)
        {
            m_descriptor.SetValue(component, value);
        }
        public override bool ShouldSerializeValue(object component)
        {
            return m_descriptor.ShouldSerializeValue(component);
        }
        #endregion
    }

The DataItemDescriptionProvider implements TypeDescriptionProvider overriding the GetTypeDescriptor method to return the specialized TypeProvider, later in our calling code we will hand this to TypeProvider for our Type.

The DataItemTypeDescriptor is where the work happens, implementing the CustomTypeDescriptor which is a simple default implementation of the ICustomTypeProvider (minimising the amount of typing required).  We are overriding the GetProperties method and extracting the properties from the base class, then (if the instance ReadOnly  is set) creating overridden PropertyDescriptors (which simply allows the setting of the ReadOnly attribute and includes lots of boiler plate to hand off to the base instance for all other requests). 

In usage code we need to hand the TypeDescriptionProvider to TypeProvider:

            TypeDescriptor.AddProvider(new DataItemDescriptionProvider(), typeof(DataItem));

To demonstrate I used this within a simple windows forms app with a property grid, show below:

 read EDITABLE

You can download the sample app here.

Visual Studio 2008 troubleshoot start-up

Had a monstrously weird issue with a particular solution file, everything was working fine (opening, building, compiling and even unit testing) then for seemingly no apparent reason the solution wouldn't even open!

I didn't know this was possible but looking at the devenv.exe command line arguments it is possible to log all activity using the /Log switch.  This outputs to an XML file which outputs with an xml-stylesheet processing instruction href to ActivityLog.xsl. Quick scan of the disk didn't find the file, but I found a post on the MSDN forum with the following:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
    <xsl:output method="html"  encoding="utf-16"/>
    <xsl:template match="activity">
        <head>
        <title>Activity Monitor Log</title>
        <style type="text/css">
            body{ text-align: left; width: 100%;  font-family: Verdana, sans-serif; }
            table{ border: none;  border-collapse: separate;  width: 100%; }
            tr.title td{ font-size: 24px;  font-weight: bold; }
            th{ background: #d0d0d0;  font-weight: bold;  font-size: 10pt;  text-align: left; }
            tr{ background: #eeeeee}
            td, th{ font-size: 8pt;  padding: 1px;  border: none; }
            tr.info td{}
            tr.warning td{background-color:yellow;color:black}
            tr.error td{background-color:red;color:black}
           
            span {text-decoration:underline}
            a:hover{text-transform:uppercase;color: #9090F0;}
        </style>
        </head>
        <body>     
        <table>
            <tr class="title">
                <td colspan="7">Activity Monitor Log</td>
            </tr>            
            <tr>
                <td colspan="2">infos</td>
                <td colspan="5"><xsl:value-of select="count(entry[type='Information'])"/></td>
            </tr>
            <tr>
                <td colspan="2">warnings</td>
                <td colspan="5"><xsl:value-of select="count(entry[type='Warning'])"/></td>
            </tr>
            <tr>
                <td colspan="2">errors</td>
                <td colspan="5"><xsl:value-of select="count(entry[type='Error'])"/></td>
            </tr>
            <tr>
                <th width="20">#</th>
                <th width="50">Type</th>
                <th>Description</th>
                <th width="280">GUID</th>
                <th>Hr</th>               
                <th>Source</th>
                <th>Time</th>
            </tr>              
            <xsl:apply-templates/>
        </table>
        </body>
    </xsl:template>
    <xsl:template match="entry">
        <!-- example
       
          <entry>
            <record>136</record>
            <time>2004/02/26 00:42:59.706</time>
            <type>Error</type>
            <source>Microsoft Visual Studio</source>
            <description>Loading UI library</description>
            <guid>{00000000-0000-0000-0000-000000000000}</guid>
            <hr>800a006f</hr>
            <path></path>
        </entry>
       
        -->
        <xsl:choose>
            <xsl:when test="type='Information'">
                    <tr id="info" class="info">
                        <td><xsl:value-of select="record"/></td>
                        <td></td>
                        <xsl:call-template name="row"/>
                    </tr>               
            </xsl:when>               
            <xsl:when test="type='Warning'">
                    <tr id="warning" class="warning">
                        <td><xsl:value-of select="record"/></td>
                        <td>Warning</td>
                        <xsl:call-template name="row"/>
                    </tr>               
            </xsl:when>            
            <xsl:when test="type='Error'">
                    <tr id="error" class="error">
                        <td><xsl:value-of select="record"/></td>
                        <td>ERROR</td>
                        <xsl:call-template name="row"/>
                    </tr>               
            </xsl:when>               
        </xsl:choose> 
    </xsl:template>
   
    <xsl:template name="row">
                <td id="description"><xsl:value-of select="description"/><xsl:if test="path"><br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<xsl:value-of select="path"/></xsl:if></td>
                <td id="guid"><xsl:value-of select="guid"/></td>   
                <td id="hr"><xsl:value-of select="hr"/></td>   
                <td><xsl:value-of select="source"/></td>   
                <td><xsl:value-of select="time"/></td>
    </xsl:template>           
</xsl:stylesheet>

The log should point to issues, but in this case actually didn't finish writing - had to close the activity to make it valid!  Using the /SafeMode switch the solution opened which pointed to a bogus add-in.  That will teach me to install so many random tools to make me more efficient!

Fix port for development server in VS2008 web projects

From time to time you need to define a fixed port for web projects during development, an example may be a need to exercise services through a proxy for testing.  This can be fixed in the SLN file to ensure that for all solution users the port is fixed.

Find the project in the SLN, and VWDPort setting will be defined, set the required port and add VWDDynamicPort = "false" setting below.  once reloaded the solution will always use the chosen port.

Policy injection and logging with the Enterprise Library

There are plenty of articles out there that cover use of the logging block with enterprise library, try here and here. For method invoke logging most end up with attribute markers for logging like the LogCallHandler. Whilst this removes most of the burdensome log code within methods - it still looks ugly IMHO, and requires compilation to change log output. For example the following basic class:

    public class Foo: MarshalByRefObject
    {
        [LogCallHandler(IncludeParameters = true, 
            Categories = new[] { "General" },
            LogAfterCall = true, LogBeforeCall = true, 
            Priority = 4, Severity = TraceEventType.Verbose)]
        public void Bar(string param)
        {
            Console.WriteLine(param);
        }
    }

With configuration:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="loggingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings, Microsoft.Practices.EnterpriseLibrary.Logging, Version=3.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
    <section name="dataConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data, Version=3.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
  </configSections>
  <loggingConfiguration name="Logging Application Block" tracingEnabled="true"
    defaultCategory="General" logWarningsWhenNoCategoriesMatch="true">
    <listeners>
      <add fileName="trace.log" header="----------------------------------------"
        footer="----------------------------------------" formatter="Text Formatter"
        listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FlatFileTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=3.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
        traceOutputOptions="None" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FlatFileTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=3.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
        name="FlatFile TraceListener" />
    </listeners>
    <formatters>
      <add template="Timestamp: {timestamp}&#xD;&#xA;Type Name: {property(TypeName)}&#xD;&#xA;Method Name: {property(MethodName)}&#xD;&#xA;Extended Properties: {dictionary({key} - {value}&#xD;&#xA;)}"
        type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=3.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
        name="Text Formatter" />
    </formatters>
    <categorySources>
      <add switchValue="All" name="General">
        <listeners>
          <add name="FlatFile TraceListener" />
        </listeners>
      </add>
    </categorySources>
    <specialSources>
      <allEvents switchValue="All" name="All Events" />
      <notProcessed switchValue="All" name="Unprocessed Category" />
      <errors switchValue="All" name="Logging Errors &amp; Warnings" />
    </specialSources>
  </loggingConfiguration>
</configuration>

gives log output:

----------------------------------------
Timestamp: 10/09/2008 12:11:40
Type Name: EntLibLogging.Foo
Method Name: Bar
Extended Properties: param - log test

----------------------------------------
----------------------------------------
Timestamp: 10/09/2008 12:11:40
Type Name: EntLibLogging.Foo
Method Name: Bar
Extended Properties: param - log test

----------------------------------------

When called using:

            Foo f = PolicyInjection.Create<Foo>();
            f.Bar("log test");

Items to note are the change in the text formatter template to use the {property()} syntax to pick up the extended properties as defined in this MSDN article.

With a pretty simple change in Config the LogCallHandler attribute can be removed from the code and logging become more flexible.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="policyInjection" type="Microsoft.Practices.EnterpriseLibrary.PolicyInjection.Configuration.PolicyInjectionSettings, Microsoft.Practices.EnterpriseLibrary.PolicyInjection, Version=3.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
    <section name="loggingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings, Microsoft.Practices.EnterpriseLibrary.Logging, Version=3.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
    <section name="dataConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data, Version=3.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
  </configSections>
  <policyInjection>
    <policies>
      <add name="Policy">
        <matchingRules>
          <add type="Microsoft.Practices.EnterpriseLibrary.PolicyInjection.MatchingRules.MemberNameMatchingRule, Microsoft.Practices.EnterpriseLibrary.PolicyInjection, Version=3.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
            name="Member Name Matching Rule">
            <matches>
              <add match="Bar" ignoreCase="false" />
            </matches>
          </add>
        </matchingRules>
        <handlers>
          <add logBehavior="BeforeAndAfter" beforeMessage="Before" afterMessage="After"
            eventId="0" includeParameterValues="true" includeCallStack="false"
            includeCallTime="true" priority="-1" severity="Information"
            type="Microsoft.Practices.EnterpriseLibrary.PolicyInjection.CallHandlers.LogCallHandler, Microsoft.Practices.EnterpriseLibrary.PolicyInjection.CallHandlers, Version=3.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
            name="Logging Handler">
            <categories>
              <add name="General" />
            </categories>
          </add>
        </handlers>
      </add>
    </policies>
  </policyInjection>
  <loggingConfiguration name="Logging Application Block" tracingEnabled="true"
    defaultCategory="General" logWarningsWhenNoCategoriesMatch="true">
    <listeners>
      <add fileName="trace.log" header="----------------------------------------"
        footer="----------------------------------------" formatter="Text Formatter"
        listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FlatFileTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=3.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
        traceOutputOptions="None" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FlatFileTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=3.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
        name="FlatFile TraceListener" />
    </listeners>
    <formatters>
      <add template="Timestamp: {timestamp}&#xD;&#xA;Type Name: {property(TypeName)}&#xD;&#xA;Method Name: {property(MethodName)}&#xD;&#xA;Extended Properties: {dictionary({key} - {value}&#xD;&#xA;)}"
        type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=3.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
        name="Text Formatter" />
    </formatters>
    <categorySources>
      <add switchValue="All" name="General">
        <listeners>
          <add name="FlatFile TraceListener" />
        </listeners>
      </add>
    </categorySources>
    <specialSources>
      <allEvents switchValue="All" name="All Events" />
      <notProcessed switchValue="All" name="Unprocessed Category" />
      <errors switchValue="All" name="Logging Errors &amp; Warnings" />
    </specialSources>
  </loggingConfiguration>
</configuration>

note the introduction of the policy injection with a specific match for the method name "Bar". 

Once you have taken the step of inheriting from MarshallByRef and instantiating using PolicyInjection to allow policy based logging, stepping onto the config based approach gives a very flexible logging capability.

 

SOA Suite 10.1.3 install issue

There is a known bug with the install of the Oracle SOA Suite on Windows Server 2003 whereby the service required to run the Oracle Application Server is not installed (bug note 423366.1). 

To fix the problem you can create the service yourself using sc.exe.

sc create Oracle<Home Name>ProcessManager binPath= "<Home Path>\opmn\bin\opmn.exe -S " DisplayName= Oracleoracleas1ProcessManager

Replace <Home Name> with the name of the Oracle Home (where the application server is installed which can be found in the registry HKLM/SOFTWARE/ORACLE/Key/ORACLE_HOME_NAME), and <Home Path> with application server the install path.  Note that the <Home Name> is case sensitive, also note the space after the binPath and DisplayName options - these are important!

This will create a service named "Oracle<Home Name>ProcessManager" which you can configure to auto start.

Using UDDI v3 from C#

Microsoft support for UDDI seems to have disappeared of late - just try tracking down anything on MSDN and you will see what I mean from all the 404's and mis-leading information you will stumble across.

UDDI is a really useful part of any SOA, and the Oracle Service Registry contained within the Oracle SOA suite (version 10.1.3) supports version 1, 2 and 3 of the specification (by the way installation of the Oracle Service Registry is not the easiest thing you will ever do).  The easiest version of the spec to implement in .NET is the version 3.

Firstly download the WSDl and supporting schema from http://uddi.xml.org.

http://uddi.org/schema/uddi_v3.xsd
http://uddi.org/wsdl/uddi_api_v3_binding.wsdl
http://uddi.org/wsdl/uddi_api_v3_portType.wsdl

download additional supporting schema from http://www.w3.org

http://www.w3.org/2001/xml.xsd
http://www.w3.org/TR/xmldsig-core/xmldsig-core-schema.xsd

saving to the same location.

Technorati Tags: ,

Edit xmldsig-core-schema.xsd and comment out the doctype definition - as this declaration makes svcutil barf as described in http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=3065329&SiteID=1).

Generate the service proxy using svcutil, making sure to reference all required WSDL and schema.

svcutil /t:code /out:svcuti.cs uddi_api_v3_binding.wsdl uddi_api_v3_portType.wsdl uddi_v3.xsd xml.xsd xmldsig-core-schema.xsd

You will need to amend the svcutil generated config to include the endpoint for the UDDI service (just add the address attribute to the endpoint config). Then you can use the proxy to access the registry.

UDDI_Inquiry_PortTypeClient proxy = new UDDI_Inquiry_PortTypeClient("UDDI_Inquiry_SoapBinding_UDDI_Inquiry_PortType");
 
find_binding fb = new find_binding();
fb.serviceKey = "uddi:systinet.com:uddi:service:v3_inquiry";
 
bindingDetail detail = proxy.find_binding(fb);
foreach (bindingTemplate template in detail.bindingTemplate)
{
   accessPoint ap = template.Item as accessPoint;
   Console.WriteLine(ap.Value);
}

The sample code defines a simple search based on the defined key of a registered service (in this case "uddi:systinet.com:uddi:service:v3_inquiry" which is a key of the UDDI inquiry service as registered in the sample data from the Oracle Service Registry install). The code then enumerates the endpoint address for each registered endpoint listed within the returned binding detail.

For more information on the use of UDDI API read http://www.uddi.org/pubs/uddi_v3.htm

DateTimePicker with nullable DateTime...

More work with nullable DateTimes!

There are oodles of articles out there discussing data binding with the DateTimePicker control attempting to address its limitations for support of nullable types.  Of course you can define your own control, or override the built in to amend the behaviour, but I wanted to see if I could use some of the .NET syntactic sugar to provide a solution that had light impact.

The idea was based on this article http://windowsclient.net/blogs/faqs/archive/2006/05/18/what-is-the-proper-way-to-bind-nullable-datetime-property-to-datetimepicker.aspx, which was obviously posted during the .NET 2 beta as it still uses INullableValue in the implementation.  The basic of this article is to use the Format and Parse events of the Binding to deal with null using the check box.  This is pretty light touch, so I thought I would wrap this in an extension to the DateTimePicker itself.  This is the extension class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
 
namespace manik.Windows.Forms
{
    public static class NullableDateTimePickerExtension
    {
        public static void AddNullableBinding(this DateTimePicker picker, Binding binding)
        {
            picker.DataBindings.Add(binding);
 
            binding.Format += new ConvertEventHandler(picker.OnFormatNullableDateTimePicker);
            binding.Parse += new ConvertEventHandler(picker.OnParseNullableDateTimePicker);
        }
 
        public static void OnParseNullableDateTimePicker(this DateTimePicker picker, object sender, ConvertEventArgs e)
        {
            Binding binding = sender as Binding;
 
            if (binding != null)
            {
                DateTimePicker dtp = (binding.Control as DateTimePicker);
 
                if ((dtp != null) && (!dtp.Checked))
                    e.Value = new Nullable<DateTime>();
            }
        }
 
        public static void OnFormatNullableDateTimePicker(this DateTimePicker picker, object sender, ConvertEventArgs e)
        {
            if (e.Value == null)
            {
                Binding binding = sender as Binding;
 
                if (binding != null)
                {
                    DateTimePicker dtp = (binding.Control as DateTimePicker);
 
                    if (dtp != null)
                    {
                        dtp.Checked = false;
                        e.Value = dtp.Value;
                    }
                }
            }
        }
    }
}

The AddNullableBinding extension will take a Binding object and hook up the Parse and Format events to further extension methods on the DateTimePicker.  Usage is really simple:

Binding testDateBinding = new Binding("Value", m_dataObject, "TestDate", true);
dtTestDate.AddNullableBinding(testDateBinding);

Just create a Binding for the date object, then call the extension method (making sure you have the correct using available of course) AddNullableBinding and that's it.  Light impact...

Nullable DateTime in PropertyGrid...

Now a lot of people hate it, but I think the PropertyGrid is cool - excellent for quick generation of edit UI.  We have shown it to customers as part of prototype build, and they have asked for its inclusion!  I was using the PropertyGrid to define a really simple editor for some data types and was working really well until I made the DateTime properties Nullable.

public virtual DateTime? EndDate
{
    get { return m_endDate; }
    set { m_endDate = value; }
}

The PropertyGrid was not displaying the editor, bit of a bummer! Although not a massive deal, I thought I was going to need to create a UITypeEditor that would cope with Nullable dates.  Fortunately if you are explicit, the built in editor supports a Nullable DateTime. 

[EditorAttribute(typeof(DateTimeEditor), typeof(UITypeEditor))]
public virtual DateTime? EndDate
{
    get { return m_endDate; }
    set { m_endDate = value; }
}

Adding the EditorAttribute specifying the DateTimeEditor to the property forces the use of the built in editor for the Nullable type.