Thursday, October 29, 2009

Multiple Web.config Management Utility

Something we all face on a regular basis is managing our Web.config files across multiple deployment environments each with their own specific set of options. The trivial, but repetitive task of managing multiple config files can become quite tedious during development and in order to take some of that stress away I have built some utilities into my own build process that automatically maintain my config files for me, allowing me to worry about more important things. Using a simple batch script which executes some basic NAnt commands I am able to rapidly generate multiple web.config files from a single template with unique values in each.

To do this, I make use of NAnt’s built-in file merging functionality which takes two files and substitutes values from one into specific locations in the other and produces a combined output. Applying this concept to creating web.config files, I have a single “web.config.format” file which looks like a normal configuration file, but contains ${Property.Name} markers in areas where a value with a given name should be substituted. I then create multiple “{deployment-type}.property” XML files which contain elements indicating each property name and its value. Finally, this is all tied together by a batch script which calls the appropriate merge commands on each file in a directory I specify.

default.build (NAnt Script)
<?xml version="1.0"?>
<project default="configMerge">
 <property name="destinationfile"
   value="web.config" overwrite="false" />
 <property name="propertyfile"
   value="invalid.file" overwrite="false" />
 <property name="sourcefile"
   value="web.format.config" overwrite="false" />

 <include buildfile="${propertyfile}" failonerror="false"
   unless="${string::contains(propertyfile, 'invalid.file')}" />

 <target name="configMerge">
   <copy file="${sourcefile}"
       tofile="${destinationfile}" overwrite="true">
     <filterchain>
       <expandproperties />
     </filterchain>
   </copy>
 </target>
</project>
Sample .Property File
<?xml version="1.0"?>
<project>
 <property name="compilationDebug" value="true" />
 <property name="customErrorsMode" value="Off" />
 <property name="smtpServer" value="mail.website.com" />
 <property name="smtpFrom" value="admin@website.com" />
 <property name="googleAnalyticsKey" value="UA-12345678-9" />
</project>
Sample Web.config.format File
<?xml version="1.0"?>
<configuration>
 <configSections>
   <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
     <section name="Project.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false"/>
   </sectionGroup>
 </configSections>
 <appSettings>
   <add key="GoogleAnalyticsKey" value="${googleAnalyticsKey}" />
 </appSettings>
 <system.web>
   <customErrors mode="${customErrorsMode}" defaultRedirect="AppError.aspx">
     <error statusCode="404" redirect="404.aspx"/>
   </customErrors>
   <compilation debug="${compilationDebug}" />
 </system.web>
 <system.net>
   <mailSettings>
     <smtp from="${smtpFrom}" deliveryMethod="Network">
       <network host="${smtpServer}" port="25" defaultCredentials="true" />
     </smtp>
   </mailSettings>
 </system.net>
</configuration>
ConfigMerge.bat (NAnt script invoker)
@ECHO OFF
SET formatFile=%2
SET outputDir=%1

IF "%2"=="" SET formatFile=%~dp0web.config.format

ECHO USING: %formatFile%
ECHO OUTPUT DIR: %outputDir%
ECHO.
IF NOT EXIST "%formatFile%" (
   ECHO Could not locate format file. Please provide a valid filename.
) ELSE (

   FOR /f %%p in ('dir /b "%~dp0*.property"') DO (
       ECHO GENERATING: web.%%~np.config FROM: %%p
       START /B /WAIT "NAnt" "%~dp0nant\nant.exe" -buildfile:"%~dp0default.build" configMerge -q+ -nologo+ -D:sourcefile="%formatFile%" -D:propertyfile="%~dp0%%p" -D:destinationfile=%outputDir%\web.%%~np.config
   )
)

To further simplify things, I built an additional batch script that invokes ConfigMerge.bat with it's first argument- output directory. By calling BuildWebConfigs.bat ..\Web I can tell the NAnt script to output the generated config files in my website project's "Web" directory (and additionally replace Web.config with my Web.debug.config).

BuildWebConfigs.bat (ConfigMerge.bat invoker)
@ECHO OFF
call "%~dp0build\ConfigMerge.bat" ..\Web
copy "%~dp0Web\web.debug.config" "%~dp0Web\web.config" /y
echo.
echo ********* BuildWebConfigs Complete *********

