Search code examples
msbuild

How do I call static class methods from msbuild?


How does one call a class static method from msbuild and store its results in a list?

EDIT: Okay, let me explain a bit further. I am using sandcastle help file builder to generate documentation for my application. One of the requirements is that you must specify the documentation sources as follows:

<DocumentationSources>
    <DocumentationSource sourceFile="$(MSBuildProjectDirectory)\..\src\myApp\bin\Debug\myApp.exe" xmlns="" />
    <DocumentationSource sourceFile="$(MSBuildProjectDirectory)\..\src\myApp\bin\Debug\myApp.xml" xmlns="" />
</DocumentationSources>

Sandcastle Help File Builder comes with a utils assembly that has a way of retrieving all dll and xml files from a specified directory. I want to call the method from this assembly and store its result as a list of <DocumentationSource>. This is a static method which returns Collection<string>


Solution

  • Generally, the most flexible option is to create a custom MSBuild task. This is all untested code meant to just to give you the idea:

    In your msbuild file:

    <UsingTask TaskName="FindFiles" AssemblyFile="FindFiles.dll" />
    
    <!-- 
    As you'll see below, SearchDirectory and SearchPatterns are input parameters,
    MatchingFiles is an output parameter, SourceFiles is an ItemGroup assigned to
    the output.
    -->
    <FindFiles SearchDirectory="$(MyDirectory)" SearchPatterns="*.dll;*.xml">
        <Output ItemName="SourceFiles" TaskParameter="MatchingFiles" />
    </FindFiles>
    
    <!-- You can then use the generated ItemGroup output elsewhere. -->
    <DocumentationSources>
        <DocumentationSource sourceFile="@(SourceFiles)" xmlns="" />
    </DocumentationSources>
    

    FindFiles.cs:

    using System;
    using System.IO;
    using System.Collections.Generic;
    
    using Microsoft.Build.Framework;
    using Microsoft.Build.Utilities;
    
    namespace FindFiles
    {
        public class FindFiles : Task
        {
            // input parameter
            [Required]
            public string SearchDirectory { get; set; }
    
            // output parameter
            [Required]
            public string[] SearchPatterns { get; set; }
    
            [Output]
            public string[] MatchingFiles { get; private set; }
    
            private bool ValidateParameters()
            {
                if (String.IsNullOrEmpty(SearchDirectory))
                {
                    return false;
                }
                if (!Directory.Exists(SearchDirectory))
                {
                    return false;
                }
                if (SearchPatterns == null || SearchPatterns.Length == 0)
                {
                    return false;
                }
                return true;
            }
    
            // MSBuild tasks use the command pattern, this is where the magic happens,
            // refactor as needed
            public override bool Execute()
            {
                if (!ValidateParameters())
                {
                    return false;
                }
                List<string> matchingFiles = new List<string>();
                try
                {
    
                    foreach (string searchPattern in SearchPatterns)
                    {
                        matchingFiles.AddRange(
                            Directory.GetFiles(SearchDirectory, searchPattern)
                            );
                    }
                }
                catch (IOException)
                {
                    // it might be smarter to just let this exception fly, depending on
                    // how you want the task to behave
                    return false;
                }
                MatchingFiles = matchingFiles.ToArray();
                return true;
            }
        }
    }