-1

I setup a build task following a tutorial several months, which allowed for single named parameters.

However, I'd like to upgrade the task to include multiple parameters. I'm having some difficulty.

Here's my current target file...

<Project>

    <PropertyGroup>
        <ThisAssembly>$(MSBuildThisFileDirectory)bin\Debug\netstandard2.0\ourapp.build.dll
        </ThisAssembly>    
        <FirstRun>false</FirstRun>    
        <FirstRun Condition="!Exists('$(ConstantGeneratorOutputFile)')">true</FirstRun>    
    </PropertyGroup>

    <UsingTask TaskName="ourapp.ConstantGeneratorTask"
               AssemblyFile="$(ThisAssembly)" />

    <!-- Pointing 'Outputs' to a non existing file will disable 
    up-to-date checks and run the task every time, there's probably a better way -->
    <Target Name="ourapp" 
            BeforeTargets="BeforeCompile;CoreCompile"
            Inputs="@(ConstantGeneratorSourceFiles)" 
            Outputs="$(ConstantGeneratorOutputFile).nocache">
        
        <ConstantGeneratorTask 
            SourceFiles="@(ConstantGeneratorSourceFiles)" 
            OutputFile="$(ConstantGeneratorOutputFile)"
            AppXamlFile="$(ConstantGeneratorAppXamlFile)"
            NameSpaceName="$(ConstantGeneratorNameSpaceName)"/>
        
        <ItemGroup Condition="Exists('$(ConstantGeneratorOutputFile)')">
            
            <FileWrites Include="$(ConstantGeneratorOutputFile)" />
            
            <Compile Include="$(ConstantGeneratorOutputFile)" 
                     Condition="$(FirstRun) == 'true'" />
            
        </ItemGroup>
    </Target>

</Project>

And here's the code to read those parameters...

namespace ourapp
{
    public class ConstantGeneratorTask : Task
    {
        [Required]
        public string OutputFile { get; set; } = "";

        [Required]
        public ITaskItem[] SourceFiles { get; set; } = Array.Empty<ITaskItem>();

        [Required]
        public string NameSpaceName { get; set; } = "";

        [Required]
        public string AppXamlFile { get; set; } = "";

And heres the csproj parameters

    <ConstantGeneratorOutputFile>$(MSBuildThisFileDirectory)/Common/Constants.cs
    </ConstantGeneratorOutputFile>

    <ConstantGeneratorAppXamlFile>$(MSBuildThisFileDirectory)/App.xaml
    </ConstantGeneratorAppXamlFile>

    <ConstantGeneratorNameSpaceName>ourapp.Common
    </ConstantGeneratorNameSpaceName>

I'd like to provide something like this..

<Items>
  <Item XamlFile="$(MSBuildThisFileDirectory)/App.xaml" 
      NS="ourapp.Common" 
      OutputFile="$(MSBuildThisFileDirectory)/Common/Constants.cs" />

  <Item XamlFile="$(MSBuildThisFileDirectory)/Resources/AutomationIds.xaml" 
      NS="ourapp.Resources" 
      OutputFile="$(MSBuildThisFileDirectory)/Common/AutomationIds.cs" />
</Items>

Can anyone point me in the right direction ?

Jules
  • 7,568
  • 14
  • 102
  • 186
  • What do you want to change from the current status? Are you having trouble defining or passing through `ConstantGeneratorSourceFiles` items (e.g. ``)? – Martin Ullrich Apr 27 '21 at 09:20
  • I’m not sure how to group items in the csproj and how that will be read the targets file. – Jules Apr 27 '21 at 09:23

1 Answers1

0

You can use <ItemGroup> to group your items in csproj file, for example:

