June 2012 - Posts

Strongly Typed Application Settings Using T4

We all know that the Settings infrastructure added to .NET a while back is the "correct" way to create strongly typed application settings in configuration files.  The problem with this approach though is that the entries generated in the config file aren't pretty.  You have only limited control over the naming, there are lots of extra information to wade through and non-devs can easily get confused.  The Appsettings that has existed since v1 is a simpler approach that most people are comfortable with.  But you lose a lot of functionality by using AppSettings.  The Settings infrastructure brings into play a Settings class with strongly typed properties for the settings and default values for settings that are missing.  But sometimes that is overkill or simplicity is just too important. 

Fortunately the biggest benefit, strongly typed properties, can be easily implemented over the existing AppSettings infrastructure.  With a little bit of extra code you can even deduce the type of the settings.  This gives developers the benefits of type checking and compiler validation with the ease of configuration.  To get all this to work all you need to do is create a T4 template.  A full discussion of writing T4 templates is beyond the scope of this post so I'm assuming you already have basic knowledge.  For more information on T4 templates I recommend MSDN and some of the blogs on the topic.

  • MSDN
  • Scott Hanselman's blog on T4 with links to lots of information

The goal is to create a Settings class that wraps each of the settings defined in appSettings in the config file.  Rather than calling ConfigurationManager with some string property that might or might not exist we want to reference a strongly typed property that is enforced at compile time.  If someone removes a setting from the config file we want a compiler error to let us know.  It also makes refactoring and determining who is using the setting a lot easier. Here's some reasonable goals:

  1. Create a static class to expose each setting defined in appSettings as a strongly typed, readonly property.
  2. Use the most restrictive type for each property rather than string.
  3. Update the generated class whenever the configuration file changes during development.

There are many articles out there on how to write T4 templates so I'm not going to go into the details other than to point out a few interesting tidbits.  Also note that some of the code I'm using was inspired from the T4 work that others have done but unfortunately it has been so long that I cannot remember who all I should give credit due. 

Defining the template, finding the namespace to use and locating the configuration file are pretty standard stuff.  Here's the start of the template.

namespace <#= GetNamespace() #>
{
    internal class AppSettings
    {
    <#
        ExeConfigurationFileMap configFile = new ExeConfigurationFileMap();
        configFile.ExeConfigFilename = GetConfigPath();

        if (String.IsNullOrEmpty(configFile.ExeConfigFilename))
            throw new ArgumentNullException("The project does not contain App.config or Web.config file.");        
        
        var config = System.Configuration.ConfigurationManager.OpenMappedExeConfiguration(configFile, ConfigurationUserLevel.None);
    #>
    }
}

GetNamespace and GetConfigPath are contained in a separate ttinclude file that can be reused across templates.  They do what you might expect.  Code in the <# #> block runs when the template is evaluated and can contain any C# code.  For this template the code creates a Configuration object for the config file used by the project.  This will be used to enumerate the application settings later.  The key functionality for this template is to enumerate the app settings which we can do almost like we'd do in regular code. 

    var appSettings = config.AppSettings.Settings;      
    <#   
         foreach(KeyValueConfigurationElement setting in appSettings) {            
    #>
    public static <#= GetSettingType(setting.Value) #> <#= GetSafeName(setting.Key) #>
        {
            get
            {
                return <#= GetSettingConverter(setting.Value) #>(GetConfigSetting("<#= setting.Key #>"));
            }
        } 
        
    <#
        }
    #>    
    
        private static string GetConfigSetting(string settingName)
        {
            var setting = ConfigurationManager.AppSettings[settingName];
            return setting ?? "";
        }                
    }

For each setting the template generates a new, readonly property that returns the value from the configuration subsystem at runtime.  This is done through a helper method on the class.  <#= %> tells the generator to evaluate the expression at generation time store the results in the template.  So the setting key is baked into the code at generation time but the retrieval of the setting is deferred until runtime.

The trickier part is determining what type to use for the setting.  That is what the GetSettingConverter is for.  It is evaluated at generation time to determine the best type for the setting.  In my development the config file generally contains the default values to use for settings.  Either at deployment or via transforms the settings can be changed to match the needs of the environment.  Because the config file contains default values it makes sense that we can try to deduce the type based upon the default value.  To keep things simple we'll just stick with simple types like numbers, booleans and strings.  We could certainly get more complex but I don't think that is necessary.  If no type can be determined then string is used.

<#@ include file="StandardTemplateInclude.ttinclude" #>
<#+    
        private static string GetSettingConverter ( string value )
        {
            var type = GetSettingType(value);
            
            if (type == "int")
                return "Convert.ToInt32";
            else if (type == "double")
                return "Convert.ToDouble";
            else if (type == "bool")
                return "Convert.ToBoolean";
            
            return "";
        }
        
        private static string GetSettingType ( string value )
        {
            //Try to convert to int first
            int iValue;
            if (Int32.TryParse(value, out iValue))
                return "int";
                        
            //Double is next
            double dValue;
            if (Double.TryParse(value, out dValue))
                return "double";
                
            //Boolean
            bool bValue;
            if (Boolean.TryParse(value, out bValue))
                return "bool";
                
            return "string";
        }
