I’m proud to announce my official entrance to the world of Open Source projects.  I just published OpenIdPortableArea on CodePlex.  It is a pluggable component for ASP.NET MVC that takes advantage of MvcContrib’s Portable Areas.  With relatively few requirements, you are able to add basic OpenId support to your applications.  For details on how to consume this Portable Area, check out the documentation I slaved over!

Proudly, this project is using mercurial.  It includes one sample project to date.  Please, take a few minutes to check it out and provide feedback.

CodePlex

DotNetOpenAuth

Thursday, April 08, 2010 10:48:12 PM (Eastern Daylight Time, UTC-04:00)  #    Comments [0] -
CodePlex | Mercurial | MvcContrib | OpenId | OpenIdPortableArea | Portable Areas

While working with areas I found that there was some occasional unexpected behavior with the order that routes get mapped.  Calling AreaRegistration.RegisterAllAreas() doesn’t give you any control over which area gets registered first.  If this becomes an issue, you may be so inclined to individually register routes.  Here is an approach:

public static void RegisterAreas(RouteCollection routes)

{

    routes.RegisterArea<BlogAreaRegistration>();

}

 

protected void Application_Start()

{

    //AreaRegistration.RegisterAllAreas();

    RegisterAreas(RouteTable.Routes);

    RegisterRoutes(RouteTable.Routes);

}


I created a RegisterAreas method just like RegisterRoutes.  Here, I can clearly register each Area one by one in the order that I choose.  This is done via an extension method on the RoutesCollection type.

public static class Extensions

{

    public static void RegisterArea<T>(this RouteCollection routes)

        where T : AreaRegistration

    {

        // instantiate the area registration

        AreaRegistration area = Activator.CreateInstance<T>();

 

        // create a context, which is just the name and routes collection

        AreaRegistrationContext context =

            new AreaRegistrationContext(area.AreaName, routes);

 

        // register it!

        area.RegisterArea(context);

    }

}


This extention method creates an instance of the AreaRegistration, and then creates an AreaRegistrationContext, and then calls RegisterArea on the area.

I find that this approach demystifies RegisterAllAreas and focuses on intention over convenience.  Registering areas individually is not always necessary, but it can be helpful to reduce routing confusion.

Wednesday, March 31, 2010 9:55:01 PM (Eastern Standard Time, UTC-05:00)  #    Comments [1] -
Areas | ASP.NET MVC | Routing

Opinions vary greatly with regular expressions, ranging among obliviousness, adoration, or disgust.  It’s no secret that I commonly use regular expressions to solve silly string problems.  I maintain that they can be simple to understand, and simple to unit test when used often and responsibly.  Using them in small doses is a way to get over the learning curve.  Here’s a simple problem that I came across, and I was able to quickly solve it without going way out of my way.

Imagine that I’m working in a source base where a Person class contains a string property called Phone which contains a phone number.  That string property can contain an impressive variation of formats for phone numbers.  Now imagine that I was tasked with consuming a third party library, which defines its own Person object.  Instead of having a string property for a phone number, it defines a PhoneNumber class with a property for Area, Exchange, and Phone.  The constructor is parameterless, so it adheres to a tight/formal definition of a phone number.  Crap.

This is where regular expressions shine.  Sure, I could write a ton of code and account for a million and one cases of what a phone number could look like.  Or, I could be generic about it and describe the pattern that phone numbers follow:

\W*\(*\d{3}\)*\W*\.*\W*\d{3}\W*-*\W*\d{4}\W*

This pattern roughly matches sets of 3, 3, and 4 digits with some input forgiveness in between (random spaces, dashes, and parentheses).  With a pattern like this, we are able to reasonably assert that a string is a phone number.  Test it for yourself.

There is a problem with this pattern.  It only confirms that the string matches.  Sure, that’s a good thing, but let us not forget the original problem.  The PhoneNumber class from this third party is string-ignorant.  I need a way to extract the critical parts of this string to an instance of this PhoneNumber class.

How?  Named Capturing Groups, that’s how.  Named capturing groups aren’t too bad.  Let’s look at a contrived example (those are the best).

Capture a string of three digits, named “digits”:

(?<digits>\d{3})

