Click here to Skip to main content
Click here to Skip to main content

Building and Deploying C# and VB projects without Visual Studio .NET: class and Command Line Utility ProjectBuilder.

By , 19 Jun 2006
 
Sample Image - ProjectBuilder.jpg

Introduction: What Is It All About?

This article describes a C# class and command line utility based on it, which helps to automatically build and deploy .NET applications written in C# or VB.NET without Visual Studio .NET 2003 only using .NET Framework. The idea of writing it came to me when I had trouble with adding new functionality to my application when no Visual Studio .NET was available. I needed a way to quickly change code and rebuild the project. Another reason to do it was the necessity of having a chance to deploy a Web application from a development environment to a test environment and after that to production in an automatic manner. There are ways to do automatic deployment with your hand-written code in *.bat files already. But unfortunately BAT files are sometimes an awkward way to do the task. When you gather files from your project folder with BAT, you have to use wildcards ( *.cs, *.cpp) and it is not a simple task to check which ones are included in the project and which aren't (you should use project file and XPath to detect files, which should be built). With this class, you can deploy only content files and DLL automatically to the folder you set as your test server's application folder. You could also create a scheduled task for the utility in your OS to compile and put your software to test server even if you are not there at the computer at the desired time.

Class Builder

Here is the interface of the Builder class:

///Build in debug mode
bool Debug { get; set; }

///The name of a file on disk
string ProjectFileName { get; }

///Path to the project file
string ProjectFilePath { get;  set; }

///Other parameters, which are sent to CSC compiler directly
string OtherCscParams { get; set; }

///Assembly type: Exe, WinExe, Library, Module
AssemblyType BuildAssemblyType { get; }

string BuildAssemblyName { get; }
Language AssemblyLanguage { get; }
string MainClass { get; }
string RootNamespace { get; }

public readonly ArrayList Files;
public readonly ArrayList Resources;
public readonly ArrayList References;

void CopyContent(string pOutputPath);
void CopyContent(string pOutputPath, bool pCopyAssemblyFromBin);
void Build(string pOutputPath);

Working with Builder Class

Using the Builder class is easy. First of all, add a reference to prjbuilder.dll (go to "Add References..." -> Browse...-> Select prjbuilder.dll). Then add using prjbuilder; to the code file. I'll show an example of using ProjectBuilder. Sorry for the fact that I omitted some code, but I made it only for the sake of readability of the code here.

Builder b = null;
try
{
    log.putLine("Reading project file " + prjFile + ".");
    b = new Builder(debug, prjFile, others);
    log.putLine("Project file read.");
}
catch(Exception ex)
{
    log.putLine(ex.Message);
}

if(b != null)
{
    if(dobuild)
    {
        log.putLine("Build started.");

        // Actually building the project
        b.Build(outputPath);

        log.putLine("Build finished.");
    }

    if(outputPath != "")
    {
        log.putLine("Copying started.");

        // Copying all content files, except for old assembly DLL
        b.CopyContent(outputPath, !dobuild);

        log.putLine("Copying finished.");
    }
}

Class Usage Points

The Builder class can build and deploy projects. So, with the Builder class, you could make your own builder applications which will build and deploy code without Visual Studio .NET. There are a lot of ways in which you can use it:

  1. You could use the class in your local development process to compile code which has changed a little, without the need to wait until heavy Visual Studio will start up.
  2. Make some automatic utility which will build your applications when you are not beside your computer by a schedule and then put it to the test environment automatically.
  3. Write a Web Service or Web application which uses ProjectBuilder to build and deploy your app remotely on the target machine. Note that the existence of Visual Studio .NET on the target machine is not required.

Inside the Build Method

Build is done by framework classes from the namespace System.CodeDom.Compiler.*. First we use XPath to know which files of each group project include: compile, resource and referenced files. After that we fill the corresponding ArrayLists: Files, Resources, References. After all, we form the parameters for compiler, passing files to build, resource files and referenced files. Here is the Builder.Build(string pOutputPath) method.