#>

First the standard include file is added.  The include file contains the helper methods mentioned earlier.  In T4 these are known as class functions (callable at generation time) so they must appear after all the other blocks.  The rest of the template consists of the class functions used to determine the setting type.  GetSettingConverter takes the value of the setting as was stored in the config file and attempts to parse it to determine its type.  The GetSettingType method takes a simple approach of just attempting to convert the setting to various types until it succeeds.  If you want to support more types or add better logic then this is the method to change.  If the type cannot be determined then string is used.  It is important to note that the return value is the primitive type name because this will end up being the value that is used in the property signature.  The converter method then generates a call to the appropriate converter function to convert the string value, stored in the config file, to the appropriate type, at runtime.  For this sample the standard conversion routines are used but more likely you'll want to call specialized conversion routines that can handle invalid values.

Having implemented all this we can run the template (by right clicking and selecting Run Custom Tool) and a generated file should appear with the strongly typed properties.  The last thing that needs to happen is that the template needs to be updated whenever the config file changes.  While templates can be configured to refresh when certain files change I've had bad luck getting it to work correctly.  Therefore I just know that if I add a new setting to the config file (that I want programmatic access to) then I need to manually refresh the generated file.  While not ideal it is at least simple.

Attached to this post is the source code for the template I'm using.  It could probably be improved in many ways but for me it solves the problem at hand.  Feel free to use it if you need to.

Attachment: T4AppSettings.zip
Posted Sun, Jun 17 2012 by Michael Taylor | no comments
Filed under:
Diskeeper 2012

Condusiv has recently released the next version of Diskeeper, 12.  I've been running it for a while now and I'm still satisfied with the way it optimizes my drives without eating up the resources.  Traditionally I wipe my machine on a yearly basis because of all the extra stuff that gets installed and the slow down on the hard drives but since I've been using Diskeeper I'm averaging closer to 18 months now.  The hard drive just isn't running slow.

For those of you using SSDs then the new version may be very useful as it has optimizations for SSDs.  As you probably know SSDs shouldn't be defragged like regular drives because it'll reduce the life expectancy.  Diskeeper somehow is suppose to keep them running at top speed without reducing the lifetime.  I have no idea how it works or how well because I don't use SSD myself but as SSD becomes more common this kind of technology is going to be really useful.

Another area that has been improved is with the initial writes to the drives.  Prevention is better than curing fragmentation.  Diskeeper is suppose to prevent common fragmentation problems from occurring to begin with.  This means you don't have to waste resources on the defrag process.  Unfortunately this isn't easy to measure so I just have to take their word for it.

HyperBoost is also new to this release.  It is documented as speeding up boot times without impacting the system.  For an initial install Windows generally boots really fast but as more components are added over time it slows down considerably.  This is one of my key indicators to know when to clean the machine.  But for my current machine I haven't really noticed Windows slow down at all.  Therefore I can't really say whether HyperBoost is helping me at all or not because it certainly hasn't slowed things down.  Still, slow boots are common on Windows machines so anything that can help alleviate that is desired.

One area that was heavily modified is the UI.  I can't really say that I like the new UI.  It seems "prettier" but wasteful to me.  The old interface wasn't pretty but I could quickly see everything I needed.  True techno-geek stuff.  The new UI seems like it is designed so a non-techy person could use it.  I have to scroll to see information now which makes it harder to navigate and not everything is visible to me at once.  Defrag is not something non-techies would do so I don't understand the need for dumbing up the UI.  Maybe I'll get use to it over time but one of the things I've always liked about Diskeeper is the "set and forget" approach so I don't expect to have to use the UI very often.  This isn't really a show stopper though.

So if you haven't been defragging your drives, are using Window's poor man's defrag or just need to get a new version then Diskeeper 12 is a good product to check out.  It isn't that expensive, does its job without having to be tweaked with and will keep your system running well. 

VS2012 RC

Now that VS 2012 RC is available I think it is time to reevaluate VS 2012 and see where it stands.

The biggest complaint most people threw at the Beta was the dullness of the colors.  MS heard and backtracked on the coloring a little.  While not fully completed by the RC, VS2012 now has color again.  It is still a gray or black IDE but common icons have colors, the icons can be more easily understand and the overall coloring is starting to make sense.  Of course you'll still be able to change your theme but I think out of the box the light and dark themes are going to be OK to use.  MS also changed the status bar color for certain operations.  I'm not sure yet if this is good or bad but it is intriguing.  The only remaining issue in the UI, in my opinion, is the horrible all caps menus.  Still cannot understand this one but fortunately MS understands and has provided a way to get rid of it.  Unfortunately there is no option in the Options dialog to turn off all caps yet (hopefully there will be) but for now you can change a registry entry.  We'll see if they add the option for the final release.  Here's a link to the fix: http://www.richard-banks.org/2012/06/how-to-prevent-visual-studio-2012-all.html.  To make it easier on myself I'm also posting the registry entry that needs to be set.


HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0\General -> SuppressUppercaseConversion = 1 (DWORD)

