Click here to Skip to main content
15,881,812 members
Articles / Programming Languages / C#
Article

NAnt : Little Pretty Automatic

Rate me:
Please Sign up or sign in to vote.
4.61/5 (16 votes)
17 Oct 20042 min read 135.4K   524   57   22
Some little utility tasks for NAnt

Introduction

Do you automate your build process? I didn't, until found that one of my ASP.NET projects required too much handwork on every release: build, copy production files, update config, etc.

Ever heard of makefiles? Me too. Endless text files stuffed with ciphered spells, dashes and dots that do all magic for your build process. Forget about this — now we have NAnt.

Born in Java world and brought to .NET, NAnt let us build our programs with easy using simple human-readable XML build scripts.

Warming Up

After spending several days on learning NAnt's documentation, I got the following build script for my project:

XML
<?xml version="1.0"?>
<project name="MyProject" default="production" basedir="..">

    <description>MyProject NANT build script</description>

    <target name="build" 
    description="Compile MyProject using Release configuration">
 <solution solutionfile="MyProject.sln" configuration="Release">
     <webmap>
  <map url="http://localhost/MyProject/Web.csproj" 
  path="Web\Web.csproj" />
  <map url="http://localhost/AchService/AchService.csproj" 
  path="AchService\AchService.csproj" />
     </webmap>
     <excludeprojects>
  <includes name="Tests\Tests.csproj"/>
     </excludeprojects>
 </solution>
    </target>

    <target name="produce" description="Copy production files">
 <!-- Copy build results to Production folder -->
 <delete dir="Build\Production" failonerror="false" />
 <copy todir="Build\Production">
     <fileset basedir="Web">
  <includes name="**.aspx" />
  <includes name="**.ascx" />
  <includes name="**.config" />
  <includes name="**.gif" />
  <includes name="**.jpg" />
  <includes name="**.mdb" />
     </fileset>
 </copy>
 <!-- Reset attributes to Normal -->
 <attrib normal="true">
     <fileset basedir="Build\Production">
  <includes name="**" />
     </fileset>
 </attrib>
 <!-- Update connection string settings -->
 <xmlpoke file="Build\Production\Web.config" 
     xpath="/configuration/MyProjectConfiguration/add
      [@key='ConnectionString']/@value"
     value="Provider=Microsoft.Jet.OLEDB.4.0;
      Data Source=D:\inetpub\wwwroot\Dev.MyProject.com\db\MyProject.mdb; 
      User ID=Admin; Password=" />
 <!-- Update path to e-mail templates -->
 <xmlpoke file="Build\Production\Web.config" 
     xpath="/configuration/MyProjectMailerConfiguration/add
     [@key='TemplatesFolder']/@value"
     value="D:\inetpub\wwwroot\Dev.MyProject.com\EmailTemplates" />
 <!-- Update path to reports templates -->
 <xmlpoke file="Build\Production\Web.config" 
     xpath="/configuration/MyProjectConfiguration/add
     [@key='ReportsTemplatesFolder']/@value"
     value="D:\inetpub\wwwroot\Dev.MyProject.com\
      landlord\Reports\Templates" />
    </target>

    <target name="production" depends="build, produce" 
     description="Build MyProject and copy production files">
 <!-- Target just refers to corresponding tasks -->
    </target>

</project>

The script builds the project, copies it to production folder and changes some key values in *.config files.

I was happy enough, but the project was growing and UI design was changing. I noticed that my script doesn't perform as expected. The problem was in the 'copy' part of the script. Take a look: to build the project, it's enough to specify solution file and map web projects to local path — the rest NAnt does itself. But when I copy cooked files, I have to specify each possible type in copy routine.

XML
...
<solution solutionfile="MyProject.sln" configuration="Release">
    <webmap>
 <map url="http://localhost/MyProject/Web.csproj"
  path="Web\Web.csproj" />
 <map url="http://localhost/AchService/AchService.csproj"
  path="AchService\AchService.csproj" />
    </webmap>
    <excludeprojects>
 <includes name="Tests\Tests.csproj"/>
    </excludeprojects>
