Terry Thibodeau's Blog

Welcome to Terry Thibodeau's Blog Sign in | Join | Help

  • Consolidating and Version-controlling Development Settings

    Those who know me know that I hate repetition. Reducing duplication and improving productivity is usually the driving force behind much that I do with computers (other than my day job of software development).

    After installing Visual Studio 2008 and new versions of Resharper, I realized that I was, once again, going to have to reset all of my preferences. Tired of dealing with this, I set on a mission to formulate a process to consolidate my Visual Studio, Macro, Resharper, and any other add-on settings into a single, convenient, static location so I would never have to re-create my preferences again!

    Using a few free utilities, I was able to come up with a pretty nice solution that works well for me (and, hopefully, you as well).

    Step 1 - Visual Studio Preferences Paths

    To ensure that Visual Studio saves any preference changes to our centralized settings location, we need to change Visual Studio's preferences to point to a nicer location than My Documents (man, I hate the My Documents folder). The spots that you want to change are the "Projects and Solutions" directories and "Import and Export Settings".

    I change locations to a separate partition/drive because I like to keep my operating system partition separate from my data partition. I can then freely re-install my OS without worrying about all of the data that would be overwritten in the process (this is why I don't like the My Documents, My Pictures, etc.)


    You will probably also want to include the new path to your Visual Studio Add-ins folder (in the new, centralized location)

     

    Macro Projects

    The Macro Projects have their own IDE environment whose preferences also need to be set to point to the centralized location. In the Visual Studio IDE, press ALT+F11 to open the Macro IDE. Open the Tools -> Options menu and set the Projects and Solutions locations to the same as the Visual Studio IDE paths.

    I also open up the Macro Explorer (ALT+F8) in the Visual Studio IDE and create a new Macro project. I then set it as the recording project (so my macros are also centralized and versioned). When creating your new Macro Project, ensure that the path is pointing to your centralized DevAppData directory (it should if you've properly set the Macro IDE preferences).

     

    Step 2 - Version Controlled Settings

    Import into SVN

    The next step was to ensure that I could save my settings and revert to previous versions at any time. Enter Subversion / TortoiseSVN. If you're not using Subversion as a version control system for your development, START NOW! It's fantastic. Subversion / TortoiseSVN / VisualSVN makes for zero-friction, rock-solid Visual Studio-integrated version control.

    Now that I've moved my Visual Studio settings to a new folder, I can add them to my Subversion repository using the method I previously blogged about. If you don't already have a Subversion repository, install one easily using the FREE VisualSVNServer download from VisualSVN!

     

    Step 3 - Consolidating Other Settings

    So, you've got your Visual Studio settings moved to a safe-from-reinstall location and imported into Subversion. What about all of the other supporting applications and their settings? 

    Applications usually store their settings in the install directory, the registry (yuck), or the %APPDATA% folder (if not on a network with roaming profiles, this location is usually C:\Documents and Settings\<your username>\Application Data\).

    With all of these applications storing their settings in various locations, how can we manage them all in one convenient location?? (This is the part that I really like. :) )

    Junctions

    There is a feature in the Unix file system, called symbolic links, that allows you to create multiple "pointers" to one location on the file system. It is not very well known that the NTFS file system has had similar features since NTFS v3.0 (Windows 2000, Windows XP, Windows Server 2003, and higher). The feature that we are interested in is a "Directory Junction". I like to think of a junction as a "wormhole" from one directory to another. The great thing about a junction is that a change in the junction directory's contents will show up in the original directory. As far as the OS is concerned, they are directories at different paths, but the contents come from the same location.

    There are many tools to help you create and manage junctions in Windows. The one that I like to use is Hardlink Shell Extension which allows me to manage the junction points with a context menu in Windows Explorer. Using Hardlink Shell Extension, I create "wormholes" to application settings directories from within my consolidated, version-controlled settings directory (I actually have to create the junction in reverse to play well with Subversion but I'll get to that).

     

    Playing nicely with Subversion

    Subversion doesn't like junctions in its structure (you get an error when trying to commit). To combat this, I simply copy the original setting folder that I wish to consolidate into my centralized location. Then, I make a junction from the centralized location back to the application's settings directory.

    Let's use the Visual Studio "Schemas" directory as an example. I like to make a junction to the Schemas folder in my centralized settings folder so I can easily add new .xsd files for intelli-sense, such as NHibernate schemas. Instead of searching through C:\Program Files\Microsoft Visual Studio...bla bla bla, I know I can drop new schemas in my centralized "Schemas" junction and Visual Studio will pick them up.

    1. First, copy the Schemas folder to your centralized settings location. For VS2008, you can find it at "C:\Program Files\Microsoft Visual Studio 9.0\Xml\Schemas".
    2. Now, rename "C:\Program Files\Microsoft Visual Studio 9.0\Xml\Schemas" to "C:\Program Files\Microsoft Visual Studio 9.0\Xml\Schemas.bak" (or delete the Schemas folder. I like to make a backup, just in case).
    3. From your centralized settings folder, pick the newly copied "Schemas" folder as the junction link source

      Import into SVN

    4. Now, drop the junction at the path where Visual Studio expects to find these Schemas ("C:\Program Files\Microsoft Visual Studio 9.0\Xml")

         

     

    By looking at the "Schema" folder's properties, we can see that the junction Target is our centralized settings folder (D:\DevAppData\Studio Settings\Visual Studio 2008\Schemas).

       

     

    Conclusion

    When all is said and done, you should now have a nice, centralized, version-controlled Visual Studio (and associated application) settings location. You should never again have to waste time re-configuring your development environment preferences!!

  • The miracle hair!

    Since Justice appreciates my hair so much (see the last interview question), I thought I'd give the rest of the public a taste as well. Enjoy ;)

     


  • Testing NHibernate object mappings in isolation (Part 2 - dependencies)

    I thought I should post an update to "Testing NHibernate object mappings in isolation" as that post didn't address dependent objects in your mapping files. For a simple mapping to a class with only fields or component object references*, the previous method works fine.

    When you start adding references to other entities in your mapping files, you must also add those mapping file references to the Configuration object. I've refactored the code from the previous post to load the mapping file resource based on the class type. Notice the test, "Should_map_Conference_class", adds its dependencies to the configuration.

    private const string mappingFileAssemblyName = "Namespace.NHibernateMappings";

    private readonly string customConfigPath = Path.Combine(Directory.GetCurrentDirectory(), @"localNHibernate.cfg.xml");

    private Configuration configuration;

     

     

    [SetUp]

    public void TestInitialize()

    {

      configuration = new Configuration()

          .Configure(customConfigPath);

    }

     

    [TearDown]

    public void TearDown()

    {

      this.configuration.BuildSessionFactory().Close();

    }

     

    [Test]

    public void Should_map_Conference_class()

    {

      AddSingleClass(typeof (Address));

      AddSingleClass(typeof (Category));

      AddSingleClass(typeof(Conference));

    }

     

    private Configuration AddSingleClass(Type persistentClassType)

    {

      Assembly assembly = Assembly.Load(mappingFileAssemblyName);

      return this.configuration.AddResource(mappingFileAssemblyName + "." + persistentClassType.Name + ".hbm.xml", assembly);

    }

    If I were using C# 3.0 on this project, I could create an extension method for the NHibernate Configuration class to allow me to do something like:

    configuration.AddSingleClass(typeof (Address), assembly)

                  .AddSingleClass(typeof(Category), assembly)

                  .AddSingleClass(typeof(Conference), assembly);

     

    * - A component is a contained object that is persisted as a value type, not an entity. See Component Mapping in the NHibernate documentation.

  • Testing NHibernate object mappings in isolation

    The other day, I found myself creating a bunch of new NHibernate object mapping files for the project I'm working on now. To test these, I had created a simple test case to ensure that the mapping files were valid by invoking BuildSessionFactory on the Configuration object (with the appropriate assemby containing the mapping files specified in AddAssembly). This is all fine and good, but if you have multiple mapping files being tested in one test, it's not a very isolated test. I set out to break up my mapping file tests into separate test cases. This proved to be a pain in the ass, simply because of the confusion I had around loading a single mapping file into the configuration.

    There are many ways to initialize an NHibernate session with your class mappings (AddAssembly, AddClass, AddResource, AddFile, AddDirectory, AddInputStream....), but I wanted to get the "automatic" discovery functionality that you get when using AddClass or AddAssembly for a single mapping file (*.hbm.xml). I thought this would be a simple, straight-forward exercise.

    What I wanted to do was specify a single Class.hbm.xml file to load and validate against the persistent class to which it is mapped. After reading through the NHibernate docs, I figured that AddResource would probably be my best bet as it lets me specify a direct path to the resource (in this case a mapping file). The AddResource signature looks like so:

    /// <summary>

    /// Adds the mappings in the resource of the assembly.

    /// </summary>

    /// <param name="path">The path to the resource file in the assembly.</param>

    /// <param name="assembly">The assembly that contains the resource file.</param>

    /// <returns>This configuration object.</returns>

    public Configuration AddResource(string path, Assembly assembly)

    After unsuccessfully attempting many different naming conventions for the path and scouring the documentation and the 'net for documentation, I finally resorted to the NHibernate source for the answer (man, I love open source software :) ). It turns out that NHibernate is using the Assembly class's GetManifestResourceStream() method in AddResource. After reading a couple of others' posts about having trouble with the syntax for GetManifestResourceStream(), I decided to do a couple tests to see what was going on here.

    I like to create a separate project specifically for NHibernate resources. Keeping with this convention, I setup a test project (see image below) to test the resource path requirements.

    NHibernate Mapping file project  Embedded Resource
    Note: the hbm.xml files need to be set as Embedded Resource for AddResource to find them

    By calling GetManifestResourceNames() on my ResourceTesting.NHibernateMappings assembly, you can see what format that GetManifestResourceStream() is expecting:

    Console Output
    ResourceTesting.NHibernateMappings.Subfolder.ClassMapping.hbm.xml
    ResourceTesting.NHibernateMappings.ClassMapping.hbm.xml

    Armed with the knowledge of the resource path syntax, I can now create a test to load a single mapping file from an assembly using NHibernate's AddResource method with the proper path syntax. Here's a sample test. I will likely refactor this for reuse to allow mapping file path inference based on the persistent class type, but this demonstrates the concept.

    [Test]

    public void Should_map_single_class()

    {

      Assembly assembly = Assembly.Load("ResourceTesting.NHibernateMappings");

      configuration = configuration.AddResource("ResourceTesting.NHibernateMappings.ClassMapping.hbm.xml", assembly);

     

      Assert.AreEqual(configuration.ClassMappings.Count, 1);

      // NHibernate won't try to map to the persistent class

      // unless you BuildSessionFactory

      configuration.BuildSessionFactory();

    }

    The thing that bugs me about the GetManifestResourceStream call is that you call it on an Assembly instance. Why not have this call infer the fully-qualified resource path from the instance? Then, I could just pass in the resource name. There are probably reasons of which I'm not aware for the decision not to infer the full path, so in lieu of this being implemented in the .NET framework or NHibernate, I hope this helps someone else struggling with resources and NHibernate.

    As a side note, I thought that the "Namespace Provider" property on my resource project's subfolder would play a part in the resource path, but it turns out that this is a Resharper addition. See David Laribee's post about it here.

  • TortoiseSVN - import an existing file structure

    Recently, I've been using Subversion as a versioned backup system for a couple of my "settings" folders (an upcoming blog post has an awesome example of this...stay tuned). In this post, I'm going to show you how to import an existing folder structure into Subversion while keeping it as your working folder as well.

    Bad way

    If you've ever used TortoiseSVN to add an existing folder structure into Subversion, you may have done it like so:

    Import into SVN
    1. Right-click the folder you wish to add to version control
    2. Choose "Import" from the TortoiseSVN menu
    3. Choose the repository
    4. Wait for the data to upload

    We now have the folder in our repository. But what about versioning local changes made to this structure? Well, you have to get a working copy from Subversion. Since we already have an existing folder with all of the files, we can't do a Checkout in the same place (which is what we want to do) or TortoiseSVN complains. What can we do? Well, we could delete that folder and Checkout.

    However, it's not very efficient to upload the entire directory structure to SVN, just to turn around and download the very same data we already have! Here's the solution:

    Good way

    1. Right-click any folder and choose "Repo-browser" from the TortoiseSVN menu
    2. In the repository, create a folder of the same name as the root of the folder that you wish to import (in the appropriate repo path where you'd like the folder to live)
      Create SVN repository folder
    3. Right-click the root folder that you wish to add to SVN and choose "Checkout" from the TortoiseSVN menu
    4. Choose the path to the newly created, empty folder in the repository, click OK
      SVN Checkout
    5. Now that you have a working SVN copy, you can right-click the root folder and choose "Add" from the TortoiseSVN menu. Select all the subfolders and files
    6. Commit (you could also have chosen Commit instead of Add and then added the files from the Commit dialog)

    You now have a local, SVN working copy, imported into Subversion, without having to upload AND then download the same data!

More Posts Next page »
Powered by Community Server (Personal Edition), by Telligent Systems