Skip to content

TaskHostFactory does not work with public properties with private get accessor as task parameters #116012

@PetSerAl

Description

@PetSerAl

Issue Description

TaskHostFactory does not allow using public properties with private get accessor as task parameters.

Steps to Reproduce

A/A.cs

using Microsoft.Build.Utilities;

public sealed class SampleTask : Task
{
	public string? S1 { private get; set; }
	public string? S2 { get; set; }
	public string? S3 { set { } }

	public SampleTask() { }

	public override bool Execute() => true;
}

A/A.csproj

<Project Sdk="Microsoft.NET.Sdk">
	<PropertyGroup>
		<Nullable>Enable</Nullable>
		<TargetFramework>net9.0</TargetFramework>
		<OutDir>../out</OutDir>
	</PropertyGroup>
	<ItemGroup>
		<PackageReference Include="Microsoft.Build.Tasks.Core">
			<Version>17.14.8</Version>
		</PackageReference>
	</ItemGroup>
</Project>

B/B.csproj

<Project Sdk="Microsoft.NET.Sdk">
	<PropertyGroup>
		<Nullable>Enable</Nullable>
		<TargetFramework>net9.0</TargetFramework>
	</PropertyGroup>
	<UsingTask TaskName="SampleTask" TaskFactory="TaskHostFactory" AssemblyFile="../out/A.dll" Condition="$(UseTaskHost)=='True'" />
	<UsingTask TaskName="SampleTask" AssemblyFile="../out/A.dll" Condition="$(UseTaskHost)=='False'" />
	<Target Name="TestTarget" AfterTargets="Build">
		<SampleTask S1="Value" Condition="$(TestParameter)=='S1'" />
		<SampleTask S2="Value" Condition="$(TestParameter)=='S2'" />
		<SampleTask S3="Value" Condition="$(TestParameter)=='S3'" />
	</Target>
</Project>

Test.cmd

dotnet build A
dotnet build B -p:UseTaskHost=False -p:TestParameter=S1
dotnet build B -p:UseTaskHost=False -p:TestParameter=S2
dotnet build B -p:UseTaskHost=False -p:TestParameter=S3
dotnet build B -p:UseTaskHost=True -p:TestParameter=S1
dotnet build B -p:UseTaskHost=True -p:TestParameter=S2
dotnet build B -p:UseTaskHost=True -p:TestParameter=S3

Test.zip
Run Test.cmd from zip file.

Expected Behavior

All calls to dotnet build should be successful.

Actual Behavior

Call to dotnet build B -p:UseTaskHost=True -p:TestParameter=S1 fails with

Restore complete (0,7s)
  B failed with 2 error(s) (0,5s) → B\bin\Debug\net9.0\B.dll
    M:\Temp\Test\B\B.csproj(9,15): error MSB4064: The "S1" parameter is not supported by the "SampleTask" task loaded from assembly: A, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null from the path: M:\Temp\Test\out\A.dll. Verify that the parameter exists on the task, the <UsingTask> points to the correct assembly, and it is a settable public instance property.
    M:\Temp\Test\B\B.csproj(9,3): error MSB4063: The "SampleTask" task could not be initialized with its input parameters.

Build failed with 2 error(s) in 2,4s

Analysis

https://github.com/dotnet/msbuild/blob/4ad462496537cd497f9c43531acb21f44d58cd67/src/Shared/LoadedType.cs#L70
When assembly loaded via MetadataLoadContext, then call to type.GetProperties(BindingFlags.Instance | BindingFlags.Public); will not return public properties with private get accessor. But when assembly loaded for execution, then such properties will be included.

Versions & Configurations

.NET SDK:
 Version:           9.0.300
 Commit:            15606fe0a8
 Workload version:  9.0.300-manifests.c678e91b
 MSBuild version:   17.14.5+edd3bbf37

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.26100
 OS Platform: Windows
 RID:         win-x64
 Base Path:   C:\Program Files\dotnet\sdk\9.0.300\

Host:
  Version:      9.0.5
  Architecture: x64
  Commit:       e36e4d1a8f

.NET SDKs installed:
  9.0.300 [C:\Program Files\dotnet\sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 9.0.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 9.0.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.WindowsDesktop.App 9.0.5 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

Metadata

Metadata

Assignees

Type

Projects

Status

No status

Relationships

None yet

Development

No branches or pull requests

Issue actions