8

I want Visual Studio to precompile my ASP.NET application which is used as an Azure web role payload. So I've found this post that explains how to call aspnet_compiler to validate views.

I tried to add the following to "post-build event" of my ASP.NET application:

call "%VS100COMNTOOLS%\vsvars32.bat"
aspnet_compiler -v / -p $(ProjectDir)

or alternatively this (application name specified explicitly):

call "%VS100COMNTOOLS%\vsvars32.bat"
aspnet_compiler -v /ASP.NET-Application-ProjectNameHere -p $(ProjectDir)

In both cases when the build runs I see the following in the build output:

Setting environment for using Microsoft Visual Studio 2010 x86 tools.
Utility to precompile an ASP.NET application
Copyright (C) Microsoft Corporation. All rights reserved.

and clearly no precompilation happens because if I change any .aspx or .cshtml file "Build Action" to "None" it doesn't get to the Azure service package and the view no longer opens once the package is deployed to Azure.

How do I setup aspnet_compiler for precompiling from within Visual Studio?

Community
  • 1
  • 1
sharptooth
  • 167,383
  • 100
  • 513
  • 979

3 Answers3

4

If you want to use Asp.NET Compiler within your Visual Studio / msbuild then you can add AspNetCompiler Task to your project file (.csproj/.vbproj) and set MvcBuildViews to true.

Example:

<Project>
  <PropertyGroup>
    <MvcBuildViews>true</MvcBuildViews>
  </PropertyGroup>
  <!-- ... -->
  <Target Name="PrecompileWeb" AfterTargets="build" Condition="'$(MvcBuildViews)'=='true'">
    <Message Text="Starting AspNetCompiler for $(ProjectDir)" Importance="high" />
    <AspNetCompiler
        VirtualPath="temp"
        PhysicalPath="$(WebProjectOutputDir)"
        Force="true"
    />
  </Target>
  <!-- ... -->
</Project>

You may also set TargetPath attribute to specify destination directory.

AfterTargets="build" is similar to "post-build event". See Target Build Order for more.

sharptooth
  • 167,383
  • 100
  • 513
  • 979
Matej
  • 7,517
  • 2
  • 36
  • 45
2

Integrate ASPX compilation into Visual Studio

One of the principles I insist on is to always try my build on a clean environment and simulate installation as if it was done by QA. Lately I've noticed that I keep falling on errors hidden deep in the aspx files. So, why not using the old and familiar aspnet_compiler.exe tool? It is located at C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727 and it is quite easy to use.

As a VS add-ins freak I've started thinking on an amazing add-in that will integrate to the VS and will listen to build events and display the results at the output pane. Heck, why not add some coffee serving capabilities?

It took me about 10 minutes of googling to stumble on this blog. Mike Hadlow had a genius in its simplicity idea. Use the POST BUILD EVENT! All I need to do is put the following line in the post build event: C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_compiler.exe -v / -p "$(ProjectDir)\"

Now, All that is left is to make the process of adding this line to each and every web project in our team to be automatic.

I have just the add-in for that :)

enter link description here

Muhammad Mubashir
  • 1,591
  • 1
  • 21
  • 18
1

The answer from Matej was helpful for me, but I was not able to use it as-is and still get it to work for both local builds within Visual Studio and automated builds via TFS.

I had to add some extra msbuild settings. Actually, there were 2 different scenarios that I had. One project was an Web App that built into the _PublishedWebsites folder and one was an MVC Web App that did not build into the _PublishedWebsites folder.

First, add the following if it is not already in your project file:

  <PropertyGroup>
    <MvcBuildViews>true</MvcBuildViews>
  </PropertyGroup>

For the one WITH _PublishedWebsites:

  <Choose>
    <When Condition="'$(BuildingInsideVisualStudio)' == true">
      <PropertyGroup>
        <AspNetCompilerPhysicalPath>$(ProjectDir)</AspNetCompilerPhysicalPath>
      </PropertyGroup>
    </When>
    <Otherwise>
      <PropertyGroup>
        <AspNetCompilerPhysicalPath>$(WebProjectOutputDir)</AspNetCompilerPhysicalPath>
      </PropertyGroup>
    </Otherwise>
  </Choose>
  <Target Name="PrecompileWeb" AfterTargets="build" Condition="'$(MvcBuildViews)'=='true'">
    <!-- aspnet_compiler.exe needs to be run on the folder that has the aspx files and the "bin" subfolder.
            When running locally, the value needs to be the project directory, which is $(ProjectDir). 
            When running the TFS build, the value needs to be (BuildFolder)\(ProjectName)\_PublishedWebsites\(ProjectName).
            The $(AspNetCompilerPhysicalPath) will hold the correct value for both types of builds.
    -->
    <Message Text="Starting AspNetCompiler for $(ProjectName) at $(AspNetCompilerPhysicalPath)" Importance="high" />
    <AspNetCompiler 
        VirtualPath="/" 
        PhysicalPath="$(AspNetCompilerPhysicalPath)" 
        TargetPath="$(AspNetCompilerPhysicalPath)\bin_precompile" 
        Force="true" 
        />
  </Target>

For the one WITHOUT _PublishedWebsites:

  <Choose>
    <When Condition="'$(BuildingInsideVisualStudio)' == true">
      <PropertyGroup>
        <AspNetCompiler_CopyFilesFirst>false</AspNetCompiler_CopyFilesFirst>
      </PropertyGroup>
    </When>
    <Otherwise>
      <PropertyGroup>
        <AspNetCompiler_CopyFilesFirst>true</AspNetCompiler_CopyFilesFirst>
      </PropertyGroup>
      <ItemGroup>
        <AllOutputFiles Include="$(OutDir)\\**\*.*" />
      </ItemGroup>
    </Otherwise>
  </Choose>
  <Target Name="PrecompileWeb" AfterTargets="build" Condition="'$(MvcBuildViews)'=='true'">
    <!-- aspnet_compiler.exe needs to be run on the folder that has the cshtml files and the "bin" subfolder. I could not find a setting that was appropriate for both. 
            When running locally, the value needs to be the project directory, which is $(ProjectDir). 
            When running the TFS build, there is no folder that matches both of those criteria. 
            So first we will copy the output into the source code folder's "bin" subfolder, 
            then run it against the source $(ProjectDir), the same as if we were building locally.
    -->
    <Message Text="Before running AspNetCompiler, copy files from $(OutDir) to $(ProjectDir)\bin" Importance="high" />
    <Exec Command="( robocopy.exe /mir  $(OutDir) $(ProjectDir)\bin ) ^&amp; IF %25ERRORLEVEL%25 LEQ 1 exit 0" Condition="'$(AspNetCompiler_CopyFilesFirst)'=='true'" />

    <Message Text="Starting AspNetCompiler for $(ProjectName) at $(ProjectDir)" Importance="high" />
    <AspNetCompiler 
        VirtualPath="/" 
        PhysicalPath="$(ProjectDir)" 
        TargetPath="$(ProjectDir)\bin_precompile" 
        Force="true" 
        />
  </Target>
kevinpo
  • 1,853
  • 19
  • 20