Another big area of complaint in the Beta was Team Explorer.  TE broke everything up into different views (work items, pending changes, etc).  While this sounds good the issue comes in that in order to check something in you often need to associate the changes with a work item.  The problem is that to get to the list of work items you have to either memorize the item ID or switch to the Work Item view, run the query and then switch back to Pending Changes view.  This was slow.  Fortunately MS has modified the Pending Changes view to allow you to access your favorite queries.  While not perfect, this at least gives us a more efficient method for associating work items with changes.  We'll see if any more changes make it into the final release.

Customizing the installation of VS has also been added in for the RC.  Unfortunately the options you're given are pretty lame.  Evidently MS believes everybody wants to develop managed and native code, use all the tools in VS and some tools that aren't even produced by them.  The list of options you can turn off are limited to things like SharePoint and some C++ libraries.  In my experience developers are either going to write all native code or their going to write all managed code.  Certainly there are folks who do it all but the majority do one or the other.  Therefore not being able to toggle managed/native languages during installation seems bad.  Additionally I, personally, find a lot of the tools that ship with VS to be useless so I'd like to eliminate them as well (especially since they have their own entries in Programs & Features) but alas I can't.  I can understand some components (like SqlLocalDB) that VS requires to run but most of the components don't fit this category.  Installation size of VS is becoming more of an issue every release.  I was really hoping they would pear it down for this release.  Oh well.

Overall I am satisfied with the performance and memory usage of VS.  I have 2 or 3 instances of it open at a time and memory isn't out of hand nor is performance slow.  The RC also seems to be really stable provided you stick with the installed components.  Extensions continue to have problems with VS2012 (even MS'es own like NuGet) and some newly release tools (like EntityFramework) really don't play well with VS2012 at all.  I expect all these issues to be resolved by release time so overall I'm looking forward to VS2012 and what it will have to offer.

(Free) WinForms/WPF is Dead in VS2012 Express

UPDATE: Great news!!! Microsoft has seen the error of their ways.  They have formally announced that they will in fact release VS2012 Express for desktop apps (instead of just Metro) - http://blogs.msdn.com/b/visualstudio/archive/2012/06/08/visual-studio-express-2012-for-windows-desktop.aspx.  This is a big win for students and hobbyists.

Well VS2012 is finally in RC mode.  I have to say the UI is looking better but please, for the love of all that use VS every day, GET RID OF THE STUPID ALL CAPS MENUS!!!!!  Who in the world is designing this stuff in Redmond?  It's like they never took UI design 101 classes.  Everybody who has used a computer for more than 5 minutes knows where the menus are so why do they have to be highlighted?  It couuld just be me but it seems like the management at MS are making more and more missteps with this release as we get closer.  Now on to the really, really disasterous news for VS2012...

You will no longer be able to create WinForms/WPF apps for any OS nor any app for pre-Win8 OSes in VS 20102, for free.  That's right the only type of desktop app you can create in VS20102 Express is Metro (which only runs on Win8).  We all know that Metro is not going to catch on any time soon because Win8 is not going to be that popular.  Yet MS is going out of their way to force Win8 and Metro down everyone's throat.  Give it up MS.  Win8 is not a mandatory upgrade so unless somebody buys a new PC (and doesn't get the downgrade DVD) Win7 will continue to be the most heavily used OS for the foreseeable future.  Yet students and hobbyist won't be able to write desktop apps with VS2012 Express. 

I can't possibly imagine what group at MS thinks this is a good idea.  As a part-time professor we use MSDNAA (or DreamSpark as it is called now) to teach classes.  But it takes a couple of weeks to get the students into the system and access to the software.  During this time students need to be able to write programs.  Currently they can download the Express edition and upgrade (if they desire) to the full version when it is available.  But now, thanks to the absolutely moronic decision by MS, schools are going to have to make a tough decision - stick with VS 2010 or switch to a different IDE.  The third option (that MS is likely hoping for) - upgrading all school computers to Win8 and teaching Metro is just completely unrealistic.  Firstly first year students cannot possibly be expected to write Metro-style apps after just a couple of lectures.  That's sort of what console apps are for.  Secondly upgrading school computers is something that takes time, at least a semester, and never done lightly.  Thirdly most schools skip a version because they can rarely justify the resources and (I believe) most schools already switched to Win7.  Finally, unless you're teaching .NET, any compiler will do and their are a lot of free compilers already available.  VS is great but if the cost of using it is high then nobody will.

At this point I think MS has just put the nail in the coffin for student and hobbyist programmers.  VS2012 Express is not a viable product for them anymore.  Therefore they will either stick with VS2010 or switch to another product entirely.  Now normally I'd say that a free product cannot be knocked but in this case one of the very big benefits of VS Express is early accessibility to new programmers which leads to a more likely use of the (paid) product professionally.  But with VS2012 Express, as the current RC stands at any rate, this will not be an option.

So, fellow developers, band together and let MS know how stupid this plan to not allow non-Metro development on VS2012 Express is.  Voice your opinion and force MS to change their plans before they doom the students and hobbyists to VS2010 or subpar IDEs.  It can only hurt us long term as we have to deal with junior developers who have no experience with VS in school because of this draconian practice.