Robert Snyder
Robert Snyder

Reputation: 2409

get solution path at build time or runtime

I have a C# solution that I would like to get the path of the solution be set to the app.config during build time. for instance. Lets say I have the solutions c:\temp\visual studio\super fun project\super_fun_project.sln open. I build and in one of the test projects a app setting is changed to be the full path of the solution. ie

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="fullSolutionPath" value="{setAtBuild}"/>
  </appSettings>
</configuration>

that if I were to go to c:\temp\visual studio\super fun project\Foobar.Tests\bin\Debug\Foobar.Tests.dll.config it would look be

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="fullSolutionPath" value="c:\temp\visual studio\super fun project\super_fun_project.sln"/>
  </appSettings>
</configuration>

or however it needs to get formated so that when at runtime I ask for the value I indeed get the correct path. I've looked down Transformation, but I can't figure out how I would get the solution path set. Are there any other tricks to get this?

Upvotes: 2

Views: 1520

Answers (2)

Simon Mourier
Simon Mourier

Reputation: 138841

What you can do is modify the project file and add an MsBuild Target.

The target can use a Custom Inline Task, a task with its source code integrated into the project file.

So to add this task:

1) unload the project (right click on project node, select "Unload Project")

2) edit the project file (right click on project node, select "Edit ")

3) add the following to the project file (for example to the end) and reload it, now when you build, the config file will be modified accordingly.

<Project ...>
  ...
    <Target Name="AfterBuild">
      <RegexReplace FilePath="$(TargetDir)$(TargetFileName).config" Input="setAtBuild" Output="$(SolutionPath)" />
    </Target>
    <UsingTask TaskName="RegexReplace" TaskFactory="CodeTaskFactory" AssemblyName="Microsoft.Build.Tasks.Core" >
      <ParameterGroup>
        <FilePath Required="true" />
        <Input Required="true" />
        <Output Required="true" />
      </ParameterGroup>
      <Task>
        <Using Namespace="System.Text.RegularExpressions"/>
        <Code Type="Fragment" Language="cs"><![CDATA[
                File.WriteAllText(FilePath, Regex.Replace(File.ReadAllText(FilePath), Input, Output));
            ]]></Code>
      </Task>
    </UsingTask>
</Project>

Here, I've defined Output to use a Visual Studio's MSBuild Property named SolutionPath, but you can reuse this RegexReplace task and update Input and Output parameters to various needs.

Upvotes: 3

Elmar
Elmar

Reputation: 1246

I dont know what your use case is but you can call a homegrown batch file to do this from the post-build events of your project.

example: create a batch script in your project entitled 'updateconf.bat', ensure that it is ANSII encoded (maybe use notepad++ to write the script and confirm ansii) or you'll get an exception indicating that the file is prefixed with an illegal character when you compile your VS project and check the output.

Contents of batch script:

@echo off > newfile & setLocal ENABLEDELAYEDEXPANSION
set old="{setAtBuild}"
set new=%2
set targetBinary=%3


cd %1
for /f "tokens=* delims= " %%a in (%targetBinary%.config) do (
set str=%%a
set str=!str:%old%=%new%!
>> newfile echo !str!
)

del /F /Q %targetBinary%.config
rename "newfile" "%targetBinary%.config"

Then add a post-build event in your project properties that calls the batch script:

call $(ProjectDir)\updateconf.bat "$(TargetDir)" "$(SolutionPath)" $(TargetFileName)

Upvotes: 1

Related Questions