Using the aspnet_compiler.exe to compile .Net Web Apps - asp.net

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>

Related

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.

NAnt and ASP.NET Compiler

I have a build script running successfully, but I am having a hard time running anything after aspnet_compiler completes. I want to use robocopy to copy the project to another folder. If I put the copy task above the compile (as shown below) I get the message to the console, but if I place it after the compile it is not seen. Am I missing something? Do I need to check for a return code from the compiler to call tasks after its completion?
<target name="copy" depends="init">
<echo message="This is my message for robocopy..."/>
</target>
<target name="compile" depends="copy">
<exec program="${msbuild.exe}"
commandline='MySolution.sln /p:Configuration=${Configuration};OutDir="${build.dir}\\"' />
</target>
<target name="precompile-web" depends="compile">
<exec program="${aspnet_compiler.exe}"
commandline='-v /MyProj-p "${build.dir}"\_PublishedWebsites\MyProj.Web'
/>
And yes, when/if I move the copy task below precompile-web I change the depends="precompile-web" and the compile task depends to "init".
If I understand you correctly here, you want to:
Copy the files
Compile them using MSBuild
Precompile them for the web
Is that right? I would have thought you'd want to do it this way around:
Compile the files using MSBuild
Precompile them for the web
Copy the files somewhere else (for use by IIS, etc)
If my way is correct, then I'd guess you'd want your targets to reference each other like this?
<target name="compile-and-publish" depends="compile,precompile-web,copy" />
<target name="compile">
<exec program="${msbuild.exe}" commandline='MySolution.sln /p:Configuration=${Configuration};OutDir="${build.dir}\\"' />
</target>
<target name="precompile-web">
<exec program="${aspnet_compiler.exe}" commandline='-v /MyProj-p "${build.dir}"\_PublishedWebsites\MyProj.Web' />
</target>
<target name="copy" depends="init">
<echo message="This is my message for robocopy..."/>
</target>
This way, you're not pinning each of your targets down to relying upon other targets (for re-use) but you get the order that you need to achieve the job at hand.
Any good to you?

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.

How do I compile an ASP.Net MVC project using MSBuild