In the interest of convenience I added a call to the second batch script into my website project's build events and included it as an external tool which I can easily invoke from Visual Studio's UI:

 

Since Visual Studio doesn't let you define per-configuration build events in C# projects (as it does in C++ projects- or so I'm told) I manually edited the CSProj file and added an instruction at the very bottom to call my batch script on all non-Debug builds:

Partial .CSProj File
<Project>
 ......
 .......
 ........
 <PropertyGroup Condition=" '$(ConfigurationName)' != 'Debug' ">
   <PostBuildEvent>
     call $(SolutionDir)BuildWebConfigs.bat
   </PostBuildEvent>
 </PropertyGroup>
</Project>

I have configured all of my solutions that use this utility to have BuildWebConfigs.bat and a folder called "build" in the $(SolutionDir). The "build" folder is laid out like so:

Folder Structure
------------------------------
+ nant
  - nant.exe
  - <related nant files>
- ConfigMerge.bat
- default.build
- {somename}.property
- {somename}.property
- {somename}.property
- web.config.format
------------------------------

I have also built a NAnt script which performs the same actions as the ConfigMerge batch script, but I find it runs significantly slower (about 4.5 seconds longer) than the batch because the NAnt script has to spawn additional instances of NAnt to perform the required actions. I've included it here in case you'd like to play with it:

Alternative NAnt-based NAnt script invoker
<project name="generate configs" default="generate ">
 <property name="destinationfile"   value="web.config" overwrite="false" />
 <property name="propertyfile"  value="invalid.file" overwrite="false" />
 <property name="sourcefile"   value="Web.format.config" overwrite="false" />

 <include buildfile="${propertyfile}"   failonerror="false"   unless="${string::contains(propertyfile, 'invalid.file')}" />

 <target name="configMerge">
   <echo message="GENERATING: ${path::get-file-name(destinationfile)} FROM: ${path::get-file-name(propertyfile)}." />
   <copy file="${sourcefile}" tofile="${destinationfile}" overwrite="true">
     <filterchain>
       <expandproperties />
     </filterchain>
   </copy>
 </target>

 <target name="generate ">
   <foreach item="File" property="file">
     <in>
       <items>
         <include name="*.property" />
       </items>
     </in>
     <do>
       <property name="propertyfile" value="${path::get-file-name(file)}" overwrite="true"/>
       <property name="destinationfile" value="web.${path::get-file-name-without-extension(propertyfile)}.config" overwrite="true"/>
       <property name="sourcefile" value="Web.format.config" overwrite="true"/>
       <echo message="Generating: ${destinationfile} from ${propertyfile}."/>

       <exec program="nant\nant">
         <arg value="configMerge"/>
         <arg value="-nologo+"/>
         <arg value="-q"/>
         <arg value="-D:sourcefile=${sourcefile}"/>
         <arg value="-D:propertyfile=${propertyfile}"/>
         <arg value="-D:destinationfile=${destinationfile}"/>
       </exec>
     </do>
   </foreach>
 </target>
</project>

Downloads:

Sources:

Tuesday, October 27, 2009

Shell Command - Delete Visual SourceSafe Files

Visual SourceSafe has a tendency to litter version-controlled directories with 3 types of project tracking files (*.scc, *.vssscc, *.vspscc) that may be undesirable when sharing a project with others. This simple "Delete SourceSafe Files" Shell command will quickly delete all instances of those files in a directory and its sub-directories. To use, run this registry script:
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Folder\shell\DeleteSourceSafe]
@="Delete SourceSafe Files"

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Folder\shell\DeleteSourceSafe\command]
@="cmd.exe /c \"TITLE Removing SourceSafe Files in %1 && COLOR 9A && del *.vssscc /s /f && del *.vspscc /s /f && del *.scc /s /f\""
I got this idea from Jon Galloway's blog post on creating a shell entry to remove SubVersion files. (Yes, the code is almost identical.) Note: This will *not* remove source-control bindings from the SLN file. That must be done manually by opening Visual Studio. If this script is run on a source-controlled solution and the solution is run VS will produce an error message regarding missing source-control files. Confirming the default action will permanently remove the binding from the SLN file. For the lazy: Download Zipped Registry File. (My host refused to serve a .reg file, sorry!)