In this pattern, "\d{3}" matches a string like "123" and is grouped by the key "digits".  Groups are created by using "(?<>)".  The group name goes between the angle brackets, "<digits>".  Perhaps it will make more sense to see it in practice.

string pattern = @"(?<digits>\d{3})";

string input = "hello 123 world";

Match match = Regex.Match(input, pattern);

string result = match.Groups["digits"].Value;


The Regex object has a Match() method that takes string input and a pattern.  The Match object returned from this call has a GroupCollection on it, which allows you to index into it with string keys.  The keys are the names given to groups.  In this example, our group was named "digits" and the result is "123".  Neat, right?

Now that we have a pattern that can match phone numbers, it would be nice to allow Regex to do the dirty work for us as it matches.  We can take advantage of named capturing groups here:

\W*\(*(?<area>\d{3})\)*\W*\.*\W*(?<exchange>\d{3})\W*-*\W*(?<phone>\d{4})\W*

Now we’re able to capture "area", "exchange", and "phone" while performing a match.  There’s lots of ways to implement this code.  Since it’s a third party library, I choose to write an extension method.

static class PhoneNumberExtensions

{

    const string pattern

        = @"\W*\(*(?<area>\d{3})\)*\W*\.*\W*(?<exchange>\d{3})\W*-*\W*(?<phone>\d{4})\W*";

    public static void SetFromString(this PhoneNumber phoneNumber, string input)

    {

        Match match = Regex.Match(input, pattern);

 

        phoneNumber.Area = match.Groups["area"].Value;

        phoneNumber.Exchange = match.Groups["exchange"].Value;

        phoneNumber.Phone = match.Groups["phone"].Value;

    }

}

 
The code is virtually the same as the first example.  The usage is also simple.

PhoneNumber myPhoneNumber = new PhoneNumber();

myPhoneNumber.SetFromString("(123) 456 - 7890");


These are the kinds of problems I like to solve with Regular Expressions.  It takes the tediousness out of dealing with strings.

Thursday, March 25, 2010 9:00:33 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
Regular Expressions

A few people have asked me for my IDE font and color schemes.  I thought it might be worthwhile to post it to my blog so that others may have access to it as well.   I use a light on dark scheme, which I adapted from Oren Ellenbogen’s VS2005 Colors.  I originally found it on Scott Hanselman’s Visual Studio Programmer Themes Gallery post.  The font I’m using is Consolas, which looks best with ClearType and has become pretty popular.

image

Enjoy!

johncoder_color_scheme.zip (1.85 KB)
Saturday, March 20, 2010 4:20:10 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
Color Schemes | Visual Studio

I can’t help it, Mercurial is my favorite VCS right now for several reasons.  I thought it might be helpful to post a list of resources that I’ve come across.

  • TortoiseHg - Download and install it!  TortoiseHg adds an item to context menus in Windows Explorer.  It also includes Mercurial.
  • Mercurial - The Mercurial website; contains lots of educational material.
  • Mercurial: The Definitive Guide - by Bryan O’Sullivan.  For all of your nitty gritty HG needs.
  • HgInit - Joel Spolsky’s introduction to Mercurial, with a little reeducation for SVN users.
  • Hg Tip - Tips for beginner and advanced users alike.
  • Using Mercurial with CodePlex and GitHub - Great post by Jeremy Skinner.
  • TekPub: Mercurial with CodePlex (free) - A special free episode.  Rob Conery walks through using Mercurial with CodePlex.
  • TekPub: Mastering Mercurial - The TekPub series on Mercurial.
  • VisualHG - Visual Studio plug-in that adds Mercurial to your list of Source Control plug-ins.
  • BitBucket - A code hosting site for Mercurial.
  • TeamCity - A continuous integration build management system by JetBrains that Supports Mercurial.  I tried this out recently, and configured it in parallel with VSS for a single project.  When I ran it cold, Hg was 65% faster than VSS.
  • Reference Cards & Cheat Sheets

If you have anything to add, please comment and I’ll update the post.

Saturday, March 13, 2010 8:59:41 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
Mercurial

Today I was challenged by a coworker to find out which tables in our database require SQL Cache Dependencies in our Application.  His use case involved automated testing, and wanted a better alternative to updating a CSV containing the table names.  Since he has access to the application’s assembly, I had a bright idea to use reflection to solve the world’s most miniscule problem.

