Fixing Error NU1202: Package Microsoft.EntityFrameworkCore.Tools 6.0.1 is not compatible with netcoreapp2.2 (.NETCoreApp,Version=v2.2)

Migrating an AspNetCore web and database application from version 2.2 to current .Net 6, I came across an occasional build error:

error NU1202: Package Microsoft.EntityFrameworkCore.Tools 6.0.1 is not compatible with netcoreapp2.2 (.NETCoreApp,Version=v2.2). Package Microsoft.EntityFrameworkCore.Tools 6.0.1 supports: net6.0 (.NETCoreApp,Version=v6.0) 

The error went away by unchecking the Option “Allow NuGet to download missing packages” under “Nuget Package Manager”, so I did not bother any longer.

Unfortunately, the error returned as soon as I ran an Azure Build Task on the project. The task failed with a simple message

##[error]Packages failed to restore

without any indication what exactly failed, what was to be restored, and, especially, why.

Going through the log file, I found that nuget tried to restore packages for .Net 6 (good), but also für .NetCore 2.2 (bad):

2022-04-06T13:59:20.3799748Z          Restoring packages for .NETCoreApp,Version=v6.0...
2022-04-06T13:59:20.4022386Z          Resolving conflicts for .NETCoreApp,Version=v2.2...
2022-04-06T13:59:20.4605261Z          Resolving conflicts for net6.0-windows7.0...
2022-04-06T13:59:20.5840720Z          Checking compatibility of packages on .NETCoreApp,Version=v2.2.
2022-04-06T13:59:20.5886337Z          Checking compatibility for microsoft.entityframeworkcore.tools-netcoreapp2.2-[6.0.1, ) 1.0.0 with .NETCoreApp,Version=v2.2.
2022-04-06T13:59:20.6014642Z          Checking compatibility for Microsoft.EntityFrameworkCore.Tools 6.0.1 with .NETCoreApp,Version=v2.2.
2022-04-06T13:59:20.6016218Z      1>D:\DevOpsAgents\some\path\Project.Data.csproj : error NU1202: Package Microsoft.EntityFrameworkCore.Tools 6.0.1 is not compatible with netcoreapp2.2 (.NETCoreApp,Version=v2.2). Package Microsoft.EntityFrameworkCore.Tools 6.0.1 supports: net6.0 (.NETCoreApp,Version=v6.0) 

I also noticed that the first lines of the log stated

Info: .NET Core SDK/runtime 2.2 and 3.0 are now End of Life(EOL) and have been removed from all hosted agents. If you're using these SDK/runtimes on hosted agents, kindly upgrade to newer versions which are not EOL, or else use UseDotNet task to install the required version.
[command]"C:\Program Files\dotnet\dotnet.exe" restore D:\DevOpsAgents\some\path\Project.sln

By that time, I had verified multiple times that the projects do not use any obsolete 2.2 packages anymore. Where does the reference come from?

Then I remembered that I had experienced *some *sort of build errors, as stated above, and tried to run a dotnet restore on my development machine, disabling parallel execution and turning verbosity to full diagnostics:

dotnet restore my.project.sln --disable-parallel -v diag > dotnet-restore.log

The output is huuuge, so I piped it to a file.

Searching the generated log file for netcoreapp2.2, I finally located these lines

17:37:29.274 10:4>_GenerateDotnetCliToolReferenceSpecs: (Target-ID:26)
    TaskParameter:ToolFramework=netcoreapp2.2 (Task-ID: 17)

I found the target _GenerateDotnetCliToolReferenceSpecs in the file C:\Program Files\dotnet\sdk\6.0.101\NuGet.targets, and it sets the DotnetCliToolTargetFramework build variable to a default value if it is not set already. The default value may be, depending on your installation, netcoreapp1.0, netcoreapp2.2, or some other version.

Which part of the project would trigger an action referring to dotnet CLI tools? It’s the EF Core Tools I needed to install for database migrations:

  <ItemGroup>
	  <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.1"></DotNetCliToolReference>
  </ItemGroup>

This project setting causes dotnet to install the referenced tool, but fails to do so because the default tool framework is incompatible.

This observed behavior is documented in this GitHub issue for NuGet:

  • The DotnetCliToolTargetFramework will be interpreted by NuGet restore as the maximum target framework that tools can be restored for
  • When restoring .NET CLI tools, NuGet will first download the package, and inspect it to see what it targets. It will choose the maximum target framework the package explicitly supports that is less than or equal to the DotnetCliToolTargetFramework

