Alfons
Alfons

Reputation: 531

Adding a Postbuild event to a project

When I generate a C# project (csproj file) and then compile it, msbuild somehow doesn’t recognize the variables $(ConfigurationName) and $(ProjectDir) (and others) in the pre- and postbuild event.

When I Manually move the pre- and postbuild event configuration in the generated .csproj file further downwards, then msbuild recognizes these variables correctly.

Adding the buildevent to the project is the last thing I do before saving the project.

This is how I add it:

using Microsoft.Build.Construction;
using Microsoft.Build.Evaluation;

private const string PreBuildEventFixture = "PreBuildEvent";
private const string PostBuildEventFixture = "PostBuildEvent";
private const string PreBuildEvent = "attrib -R \"$(ProjectDir)app.config\"";
private const string PostBuildEvent = "copy \"$(ProjectDir)app.config.$(ConfigurationName)\" \"$(TargetDir)\\$(ProjectName).dll.config\" \r\n attrib -R \"$(ProjectPath)\"";

public void AddBuildEvents(Project project)
{
    ProjectPropertyGroupElement propertyGroupElement = project.Xml.AddPropertyGroup();
    propertyGroupElement.AddProperty(PreBuildEventFixture, PreBuildEvent);
    propertyGroupElement.AddProperty(PostBuildEventFixture, PostBuildEvent);
}

The error I get when running the generated project through msbuild is this:

The command "copy "app.config." "\.dll.config"" exited with code 1

When I then manually edit the .csproj file (with notepad or another text editor), cut the pre-and postbuild event, and paste it below the <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> element, then msbuild builds the generated .csproj file fine.

What is the best way to add the build events to the .csproj file so it ends up after the Import element in the resulting XML?

Apparently, my current way of using [ProjectPropertyGroupElement][1] by requesting it from AddPropertyGroup of the the Xml property of the Microsoft.Build.Evaluation.Project is not.

Example Project:

using System.IO;
using Microsoft.Build.Construction;
using Microsoft.Build.Evaluation;

class Program
{
    private const string PreBuildEventFixture = "PreBuildEvent";
    private const string PostBuildEventFixture = "PostBuildEvent";
    private const string PreBuildEvent = "attrib -R \"$(ProjectDir)app.config\"";
    private const string PostBuildEvent = "copy \"$(ProjectDir)app.config.$(ConfigurationName)\" \"$(TargetDir)\\$(ProjectName).exe.config\" \r\n attrib -R \"$(ProjectPath)\"";

    private const string ProjectFile = @"C:\test\TestProject\TestProject.csproj";

    static void Main(string[] args)
    {
        if (!File.Exists(ProjectFile))
            throw new FileNotFoundException("ProjectFile not found");

        ProjectCollection collection = new ProjectCollection();
        Project project = collection.LoadProject(ProjectFile);

        ProjectPropertyGroupElement propertyGroupElement = project.Xml.AddPropertyGroup();
        propertyGroupElement.AddProperty(PreBuildEventFixture, PreBuildEvent);
        propertyGroupElement.AddProperty(PostBuildEventFixture, PostBuildEvent);
        project.Save();
        collection.UnloadAllProjects();
    }
}

Steps to reproduce

Upvotes: 4

Views: 3371

Answers (2)

Ilya Kozhevnikov
Ilya Kozhevnikov

Reputation: 10432

var propertyGroupElement = project.Xml.CreatePropertyGroupElement();
project.Xml.AppendChild(propertyGroupElement);
propertyGroupElement.AddProperty(PreBuildEventFixture, PreBuildEvent);
propertyGroupElement.AddProperty(PostBuildEventFixture, PostBuildEvent);

Upvotes: 5

Mihai
Mihai

Reputation: 471

Project related macros are not parsed if they are added before the project is actually constructed (constructing a project includes adding references). Instead of using $(ProjectName), the path can be constructed using solution variables (that already exist) like this :

copy "$(SolutionDir)ProjectName\app.config.$(Configuration)" "$(SolutionDir)ProjectName\bin\$(Configuration)\ProjectName.dll.config"

Note that ProjectName is the actual name of the project hardcoded, but since you are generating a project this should be easy to add.

Upvotes: 2

Related Questions