Skip to content

Commit 9050147

Browse files
YuliiaKovalovaJanProvaznik
authored andcommitted
Add hostservices translation support for clr 4 task host (dotnet#13154)
Attempt 2 for dotnet#13089 In scope of dotnet#12753 support for translating HostServices in Out of Proc Task Host was added, but limited to NET task host. This change removes this limitation.
1 parent b5d4e63 commit 9050147

File tree

7 files changed

+36
-17
lines changed

7 files changed

+36
-17
lines changed

src/Build.UnitTests/BackEnd/TaskHostConfiguration_Tests.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -463,8 +463,14 @@ public void TestTranslationWithAppDomainSetup(byte[] configBytes)
463463

464464
setup.SetConfigurationBytes(configBytes);
465465

466-
((ITranslatable)config).Translate(TranslationHelpers.GetWriteTranslator());
467-
INodePacket packet = TaskHostConfiguration.FactoryForDeserialization(TranslationHelpers.GetReadTranslator());
466+
// Set version to 0 for CLR4 (Framework-to-Framework) communication which supports AppDomain.
467+
ITranslator writeTranslator = TranslationHelpers.GetWriteTranslator();
468+
writeTranslator.NegotiatedPacketVersion = 0;
469+
((ITranslatable)config).Translate(writeTranslator);
470+
471+
ITranslator readTranslator = TranslationHelpers.GetReadTranslator();
472+
readTranslator.NegotiatedPacketVersion = 0;
473+
INodePacket packet = TaskHostConfiguration.FactoryForDeserialization(readTranslator);
468474

469475
TaskHostConfiguration deserializedConfig = packet as TaskHostConfiguration;
470476

src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -849,6 +849,12 @@ private void DrainPacketQueue(object state)
849849
NodePacketTypeExtensions.WriteVersion(writeStream, context._negotiatedPacketVersion);
850850
writeTranslator.NegotiatedPacketVersion = context._negotiatedPacketVersion;
851851
}
852+
else if (!Handshake.IsHandshakeOptionEnabled(_handshakeOptions, HandshakeOptions.CLR2))
853+
{
854+
// CLR4 task hosts: set version to 0 to enable version-dependent fields.
855+
// CLR2 task hosts: leave as null (default) to skip version-dependent fields.
856+
writeTranslator.NegotiatedPacketVersion = 0;
857+
}
852858

853859
packet.Translate(writeTranslator);
854860

src/Framework/BinaryTranslator.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ public TranslationDirection Mode
119119
}
120120

121121
/// <inheritdoc/>
122-
public byte NegotiatedPacketVersion { get; set; }
122+
public byte? NegotiatedPacketVersion { get; set; }
123123

124124
/// <summary>
125125
/// Translates a boolean.
@@ -1006,7 +1006,7 @@ public TranslationDirection Mode
10061006
}
10071007

10081008
/// <inheritdoc/>
1009-
public byte NegotiatedPacketVersion { get; set; }
1009+
public byte? NegotiatedPacketVersion { get; set; }
10101010

10111011
/// <summary>
10121012
/// Translates a boolean.

src/Framework/ITranslator.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,12 @@ internal interface ITranslator : IDisposable
8484
/// from NodePacketTypeExtensions.PacketVersion when nodes are running different MSBuild versions.
8585
/// The negotiated version is used to conditionally serialize/deserialize fields that may
8686
/// not be supported by older packet versions.
87+
/// Special values:
88+
/// null: CLR2 (NET35) task host communication. Version-dependent fields are skipped because NET35 doesn't have them.
89+
/// 0: The constant value for Framework-to-Framework (CLR4) task host communication. Supports HostServices, TargetName, ProjectFile, and AppDomain.
90+
/// 2+: .NET task host communication with full support for version-dependent fields.
8791
/// </remarks>
88-
byte NegotiatedPacketVersion { get; set; }
92+
byte? NegotiatedPacketVersion { get; set; }
8993