This GitHub issue showed me how to set the framework version, so I added to my csproj file the following lines:

  <PropertyGroup>
    <DotnetCliToolTargetFramework>net6.0</DotnetCliToolTargetFramework>
  </PropertyGroup>

and dotnet restore worked without errors.

Finding unused SpecFlow step implementations with PowerShell

SpecFlow steps are public methods adorned using the [Given], [When], and [Then] attributes inside classes marked with the [Binding] attribute.

To load the assembly containing the compiled SpecFlow steps, I found it necessary to load all other assemblies inside the bin directory. Otherwise an error would occur in the assembly’s GetTypes() method stating the references to other assemblies could not be resolved.

$asm = [System.Reflection.Assembly]::LoadFrom("$basedir\$specdll", 
$null, 0)
$types = $asm.GetTypes()

Next, the SpecFlow attribute types are retrieved

$binding = [TechTalk.SpecFlow.BindingAttribute]
$given = [TechTalk.SpecFlow.GivenAttribute]
$when = [TechTalk.SpecFlow.WhenAttribute]
$then = [TechTalk.SpecFlow.ThenAttribute]

along with all [Binding] classes and there methods with the attributes listed above.

The attributes are collected in an array, as their Regex property contains the regular expression that will be used to search the .feature files using PowerShell’s select-string cmdlet.

:Outer foreach($a in $attributes) {    
foreach($ff in $featurefiles) {
        $found = $featurefilecontents[$ff] | 
select-string -Pattern $a.Regex -CaseSensitive
        if ($found.Matches.Length -gt 0) {
            #write-host "found $($a.Regex) in file $ff"
            $foundattributes += $a
            continue Outer
        }
    }
    write-host "did not found reference for $($a.GetType().Name) $($a.Regex)"
    $notfoundattributes += $a
}

The script has been developed to analyze a project using SpecFlow 2.4.0, and is available on my PowerShell Snippets repository.

Invoking app/web.config File Transformations on Build

MSBuild provides the functionality to generate a production web.config (or app.config) from the developer’s web.config merged with a web.*.config transformation file named after the current Configuration. This web.config File Transformation is applied when you Deploy a (web) application.

But what if you want to apply the same file transformation during build? The scenario occurs if a team checks in the web.config file, but needs customization for each developer of the team (e.g. different local SQL connection strings, log directories etc).

Digging through the various .targets files that configure the VS build system, I found a reference to the <TransformXml> command in Microsoft.Web.Publishing.targets deep inside the Visual Studio installation directory. (see the answers on this SO question)

Putting it all together, I came up with an AfterBuild step in the .csproj file which applies the web.config transformation on build, rather than on deploy:

  <Target Name="AfterBuild">
	<TransformXml Source="web.common.config"
	        Transform="web.onbuild.config"
	        Destination="web.config" />
  </Target>

(add the parameter $(Configuration) where necessary.)

Remove Unused References with Visual Studio 2017

I liked the Reference Assistant extension very much, but unfortunately it only works for Visual Studio versions 2010 through 2013, and I always wanted to adapt the extension to later versions of Visual Studio.

Now I did.

So I forked the original code from the repository on GitHub (really originally hosted on CodePlex).

Since I had no experience in working with the VSSDK, I created a dummy project and clicked my way through it, and tried to figure out, where the original code hooked into VS, and how to migrate that code from 2010 to 2017.

One of the main obstacles was the setup of the Options page, which seems to have changed fundamentally. Fortunately, the Extensibility Samples also contain a project named Options covering the Tools->Options dialog.

Of course, migration also means upgrading .Net versions (implied by creating a VS2017 extension project), replacing assembly references with NuGet packages, and a little bit of tuning and tweaking.

You can find the upgraded Reference Assistant on GitHub, the first release version is here.

What I like about this tool is that is lets you preview the changes it is going to make, and exclude references from removal you know are required, as the tool does not consider occasional implied references and assemblies referenced in .config files.

VS Solution Dependency Visualizer supports .NET Core Project Files

When I tried to analyze an unknown Visual Studio solution in my tool VS Solution Dependency Visualizer, I noticed that the project dependencies were not analyzed correctly. In fact, the dependencies were completely ignored.

A bit of research turned up that the solution in question was partly migrated to .NET Core, and the .csproj project files have a slightly different structure than good old .Net project files.

