How do I publish a Asp.NET web application using MSBuild? - asp.net

I am trying to publish an Asp.net MVC web application locally using the NAnt and MSBuild. This is what I am using for my NAnt target;
<target name="publish-artifacts-to-build">
<msbuild project="my-solution.sln" target="Publish">
<property name="Configuration" value="debug" />
<property name="OutDir" value="builds\" />
<arg line="/m:2 /tv:3.5" />
</msbuild>
</target>
and all I get is this as a response;
[msbuild] Skipping unpublishable project.
Is it possible to publish web applications via the command line in this way?

The "Publish" target you are trying to invoke is for "OneClick" deployment, not for publishing a website... This is why you are getting the seemingly bizarre message.
You would want to use the AspNetCompiler task, rather than the MSBuild task. See http://msdn2.microsoft.com/en-us/library/ms164291.aspx for more info on this task. Your "PublishDir" would correspond to the TargetPath property of the task.
Source

I came up with such solution, works great for me:
msbuild /t:ResolveReferences;_WPPCopyWebApplication /p:BuildingProject=true;OutDir=C:\Temp\buidl\ Test.csproj
Secret sauce is _WPPCopyWebApplication target.

Related

How to get aspnet_compiler invoked from Visual Studio during build?

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?
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.
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
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 ) ^& 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>

How build asp.net web site using nant script?

I am using nant-0.90-alpha1 to build asp.net 3.5 web site. I am unable do that. When I am using msbuild , it throwing error saying unknown tag msbuild. How can I build asp.net 3.5 website using nant?
nRk
The CodeCampServer project provides good examples for a variety of tasks using nant to build MS projects including using MSBuild. However it doesn't use the msbuild task. Here's an excerpt from the common.build file from CodeCampServer:
<target name="compile" depends="init">
<echo message="Build Directory is ${dir.build}" />
<exec program="${framework::get-framework-directory(framework::get-target-framework())}\msbuild.exe"
commandline="${file.solution} /t:Clean /p:Configuration=${project.config} /v:q" workingdir="." />
<exec program="${framework::get-framework-directory(framework::get-target-framework())}\msbuild.exe"
commandline="${file.solution} /t:Rebuild /p:Configuration=${project.config} /v:q" workingdir="." />
</target>
<msbuild> task is part of NAntContrib.
The <msbuild> task must be imported into your build script. Put the following element somewhere within your <project> element.
<project ...>
<loadtasks assembly="C:\Program Files\NAntContrib\NAnt.Contrib.Tasks.dll"/>
...
</project>
I believe NAnt will also pick up additional task libraries if the dlls are placed in the NAnt bin folder.

Using the ASP Compiler in NAnt to build an ASP .Net MVC application

I am succesfully building ASP .Net applications in NAnt using the ASP Compiler, without a problem., as part of my Continuous Integration process.
However, if I try exactly the same process on an ASP .NET MVC application, the build fails in NAnt, but will compile succesfully in Visual Studio. The error message I get in NAnt is:
[HttpParseException]: Could not load type 'MyNamespace.Views.Home.Index'
which appears that it has a problem with the dots in the filenames, but I might be wrong.
Any suggestions are most welcome.
You shouldn't install ASP.NET MVC onto the build box. You should be referencing the System.Web.MVC, System.Web.Routing and System.Web.Abstractions DLLs from wherever you store your third-party references. We normally have a /lib folder for all references where we have those 3 DLLs (and many more) stored and a /src folder where all of our code lives. If you are referencing these DLLs this way, you no longer have to rely on the environment for those DLLs. This blog post explains this idea in more detail.
Installing the MVC bits on the build box should sort this out--it is either lacking the .dlls to know your Home.Index view descends from System.Web.Mvc.ViewPage or it doesn't have the right project template for the compiler to use.
The MVC app needs to be built as a project before using aspnet_compile. If your MVC project uses other class library projects, they also need to be compiled.
After running aspnet_compile, we then want to delete various files that should not be part of the deployed site.
This build file is located in the parent directory to my project MvcApplication.
<project default="build">
<property name="build.dir" value="${project::get-base-directory()}"/>
<property name="build.config" value="Release" />
<target name="build">
<exec program="${framework::get-framework-directory('net-3.5')}/msbuild.exe">
<arg value="/property:Configuration=${build.config}" />
<arg value="${build.dir}/MvcApplication/MvcApplication.csproj" />
</exec>
<delete dir="${build.dir}/PrecompiledWeb" includeemptydirs="true" failonerror="false"/>
<exec program="${framework::get-framework-directory('net-2.0')}/aspnet_compiler.exe">
<arg value="-v" />
<arg value="/" />
<arg value="-p" />
<arg value="MvcApplication/" />
<arg value="-f" />
<arg value="PrecompiledWeb" />
</exec>
<delete verbose="true" includeemptydirs="true" failonerror="false">
<fileset basedir="${build.dir}/PrecompiledWeb">
<include name="Controllers" />
<include name="Properties" />
<include name="obj/**" />
<include name="obj" />
<include name="*.csproj" />
<include name="*.csproj.user" />
</fileset>
</delete>
</target>
</project>
Not exactly an answer to your question but more a different tack that might solve what you wish to achieve.
I find studio to be more friendly that the asp compiler from the command line.
Could you not build it with devenv.exe through a NAnt command line task.
Best of luck,
Dan
On a project I was working on recently we build the ASP.NET MVC web app using this target:
<target name="CompileSite" depends="blah blah">
<exec program="${framework::get-framework-directory('net-2.0')}\aspnet_compiler.exe" commandline="-p "${SrcDir}\Website" -v / -d "${CompiledSiteOutputDir}" -fixednames" workingdir="${BaseDir}" />
</target>
so it is definitely possible. Our views were named something like ProjectName.Views.News.List etc.
Could you provide more details? Does the compiler say where it encounters the error (file, linenumber etc.)?
My best guess is that the ASP.Net mvc dll's are not installed on the build server. ASP.Net MVC is a separate download.