Thursday, September 3, 2009

ASP.NET Web.config - Simple Website Settings Provider

While working on a new website today I felt compelled to make myself a simple, type-safe accessor for fields in my Web.config. Using some handy reflection I came up with the solution below. Upon a call to Loader.Initialize(), reflection is used to examine all properties for the AppSettingsKeyAttibute. If the attribute exists for a given property, the property is mapped to the specified key in the provided value collection.
public class WebsiteSettings
{
 [AppSettingsKey("Website.Name"), Required]
 public static string WebsiteName
 {
  get;
  private set;
 }

 [AppSettingsKey("Uploads.TempDirectory")]
 public static string UploadsTemporaryDirectory
 {
  get;
  private set;
 }

 [AppSettingsKey("Products.ImagesDirectory"), Required]
 public static string ProductImagesDirectory
 {
  get;
  private set;
 }

 public static class Loader
 {
  public static void Initialize(NameValueCollection appSettings)
  {
   if (appSettings == null)
    throw new ConfigurationErrorsException("AppSettings collection was null.");

   foreach (var property in typeof(WebsiteSettings).GetProperties())
   {
    if (property.IsDefined(typeof(AppSettingsKeyAttribute), false) && property.CanWrite)
    {
     var attribute = (AppSettingsKeyAttribute)property.GetCustomAttributes(typeof(AppSettingsKeyAttribute), false)[0];
     var value = appSettings[attribute.AppSettingsKey];

     if (value != null)
     {
      try
      {
       var changeType = Convert.ChangeType(value, property.PropertyType);
       property.SetValue(null, changeType, null);
      }
      catch (Exception ex)
      {
       if (HttpContext.Current != null)
        ErrorSignal.FromContext(HttpContext.Current).Raise(ex);
      }
     }
    }
   }

   if (!Validate())
    throw new ConfigurationErrorsException("One or more required Application Setting is missing or empty.");
  }

  private static bool Validate()
  {
   foreach (var property in typeof(WebsiteSettings).GetProperties())
   {
    if (property.IsDefined(typeof(RequiredAttribute), false) && property.CanRead)
    {
     var value = property.GetValue(null, null);
     if (value == null)
      return false;
     if (value is string && string.IsNullOrEmpty(value as string))
      return false;
    }
   }
   return true;
  }
 }

