dotnet / winforms

Windows Forms is a .NET UI framework for building Windows desktop applications.
MIT License
4.41k stars 982 forks source link

Control fails to load with serialization issue when upgrading Framework project to .NET 6 #9602

Open asamanta-tg opened 1 year ago

asamanta-tg commented 1 year ago

.NET version

.NET 6.0.20 .NET 8.0.0 Preview 6

Did it work in .NET Framework?

Yes

Did it work in any of the earlier releases of .NET Core or .NET 5+?

No response

Issue description

Hello,

I wasn't sure if this is the correct repository to create this issue, but I have been running into a problem migrating a large WinForms .NET Framework project to .NET 6 and eventually .NET 8.

My first step was to convert all of the .csproj files into the SDK style format, which I used the upgrade-assistant dotnet tool to accomplish, and with some manual adjustments I was able to get everything converted and running. I am able to build my solution and get my project up and running with some visual artifacts that I will have to fix.

Now my problem I am encountering has to do with the designer and how it stores public properties into the resource .resx file within my Controls and Forms. In .NET Framework, our public properties are being stored and binary serialized into the resx file for the form/control, but since the upgrade to .NET 6, most of them are failing to deserialize when opening the designer and are giving the following error.

Unable to find assembly 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. at System.Runtime.Serialization.Formatters.Binary.BinaryAssemblyInfo.GetAssembly() at System.Runtime.Serialization.Formatters.Binary.ObjectReader.GetType(BinaryAssemblyInfo assemblyInfo, String name) at System.Runtime.Serialization.Formatters.Binary.ObjectMap..ctor(String objectName, String[] memberNames, BinaryTypeEnum[] binaryTypeEnumA, Object[] typeInformationA, Int32[] memberAssemIds, ObjectReader objectReader, Int32 objectId, BinaryAssemblyInfo assemblyInfo, SizedArray assemIdToAssemblyTable) at System.Runtime.Serialization.Formatters.Binary.BinaryParser.ReadObjectWithMapTyped(BinaryObjectWithMapTyped record) at System.Runtime.Serialization.Formatters.Binary.BinaryParser.ReadObjectWithMapTyped(BinaryHeaderEnum binaryHeaderEnum) at System.Runtime.Serialization.Formatters.Binary.BinaryParser.Run() at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(BinaryParser serParser) at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream) at Microsoft.DotNet.DesignTools.Utilities.Resources.ResXDataNode.GenerateObjectFromDataNodeInfo(DataNodeInfo dataNodeInfo, ITypeResolutionService typeResolver) at Microsoft.DotNet.DesignTools.Utilities.Resources.ResXDataNode.GetValue(ITypeResolutionService typeResolver) at Microsoft.DotNet.DesignTools.Utilities.Resources.ResXResourceReader.ParseDataNode(XmlTextReader reader, Boolean isMetaData) at Microsoft.DotNet.DesignTools.Utilities.Resources.ResXResourceReader.ParseXml(XmlTextReader reader)

Looking further into this, one example I came across was that our public property at design time is an empty List\<int>, and upon further inspection of the resx file for the form which contains the value of the property differs between .NET Framework and .NET 6. The example below is from my sample application I have attached.

<!-- .NET Framework -->
<data name="userControl11.CollectionInt" mimetype="application/x-microsoft.net.object.binary.base64">
    <value>
        AAEAAAD/////AQAAAAAAAAAMAgAAAJoBbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1u
        ZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIG1zY29ybGliLCBWZXJzaW9u
        PTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUB
        AAAAL1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLkludDMyAwAAAAZfaXRl
        bXMFX3NpemUIX3ZlcnNpb24HAAAICAgCAAAACQMAAAAAAAAAAAAAAA8DAAAAAAAAAAgL
    </value>
</data>
<!-- .NET 6 -->
<data name="userControl11.CollectionInt" mimetype="application/x-microsoft.net.object.binary.base64">
    <value>
        AAEAAAD/////AQAAAAAAAAAEAQAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5
        c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJs
        aWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgcAAAgI
        CAkCAAAAAAAAAAAAAAAPAgAAAAAAAAAICw==
    </value>
</data>

It looks like the binary serializer has changed between these two frameworks, but I don't believe that is the case. I have tried taking the base64-encoded string generated by the .NET Framework designer and tried to manually deserialize it with code within my .NET Framework project and I encounter the same error. I do not encounter the error with the .NET 6 version of the base64-encoded binary string in either .NET Framework or .NET 6. I believe the designer in .NET Framework is adding something else that cannot be deserialized without going through the resources.GetObject() method within the designer, and that will be a problem for anyone going through the same upgrade process as myself.

I can manually fix most of these with a find/replace using the sample project I created since they are empty lists in our case, but we do have some where some data has been manually inputted into the collection, so doing a simple find/replace isn't going to work here.

There is a vaguely similar issue that I found that could be related to this problem. https://github.com/dotnet/winforms/issues/8584

Steps to reproduce

I will attach a sample Visual Studio solution demonstrating this issue. Inside of the solution there will be 4 WinForms projects: ResXPropertySerialization.zip

Each project has one Form and one Control, where the Form has the control inside of it. All of the projects open up in the respected designer (in/out of process) with the exception of the one that was converted using upgrade-assistant, which throws the error.

You can replicate this error with my sample application by updating the third project that is the SDK style csproj targetting 'net48' and changing that to 'net6.0-windows', building the solution, then trying to open the form with the designer in the project.

elachlan commented 1 year ago

@Olina-Zhang I think your team might need to test this? Maybe there is already a designer issue?

Amy-Li03 commented 1 year ago

@Olina-Zhang I think your team might need to test this? Maybe there is already a designer issue?

Create a new designer issue: https://github.com/microsoft/winforms-designer/issues/5399.