First, the classic .Net project files use a namespace

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

whereas .NET Core project files come without XML namespace, and have the root attribute Sdk:

<Project Sdk="Microsoft.NET.Sdk">

Also, files are not compiled if they are explicitly contained in the .csproj file, but rather by a rule-based Default Compilation mechanism which decides whether files in or below the project directory are compiled, embedded, or ignored.

For a detailed documentation of .NET Core project files, see MS docs or the dotnet GitHub docs.

The latest version of VS Solution Dependency Visualizer with support for .NET Core projects is available for download here.

BTW: In previous versions of this tool, I tried to register VS Solution Dependency Visualizer as an External Tool in all installed versions of Visual Studio.

However, things change all the time, and VS 2013 was the first version that did not support registration via registry, and with VS 2017 things got even more different, and finally I had to give up.

Instructions on how to add VS Solution Dependency Visualizer as an External Tool in your version of Visual Studio can be found in the readme file that comes with the installer.

External Tools in Visual Studio 2017 and higher

Back in 2011, I wrote the post Programmatically Add External Tool to Visual Studio and sketched, how Visual Studio stores its External Tools in the registry unter

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\[VersionNumber]\External Tools\

Recently a reader asked

Is this capability still available in Visual Studio 2019

which got me researching.

Indeed, VS 2017 and 2019 do not seem to have the same registry trees as versions up to 14.0 (VS 2015) have.

I searched the registry and %ProgramData% and %AppData% for the well-known external tool GuidGen.exe, but did not immediately find anything useful.

What I did find, was that the configuration file for the WebCode persona of VS (C:\Program Files\Microsoft Visual Studio\2017\Community\Common7\IDE\Profiles\WebCode.vssettings) contains the section

<Category name="Environment_ExternalTools"  ...>
  <ExternalTools>
    ...
    <ExcludeRegisteredTool SourceKeyName="Create GUID"/>
  </ExternalTools>
</Category>

Aha, so there are “Registered Tools”. But how are they registered, and where?

Next, I found the registration file for guidgen.exe (C:\Program Files\Microsoft Visual Studio\2017\Community\Common7\IDE\CommonExtensions\Microsoft\External Tools\GuidGen\GuidGen.pkgdef), which almost looks like a .reg Registry file

[$RootKey$\External Tools\Create GUID]

but what is $RootKey$? Certainly a macro evaluated during installation, but where does the registry key end up?

Another search brought me to this answer on SO, stating

In Visual Studio 2017, External Tools are stored in a private registry hive in the user’s local application data folder

along with source code how to find and open the private registry hive depending on the VS version.

I started up VS 2017 and VS 2019 and created a dummy External Tool called “Test Cmd” for cmd.exe, and tried to find the name in my local AppData directory.

Indeed I found the entry in the file
C:\Users\[Username]\AppData\Local\Microsoft\VisualStudio\[VersionNumber_8Hex]\Settings\CurrentSettings.vssettings:

<UserCreatedTool>
  <Arguments/>
  <CloseOnExit>true</CloseOnExit>
  <Command>cmd.exe</Command>
  <Index>0</Index>
  <InitialDirectory/>
  <IsGUIapp>false</IsGUIapp>
  <NameID>0</NameID>
  <Package>{00000000-0000-0000-0000-000000000000}</Package>
  <PromptForArguments>false</PromptForArguments>
  <SaveAllDocs>true</SaveAllDocs>
  <Title>Test Cmd Edited</Title>
  <Unicode>false</Unicode>
  <UseOutputWindow>false</UseOutputWindow>
  <UseTaskList>false</UseTaskList>
</UserCreatedTool>

I manually copied this entry under a different <Title>, started up VS, and found the copied entry being displayed in the Tools menu.

I did not check where the private registry hive is updated to reflect the changes in the CurrentSettings file, but it seems that changing the file manually or programmatically (while VS is not running) is sufficient to register an external tool.

Which Version of TypeScript does Visual Studio use?

I really love TypeScript.

I started out with version 0.8 in VS 2010 because of a (mostly) client-side web project. I always tried to avoid JavaScript because I prefer programming languages that compile, and I found that finally TypeScript was the way to go.

Projects live on, and VS 2013 got installed on the PC, along with (manually installed) TypeScript 1.4. Now colleagues are already on VS 2015, and we need to have the same TypeScript compiler. So which version of TypeScript does Visual Studio use?

