Monday, August 09, 2010

Dear Microsoft: Embrace JavaScript Already

It’s 2010:JavaScript is 14 years old, and you’ve officially supported “JScript” for the past 13 years.  Yet today, I have to open my JavaScript file in the FREE, OPENSOURCE, NotePad++ to find a missing closing } deep in my JavaScript file, because your latest premium Visual Studio IDE still can’t properly parse the language.

I appreciate the efforts you’ve gone to with improved intellisense in VS2010, but that is far from enough.  Why do we still need macros or plugins for elementary functionality such as function outlining, a document hierarchy tree, bracket matching and other validation?

As long as there is an internet driven by HTML, there will be JavaScript right beside it.  Embrace it already.

Labels: , , , ,

Friday, June 11, 2010

How to Always Run Visual Studio As Administrator

To jum straight to the solution, click here

“Certain tasks, including debugging and creating local IIS applications, require that you start Visual Studio as a user with Administrative privileges. On Windows Vista, and Windows Server 2008 when not running as the built-in Administrator account, this requires right-clicking the Visual Studio 2008 icon in the Start Menu and choosing Run as administrator.

“To make this process easier, you can create a shortcut and check the Run this program as an administrator check box on the Compatibility tab of the shortcut properties.”
from Using Visual Studio 2008 with IIS 7 @

On the last few projects I’ve worked on, we’ve used IIS sites for our development (for a number of reasons I won’t detail here), and the need to open VS in admin mode has been a constant annoyance.  It’s like constantly getting bitten by a mosquito. Today I finally got annoyed enough to spend 5 minutes researching a solution.  (I know.  I procrastinate.)

The solution, or what seems to be working for me so far at least was found at How to Run a Program as an Administrator in Windows 7.  Some of these options I knew about, the one I hadn’t tried and which worked for me was this:

1. Right click on the program shortcut or program .exe file, then click on Properties, and on the Compatibility tab. (See screenshots below)
NOTE: If you are doing this while logged on as a standard user instead of an administrator, then you will need to also click on the Change settings for all users button and type in the administrator's password.

Run as Administrator-compatibility_mode1.jpgRun as Administrator-compatibility_mode2.jpg

2. To Always Run this Program as an Administrator -

A) Check the Run this program as an administrator box, and click on OK. (See screenshots above)

The key is to change the compatibility setting of the Visual Studio EXECUTABLE, not the shortcut to it.  I.e., on my laptop, I went to C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ and right-clicked devenv.exe and then proceeded as above.

I then had to add one more step – when I now clicked on a .sln file, nothing would happen.  It appears the default Open action couldn’t run, I assume, due to inadequate privileges.  To fix this, I right-clicked the .sln file, selected Open With –> Choose Default Program, and then selected Visual Studio, making sure Always use… was checked.

Presto – my .sln files now open asking to be run as admin, as do my jump list projects.

Itch scratched.

Labels: , , , , , , , ,

Thursday, May 27, 2010

Enabling Support for HTML 5 Schema Validation in Visual Studio 2010

Out of the box, HTML 5 schema validation is not supported in Visual Studio 2008 and 2010.  The folks on the Visual Web Developer Team rectified this for VS 2008 and Visual Web Developer, but they did not provide any update for VS 2010 (that I know of).  No matter, you can use the 2008 version – here’s how.

1. Download the schema update for VS 2008/VWD

2. Open the downloaded zip file and follow the instructions in the ReadMe.txt file except:

2.a) Where it says to add the schema to C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\Packages\schemas\html, replace the 9.0 with 10.0 – the path for VS 2010 (in 64 bit Windows) is:

C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\Packages\schemas\html

2.b) Edit the VS registry file matching your Windows environment, and again change the 9.0 to 10.0 – e.g. for my Windows 7 64 bit machine the correct registry file is:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\Packages\{1B437D20-F8FE-11D2-A6AE-00104BCC7269}\Schemas\Schema 23]
"Friendly Name"="HTML 5"

3. Back up your registry

4. Run the registry file (as always, take caution)

Labels: , , ,

Friday, August 28, 2009

Making T4MVC comply with CLS

FXCop rule CA1014 tells you to mark your assembly as CLSCompliant. If you adhere to this, your T4MVC (as of build 2.4.01 at least) will throw compiler warnings saying stuff like



is not CLS-Compliant.

If you have 10 controllers and 50 views this will result in 61 warnings…

The reason is that these are public members that start with an underscore, which is a CLS no-no:


