msbuildmsbuild-taskmsbuild-4.0

How to re-run property evaluation in MSBuild target?


I have a custom MSBuild target, partial snippet as follows ..

<Target Name="PublishHtm">
  <PropertyGroup>
    <PublishHtmTemplateContents>$([System.IO.File]::ReadAllText($(PublishHtmTemplatePath)))</PublishHtmTemplateContents>
    <PublishHtm>$(PublishHtmTemplateContents)</PublishHtm>
  </PropertyGroup>
  <WriteLinesToFile Lines="$(PublishHtm)" File="$(PublishDir)\publish.htm" Overwrite="true"/>
</Target>

This is a rework attempt for this solution in that I'm trying to isolate this template to an external file. The template contains MSBuild property references such as $(ApplicationName). When doing this exactly as described in the linked solution, it works fine, but when loading the template in as a string, none of these property expressions are evaluated by the time it gets to the file.

<SPAN CLASS="BannerTextApplication">$(ApplicationName)</SPAN>

Is there an MSBuild expression/function I can use to get the string to be reevaluated given the context that the Target is being invoked?

BTW I'd rather not work around the problem using find/replace or regex replace, and stick with the MSBuild expression engine.

Using Visual Studio 2012 & .NET Framework 4.5.


Solution

  • Sorry for not getting back to this question for awhile. Initially I thought that to solve this problem we'll need to bend MSBuild in very unusual way (plan for today was to write complex inline task which will do regex-replace in external file using Msbuild properties as tokens ). But I think this can be solved easier, using CDATA section, which is valid inside property definition:

    Here is main script:

    <?xml version="1.0" encoding="utf-8"?>
    <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
        <PropertyGroup>
            <MyOtherProperty>$([System.DateTime]::Now)</MyOtherProperty>
            <Version>1.0.1b</Version>
            <ProjectName>MSBuild Rox</ProjectName>
            <Author>Alexey Shcherbak</Author>
        </PropertyGroup>
    
        <Target Name="Build">
            <ItemGroup>
                <PropsToPass Include="MyOtherProperty=$(MyOtherProperty)" />
                <PropsToPass Include="Version=$(Version)" />
                <PropsToPass Include="ProjectName=$(ProjectName)" />
                <PropsToPass Include="Author=$(Author)" />
            </ItemGroup>
    
            <MSBuild Projects="TransformHTML.Template.proj" Properties="@(PropsToPass)" />
        </Target>
    </Project>  
    

    And here is your template. It's not pure html, it's still msbuild file, but at least without ugly encoding for html tags in xml. It's just a block in CDATA

    <?xml version="1.0" encoding="utf-8"?>
    <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Transform">
        <PropertyGroup>
                <HtmlProperty><![CDATA[
                    <body>
                        <div>$(MyOtherProperty)</div>
                        <div>$(Version)</div>
                        <div>$(ProjectName)</div>
                        <div>$(Author)</div>
                    </body>
                ]]></HtmlProperty>
            </PropertyGroup>
    
        <Target Name="Transform">
            <Message Text="HtmlProperty: $(HtmlProperty)" Importance="High" />
        </Target>
    </Project>  
    

    Maybe it's not very elegant ( I personally don't like the section with @PropsToPass) but it'll do the job. You can put everything inline into single file and then you don't need to pass properties to MSBuild task. I don't like massive html-encoding from proposed "this solution" but I'd rather prefer to keep HTML template in the same script where it'll be transformed, just in nice html format, without encoding.

    Single file example:

    <?xml version="1.0" encoding="utf-8"?>
    <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
        <PropertyGroup>
            <MyOtherProperty>$([System.DateTime]::Now)</MyOtherProperty>
            <Version>1.0.1b</Version>
            <ProjectName>MSBuild Rox</ProjectName>
            <Author>Alexey Shcherbak</Author>
        </PropertyGroup>
    
        <Target Name="Build">
            <PropertyGroup>
                <HtmlProperty><![CDATA[
                    <body>
                        <div>$(MyOtherProperty)</div>
                        <div>$(Version)</div>
                        <div>$(ProjectName)</div>
                        <div>$(Author)</div>
                    </body>
                ]]></HtmlProperty>
            </PropertyGroup>
    
            <Message Text="HtmlProperty: $(HtmlProperty)" Importance="High" />
        </Target>
    </Project>  
    

    You can also download these files here