 [AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
 private sealed class RequiredAttribute : Attribute { }

 [AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
 private sealed class AppSettingsKeyAttribute : Attribute
 {
  public string AppSettingsKey { get; private set; }

  public AppSettingsKeyAttribute(string appSettingsKey)
  {
   this.AppSettingsKey = appSettingsKey;
  }
 }
}
Mapping a setting to a property is as simple as decorating the property with the AppSettingsKey attribute which takes a string containing the name of that property in the collection. If the specified key is found, the class will attempt to convert the value of the provided key to the type of the property referencing it. If the type conversion fails, no value is assigned. The rules checked as a result of the Required attribute is that the value is not null and, if it is a string, not empty. If you find yourself using this, you may wish to further customize this evaluation and the conversion failure handlers, depending on your situation of course. Personally, I am calling the Loader.Initialize() method in the Application_Start() method of Global.asax:
protected void Application_Start(object sender, EventArgs e) 
{
    WebsiteSettings.Loader.Initialize(WebConfigurationManager.AppSettings);
}
If you found this useful, let me know!

Friday, July 31, 2009

.NET Reflection - Generic Method Type Inference of a Boxed Parameter

Before I begin- this is a fairly lengthy post and if you'd rather not read the whole thing and would just like to know how to pass a boxed object to a generic method and have the run-time properly infer the base type of that object for the method, jump to the bottom.

Today I was working on an ASP.NET MVC project I've been putting together for the past couple weeks and I realized that I have been duplicating a small piece of code over and over out of a falsely perceived necessity. After considering my options and coming up with a simple solution, I began to put it into place- only to quickly discover that there was no way to do what I wanted without some clever Reflection.

My project is set up such that all of my View pages inherit from a class I defined, MasterViewModel, which holds a few top level variables my Master Page requires for rendering. While all of my Views do inherit from MasterViewModel, the majority of them take a derived class, ContentViewPage<T>, which contains a simple generic property housing the Data (simple or complex) for that View. With this design, when I construct my View I always have the Master Page Model items included in the Controller result without having to explicitly add them in my Controller method. This is all well and good, but as you may imagine it became rather annoying to have to wrap the Model data I gave the View in a ContentViewModel<T> object at the end of every Controller call.

public ViewResult SayHello() {
 return View(new ContentViewModel<string>("Hello"));
}

So after a little digging around on Stack Overflow I decided to create myself a couple of helpers to assist in the creation of my ContentViewModel<T> object.

public static class ContentViewModel
{
    public static ContentViewModel<T> Create<T>(T data)
    {
        return new ContentViewModel<T>(data);
    }

    public static readonly MasterViewModel Empty = new MasterViewModel();
}

With this in hand I now need only write ContentViewModel.Create("Hello") to produce the same object I defined above. This seemed like a pretty decent solution at first, but I still wasn't particularly satisfied. Then it occurred to me that if I overrode the View() method of the Controller class and wrapped my objects in a ContentViewModel<T> before calling base.View() I wouldn't ever need to type ContentView.Create() again.

protected override ViewResult View(IView view, object model)
{
    if (model == null)
        return base.View(view, ContentViewModel.Empty);
    if (model is MasterViewModel)
        return base.View(view, model);
    else
        return base.View(view, ContentViewModel.Create(model));
}

protected override ViewResult View(string viewName, string masterName, object model)
{
    if (model == null)
        return base.View(viewName, masterName, ContentViewModel.Empty);
    else if (model is MasterViewModel)
        return base.View(viewName, masterName, model);
    else
        return base.View(viewName, masterName, ContentViewModel.Create(model));
}

Simple and effective, I thought.

Server Error in '/' Application.

The model item passed into the dictionary is of type 'MvcScratch.Controllers.HomeController+ContentViewModel`1[System.Object]' but this dictionary requires a model item of type 'MvcScratch.Controllers.HomeController+ContentViewModel`1[System.String]'.

Or not. This was all working swell before... what went wrong? Well, the View() method's model property is a non-generic Object, that's what went wrong. Usually that wouldn't matter because our View knows what type to cast the Model to based on the Inherits="" attribute of <%@ Page %> and therefore although we downcast our Model for the call to View() in the Controller, the View knows what to expect and upcasts it for us. Trouble is, ContentViewModel.Create() doesn't know that at run time and it only has the type of the parameter to go off of, which, no thanks to the View() method, is an object. Keep in mind, C# still knows the actual type of the object, but at run time ContentViewModel.Create() is unable to infer that until it is within the scope of the method- which is after T has been given a Type. Thus, instead of a ContentViewModel<string> being returned, we get a ContentViewModel<object>. To confirm this:

static void Main(string[] args)
{
    object str = "Hello World";
    Foo(str);
}

static void Foo<T>(T param)
{
    Console.WriteLine("typeof(T): {0}", typeof(T));
    Console.WriteLine("param.GetType(): {0}", param.GetType());
}
Which outputs:
typeof(T):              System.Object
   param.GetType():        System.String

Clearly,we can see that doesn't work quite how we'd like it to, but fear not, we're not out of luck just yet! Using a little bit of reflection we can fix this problem. The solution? Rather than calling ContentViewModel.Create() directly, and allowing the run-time to infer the the generic type T, we're going to invoke it through the class's Type definition and explictly define T's type.

typeof(ContentViewModel).GetMethod("Create").MakeGenericMethod(new Type[] { data.GetType() }).Invoke(null, new object[] { data });

BAM! If you examine this code for a moment or two you should be able to get the general idea. Using Reflection we're grabbing the Type of our method's container and then returning a MethodInfo for that method using its string representation. With that MethodInfo we are calling MethodInfo.MakeGenericMethod() which takes a array of parameter Types (in the order they're defined in the method signature) that will strongly type the method's generic parameters. So instead of T mapping to an 'object' it maps to whatever 'data.GetType()' returns- the actual parameter type. Finally, we invoke the method with a call to MethodInfo.Invoke() which receives an instance of the given Type (or null for a static method) and an Object array containing each parameter in order (or null for a parameterless method). Now if we replace the View() code from above with this call instead we can rest easy knowing that ContentViewModel<T>'s generic type is correctly instantiated.

It is worth noting that of course there is some extra overhead being created here because of our calls into System.Reflection and for that reason I am not entirely sure if this working solution is ideal- it's at least a little iffy and I'd be curious to know what the server performance looks like in a high-traffic environment where this reflection call is being run on every Controller request that doesn't explictly wrap its View() model parameter in a ContentViewModel<T> first, but maybe one of my readers can shine some light on that?

Here is a complete sample of this method invocation technique outside of my MVC project:

class Program 
{
    static void Main(string[] args)
    {
        object str = "Hello World";
        object num = 5;
        object obj = new object();

        Console.WriteLine("var\tvalue\t\tFoo() Type\tCallFoo() Type");
        Console.WriteLine("-------------------------------------------------------");
        Console.WriteLine("{0}\t{1}\t{2}\t{3}", "str", str, MyClass.Foo(str), MyClass.CallFoo(str));
        Console.WriteLine("{0}\t{1}\t\t{2}\t{3}", "num", num, MyClass.Foo(num), MyClass.CallFoo(num));
        Console.WriteLine("{0}\t{1}\t{2}\t{3}", "obj", obj, MyClass.Foo(obj), MyClass.CallFoo(obj));
    }
}

class MyClass 
{
    public static Type Foo<T>(T param)
    {
        return typeof(T);
    }

    public static Type CallFoo(object param)
    {
        return (Type)typeof(MyClass).GetMethod("Foo").MakeGenericMethod(new[] { param.GetType() }).Invoke(null, new[] { param });
    }
}

Which, outputs:

var     value           Foo() Type      CallFoo() Type
   -------------------------------------------------------
   str     Hello World     System.Object   System.String
   num     5               System.Object   System.Int32
   obj     System.Object   System.Object   System.Object

Tuesday, July 28, 2009

Check for Content in Control

While working on a project recently I had a requirement for ContentPlaceHolder in my Master Page that was wrapped in a container that I only wanted to render if the ContentPlaceHolder was actually being populated by a page inheriting the Master. The container was a Firefox-style notice bar that renders at the top of the site with a simple message and a close button. The message area of the notice bar contains the ContentPlaceHolder which will govern whether or not the notice bar gets rendered. To achieve this two things must be done:
  1. Check if any controls exist in the ContentPlaceHolder's Controls collection
  2. If controls do exist, iterate over each one and check whether or not it:
    • A) Has a text property which is not whitespace
    • B) Contains controls in its own control collection meeting the latter condition
    • C) Is currently visible
