With a continuous integration and release pipeline configured and working, I was going back through projects and creating the necessary build and release tasks. One build job however was failing with the following error:

2016-03-04T13:04:26.3021168Z Set workingFolder to default: D:\TFS\tasks\NuGetInstaller\0.1.16
2016-03-04T13:04:26.3391205Z Executing the powershell script: D:\TFS\tasks\NuGetInstaller\0.1.16\NuGetInstaller.ps1
2016-03-04T13:04:26.6061472Z D:\TFS\agent\worker\tools\NuGet.exe restore "d:\TFS\_work\1\s\src\MySolution.sln"  -NonInteractive
2016-03-04T13:04:26.9761842Z MSBuild auto-detection: using msbuild version '14.0' from 'C:\Program Files (x86)\MSBuild\14.0\bin'.
2016-03-04T13:04:27.0951961Z ##[error]There are duplicate packages: log4net.1.2.10
2016-03-04T13:04:27.1041970Z ##[error]Unexpected exit code 1 returned from tool NuGet.exe

The error causing the job to fail is:

There are duplicate packages

Checking The Build

So I checked out the project and compiled with Visual Studio, no problems. Then I tried using the nuget command from the command line.

D:\Projects\MySolution\src>nuget restore
ll packages listed in packages.config are already installed.

The packages folder already exists so we have to clear it first. Since I have Cygwin installed (and I prefer the Unix tools), I just deleted the folder from the command line:

rm -rf Packages

You can obviously do this from the Windows explorer shell or use the native DOS commands.

So running the command again, all of the packages restore without issue. Hmmm…

Replicating The Error

So next, I run the identical command that was logged in the log output for the build job:

D:\TFS\_work\1\s\src>D:\TFS\agent\worker\tools\NuGet.exe restore "d:\TFS\_work\1\s\src\MySolution.sln"  -NonInteractive
MSBuild auto-detection: using msbuild version '12.0' from 'C:\Program Files (x86)\MSBuild\12.0\bin'.
There are duplicate packages: log4net.1.2.10

And now we finally get the error to duplicate.

But why?

Let’s check the versions of our NuGet utility.

On the build server, we have:

D:\TFS\_work\1\s\src>D:\TFS\agent\worker\tools\NuGet.exe
nuget Version: 3.2.1.10581

On the workstation with Visual Studio (with NuGet specified in the path), we have:

D:\Projects\MySolution\src>nuget
NuGet Version: 2.8.50926.602

Different NuGet Versions

So the build server is using the 3.x branch of NuGet which doesn’t handle XML errors as gracefully (or is more strict) as the prior version. So now we know the cause of the problem, let see if we can find the duplicate.

And sure enough, inside of a subproject we have the following inside of the packages.config file:

  <package id="log4net" version="1.2.10" targetFramework="net45" />
  <package id="log4net" version="1.2.10" targetFramework="net45" />

Remove the dupliate line, recommit and push the code.

Problem SOLVED!

I stumbled across a link to the CommandPromptHere git hub repository and immediately thought to myself…

Hey I could use that!

So I installed it but it wasn’t quite what I wanted. In particular, like the built-in “open command window here” option, I only wanted it available when I held down the shift key.

So after a bit of digging, I stumbled across the Microsoft article titled Creating Shortcut Menu Handlers. While reading the article, I discovered that through the registry we could create cascading menus. Hmm… I liked that idea even better. So after a bit more reading and frustration due to the poor documentation, I finally found success!!!

opencommandwindowhere-custom

commandprompt-defaultregistryAlthough I still hadn’t solved my original desire which was to make it activate only when you “Shift” right-click. Inspecting the default registry key (HKCR\Directory\Shell\Cmd), we find an empty string value labeled “Extended”. By simply adding this empty string value to our command, it now works as intended. That was easy!

But why stop there? How about an elevated command prompt? So a quick search lands us on the seven forums page labeled Add or Remove “Open Command Window Here as Administrator” to Context Menu. Add those registry settings and we’re all set.

Of course you can continue to customize to suit your needs and preferences.

For reference, here is the completed registry file.

[ Download ]

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\Directory\Background]

[HKEY_CLASSES_ROOT\Directory\Background\shell]

[HKEY_CLASSES_ROOT\Directory\Background\shell\cmd]
@="@shell32.dll,-8506"
"Extended"=""
"NoWorkingDirectory"=""

[HKEY_CLASSES_ROOT\Directory\Background\shell\cmd\command]
@="cmd.exe /s /k pushd \"%V\""

[HKEY_CLASSES_ROOT\Directory\Background\shell\runas]
@="Open command window here as Administrator"
"Extended"=""
"HasLUAShield"=""

[HKEY_CLASSES_ROOT\Directory\Background\shell\runas\command]
@="cmd.exe /s /k pushd \"%V\""

[HKEY_CLASSES_ROOT\Directory\Background\shell\VisualStudio]
"Extended"=""
"subcommands"=""
"MUIVerb"="Open command window here for Visual Studio"

[HKEY_CLASSES_ROOT\Directory\Background\shell\VisualStudio\Shell]

[HKEY_CLASSES_ROOT\Directory\Background\shell\VisualStudio\Shell\2013CmdHere]
@="VS 2013 Prompt"
"Icon"="C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\Common7\\IDE\\devenv.exe,0"

[HKEY_CLASSES_ROOT\Directory\Background\shell\VisualStudio\Shell\2013CmdHere\command]
@="C:\\Windows\\system32\\cmd.exe /k cd \"%V\" && \"C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\Common7\\Tools\\VsDevCmd.bat\""

[HKEY_CLASSES_ROOT\Directory\Background\shell\VisualStudio\Shell\2015CmdHere]
@="VS 2015 Prompt"
"Icon"="C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\IDE\\devenv.exe,0"

[HKEY_CLASSES_ROOT\Directory\Background\shell\VisualStudio\Shell\2015CmdHere\command]
@="C:\\Windows\\system32\\cmd.exe /k cd \"%1\" && \"C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\Tools\\VsDevCmd.bat\""

[HKEY_CLASSES_ROOT\Directory\shell\runas]
@="Open command window here as Administrator"
"Extended"=""
"HasLUAShield"=""

[HKEY_CLASSES_ROOT\Directory\shell\runas\command]
@="cmd.exe /s /k pushd \"%V\""

[HKEY_CLASSES_ROOT\Directory\shell\VisualStudio]
"Extended"=""
"subcommands"=""
"MUIVerb"="Open command window here for Visual Studio"

[HKEY_CLASSES_ROOT\Directory\shell\VisualStudio\Shell]

[HKEY_CLASSES_ROOT\Directory\shell\VisualStudio\Shell\2013CmdHere]
@="2013"
"Icon"="C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\Common7\\IDE\\devenv.exe,0"

[HKEY_CLASSES_ROOT\Directory\shell\VisualStudio\Shell\2013CmdHere\command]
@="C:\\Windows\\system32\\cmd.exe /k cd \"%V\" && \"C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\Common7\\Tools\\VsDevCmd.bat\""

[HKEY_CLASSES_ROOT\Directory\shell\VisualStudio\Shell\2015CmdHere]
@="2015"
"Icon"="C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\IDE\\devenv.exe,0"

[HKEY_CLASSES_ROOT\Directory\shell\VisualStudio\Shell\2015CmdHere\command]
@="C:\\Windows\\system32\\cmd.exe /k cd \"%1\" && \"C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\Tools\\VsDevCmd.bat\""

[HKEY_CLASSES_ROOT\Drive\Background]

[HKEY_CLASSES_ROOT\Drive\Background\shell]

[HKEY_CLASSES_ROOT\Drive\Background\shell\cmd]
@="@shell32.dll,-8506"
"Extended"=""
"NoWorkingDirectory"=""

[HKEY_CLASSES_ROOT\Drive\Background\shell\cmd\command]
@="cmd.exe /s /k pushd \"%V\""

[HKEY_CLASSES_ROOT\Drive\Background\shell\runas]
@="Open command window here as Administrator"
"Extended"=""
"HasLUAShield"=""

[HKEY_CLASSES_ROOT\Drive\Background\shell\runas\command]
@="cmd.exe /s /k pushd \"%V\""

[HKEY_CLASSES_ROOT\Drive\Background\shell\VisualStudio]
"Extended"=""
"subcommands"=""
"MUIVerb"="Open command window here for Visual Studio"

[HKEY_CLASSES_ROOT\Drive\Background\shell\VisualStudio\Shell]