ts2013

No indication that version 1.4 is installed

As far as I’m aware, VS 2013 does not provide the means to display the currently used TypeScript version. Answers to a related question on SO suggest to

  • open cmd and run tsc -v
  • use VS Command Prompt and run tsc -v
  • open the Package Manager Console and run tsc -v

but the always result in the message

Unknown option ‘v’

What’s going on here?

TypeScript is installed under C:\Program Files\Microsoft SDKs\TypeScript (or C:\Program Files (x86)\Microsoft SDKs\TypeScript on 64-bit Windows). To my surprise, I found 3 versions installed: 0.8.0.0, 1.0, 1.4, but the list of installed software in Programs and Features only listed 0.8.0.0 (“TypeScript for Microsoft VS 2012”) and 1.4.

Where did TypeScript version 1.0 come from? Apparently it got installed while applying VS2013 Update 5, judging from the directory timestamps. Oops: It might also have been installed with VS2013, and some timestamps updated during upgrade.

Different versions, different help message

This is the output if you run tsc from the directory 0.8.0.0:

Syntax:   tsc [options] [file ..]

Examples: tsc hello.ts
          tsc --out foo.js foo.ts
          tsc @args.txt

Options:
  -c, --comments  Emit comments to output
  --declarations  Generates corresponding .d.ts file
  -e, --exec      Execute the script after compilation
  -h, --help      Print this message
  --module KIND   Specify module code generation: "commonjs" (default) or "amd"
  --nolib         Do not include a default lib.d.ts with global declarations
  --out FILE      Concatenate and emit output to single file
  --target VER    Specify ECMAScript target version: "ES3" (default), or "ES5"
  @<file>         Insert command line options and files from a file.

Note that there is no '-v' option!

This is the output of tsc run from directory 1.0:

Version 1.0.3.0
Syntax:   tsc [options] [file ..]

Examples: tsc hello.ts
          tsc --out foo.js foo.ts
          tsc @args.txt

Options:
  --codepage NUMBER             Specify the codepage to use when opening source
files.
  -d, --declaration             Generates corresponding .d.ts file.
  -h, --help                    Print this message.
  --mapRoot LOCATION            Specifies the location where debugger should loc
ate map files instead of generated locations.
  -m KIND, --module KIND        Specify module code generation: 'commonjs' or 'a
md'
  --noImplicitAny               Warn on expressions and declarations with an imp
lied 'any' type.
  --out FILE                    Concatenate and emit output to single file.
  --outDir DIRECTORY            Redirect output structure to the directory.
  --removeComments              Do not emit comments to output.
  --sourcemap                   Generates corresponding .map file.
  --sourceRoot LOCATION         Specifies the location where debugger should loc
ate TypeScript files instead of source locations.
  -t VERSION, --target VERSION  Specify ECMAScript target version: 'ES3' (defaul
t), or 'ES5'
  -v, --version                 Print the compiler's version: 1.0.3.0
  @<file>                       Insert command line options and files from a fil
e.

tsc -v results in

Version 1.0.3.0

This is the output of tsc run from directory 1.4:

Version 1.4.0.0
Syntax:   tsc [options] [file ...]

Examples: tsc hello.ts
          tsc --out file.js file.ts
          tsc @args.txt

Options:
 -d, --declaration                 Generates corresponding '.d.ts' file.
 -h, --help                        Print this message.
 --mapRoot LOCATION                Specifies the location where debugger should
locate map files instead of generated locations.
 -m KIND, --module KIND            Specify module code generation: 'commonjs' or
 'amd'
 --noEmitOnError                   Do not emit outputs if any type checking erro
rs were reported.
 --noImplicitAny                   Warn on expressions and declarations with an
implied 'any' type.
 --out FILE                        Concatenate and emit output to single file.
 --outDir DIRECTORY                Redirect output structure to the directory.
 --preserveConstEnums              Do not erase const enum declarations in gener
ated code.
 --removeComments                  Do not emit comments to output.
 --sourceMap                       Generates corresponding '.map' file.
 --sourceRoot LOCATION             Specifies the location where debugger should
locate TypeScript files instead of source locations.
 --suppressImplicitAnyIndexErrors  Suppress noImplicitAny errors for indexing ob