</solution>
...
<copy todir="Build\Production">
    <fileset basedir="Web">
 <includes name="**.aspx" />
 <includes name="**.ascx" />
 <includes name="**.config" />
 <includes name="**.gif" />
 <includes name="**.jpg" />
 <includes name="**.mdb" />
    </fileset>
</copy>
...

Guess what happens when my designer adds some Flash animation to the UI?

Do It Yourself

Fortunately, NAnt was designed with extensibility in mind. And the solution is simple — develop your own task for the problem you faced.

NAnt's task is simply a descendant of NAnt.Core.Task class with overridden ExecuteTask method. The only trick is to name your assembly properly: the name should look like YourAssemblyNameTasks.dll. The assembly should be placed to %nant%\bin folder. The rest will be done by NAnt using .NET reflection magic. I developed extensions for various software in the past, but seems task development for the NAnt was the easiest.

Effortless Copy

After spending couple of days on spare time coding, I got the task that makes 'production' copy of any ASP.NET project. Now my script looks like this:

XML
<?xml version="1.0"?>
<project name="MyProject" default="production" basedir="..">

    <description>MyProject NANT build script</description>

    <target name="build" 
    description="Compile MyProject using Release configuration">
 <solution solutionfile="MyProject.sln" configuration="Release">
     <webmap>
  <map url="http://localhost/MyProject/Web.csproj" 
  path="Web\Web.csproj" />
  <map url="http://localhost/AchService/AchService.csproj" 
  path="AchService\AchService.csproj" />
     </webmap>
     <excludeprojects>
  <includes name="Tests\Tests.csproj"/>
     </excludeprojects>
 </solution>
    </target>

    <target name="produce" description="Copy production files">
 <!-- Copy build results to Production folder -->
 <delete dir="Build\Production" failonerror="false" />
 <copywebproject project="Web\Web.csproj" 
todir="Build\Production" configuration="Release" />
 <copywebproject project="AchService\AchService.csproj" 
 todir="Build\Production\AchService" configuration="Release" />
 <!-- Reset attributes to Normal -->
 <attrib normal="true">
     <fileset basedir="Build\Production">
  <includes name="**" />
     </fileset>
 </attrib>
 <!-- Update connection string settings -->
 <xmlpoke file="Build\Production\Web.config" 
     xpath="/configuration/MyProjectConfiguration/add
     [@key='ConnectionString']/@value"
     value="Provider=Microsoft.Jet.OLEDB.4.0;
      Data Source=D:\inetpub\wwwroot\Dev.MyProject.com\db\MyProject.mdb; 
      User ID=Admin; Password=" />
 <!-- Update path to e-mail templates -->
 <xmlpoke file="Build\Production\Web.config" 
     xpath="/configuration/MyProjectMailerConfiguration/add
     [@key='TemplatesFolder']/@value"
     value="D:\inetpub\wwwroot\Dev.MyProject.com\EmailTemplates" />
 <!-- Update path to reports templates -->
 <xmlpoke file="Build\Production\Web.config" 
     xpath="/configuration/MyProjectConfiguration/add
     [@key='ReportsTemplatesFolder']/@value"
     value="D:\inetpub\wwwroot\Dev.MyProject.com\
      landlord\Reports\Templates" />
    </target>

    <target name="production" depends="build, produce" 
     description="Build MyProject and copy production files">
 <!-- Target just refers to corresponding tasks -->
    </target>

</project>

The only thing you have to care of now, is to have all production files included in the project. You can do this right-clicking on the file name in Solution Explorer and selecting 'Include in Project' command.

<copywebproject> Syntax

XML
<copywebproject project="PATH TO PROJECT" todir="TARGET PATH" 
  configuration="CONFIGURATION OF INTEREST" />

PATH TO PROJECT is an absolute or relative path to the web project you want to copy.

TARGET PATH is an absolute or relative path to the target directory.

The task uses CONFIGURATION OF INTEREST attribute to obtain path to compiled project files.

Note that <copywebproject> task supports only web project written in C#, VB.NET or any compatible .NET language.

History

  • Version 1.0 so far.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Software Developer (Senior)