[HKEY_CLASSES_ROOT\Drive\Background\shell\VisualStudio\Shell\2013CmdHere]
@="VS 2013 Prompt"
"Icon"="C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\Common7\\IDE\\devenv.exe,0"

[HKEY_CLASSES_ROOT\Drive\Background\shell\VisualStudio\Shell\2013CmdHere\command]
@="C:\\Windows\\system32\\cmd.exe /k cd \"%V\" && \"C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\Common7\\Tools\\VsDevCmd.bat\""

[HKEY_CLASSES_ROOT\Drive\Background\shell\VisualStudio\Shell\2015CmdHere]
@="VS 2015 Prompt"
"Icon"="C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\IDE\\devenv.exe,0"

[HKEY_CLASSES_ROOT\Drive\Background\shell\VisualStudio\Shell\2015CmdHere\command]
@="C:\\Windows\\system32\\cmd.exe /k cd \"%1\" && \"C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\Tools\\VsDevCmd.bat\""

[HKEY_CLASSES_ROOT\Drive\shell\runas]
@="Open command window here as Administrator"
"Extended"=""
"HasLUAShield"=""

[HKEY_CLASSES_ROOT\Drive\shell\runas\command]
@="cmd.exe /s /k pushd \"%V\""

[HKEY_CLASSES_ROOT\Drive\shell\VisualStudio]
"Extended"=""
"subcommands"=""
"MUIVerb"="Open command window here for Visual Studio"

[HKEY_CLASSES_ROOT\Drive\shell\VisualStudio\Shell]

[HKEY_CLASSES_ROOT\Drive\shell\VisualStudio\Shell\2013CmdHere]
@="2013"
"Icon"="C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\Common7\\IDE\\devenv.exe,0"

[HKEY_CLASSES_ROOT\Drive\shell\VisualStudio\Shell\2013CmdHere\command]
@="C:\\Windows\\system32\\cmd.exe /k cd \"%V\" && \"C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\Common7\\Tools\\VsDevCmd.bat\""

[HKEY_CLASSES_ROOT\Drive\shell\VisualStudio\Shell\2015CmdHere]
@="2015"
"Icon"="C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\IDE\\devenv.exe,0"

[HKEY_CLASSES_ROOT\Drive\shell\VisualStudio\Shell\2015CmdHere\command]
@="C:\\Windows\\system32\\cmd.exe /k cd \"%1\" && \"C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\Tools\\VsDevCmd.bat\""

A co-worker was working on a new MVC project using role based authorization when he ran into a concern where a view was nearly identical between two different roles. The only difference between the views was one role had the ability to “Delete” and included a delete button, the other role didn’t have the delete capability.

One solution to the problem would have been to add the following code into the view:

if (User.IsInRole("Administrator")) {
  <button>delete</button>
}

Using the above wouldn’t be the end of the word, since the “Delete” action on the controller would be limited to only the “Administrator” role. However, in the future as the abilities of the two roles diverge, we’re likely to continue sprinkling more authorization code into our view creating a bundle of mud. I recommended the developer to create a dedicated view for each role, using partials where able to minimize code duplication.

By doing so, we can have the controller determine the correct view to render.

public class HomeController: Controller
{
  [AcceptVerbs(HttpVerbs.Get)]
  public virtual ActionResult Index()
  {
    if (User.IsInRole("Administrator")) {
        return (View("AdministratorIndex"));
    }
    return (View());
  }
}

That will work and is better than having the the authorization logic inside of the view. We could even make it better by moving the custom views into a subfolder based on the role to help keep our files organized.

- Views
  - Home
    - Administrator
      index.cshtml
    index.cshtml

That’ll help keep our role custom views organized.

But something still “smells” here. Our controller / action is now dealing with authorization concerns. Can we somehow move that authorization logic outside of our controller? Essentially our authorization logic is merely selecting what view to render. Let’s see if we can override the view selection logic…

ViewEngine (RazorViewEngine) To The Rescue

Looking at the ASP.NET MVC stack, we can see that there are ViewEngine classes, (RazorViewEngine, WebFormViewEngine) which will apply a set of rules to locating the appropriate view.

To implement this, we’ll create an RoleBasedRazorViewEngine class with the following contents:

/// <summary>
/// A razor based view engine that locates views based on their role.
/// </summary>
public class RoleBasedRazorViewEngine: RazorViewEngine
{
  private readonly IEnumerable<string> _roles;

  /// <summary>
  /// Creates an instance of the RoleBasedRazorViewEngine class.
  /// </summary>
  /// <param name="roles">The list of roles in priority order supported by the application.</param>
  public RoleBasedRazorViewEngine(IEnumerable<string> roles): this(roles, null)
  {
  }

  /// <summary>
  /// Creates an instance of the RoleBasedRazorViewEngine class.
  /// </summary>
  /// <param name="roles">The list of roles in priority order supported by the application.</param>
  /// <param name="viewPageActivator">The ViewPageActivator to use for page dependency resolution.</param>
  public RoleBasedRazorViewEngine(IEnumerable<string> roles, IViewPageActivator viewPageActivator): base(viewPageActivator)
  {
    _roles = roles ?? new String[0];

    AreaViewLocationFormats = new [] {
      "~/Areas/{2}/Views/{1}/{{0}}/{0}.cshtml",
      "~/Areas/{2}/Views/{1}/{{0}}/{0}.vbhtml",
      "~/Areas/{2}/Views/Shared/{{0}}/{0}.cshtml",
      "~/Areas/{2}/Views/Shared/{{0}}/{0}.vbhtml"
    }.Concat(base.AreaViewLocationFormats).ToArray();
    AreaMasterLocationFormats = new[] {
      "~/Areas/{2}/Views/{1}/{{0}}/{0}.cshtml",
      "~/Areas/{2}/Views/{1}/{{0}}/{0}.vbhtml",
      "~/Areas/{2}/Views/Shared/{{0}}/{0}.cshtml",
      "~/Areas/{2}/Views/Shared/{{0}}/{0}.vbhtml"
    }.Concat(base.AreaMasterLocationFormats).ToArray();
    AreaPartialViewLocationFormats = new[] {
      "~/Areas/{2}/Views/{1}/{{0}}/{0}.cshtml",
      "~/Areas/{2}/Views/{1}/{{0}}/{0}.vbhtml",
      "~/Areas/{2}/Views/Shared/{{0}}/{0}.cshtml",
      "~/Areas/{2}/Views/Shared/{{0}}/{0}.vbhtml"
    }.Concat(base.AreaPartialViewLocationFormats).ToArray();

    ViewLocationFormats = new[] {
      "~/Views/{1}/{{0}}/{0}.cshtml",
      "~/Views/{1}/{{0}}/{0}.vbhtml",
      "~/Views/Shared/{{0}}/{0}.cshtml",
      "~/Views/Shared/{{0}}/{0}.vbhtml"
    }.Concat(base.ViewLocationFormats).ToArray();
    MasterLocationFormats = new[] {
      "~/Views/{1}/{{0}}/{0}.cshtml",
      "~/Views/{1}/{{0}}/{0}.vbhtml",
      "~/Views/Shared/{{0}}/{0}.cshtml",
      "~/Views/Shared/{{0}}/{0}.vbhtml"
    }.Concat(base.MasterLocationFormats).ToArray();
    PartialViewLocationFormats = new[] {
      "~/Views/{1}/{{0}}/{0}.cshtml",
      "~/Views/{1}/{{0}}/{0}.vbhtml",
      "~/Views/Shared/{{0}}/{0}.cshtml",
      "~/Views/Shared/{{0}}/{0}.vbhtml"
    }.Concat(base.PartialViewLocationFormats).ToArray();
  }

  /// <summary>
  /// Creates a partial view using the specified controller context and partial path.
  /// </summary>
  /// <returns>
  /// The partial view.
  /// </returns>
  /// <param name="controllerContext">The controller context.</param><param name="partialPath">The path to the partial view.</param>
  protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
  {
    return base.CreatePartialView(controllerContext, GetRoleBasedPath(controllerContext, partialPath));
  }

  /// <summary>
  /// Creates a view by using the specified controller context and the paths of the view and master view.
  /// </summary>
  /// <returns>
  /// The view.
  /// </returns>
  /// <param name="controllerContext">The controller context.</param>
  /// <param name="viewPath">The path to the view.</param>
  /// <param name="masterPath">The path to the master view.</param>
  protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
  {
    return base.CreateView(controllerContext, 
                           GetRoleBasedPath(controllerContext, viewPath), 
                           GetRoleBasedPath(controllerContext, masterPath));
  }

