63

I've upgraded from ASP.NET MVC Beta to 1.0 and did the following changes to the MVC project (as descibed in the RC release notes):

<Project ...>
  ...
  <MvcBuildViews>true</MvcBuildViews>
  ...
  <Target Name="AfterBuild" Condition="'$(MvcBuildViews)'=='true'">
    <AspNetCompiler VirtualPath="temp" PhysicalPath="$(ProjectDir)\..\$(ProjectName)" />
  </Target>
  ...
</Project>

While the build runs fine on our local dev boxes, it fails under TFS 2008 Build with "Could not load type 'xxx.MvcApplication'", see below build log:

...
using "AspNetCompiler" task from assembly "Microsoft.Build.Tasks.v3.5, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a".
Task "AspNetCompiler"

  Command:
  C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_compiler.exe -v temp -p D:\Builds\xxx\Continuous\TeamBuild\Sources\UI\xxx.UI.Dashboard\\..\xxx.UI.Dashboard 
  The "AspNetCompiler" task is using "aspnet_compiler.exe" from "C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_compiler.exe".
  Utility to precompile an ASP.NET application
  Copyright (C) Microsoft Corporation. All rights reserved.

/temp/global.asax(1): error ASPPARSE: Could not load type 'xxx.UI.Dashboard.MvcApplication'.
  The command exited with code 1.

Done executing task "AspNetCompiler" -- FAILED.
...

MVC 1.0 is installed on TFS and the solution compiles when built within a Visual Studio instance on the same TFS server.

How can I resolve this TFS Build issue?

o_o
  • 938
  • 1
  • 9
  • 14

9 Answers9

181

Actually, there's a better solution to this problem. I've tested it with VS/TFS 2010 but it should also work with VS/TFS 2008.

<Target Name="AfterBuild" Condition="'$(MvcBuildViews)'=='true'">
  <AspNetCompiler VirtualPath="temp" PhysicalPath="$(WebProjectOutputDir)" />
</Target>

I'm going to work with the MVC team to update their project template to to use this approach along with a custom target (rather than overriding AfterBuild).

I've published a blog post on How to Turn on Compile-time View Checking for ASP.NET MVC projects in TFS Build 2010.

Jim Lamb
  • 25,355
  • 6
  • 42
  • 48
  • And if your solution contains more than one web project, how will this work? That is why I built the path myself... – crowleym Apr 21 '10 at 08:39
  • 1
    Should work fine with multiple web projects - WebProjectOutputDir is distinct for each project. – Jim Lamb Apr 22 '10 at 15:01
  • 27
    This ended up being the solution we used. Thanks Jim! It's been fixed in ASP.NET MVC 3 Tools Update. See my blog post here: http://haacked.com/archive/2011/05/09/compiling-mvc-views-in-a-build-environment.aspx – Haacked May 09 '11 at 17:54
  • Strange, my project was apparently new enough that I already had the physical path set to `$(WebProjectOutputDir)`, yet I was still getting the error after setting `MvcBuildViews` to true. Adding `BaseIntermediateOutputPath` was the only thing that seemed to solve the problem. This makes me wonder what my WebProjectOutputDir is set to...Any idea what could be going on? – devuxer Sep 17 '11 at 06:40
  • 1
    Followup: I seemed to require this modified version of your Target block: [apologies for the formatting] – devuxer Sep 17 '11 at 07:06
  • This works with msbuild v14 but fails with msbuild v15.1: `$ aspnet_compiler.exe -v temp ` `$ error: ASPRUNTIME: '/temp' is not a valid IIS application` I haven't found a solution yet for msbuild v15.1 – Vetras Jun 20 '17 at 11:13
  • Using VS 2017 with MVC 5, I had to restrict the Physical Path further. By default, `$(WebProjectOutputDir)` points to the project's folder. We had something that would create copies of revisioned files (using a CMS), which were not included in the project. We ultimately went with `PhysicalPath=$(WebProjectOutputDir)\Views`, but now we'll have to add a new Target if we add new View folders (such as for Areas). – ps2goat Jul 06 '17 at 18:43
  • 4
    What's the best way to do this with MVC 5 in VS 2017? None of this works. – niico Nov 07 '17 at 23:43
  • 1
    the link in the answer is not working anymore :( do you have the right one? – Amr Elgarhy Mar 01 '19 at 21:23
17

The problem stems from the fact that the AspNetCompiler MSBuild task used within the AfterBuild target of an ASP.NET MVC project expects to reference the dll's in the bin folder of the Web project.

On a desktop build the bin folder is where you would expect it under your source tree.

However TFS Teambuild compiles the output of your source to a different directory on the build server. When the AspNetCompiler task starts it cannot find the bin directory to reference the required DLL and you get the exception.

Solution is to modify the AfterBuild target of the MVC Project to be as follows:

  <Target Name="AfterBuild" Condition="'$(MvcBuildViews)'=='true'">
    <AspNetCompiler Condition="'$(IsDesktopBuild)' != 'false'" VirtualPath="temp" PhysicalPath="$(ProjectDir)\..\$(ProjectName)" />
    <AspNetCompiler Condition="'$(IsDesktopBuild)' == 'false'" VirtualPath="temp" PhysicalPath="$(PublishDir)\_PublishedWebsites\$(ProjectName)" />
  </Target>

This change enables you to compile Views on both the desktop, and the TFS build server.

crowleym
  • 2,532
  • 3
  • 22
  • 28
  • That worked. Hope MS changes the .csproj file template accordingly. – o_o Jul 09 '09 at 10:34
  • thats crazy why they haven't fixed this!! ?? – Simon_Weaver Apr 13 '10 at 08:45
  • I'll check with the TFS TeamBuild team, but I'm not sure if we can "fix" this. This answer hard-codes a TFS specific directory structure "_PublishedWebsites". What if you're not using TFS TeamBuild to build your site but using something else? That would likely break. By moving this build to TFS Team Build, you've customized your project. You'll need to update the paths accordingly, which is what the person did who answered this question. – Haacked Apr 19 '10 at 17:17
  • 4
    I've detailed a better solution to this problem in my answer below. – Jim Lamb Apr 20 '10 at 18:06
  • 5
    Jim's solution is the one we used in ASP.NET MVC 3 Tools Update. See my comment to his answer. – Haacked May 09 '11 at 17:54
  • Thanks! This fixed my similar problem! – Dan Csharpster Apr 09 '12 at 19:21
  • This involves another hardcoding in some way while Jim's solution is more generic. – John-Philip Jun 24 '15 at 13:19
3

Jim Lamb's solution didn't work for us when I built our web .csproj with

/p:UseWPP_CopyWebApplication=true;PipelineDependsOnBuild=False

because the target was being executed AfterBuild and the application has not been copied into the WebProjectOutputDir yet. (BTW, I pass those properties to the web project build cos I want the build to create a OutDir folder with only my binaries and cshtml files suitable for zipping, ie not an in-place build)

To get around this issue and honour the intent of his original target, I did the following:

<PropertyGroup>
    <OnAfter_WPPCopyWebApplication>
        MvcBuildViews;
    </OnAfter_WPPCopyWebApplication>
</PropertyGroup>

<Target Name="MvcBuildViews" Condition="'$(MvcBuildViews)'=='true'">
    <AspNetCompiler VirtualPath="temp" PhysicalPath="$(WebProjectOutputDir)" />
</Target>
Peter McEvoy
  • 2,816
  • 19
  • 24
1

I assume you meant you changed the following setting in the .csproj file:

<MvcBuildViews>true</MvcBuildViews>

The setting you posted in your question shouldn't be touched. If it works on your local machine, then obviously you can pre-build an ASP.NET MVC application.

I think you need to track down what's different between your TFS build environment and your local VS machines. Maybe it's using a different version of MsBuild or something.

Try performing both builds with verbose output and compare the two to see what's different.

Haacked
  • 58,045
  • 14
  • 90
  • 114
  • The paths etc used in TFS appear to be completely different from those on my local machine and in source control, therefore you have to specify different locations for each scenario. – Leather Oct 19 '09 at 15:14
  • @haacked how come this was never updated in the template? its quite confusing the first time you run up against it. especially all those new 'TFS Basic' users not used to dealing with things like this – Simon_Weaver Apr 13 '10 at 23:26
0

The accepted answer didn't work for me. The $(PublishDir) parameter did not point to the correct location. Instead I had to use:

  <Target Name="AfterBuild" Condition="'$(MvcBuildViews)'=='true'">
    <AspNetCompiler Condition="'$(IsDesktopBuild)' != 'false'" VirtualPath="temp" PhysicalPath="$(ProjectDir)\..\$(ProjectName)" />
    <AspNetCompiler Condition="'$(IsDesktopBuild)' == 'false'" VirtualPath="temp" PhysicalPath="$(OutDir)\_PublishedWebsites\$(ProjectName)" />
  </Target>
Paul Batum
  • 8,165
  • 5
  • 40
  • 45
  • Well as long as the answer pointed you in the right direction, then its all good. OutDir on my setup points to a root build dir that contains all assemblies from the other projects within the solution, the PublishDir points to the Web Application projects contained with in the solution. Does your solution contain other projects than just the MVC Web App? – crowleym Aug 06 '09 at 16:22
  • Yes it contains multiple projects, and yes your answer did point me in the right direction. I'm not sure why the $PublishDir works for you and not me, but I'm not too hung up over it, the fix was straightforward and I just thought I'd put it out there if anyone else runs into the same issue. – Paul Batum Aug 09 '09 at 00:50
0

I had some old folders in my source control that were not visible in the Solution.

Andriy Volkov
  • 18,653
  • 9
  • 68
  • 83
0

We are still testing this out, but it appears that you can move the false/true from the tag set, into the property group for your DEBUG build version, you can still set it to true and MSBuild will compile (assuming MSBuild TfsBuild.proj file is setup to use something other than debug configuration). You will need to edit the csproj file using Notepad to accomplish this.

<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <MvcBuildViews>true</MvcBuildViews>
    ....

You need to move the MVCBuildViews tag from the default property group above, to the debug configuration property group (below). Again, when we get the TFS / MSBuild setup, I'll try to post the step we added to our TFSBuild.proj file in TFS.

  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <MvcBuildViews>true</MvcBuildViews>
    <DebugSymbols>true</DebugSymbols>
    ....
0

This problem seems similar to the one talked about here: http://blogs.msdn.com/aaronhallberg/archive/2007/07/02/team-build-and-web-deployment-projects.aspx it seems the invocation of aspnet_compiler.exe fails to locate the binaries because the are not in the bin folder of the MVC project on the build machine. I haven't worked out a solution yet.

Jeremy Thomas
  • 189
  • 2
  • 4
-6

You cannot pre-build an ASP.NET MVC application.

Brad Wilson
  • 67,914
  • 9
  • 74
  • 83