Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AssemblyLoadContext crash when collectible assembly use XmlSerializer #1388

Closed
uffebjorklund opened this issue Sep 24, 2019 · 55 comments · Fixed by #58932
Closed

AssemblyLoadContext crash when collectible assembly use XmlSerializer #1388

uffebjorklund opened this issue Sep 24, 2019 · 55 comments · Fixed by #58932
Assignees
Milestone

Comments

@uffebjorklund
Copy link

[EDIT]
Investigation of this issue is complete and has resulted in 5 additional issues being opened.
See this comment below for links to each of those issues.

We will keep this issue open and update it as those other issues are fixed.
Please add any additional comments to those issues.


When creating a collectible AssemblyLoadContext and then use System.Xml.Serialization.XmlSerializer inside of a collectible assembly you will get a crash.

I have a repro project: https://github.com/uffebjorklund/AssemblyLoadContextBug

Have tried a few different things

  • If creating the ALC as collectible = false there is no crash
  • If the XmlSerializer code is removed from the collectible assembly there is no crash
  • The crash will occur regardless of using netstandard2.0 or netstandard2.1 on the collectible assembly

Exception

A non-collectible assembly may not reference a collectible assembly

Stacktrace

at System.Reflection.Emit.ModuleBuilder.GetTypeRef(QCallModule module, String strFullName, QCallModule refedModule, String strRefedModuleFileName, Int32 tkResolution)
at System.Reflection.Emit.ModuleBuilder.GetTypeRefNested(Type type, Module refedModule, String strRefedModuleFileName)
at System.Reflection.Emit.ModuleBuilder.GetTypeTokenWorkerNoLock(Type type, Boolean getGenericDefinition)
at System.Reflection.Emit.ModuleBuilder.GetTypeTokenInternal(Type type, Boolean getGenericDefinition)
at System.Reflection.Emit.ILGenerator.Emit(OpCode opcode, Type cls)
at System.Xml.Serialization.CodeGenerator.Castclass(Type target)
at System.Xml.Serialization.CodeGenerator.InternalConvert(Type source, Type target, Boolean isAddress)
at System.Xml.Serialization.SourceInfo.InternalLoad(Type elementType, Boolean asAddress)
at System.Xml.Serialization.XmlSerializationWriterILGen.WriteElement(SourceInfo source, ElementAccessor element, String arrayName, Boolean writeAccessor)
at System.Xml.Serialization.XmlSerializationWriterILGen.WriteElements(SourceInfo source, String enumSource, ElementAccessor[] elements, TextAccessor text, ChoiceIdentifierAccessor choice, String arrayName, Boolean writeAccessors, Boolean isNullable)
at System.Xml.Serialization.XmlSerializationWriterILGen.WriteMember(SourceInfo source, String choiceSource, ElementAccessor[] elements, TextAccessor text, ChoiceIdentifierAccessor choice, TypeDesc memberTypeDesc, Boolean writeAccessors)
at System.Xml.Serialization.XmlSerializationWriterILGen.GenerateTypeElement(XmlTypeMapping xmlTypeMapping)
at System.Xml.Serialization.XmlSerializationWriterILGen.GenerateElement(XmlMapping xmlMapping)
at System.Xml.Serialization.TempAssembly.GenerateRefEmitAssembly(XmlMapping[] xmlMappings, Type[] types, String defaultNamespace)
at System.Xml.Serialization.TempAssembly..ctor(XmlMapping[] xmlMappings, Type[] types, String defaultNamespace, String location)
at System.Xml.Serialization.XmlSerializer.GenerateTempAssembly(XmlMapping xmlMapping, Type type, String defaultNamespace, String location)
at System.Xml.Serialization.XmlSerializer..ctor(Type type, String defaultNamespace)

dotnet --info

.NET Core SDK (reflecting any global.json):
 Version:   3.0.100
 Commit:    04339c3a26

Runtime Environment:
 OS Name:     Mac OS X
 OS Version:  10.13
 OS Platform: Darwin
 RID:         osx.10.13-x64
 Base Path:   /usr/local/share/dotnet/sdk/3.0.100/

Host (useful for support):
  Version: 3.0.0
  Commit:  7d57652f33