In order to support such a query against the assembly, I needed some way to indicate that a class or business object in the assembly uses SQL Cache Dependency.  I came up with a new attribute, SqlCacheAttribute:

public class SqlCacheAttribute : Attribute { }


Now, I can decorate business objects that represent tables (Custom Collections, Repositories, etc.) with this new attribute where appropriate:

internal class CustomersRepository { }

 

[SqlCache]

internal class DepartmentsRepository { }

 

[SqlCache]

internal class ItemsRepository { }

 

internal class OrdersRepository { }

 

[SqlCache]

internal class SuppliersRepository { }


Notice that I have even marked my repositories as internal.  I have done this to demonstrate that table names for SQL Cache can be exposed while the classes remain local to the assembly.  With these attributes in place, I can now reflect against the assembly to query these names.

I created a static class called Helpers to put all of my utility methods.  The first helper method that I wrote was for getting a reference to the current assembly.  I wasn’t sure how to easily pull this off, but StackOverflow had an answer (the accepted answer wasn’t exactly what I was looking for).

/// <summary>

/// Returns the current Assembly

/// </summary>

/// <returns></returns>

static Assembly GetAssembly()

{

    string loc = (typeof(SqlCacheAttribute)).Assembly.FullName;

    return Assembly.Load(loc);

}


Yeah, I’m cheating a little here.  GetAssembly knows to use SqlCacheAttribute to find the correct Assembly.  There is probably a better way, but this worked great.  Now that I have access to this assembly, I am able to perform the actual reflection to solve our problem.  Calling GetTypes() on the Assembly is helpful, but I could surely benefit from a way to detect if a specific type has any specific attribute types on it.

/// <summary>

/// Returns true if the type has any attributes of the generic type

/// </summary>

/// <typeparam name="TAttribute"></typeparam>

/// <param name="type"></param>

/// <returns></returns>

public static bool AnyAttributes<TAttribute>(this Type type) where TAttribute : Attribute

{

    return type.GetCustomAttributes(false).OfType<TAttribute>().Any();

}


This is a generic extension method that allows Type objects to easily decide whether it has attributes of the generic type.  TAttribute has a clause that requires it to derive from System.Attribute.  Okay, so quick recap.  I can now 1) reference the assembly, 2) test types for a certain attribute.  Now consider the following code:

/// <summary>

/// Gets an array of Table Names.

/// </summary>

/// <returns></returns>

public static string[] GetTablesForSqlCache()

{

    var names = from type in GetAssembly().GetTypes()

                where type.AnyAttributes<SqlCacheAttribute>()

                select type.Name;

 

    return names.ToArray();

}


The GetTablesForSqlCache method uses LINQ to Obejcts to query the Types in the Assembly, and filtering where the types have AnyAttribute of type SqlCacheAttribute.  Pretty intuitive, right?  There is a problem with this functionality, though.  It’s highly unlikely that my table names will be ItemsRepository or DepartmentsRepository.  I need to provide a way of manipulating these names as I query them:

/// <summary>

/// Gets an array of Table Names.

/// </summary>

/// <param name="manipulate">

///     <remarks>

///         Allows the consumer to manipulate the name.

///     </remarks>

/// </param>

/// <returns></returns>

public static string[] GetTablesForSqlCache(Func<string, string> manipulate)

{

    var names = from type in GetAssembly().GetTypes()

                where type.AnyAttributes<SqlCacheAttribute>()

                select manipulate(type.Name);

 

    return names.ToArray();

}


The revised GetTablesForSqlCache function takes a delegate of type Func.  The delegate is called during the select portion of the query.  If the table names are the same as the objects decorated, I can offer a parameterless overload.

/// <summary>

/// Gets an array of Table Names

/// </summary>

/// <returns></returns>

public static string[] GetTablesForSqlCache()

{

    return GetTablesForSqlCache(p => p);

}


This completes all of the functionality required to query the assembly for SQL Cache table names.  In my solution I have added a new console application for testing this new code.  The console application has a reference to my class library project.

namespace ConsoleApplication1

{

    class Program

    {

        static void Main(string[] args)