   <ItemGroup>
    <Xaml Include = "$(MSBuildThisFileDirectory)/App.xaml" >
      <NS>ourapp.Common</NS>
      <OutputFile>$(MSBuildThisFileDirectory)Common\Constants.cs</OutputFile>
    </Xaml>
  </ItemGroup>

Then, you can use %(Xaml.OutputFile) in targets file, for example:

<Project>
  <Target Name="message" AfterTargets="build">
    <Message Text="%(Xaml.OutputFile)"/>
  </Target>
</Project>

Update: The cs file:

public class Common : Task
{
    [Required]
    public ITaskItem[] SourceFiles
    {
        get
        {
            return sourceFiles;
        }
        set
        {
            sourceFiles = value;
        }
    }

    [Required]
    public string NS { get; set;}

    [Output]
    public ITaskItem[] temp { get; }

    private ITaskItem[] sourceFiles;

    public override bool Execute()
    {
        foreach (var item in SourceFiles)
        {
            Console.WriteLine(item.ToString());
        }

        Console.WriteLine(NS);
        Console.WriteLine("*************Common****************");
        return true;
    }
}

The targets file:

  <UsingTask TaskName="Common" AssemblyFile="C:\ClassLibrary1.dll" />
  
  <Target Name="taskdll" AfterTargets="build">
    
    <ItemGroup>
      <XamlFile Include ="$(MSBuildThisFileDirectory)/App.xaml">
        <NS>ourapp.common</NS>
        <OutputFile>$(MSBuildThisFileDirectory)/Common/Constants.cs</OutputFile>
      </XamlFile>

      <XamlFile Include ="$(MSBuildThisFileDirectory)/App.xaml">
        <NS>ourapp.Resources</NS>
        <OutputFile>$(MSBuildThisFileDirectory)/Common/Constants.cs</OutputFile>
      </XamlFile> 
      
    </ItemGroup>
    
    <Message Text="***************START************"/>
    <Common SourceFiles ="@(XamlFile);%(XamlFile.NS);%(XamlFile.OutputFile)"
        NS ="%(XamlFile.NS)" 
        Condition ="'%(XamlFile.NS)' == 'ourapp.common'"/>
    <Message Text="***************END*************"/>
  </Target>

The result on my side:

enter image description here

Dylan
  • 504
  • 2
  • 5
  • 9
  • @Jules, I have updated my answer, hope it could work for you. – Dylan Apr 28 '21 at 08:22
  • Is this: [pass data to an ITaskItem property of an MSBuild task](https://stackoverflow.com/questions/675741/how-to-pass-data-to-an-itaskitem-property-of-an-msbuild-task) what you need? If not, I think an example will be better to make me clear. – Dylan Apr 29 '21 at 06:30
  • Ah yes this is helpful https://stackoverflow.com/a/678427/450456 although I wish there was an itemgroup example, however the other answer has them with the Include attribute, will that regard them as actual files. Or could I include strings ? – Jules Apr 29 '21 at 06:35
  • Yes, you can include string, it can also work. – Dylan Apr 29 '21 at 09:14
  • Would you mind updating your answer please, could you adding you add two item groups, showing two different NS and add the cs too ? Just for completeness. – Jules Apr 30 '21 at 06:12
  • Thanks @DylanZhu-MSFT sorry to be so much trouble but could you add NS to the cs code so I can see how the would flow through from your csproj example? I just don’t see how that data can be grouped with the correct SourceFile and AppXamlFile etc ? – Jules May 06 '21 at 12:11
  • @Jules, I have modified my answer. If it is still not what you want, a sample of this will be better. – Dylan May 07 '21 at 09:26
  • maybe I’m just not understanding, perhaps one item group is one session of the task? I assumed that everything needed to be passed in for one session of the task. When I say session I mean one call of the task. – Jules May 07 '21 at 09:31
  • In one build process, the items from multiple(or one) item groups are shared. The items can be divided into different groups, but the groups are just made to be readable. They are equal to one group. So if you want to specify one itemgroup for one task, you need to add condition to distinguish the items which have the same name. – Dylan May 10 '21 at 06:08