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

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

Rate me:
Please Sign up or sign in to vote.
3.67/5 (4 votes)
19 Jun 2006CPOL4 min read 94.3K   1.3K   27   19
This class and command line utility shows how to easily build and deploy C# and VB projects without VS.NET.
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:

C#
///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.

C#
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.

C#
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)


Written By
Russian Federation Russian Federation
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.

Comments and Discussions

 
Questionthe Xpath is unable to find the xml tags Pin
anilkumar19867-Dec-15 20:21
anilkumar19867-Dec-15 20:21 
QuestionProblems with libs Pin
titocozza11-Nov-06 9:40
titocozza11-Nov-06 9:40 
AnswerRe: Problems with libs Pin
Mihail Arhipov12-Nov-06 23:15
Mihail Arhipov12-Nov-06 23:15 
QuestionRe: Problems with libs Pin
titocozza13-Nov-06 10:16
titocozza13-Nov-06 10:16 
Generalhi Pin
pkarthik197924-Jul-06 22:16
pkarthik197924-Jul-06 22:16 
AnswerRe: hi Pin
Mihail Arhipov25-Jul-06 23:49
Mihail Arhipov25-Jul-06 23:49 
GeneralCommandline work Pin
intrader26-Jun-06 12:06
intrader26-Jun-06 12:06 
GeneralGood job! Some requests... Pin
RK KL20-Jun-06 4:30
RK KL20-Jun-06 4:30 
GeneralRe: Good job! Some requests... Pin
Mihail Arhipov20-Jun-06 20:13
Mihail Arhipov20-Jun-06 20:13 
GeneralRe: Good job! Some requests... Pin
Vitaliy Tsvayer27-Jun-06 3:22
Vitaliy Tsvayer27-Jun-06 3:22 
GeneralRe: Good job! Some requests... Pin
Software_Architect27-Jun-06 9:23
Software_Architect27-Jun-06 9:23 
GeneralRe: Good job! Some requests... Pin
Vitaliy Tsvayer27-Jun-06 10:22
Vitaliy Tsvayer27-Jun-06 10:22 
Generalmsbuild.exe Pin
Igor Vigdorchik20-Jun-06 3:16
Igor Vigdorchik20-Jun-06 3:16 
GeneralRe: msbuild.exe Pin
Mihail Arhipov20-Jun-06 19:59
Mihail Arhipov20-Jun-06 19:59 
GeneralRe: msbuild.exe Pin
Igor Vigdorchik21-Jun-06 3:13
Igor Vigdorchik21-Jun-06 3:13 
GeneralRe: msbuild.exe Pin
Mihail Arhipov21-Jun-06 19:28
Mihail Arhipov21-Jun-06 19:28 
GeneralRe: msbuild.exe Pin
Igor Vigdorchik22-Jun-06 3:40
Igor Vigdorchik22-Jun-06 3:40 
GeneralRe: msbuild.exe Pin
hauer26-Jun-06 6:04
hauer26-Jun-06 6:04 
GeneralRe: msbuild.exe Pin
BeSoft6-Nov-06 22:03
BeSoft6-Nov-06 22:03 

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.