Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
67b110e
[release/6.0] Fixing a possible null reference error in WebSocket def…
github-actions[bot] Dec 23, 2021
3b71fd8
[release/6.0] Don't create multiple large files at the same time (#63…
jozkee Dec 31, 2021
816653e
[release/6.0] Use Ubuntu 18.04 and dotnet-buildtools-prereq docker im…
github-actions[bot] Jan 3, 2022
2282b00
[release/6.0] Add runtime-community.yml pipeline and add s390x job (#…
directhex Jan 3, 2022
6f1e03f
[release/6.0] Do not promote struct locals with holes (#62738)
github-actions[bot] Jan 3, 2022
7d82ac7
[wasm][release/6.0] Reduce number of calls to setTimer (#62705)
maraf Jan 3, 2022
bdd6647
fix issue where HTTP2 connection could be scavenged but not disposed …
github-actions[bot] Jan 3, 2022
45d1f9e
Update dependencies from https://github.com/dotnet/arcade build 20211…
dotnet-maestro[bot] Jan 3, 2022
f86caa5
[release/6.0] Fix build with Clang 13 (#63314)
janvorli Jan 4, 2022
51b6749
[release/6.0] bump sourcebuild leg timeout (#63298)
safern Jan 5, 2022
dc6a86d
Fix bug where we reference the entry #0 in the pinned plug queue (#60…
cshung Jan 6, 2022
4f01ff5
Fix named mutexes on OSX to work between arm64 and emulated x64 proce…
kouvel Jan 6, 2022
b71484c
Unify the FlushProcessWriteBuffers mechanism for macOS arm64 / x64 (#…
github-actions[bot] Jan 6, 2022
898f09a
[release/6.0] Change macOS activatin injection failure handling (#63393)
janvorli Jan 6, 2022
1c2501d
[release/6.0] Fix XXHash for stripe size (#61923)
github-actions[bot] Jan 6, 2022
25d2a1f
[release/6.0] Making user secrets optional by default (#62917)
github-actions[bot] Jan 6, 2022
201673a
[release/6.0] WinHttp: always read HTTP/2 streams to the end (#63346)
github-actions[bot] Jan 7, 2022
73f902f
[release/6.0] Fix setting timestamp on Windows on readonly files (#62…
adamsitnik Jan 7, 2022
8abc8fc
[release/6.0] Undo breaking change in 6.0 in environment variable con…
github-actions[bot] Jan 7, 2022
a8b733b
[release/6.0] Ensure UserSecretsIdAttribute is added to assembly (#63…
eerhardt Jan 7, 2022
d575a6f
[release/6.0] Add explicit null-check for tailcalls to VSD (#62769)
github-actions[bot] Jan 7, 2022
dc56b08
[release/6.0] Port test-only test fixes (#63507)
danmoseley Jan 7, 2022
abe7d08
[release/6.0] Fix System.Object serialization with custom number hand…
github-actions[bot] Jan 8, 2022
039ab90
Fix bugs with generation for ctor param default values (#62798) (#63493)
layomia Jan 8, 2022
5af5538
Suppress warnings about [Obsolete] member usage in JSON src-gen'd cod…
github-actions[bot] Jan 8, 2022
26b0a12
[release/6.0] Fix TimeSpan support in sourcegen (#62191)
github-actions[bot] Jan 8, 2022
a9723f3
Include properties on records for (de)serialization in source-gen (#6…
github-actions[bot] Jan 8, 2022
4d8bebc
[wasm] Backport build improvements, and fixes from #61581 (#62757)
radical Jan 8, 2022
dfcba66
disable tests unstable on Windows 11 (#63527)
github-actions[bot] Jan 8, 2022
a16c322
[release/6.0] Suppress SendPacketsElement_FileStreamMultiPartMixed_Mu…
github-actions[bot] Jan 8, 2022
749c02b
[release/6.0] Fix GENERIC_MATH_FEATURE by making sure we always choos…
safern Jan 10, 2022
7a26492
Fix NETStandard library using JSON source gen (#63520)
ericstj Jan 10, 2022
3f6d8fa
Make delegates unsupported by JsonSerializer (#63514)
github-actions[bot] Jan 10, 2022
04a5836
[release/6.0] 1388 xml serializer assembly load context awareness (#6…
github-actions[bot] Jan 10, 2022
7780d28
Fix custom JsonConverterFactories not working with transitive type/pr…
github-actions[bot] Jan 10, 2022
46d9a58
Merge branch 'release/6.0-maui' into merge/release/6.0-to-release/6.0…
akoeplinger Jan 12, 2022
7f6c36e
Disable GeneratePackageOnBuild
akoeplinger Jan 12, 2022
d24f93e
Update CompatibilitySuppressions.xml for System.Data.Odbc
akoeplinger Jan 12, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
[release/6.0] 1388 xml serializer assembly load context awareness (#6…
…1266)

* Generate dynamic serialization assembly in the appropriate ALC, and don't keep any hard refs to types that could prevent unloading.

* Add small test for ALC unloading.

* PR feedback; Move into TempAssembly; Strong/Weak lookup tables; Test refinement

* Refining TempAssembly cache; Reflection-based fix; Test corrections

* Mono/wasm test fixup

* Ensure that serializers from XmlMappings don't run afoul of collectible ALCs.

* PR feedback

* Unloadable contexts not yet supported in Mono.

* Fix trimming of types for XmlSerializer tests that got moved out of main test assembly.

* Encapsulating the duality of dealing with unloadable ALC instead of rewriting similar code everywhere.

* Missed new file in last commit.

* Compilation bug not seen locally.

* Perf improvement.

* Remove extraneous line. Test feedback.

* Fix unloadability (#58948)

There is a bug in AppDomain::FindAssembly code path that iterates over
the domain assemblies. The iteration loop leaves the refcount of the
LoaderAllocator related to the returned DomainAssembly bumped, but
nothing ever decrements it. So when a code that needs to be unloaded
ends up in that code path, all the managed things like managed
LoaderAllocator, LoaderAllocatorScout are destroyed, but the unloading
doesn't complete due to the refcount.

We have never found it before as this code path is never executed in any
of the coreclr tests even with unloadability testing option.

(cherry picked from commit 8b38c19)

Co-authored-by: Steve Molloy <[email protected]>
Co-authored-by: Jan Vorlicek <[email protected]>
  • Loading branch information
3 people authored Jan 10, 2022
commit 04a58365e6f997cb55c1ab534e5befdf502002e0
4 changes: 2 additions & 2 deletions src/coreclr/vm/appdomain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3533,8 +3533,8 @@ DomainAssembly * AppDomain::FindAssembly(PEAssembly * pFile, FindAssemblyOptions
!pManifestFile->IsResource() &&
pManifestFile->Equals(pFile))
{
// Caller already has PEAssembly, so we can give DomainAssembly away freely without AddRef
return pDomainAssembly.Extract();
// Caller already has PEAssembly, so we can give DomainAssembly away freely without added reference
return pDomainAssembly.GetValue();
}
}
return NULL;
Expand Down
29 changes: 29 additions & 0 deletions src/libraries/Common/tests/System/Runtime/Serialization/Utils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
using System.Threading.Tasks;
using System.Xml.Linq;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using Xunit;

internal static class Utils
Expand Down Expand Up @@ -351,3 +353,30 @@ private static bool IsPrefixedAttributeValue(string atrValue, out string localPr
return false;
}
}

internal class TestAssemblyLoadContext : AssemblyLoadContext
{
private AssemblyDependencyResolver _resolver;

public TestAssemblyLoadContext(string name, bool isCollectible, string mainAssemblyToLoadPath = null) : base(name, isCollectible)
{
if (!PlatformDetection.IsBrowser)
_resolver = new AssemblyDependencyResolver(mainAssemblyToLoadPath ?? Assembly.GetExecutingAssembly().Location);
}

protected override Assembly Load(AssemblyName name)
{
if (PlatformDetection.IsBrowser)
{
return base.Load(name);
}

string assemblyPath = _resolver.ResolveAssemblyToPath(name);
if (assemblyPath != null)
{
return LoadFromAssemblyPath(assemblyPath);
}

return null;
}
}
3 changes: 3 additions & 0 deletions src/libraries/System.Private.Xml/src/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -2787,6 +2787,9 @@
<data name="XmlNotSerializable" xml:space="preserve">
<value>Type '{0}' is not serializable.</value>
</data>
<data name="XmlTypeInBadLoadContext" xml:space="preserve">
<value>Type '{0}' is from an AssemblyLoadContext which is incompatible with that which contains this XmlSerializer.</value>
</data>
<data name="XmlPregenInvalidXmlSerializerAssemblyAttribute" xml:space="preserve">
<value>Invalid XmlSerializerAssemblyAttribute usage. Please use {0} property or {1} property.</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,7 @@
<Compile Include="System\Xml\Serialization\CodeIdentifiers.cs" />
<Compile Include="System\Xml\Serialization\Compilation.cs" />
<Compile Include="System\Xml\Serialization\Compiler.cs" />
<Compile Include="System\Xml\Serialization\ContextAwareTables.cs" />
<Compile Include="System\Xml\Serialization\ImportContext.cs" />
<Compile Include="System\Xml\Serialization\indentedWriter.cs" />
<Compile Include="System\Xml\Serialization\IXmlSerializable.cs" />
Expand Down Expand Up @@ -565,6 +566,7 @@
<Reference Include="System.Runtime.CompilerServices.Unsafe" />
<Reference Include="System.Runtime.Extensions" />
<Reference Include="System.Runtime.InteropServices" />
<Reference Include="System.Runtime.Loader" />
<Reference Include="System.Security.Cryptography.Algorithms" />
<Reference Include="System.Security.Cryptography.Primitives" />
<Reference Include="System.Text.Encoding.Extensions" />
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace System.Xml.Serialization
{
using System;
using System.Collections;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.Loader;

internal class ContextAwareTables<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]T> where T : class?
{
private Hashtable _defaultTable;
private ConditionalWeakTable<Type, T> _collectibleTable;

public ContextAwareTables()
{
_defaultTable = new Hashtable();
_collectibleTable = new ConditionalWeakTable<Type, T>();
}

internal T GetOrCreateValue(Type t, Func<T> f)
{
// The fast and most common default case
T? ret = (T?)_defaultTable[t];
if (ret != null)
return ret;

// Common case for collectible contexts
if (_collectibleTable.TryGetValue(t, out ret))
return ret;

// Not found. Do the slower work of creating the value in the correct collection.
AssemblyLoadContext? alc = AssemblyLoadContext.GetLoadContext(t.Assembly);

// Null and non-collectible load contexts use the default table
if (alc == null || !alc.IsCollectible)
{
lock (_defaultTable)
{
if ((ret = (T?)_defaultTable[t]) == null)
{
ret = f();
_defaultTable[t] = ret;
}
}
}

// Collectible load contexts should use the ConditionalWeakTable so they can be unloaded
else
{
lock (_collectibleTable)
{
if (!_collectibleTable.TryGetValue(t, out ret))
{
ret = f();
_collectibleTable.AddOrUpdate(t, ret);
}
}
}

return ret;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -627,40 +627,48 @@ private static void AddObjectsIntoTargetCollection(object targetCollection, List
}
}

private static readonly ConcurrentDictionary<(Type, string), ReflectionXmlSerializationReaderHelper.SetMemberValueDelegate> s_setMemberValueDelegateCache = new ConcurrentDictionary<(Type, string), ReflectionXmlSerializationReaderHelper.SetMemberValueDelegate>();
private static readonly ContextAwareTables<Hashtable> s_setMemberValueDelegateCache = new ContextAwareTables<Hashtable>();

[RequiresUnreferencedCode(XmlSerializer.TrimSerializationWarning)]
private static ReflectionXmlSerializationReaderHelper.SetMemberValueDelegate GetSetMemberValueDelegate(object o, string memberName)
{
Debug.Assert(o != null, "Object o should not be null");
Debug.Assert(!string.IsNullOrEmpty(memberName), "memberName must have a value");
(Type, string) typeMemberNameTuple = (o.GetType(), memberName);
if (!s_setMemberValueDelegateCache.TryGetValue(typeMemberNameTuple, out ReflectionXmlSerializationReaderHelper.SetMemberValueDelegate? result))
Type type = o.GetType();
var delegateCacheForType = s_setMemberValueDelegateCache.GetOrCreateValue(type, () => new Hashtable());
var result = delegateCacheForType[memberName];
if (result == null)
{
MemberInfo memberInfo = ReflectionXmlSerializationHelper.GetEffectiveSetInfo(o.GetType(), memberName);
Debug.Assert(memberInfo != null, "memberInfo could not be retrieved");
Type memberType;
if (memberInfo is PropertyInfo propInfo)
{
memberType = propInfo.PropertyType;
}
else if (memberInfo is FieldInfo fieldInfo)
{
memberType = fieldInfo.FieldType;
}
else
lock (delegateCacheForType)
{
throw new InvalidOperationException(SR.XmlInternalError);
}
if ((result = delegateCacheForType[memberName]) == null)
{
MemberInfo memberInfo = ReflectionXmlSerializationHelper.GetEffectiveSetInfo(o.GetType(), memberName);
Debug.Assert(memberInfo != null, "memberInfo could not be retrieved");
Type memberType;
if (memberInfo is PropertyInfo propInfo)
{
memberType = propInfo.PropertyType;
}
else if (memberInfo is FieldInfo fieldInfo)
{
memberType = fieldInfo.FieldType;
}
else
{
throw new InvalidOperationException(SR.XmlInternalError);
}

MethodInfo getSetMemberValueDelegateWithTypeGenericMi = typeof(ReflectionXmlSerializationReaderHelper).GetMethod("GetSetMemberValueDelegateWithType", BindingFlags.Static | BindingFlags.Public)!;
MethodInfo getSetMemberValueDelegateWithTypeMi = getSetMemberValueDelegateWithTypeGenericMi.MakeGenericMethod(o.GetType(), memberType);
var getSetMemberValueDelegateWithType = (Func<MemberInfo, ReflectionXmlSerializationReaderHelper.SetMemberValueDelegate>)getSetMemberValueDelegateWithTypeMi.CreateDelegate(typeof(Func<MemberInfo, ReflectionXmlSerializationReaderHelper.SetMemberValueDelegate>));
result = getSetMemberValueDelegateWithType(memberInfo);
s_setMemberValueDelegateCache.TryAdd(typeMemberNameTuple, result);
MethodInfo getSetMemberValueDelegateWithTypeGenericMi = typeof(ReflectionXmlSerializationReaderHelper).GetMethod("GetSetMemberValueDelegateWithType", BindingFlags.Static | BindingFlags.Public)!;
MethodInfo getSetMemberValueDelegateWithTypeMi = getSetMemberValueDelegateWithTypeGenericMi.MakeGenericMethod(o.GetType(), memberType);
var getSetMemberValueDelegateWithType = (Func<MemberInfo, ReflectionXmlSerializationReaderHelper.SetMemberValueDelegate>)getSetMemberValueDelegateWithTypeMi.CreateDelegate(typeof(Func<MemberInfo, ReflectionXmlSerializationReaderHelper.SetMemberValueDelegate>));
result = getSetMemberValueDelegateWithType(memberInfo);
delegateCacheForType[memberName] = result;
}
}
}

return result;
return (ReflectionXmlSerializationReaderHelper.SetMemberValueDelegate)result;
}

private object? GetMemberValue(object o, MemberInfo memberInfo)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ namespace System.Xml.Serialization
using System.Xml.Serialization;
using System.Xml;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;

///<internalonly/>
public abstract class XmlSerializationWriter : XmlSerializationGeneratedCode
Expand Down Expand Up @@ -1465,14 +1466,13 @@ internal static class DynamicAssemblies
{
private static readonly Hashtable s_nameToAssemblyMap = new Hashtable();
private static readonly Hashtable s_assemblyToNameMap = new Hashtable();
private static readonly Hashtable s_tableIsTypeDynamic = Hashtable.Synchronized(new Hashtable());
private static readonly ContextAwareTables<object> s_tableIsTypeDynamic = new ContextAwareTables<object>();

// SxS: This method does not take any resource name and does not expose any resources to the caller.
// It's OK to suppress the SxS warning.
internal static bool IsTypeDynamic(Type type)
{
object? oIsTypeDynamic = s_tableIsTypeDynamic[type];
if (oIsTypeDynamic == null)
object oIsTypeDynamic = s_tableIsTypeDynamic.GetOrCreateValue(type, () =>
{
Assembly assembly = type.Assembly;
bool isTypeDynamic = assembly.IsDynamic /*|| string.IsNullOrEmpty(assembly.Location)*/;
Expand Down Expand Up @@ -1500,8 +1500,8 @@ internal static bool IsTypeDynamic(Type type)
}
}
}
s_tableIsTypeDynamic[type] = oIsTypeDynamic = isTypeDynamic;
}
return isTypeDynamic;
});
return (bool)oIsTypeDynamic;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Loader;
using System.Runtime.Versioning;
using System.Security;
using System.Text;
Expand Down Expand Up @@ -161,8 +162,7 @@ private static XmlSerializerNamespaces DefaultNamespaces
internal const string TrimSerializationWarning = "Members from serialized types may be trimmed if not referenced directly";
private const string TrimDeserializationWarning = "Members from deserialized types may be trimmed if not referenced directly";

private static readonly Dictionary<Type, Dictionary<XmlSerializerMappingKey, XmlSerializer>> s_xmlSerializerTable = new Dictionary<Type, Dictionary<XmlSerializerMappingKey, XmlSerializer>>();

private static readonly ContextAwareTables<Dictionary<XmlSerializerMappingKey, XmlSerializer>> s_xmlSerializerTable = new ContextAwareTables<Dictionary<XmlSerializerMappingKey, XmlSerializer>>();
protected XmlSerializer()
{
}
Expand Down Expand Up @@ -235,30 +235,28 @@ public XmlSerializer(Type type, string? defaultNamespace)
_tempAssembly = s_cache[defaultNamespace, type];
if (_tempAssembly == null)
{
XmlSerializerImplementation? contract = null;
Assembly? assembly = TempAssembly.LoadGeneratedAssembly(type, defaultNamespace, out contract);
if (assembly == null)
{
XmlSerializerImplementation? contract = null;
Assembly? assembly = TempAssembly.LoadGeneratedAssembly(type, defaultNamespace, out contract);
if (assembly == null)
{
if (Mode == SerializationMode.PreGenOnly)
{
AssemblyName name = type.Assembly.GetName();
var serializerName = Compiler.GetTempAssemblyName(name, defaultNamespace);
throw new FileLoadException(SR.Format(SR.FailLoadAssemblyUnderPregenMode, serializerName));
}

// need to reflect and generate new serialization assembly
XmlReflectionImporter importer = new XmlReflectionImporter(defaultNamespace);
_mapping = importer.ImportTypeMapping(type, null, defaultNamespace);
_tempAssembly = GenerateTempAssembly(_mapping, type, defaultNamespace)!;
}
else
if (Mode == SerializationMode.PreGenOnly)
{
// we found the pre-generated assembly, now make sure that the assembly has the right serializer
// try to avoid the reflection step, need to get ElementName, namespace and the Key form the type
_mapping = XmlReflectionImporter.GetTopLevelMapping(type, defaultNamespace);
_tempAssembly = new TempAssembly(new XmlMapping[] { _mapping }, assembly, contract);
AssemblyName name = type.Assembly.GetName();
var serializerName = Compiler.GetTempAssemblyName(name, defaultNamespace);
throw new FileLoadException(SR.Format(SR.FailLoadAssemblyUnderPregenMode, serializerName));
}

// need to reflect and generate new serialization assembly
XmlReflectionImporter importer = new XmlReflectionImporter(defaultNamespace);
_mapping = importer.ImportTypeMapping(type, null, defaultNamespace);
_tempAssembly = GenerateTempAssembly(_mapping, type, defaultNamespace)!;
}
else
{
// we found the pre-generated assembly, now make sure that the assembly has the right serializer
// try to avoid the reflection step, need to get ElementName, namespace and the Key form the type
_mapping = XmlReflectionImporter.GetTopLevelMapping(type, defaultNamespace);
_tempAssembly = new TempAssembly(new XmlMapping[] { _mapping }, assembly, contract);
}
}
s_cache.Add(defaultNamespace, type, _tempAssembly);
Expand Down Expand Up @@ -403,7 +401,9 @@ public void Serialize(XmlWriter xmlWriter, object? o, XmlSerializerNamespaces? n
}
}
else
{
_tempAssembly.InvokeWriter(_mapping, xmlWriter, o, namespaces == null || namespaces.Count == 0 ? DefaultNamespaces : namespaces, encodingStyle, id);
}
}
catch (Exception? e)
{
Expand Down Expand Up @@ -629,7 +629,10 @@ public static XmlSerializer[] FromMappings(XmlMapping[]? mappings, Type? type)
{
XmlSerializer[] serializers = new XmlSerializer[mappings.Length];
for (int i = 0; i < serializers.Length; i++)
{
serializers[i] = (XmlSerializer)contract!.TypedSerializers[mappings[i].Key!]!;
TempAssembly.VerifyLoadContext(serializers[i]._rootType, type!.Assembly);
}
return serializers;
}
}
Expand Down Expand Up @@ -696,16 +699,9 @@ internal static bool GenerateSerializer(Type[]? types, XmlMapping[] mappings, St
private static XmlSerializer[] GetSerializersFromCache(XmlMapping[] mappings, Type type)
{
XmlSerializer?[] serializers = new XmlSerializer?[mappings.Length];

Dictionary<XmlSerializerMappingKey, XmlSerializer>? typedMappingTable = null;
lock (s_xmlSerializerTable)
{
if (!s_xmlSerializerTable.TryGetValue(type, out typedMappingTable))
{
typedMappingTable = new Dictionary<XmlSerializerMappingKey, XmlSerializer>();
s_xmlSerializerTable[type] = typedMappingTable;
}
}

typedMappingTable = s_xmlSerializerTable.GetOrCreateValue(type, () => new Dictionary<XmlSerializerMappingKey, XmlSerializer>());

lock (typedMappingTable)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@
<DefineConstants>$(DefineConstants);ReflectionOnly</DefineConstants>
<TargetFrameworks>$(NetCoreAppCurrent)</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\Microsoft.XmlSerializer.Generator\tests\SerializableAssembly.csproj" />
<TrimmerRootAssembly Include="SerializableAssembly" />
</ItemGroup>
<ItemGroup>
<Compile Include="$(CommonTestPath)System\Runtime\Serialization\Utils.cs" />
<Compile Include="$(TestSourceFolder)..\..\..\..\System.Runtime.Serialization.Xml\tests\SerializationTypes.cs" />
<None Include="$(TestSourceFolder)..\..\..\..\System.Runtime.Serialization.Xml\tests\SerializationTypes.cs" />
<Compile Include="$(TestSourceFolder)..\..\..\..\System.Runtime.Serialization.Xml\tests\SerializationTypes.RuntimeOnly.cs" />
<Compile Include="$(TestSourceFolder)..\XmlSerializerTests.cs" />
<Compile Include="$(TestSourceFolder)..\XmlSerializerTests.RuntimeOnly.cs" />
Expand Down
Loading