These requirements are all relatively straightforward, and as you may have guessed, recursion comes to the rescue in this scenario. Although this code is ultimately going to be called on a ContentPlaceHolder, it makes more sense (and saves code) if the method accepts a non-specific control object, rather than a ContentPlaceHolder as its parameter.
public static bool IsNonEmptyControl(Control ctrl)
{
 if (!(ctrl is ITextControl) && ctrl.Controls.Count > 0)
 {
  for (int i = 0; i < ctrl.Controls.Count; i++)
  {
   if (IsNonEmptyControl(ctrl.Controls[i]))
    return true;
  }
 }
 else if (ctrl is ITextControl && ctrl.Visible)
 {
  return HasContent(ctrl as ITextControl);
 }
 return false;
}
This method is fairly simple and has one of two paths- immediate result, or recursion leading to a result. We start by checking if we're dealing with a container or a content control. This is a rather arbitrary test, but what this means is it's a control with a non-empty Controls collection or one with a "Text" property. If the control does have children we loop over each child and call IsNonEmptyControl() on it, or if the control has a text property we check the content of that text property with HasContent().
private static bool HasContent(ITextControl itc)
{
 if (itc != null && !string.IsNullOrEmpty(itc.Text) && !IsWhiteSpace(itc.Text))
  return true;
 //else
 return false;
}

