Guard MarshalByRefObject, [Serializable], and InitializeLifetimeService behind #if NETFRAMEWORK#8174
Guard MarshalByRefObject, [Serializable], and InitializeLifetimeService behind #if NETFRAMEWORK#8174Evangelink wants to merge 3 commits into
Conversation
…ce behind #if NETFRAMEWORK - Make all MarshalByRefObject inheritance conditional on NETFRAMEWORK across 10 classes - Wrap InitializeLifetimeService overrides and [SecurityCritical] in #if NETFRAMEWORK - Guard [Serializable] with #if NETFRAMEWORK on 11 non-exception data types - Conditionally include 'using System.Security' only for NETFRAMEWORK - Exception types retain [Serializable] unconditionally (standard .NET convention) On modern .NET (net8.0/net9.0), these classes are now plain types with no remoting or BinaryFormatter baggage. On net462, the full AppDomain marshaling support is preserved.
There was a problem hiding this comment.
Pull request overview
This PR scopes .NET Framework remoting/serialization artifacts (MarshalByRefObject, [Serializable], and InitializeLifetimeService) to #if NETFRAMEWORK, keeping AppDomain marshaling behavior on net462 while removing remoting-related baggage from modern .NET builds.
Changes:
- Guarded
MarshalByRefObjectinheritance andInitializeLifetimeService()overrides behind#if NETFRAMEWORK. - Guarded
[Serializable]on non-exception transport/data types behind#if NETFRAMEWORK. - Conditionally included
using System.Security;only where[SecurityCritical]is compiled to avoid unused-using warnings.
Show a summary per file
| File | Description |
|---|---|
| src/TestFramework/TestFramework/Attributes/TestMethod/TestResult.cs | Makes TestResult [Serializable] only on .NET Framework. |
| src/Adapter/MSTestAdapter.PlatformServices/RecursiveDirectoryPath.cs | Guards [Serializable], MarshalByRefObject, InitializeLifetimeService, and System.Security usage to .NET Framework. |
| src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/UnitTestElement.cs | Guards [Serializable] to .NET Framework. |
| src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/TestMethod.cs | Guards [Serializable] to .NET Framework. |
| src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/TestAssemblySettings.cs | Guards [Serializable] to .NET Framework. |
| src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/StackTraceInformation.cs | Guards [Serializable] to .NET Framework. |
| src/Adapter/MSTestAdapter.PlatformServices/NopTraceLogger.cs | Makes MarshalByRefObject base conditional for .NET Framework remoting. |
| src/Adapter/MSTestAdapter.PlatformServices/MSTestSettings.cs | Guards [Serializable] to .NET Framework. |
| src/Adapter/MSTestAdapter.PlatformServices/Helpers/ReflectHelper.cs | Makes MarshalByRefObject/InitializeLifetimeService and System.Security usage conditional on .NET Framework. |
| src/Adapter/MSTestAdapter.PlatformServices/Execution/UnitTestRunner.cs | Makes MarshalByRefObject/InitializeLifetimeService and System.Security usage conditional on .NET Framework. |
| src/Adapter/MSTestAdapter.PlatformServices/Execution/TypeCache.cs | Makes MarshalByRefObject/InitializeLifetimeService and System.Security usage conditional on .NET Framework. |
| src/Adapter/MSTestAdapter.PlatformServices/Execution/TestExecutionManager.cs | Makes nested RemotingMessageLogger inherit MarshalByRefObject only on .NET Framework. |
| src/Adapter/MSTestAdapter.PlatformServices/Execution/TestAssemblySettingsProvider.cs | Makes MarshalByRefObject/InitializeLifetimeService and System.Security usage conditional on .NET Framework. |
| src/Adapter/MSTestAdapter.PlatformServices/Discovery/AssemblyEnumerator.cs | Makes MarshalByRefObject/InitializeLifetimeService and System.Security usage conditional on .NET Framework. |
| src/Adapter/MSTestAdapter.PlatformServices/Discovery/AssemblyEnumerationResult.cs | Guards [Serializable] to .NET Framework. |
| src/Adapter/MSTestAdapter.PlatformServices/Deployment/TestRunDirectories.cs | Guards [Serializable] to .NET Framework. |
| src/Adapter/MSTestAdapter.PlatformServices/Deployment/DeploymentItem.cs | Guards [Serializable] on enum and class to .NET Framework. |
| src/Adapter/MSTest.TestAdapter/VSTestAdapter/EqtTraceLogger.cs | Makes MarshalByRefObject base conditional for .NET Framework remoting. |
| src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MTPTraceLogger.cs | Makes MarshalByRefObject base conditional for .NET Framework remoting. |
Copilot's findings
- Files reviewed: 19/19 changed files
- Comments generated: 0
| #if NETFRAMEWORK | ||
| [Serializable] | ||
| #endif |
There was a problem hiding this comment.
Consider reverting and keep the changes only in Adapter, or at least have this under #if NETFRAMEWORK || NETSTANDARD to be safe. I would be worried if TestFramework netstandard assemblies end up getting loaded in a .NET Framework process where Serializable will be needed.
Under adapter, we no longer target .NET Standard so we are pretty safe there.
There was a problem hiding this comment.
Actually better to simply just revert in this case.
This is a public class and we might not know what users are doing with it.
|
@copilot resolve the merge conflicts in this pull request |
Co-authored-by: Evangelink <11340282+Evangelink@users.noreply.github.com>
Resolved. The only conflict was in |
Removing [Serializable] for non-NETFRAMEWORK exposed an IDE0032 false positive on s_currentSettings/s_runConfigurationSettings, whose backing properties use '??=' lazy initialization (not expressible as an auto-property). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
| return ResolveTestMethodInfoForDiscovery(testMethod, testClassInfo); | ||
| } | ||
|
|
||
| #if NETFRAMEWORK |
| #if NET5_0_OR_GREATER | ||
| [Obsolete("MarshalByRefObject.InitializeLifetimeService is obsolete in .NET 5+. This override is required to maintain infinite lifetime service.")] | ||
| #endif | ||
| public override object InitializeLifetimeService() => null!; |
|
|
||
| /// <summary> | ||
| /// Member variable for RunConfiguration settings. | ||
| /// </summary> | ||
| private static RunConfigurationSettings? s_runConfigurationSettings; | ||
| #pragma warning restore IDE0032 |
| #pragma warning disable IDE0032 // Use auto property — property uses lazy '??=' initialization, which cannot be expressed as an auto-property. | ||
| private static MSTestSettings? s_currentSettings; | ||
|
|
||
| /// <summary> | ||
| /// Member variable for RunConfiguration settings. | ||
| /// </summary> | ||
| private static RunConfigurationSettings? s_runConfigurationSettings; | ||
| #pragma warning restore IDE0032 |
| /// <summary> | ||
| /// Member variable for Adapter settings. | ||
| /// </summary> | ||
| #pragma warning disable IDE0032 // Use auto property — property uses lazy '??=' initialization, which cannot be expressed as an auto-property. |
There was a problem hiding this comment.
This suppression is not correct. You can use field keyword.
Summary
Audit and clean up
MarshalByRefObjectand[Serializable]usage acrosssrc/to ensure these .NET Framework remoting artifacts are properly scoped tonet462only.Changes
MarshalByRefObjectinheritance (10 classes)Made all
MarshalByRefObjectbase class inheritance conditional on#if NETFRAMEWORK:Classes with only MarshalByRefObject as base (6):
AssemblyEnumerator,ReflectHelper,RecursiveDirectoryPath,UnitTestRunner,TypeCache,TestAssemblySettingsProviderClasses implementing MarshalByRefObject + an interface (4):
RemotingMessageLogger,NopTraceLogger,EqtTraceLogger,MTPTraceLoggerInitializeLifetimeServiceoverrides (6 methods)Wrapped all
InitializeLifetimeService()overrides (including[SecurityCritical]and the previous[Obsolete]attributes) entirely in#if NETFRAMEWORK. Onnet462, the override returnsnullfor infinite lifetime. On modern .NET, the override doesn't exist since the base class is no longerMarshalByRefObject.Also conditionally included
using System.Security;to avoid IDE0005 warnings.[Serializable]attribute (11 non-exception types)Guarded
[Serializable]with#if NETFRAMEWORKon data types that only needed it forBinaryFormattermarshaling across AppDomain boundaries:RecursiveDirectoryPath,UnitTestElement,TestMethod,TestAssemblySettings,StackTraceInformation,MSTestSettings,AssemblyEnumerationResult,TestRunDirectories,DeploymentItem,DeploymentItemOriginType,TestResultException types (
AssertFailedException,UnitTestAssertException, etc.) intentionally retain[Serializable]unconditionally — this is a standard .NET convention for exceptions.Already correctly guarded (no changes needed)
These were already behind
#if NETFRAMEWORK:AssemblyLoadWorker,StaticStateHelper(inAppDomainUtilities.cs),AssemblyResolver(conditional base class)AppDomain.CreateDomain/Unloadcalls inAppDomainUtilities.cs,AppDomainWrapper.cs,IAppDomain.cs,TestSourceHost.csResult
On modern .NET (
net8.0/net9.0), these classes are now plain types with no remoting orBinaryFormatterbaggage. Onnet462, the full AppDomain marshaling support is preserved.Validation
dotnet buildnet9.0 — 0 warnings, 0 errorsdotnet buildnet462 — 0 warnings, 0 errorsdotnet buildMSTest.TestAdapter net9.0 — 0 warnings, 0 errorsdotnet buildTestFramework net9.0 — 0 warnings, 0 errors