  /// <summary>
  /// Resolves the path based on the role information.
  /// </summary>
  /// <param name="controllerContext">The controller context.</param>
  /// <param name="viewPath">The path to the view.</param>
  /// <returns>The resolved view path.</returns>
  private string GetRoleBasedPath(ControllerContext controllerContext, string viewPath)
  {
    if ((! String.IsNullOrEmpty(viewPath)) && 
        (controllerContext.HttpContext.User != null)) {
      IPrincipal principal = controllerContext.HttpContext.User;
      foreach (string role in _roles.Where(role => principal.IsInRole(role))) {
        string resolvedViewPath = String.Format(CultureInfo.InvariantCulture, viewPath, role);
        if (base.FileExists(controllerContext, resolvedViewPath)) {
          return (resolvedViewPath);
        }
      }
    }
    return (viewPath);
  }

  /// <summary>
  /// Gets a value that indicates whether a file exists in the specified virtual file system (path).
  /// </summary>
  /// <returns>
  /// true if the file exists in the virtual file system; otherwise, false.
  /// </returns>
  /// <param name="controllerContext">The controller context.</param><param name="virtualPath">The virtual path.</param>
  protected override bool FileExists(ControllerContext controllerContext, string virtualPath)
  {
    if (controllerContext.HttpContext.User != null) {
      IPrincipal principal = controllerContext.HttpContext.User;
      if (_roles.Where(role => principal.IsInRole(role))
                .Any(role => base.FileExists(controllerContext, String.Format(CultureInfo.InvariantCulture, virtualPath, role)))) {
        return (true);
      }
    }
    return(base.FileExists(controllerContext, virtualPath));
  }

  /// <summary>
  /// Finds the specified partial view by using the specified controller context.
  /// </summary>
  /// <returns>
  /// The partial view.
  /// </returns>
  /// <param name="controllerContext">The controller context.</param>
  /// <param name="partialViewName">The name of the partial view.</param>
  /// <param name="useCache">true to use the cached partial view.</param>
  /// <exception cref="T:System.ArgumentNullException">The <paramref name="controllerContext"/> parameter is null (Nothing in Visual Basic).</exception>
  /// <exception cref="T:System.ArgumentException">The <paramref name="partialViewName"/> parameter is null or empty.</exception>
  public override ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
  {
    return(base.FindPartialView(controllerContext, partialViewName, false));
  }

  /// <summary>
  /// Finds the specified view by using the specified controller context and master view name.
  /// </summary>
  /// <returns>
  /// The page view.
  /// </returns>
  /// <param name="controllerContext">The controller context.</param>
  /// <param name="viewName">The name of the view.</param>
  /// <param name="masterName">The name of the master view.</param>
  /// <param name="useCache">true to use the cached view.</param>
  /// <exception cref="T:System.ArgumentNullException">The <paramref name="controllerContext"/> parameter is null (Nothing in Visual Basic).</exception>
  /// <exception cref="T:System.ArgumentException">The <paramref name="viewName"/> parameter is null or empty.</exception>
  public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
  {
    return (base.FindView(controllerContext, viewName, masterName, false));
  }
}

A Walkthrough

The logic is pretty simple.

All of the available application roles are injected into the RoleBasedRazorViewEngine in priority order. Basically if someone is a member of multiple roles, the first role with a matching view will be returned.

We prepend custom views paths to include a file path based on roles. The defaults paths use the .NET string formatting place holders. The default .NET placeholders for MVC paths are:

  • {0} – The name of the action.
  • {1} – The name of the controller.
  • {2} – The name of the area.

When dealing with .NET place holder values, if you actually want to output the value {0} in a string that is being formatted, you wrap it with double braces like {{0}}. In our custom paths, we want the default .NET MVC string substitutions to occur. After that parsing has occurred, we’ll do a second string format / replacement specifying each of the user’s roles.

  ViewLocationFormats = new[] {
    "~/Views/{1}/{{0}}/{0}.cshtml",
    "~/Views/{1}/{{0}}/{0}.vbhtml",
    "~/Views/Shared/{{0}}/{0}.cshtml",
    "~/Views/Shared/{{0}}/{0}.vbhtml"
  }.Concat(base.ViewLocationFormats).ToArray();

Given the previous example, for the Index action on the Home controller, our custom search path of view locations would be:

  "~/Views/Home/{0}/index.cshtml",
  "~/Views/Home/{0}/index.vbhtml",
  "~/Views/Shared/{0}/index.cshtml",
  "~/Views/Shared/{0}/index.vbhtml",
  "~/Views/Home/index.cshtml",
  "~/Views/Home/index.vbhtml",
  "~/Views/Shared/index.cshtml",
  "~/Views/Shared/index.vbhtml"

Or our second pass, we’ll dynamically fill in what {0} should be with one of the user’s roles.

In the FileExists method, we check to see if the user belongs to any of the predefined roles. At this point, we don’t actually return the name of the file, we just indicate if we can resolve the requested path.

  protected override bool FileExists(ControllerContext controllerContext, string virtualPath)
  {
    if (controllerContext.HttpContext.User != null) {
      IPrincipal principal = controllerContext.HttpContext.User;
      if (_roles.Where(role => principal.IsInRole(role))
                .Any(role => base.FileExists(controllerContext, String.Format(CultureInfo.InvariantCulture, virtualPath, role)))) {
        return (true);
      }
    }
    return(base.FileExists(controllerContext, virtualPath));
  }

If we had the following defined roles for our application: “Administrator”, “Operator”, “User”, the following file names would be searched in order.

  "~/Views/Home/Administrator/index.cshtml",
  "~/Views/Home/Administrator/index.vbhtml",
  "~/Views/Shared/Administrator/index.cshtml",
  "~/Views/Shared/Administrator/index.vbhtml",
  "~/Views/Home/Operator/index.cshtml",
  "~/Views/Home/Operator/index.vbhtml",
  "~/Views/Shared/Operator/index.cshtml",
  "~/Views/Shared/Operator/index.vbhtml",
  "~/Views/Home/User/index.cshtml",
  "~/Views/Home/User/index.vbhtml",
  "~/Views/Shared/User/index.cshtml",
  "~/Views/Shared/User/index.vbhtml",
  "~/Views/Home/index.cshtml",
  "~/Views/Home/index.vbhtml",
  "~/Views/Shared/index.cshtml",
  "~/Views/Shared/index.vbhtml"

If one of those paths match, the CreateView or CreatePartialView methods will dynamically expand the path using a helper function to locate the correct view based on the role.

  private string GetRoleBasedPath(ControllerContext controllerContext, string viewPath)
  {
    if ((! String.IsNullOrEmpty(viewPath)) && 
        (controllerContext.HttpContext.User != null)) {
      IPrincipal principal = controllerContext.HttpContext.User;
      foreach (string role in _roles.Where(role => principal.IsInRole(role))) {
        string resolvedViewPath = String.Format(CultureInfo.InvariantCulture, viewPath, role);
        if (base.FileExists(controllerContext, resolvedViewPath)) {
          return (resolvedViewPath);
        }
      }
    }
    return (viewPath);
  }

To use this new custom ViewEngine, we simply need to register it in our Global.asax.cs file.

    /// <summary>
    /// Occurs when the first resource is requested from the web server and the web application starts.
    /// </summary>
    protected void Application_Start()
    {
      ViewEngines.Engines.Clear();
      ViewEngines.Engines.Add(new RoleBasedRazorViewEngine(new[] { "Administrator", "Operator", "User" }));
    }

With the new view engine registered, we can go back and remove our authorization or view selection logic from our controller.

public class HomeController: Controller
{
  [AcceptVerbs(HttpVerbs.Get)]
  public virtual ActionResult Index()
  {
    return (View());
  }
}

Nice, simple, clean code with a separation of concerns! We let the view engine do it’s job and pick the right view for our controller action.

While working on packaging some internal .Net libraries for publishing to our internal NuGet server, I encountered the following cryptic error:

D:\Projects\Company\Web>nuget pack Web.csproj -Prop Configuration=Release
Attempting to build package from 'Web.csproj'.
Packing files from 'D:\Projects\Company\Web\bin\Release'.
Using 'Web.nuspec' for metadata.
An error occurred while parsing EntityName. Line 10, position 35.

An error occurred while parsing EntityName. Line 10, position 35.

“EntityName”? What?!? Where did that variable or name come from? Checking my NuGet spec file. Everything looks fine.