private static bool IsWhiteSpace(string s)
{
 for (int i = 0; i < s.Length; i++)
 {
  if (!char.IsWhiteSpace(s[i]))
   return false;
 }
 return true;
}
Both of these methods are pretty obvious- check thatthe text property is not null, not empty, and does not contain whitespace ("\r, \n, " ", etc). And that's all there is to it. The method can be called on any control and will correctly indicate whether or not that control has content. In my case I call it in my Master Page's Page_PreRender event and pass it my ContentPlaceHolder. Now, there is one problem with this method: it doesn't properly address 2C from above- checking whether or not the content is actually visible when we call this from the Master Page on a ContentPlaceHolder. After digging a bit I realized this is actually less intuitive than I would have hoped due to your friend and mine: Page Life Cycle. When calling this method in the Master Page's PreRender event none of the content pages have yet initialized any of their controls from the code/markup so although they are accessible, all control properties are defaulted. In fact, it is not until Page_PreRenderComplete that we are able to see the actual property values of our controls and, unfortunately, the Master Page does not throw this event. I am honestly not sure how to handle this scenario and I would be very interested to know if anyone has some ideas on how to tackle this problem. Tips
  • If you're using C# 3.0 consider changing the signature to IsNonEmptyControl(this Control ctrl) for some Extension Method goodness.
Sources

Wednesday, July 8, 2009

ASP.NET Validation - Client-Side IsControlValid() Function

While working on a rather unique form for one of the websites I maintain at work (Rated Golf) I found myself needing to do some very case specific form validation on a collection of fields. All of the fields in question had a pair of ASP.NET validation controls attached to them and depending on what the client selected while filling out the form I needed to perform validation on a variable number of fields. Namely, the user could fill out either 9 or 18 of the fields in any order and provided that one of those conditions was met I would allow submission. I spent a good bit of time digging through the ASP.NET client-side validation API to get a feel for how to go about the task at hand and finally I decided on enumerating over the page's validator collection and making sure the correct number of fields checked out. I went to work on this approach only to soon find out there is no way to check if a given control is valid- only a given validator. Now I knew that each input control had exactly two validators and that would [most likely] never change so after some tooling around I slapped together a solution. The solution I came up with was not scalable when an input control had more than two validators, so after leaving work I came up with a slightly better, less specialized solution for this problem using some very basic JavaScript. I started by defining some simple ASP.NET markup to create a TextBox, a RequiredFieldValidator, and a CompareValidator.
<asp:TextBox ID="tbxValue" runat="server" ValidationGroup="vg1" Style="width: 400px;" />
<asp:RequiredFieldValidator ID="rfvValue" runat="server" ErrorMessage="Value is required."
ControlToValidate="tbxValue" Display="Dynamic" ValidationGroup="vg1" />
<asp:CompareValidator ID="cvValue" runat="server" ErrorMessage="Value must be a number."
ControlToValidate="tbxValue" Operator="DataTypeCheck" Type="Integer" Display="Dynamic"
ValidationGroup="vg2" />
Now that our page is setup we can jump into the JavaScript. The first place to start is figuring out how many validators exist for a given control. One of the convenient nuances of the Microsoft JavaScript framework is that input fields having validators are automatically decorated with a "Validators" array at run time, making it very simple to grab a list of validators for that control. In order to simplify working with the control and its validators after verifying its validity I chose to define an IsControlValidResult object to wrap the Control, its Validators, and an IsValid field. Of course this can easily be swapped out for a simple Boolean result if that better fits your implementation:
function IsControlValidResult() {
    this.IsValid = false;
    this.Control = null;
    this.Validators = new Array();
}
And finally:
function IsControlValid(controlId, validationGroup, displayErrors) {
    var result = new IsControlValidResult();
    var validatorCount = 0;
    var validCount = 0;
    if (controlId != null && typeof (controlId) == "string") {
        var control = document.getElementById(controlId);
        validatorCount = control.Validators.length;
        if (validatorCount > 0) {
            var i = validatorCount;
            while (i--) {
                if (validationGroup == null || IsValidationGroupMatch(control.Validators[i], validationGroup)) {
                    result.Validators.push(control.Validators[i]);
                    MyValidatatorValidate(control.Validators[i], validationGroup, null, displayErrors);
                    if (control.Validators[i].isvalid) {
                        validCount++
                        if (validCount >= validatorCount)
                            break;
                    }
                }
            }
        }
        result.Control = control;        
    }
    result.IsValid = validCount >= validatorCount;
    return result;
}
IsControlValid() function accepts a controlID string and an optional (read: nullable) validationGroup string in order to limit the validation to a given validationGroup for scenarios where more than one ValidationGroup is assigned to a control and its validators. The method is quite simple and works by iterating over the control's Validators array and for each validator it calls MyValidatorValidate(), which performs the actual validation. MyValidatorValidate() is identical to the framework function ValidatorValidate() aside from an additional Boolean variable controlling whether or not the error should be displayed graphically. I chose to do this because I wanted to check the validity of a validator without visually alerting the user that I had done so. Just be warned: even though MyValidatorValidate puts ValidatorUpdateDisplay() in a conditional statement, calling "val.evaluationfunction" will still set the state of the control as invalid and if you're using the AJAX Control Toolkit's "ValidatorCalloutExtender" it will render as soon as that function executes. I was not able to identify a workaround for this. Here's the code for MyValidatorValidate():
function MyValidatatorValidate(val, validationGroup, event, displayError) {
    val.isvalid = true;
    if ((typeof (val.enabled) == "undefined" || val.enabled != false) && IsValidationGroupMatch(val, validationGroup)) {
        if (typeof (val.evaluationfunction) == "function") {
            val.isvalid = val.evaluationfunction(val);
            if (displayError && (!val.isvalid && Page_InvalidControlToBeFocused == null && typeof (val.focusOnError) == "string" && val.focusOnError == "t")) {
                ValidatorSetFocus(val, event);
            }
        }
    }
    if (displayError)
        ValidatorUpdateDisplay(val);
}
If, after calling MyValidatorValidate, you have any ValidatorCalloutExtenders being rendered on the page that you would like hidden from the user, the following function will turn off all visual validation cues:
function Unvalidate(myValidationGroup) {
    // Remove the validator control(s) from display.
    var myValidators = Page_Validators;
    if ((typeof (myValidators) != "undefined") && (myValidators != null)) {
        for (i = 0; i < myValidators.length; i++) {
            var myValidator = myValidators[i];
            if (myValidationGroup == null || IsValidationGroupMatch(myValidator, myValidationGroup)) {
                if (myValidator.style.visibility.length > 0 && myValidator.style.display.length == 0) {
                    myValidator.style.visibility = 'hidden';
                }
                else if (myValidator.style.display.length > 0 && myValidator.style.visibility.length == 0) {
                    myValidator.style.display = 'none';
                }
                if ((typeof (myValidator.ValidatorCalloutBehavior) != "undefined") && (myValidator.ValidatorCalloutBehavior != null)) {
                    myValidator.ValidatorCalloutBehavior.hide();
                    if ((typeof (myValidator.ValidatorCalloutBehavior._highlightCssClass) != "undefined") && (myValidator.ValidatorCalloutBehavior._highlightCssClass != null) && (typeof (myValidator.ValidatorCalloutBehavior._elementToValidate) != "undefined") && (myValidator.ValidatorCalloutBehavior._elementToValidate != null))
                        Sys.UI.DomElement.removeCssClass(myValidator.ValidatorCalloutBehavior._elementToValidate, myValidator.ValidatorCalloutBehavior._highlightCssClass);
                }
            }
        }
    }

    // Remove the validator summary(ies) from display.
    if ((typeof (Page_ValidationSummaries) != "undefined") && (Page_ValidationSummaries != null)) {
        for (i = 0; i < Page_ValidationSummaries.length; i++) {
            var mySummary = Page_ValidationSummaries[i];
            if (myValidationGroup == null || IsValidationGroupMatch(mySummary, myValidationGroup)) {
                mySummary.style.display = 'none';
            }
        }
    }
}
And that's all there is to it. If you found this useful don't hesitate to let me know in the Comments!

Visual Studio 2008 var Keyword ‘Bug’ – Microsoft Follow-up

I got a response back from Microsoft support regarding an issue with the var keyword in Visual Studio 2008 and what they had to say isn’t particularly surprising (or motivating):

Thanks for the feedback! You're seeing that using C# 3.0 specific language features in a .NET 2.0 targeted web project fails since the code is actually being compiled on the server using the C# 2.0 compiler (more specifically, the script blocks of Web App Projects and all of Web Sites). This is a limitation that we're currently aware of and one that we will be re-evaluating as we begin planning for the next release. In the meantime, when targeting .NET 2.0, you can actually go into "Project | Properties | Build | Advanced Build Settings" and set the language version of the project to be ISO-2, which will force the design time compilers to emit errors for C# 3.0 specific language features.

Given that we won't be able to address this issue in the upcoming VS2010 release, I'm going to go ahead and mark this bug as a "Wont Fix" but please be assured that we are tracking this suggestion internally and will be considering it again for the next product cycle.

Thanks!
DJ Park
C# IDE, Program Manager

I tested the ISO suggestion the report handler sent me and as far as I could tell ISO-2 does not cause Visual Studio to emit any errors when the var keyword is used. ISO-1 did produce some non-standard build errors, but nothing to do with the var keyword. If anyone can demonstrate otherwise I’d love to hear about it in the comments.

It would have been foolish to think Microsoft would actually want to fix this little issue, but at least they know it’s there.

Thursday, July 2, 2009

Visual Studio 2008 var Keyword ‘Bug’

I stumbled across an interesting bug while editing an ASP.NET web project in Visual Studio 2008 a few days ago and I figure after four years of using the Visual Studio suite without encountering any real bugs, one isn't all that bad. That being said, given the nature of the behavior I encountered, I was compelled to investigate the issue behind it.

With the introduction of C# 3.0's implicit variable keyword var Microsoft added some simple tricks to the compiler in order to produce the traditional C# 2.0 IL code backing this new keyword. That being so, .NET 2.0 projects are fully capable of running projects written with most C# 3.0 syntax.

The bug I encountered, if you can call it that, pertains to how Visual Studio treats code written inside ASP script tags within the page markup. As has been the case since classic ASP, C# or VB code can be written directly into the markup using <% %> tags. Consider the following rudimentary example:

<%
  string hello = "Hello";
  Response.Write(hello);
%>

Like code placed in your code behind, this code is run when the page is loaded by the user; unlike the code in your code behind, this code is not compiled until runtime. A key distinction.

This brings me to the bug I noticed in the editor that pertains more to syntax highlighting than anything else. Consider this identical example written with C# 3.0 syntax.

<%
  var hello = "Hello";
  Response.Write(hello);
%>

Functionally these two blocks of code perform the same task and produce the same IL code when compiled; however, running the latter piece of code in a .NET 3.5 project will not yield the same results as it does in a .NET 2.0 project. Due to the fact that code contained in script tags is not compiled until runtime the target environment ultimately affects the compilation of that code. For that reason, given that the .NET 2.0 runtime doesn’t know what var means it cannot correctly detect the type and compile the code.

Now this behavior is neither surprising nor a bug in itself, but rather it pertains to small lack of gracefulness on Visual Studio’s part in detecting this specific condition. In Visual Studio 2008 while editing a C# project var is a keyword that is highlighted by the editor regardless of the target platform because in all but this one scenario var can safely be used in a .NET 2.0 project and, unfortunately, the development team overlooked this one scenario.

One more thing worth noting for all you ReSharper users out there is the breaking vulnerability this exposes with the Code Cleanup tool in the plug-in. If you have ever tried configuring the Code Cleanup options you may have noticed it is possible to tell it to replace all explicit variable definitions with the implicit var keyword. If you’re running a .NET 2.0 project with inline script tags in your pages make sure to watch for this setting and ignore the inline code inspection advice.

Happy Coding!