How do I compile an ASP.Net MVC project using MSBuild? We use a Continuous Integration server to compile and deploy our applications. To keep things simple I created an MVC 1.0 project in VS2008. I immediately created an MSBuild script file to compile it. I did not change any code in the project. The MSBuild script contained the following target.
<AspNetCompiler
VirtualPath="/"
PhysicalPath="C:\Development\mvc1\"
TargetPath="c:\publish\xxx"
Force="true"
Debug="false"
Updateable="true"
The MVC project sln file is contained in the c:\development\mvc1\ directory. I am running XP/Pro.
I am receiving an error ASPCONFIG: it is an error to use a section registered as allowDefintion='MachineToApplication' beyond application level.. I removed the authenication mode, membership provider, etc. from the web config file until I finally saw a different error message. I am now receiving an error message saying that the file '/views/shared/site.master' does not exist.
What is going on? Thanks in advance for your help!
Am I using the wrong MSBuild command?
If you compile your sln-file (msbuild mysolution.sln) or
<MSBuild Projects="msbuild mysolution.sln" Targets="Rebuild" ContinueOnError="false"
StopOnFirstFailure="false" /><!-- -d -errorstack -->
and the sln-file has the ASP.NET MVC-project .csproj-file then the .csproj-file does have everything you need. Open the .csproj with notepad and look for:
1) This should be true:
<MvcBuildViews>false</MvcBuildViews>
2) Target Name="AfterBuildCompiler":
<Target Name="AfterBuildCompiler" Condition="'$(MvcBuildViews)'=='true'">
<AspNetCompiler VirtualPath="SomeVirtualDir" PhysicalPath="C:\Development\mvc1\" TargetPath="c:\publish\xxx\" />
</Target>
I didn't do anything else and it worked. I actually made my config so that only release build deploy the application (by moving MvcBuildViews-property under PropertyGroups. Then I can use the same .csproj in the development (debug) and deployment (release).
This build script compiles an asp.net MVC 3 application. Since the entire internet appears to have forgotten the concept of "Build Script" this one does not require you to have Visual Studio installed on the target Machine or to "lol, you just have to edit your csproj file to get msbuild!!"
Moving on.
Make sure you have .NET 4 and MVC3 installed. By the way, my build scripts only work with msbuild 4, so make sure you're using the proper one.
The general process is as follows (thanks to many hints and answers I got here!)
1) Build the dependencies (you DLL's)
2) Build the DLL for your web application.
3) Call the asp.net compiler task.
4) Check the scripts for additional comments.
Note that this is called from an outside script that compiles other DLL's (Business, data access, etc.)
<Project ToolsVersion="4.0" DefaultTargets="build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<BuildDir>..\..\dist</BuildDir>
<Optimize>true</Optimize>
</PropertyGroup>
<ItemGroup >
<Reference Include="System.dll" />
<Reference Include="System.Core.dll" />
<Reference Include="System.Web.Abstractions.dll" />
<!-- add the remaining DLL's required. Check your References folder inside VS2010 and add the relevant entries here. It's a lot of references. I ommited them to make the post more compact.
For reasons that are beyond me, I only managed to get some DLL's referenced by full path. Go figure... -->
<Reference Include="C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Web.Helpers\v4.0_1.0.0.0__31bf3856ad364e35\System.Web.Helpers.dll" />
<Reference Include="C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Web.Mvc\v4.0_3.0.0.0__31bf3856ad364e35\System.Web.Mvc.dll" />
<Reference Include="C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Web.WebPages\v4.0_1.0.0.0__31bf3856ad364e35\System.Web.WebPages.dll" />
<!-- The "main build script" compiles the other DLL's from the project and places them on the BuildDir folder. Just reference it here-->
<Reference Include="$(BuildDir)\*.dll"></Reference>
</ItemGroup>
<!-- Build a DLL for the code file inside your web project (controllers, models, the lot...) place it together with the other DLL's
WARNING: Simple build command. Resource files are not included in this.
-->
<Target Name="BuildWebDll">
<ItemGroup>
<CodeFiles Include=".\**\*.cs" />
</ItemGroup>
<CSC Sources="#(CodeFiles)" TargetType="Library" References="#(Reference)" OutputAssembly="$(BuildDir)\cth.web.dll" >
</CSC>
</Target>
<!-- For reasons also unkown, but covered in a number os posts in this forum, the asp.net compiler requires the necessary DLL's to be placed on the BIN/ folder of your web project. That's why we're copying every DLL we need to said folder. For debugging, check the Bin folder on Visual Studio after you compile the project. You need to replicate that in your BIN/
-->
<Target Name="CopyDLLs">
<ItemGroup>
<DllFiles Include="$(BuildDir)/*.dll"/>
</ItemGroup>
<Copy SourceFiles="#(DllFiles)" DestinationFolder="Bin\"></Copy>
</Target>
<Target Name="build">
<CallTarget Targets="BuildWebDll"></CallTarget>
<CallTarget Targets="CopyDLLs"></CallTarget>
<!-- Call this from the webproject directory. PhysicalPath references ".". TargetPath can be everything you want -->
<AspNetCompiler Updateable="true" VirtualPath="/CTH.Web" PhysicalPath="./" TargetPath="$(BuildDir)/CTH.Web" Force="true" Debug="false" />
</Target>
Remember that you have to include resource files, do any web.config replacements, etc. I really hope this helps.
The easiest way I found was to add a WebDeployment project to your solution.
http://www.microsoft.com/DOWNLOADS/details.aspx?FamilyID=0aa30ae8-c73b-4bdd-bb1b-fe697256c459&displaylang=en
You set the properties for the build in the WebDeployment project (like precompile ) . The Buildserver builds the wdprj.
In my environment I have to start by building the web first. After that I can start the wdprj.
Here is my nant - script. It should be easy to write the same in msbuild. It actually runs in TeamCity.
xml version="1.0"?>
<project name="GreatProjectWeb"
default="build" basedir="."
xmlns="http://nant.sf.net/release/0.85/nant.xsd">
<description>Build Script</description>
<!-- builds only the csproj, not the entire solution-->
<target name="build" description="Compile the project using Debug configuration for more verbose error descriptions">
<echo message="Building..."> </echo>
<exec program="C:\WINDOWS\Microsoft.NET\Framework\v3.5\MSBuild.exe" >
<arg value="GreatProjectWeb\GreatProjectWeb.csproj" />
<arg value="/t:Build" />
<arg value="/p:Configuration=Release" />
</exec>
<echo message="Building Projektfile finished. Starting WDP Project..."> </echo>
<exec program="C:\WINDOWS\Microsoft.NET\Framework\v3.5\MSBuild.exe" >
<arg value="GreatProjectWeb_Build\GreatProjectWeb_Build.wdproj" />
<arg value="/t:Build" />
<arg value="/p:Configuration=Release" />
</exec>
<exec program="7z" >
<arg value="a" />
<arg value="GreatProjectWeb_Deploy\web_GreatProject.zip" />
<arg value="GreatProjectWeb_Deploy\*" />
</exec>
</target>
</project>
You could use NAnt which has a "msbuild" task in it that will just do it for you. NAnt is a great way to go for CI builds.
The NAnt home page
The NAnt Contrib home page
The MSBuild task reference from NAnt Contrib
...the contrib library adds some great functionality that the vanilla NAnt doesn't have. It is very simple. I've included a snippet of my .build file here so you can see how I've used it:
<property name="DeployDestination" value="\\MyTestServerName\DestinationFolder"/>
<property name="Solution.Configuration" value="Debug" overwrite="True" />
<property name="nant.settings.currentframework" value="net-3.5" />
<if test="${WebContentDestination=='Production'}">
<property name="DeployDestination" value="\\MyProductionServer\DestinationFolder"/>
</if>
...<snip>
<target name="Build">
<msbuild project="SolutionFileName.sln">
<arg value="/p:Configuration=${Solution.Configuration}" />
</msbuild>
</target>
<target name="Deploy">
<copy todir="${DeployDestination}" flatten="true" >
<fileset>All files to copy</fileset>
</copy>
</target>

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

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.

Resources