<?xml version="1.0"?>
<package >
  <metadata>
    <id>$id$</id>
    <version>$version$</version>
    <title>$title$</title>
    <authors>George Heeres</authors>
    <owners>$author$</owners>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>$description$</description>
    <releaseNotes>Initial release.</releaseNotes>
    <copyright>Copyright 2014</copyright>
    <tags>company web mvc api webapi http json xml javascript</tags>
    <dependencies>
      <dependency id="Castle.Core" version="[3.0.0.4001,4.0)" />
      <dependency id="Castle.Windsor" version="[3.0.0.4001,4.0)" />
      <dependency id="Company.Core" version="(1,)" />
      <dependency id="Company.Logging" version="(1,)" />
      <dependency id="Company.Security" version="(1,)" />
    </dependencies>
  </metadata>
  <files>
    <file src="bin\Release-Net45\Company.Web.dll" target="lib\net45" />
    <file src="bin\Release-Net45\Company.Web.XML" target="lib\net45" />
  </files>
</package>

The NuGet spec allows for variables ($id$, etc.) to be replaced by values defined in our Assembly (typically AssemblyInfo.cs). In our AssemblyInfo.cs file we have the following:

using System.Reflection;
using System.Resources;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following 
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Company.Web")]
[assembly: AssemblyDescription("Custom Web, Mvc & Http components, object and extensions.")]
#if DEBUG
[assembly: AssemblyConfiguration("Debug")]
#else
[assembly: AssemblyConfiguration("Release")]
#endif
[assembly: AssemblyCompany("Company")]
[assembly: AssemblyProduct("Company Web Framework")]
[assembly: AssemblyCopyright("Copyright © 2012,2013,2014; Company")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: NeutralResourcesLanguage("en-US")]

// Setting ComVisible to false makes the types in this assembly not visible 
// to COM components.  If you need to access a type in this assembly from 
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("1943f4e9-b0c0-4daf-bd62-27e2e33f9dc0")]

// Version information for an assembly consists of the following four values:
//
//      Major Version
//      Minor Version 
//      Build Number
//      Revision
//
// You can specify all the values or you can default the Build and Revision Numbers 
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.1.0")]

Note: The assembly file version (AssemblyFileVersion) is dynamically generated by the build script & tasks.

So can you spot the problem? I’ll give you a hint, it’s in the AssemblyDescription.

The problem is that “&” sign. Because our NuGet file is an XML file, the “&” value must be escaped. The solution is simple:

[assembly: AssemblyDescription("Custom Web, Mvc &amp; Http components, object and extensions.")]

Or optionally, we can leverage the English language and not be lazy…

[assembly: AssemblyDescription("Custom Web, Mvc and Http components, object and extensions.")]

The later solution may be preferrable because the Windows explorer file properties would display “&amp;” instead of “&”. Using “and” would be more agnostic.

Hopefully this post will save you some time!

As everyone knows, mocking the HttpContext and associated classes is a nightmare and should just be avoided. I recently joined a different team at work where they were still running a lot of .NET 1.0 code. Most of the code was poorly designed and highly coupled having been written primarily by developers without proper object oriented design training. Calling this code “spaghetti code” would have been an insult to spaghetti code.

How bad? Most methods are over 1000 lines of code, filled with nested if/else statements and copy/pasted code all over. Extracting the business logic from one method and class resulted in 15 new classes. Here is an quick example of the code quality.

if (_username.ToLower().PadRight(12, ' ').Substring(0, 7).Equals("demo123")) {
}

Lots of useless string parsing and casting to wade through… But anyway, that isn’t the point of this post. Long story short is that as I’m modularizing this code I’ve run into the dreaded HttpContext.Current integrated throughout the code. Before I make extensive changes to the code, I wanted to have some unit tests to ensure that I wasn’t breaking the existing functionality as I modified the code. So the first thing I did was to inject the HttpContext as a dependency into the class. Although far from ideal, it allows me to at least run the code outside of IIS.

Here is my test helper to get the HttpContext:

/// <summary>
/// Retreives an HttpContext for testing.
/// </summary>
/// <returns>An HttpContext for testing.</returns>
internal HttpContext GetHttpContext(string url = "http://127.0.0.1/")
{
  var request = new HttpRequest(String.Empty, url, String.Empty);
  var response = new HttpResponse(new StringWriter());
  var context = new HttpContext(request, response);
  return(context);
}

Unfortunately, the code has numereous references to Request.ServerVariables. If you try to add to this NameValueCollection you’ll find that it is a read only collection. Here is the decompiled code:

public sealed class HttpRequest
{
  private HttpServerVarsCollection _serverVariables;
  public NameValueCollection ServerVariables
  {
    get
    {
      if (HttpRuntime.HasAspNetHostingPermission(AspNetHostingPermissionLevel.Low)) {
        return this.GetServerVars();
      }
      return this.GetServerVarsWithDemand();
    }
  }
  private NameValueCollection GetServerVars()
  {
    if (this._serverVariables == null) {
      this._serverVariables = new HttpServerVarsCollection(this._wr, this);
      if (!(this._wr is IIS7WorkerRequest)) {
        this._serverVariables.MakeReadOnly();
      }
    }
    return this._serverVariables;
  }
}

We can’t override ServerVariables since it’s not virtual and there is no setter. Digging deeper finds an internal HttpServerVarsCollection class which has the following Add signature:

public override void Add(string name, string value)
{
  throw new NotSupportedException();
}

The rabbit hole keeps getting deeper. Fortunately we find the AddStatic method which gives us some hope:

internal void AddStatic(string name, string value)
{
  if (value == null) {
    value = string.Empty;
  }
  base.InvalidateCachedArrays();
  base.BaseAdd(name, new HttpServerVarsCollectionEntry(name, value));
}

That looks promising. So let’s try making this work using reflection.

  var field = request.GetType()
                     .GetField("_serverVariables", BindingFlags.Instance | BindingFlags.NonPublic);
  if (field != null) {
    var variables = field.GetValue(request);
    var type = field.FieldType;
    if (variables == null) {
      var constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null,
                                            new[] { typeof(HttpWorkerRequest), typeof(HttpRequest) }, null);
      variables = constructor.Invoke(new[] { null, request });
    }
    type.GetProperty("IsReadOnly", BindingFlags.Instance | BindingFlags.NonPublic)
        .SetValue(variables, false, null);
    var addStatic = type.GetMethod("AddStatic", BindingFlags.Instance | BindingFlags.NonPublic);
    addStatic.Invoke(variables, new[] { "REMOTE_ADDR", "127.0.0.1" });
    addStatic.Invoke(variables, new[] { "HTTP_USER_AGENT", "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2049.0 Safari/537.36" });
  }

SUCCESS! But we can do even better. How about we make this code extend the HttpRequest object and clean things up a little.

/// <summary>
/// Extension methods for the HttpRequest class.
/// </summary>
public static class HttpRequestExtensions
{
  /// <summary>
  /// Adds the name/value pair to the ServerVariables for the HttpRequest.
  /// </summary>
  /// <param name="request">The request to append the variables to.</param>
  /// <param name="name">The name of the variable.</param>
  /// <param name="value">The value of the variable.</param>
  public static void AddServerVariable(this HttpRequest request, string name, string value)
  {
    if (request == null) return;

    AddServerVariables(request, new Dictionary<string, string>() {
      { name, value }
    });
  }

  /// <summary>
  /// Adds the name/value pairs to the ServerVariables for the HttpRequest.
  /// </summary>
  /// <param name="request">The request to append the variables to.</param>
  /// <param name="collection">The collection of name/value pairs to add.</param>
  public static void AddServerVariables(this HttpRequest request, NameValueCollection collection)
  {
    if (request == null) return;
    if (collection == null) return;

    AddServerVariables(request, collection.AllKeys
                                          .ToDictionary(k => k, k => collection[k]));
  }

  /// <summary>
  /// Adds the name/value pairs to the ServerVariables for the HttpRequest.
  /// </summary>
  /// <param name="request">The request to append the variables to.</param>
  /// <param name="dictionary">The dictionary containing the pairs to add.</param>
  public static void AddServerVariables(this HttpRequest request, IDictionary<string,string> dictionary)
  {
    if (request == null) return;
    if (dictionary == null) return;

    var field = request.GetType()
                       .GetField("_serverVariables", BindingFlags.Instance | BindingFlags.NonPublic);
    if (field != null) {
      var type = field.FieldType;

      var serverVariables = field.GetValue(request);
      if (serverVariables == null) {
        var constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null,
                                              new[] { typeof(HttpWorkerRequest), typeof(HttpRequest) }, null);
        serverVariables = constructor.Invoke(new[] { null, request });
        field.SetValue(request, serverVariables);
      }
      var addStatic = type.GetMethod("AddStatic", BindingFlags.Instance | BindingFlags.NonPublic);

      ((NameValueCollection) serverVariables).MakeWriteable();
      foreach (var item in dictionary) {
        addStatic.Invoke(serverVariables, new[] { item.Key, item.Value });
      }
      ((NameValueCollection)serverVariables).MakeReadOnly();
    }
  }
}