        {

            Console.WriteLine("----- Unchanged Class Names -----");

            foreach (string s in Helpers.GetTablesForSqlCache())

                Console.WriteLine(s);

 

            Console.WriteLine("----- Manipulated Class Names ----");

            foreach (string s in Helpers.GetTablesForSqlCache(Manipulate))

                Console.WriteLine(s);

 

            Console.ReadKey();

        }

 

        static string Manipulate(string input)

        {

            int index = input.IndexOf("Repository");

            return input.Substring(0, index);

        }

    }

}


This code demonstrates the use of both overloads of the GetTablesForSqlCache method.  Since one of the overloads takes Func, the Manipulate method fits the criteria.  Running this code will generate the following output:

image

Notice that only the classes marked with the [SqlCache] attribute have been returned by this code.  This strategy could have a number of other uses, such as creating a static method in the assembly for writing out a batch file that makes calls to aspnet_regsql.exe.

Monday, March 08, 2010 10:07:05 PM (Eastern Standard Time, UTC-05:00)  #    Comments [1] -
Reflection | SQL Cache

***Disclaimer*** - This is definitely a rant, but I think we should all take a moment to reflect on our emailing habits.

Work email is a fun topic because everyone abuses it, myself included.  It is far and away one of the biggest disturbances throughout the day.  I would be willing to bet you're either nodding incessantly, or screaming "What the heck are you talking about!?" at the monitor as you read this.  Either way, I would be glad to elaborate.

Problem:  The Cc Game

You might Cc someone because you think the person in the To field will respond better if they see that someone else has been invited to the conversation.  That's wrong, don't do it.  The people who get included on these emails can't get to other emails that are actually important, or may skip over the wrong emails.  If you feel like that is the only way to get an answer, then email is probably the wrong medium of communication.

CYA is a culprit motive of the Cc game, but we shouldn't have to feel like we need to cover our footprints with everything we do.  If you feel that way, it's probably a good idea to discuss it with someone.

Another reason to Cc someone (or better yet, a mailing list) is a shift of responsibility.  For all intents and purposes, it's like raising a flag to identify a problem, and then offloading the burden to all included parties.  Again, don't.  If you need help, you should have a prioritized list of people to talk to about your problem.  If you don't know who to talk to, don't use the spaghetti test (throw it at the wall and see what sticks).  Ask someone else who might know who you should ask.  Sometimes, there's even a process to dictate that for you.

A side effect of playing the Cc game is that people hit the Reply To All button.  If you're going to hit Reply To All, take a second to skim the recipients, and knock off the unnecessary ones.

Funny side note:  I saw an email today that had individually listed a few of my team members and myself in the To line, and then our emailing list in the Cc field.  Redundant!

To be clear: email is not unnecessary, but its misuse is.  Good communication has a strong correlation with success but it can be a double edged sword.  Over communication is distracting, and has a direct negative effect on productivity.  One general piece of advice I found while googling this topic was to only include recipients if you would actually call them on the phone about the issue at hand.  If you wouldn't include all of my team members in a meeting about your priority, then by Modus Ponens it is also unnecessary to include them in the Cc.

I'm not alone with this opinion, others feel this way tooMany other peopleLots of them.  This is all subjective, and is endlessly debatable.  I offer no concrete advice on when specific behavior is appropriate, but instead encourage you to think about who is on the receiving end before you press "Send," because I will.

Wednesday, February 17, 2010 7:18:21 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
Productivity | Email

Frankly, I’m surprised that it took until page 12 of the jQuery Cookbook to mention putting JavaScript at the bottom of the page before the closing tag.  Pages load faster with the JavaScript at the bottom, and it removes the need to use the ready() function.  This is great advice.  Using a ContentPlaceHolder helps keep the scripts in their optimal location.

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title><asp:ContentPlaceHolder ID="TitleContent" runat="server" /></title>
</head>
<body>
<div>
<asp:ContentPlaceHolder ID="MainContent" runat="server" />
</div>
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.0/jquery.min.js"></script>
<asp:ContentPlaceHolder ID="ScriptContent" runat="server" />
</body>
</html>

Then, I’m able to include an element inside of my View and use it freely.  Notice that I was able to include jquery.min.js above the ContentPlaceHolder, which means jQuery will already be warm for any JavaScript in my ScriptContent.
 
