Using Mini Profiler’s TimeScript With MVC4 Script And Style Bundles

I’m in the process of updating a couple of my projects to MVC4 and switching some of the CSS and JavaScript to use the new bundle and minification features. To simplify this while using script timing in Mini Profiler I created these two extension methods.

public static class ProfilingExtensions
{
    public static IHtmlString TimeScriptBundle(this WebPageBase page, string name, params string[] paths)
    {
        var bundle = Scripts.Render(paths);
        return page.TimeScript(name, bundle);
    }

    public static IHtmlString TimeStyleBundle(this WebPageBase page, string name, params string[] paths)
    {
        var bundle = Styles.Render(paths);
        return page.TimeScript(name, bundle);
    }
}

Now instead of calling Time Script like this

@this.TimeScript("Content: Main CSS", Styles.Render("~/Content/css"))

@this.TimeScript("Content: Base JS", Scripts.Render("~/bundles/jquery", "~/bundles/jqueryval"))

You can more easily do

@this.TimeStyleBundle("Content: Main CSS", "~/Content/css")

@this.TimeScriptBundle("Content: Base JS", "~/bundles/jquery", "~/bundles/jqueryval")

Version 1.5.2 Of The Visual Studio Icon Patcher Is Now Available

Version 1.5.2 of the Visual Studio Icon Patcher is now available on CodePlex.

This version brings some minor, but important, fixes such as:

  • Better support for detecting the installed languages
  • The extract & inject commands won’t run  if Visual Studio is running
  • You may now run in extract or inject mode*
  • The p/invoke code was cleaned up based on Code Analysis recommendations
  • When a p/invoke method fails the Win32 error message is now displayed
  • Error messages use red text
  • Status messages use green text

* Extract mode will allow you to run on a machine with only Visual Studio 2010 installed and inject mode will allow you to run on a machine with only Visual Studio 2012 installed. This means you no longer need both versions installed on the same machine and you can copy the images folder from one machine to another as needed.

This version contains no new icons so if you’ve already run version 1.5 or 1.5.1 then there’s no need to run this version.

Detecting The Installed Languages For Visual Studio 2010 And 2012

Recently I needed to detect the installed languages for Visual Studio 2010 and 2012 along with the primary language (the language of the installer). There’s some information on how to do this on the MSDN site but there’s no official code to do it for you, not from outside Visual Studio at least.

The way to detect the installed languages requires that you know what edition is installed. The only way to find that out is to check the registry keys for each edition until one of them is found. There are three editions of Visual Studio plus the integrated/shell version which is what programs such as SQL Management Studio are built on.

The basic process to get this information requires looking at the available keys under HKLM\Software\Microsoft\DevDiv\vs\Servicing\11.0. Among these keys will be one for the edition (Professional, Premium, Ultimate, or Integrated/Shell) and then beneath that will be a key with the Locale ID.

The process differs a bit between versions though. For Visual Studio 2010 there will only be one Locale ID which is the language of the installer. Language packs are listed under another key which is HKLM\Software\Microsoft\DevDiv\vs\Servicing\10.0\prolp. But for Visual Studio 2012 all languages are listed under the edition key. This means there’s no way to detect what the primary language is so we simply make an educated guess and look at the HKCU\Software\Microsoft\VisualStudio\11.0\General key. Under here will be an entry called UILanguage whose value will be the user’s selected language (this is the value located under Tools > Options > International Settings).

Putting It All Together

To make these checks easier to use I wrote up two classes that will detect what edition is installed along with what languages are available to the user. Currently the Integrated/Shell check for Visual Studio 2012 is missing since the key name isn’t listed on the MSDN site. So instead of taking a guess (I think it’s devenv or minshellcore) I left this check out. If anyone knows the correct key let me know and I’ll update the code with it.

All checks against the HKLM\Software hive need to check if the system is 64bit or not. For that there’s a method called GetSoftwareRoot() which handles the check for us.

public static class VisualStudio2010
{
    // http://stackoverflow.com/q/1074411/39605
    private static RegistryKey GetSoftwareRoot()
    {
        var path = IntPtr.Size == 8
                    ? @"Software\Wow6432Node"
                    : @"Software";
        return Registry.LocalMachine.OpenSubKey(path);
    }

    // http://blogs.msdn.com/b/heaths/archive/2010/05/04/detection-keys-for-net-framework-4-0-and-visual-studio-2010.aspx
    public enum Edition
    {
        Undefined = -1,
        IntShell = 0,
        PROCore = 1,
        VSTDCore = 2,
        VSTSCore = 3
    }