jects lacking index signatures.
 -t VERSION, --target VERSION      Specify ECMAScript target version: 'ES3' (def
ault), 'ES5', or 'ES6' (experimental)
 -v, --version                     Print the compiler's version.
 -w, --watch                       Watch input files.
 @<file>                           Insert command line options and files from a
file.

tsc -v results in

message TS6029: Version 1.4.0.0

Due to whatever installation magic the installers perform, the PATH environment variable contains the directories related to TypeScript in this order:

C:\Program Files\Microsoft SDKs\TypeScript\0.8.0.0\;
C:\Program Files\Microsoft SDKs\TypeScript\1.0\;
C:\Program Files\Microsoft SDKs\TypeScript\1.4\;

which explains why the oldest version of TypeScript is called when invoked from command line.

This sequence is the same in Visual Studio Command Prompt (2010), which is OK due to compatibility. But the Developer Command prompt for VS2013 prepends version 1.0, resulting in

C:\Program Files\Microsoft SDKs\TypeScript\1.0\;
C:\Program Files\Microsoft SDKs\TypeScript\0.8.0.0\;
C:\Program Files\Microsoft SDKs\TypeScript\1.0\;
C:\Program Files\Microsoft SDKs\TypeScript\1.4\;

This is because the VsDevCmd.bat – which initializes all VS-related paths and environment variables – checks for version 1.0, but no higher version:

@rem Add path to TypeScript Compiler
@if exist "%ProgramFiles%\Microsoft SDKs\TypeScript\1.0" set PATH=%ProgramFiles%\Microsoft SDKs\TypeScript\1.0;%PATH%
@if exist "%ProgramFiles(x86)%\Microsoft SDKs\TypeScript\1.0" set PATH=%ProgramFiles(x86)%\Microsoft SDKs\TypeScript\1.0;%PATH%

And my project?

And just in case you’re wondering which version of TypeScript your project is using, open its .csproj file in a text editor and search for TypeScript:

    <TypeScriptToolsVersion>1.4</TypeScriptToolsVersion>

Blogger Allen Conway had similar experience regarding this question.

Upgrading ASP.Net MVC3 to Visual Studio 2013

I migrated an ASP.Net MVC 3 application from VS 2010 to VS 2013, adding a reference to version 3 of System.Web.Mvc, and never experienced problems as compilation of C# code was still working, and I mainly coded in TypeScript (manually updated to version 1.4).

Only when I had to edit Razor views (.cshtml), I noticed the red squiggles in the IDE. But hey, it still compiled.

Now I had a look into this problem, and found various lots of questions on the internets:

As it turns out, different versions of Visual Studio are compatible only with specific versions of ASP.Net MVC.

From the MSDN articles on Visual Studio 2013 Compatibility and Porting, Migrating, and Upgrading Visual Studio Projects (2015) we can extract the following compatibility matrix:

Visual Studio .Net Framework MVC Version
2010 SP1 4 2, 3
2012 4.5, 4.5.1 3, 4
2013 4.5, 4.5.1 4, 5(*)
2015 4.5, 4.5.1 4, 5(*)

(*) MVC 5 can be installed using NuGet Package Manager.

Next, I tried to follow this upgrade instruction, but failed because ASP.Net MVC 4 is no longer available on nuget.

So here is my personal upgrade guide from VS2010 to VS2013/MVC5:

  • In your web application project, set the Target framework from “.Net Framework 4” to “.Net Framework 4.5”, otherwise you won’t find the current MVC package on nuget.
  • If other projects in your solution also depend on System.Web.Mvc, you need to re-target these projects as well
  • Open the NuGet Manager for Solution, locate the current MVC package (currently 5.2.3), and install it in all projects that reference MVC
  • Since we are already in NuGet, it might be a good idea to reference other 3rd party libraries from NuGet as well (NewtonSoft.JSON in my case, probably also jQuery depending on your support for legacy browsers)

If you compile now, the aspnetcompiler will complain about invalid assembly version numbers in your web.config files.

To resolve this, create a new ASP.Net MVC project from scratch, and compare the root web.config and Views\web.config files

old web.config:

<system.web>
  <compilation debug="true" targetFramework="4.0">
    <assemblies>
      <add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
      <add assembly="System.Web.Helpers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
      <add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
      <add assembly="System.Web.Mvc, Version=3.0.0.1, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
      <add assembly="System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<runtime>
  <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
    <dependentAssembly>
      <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
      <bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="3.0.0.1" />
    </dependentAssembly>