<asp:Content ID="Content3" ContentPlaceHolderID="TitleContent" runat="server">
About
</asp:Content>
<asp:Content ID="Content4" ContentPlaceHolderID="MainContent" runat="server">
<h2>About</h2>
<div class="about-message"></div>
</asp:Content>
<asp:Content ID="Content5" ContentPlaceHolderID="ScriptContent" runat="server">
<script type="text/javascript">
      $('.about-message').text("This is the About Page!");
</script>
</asp:Content>

Another added perk to this ContentPlaceHolder approach is that it lets me include other JavaScript libraries that individual Views might depend on.  Pretty simple, but I hope you enjoy it!
Thursday, January 21, 2010 10:00:41 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
ASP.NET MVC | JavaScript | jQuery

cookbook I received an email today, notifying me that I have won the mega millions.  All I have to do is send my social security number, all credit card numbers, bank account numbers, a photo copy of my driver’s license and birth certificate, and viola!

Okay so it wasn’t mega millions, but I did actually win something.  A couple of days ago I saw tweet about a contest to win a free copy of the jQuery Cookbook.  Winners were to be chosen at random, and all I had to do to enter was reply to a blog post with something silly about why I wanted the jQuery Cookbook.  The winners were announced, and I was one of the lucky five selected at random.

That’s one more book on my list to read.  I can’t wait.

Friday, December 11, 2009 10:25:18 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
Books | jQuery

Craig Shoemaker posted a blog entry yesterday, and point number six was about using a custom attribute to ease QueryString pains.  At my current job I work with ASP.NET WebForms, and I knew exactly what he was talking about.  I thought this was an awesome idea, and followed his link to a VB article on code project.  I converted the VB code to C#, and made some slight changes.

The Goal

Eliminate “keyboard slapping” and provide some robust functionality at the same time.  In other words, we’re trying to solve the following problems:

  1. Try to eliminate the need to access Request.QueryString directly.
  2. Try to make the implementation as streamlined as possible.
  3. Account for some possible use cases like:
    • Special Parameter Names
    • Synonymous Parameter Names

Out With The Old

As Craig pointed out in his blog, we’ve all written the same mindless QueryString code over and over.  It always amounts to the same boiler plate code, which involves indexing into the Request.QueryString object using a string key and safeguarding the entire operation.  Don’t repeat yourself.

protected string UserName

{

    get

    {

        if (Request.QueryString["UserName"] != null)

            return Request.QueryString["UserName"].ToString();

        return string.Empty;

    }

}


Would become:

[QueryStringValue]

public int UserName { get; set; }


AutoValueAttribute

I started with an abstract base class for this implementation.  The idea is that the attribute will have keys, and a way to get a value from those keys.  The idea behind using an abstract base is that we may implement other versions of the AutoValueAttribute later on.

//-----------------------------------------------------------------------------

/// <summary>

///     AutoValueAttribute

/// </summary>

public abstract class AutoValueAttribute : Attribute

{

    //-------------------------------------------------------------------------

    /// <summary>

    ///     Gets a collection of Keys to be used for

    ///     retrieving a value for the property.

    /// </summary>

    public abstract ICollection<string> Keys { get; protected set; }

 

    //-------------------------------------------------------------------------

    /// <summary>

    ///     Uses its keys to find a value.

    /// </summary>

    /// <returns></returns>

    public abstract object GetValue();

}


The QueryStringValue Attribute

Any property we wish to set from a QueryString parameter can be decorated with a QueryStringValue attribute.  The implementation is simple, supporting three specific use cases.  This attribute just holds onto values that we can use for processing later.

//-----------------------------------------------------------------------------

/// <summary>

///        QueryStringValue Attribute

/// </summary>

public class QueryStringValueAttribute : AutoValueAttribute

{

    #region Properties

 

    //-------------------------------------------------------------------------

    /// <summary>

    ///        Gets a collection of Keys

    /// </summary>

    public override ICollection<string> Keys { get; protected set; }

 

    #endregion

 

    #region Constructors

 

    //-------------------------------------------------------------------------

    /// <summary>

    ///        Constructor;  Defaults to property name

    /// </summary>

    public QueryStringValueAttribute()