To solve this, edit the file to mark the code with a [CLSCompliant(false)] attribute.  Once you start this, you’ll also find additional warnings from mebers that implement the now-explicitly-non-compliant members, but a few more [CLSCompliant(false)] attribute handles that. Full code in gist below.

Labels: , , , , , ,

Monday, August 24, 2009

Making T4MVC comply with StyleCop

On a current MVC project we’re also using the excellent T4MVC template by David Ebbo.  StyleCop however, thinks the generated code is well, less than perfect – it generates some 500 warnings at the moment. 

The solution to this is a simple choice between two options:

Fix the TT file to generate StyleCop compliant code, or exclude the generated T4MVC.cs class from StyleCop.

The pragmatic choice here is of course to exclude the file.  But how?

I first tried to add <ExcludeFromStyleCop>true</ExcludeFromStyleCop> to the Compile entry in the csproj file. Unfortunately that only works with builds from OUTSIDE Visual Studio.

Sergey Shishkin has the answers:

Encapsulating the code in a region that contains the string “generated code” does the trick, but even easier is to simply put a // <auto-generated /> comment at the top of the generated file – which of course means edit the TT file to stick it there.

Would be nice to see this included in the next release….

Labels: , , , , ,

Tuesday, March 10, 2009

Visual Studio: A handful of useful Find and Replace Expressions

  • Find empty get; set; property declarations:
  • Replace empty get; set; declarations with single line equivalent:
    { get; set; }
  • Find candidates for single line summary comments:
    /// \<summary\>\n:b+///:b*{[^\n]*}:b*\n:b+/// \</summary\>
  • Replace candidates with single line equivalent:
    /// \<summary\>\1\</summary\>
  • Find Class Diagram generated get:
    get\n:b+\{\n:b+throw new System.NotImplementedException\(\);\n:b+\}
  • Find Class Diagram generated empty set:

Labels: , , , , ,

Monday, October 20, 2008

Installing VS 2008 SP1: Installing |/-\|/-\|


zzz….  zzz…

The Visual Studio 2008 SP1 install takes forever, and the vast majority of the time is spent in that tiny little sliver of the progress bar at the right.  The only sense you get that something is actually still running is the sad little ascii-based spinner (|/-\|/-\|).

First time I ran this I thought something had crashed, so I cancelled.  Don’t – it takes almost as long.  So I ran it again, same issue – stuck at the apparent “95%”  for longer than it takes for a cup of coffee to wear off – I was about to throw in the towel a second time when – something happened!  I was asked to shut down Word and then eventually I got this:


Yay for completing.

Boo for lousy installation progress feedback.

Labels: , , ,

Tuesday, July 22, 2008

C#: String.Inject() - Format strings by key tokens

I generally prefer to use String.Format() instead of doing a bunch of string additions, but constantly find myself splitting the code onto multiple lines with an appended comment to keep track of the indices:

string myString = string.Format("{0} is {1} and {2} is {3}",, //0, //1
  o.yadi, //2
  o.yada //3

Wouldn't it be nice you could instead write something like this?:

string myString = "{foo} is {bar} and {yadi} is {yada}".Inject(o);

Well, now you can - see the string extension method Inject below; it accepts an object, IDictionary or HashTable and replaces the property name/key tokens with the instance values.  Since it uses string.Format internally, it also supports string.Format-like custom formatting:

   1:  using System;
   2:  using System.Text.RegularExpressions;
   3:  using System.Collections;
   4:  using System.Globalization;
   5:  using System.ComponentModel;
   7:  [assembly: CLSCompliant(true)]
   8:  namespace StringInject
   9:  {
  10:    public static class StringInjectExtension
  11:    {
  12:      /// <summary>
  13:      /// Extension method that replaces keys in a string with the values of matching object properties.
  14:      /// <remarks>Uses <see cref="String.Format()"/> internally; custom formats should match those used for that method.</remarks>
  15:      /// </summary>
  16:      /// <param name="formatString">The format string, containing keys like {foo} and {foo:SomeFormat}.</param>
  17:      /// <param name="injectionObject">The object whose properties should be injected in the string</param>
  18:      /// <returns>A version of the formatString string with keys replaced by (formatted) key values.</returns>
  19:      public static string Inject(this string formatString, object injectionObject)
  20:      {
  21:        return formatString.Inject(GetPropertyHash(injectionObject));
  22:      }
  24:      /// <summary>
  25:      /// Extension method that replaces keys in a string with the values of matching dictionary entries.
  26:      /// <remarks>Uses <see cref="String.Format()"/> internally; custom formats should match those used for that method.</remarks>
  27:      /// </summary>
  28:      /// <param name="formatString">The format string, containing keys like {foo} and {foo:SomeFormat}.</param>
  29:      /// <param name="dictionary">An <see cref="IDictionary"/> with keys and values to inject into the string</param>
  30:      /// <returns>A version of the formatString string with dictionary keys replaced by (formatted) key values.</returns>
  31:      public static string Inject(this string formatString, IDictionary dictionary)
  32:      {
  33:        return formatString.Inject(new Hashtable(dictionary));
  34:      }
  36:      /// <summary>
  37:      /// Extension method that replaces keys in a string with the values of matching hashtable entries.
  38:      /// <remarks>Uses <see cref="String.Format()"/> internally; custom formats should match those used for that method.</remarks>
  39:      /// </summary>
  40:      /// <param name="formatString">The format string, containing keys like {foo} and {foo:SomeFormat}.</param>
  41:      /// <param name="attributes">A <see cref="Hashtable"/> with keys and values to inject into the string</param>
  42:      /// <returns>A version of the formatString string with hastable keys replaced by (formatted) key values.</returns>
  43:      public static string Inject(this string formatString, Hashtable attributes)
  44:      {
  45:        string result = formatString;
  46:        if (attributes == null || formatString == null)
  47:          return result;
  49:        foreach (string attributeKey in attributes.Keys)
  50:        {
  51:          result = result.InjectSingleValue(attributeKey, attributes[attributeKey]);
  52:        }
  53:        return result;
  54:      }
  56:      /// <summary>
  57:      /// Replaces all instances of a 'key' (e.g. {foo} or {foo:SomeFormat}) in a string with an optionally formatted value, and returns the result.
  58:      /// </summary>
  59:      /// <param name="formatString">The string containing the key; unformatted ({foo}), or formatted ({foo:SomeFormat})</param>
  60:      /// <param name="key">The key name (foo)</param>
  61:      /// <param name="replacementValue">The replacement value; if null is replaced with an empty string</param>
  62:      /// <returns>The input string with any instances of the key replaced with the replacement value</returns>
  63:      public static string InjectSingleValue(this string formatString, string key, object replacementValue)
  64:      {
  65:        string result = formatString;
  66:        //regex replacement of key with value, where the generic key format is:
  67:        //Regex foo = new Regex("{(foo)(?:}|(?::(.[^}]*)}))");
  68:        Regex attributeRegex = new Regex("{(" + key + ")(?:}|(?::(.[^}]*)}))");  //for key = foo, matches {foo} and {foo:SomeFormat}
  70:        //loop through matches, since each key may be used more than once (and with a different format string)
  71:        foreach (Match m in attributeRegex.Matches(formatString))
  72:        {
  73:          string replacement = m.ToString();
  74:          if (m.Groups[2].Length > 0) //matched {foo:SomeFormat}
  75:          {
  76:            //do a double string.Format - first to build the proper format string, and then to format the replacement value
  77:            string attributeFormatString = string.Format(CultureInfo.InvariantCulture, "{{0:{0}}}", m.Groups[2]);
  78:            replacement = string.Format(CultureInfo.CurrentCulture, attributeFormatString, replacementValue);
  79:          }
  80:          else //matched {foo}
  81:          {
  82:            replacement = (replacementValue ?? string.Empty).ToString();
  83:          }
  84:          //perform replacements, one match at a time
  85:          result = result.Replace(m.ToString(), replacement);  //attributeRegex.Replace(result, replacement, 1);
  86:        }
  87:        return result;
  89:      }
  92:      /// <summary>
  93:      /// Creates a HashTable based on current object state.
  94:      /// <remarks>Copied from the MVCToolkit HtmlExtensionUtility class</remarks>
  95:      /// </summary>
  96:      /// <param name="properties">The object from which to get the properties</param>
  97:      /// <returns>A <see cref="Hashtable"/> containing the object instance's property names and their values</returns>
  98:      private static Hashtable GetPropertyHash(object properties)
  99:      {
 100:        Hashtable values = null;
 101:        if (properties != null)
 102:        {
 103:          values = new Hashtable();
 104:          PropertyDescriptorCollection props = TypeDescriptor.GetProperties(properties);
 105:          foreach (PropertyDescriptor prop in props)
 106:          {
 107:            values.Add(prop.Name, prop.GetValue(properties));
 108:          }
 109:        }
 110:        return values;
 111:      }
 113:    }
 114:  }

File downloads:

Labels: , , , , , , , , ,

Wednesday, April 02, 2008

VSS: How to Fix a Broken 'Working Folder' Structure

I have a VS project that somehow ended up with a less than advantageous folder path of

C:\Documents and Settings\moss-admin\My Documents\Visual Studio 2005\Projects\MyProjectName\

Changing this in VSS proved to be difficult: you have to edit each folder's working folder path.  P.I.T.A.

Then Kevin pointed me to my very own ss.ini file sitting on the server:


Turns out this file stores all the unique Working Folder paths - to fix my problem all I had to do was replace all the individual entries that looked something like this

Dir (POA1) = C:\Documents and Settings\moss-admin\My Documents\Visual Studio 2005\Projects\MyProjectName\Foo\Bar

with a single

Dir (POA1) = C:\Projects

Problem solved.

Labels: , ,

Tuesday, June 26, 2007

Generic Batch File to GAC Assembly DLLs and PDBs

:: GACs assemblies located in the Assemblies folder - these have been stuck 
:: there by the following post-build event script on each individual project:
::	copy "$(TargetPath)" "$(SolutionDir)\Assemblies\$(ConfigurationName)\"
::	copy $(TargetDir)$(TargetName).pdb "$(SolutionDir)\Assemblies\$(ConfigurationName)

:: Temporarily navigate to the Assemblies folder
PUSHD C:\Projects\YOURPROJECT\Assemblies\Debug

:: Call the GacAssembly subroutine once for each assembly
CALL :GacAssembly YOURPROJECT.BusinessLogic
CALL :GacAssembly YOURPROJECT.DataAccess
CALL :GacAssembly YOURPROJECT.Interfaces
CALL :GacAssembly YOURPROJECT.ServiceImplementation

ECHO Recycle the "YOURAPPPOOLNAME IIS Application Pool
%windir%\system32\cscript.exe c:\windows\system32\iisapp.vbs /a YOURAPPPOOLNAME /r


ECHO -------------------------------------------------------------------------
ECHO GACing the %1 assembly and its PDB file
ECHO -------------------------------------------------------------------------
@"C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\gacutil" /u %1
@"C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\gacutil" /i %1.dll
copy %1.pdb "C:\WINDOWS\assembly\GAC_MSIL\%1\\"

Labels: ,

Monday, June 25, 2007

VS2005: Where is my Code Snippets Manager?

It appears that the Code Snippets manager in VS 2005 may or may not be hidden from view.  Normally it should be located under the Tools menu.  If you can't find it there, simply add it by selecting Customize from the Tools menu, then adding it as you would any other missing command.  In the customize dialog it is located (as it should) under the Tools category. 

Labels: ,

Friday, June 22, 2007

VS 2008 JavaScript Intellisense

Scott Guthrie has another great post on VS 2008, this time on JavaScript Intellisense:

Topics he discusses are:

  • JavaScript Type Inference
  • Intellisense for External JavaScript Libraries
  • Adding Intellisense Hints to JavaScript
  • Intellisense within External JavaScript files
  • Calling Web Services using ASP.NET AJAX
  • Creating Re-Usable ASP.NET AJAX Behaviors, Controls and Libraries

Read it all at VS 2008 JavaScript Intellisense

Technorati tags: ,

Labels: , , ,

Wednesday, June 20, 2007

7 Reasons For ASP.NET 2.0 Developers to Use VS 2008

VS 2008 can target both the 2.0 and the 3.0 (as well as the new 3.5) versions of .NET. But if you're not using 3.5, why would you want to use VS 2008?

Direct from the horse's Scott Guthrie's mouth:

  1. JavaScript intellisense
  2. Much richer JavaScript debugging
  3. Nested ASP.NET master page support at design-time
  4. Rich CSS editing and layout support within the WYSIWYG designer
  5. Split-view designer support for having both source and design views open on a page at the same time
  6. A much faster ASP.NET page designer - with dramatic perf improvements in view-switches between source/design mode
  7. Automated .SQL script generation and hosting deployment support for databases on remote servers

I for one am looking forward to it.

Technorati tags:

Labels: , ,

Wednesday, May 02, 2007

VS: Select Block

This one's for Peter - though it has been detailed extensively before:

In Visual Studio (all versions), to select a block of text (spanning portions of multiple lines), simply hold down the Alt key while clicking and dragging.

Very helpful for removing repeated whitespace, etc. tags: , ,

Labels: ,