new web.config:

<appSettings>
  <add key="webpages:Version" value="3.0.0.0"/>
  <add key="webpages:Enabled" value="false"/>
  <add key="PreserveLoginUrl" value="true"/>
</appSettings>
<system.web>
  <compilation debug="true" targetFramework="4.5">
    <assemblies>
      <add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
      <add assembly="System.Web.Helpers, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
      <add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
      <add assembly="System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
      <add assembly="System.Web.WebPages, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
      <add assembly="System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
    </assemblies>
  </compilation>
  <pages controlRenderingCompatibilityVersion="4.0">
<runtime>
  <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
    <dependentAssembly>
      <assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35"/>
      <bindingRedirect oldVersion="1.0.0.0-1.5.2.14234" newVersion="1.5.2.14234"/>
    </dependentAssembly>
    <dependentAssembly>
      <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35"/>
      <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0"/>
    </dependentAssembly>
    <dependentAssembly>
      <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35"/>
      <bindingRedirect oldVersion="1.0.0.0-5.2.3.0" newVersion="5.2.3.0"/>
    </dependentAssembly>
    <dependentAssembly>
      <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35"/>
      <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0"/>
    </dependentAssembly>
  </assemblyBinding>
</runtime>

old Views\web.config:

<configuration>
  <configSections>
    <sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
    <section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
    <section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
<system.web.webPages.razor>
  <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=3.0.0.1, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />

new Views\web.config:

<configuration>
  <configSections>
    <sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
    <section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
    <section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
<system.web.webPages.razor>
  <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<appSettings>
  <add key="webpages:Enabled" value="false" />
  <add key="webpages:Version" value="3.0.0.0" />
</appSettings>
<system.web>
  <compilation>
    <assemblies>
      <add assembly="System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    </assemblies>
  </compilation>
</system.web>

That’s it.

Remove Unused References with Visual Studio 2013

My favorite reference removal tool, Reference Assistant, only target Visual Studio 10 (2010) and 11 (2012), according to the description.

To install it in VS 2013, you need to follow the tips given on the Q&A tab of the assistant’s page on the Visual Studio Gallery:

So, the manifest file in this extension has a typo, which is why it wont install in VS2013. Change the vsix file to .zip, unzip it, edit the manifest file for the installationtargets from “[11.0,12.0)” to “[11.0,12.0]” and save it. Select all the files and zip it up. Rename the zip file to .vsix again and install.

If you follow those instructions literally,

  • rename the .vsix to .zip
  • unzip the .zip
  • edit the extension.vsixmanifest file
  • replace every instance of
InstallationTarget Version="[11.0,12.0)"

with

InstallationTarget Version="[11.0,12.0]"
  • save the file
  • zip all files
  • rename the .zip to .vsix

then the modified vsix can be installed in VS2013.

When I first tried it (by not following exactly), I simply dragged the .vsixmanifest file out of the .zip, edited it, and then moved it back into the .zip using Windows Explorer, I actually received the error message reported in the Q&A:

Microsoft.VisualStudio.ExtensionManager.InvalidExtensionPackageException:
The file is not a valid VSIX package.
---> System.IO.FileFormatException: File contains corrupted data.

Good to have the tool in the latest version of VS as well 😉

Fixing “The type ‘System.Web.Mvc.***’ is defined in an assembly that is not referenced.”

In Visual Studio 2010, I tried to compile an ASP.Net MVC 3 project that I have been working on for months, and suddenly received the error messages

The type ‘System.Web.Mvc.IAuthorizationFilter’ is defined in an assembly that is not referenced. You must add a reference to assembly ‘System.Web.Mvc, Version=3.0.0.1, Culture=neutral, PublicKeyToken=31bf3856ad364e35’.

The type ‘System.Web.Mvc.FilterAttribute’ is defined in an assembly that is not referenced. You must add a reference to assembly ‘System.Web.Mvc, Version=3.0.0.1, Culture=neutral, PublicKeyToken=31bf3856ad364e35’.

Turns out that by installing Visual Studio 2013 (or one its product updates) switches from 3.0.0.0 to 3.0.0.1, as a quick glance in the .csproj reveals:

<Reference Include="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, 
    PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />

versus

<Reference Include="System.Web.Mvc, Version=3.0.0.1, Culture=neutral, 
    PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />

By removing the reference and re-adding it, the solution compiled again successfully.