    {

        Keys = new List<string>();

    }

 

    //-------------------------------------------------------------------------

    /// <summary>

    ///        Constructor;  Specifies a single key

    /// </summary>

    /// <param name="key"></param>

    public QueryStringValueAttribute(string key)

    {

        Keys = new List<string> { key };

    }

 

    //-------------------------------------------------------------------------

    /// <summary>

    ///        Constructor;  Specifies many keys

    /// </summary>

    /// <param name="keys"></param>

    public QueryStringValueAttribute(string[] keys)

    {

        Keys = new List<string>(keys);

    }

 

    #endregion

 

    #region Methods

 

    //-------------------------------------------------------------------------

    /// <summary>

    ///     Iterates through all of the Keys, and returns the first match

    /// </summary>

    /// <returns></returns>

    public override object GetValue()

    {

        object value = null;

 

        foreach (string key in Keys)

        {

            value = HttpContext.Current.Request.QueryString[key];

 

            if (value != null)

                break;

        }

 

        return value;

    }

 

    #endregion

}


I expanded on the concept of Keys while converting the VB code.  It originally used a string property named QueryStringParameter.  While this was straight forward, I thought it might be beneficial to build in the ability to handle many parameter names by using a list instead.  A simple use case is changing the parameter name, but wishing to maintain backwards compatibility.

The default constructor doesn’t specify a name.  Instead, the target property’s name will be used as the QueryString parameter key.  A second constructor accepts a single string.  The last constructor accepts an array of strings.  In this case, the first match is the one that will be used.

Calling the GetValue method will iterate through the list of keys, indexing into Request.QueryString until it finds a value.  There is one important caveat to be aware of, and that is if the default constructor was used, the list of keys will be empty.  If only attributes knew exactly which property they were decorating, it wouldn’t be a problem.  The code that consumes this method must add the property name if the attribute contains no other keys (more on that shortly).

Processing The Attributes Via Reflection

In order to make this widely available in an ASP.NET application, I created the processing method as a generic extension method.  The method is called ProcessAttributes.  It uses a constraint to limit it to System.Web.UI.Control objects.

//---------------------------------------------------------------------

/// <summary>

///     Processes all attributes

/// </summary>

/// <typeparam name="T"></typeparam>

/// <param name="ui"></param>

public static void ProcessAttributes<T>(this T ui)

    where T : System.Web.UI.Control

{

    const BindingFlags flags = BindingFlags.NonPublic

        | BindingFlags.Public | BindingFlags.Instance;

 

    PropertyInfo[] properties = ui.GetType().GetProperties(flags);

 

    foreach (PropertyInfo property in properties)

    {

        var att = property.GetCustomAttributes(true)

                          .OfType<AutoValueAttribute>()

                          .FirstOrDefault();

 

        if (att == null)

            continue;

 

        object value = GetValue(property, att);

 

        SetValue(ui, property, value);

    }

}


BindingFlags are used to get the properties of the Page.  Then, we iterate through each one.  Using the first QueryStringValueAttribute of each property,  we proceed to get the QueryString value, and set the property.

//---------------------------------------------------------------------

/// <summary>

///     Gets a value from the AutoValueAttribute

/// </summary>

/// <typeparam name="T"></typeparam>

/// <param name="ui"></param>

/// <param name="request"></param>

/// <param name="field"></param>

/// <param name="att"></param>

/// <returns></returns>

private static object GetValue(PropertyInfo property, AutoValueAttribute att)

{

    if (att.Keys.Count == 0)

        att.Keys.Add(property.Name);

 

    return att.GetValue();

}


As previously noted, there is a caveat for calling the GetValue method.  It iterates the attribute’s Keys property until it can get a value out of the QueryString.  If no key was specified in the attribute constructor, it will have a Keys.Count of 0.  In this case, we need to add the property’s name to the list of Keys.

//---------------------------------------------------------------------

/// <summary>

///     Sets the property with the extracted value

/// </summary>

/// <typeparam name="T"></typeparam>

/// <param name="ui"></param>

/// <param name="property"></param>

/// <param name="value"></param>

private static void SetValue(System.Web.UI.Control ui, PropertyInfo property, object value)