ASP.NET MVC 1.0 AfterBuilding Views fails on TFS Build

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?
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.
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.
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>
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.
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>
....
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.
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>
I had some old folders in my source control that were not visible in the Solution.
You cannot pre-build an ASP.NET MVC application.

Using the aspnet_compiler.exe to compile .Net Web Apps

I have code in the top layer of my .Net web application that I'd like to unit test, but when my build server compiles the project using the aspnet_compiler.exe, it makes a .dll file that is not at all usable by another project, i.e. an NUnit test project.
(This is true of ASP .Net web applications and of ASP .Net MVC applications.)
Am I doing something wrong here? Here's my NAnt script that calls the compiler...
<exec program="${asp.compiler.home}/aspnet_compiler.exe" failonerror="true">
<arg value="-nologo"/>
<arg value="-c"/>
<arg value="-f"/>
<arg value="-errorstack"/>
<arg value="-v"/>
<arg value="${project.name}"/>
<arg value="-p"/>
<arg value="${project::get-base-directory()}"/>
<arg value="${web.deploy.dir}\${project.name}"/>
</exec>
I have code in the top layer of my .Net web application that I'd like to unit test [...]
Stop right there; that's the problem. Put that code into a helper, and test it outside of ASP.NET.
You don't need to use aspnet_compiler.exe. That is just a utility application for precompiling your aspx pages to avoid the startup lag when a user hits a page for the first time.
As I understand it, any non-aspx/ascx code in your ASP.NET MVC web application will be compiled normally into a DLL when your solution is built. This DLL is then usable by your NUnit test project. I assume it's those bits you want to test.
So, just build the project using MSBuild from NAnt and forget about aspnet_compiler.exe.
Can't you run something like here, instead of in Nant as a post-build event?
C:\Windows\Microsoft.NET\Framework\v2.0.50727\aspnet_compiler -v / -p "$(SolutionDir)\PathToMyWebProject"
(where FilePathToMyWebProject is the path to your project file relative to the solution file)
We use MSBuild with a build file to compile the web app and run tests, if you can skip the NAnt stuff, here is a relevent section from the build file (called as a parameter to MSbuild.exe):
<!-- Build projects by calling the Project files generated by VS -->
<Target Name="Build">
<MSBuild Projects="$(ProjectFile)" />
<MSBuild Projects="$(TestProjectFile)" />
</Target>
<!-- Run Unit tests -->
<Target Name="Test" DependsOnTargets="Build">
<CreateItem Include="ClearViewTest\Bin\Debug\ClearViewTest.exe">
<Output TaskParameter="Include" ItemName="ClearViewTest" />
</CreateItem>
<NUnit Assemblies="#(ClearViewTest)" ToolPath="C:\Program Files\NUnit 2.4\bin" ContinueOnError="false" OutputXmlFile="SoultionTestResults.xml" />
</Target>

Resources