You might have noticed, that I also created a NameValueCollection extension to modify the IsReadOnly property. Of course, use this with care… “with great power comes great responsibility“. The creator of the NameValueCollection you’re consuming likely set the IsReadOnly property for a reason…

/// <summary>
/// Extension methods for the NameValueCollection class.
/// </summary>
public static class NameValueCollectionExtensions
{
  /// <summary>
  /// Retreives the IsReadOnly property from the NameValueCollection
  /// </summary>
  /// <param name="collection">The collection to retrieve the propertyInfo from.</param>
  /// <param name="bindingFlags">The optional BindingFlags to use. If not specified defautls to Instance|NonPublic.</param>
  /// <returns>The PropertyInfo for the IsReadOnly property.</returns>
  private static PropertyInfo GetIsReadOnlyProperty(this NameValueCollection collection, BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic)
  {
    if (collection == null) return (null);
    return(collection.GetType().GetProperty("IsReadOnly", bindingFlags));
  }

  /// <summary>
  /// Sets the IsReadOnly property to the specified value.
  /// </summary>
  /// <param name="collection">The collection to modify.</param>
  /// <param name="isReadOnly">The value to set.</param>
  private static void SetIsReadOnly(this NameValueCollection collection, bool isReadOnly)
  {
    if (collection == null) return;

    var property = GetIsReadOnlyProperty(collection);
    if (property != null) {
      property.SetValue(collection, isReadOnly, null);
    }
  }

  /// <summary>
  /// Makes the specified collection writable via reflection.
  /// </summary>
  /// <param name="collection">The collection to make writable.</param>
  public static void MakeWriteable(this NameValueCollection collection)
  {
    SetIsReadOnly(collection, false);
  }

  /// <summary>
  /// Makes the specified collection readonly via reflection.
  /// </summary>
  /// <param name="collection">The collection to make readonly.</param>
  public static void MakeReadOnly(this NameValueCollection collection)
  {
    SetIsReadOnly(collection, true);
  }
}

And there you have it. A way to add ServerVariables. Keep in mind that this code is extremely fragile because it’s using reflection to access the internal workings of code that we don’t have control over. Below are examples of using the extension method.

public class Example
{
  public void Test() 
  {
    string url = "http://127.0.0.1";
    var request = new HttpRequest(String.Empty, url, String.Empty);
    request.AddServerVariable("REMOTE_ADDR", "127.0.0.1");

    // or
    
    request.AddServerVariables(new Dictionary<string, string>() {
      { "REMOTE_ADDR", "127.0.0.1" },
      { "HTTP_USER_AGENT", "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2049.0 Safari/537.36" }
    });
  }
}

I hope you find this useful and it can save you some time.

I’m working on a project to bridge the gap between some legacy infrastructure code with newer infrastructure code based on a newer .NET framework code. The legacy infrastructure code is .NET 3.5, while the newer infrastructure code is a mixture of .NET 4.0 and 4.5. v4.5 framework usage is currently limited to modules implementing Windows Identity Foundation (WIF) v4.5. Thankfully, the bridging code doesn’t require those features so we can isolate just the relevant infrastructure code.

While writing the bridging code, I needed to compile the relevant portions of the newer infrastructure with 3.5 for compatibility. A couple of problems were encountered with backporting:

Usage of .NET 4.0 specific methods

There were two compilation problems:

String.IsNullOrWhiteSpace()

The first step was to fix the missing IsNullOrWhiteSpace() function. To do this, I simply created my own extension methods and related tests.

  /// <summary>
  /// Extensions to the string class.
  /// </summary>
  public static class StringExtensions
  {
    /// <summary>
    /// Indicates whether a specified string is null, empty, or consists only of white-space characters.
    /// </summary>
    /// <param name="value">The string to test.</param>
    /// <returns>true if the value parameter is null or String.Empty, or if value consists exclusively of white-space characters. </returns>
    public static bool IsNullOrWhiteSpace(this string value)
    {
#if NET35
      /// The IsNullOrWhiteSpace function was added in NET40
      return (String.IsNullOrEmpty(value) || (value.Trim().Length == 0));
#else
      return (String.IsNullOrWhiteSpace(value));
#endif
    }
  }

Inside of our *.csproj file, I set a CONSTANT based on the framework. There are lots of ways to do this, but the simplest is to just hard code it in the relevant PropertyGroup setting.

  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug-Net35|AnyCPU'">
    <DebugSymbols>true</DebugSymbols>
    <OutputPath>bin\Debug-Net35\</OutputPath>
    <DefineConstants>DEBUG;TRACE;NET35</DefineConstants>
    <DebugType>full</DebugType>
    <PlatformTarget>AnyCPU</PlatformTarget>
    <ErrorReport>prompt</ErrorReport>
    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
  </PropertyGroup>

The line of interest is:

<DefineConstants>DEBUG;TRACE;NET35</DefineConstants>

An lastly we have our tests to make sure our implementation functions correctly:

  [TestClass]
  public class StringExtensionTests
  {
    [TestMethod]
    public void IsNullOrWhiteSpace_With_Null_Returns_True()
    {
      Assert.IsTrue(((string) null).IsNullOrWhiteSpace());      
    }

    [TestMethod]
    public void IsNullOrWhiteSpace_With_EmptyString_Returns_True()
    {
      Assert.IsTrue(String.Empty.IsNullOrWhiteSpace());
    }

    [TestMethod]
    public void IsNullOrWhiteSpace_With_Spaces_Returns_True()
    {
      Assert.IsTrue("   ".IsNullOrWhiteSpace());
    }

    [TestMethod]
    public void IsNullOrWhiteSpace_With_Linefeeds_Returns_True()
    {
      Assert.IsTrue("\r\n".IsNullOrWhiteSpace());
    }

    [TestMethod]
    public void IsNullOrWhiteSpace_With_Whitepace_Returns_True()
    {
      Assert.IsTrue(" \r\n   \t ".IsNullOrWhiteSpace());
    }

    [TestMethod]
    public void IsNullOrWhiteSpace_With_Nonwhitespace_Returns_False()
    {
      Assert.IsFalse("   NO WHITESPACE HERE  ".IsNullOrWhiteSpace());
    }
  }

Fixing the code is pretty simple. We add a reference to our namespace to enable the extension methods and then reverse the parameters for the code:

Before
String.IsNullOrWhiteSpace(where)
After
where.IsNullOrWhiteSpace()

String.Join()

In .NET 3.5, the String.Join() method has 2 overloads:

Join(String, String[])
Join(String, String[], Int32, Int32)

In .NET 4.0, there are now five overloads. The overloads mostly allow for an object instead of a string to be specified, along with the ability to use an IEnumerable.

Join(String, IEnumerable<String>)
Join<T>(String, IEnumerable<T>)
Join(String, Object[])
Join(String, String[])
Join(String, String[], Int32, Int32)

Unfortunately, the newer framework contained a number of LINQ statements which passed the statement as an IEnumerable. The solution was to simply add .ToArray() to the end of the IEnumerable.

Before
IEnumerable<T> items;
Func<T, object> output;
String.Join(",", items.Select((item) => (output != null) ? output.Invoke(item) : item))
After
String.Join(",", items.Select((item) => (output != null) ? output.Invoke(item) : item).ToArray())

Unfortunately, that isn’t enough since we need to convert our type of T to a string. Based on the documentation, and viewing the decompiled source for the method, we can see that the type of T is converted by simply calling the .ToString() method on the item. So we can simply fix that by adding .ToString() to each of the ternary results:

String.Join(",", items.Select((item) => (output != null) ? output.Invoke(item).ToString() : item.ToString()).ToArray())

BUT… what about if the invoked output or item are null? We can handle that all by simply using the Convert.ToString() method. And instead of doing it for each ternary result, we’ll just convert the final result from the ternary, making our code more readable and maintainable.

String.Join(",", items.Select((item) => Convert.ToString((output != null) ? output.Invoke(item) : item)))

External library dependencies

Now, the next step is getting conditional compilation working for our 3rd party libraries. Many of the tutorials you’ll find will show string matching against the $(TargetFrameworkVersion) build variable.

<PropertyGroup Condition=" '$(TargetFrameworkVersion)' == 'v3.5' ">
    <DefineConstants>NET35</DefineConstants>
</PropertyGroup>