public void Build(string pOutputPath)
{
    // Initialize properties from the project file
    initProps();

    // Changing current directory to project file's folder
    string oldFolder = Environment.CurrentDirectory;
    string sDir = ProjectFilePath.Replace(ProjectFileName, "");
    if (sDir != "")
        Environment.CurrentDirectory    = sDir;

    // Getting Files, Resources, References from the project file
    getFiles();
    getResources();
    getReferences();

    // Getting Imports, this should be done only for VB
    if(AssemblyLanguage == Language.VB)
        getImports();

    string buildAssmTypeAttr    = "/t:library";
    switch(BuildAssemblyType)
    {
        case AssemblyType.Library:
            break;
        case AssemblyType.Module:
            buildAssmTypeAttr = "/t:module";
            break;
        case AssemblyType.Exe:
            buildAssmTypeAttr = "/t:exe";
            break;
        case AssemblyType.WinExe:
            buildAssmTypeAttr = "/t:winexe";
            break;
    }

    string compilerName = "csc.exe";
    switch(AssemblyLanguage)
    {
        case Language.CSharp:
            break;
        case Language.VB:
            compilerName = "vbc.exe";
            break;
    }

    string outDir = pathToBin(pOutputPath);
    if(!Directory.Exists(outDir))
        Directory.CreateDirectory(outDir);

    //Create an instance whichever code provider that is needed
    CodeDomProvider codeProvider = null;
    switch(AssemblyLanguage)
    {
        case Language.CSharp:
            codeProvider = new CSharpCodeProvider();
            break;
        case Language.VB:
            codeProvider = new VBCodeProvider();
            break;
    }

    //create the language specific code compiler
    ICodeCompiler compiler = codeProvider.CreateCompiler();

    //add compiler parameters
    CompilerParameters compilerParams = new CompilerParameters();
    compilerParams.CompilerOptions  = buildAssmTypeAttr + " " +
        (AssemblyLanguage == Language.VB? "/rootnamespace:" + RootNamespace: "")
        + OtherCscParams.Trim();
    compilerParams.OutputAssembly = outDir + BuildAssemblyName +
        "." + buildAssemblyExt;
    compilerParams.GenerateExecutable = BuildAssemblyType ==
        AssemblyType.Exe || BuildAssemblyType == AssemblyType.WinExe;
    compilerParams.GenerateInMemory = false;
    compilerParams.IncludeDebugInformation = Debug;
    compilerParams.MainClass = MainClass;

    // Adding all References
    foreach(string rel in References)
        compilerParams.ReferencedAssemblies.Add(rel);

    // Adding all Resources
    foreach(string res in Resources)
        compilerParams.CompilerOptions += " /res:\"" + res + "\"";

    if(AssemblyLanguage == Language.VB)
    // Adding all imports
    foreach(string import in Imports)
        compilerParams.CompilerOptions += " /imports:" + import;

    bool buildSuccessful = false;
    try
    {
        if(log != null)
        {
            log.putLine("Using compiler: " + compilerName + "\n");
            log.putParameters(Files, Resources, References, Imports);
        }

        string[] compileFiles = new string[Files.Count];
        Files.CopyTo(compileFiles);

        //actually compile the code
        CompilerResults results = compiler.CompileAssemblyFromFileBatch(
            compilerParams,
            compileFiles);

        string sOutput = "";
        foreach(string s in results.Output)
            sOutput += "\n" + s;

        if(log != null)
            log.putLine(sOutput);

        // Copying all content files, except for old assembly DLL
        copyFiles(localLibs, pathToBin(pOutputPath), false);

        if(log != null)
            log.putLine("");

        buildSuccessful = true;
    }
    catch(Exception ex)
    {
        if(log != null)
        log.put("Error: " + ex.Message + "\n" +
        "Stack trace: \n" + ex.StackTrace);
    }
    finally
    {
        Environment.CurrentDirectory = oldFolder;
    }

    return buildSuccessful;
}

Utility Usage

The utility uses ProjectBuilder.Builder class to build and deploy .NET C# and VB projects. You could also easily extract only the deployment part from your project, which consists of:

  1. Assembly DLL
  2. Referenced DLLs copied to the bin folder
  3. Content files:

    prjbuilder.exe [/release] [/copy:destination] [/nobuild] 
        [other parameters for framework compiler] project_name
    • /release: Forces compiler to do release build
    • /copy:destination: Sets the destination directory, where only content and compiled assemblies will be placed saving the catalog structure.
      Note:
      1. Copied files replace old ones in the destination folder.
      2. If path consists of white spaces, then include it in double quotes "", do not use trailing slash. Example:
        • prjbuilder.exe /copy:"C\Program files\my app"
    • /nobuild: When this option is used, no build is done. It is useful when you need to copy the project to some destination without compiling.
    • project_name: Specifies path to the project to build.
    • Other parameters for framework compiler: These parameters are passed to the .NET compiler without changes. It was done to help to work in situations when you want to pass a parameter directly to the compiler.