9094
/// <summary>
9195
/// Returns the current serialization mode.

src/Shared/INodePacket.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -291,11 +291,9 @@ internal static class NodePacketTypeExtensions
291291
/// <summary>
292292
/// Defines the communication protocol version for node communication.
293293
///
294-
/// Version 1: Introduced for the .NET Task Host protocol. This version
295-
/// excludes the translation of appDomainConfig within TaskHostConfiguration
296-
/// to maintain backward compatibility and reduce serialization overhead.
297-
///
298-
/// Version 2: Adds support of HostServices and target name translation in TaskHostConfiguration.
294+
/// null: CLR2 (NET35) task host. Version-dependent fields skipped (not compiled in NET35).
295+
/// 0: The constant value for Framework-to-Framework (CLR4) task host. Supports HostServices, TargetName, ProjectFile.
296+
/// 2+: .NET task host with full support for version-dependent fields.
299297
///
300298
/// When incrementing this version, ensure compatibility with existing
301299
/// task hosts and update the corresponding deserialization logic.

src/Shared/NodeEndpointOutOfProcBase.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,8 @@ private void RunReadLoop(
721721
ITranslator readTranslator = BinaryTranslator.GetReadTranslator(localReadPipe, _sharedReadBuffer);
722722

723723
// parent sends a packet version that is already negotiated during handshake.
724+
// For Framework task hosts (CLR2/CLR4) without extended headers, defaults to 0.
725+
// For .NET task hosts, read from extended header (>= 1).
724726
readTranslator.NegotiatedPacketVersion = parentVersion;
725727
_packetFactory.DeserializeAndRoutePacket(0, packetType, readTranslator);
726728
}

src/Shared/TaskHostConfiguration.cs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -480,10 +480,10 @@ public void Translate(ITranslator translator)
480480
translator.TranslateCulture(ref _uiCulture);
481481
#if FEATURE_APPDOMAIN
482482
// The packet version is used to determine if the AppDomain configuration should be serialized.
483-
// If the packet version is bigger then 0, it means the task host will running under .NET.
484-
// Although MSBuild.exe runs under .NET Framework and has AppDomain support,
485-
// we don't transmit AppDomain config when communicating with dotnet.exe (it is not supported in .NET 5+).
486-
if (translator.NegotiatedPacketVersion == 0)
483+
// null = CLR2 (NET35) task host - supports AppDomain
484+
// 0 = CLR4 (NET472) task host - supports AppDomain
485+
// We serialize AppDomain for Framework task hosts (null or 0), but not for .NET (>= 2).
486+
if (translator.NegotiatedPacketVersion is null or 0)
487487
{
488488
byte[] appDomainConfigBytes = null;
489489

@@ -507,14 +507,17 @@ public void Translate(ITranslator translator)
507507
translator.Translate(ref _projectFileOfTask);
508508
translator.Translate(ref _taskName);
509509
translator.Translate(ref _taskLocation);
510-
if (translator.NegotiatedPacketVersion >= 2)
510+
511+
// null = CLR2 (NET35) task hosts which don't have these fields compiled in.
512+
// 0 = CLR4, 2+ = .NET - both support these fields.
513+
#if NET472 || NETCOREAPP
514+
if (translator.NegotiatedPacketVersion.HasValue && translator.NegotiatedPacketVersion is 0 or >= 2)
511515
{
512516
translator.Translate(ref _targetName);
513517
translator.Translate(ref _projectFile);
514-
#if !NET35
515518
translator.Translate(ref _hostServices);
516-
#endif
517519
}
520+
#endif
518521

519522
translator.Translate(ref _isTaskInputLoggingEnabled);
520523
translator.TranslateDictionary(ref _taskParameters, StringComparer.OrdinalIgnoreCase, TaskParameter.FactoryForDeserialization);

0 commit comments

Comments
 (0)