Ideally, we’d like to be able to do a simple number comparison (i.e. $(TargetFrameworkVersion) > 3.5). Unfortunately, because $(TargetFrameworkVersion) is prefixed with a ‘v’ it’s not interpreted as a number. Not to worry though, in newer versions of MSBuild, we can actually make calls to the .NET library.

To start, we’re going to create a PropertyGroup AFTER the existing property groups. Any variables declared AFTER your property group are invalid and empty strings inside of your PropertyGroup. Then we’re going to create our own custom variable called TargetFrameworkVersionNumber that we can use in our conditional expressions. The simplest option is to simply hard code this value.

<PropertyGroup>
  <TargetFrameworkVersionNumber>2.0</TargetFrameworkVersionNumber>
</PropertyGroup>

While hard coding the value might work in simple scenarios, it can be tedious to maintain. Ideally, we’d like to dynamically set that value based on the $TargetFrameworkVersion value. While there are a number of ways to exclude the ‘v’ from the preceding value, such as using Double.Parse(), what fun would that be? We’re going to use a regular expression because they unlock the possibilities of what you can do.

<PropertyGroup>
  <TargetFrameworkVersionNumber>$([System.Text.RegularExpressions.Regex]::Replace($(TargetFrameworkVersion), '[^\d\.]+', '', System.Text.RegularExpressions.RegexOptions.IgnoreCase))</TargetFrameworkVersionNumber>
</PropertyGroup>

The above regular expression “[^\d\.]+”, simply says to match anything that isn’t a digit or a decimal point (period) and then replace those matches with an empty string / nothing. If you’re not already using regular expressions in your code, they’re worth their weight in gold to learn and most modern languages include support for them including JavaScript.

At this point, if we add a Target element with a Message to our *.csproj file, we can output and inspect the values.

<Target Name="BeforeBuild">
  <Message Text="$(TargetFrameworkVersionNumber)" Importance="High" />
</Target>

You should be able to see the output now during your compilation. Let’s create our conditional compilation statement now.

<ItemGroup Condition=" $(TargetFrameworkVersionNumber) >= 3.5 ">
  <Reference Include="Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
    <SpecificVersion>False</SpecificVersion>
    <HintPath>..\packages\Newtonsoft.Json.4.5.7\lib\net35\Newtonsoft.Json.dll</HintPath>
  </Reference>
</ItemGroup>

Unfortunately, if you run or open this build file, you’ll get an error that you can’t compare the string “” with a number. Even though our number looks like a number, internally the build it treating it like a string. MSBuild is supposed to automatically convert from string to number, and vice versa, but “my mileage varied”… Not to worry, we can use some additional .NET library function calls to convert that string to a number for us.

<ItemGroup Condition=" $([System.Single]::Parse($(TargetFrameworkVersionNumber))) <= 3.5 ">
  <Reference Include="Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
    <SpecificVersion>False</SpecificVersion>
    <HintPath>..\packages\Newtonsoft.Json.4.5.7\lib\net35\Newtonsoft.Json.dll</HintPath>
  </Reference>
</ItemGroup>

Here you see we made another call to $([System.Single]::Parse( )).

Unfortunately, now you’ll get an error the “The project file could not be loaded. ‘&lt’, hexadecimal value 0x3C, is an invalid attribute character.’. Thankfully, the fix is simple, you just need to encode the ‘<‘ as ‘&lt;’ as follows:

<ItemGroup Condition=" $([System.Single]::Parse($(TargetFrameworkVersionNumber))) &lt;= 3.5 ">
  <Reference Include="Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
    <SpecificVersion>False</SpecificVersion>
    <HintPath>..\packages\Newtonsoft.Json.4.5.7\lib\net35\Newtonsoft.Json.dll</HintPath>
  </Reference>
</ItemGroup>

Now, under each ItemGroup, you can add the custom references that are framework version dependent. You don’t need to repeat the ItemGroup for each Reference you want to add for each framework. Just add additional Reference items accordingly.

<Choose>
  <When Condition=" $([System.Single]::Parse($(TargetFrameworkVersionNumber))) &lt;= 3.5 ">
    <ItemGroup>
      <Reference Include="Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
        <SpecificVersion>False</SpecificVersion>
        <HintPath>..\packages\Newtonsoft.Json.4.5.7\lib\net35\Newtonsoft.Json.dll</HintPath>
      </Reference>
    </ItemGroup>
  </When>
  <Otherwise>
    <ItemGroup>
      <Reference Include="Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
        <SpecificVersion>False</SpecificVersion>
        <HintPath>..\packages\Newtonsoft.Json.4.5.7\lib\net35\Newtonsoft.Json.dll</HintPath>
      </Reference>
    </ItemGroup>
  </Otherwise>
</Choose>

Hopefully that helps you when attempting to backport a library or do conditional compilation in your projects.

References / Additional Information

Disclaimer: I am neither an expert, nor fan of SharePoint. Simple fact is I abhore SharePoint.

Unfortunately, I was brought into a project that required a SharePoint list to be updated via an external web service. There are two ways to accomplish this:

  • Use the SharePoint Client Object Model (client.svc) interface and get the rich client interface similar to writing applications that are hosted within SharePoint. This requires that the Microsoft.SharePoint.Client libraries are included or available to your application.
  • Use the WCF DataServices or REST interfaces (listdata.svc) to interact with the Lists on the SharePoint site. Unlike the Client Object Model, you’ll be limited to only working with the list data doing CRUD (Create, Read, Update, Delete) operations. Note: If the list columns change, or new lists added to the site, the service reference will need to be updated since the generated code is type-safe.

For this project, we opted to go with the WCF DataServices approach since we only needed to populate and update existing list data. In Visual Studio it’s easy to add the WCF web service reference which will create the proxy for you. Basically reference your site url and prefix ‘_vti_bin/listdata.svc’ to the end of the url.

When creating a new column in SharePoint, you have the following options for the ‘type’:

  • Single line of text
  • Multiple lines of text
  • Choice (menu to choose from)
  • Number (1, 1.0, 100)
  • Currency ($, ¥, €)
  • Date and Time
  • Lookup (information already on this site)
  • Yes/No (check box)
  • Person or Group
  • Hyperlink or Picture
  • Calculated (calculation based on other columns)
  • External Data
  • Managed Metadata

When using the WCF proxy, the bold items identified above require special treatment for both reading and writing the values. Let’s look at reading these values via the WCF proxy.

For this example setup, we’re going to have a ‘Products’ list with the following columns:

  • Shipping: Choice (Multi-value)
  • Color: Choice (single value)
  • Category: Lookup (Multi-value)
  • Manufacturer: Lookup (single value)

Two additional lookup lists were created called ‘Categories’ and ‘Manufacturers’. Nothing special about these lookup lists, just used the default ‘Id’ and ‘Title’ columns to store our data.

For the purpose of this demo, the SharePoint site name was ‘WCF Test’. In our Visual Studio project, the web service reference was named ‘StoreSite’.

Reading Lists

First we’ll create a little utility function to get our DataContext.

/// <summary>
/// Get the WCF data context proxy.
/// </summary>
/// <param name="url">The optional Url for the sharepoint site listdata.svc endpoint.</param>
/// <returns>The DataContext to operate on.</returns>
static WCFTestDataContext GetDataContext(string url = null)
{
  if (url == null) url = ConfigurationManager.AppSettings["SharePointSiteURL"];
      
  var context = new StoreSite.WCFTestDataContext(new Uri(ConfigurationManager.AppSettings["SharePointSiteURL"]));
  context.Credentials = CredentialCache.DefaultNetworkCredentials;
  return (context);
}

The first step is reading the results from the ‘Products’ list. Go ahead and create some sample data manually via the SharePoint site.

/// <summary>
/// Displays the products to the console.
/// </summary>
static void DisplayProducts()
{
  var context = GetDataContext();
  var products = context.Products;
  foreach (var product in products) {
    Console.WriteLine("[{0}] {1} @ {2}", product.Id, product.Title, product.Created);
    Console.WriteLine("  Manufacturer: [{0}] {1}", product.Manufacturer.Id, product.Manufacturer.Title);
    Console.WriteLine("  Color:        {0}", product.Color.Value);
    Console.WriteLine("  Category:     {0}", String.Join(",", product.Category.Select(c => String.Format("[{0}] {1}", c.Id, c.Title))));
    Console.WriteLine("  Shipping:     {0}", String.Join(",", product.Shipping.Select(s => s.Value)));
  }
}