United States United States
Started professional career in software development back in 2000, in Ukraine. Founder and owner of a boutique software company called ByteGems.com Software. Worked for 6 years at w2bi, Inc in New Jersey USA, currently work in a large multinational company based in Redmond, WA.

My buzzwords at the moment: .NET, C#, ASP.NET, MVC, LINQ, TypeScript, JavaScript, AngularJS, HTML, JSON, services.

Still buzzing: C++, Win32, ATL, MFC, SQL, WinForms, WebForms, EF, Sockets, TCP/IP, Remoting.

Comments and Discussions

 
QuestionHow can I input user name and password when I exec a task Pin
Youzelin5-Nov-11 21:33
Youzelin5-Nov-11 21:33 
Questionversioning in .net 2005 Pin
kunal_singh9-May-06 20:11
kunal_singh9-May-06 20:11 
QuestionUsing NAnt I need to Customize the Installation Pin
ChowdaryR29-Aug-05 17:53
ChowdaryR29-Aug-05 17:53 
Generalgui to build nant files Pin
paul heap24-Jun-05 16:58
paul heap24-Jun-05 16:58 
GeneralRe: gui to build nant files Pin
WayneWong18-Sep-07 6:39
WayneWong18-Sep-07 6:39 
GeneralBuilding .Net ASP Project Using NAnt Pin
Anonymous21-Jun-05 22:10
Anonymous21-Jun-05 22:10 
GeneralNant send mail Pin
Soumik Ghosh26-Apr-05 21:46
Soumik Ghosh26-Apr-05 21:46 
GeneralSeparate Domain with vssget Pin
DattaSha25-Apr-05 5:14
DattaSha25-Apr-05 5:14 
Hi,
How can we pass domain name with user id for "vssget" of Nant. We want to get labeled version of source code from Remote vss which is out side our domain.
(i.e it is a remote m/c on a separate domain, we have it's ip address and all permission.
On specifying the UserId and Pasword as per the generic syntax of vssget, we are encountering the 'Invalid password' error while trying to get code fom the remote VSS. Same script is working fine while fetching code from VSS server on the same network.

Thanks & regards,
Shalini.
GeneralNANT Incremental Build Pin
Soumik Ghosh19-Apr-05 23:01
Soumik Ghosh19-Apr-05 23:01 
GeneralRe: NANT Incremental Build Pin
Anonymous21-Apr-05 19:47
Anonymous21-Apr-05 19:47 
GeneralRe: NANT Incremental Build Pin
Anonymous21-Apr-05 20:04
Anonymous21-Apr-05 20:04 
GeneralConfig Override File Pin
djsdjsdjsdjs29-Oct-04 3:56
djsdjsdjsdjs29-Oct-04 3:56 
GeneralRe: Config Override File Pin
Alex Kolesnichenko2-Nov-04 0:39
professionalAlex Kolesnichenko2-Nov-04 0:39 
GeneralAutomate creating building project Pin
DipeshKhakhkhar22-Oct-04 15:28
DipeshKhakhkhar22-Oct-04 15:28 
GeneralCopyWebProjectTask Pin
attackweasel18-Oct-04 4:08
attackweasel18-Oct-04 4:08 
GeneralMentality Pin
Marc Clifton18-Oct-04 1:23
mvaMarc Clifton18-Oct-04 1:23 
GeneralRe: Mentality Pin
Alex Kolesnichenko18-Oct-04 2:03
professionalAlex Kolesnichenko18-Oct-04 2:03 
GeneralRe: Mentality Pin
attackweasel18-Oct-04 3:47
attackweasel18-Oct-04 3:47 
GeneralRe: Mentality Pin
Kevin McFarlane22-Oct-04 10:18
Kevin McFarlane22-Oct-04 10:18 
GeneralRe: Mentality Pin
JerryClinesmith21-Oct-04 16:35
JerryClinesmith21-Oct-04 16:35 
GeneralRe: Mentality Pin
DJ_Graham3-Nov-04 1:00
DJ_Graham3-Nov-04 1:00 
GeneralRe: Mentality Pin
Tom.B.11-Jun-06 3:49
Tom.B.11-Jun-06 3:49 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.