{

    try

    {

        object convertedValue = Convert.ChangeType(value, property.PropertyType);

        property.SetValue(ui, convertedValue, null);

    }

    catch

    {

        // Log the error and continue gracefully

        // Allow business logic to care about the real value.

        // The job here is to make the best possible effort to

        // set values from the QueryString.

        return;

    }

}


The the SetField method attempts to convert the value to the property’s data type.  There’s a strong chance that this conversion can fail.  While this is probably the most arguable aspect of the whole endeavor, I think that validation is not necessary at this point, and would be better suited for later in the life cycle of the page.  The main goal of this code is to set properties on the page to values in the QueryString.  It seems a little silly to absorb an exception, but it was meant to keep the attribute from getting in your way.

Conclusion

The barrier to entry is really small for making this feature completely streamlined.  I created a new class to derive my Pages from, called PageBase (creative, right?).  It descends from System.Web.UI.Page, and overrides OnPreInit.

//--------------------------------------------------------------------------

/// <summary>

///        Some Page Base Class

/// </summary>

public class PageBase : Page

{

    protected override void OnPreInit(EventArgs e)

    {

        base.OnPreInit(e);

        this.ProcessAttributes();

    }

}


By calling ProcessAttributes in OnPreInit, derived classes get this functionality almost completely for free.  Even if you find a need to override OnPreInit in a descending class, base.OnPreInit(e) will keep that going.  The nice part about all of this is how it finally works:

[QueryStringValue]

protected string Value1 { get; set; }

 

[QueryStringValue]

protected string Value2 { get; set; }

 

[QueryStringValue("ThirdValue")]

public string Value3 { get; set; }

 

[QueryStringValue(new[] { "FourthValue", "Value4" })]

public string Value4 { get; set; }

 

[QueryStringValue]

public int Value5 { get; set; }

 

//-------------------------------------------------------------------------

/// <summary>

///        Page Load Event

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

protected void Page_Load(object sender, EventArgs e)

{

    Label1.Text = string.Format("Value1: [{0}], Value2: [{1}], Value3: [{2}], Value4: [{3}], Value5: [{4}]", Value1, Value2, Value3, Value4, Value5);

}


Using this approach to QueryStrings greatly reduces the amount of code you need to write each time a property needs to access the QueryString.  It’s robust because it supports multiple keys, and even works against public and protected properties.  It does its best to stay out of your way while you’re coding, and hopefully shaves off a few keystrokes here and there.

Going The Extra Mile

Craig pointed out that there are other possible uses for this approach, like Form Elements, Cache and Session.  I have looked at trying this out, but found it to be much more difficult.  Things get hairy when you need to save values.  I played with the idea of a [SessionValue] attribute, and even had some success.  I could provide an identical experience to the [QueryStringValue] attribute, where values are automatically assigned.  The problem is that Session variables often change over the course of a request.  If you’re using auto properties, the value just sits there.  That’s where I came up with a PersistableValueAttribute, deriving from AutoValueAttribute.  It added to the AutoValueAttribute functionality, because it provided a Persist method for saving off the value.  I tried to use this in the OnPreRenderComplete event, and it worked.  So it worked, what’s the problem?

Sometimes it is unavoidable, but you just have to tuck your ego in your back pocket and do what you have to do.  The situation I’m talking about is when the request comes in, you change a session variable, more code runs, and then other code uses the same session variable (knowing that it was changed) during the same request.  In the effort I described in the previous paragraph the [SessionValue] property isn’t persisted until the very last second.  That creates a problem when another code depends on that value before it’s persisted.  Oops.  Added complexity isn’t very fun.  I haven’t given up on the thought, but it’s a problem for another day.

Saturday, December 05, 2009 11:12:13 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
ASP.NET | Attributes | AutoValueAttribute | C# | Craig Shoemaker | QueryString

John Nelson

mugshot I am a passionate C# Developer working in ASP.NET on an e-commerce solution for ticketing software. I work across all of the application layers, including server side functionality, and client side programming with jQuery and MS Ajax. Although my full time job is in WebForms, I spend many of my off hours working with MVC. I am especially interested in productivity and good programming practices.

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2010
johncoder.com
Statistics
Total Posts: 41
This Year: 17
This Month: 0
This Week: 0
Comments: 4