If you run this, you’ll get a System.NullReferenceException. If you trace through the debugger, you’ll find that all of the choice and lookup columns are null and/or don’t contain any items. Essentially, SharePoint is not doing the joins on that data to avoid unnecessary data transfer and optimal query performance. We have to explicitly tell SharePoint that we want that data included in our results. At the same time, we’ll make our output code a little more robust with some null checking.

Replace the previous function with the following:

/// <summary>
/// Displays the products to the console.
/// </summary>
static void DisplayProducts()
{
  var context = GetDataContext();
  var products = context.Products.Expand(p => p.Manufacturer)
                                 .Expand(p => p.Category)
                                 .Expand(p => p.Shipping)
                                 .Expand(p => p.Color);
  foreach (var product in products) {
    if (product.Manufacturer != null) {
      Console.WriteLine("  Manufacturer: [{0}] {1}", product.Manufacturer.Id, product.Manufacturer.Title);
    }
    if (product.Color != null) {
      Console.WriteLine("  Color:        {0}", product.Color.Value);
    }
    if (product.Category != null) {
      Console.WriteLine("  Category:     {0}", String.Join(",", product.Category.Select(c => String.Format("[{0}] {1}", c.Id, c.Title))));
    }
    if (product.Shipping != null) {
      Console.WriteLine("  Shipping:     {0}", String.Join(",", product.Shipping.Select(s => s.Value)));
    }
  }
}

The key in the above code is the .Expand() function.

  var products = context.Products.Expand(p => p.Manufacturer)
                                 .Expand(p => p.Category)
                                 .Expand(p => p.Shipping)
                                 .Expand(p => p.Color);

It basically instructs SharePoint to also return that auxiliary data in the results. With that change, we should now get our expected results. For each choice and lookup field that you want included or populated, you need to include a corresponding .Expand() statement with a lambda selector.

[1] Bosch 10-in Table Saw @ 7/1/2014 11:51:35 AM
  Manufacturer: [6] Bosch
  Color:        Green
  Category:     [8] Tools,[9] Saws
  Shipping:     FedEx,UPS

Creation

For creating a new item, we’ll need to create a new ProductsItem. Once you’re ProductsItem is created, you’ll need to add it to your context which is keeping track of all changes.

var context = GetDataContext();
var product = new ProductsItem() {
  Title = "Bosch 10-in Table Saw"
};
context.AddToProducts(product);

// TODO: Assign addition properties / fields

context.saveChanges();

The above code snippet will be used for each specialized example. Note: The new product MUST be added to the context (tracked) before you can attach or link the choice and lookup columns.

Modifying Single Choice Columns

Modifying a single choice column is pretty simple. In our case, our ‘Color’ field in a single choice. Essentially we just need to set the value using the *Value attribute. Using the Visual Studio intellisense, you’ll see that ProductsItem has a ‘Color’ as well as a ‘ColorValue’ property. We can simply set the ‘ColorValue’ property.

// Color: Choice (Single)
product.ColorValue = "Green";

You can get the list of all the available choices with the following:

foreach (var color in context.ProductsColor) {
  Console.WriteLine("{0}", color.Value);
}

Note: You can set the ‘ColorValue’ string to anything. It doesn’t have to exist in the list although the native SharePoint tools and editor will likely not be happy and lose the custom value on a subsequent edit.

Modifying Multiple Choice Columns

For a multiple choice column, the ‘ProductItem’ class contains a ‘Shipping’ field of type DataServiceCollection<>. Included with this method are convenient .Add() methods. You might think that you only need to do the following:

var product = new ProductItem();
var ups = ProductsShippingValue.CreateProductsShippingValue("UPS");
product.Shipping.Add(ups);

Unfortunately, the above won’t generate an error, but neither will your data be saved. Go ahead and try it.

To save this item, we must get an existing ProductsShippingValue which is already being tracked by the context or create a new one and manually attach it to the context.

Use / Retrieve Existing Tracked Context

The following code shows how to query the list of available choices and add it to the multi choice column.

// Shipping: Choice (Multiple)
var ups = context.ProductsShipping.Where(s => s.Value == "UPS").FirstOrDefault();
var fedex = context.ProductsShipping.Where(s => s.Value == "FedEx").FirstOrDefault();
product.Shipping.Add(ups);
product.Shipping.Add(fedex);
context.AddLink(product, "Shipping", ups);
context.AddLink(product, "Shipping", fedex);

Essentially we lookup one of the available choice values which is being tracked, add it to multi-choice column and then notify the DataContext that the values are “linked”. Please note, that the above code should be made more robust by checking for null values, etc.

Create New Entity and Track It

The above example has the overhead of running a remote query. Since we’re just matching on a predetermined or known string we can instead manually create our ProductsShippingValue and accomplish the same things. The only difference is that we need to make our context start tracking our new item. We accomplish this by “attaching” it. Otherwise the code is nearly identical.

// Manufacturer: Lookup (Single)
var ups = ProductsShippingValue.CreateProductsShippingValue("UPS");
var fedex = ProductsShippingValue.CreateProductsShippingValue("FedEx");
context.AttachTo("ProductsShipping", ups);
context.AttachTo("ProductsShipping", fedex);
product.Shipping.Add(ups);
product.Shipping.Add(fedex);
context.AddLink(product, "Shipping", ups);
context.AddLink(product, "Shipping", fedex);

Either option works although I would argue that the later option, although more code, makes more sense since you’re matching and selecting based predetermined strings. An enumeration would probably be ideal for this and could be streamlined with some extension method overloads.

Modifying Single Lookup Columns

For modifying a lookup field with a single value, we simply set the appropriate ‘*Id’ value that corresponds to our lookup value. You can also dynamically lookup this value which the following example demonstrates:

// Manufacturer: Lookup (Single)
var manufacturer = context.Manufacturers.Where(m => m.Title == "Bosch").FirstOrDefault();
product.ManufacturerId = manufacturer.Id;

For brevity, null checks and other exceptions were omitted and should be included in your production code.

Modifying Multiple Lookup Columns

Setting a multiple lookup column is very similar to setting a multi-choice column value. We can either query the existing lookup value which will already be “tracked” by the DataContext or we can manually create our items.

Use / Retrieve Existing Tracked Context

We query the existing lookup value although we’re only interested and need to set the Id value.

// Category: Lookup (Multiple)
var tools = context.Categories.Where(m => m.Title == "Tools").FirstOrDefault();
var saws = context.Categories.Where(m => m.Title == "Saws").FirstOrDefault();
product.Category.Add(tools);
product.Category.Add(saws);
context.AddLink(product, "Category", tools);
context.AddLink(product, "Category", saws);

Create New Entity and Track It

We can also create our objects manually, assuming we know their Id fields. When creating the CategoriesItem, the only thing we need to set is the Id field.

// Category: Lookup (Multiple)
var tools = new CategoriesItem() { Id = 8 };
var saws = new CategoriesItem() { Id = 9 };
context.AttachTo("Categories", tools);
context.AttachTo("Categories", saws);
product.Category.Add(tools);
product.Category.Add(saws);
context.AddLink(product, "Category", tools);
context.AddLink(product, "Category", saws);

Remarks

Hopefully this helps save you time. At the time I did this, it took my several days of digging, searching and experimenting before I found the right references and ordering. Special thanks to the following post on the MSDN forums which really helped to get things going in the right direction.

And yes, SharePoint sucks…


Below is the complete example of adding a product with basic error checking:

class Program
{
  /// <summary>
  /// Get the WCF data context proxy.
  /// </summary>
  /// <param name="url">The optional Url for the sharepoint site listdata.svc endpoint.</param>
  /// <returns>The WCFDataContext to operate on.</returns>
  static WCFTestDataContext GetDataContext(string url = null)
  {
    if (url == null) url = ConfigurationManager.AppSettings["SharePointSiteURL"];
    
    var context = new StoreSite.WCFTestDataContext(new Uri(ConfigurationManager.AppSettings["SharePointSiteURL"]));
    context.Credentials = CredentialCache.DefaultNetworkCredentials;
    return (context);
  }

  /// <summary>
  /// Displays the products to the console.
  /// </summary>
  static void DisplayProducts()
  {
    var context = GetDataContext();
    var products = context.Products.Expand(p => p.Manufacturer)
                                   .Expand(p => p.Category)
                                   .Expand(p => p.Shipping)
                                   .Expand(p => p.Color);
    foreach (var product in products) {
      Console.WriteLine("[{0}] {1} @ {2}", product.Id, product.Title, product.Created);
      if (product.Manufacturer != null) {
        Console.WriteLine("  Manufacturer: [{0}] {1}", product.Manufacturer.Id, product.Manufacturer.Title);
      }
      if (product.Color != null) {
        Console.WriteLine("  Color:        {0}", product.Color.Value);
      }
      if (product.Category != null) {
        Console.WriteLine("  Category:     {0}", String.Join(",", product.Category.Select(c => String.Format("[{0}] {1}", c.Id, c.Title))));
      }
      if (product.Shipping != null) {
        Console.WriteLine("  Shipping:     {0}", String.Join(",", product.Shipping.Select(s => s.Value)));
      }
    }
  }

  private static void Main(string[] args)
  {
    var context = GetDataContext();
    var product = new ProductsItem() {
      Title = "Bosch 10-in Table Saw"
    };
    context.AddToProducts(product);

    // Color: Choice (Single)
    product.ColorValue = "Teale";
    foreach (var color in context.ProductsColor) {
      Console.WriteLine("{0}", color.Value);
    }

    // Shipping: Choice (Multiple)
    var ups = context.ProductsShipping.Where(s => s.Value == "UPS").FirstOrDefault();
    var fedex = context.ProductsShipping.Where(s => s.Value == "FedEx").FirstOrDefault();
    //var ups = ProductsShippingValue.CreateProductsShippingValue("UPS");
    //var fedex = ProductsShippingValue.CreateProductsShippingValue("FedEx");
    //context.AttachTo("ProductsShipping", ups);
    //context.AttachTo("ProductsShipping", fedex);
    product.Shipping.Add(ups);
    product.Shipping.Add(fedex);
    context.AddLink(product, "Shipping", ups);
    context.AddLink(product, "Shipping", fedex);

    // Manufacturer: Lookup (Single)
    var manufacturer = context.Manufacturers.Where(m => m.Title == "Bosch").FirstOrDefault();
    if (manufacturer != null) {
      product.ManufacturerId = manufacturer.Id;
    }

    // Category: Lookup (Multiple)
    var tools = new CategoriesItem() { Id = 8 };
    var saws = new CategoriesItem() { Id = 9 };
    context.AttachTo("Categories", tools);
    context.AttachTo("Categories", saws);
    //var tools = context.Categories.Where(m => m.Title == "Tools").FirstOrDefault();
    //var saws = context.Categories.Where(m => m.Title == "Saws").FirstOrDefault();
    if (tools != null) {
      product.Category.Add(tools);
      context.AddLink(product, "Category", tools);
    }
    if (saws != null) {
      product.Category.Add(saws);
      context.AddLink(product, "Category", saws);
    }

    Console.WriteLine("Adding new product '{0}'...", product.Title);
    context.SaveChanges();

    DisplayProducts();
  }
}

If you’ve just deployed a .svc file to a server (or your local IIS server) and you get an error that it doesn’t recognize the .svc mime type (or the type was blocked), they you need to do the following:

  1. Ensure that the .NET 3.5.1 Framework is installed.
  2. Ensure that “Windows Communication Foundation HTTP Activation is enabled and installed. This can be access via the Program Features in the Control panel under “Turn Windows Features on or off”.
    Enable WCF HTTP Activation.

    Ensure that Windows Communication Foundation HTTP Activation is installed.

  3. Execute the following command with elevated privileges (as administrator):
    "%WINDIR%\Microsoft.Net\Framework\v3.0\Windows Communication Foundation\ServiceModelReg.exe" -i
         

    When you run the WCF service model registration, your machine web.config file will be updated. Below is output from the above command:

    Microsoft(R) Windows Communication Foundation Installation Utility
    [Microsoft (R) Windows (R) Communication Foundation, Version 3.0.4506.5420]
    Copyright (c) Microsoft Corporation.  All rights reserved.
    
    Installing: Machine.config Section Groups and Handlers (WOW64)
    Installing: Machine.config Section Groups and Handlers
    Installing: System.Web Build Provider (WOW64)
    Installing: System.Web Compilation Assemblies (WOW64)
    Installing: HTTP Handlers (WOW64)
    Installing: HTTP Modules (WOW64)
    Installing: System.Web Build Provider
    Installing: System.Web Compilation Assemblies
    Installing: HTTP Handlers
    Installing: HTTP Modules
    Installing: Protocol node for protocol net.tcp (WOW64)
    Installing: TransportConfiguration node for protocol net.tcp (WOW64)
    Installing: ListenerAdapter node for protocol net.tcp
    Installing: Protocol node for protocol net.tcp
    Installing: TransportConfiguration node for protocol net.tcp
    Installing: Protocol node for protocol net.pipe (WOW64)
    Installing: TransportConfiguration node for protocol net.pipe (WOW64)
    Installing: ListenerAdapter node for protocol net.pipe
    Installing: Protocol node for protocol net.pipe
    Installing: TransportConfiguration node for protocol net.pipe
    Installing: Protocol node for protocol net.msmq (WOW64)
    Installing: TransportConfiguration node for protocol net.msmq (WOW64)
    Installing: ListenerAdapter node for protocol net.msmq
    Installing: Protocol node for protocol net.msmq
    Installing: TransportConfiguration node for protocol net.msmq
    Installing: Protocol node for protocol msmq.formatname (WOW64)
    Installing: TransportConfiguration node for protocol msmq.formatname (WOW64)
    Installing: ListenerAdapter node for protocol msmq.formatname
    Installing: Protocol node for protocol msmq.formatname
    Installing: TransportConfiguration node for protocol msmq.formatname
    Installing: HTTP Modules (WAS)
    Installing: HTTP Handlers (WAS)
    

In the process of working through this problem, I first attempt to add the WCF HTTP Activation, which unfortunately corrupted my machine web.config file which prevented access to the IIS manager and associated application pools due to the error:

The configuration section 'system.serviceModel' cannot be read because it is missing a section declaration  

It broke everything .NET related… GREAT!!!

Basically, for some reason my machine web.config was missing the configuration section DLL registrations for the WCF serviceModel. By using the ServiceModelReg.exe tool, it ensured that those base registrations were entered correctly. Once that was updated, the add new features option was able to complete successfully.

If after those changes, you are receiving the following error:

Could not load type ‘System.ServiceModel.Activation.HttpModule’ from assembly ‘System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089

This error can occur when there are multiple versions of the .NET Framework on the computer that is running IIS, and IIS was installed after .NET Framework 4.0 or before the Service Model in Windows Communication Foundation was registered. [MSDN]

To fix this error, start a command prompt as an administrator. And run the following commands:

cd %WINDIR%\Microsoft.NET\Framework64\v4.0.30319
aspnet_regiis.exe -iru
iisreset

Who doesn’t love LINQ? Who doesn’t love extension methods in .NET?

Unfortunately, Microsoft could have made things easier for developers by handling nulls gracefully. What do I mean? Take the following code as an example:

IEnumerable<int> numbers = null;
if (numbers.Any()) {
}

Obviously, as a programmer you would know that you should get a NullReferenceException from the above code. Below is the correct way to write that function:

IEnumerable<int> numbers = null;
if ((numbers != null) && (numbers.Any())) {
}

Simple and logical fix, but it’s just “noisy”. When dealing with an extension method, I disagree with how null references were handled in the LINQ libraries. Any extension function should detect null and return early (when possible). I believe that Microsoft’s view and defense is that an IEnumerable should never be “null” but instead be an empty collection.

Below is the decompiled implementation of the .Any() LINQ extension method (courtesy of .Net Reflector v6).

[__DynamicallyInvokable]
public static bool Any<TSource>(this IEnumerable<TSource> source)
{
  if (source == null) {
    throw Error.ArgumentNull("source");
  }
  using (IEnumerator<TSource> enumerator = source.GetEnumerator()) {
    if (enumerator.MoveNext()) {
      return true;
    }
  }
  return false;
}

The following simple change to the above method would remove all of that extra “noise” and make our code easier to read.

[__DynamicallyInvokable]
public static bool Any<TSource>(this IEnumerable<TSource> source)
{
  if (source == null) return(false);
  using (IEnumerator<TSource> enumerator = source.GetEnumerator()) {
    if (enumerator.MoveNext()) {
      return true;
    }
  }
  return false;
}

Of course, the other solution (and recommended best practice) is to not return null from a function that returns an IEnumerable, but to instead return an empty collection. Unfortunately, when dealing with other people’s code or libraries you may not have that luxury. Below is a simple and efficient example of how to NOT return null for an IEnumerable result. Please note that the example is contrived and a String.Split function already exists.

public IEnumerable<string> Split(string input, string value) {
  if (input == null) return(new string[0]);
  ...
}

So when you’re writing you own extension methods in .NET, do the world a favor and handle null much better.