    public static Edition InstalledEdition()
    {
        var rootKey = GetSoftwareRoot().OpenSubKey(@"Microsoft\DevDiv\vs\Servicing\10.0");
        if (rootKey == null)
        {
            return Edition.Undefined;
        }

        var subkeys = rootKey.GetSubKeyNames()
                                .OrderByDescending(x => x, StringComparer.OrdinalIgnoreCase);

        var names = Enum.GetNames(typeof(Edition));
        Array.Reverse(names); // this makes IntShell the last value checked

        foreach (var name in names)
        {
            if (subkeys.Contains(name, StringComparer.OrdinalIgnoreCase))
            {
                return (Edition) Enum.Parse(typeof (Edition), name);
            }
        }

        return Edition.Undefined;
    }

    public static bool IsVersionInstalled(Edition edition)
    {
        try
        {
            var key = GetSoftwareRoot().OpenSubKey(@"Microsoft\DevDiv\VS\Servicing\10.0\" + edition);
            return key != null;
        }
        catch
        {
            return false;
        }
    }

    public static string PrimaryLanguage(Edition edition)
    {
        try
        {
            var rootKey = GetSoftwareRoot().OpenSubKey(@"Microsoft\DevDiv\VS\Servicing\10.0\" + edition);
            if (rootKey == null)
            {
                return null;
            }

            var keys = rootKey.GetSubKeyNames();
            if (keys.Length > 1)
            {
                throw new Exception("There are multiple sub keys. Unable to determine the primary language.");
            }

            return keys[0];
        }
        catch
        {
            return null;
        }
    }

    public static string[] AllLanguages(Edition edition)
    {
        var languages = new[]
        {
            PrimaryLanguage(edition)
        };

        var languagePacks = GetSoftwareRoot().OpenSubKey(@"Microsoft\DevDiv\vs\Servicing\10.0\prolp");
        if (languagePacks != null && languagePacks.SubKeyCount != 0)
        {
            languages = languages.Concat(languagePacks.GetSubKeyNames()).ToArray();
        }

        return languages;
    }
}

 

public static class VisualStudio2012
{
    // http://stackoverflow.com/q/1074411/39605
    private static RegistryKey GetSoftwareRoot()
    {
        var path = IntPtr.Size == 8
                    ? @"Software\Wow6432Node"
                    : @"Software";
        return Registry.LocalMachine.OpenSubKey(path);
    }

    // http://technet.microsoft.com/en-us/library/ee225238(v=vs.110).aspx
    public enum Edition
    {
        Undefined = -1,
        Professional = 1,
        Premium = 2,
        Ultimate = 3
    }

    public static Edition InstalledEdition()
    {
        var rootKey = GetSoftwareRoot().OpenSubKey(@"Microsoft\DevDiv\vs\Servicing\11.0");
        if (rootKey == null)
        {
            return Edition.Undefined;
        }

        var subkeys = rootKey.GetSubKeyNames()
                                .OrderByDescending(x => x, StringComparer.OrdinalIgnoreCase);

        var names = Enum.GetNames(typeof(Edition));

        foreach (var name in names)
        {
            if (subkeys.Contains(name, StringComparer.OrdinalIgnoreCase))
            {
                return (Edition)Enum.Parse(typeof(Edition), name);
            }
        }

        return Edition.Undefined;
    }

    public static bool IsVersionInstalled(Edition edition)
    {
        try
        {
            var key = GetSoftwareRoot().OpenSubKey(@"Microsoft\DevDiv\VS\Servicing\11.0\" + edition);
            return key != null;
        }
        catch
        {
            return false;
        }
    }

    public static string PrimaryLanguage()
    {
        try
        {
            var rootKey = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\VisualStudio\11.0\General");
            if (rootKey == null)
            {
                return null;
            }

            var language = (int) rootKey.GetValue("UILanguage", 0);
            if (language == 0)
            {
                throw new Exception("Unable to determine the primary language.");
            }

            return language.ToString(CultureInfo.InvariantCulture);
        }
        catch
        {
            return null;
        }
    }

    public static string[] AllLanguages(Edition edition)
    {
        var rootKey = GetSoftwareRoot().OpenSubKey(@"Microsoft\DevDiv\vs\Servicing\11.0\" + edition);
        if (rootKey == null)
        {
            throw new Exception("Unable to find registry key for the " + edition + " edition.");
        }

        return rootKey.GetSubKeyNames();
    }
}

Microsoft Planning To Add More Color Back Into Visual Studio 2012

I just read that at the big purple party last week Microsoft announced they’re going to be releasing an update to add some more color back into Visual Studio 2012. Does anyone have more info on this? The official anouncement is pretty vague as well and doesn’t say anything other than they’re planning to give us some more color. They promised this more than once during the beta so it should be interesting to see their interpretation this time around.