MSBuild ReadLinesFromFile all text on one line

deployment, msbuild, msbuild-task, msbuildcommunitytasks

Solution

The problem here is you are using the `ReadLinesFromFile` task in a manner it wasn't intended.

ReadLinesFromFile Task Reads a list of items from a text file.

So it's not just reading all the text from a file, it's reading individual items from a file and returning an item group of ITaskItems. Whenever you output a list of items using the `@()` syntax you will get a separated list, the default of which is a semicolon. This example illustrates this behavior:

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build"    xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">

    <ItemGroup>
        <Color Include="Red" />
        <Color Include="Blue" />
        <Color Include="Green" />
</ItemGroup>

<Target Name="Build">
        <Message Text="ItemGroup Color: @(Color)" />
</Target>

</Project>

And the output looks like this:

  ItemGroup Color: Red;Blue;Green

So while the best solution to your problem is to write an MSBuild task that reads a file into a property as a string an not a list of items, that's really not what you asked for. You asked if there was a way to put them back, and there is using MSBuild Transforms.

Transforms are used to create one list from another and also have the ability to transform using a custom separator. So the answer is to transform your list read in using `ReadItemsFromFile` into another list with newlines. Here is an example that does just that:

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">

    <ItemGroup>
        <File Include="$(MSBuildProjectDirectory)\Test.txt" />
    </ItemGroup>

    <Target Name="Build">
        <ReadLinesFromFile File="@(File)">
            <Output TaskParameter="Lines" ItemName="FileContents" />
        </ReadLinesFromFile>

        <Message Text="FileContents: @(FileContents)" />
        <Message Text="FileContents Transformed: @(FileContents->'%(Identity)', '%0a%0d')" />
    </Target>

</Project>

Test.text looks like:

Red
Green
Blue

And the output looks like this:

[C:\temp]:: msbuild test.proj
Microsoft (R) Build Engine Version 3.5.21022.8
[Microsoft .NET Framework, Version 2.0.50727.1433]
Copyright (C) Microsoft Corporation 2007. All rights reserved.

Build started 11/8/2008 8:16:59 AM.
Project "C:\temp\test.proj" on node 0 (default targets).
  FileContents: Red;Green;Blue
  FileContents Transformed: Red
Green
Blue
Done Building Project "C:\temp\test.proj" (default targets).


Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:00.03

What's going on here is two things.

@(FileContents->'%(Identity)', '%0a%0d')   

- We are transforming the list from one type to another using the same values (`Identity`) but a custom separator `'%0a%0d'`

- We are using MSBuild Escaping to escape the line feed (`%0a`) and carriage return (`%0d`)

Problem

When I do a ReadLinesFromFile on a file in MSBUILD and go to output that file again, I get all the text on one line. All the Carriage returns and LineFeeds are stripped out. ``` <Project DefaultTargets = "Deploy" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" > <Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/> <ItemGroup> <MyTextFile Include="$(ReleaseNotesDir)$(NewBuildNumber).txt"/> </ItemGroup> <Target Name="ReadReleaseNotes"> <ReadLinesFromFile File="@(MyTextFile)" > <Output TaskParameter="Lines" ItemName="ReleaseNoteItems"/> </ReadLinesFromFile> </Target> <Target Name="MailUsers" DependsOnTargets="ReadReleaseNotes" > <Mail SmtpServer="$(MailServer)" To="$(MyEMail)" From="$(MyEMail)" Subject="Test Mail Task" Body="@(ReleaseNoteItems)" /> </Target> <Target Name="Deploy"> <CallTarget Targets="MailUsers" /> </Target> </Project> ``` I get the text from the file which normally looks like this ``` - New Deployment Tool for BLAH - Random other stuff()"" ``` Coming out like this ``` - New Deployment Tool for BLAH;- Random other stuff()"" ``` I know that the code for ReadLinesFromFile will pull the data in one line at a time and strip out the carriage returns. Is there a way to put them back in? So my e-mail looks all nicely formatted? Thanks

Original source