.NET Core SDKs installed:
  2.1.301 [/usr/local/share/dotnet/sdk]
  2.1.302 [/usr/local/share/dotnet/sdk]
  2.1.400 [/usr/local/share/dotnet/sdk]
  2.1.401 [/usr/local/share/dotnet/sdk]
  2.1.403 [/usr/local/share/dotnet/sdk]
  2.1.500 [/usr/local/share/dotnet/sdk]
  2.2.100-preview3-009430 [/usr/local/share/dotnet/sdk]
  2.2.101 [/usr/local/share/dotnet/sdk]
  2.2.102 [/usr/local/share/dotnet/sdk]
  2.2.103 [/usr/local/share/dotnet/sdk]
  2.2.105 [/usr/local/share/dotnet/sdk]
  2.2.106 [/usr/local/share/dotnet/sdk]
  2.2.203 [/usr/local/share/dotnet/sdk]
  2.2.300 [/usr/local/share/dotnet/sdk]
  3.0.100-alpha1-009708 [/usr/local/share/dotnet/sdk]
  3.0.100-preview-010184 [/usr/local/share/dotnet/sdk]
  3.0.100-preview3-010431 [/usr/local/share/dotnet/sdk]
  3.0.100-preview8-013656 [/usr/local/share/dotnet/sdk]
  3.0.100-preview9-014004 [/usr/local/share/dotnet/sdk]
  3.0.100 [/usr/local/share/dotnet/sdk]

.NET Core runtimes installed:
  Microsoft.AspNetCore.All 2.1.1 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.2 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.3 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.5 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.6 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.2.0-preview3-35497 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.2.0 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.2.1 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.2.3 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.2.4 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 3.0.0-alpha1-10062 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.App 2.1.1 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.2 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.3 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.5 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.6 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.2.0-preview3-35497 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.2.0 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.2.1 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.2.3 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.2.4 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.0.0-alpha1-10062 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.0.0-preview-19075-0444 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.0.0-preview3-19153-02 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.0.0-preview8.19405.7 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.0.0-preview9.19424.4 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.0.0 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 2.1.1 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.2 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.3 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.6 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.2.0-preview3-27014-02 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.2.0 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.2.1 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.2.3 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.2.4 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.0.0-preview-27324-5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.0.0-preview1-27029-03 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.0.0-preview3-27503-5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.0.0-preview9-19423-09 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.0.0 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
@jkotas jkotas transferred this issue from dotnet/coreclr Sep 24, 2019
@csalat
Copy link

csalat commented Oct 4, 2019

Hello,

Is any update on this?

Thanks,
Csaba

@StephenBonikowsky
Copy link
Member

@uffebjorklund Thanks for reporting this, sorry for the slow response. It looks like all the information we need to do further investigation is here. We will look into it.

@mconnew
Copy link
Member

mconnew commented Nov 22, 2019

I did a bit of digging in to this and I believe that the problem is due to XmlSerializer creating a dynamic assembly in the default load context which makes the dynamic assembly non-collectible. When we call ILGenerator.Emit(OpCodes.Castclass, type) with a type which is a collectible assembly, we get an exception. I did some digging around the api's and I can't see a way to specify the AssemblyLoadContext to generate a dynamic assembly into.
@sdmaclea, is this scenario supported? If so, can you point me to the api's to create a dynamic assembly in a specific AssemblyLoadContext?

@sdmaclea
Copy link
Contributor

@sdmaclea, is this scenario supported? If so, can you point me to the api's to create a dynamic assembly in a specific AssemblyLoadContext?

@mconnew I think this was a feature we missed in 3.0. There is an API proposal to close this gap dotnet/corefx#38426

/cc @vitek-karas @elinor-fung @jeffschwMSFT

@curia-damiano
Copy link

Hi,
I share the same supposition, that it can be because of the dynamic generated assemblies.
But: I have tried using the XmlSerializerGenerator, with the idea that it wouldn't generated dynamic assemblies anymore.
But still I can't make it to work, see attached solution.
Do I miss anything?!?
Test_ALC with XmlSerializerGenerator.zip

@curia-damiano
Copy link

Btw this was my first project with the issue, without the XmlSerializerGenerator
Test_ALC.zip

@vitek-karas
Copy link
Member

@curia-damiano How do you generate the serialization code? I tried to turning it on via VS on the CL.Implementation.Problem assembly and that failed (which is probably an issue on its own, but not directly related to this issue).

Also - I noticed that your "plugins" are built as netstandard2.0 - this is not recommended as SDK will not always produce the right assets. Ideally plugins should not target a standard but a specific framework - for example netcoreapp3.1 or so.

@curia-damiano
Copy link

Hi,
I have a ItemGroup in the project that "should" invoke the generation of the serialization code during build time. I haven't found any additional documentation saying I should do something more.
FYI I have used VS 2019 Preview (16.4.0 Preview 5 or 6).

@vitek-karas
Copy link
Member

I tried again - Release build this time - and I spotted this in the output of the build:

3>Method 'System.Xml.Serialization.XmlSerializer.GenerateSerializer' was not found. This is likely because you are using an older version of the framework. Please update to .NET Core v2.1 or later.
3>Sgen utility failed to pregenerate serialization code for E:\AppModel\repro\Test_ALC\CL.Implementation.Problem\obj\Release\netstandard2.0\CL.Implementation.Problem.dll.

@StephenMolloy for the XML serializer specific portions of this question, like the above failure of sgen.

@mconnew
Copy link
Member

mconnew commented Nov 25, 2019

@curia-damiano, I haven't tried running your code yet but I can see a problem in Test_ALC with XmlSerializerGenerator.zip. This is the problem code:

	var assembly = TLC.LoadFromAssemblyPath(dllPath);
	labelUnloaded.Text = "Loaded";
	var type = assembly.GetType("CL.Implementation.Easy.Multiplier");
	var constructor = type.GetConstructor(new Type[] { });
	ICompute compute = (ICompute)constructor.Invoke(new object[] { });

When using a different AssemblyLoadContext, the same type in the same assembly is a different runtime type. So this means the ICompute interface that CL.Implementation.Easy.Multiplier implements is a different runtime type that the same interface in the default load context. So the cast on the last line will fail.

@mconnew
Copy link
Member

mconnew commented Nov 25, 2019

@sdmaclea, in this comment it says it uses the callers AssemblyLoadContext. You can see here that we do use AssemblyBuilder.DefineDynamicAssembly so I would expect the dynamically created assembly to use the custom AssemblyLoadContext. Is the problem that we pass AssemblyBuilderAccess.Run instead of AssemblyBuilderAccess.RunAndCollect? What's stopping the dynamically generated assembly from being created in the correct context? Also, is this going to be a problem for DispatchProxy too?

@sdmaclea
Copy link
Contributor

sdmaclea commented Nov 25, 2019

@sdmaclea, in this https://github.com/dotnet/corefx/issues/38426#issuecomment-500723986 it says it uses the callers AssemblyLoadContext. You can see https://github.com/dotnet/corefx/blob/e99ec129cfd594d53f4390bf97d1d736cff6f860/src/System.Private.Xml/src/System/Xml/Serialization/CodeGenerator.cs#L1297 that we do use AssemblyBuilder.DefineDynamicAssembly so I would expect the dynamically created assembly to use the custom AssemblyLoadContext.

@mconnew Looking at the link. It looks like System.Xml.Serialization.CodeGenerator.CreateAssemblyBuilder is the caller of AssemblyBuilder.DefineDynamicAssembly so the dynamic assembly would be created in the default ALC, where the CoreFX runtime is loaded.

@sdmaclea
Copy link
Contributor

sdmaclea commented Nov 25, 2019

When using a different AssemblyLoadContext, the same type in the same assembly is a different runtime type. So this means the ICompute interface that CL.Implementation.Easy.Multiplier implements is a different runtime type that the same interface in the default load context. So the cast on the last line will fail.

I haven't looked at the code. So I am not sure this statement above is correct.

Presuming the cited code is loaded and running in AssemblyLoadContext.Default, the ICompute cast will attempt to cast to AssemblyLoadContext.Default version of the type.

For the cast to succeed:

  • the CL.Implementation.Easy.Multiplier constructor will need to return an object which implements ICompute.
  • ICompute will need to be defined in a different assembly than CL.Implementation.Easy.Multiplier
  • The assembly which defines ICompute should only be loaded into AssemblyLoadContext.Default. So that there is only one version of the type.

@curia-damiano
Copy link

Hi,
Thank you for the comments above.
So, a good point is that using the XmlSerializerGenerator should be a walkaround for the problem.
The bad point is that XmlSerializerGenerator is badly (or almost no) documented.

@csalat: Following the comments above:

  • I have converted the dll from netstandard2.0 to netcore3.1;
  • I have removed the project ItemGroup to invoke the generator (now it's in the build.props of the NuGet package, as it comes out from multiple comments);
  • still, I get a compile time error saying that it can't find any time to be serialized.

@mconnew : Also, about the cast at runtime: I get the point that there is another instance of the dll in memory and the cast doesn't work. Still I have to guess how to solve this after I am able to make the serializer generator work. My idea is that I should be able to tell the dynamic dll loader to use the Interface dll already loaded in memory. Any tip about this second point?

I kindly ask all of you if you can please help me in making this simple POC to work.

@curia-damiano
Copy link

I attach here the modified POC after the changes discussed in the previous post
Test_ALC.zip

@vitek-karas
Copy link
Member

@curia-damiano please consider using the same patterns as shown in this sample https://docs.microsoft.com/en-us/dotnet/core/tutorials/creating-app-with-plugin-support. It shows how to write an app with plugins where the problem with casting the interface types doesn't exist.

Namely I would suggest:

  • Use AssemblyDependencyResolver if possible - in the sample you shared this is definitely a typical case where it should be used. Using mechanisms like enumerating files in current directory is problematic (it's not guaranteed that the current directory will be what you expect for example, or if there's a .dll which should not be present it might get picked up and so on).
  • Build the plugins as "plugins" - that is mark the project dependencies which should be provided by the host with the <Private>false</Private> so that the plugins don't carry copies of host assemblies with them.
  • Unless necessary, avoid duplication of assembly resolution logic - in your sample you implement both the AssemblyLoadContext.Load method as well as a handler for the AssemblyLoadContext.Resolving event. You should not need both for typical cases.
  • Ideally the plugins should be self-descriptive, that is carry only the files they need to keep in isolation and rely on the host to provide the rest. If that is the case, then you don't need to implement any logic to search for assemblies which are already loaded - instead, just return null from AssemblyLoadContext.Load and the runtime will fallback to the AssemblyLoadContext.Default which has the host (the app).
  • Avoid usage of AppDomain.CurrentDomain.GetAssemblies - this returns list of all assemblies loaded in the process, across all AssemblyLoadContext instances. This means that if you load two plugins which both carry some private dependency, you might end up using the dependency from another plugin. It might work, but it would for example prevent unloading from working correctly.

In the sample app I fixed the path to the "problem" dll to use netcoreapp3.1 and now it fails to find the XmlSerializers.dll, which is expected given the failure during build.
If I comment out loading the XmlSerialziers.dll the plugin itself works correctly (so casting to ICompute works, since the custom ALC does end up sharing the Interface assembly correctly), but it fails in the XmlSerializer due to the wrong load context used by the dynamically generated code.

@curia-damiano
Copy link

curia-damiano commented Nov 26, 2019 via email

@vitek-karas
Copy link
Member

I'm not an expert in the XmlSerializerGenerator, so hopefully others on this thread will be able to help with that aspect of the issue.

@mconnew
Copy link
Member

mconnew commented Nov 26, 2019

I've worked out the problem with XmlSerializerGenerator. There's a temporary workaround until we work out a proper fix. The issue is being tracked in issue dotnet/corefx#40730. Unfortunately that doesn't solve this problem. XmlSerializer loads the pre-generated serialization assembly into the default AssemblyLoadContext. It then calls the method CanSerialize in the pre-generated serializer which references the types CL.Implementation.Problem.Adder and CL.Implementation.Problem.MyEntity. These types are attempted to be loaded in the default AssemblyLoadContext which is then unable to find them. We should be able to fix that problem by getting the AssemblyLoadContext from the passed in type and loading the pre-generated assembly into it, but I suspect this might end up being an onion problem where we might ultimately need new capabilities from the AssemblyLoadContext feature. We won't know until we get there.

@vitek-karas
Copy link
Member

I tried the workaround and ran into two other issues:

Doesn't work with netcoreapp3.1

If I set the TFM to netcoreapp3.1 (since I'm compiling the component in questions as netcoreapp3.1) the SGEN itself works and produces the .cs file, but then compiling that fails with:

2>CSC : warning CS1703: Multiple assemblies with equivalent identity have been imported: 'C:\Windows\Microsoft.NET\Framework64\v4.0.30319\System.Data.DataSetExtensions.dll' and 'C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\3.1.0\ref\netcoreapp3.1\System.Data.DataSetExtensions.dll'. Remove one of the duplicate references.

This in itself shows two problems:

  • We obviously don't de-dupe the ref assemblies for some reason.
  • More alarmingly, we're using .NET Framework assemblies - something in the build decided that it should look for ref assemblies in the .NET Framework installation. This seems really weird for .NET Core tools.

The generated assembly is not in .deps.json

Once I switched to netcoreapp2.2 it worked and generated the serialization assembly. But I noticed that while we do put that assembly to the output folder, we don't put it into the .deps.json for the app/component. As it now becomes part of the app, it should be listed in the .deps.json as well.
Additionally, the .deps.json now contains entry for dotnet-Microsoft.XmlSerialzier.Generator.dll. If I understand it correctly that assembly should not be needed/used at runtime at all - so it should not be listed in .deps.json. In 3.0 (if it worked) I would actually expect this to be copied to the output (since all NuGet dependencies are now copied to build output).

Loading the generated code

The code which loads the generated assembly is not only not AssemblyLoadContext aware, but to make things worse, it uses Assembly.LoadFile - this will load the assembly into a new "private" instance of AssemblyLoadContext. Ideally the loader would first try to load it via Assembly.Load (or even better AssemblyLoadContext.LoadAssemblyByName) so that the custom ALC logic can kick in. Note that Assembly.Load normally loads into the ALC of the caller, in this case that would be Default, but this can be changed by using contextual reflection - for example AssemblyLoadContext.EnterContextualReflection. Only if that fails I think we should fall back to searching for the file ourselves, by looking next to the assembly (the way it works now). In that case it should definitely load the file into the same ALC as the assembly for which the serializer was generated - by using AssemblyLoadContext.LoadAssemblyByPath.

@curia-damiano
Copy link

Thank you Vitek for your further investigations.
So the current state is that XmlSerializerGenerator should work with AssemblyLoadContext, but due to various issues it doesn't.
FYI I have also used the NuGet preview package (available in the public NuGet), but I've got the same results.

@mconnew
Copy link
Member

mconnew commented Nov 27, 2019

@vitek-karas, the set of reference assemblies that is passed to csc when compiling the generated serializer is just copied from the list of reference assemblies passed to csc when compiling your application assembly. We're not changing that list at all. If full framework assemblies are being added to the set of reference assemblies, something has changed in how the .NET Core SDK compiles that list. That's a breaking change in the .NET SDK.

@vitek-karas
Copy link
Member

I'm not trying to put blame on anybody 😄 I'm just pointing out potential issues.
@nguerrera can you please comment on the presence of .NET Framework assemblies in assembly refs list for the compilers?

@nguerrera

This comment has been minimized.

@nguerrera

This comment has been minimized.

@nguerrera

This comment has been minimized.

@HongGit HongGit added this to the 6.0.0 milestone Aug 25, 2020
@MatthewLymer
Copy link

MatthewLymer commented Sep 14, 2020

I'm having the same issue with our plugin system, a plugin may reference XmlSerializer and we can't load it into a collectable assembly context.

Is there an env-var or something that instructs XmlSerializer to behave better in these scenarios, perhaps at the expense of performance?

@KallDrexx
Copy link

KallDrexx commented Nov 3, 2020

Just encountered this as we tried to update our app to allow dynamic loading and unloading of plugins using the AssemblyLoadContext, and unfortunately this may put the whole effort on hold (as some existing plugins make use of the XmlSerializer).

It appears that the fixes for this is no longer targeting .net 5 but now .net 6, am I understanding that correctly from the corresponding issues?

KallDrexx added a commit to vchelaru/FlatRedBall that referenced this issue Nov 3, 2020
While this works, it cannot be merged in due to dotnet/runtime#1388.  Specifically, the Tiled plugin uses the `XmlSerializer` type, but the `XmlSerializer` tries to create dynamic assemblies in the default `AssemblyLoadContext`, which is not collectible.  Therefore you have a collectible assembly creating and loading a non-collectible assembly, which is invalid and thus an exception occurs.

So far this does not look like it will be fixed until .net 6 at the earliest.
KallDrexx added a commit to vchelaru/FlatRedBall that referenced this issue Nov 3, 2020
While this works, it cannot be merged in due to dotnet/runtime#1388.  Specifically, the Tiled plugin uses the `XmlSerializer` type, but the `XmlSerializer` tries to create dynamic assemblies in the default `AssemblyLoadContext`, which is not collectible.  Therefore you have a collectible assembly creating and loading a non-collectible assembly, which is invalid and thus an exception occurs.

So far this does not look like it will be fixed until .net 6 at the earliest.
@drocx
Copy link

drocx commented Nov 11, 2020

Why has this bug not been fixed yet?
It has been known since September 2019 ... At that time the bug fix was moved to the .Net 5.0 framework. Now it is out and XML files still cannot be deserialized.

Here is a simple example that has crashed since 2019:

using System;
using System.IO;
using System.Xml.Serialization;

// This is the class that will be deserialized.
public class OrderedItem
{
    [XmlElement(Namespace = "http://www.cpandl.com")]
    public string ItemName;
    [XmlElement(Namespace = "http://www.cpandl.com")]
    public string Description;
    [XmlElement(Namespace="http://www.cohowinery.com")]
    public decimal UnitPrice;
    [XmlElement(Namespace = "http://www.cpandl.com")]
    public int Quantity;
    [XmlElement(Namespace="http://www.cohowinery.com")]
    public decimal LineTotal;
    // A custom method used to calculate price per item.
    public void Calculate()
    {
        LineTotal = UnitPrice * Quantity;
    }
}

public class Test
{
    public static void Main()
    {
        Test t = new Test();
        // Read a purchase order.
        t.DeserializeObject("simple.xml");
    }

    private void DeserializeObject(string filename)
    {
        Console.WriteLine("Reading with Stream");

        // Create an instance of the XmlSerializer.
        // NotSupportedException: A non-collectible assembly may not reference a collectible assembly.
        XmlSerializer serializer =
        new XmlSerializer(typeof(OrderedItem));

        // Declare an object variable of the type to be deserialized.
        OrderedItem i;

        using (Stream reader = new FileStream(filename, FileMode.Open))
        {
            // Call the Deserialize method to restore the object's state.
            i = (OrderedItem)serializer.Deserialize(reader);
        }

        // Write out the properties of the object.
        Console.Write(
        i.ItemName + "\t" +
        i.Description + "\t" +
        i.UnitPrice + "\t" +
        i.Quantity + "\t" +
        i.LineTotal);
    }
}

XmlSerializer.Deserialize Method

@drocx
Copy link

drocx commented Feb 16, 2021

@zengqinglei I reviewed your question with @mconnew and unfortunately there is no short-term workaround.

Will the bug be fixed with .NET 6?
Is there any news?

@Ap0k
Copy link
Contributor

Ap0k commented Feb 16, 2021

@drocx The creation of dynamic assemblies in the unloaded contexts, and therefore the work of the XML serializer, is fixed in PR #48072

@lsoft
Copy link

lsoft commented Feb 19, 2021

@Ap0k if I understand correctly, it will be fixed in NET6; is there any chance to backport this fix to NET5?

@Ap0k
Copy link
Contributor

Ap0k commented Feb 19, 2021

@lsoft Yes, the problem is only solved for NET6. Technically, these changes can be made in NET5 as well, but this is up to the repository owner.
cc: @vitek-karas @jkotas

@lsoft
Copy link

lsoft commented Feb 19, 2021

Thanks, @Ap0k. Looking forward for repository owner's decision.

@Benjiinator
Copy link

Benjiinator commented Feb 23, 2021

I am looking forward to hear if this can be fixed in Net5.0. as this is keeping our migration from .Net Framework to .Net5.0 from moving forward.

@drocx
Copy link

drocx commented Mar 5, 2021

@Ap0k Is the bugfix #48072 contained in NET 6 Preview 1 (6.0.100-preview.1.21103.13)?

@jkotas
Copy link
Member

jkotas commented Mar 5, 2021

#48072 is not in .NET 6 Preview 1. It will be in Preview 2.

@StephenMolloy StephenMolloy removed the tracking This issue is tracking the completion of other related issues. label Jul 27, 2021
@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label Sep 10, 2021
@ghost ghost removed the in-pr There is an active PR which will close this issue when it is merged label Nov 5, 2021
@chswin
Copy link

chswin commented Dec 2, 2021

This is not fixed in .net 6...

@StephenMolloy
Copy link
Member

@chswin, this has been fixed in 7.0... and the issue unfortunately got closed when that PR was pushed through. We are trying to get approval to bring this back to 6.0, so I do expect it to show up in a servicing release. But you are correct, it is not yet fixed in .Net 6.

@ghost ghost locked as resolved and limited conversation to collaborators Jan 2, 2022
@StephenMolloy
Copy link
Member

The PR that brings this into the 6.0 servicing branch is #61266.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.