4

I have a custom MSBuild Task that generates a file based on files that have no build action. The generated files need to be embedded into the final assembly. The task looks something like this:

public class MyTask : Task
{
    public string OutputDirectory { get; set; }

    public string[] NoneIncluded { get; set; }

    private IEnumerable<ITaskItem> _generatedFiles;
    [Output]
    public ITaskItem[] GeneratedFiles => _generatedFiles.ToArray();

    public override bool Execute()
    {
        _generatedCssFiles = new List<ITaskItem>();
        foreach(var item in NoneIncluded)
        {
            if(someCondition)
            {
                var contents = DoFoo(item);
                var outputPath = Path.Combine(OutputDirectory, $"{item}.txt");
                File.WriteAllText(outputPath, contents);
                _generatedFiles.Add(new TaskItem(ProjectCollection.Escape(outputFile)));
            }
        }
    }
}

In my targets file, I then have a target defined like the following:

<PropertyGroup>
    <CoreCompileDependsOn>MyTarget;$(CoreCompileDependsOn);</CoreCompileDependsOn>
</PropertyGroup>

<Target Name="MyTarget"
        BeforeTargets="CoreCompile;Build">

  <MyTask OutputDirectory="$(IntermediateOutputPath)"
          NoneIncluded="@(None)">
    <Output ItemName="FilesWrite"
            TaskParameter="GeneratedFiles"/>
    <Output ItemName="EmbeddedResource" 
            TaskParameter="GeneratedFiles" />
  </MyTask>

</Target>

I ultimately end up with two issues that I can't seem to resolve:

  1. Although the files are generated prior to the compile task, it isn't embedded into the assembly, unless I rebuild the project without cleaning the outputs. On the subsequent build the file is embedded.
  2. If I generate the files in the IntermediateOutputPath, the embedded resource id includes that path. So instead of MyProject.SomeResource.txt I get MyProject.obj.netstandard2._0.SomeResource.txt

Note: - If I replace the Path.Combine and simply generate the output file in the project, it fixes the issue of the resource id, but not the first issue with it not being embedded on the first compile.

How can I ensure the my generated files are embedded on the first compilation, and that I can generate them in the IntermediateOutputPath rather than the Project directory with a resource id as if it were in the project.

2 Answers 2

3

You need to run your target earlier in the pipeline. CoreCompile is too late.

You can add the following to your .csproj file. This target will run before ResolveReferences and add Image.png as an embedded resource.

<Target Name="IncludeDynamicResources" BeforeTargets="ResolveReferences">
    <ItemGroup>
      <EmbeddedResource Include="Image.png">
        <Type>Non-Resx</Type>
      </EmbeddedResource>
    </ItemGroup>
</Target>
Sign up to request clarification or add additional context in comments.

Comments

0

Your second issue can be solved by simply setting LogicalName metadata to the created task item.

TaskItem taskItem = new TaskItem(ProjectCollection.Escape(outputFile));   
taskItem.SetMetadata("LogicalName", $"{AssemblyName}.{item}.txt");
_generatedFiles.Add(taskItem);

Now to access the assembly name inside your task just add AssemblyName string property to MyTask and AssemblyName="$(AssemblyName)" to your targets. This should produce the desired result.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.