Logging

The compiler makes build logs and places them into the project file's folder. If the project could not be found, then logs are placed into the current directory - build.log. This file consists of all the information, which is printed when the build is done - build_files.log. All files, which take part in the build process: compiled files, resource files, reference files.

Examples

  1. Simply building the project in debug mode:

  2. prjbuilder.exe c:\dev\test\test.csproj 
  3. Building project in release mode:

    prjbuilder.exe /release "C:\Documents and Settings\devuser\My Documents\
        Visual Studio Projects\test\test.vbproj" 
  4. Building and copying project (note, that in the source project's folder, DLLs are not changed):

    prjbuilder.exe /copy:"C:\folder with spaces" c:\dev\test\test.csproj 
  5. Make a deployable copy of the project without building it (note that DLL, content and referenced assemblies are copied only):

    prjbuilder.exe /copy:"C:\folder with spaces" /nobuild c:\dev\test\test.csproj 

History

  • 20th June, 2006: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Mihail Arhipov
Russian Federation Russian Federation
Member
My name is Mihail Arhipov. I live in Saint-Petersburg, Russia. I am studing at university 4th course now and working as a developer in C#, ASP.NET, Oracle, MS SQL for 1,5 year already.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionProblems with libsmembertitocozza11 Nov '06 - 9:40 
Helo,
This software is great, but I have some problems with external libs that are referenced in the bin directory.
How con I solve this?
 
I copy the compiler output:
 
Reading project file Test.vbproj.
Project file read.
-------------------------------------------------------------------------------------
Build started at 11/11/2006 12:32:53 p.m.
Using compiler: vbc.exe
 

C:\Test> "c:\windows\microsoft.net\framework\v1.1.4322\vbc.exe" /t:library /utf8output /R:"bin\Infragistics.WebUI.WebDateChooser.v5.1.dll" /R:"bin\ICSharpCode.SharpZipLib.dll" /R:"bin\Infragistics.WebUI.Shared.v5.1.dll" /R:"bin\Infragistics.WebUI.UltraWebGrid.v5.1.dll" /R:"bin\Infragistics.WebUI.UltraWebNavigator.v5.1.dll" /R:"bin\Infragistics.WebUI.WebDataInput.v5.1.dll" /R:"C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\System.Design.dll" /R:"lib\AdvAjaxControls.dll" /R:"System.dll" /R:"System.Data.dll" /R:"System.Drawing.dll" /R:"System.Web.dll" /R:"System.Xml.dll" /R:"Infragistics.WebUI.WebDateChooser.v5.1.dll" /R:"ICSharpCode.SharpZipLib.dll" /R:"Infragistics.WebUI.Shared.v5.1.dll" /R:"Infragistics.WebUI.UltraWebGrid.v5.1.dll" /R:"Infragistics.WebUI.UltraWebNavigator.v5.1.dll" /R:"Infragistics.WebUI.WebDataInput.v5.1.dll" /R:"System.Design.dll" /R:"AdvAjaxControls.dll" /out:"bin\Test.dll" /D:DEBUG=1 /debug+ /t:library /rootnamespace:Test /res:"Global.asax.resx" /res:"licenses.licx" /res:"Message.aspx.resx" /res:"QueryBridge.aspx.resx" /res:"Search.aspx.resx" /res:"Step1.aspx.resx" /res:"Step1_1.aspx.resx" /res:"Step2.aspx.resx" /res:"Step2_0.aspx.resx" /res:"Step2_1.aspx.resx" /res:"Step2_2.aspx.resx" /res:"Step3.aspx.resx" /res:"Step3_0.aspx.resx" /res:"SuperBBTest.aspx.resx" /res:"WebForm1.aspx.resx" /imports:Microsoft.VisualBasic /imports:System /imports:System.Collections /imports:System.Configuration /imports:System.Data /imports:System.Drawing /imports:System.Web /imports:System.Web.UI /imports:System.Web.UI.HtmlControls /imports:System.Web.UI.WebControls "AssemblyInfo.vb" "Global.asax.vb" "Message.aspx.vb" "QueryBridge.aspx.vb" "Search.aspx.vb" "Step1.aspx.vb" "Step1_1.aspx.vb" "Step2.aspx.vb" "Step2_0.aspx.vb" "Step2_1.aspx.vb" "Step2_2.aspx.vb" "Step3.aspx.vb" "Step3_0.aspx.vb" "SuperBBTest.aspx.vb" "WebForm1.aspx.vb" "XML.vb" "Controls\AdvancedSearch.ascx.vb" "Controls\BuyerData.ascx.vb"
 

Versión 7.10.6001.4 del compilador de Microsoft (R) Visual Basic .NET
para Microsoft (R) .NET Framework, versión 1.1.4322.2032
(C) Microsoft Corporation 1987-2002. Reservados todos los derechos.
 
vbc : Error de la lí­nea de comandos BC2017 : no se encuentra la biblioteca 'Infragistics.WebUI.WebDateChooser.v5.1.dll'
vbc : Error grave BC2000 : Fallo inesperado de inicialización del compilador: El sistema no puede hallar el archivo especificado.
Warning: File "bin\Infragistics.WebUI.WebDateChooser.v5.1.dll" is referenced from "bin" directory.
Warning: File "bin\ICSharpCode.SharpZipLib.dll" is referenced from "bin" directory.
Warning: File "bin\Infragistics.WebUI.Shared.v5.1.dll" is referenced from "bin" directory.
Warning: File "bin\Infragistics.WebUI.UltraWebGrid.v5.1.dll" is referenced from "bin" directory.
Warning: File "bin\Infragistics.WebUI.UltraWebNavigator.v5.1.dll" is referenced from "bin" directory.
Warning: File "bin\Infragistics.WebUI.WebDataInput.v5.1.dll" is referenced from "bin" directory.
 
Build finished at 11/11/2006 12:32:54 p.m.
-------------------------------------------------------------------------------------
 


AnswerRe: Problems with libsmemberMihail Arhipov12 Nov '06 - 23:15 
Hello,
 
unfortunately i don't understand spanish (is this spanish? Blush | :O ))
to resolve this error you try reference the assemblies from the other folder, and if it fails too, please write the error you get in english.
 
Mike
 
Samson

QuestionRe: Problems with libsmembertitocozza13 Nov '06 - 10:16 
Hello,
Thanks for the replay!
 
I'm steel having troubles with the external libs.
I've moved all external libs to the lib\ folder.
 
(it's like it copies 2 times, with and without "lib\")
 

------------------------------------------
Reading project file Test.vbproj.
Project file read.
-------------------------------------------------------------------------------------
Build started at 11/13/2006 5:56:47 PM
Using compiler: vbc.exe
 

C:\Test> "c:\winnt\microsoft.net\framework\v1.1.4322\vbc.exe" /t:library /utf8output /R:"lib\Infragistics.WebUI.WebDateChooser.v5.1.dll" /R:"lib\ICSharpCode.SharpZipLib.dll" /R:"lib\Infragistics.WebUI.Shared.v5.1.dll" /R:"lib\Infragistics.WebUI.UltraWebGrid.v5.1.dll" /R:"lib\Infragistics.WebUI.UltraWebNavigator.v5.1.dll" /R:"lib\Infragistics.WebUI.WebDataInput.v5.1.dll" /R:"C:\WINNT\Microsoft.NET\Framework\v1.1.4322\System.Design.dll" /R:"lib\AdvAjaxControls.dll" /R:"System.dll" /R:"System.Data.dll" /R:"System.Drawing.dll" /R:"System.Web.dll" /R:"System.Xml.dll" /R:"Infragistics.WebUI.WebDateChooser.v5.1.dll" /R:"ICSharpCode.SharpZipLib.dll" /R:"Infragistics.WebUI.Shared.v5.1.dll" /R:"Infragistics.WebUI.UltraWebGrid.v5.1.dll" /R:"Infragistics.WebUI.UltraWebNavigator.v5.1.dll" /R:"Infragistics.WebUI.WebDataInput.v5.1.dll" /R:"System.Design.dll" /R:"AdvAjaxControls.dll" /out:"bin\Test.dll" /D:DEBUG=1 /debug+ /t:library /rootnamespace:Test /res:"Global.asax.resx" /res:"licenses.licx" /res:"Message.aspx.resx" /res:"QueryBridge.aspx.resx" /res:"Search.aspx.resx" /res:"Step1.aspx.resx" /res:"Step1_1.aspx.resx" /res:"Step2.aspx.resx" /res:"Step2_0.aspx.resx" /res:"Step2_1.aspx.resx" /res:"Step2_2.aspx.resx" /res:"Step3.aspx.resx" /res:"Step3_0.aspx.resx" /res:"SuperBBTest.aspx.resx" /res:"WebForm1.aspx.resx" /imports:Microsoft.VisualBasic /imports:System /imports:System.Collections /imports:System.Configuration /imports:System.Data /imports:System.Drawing /imports:System.Web /imports:System.Web.UI /imports:System.Web.UI.HtmlControls /imports:System.Web.UI.WebControls "AssemblyInfo.vb" "Global.asax.vb" "Message.aspx.vb" "QueryBridge.aspx.vb" "Search.aspx.vb" "Step1.aspx.vb" "Step1_1.aspx.vb" "Step2.aspx.vb" "Step2_0.aspx.vb" "Step2_1.aspx.vb" "Step2_2.aspx.vb" "Step3.aspx.vb" "Step3_0.aspx.vb" "SuperBBTest.aspx.vb" "WebForm1.aspx.vb" "XML.vb"
 

Microsoft (R) Visual Basic .NET Compiler version 7.10.3052.4
for Microsoft (R) .NET Framework version 1.1.4322.573
Copyright (C) Microsoft Corporation 1987-2002. All rights reserved.
 
vbc : Command line error BC2017 : could not find library 'Infragistics.WebUI.WebDateChooser.v5.1.dll'
vbc : Fatal error BC2000 : compiler initialization failed unexpectedly: The system cannot find the file specified.
 
Build finished at 11/13/2006 5:56:49 PM
-------------------------------------------------------------------------------------
 

 
By the way, this is part of a solution, with other proyects.
I should copy first each DLL to one folder to compile, isn't it?
 
Thanks a lot!
 
Tito
Generalhimemberpkarthik197924 Jul '06 - 22:16 
Thats a nice work..
 
Iam having VS.net 2002 in my system.Is there any chance to use your source.
 
I need to build the application from my web application by clicking some button.Please give me the details to call your source code from my webapplication...

 
Karthik
AnswerRe: himemberMihail Arhipov25 Jul '06 - 23:49 
Hello!
 
You use VS .net 2002, I suppose you also use framework v1.1. If so, then the building in itself should work, but I'm not sure about the same structure of the VS .net 2002 and VS .net 2003 project files.
 
This utility uses VS project file (.csproj, if you code c#) to gather information and if project file structure was changed in VS .net 2003, then to use the tool, you should change it's source code.
 
First of all try to use the utility as in original, then if an error occures, write me and I'll see how I could help.
 
Mihail
 
Samson

GeneralCommandline workmemberintrader26 Jun '06 - 12:06 
I saw an old article by Fritz Onion that suggests to leave behind the IDE. I may be wrong, but using built tools like NANT could help you
 
Fritz Schenk
GeneralGood job! Some requests...memberHyperX20 Jun '06 - 4:30 
Mihail,
 
This is a good article. We have about 9 dependencies and we always have to
 
- Open the solution,
- Get latest from Visual SourceSafe
- Build
- Copy the DLL to the deploy directory.
 
Is there any way that we can automate Microsoft SourceSafe to grab the latest version of the solution and then run your ProjectBuilder?
 
Thanks!
 
HyperX.
 
-- modified at 10:31 Tuesday 20th June, 2006
GeneralRe: Good job! Some requests...memberMihail Arhipov20 Jun '06 - 20:13 
Here you could read about using VSS from the command line.
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/guides/html/vsgrfcmdline.asp
 
Samson
GeneralRe: Good job! Some requests...membertsvayer27 Jun '06 - 3:22 
You can do that in NANT.
First use "vssget" to get solution from VSS.
Then simple use "copy" to put required DLLs into solution.
and finally use "solution" to build solution.
Finally after build you "copy" content & executables into a deployment directory.
 
In case you need specific functionality not provided by NANT, it can be easily extended.
 

 

 
Vitaliy
GeneralRe: Good job! Some requests...memberSoftware_Architect27 Jun '06 - 9:23 
tsvayer wrote:
You can do that in NANT.

 
Yes, but it is perhaps worth noting that the vssget (and other source-control related tasks) are a part of the NAnt-contrib project.
 
(Not to be pedantic - I just know it can be confusing for anyone starting to find their way around NAnt.)

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

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130523.1 | Last Updated 20 Jun 2006
Article Copyright 2006 by Mihail Arhipov
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid