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

Strange Issue with Blazor WebAssembly in .Net 5.0 & DataContractSerializer #25909

Closed
LaughingJohn opened this issue Sep 15, 2020 · 7 comments
Closed
Labels
area-blazor Includes: Blazor, Razor Components External This is an issue in a component not contained in this repository. It is open for tracking purposes.

Comments

@LaughingJohn
Copy link

LaughingJohn commented Sep 15, 2020

Hi Apologies in advance as I'm not sure exactly what this is related to, Blazor, .Net 5.0, Azure or what, but it has me bamboozled and I'm just hoping someone might have a clue!

I have a Blazor webassembly application which has the usual 3 projects, Client, Server and Shared. It was all running fine under .Net Core 3.1. I have managed to convert it to .Net 5.0 RC1 (all 3 projects) and it's all running fine locally. I have also been able to publish it to Azure successfully.

Because I have some complex types in my webapi that the JSON serializer doesn't like, I use XML instead. Which has been working fine.

However since upgrading, and ONLY on the version published to Azure, the DataContractSerializer is throwing an exception when deserializing the result of any call the webassembly client makes to the webapi. It works fine when I run it locally both in Debug & Release. I have tried publishing using as framework dependant and as Self contained (out of desperation - the failure is happening in the webassembly so the method of publishing shouldn't make any difference). I have also tried turning off linking just in case it was something to do with that...

The error I get is this:

dbug: MyApplication.Blazor.Library.Classes.HttpClientXml[0]
      Error in GetAsync: System.NullReferenceException: Arg_NullReferenceException
         at System.Runtime.Serialization.CodeGenerator.Call(MethodInfo methodInfo)
         at System.Runtime.Serialization.XmlFormatReaderGenerator.CriticalHelper.ThrowValidationException()
         at System.Runtime.Serialization.XmlFormatReaderGenerator.CriticalHelper.ThrowValidationException(String msg, Object[] values)
         at System.Runtime.Serialization.XmlFormatReaderGenerator.CriticalHelper.ReadValue(Type type, String name, String ns)
         at System.Runtime.Serialization.XmlFormatReaderGenerator.CriticalHelper.ReadMembers(ClassDataContract classContract, Boolean[] requiredMembers, Label[] memberLabels, LocalBuilder memberIndexLocal, LocalBuilder requiredIndexLocal)
         at System.Runtime.Serialization.XmlFormatReaderGenerator.CriticalHelper.ReadMembers(ClassDataContract classContract, LocalBuilder extensionDataLocal)
         at System.Runtime.Serialization.XmlFormatReaderGenerator.CriticalHelper.ReadClass(ClassDataContract classContract)
         at System.Runtime.Serialization.XmlFormatReaderGenerator.CriticalHelper.GenerateClassReader(ClassDataContract classContract)
         at System.Runtime.Serialization.XmlFormatReaderGenerator.GenerateClassReader(ClassDataContract classContract)
         at System.Runtime.Serialization.ClassDataContract.CreateXmlFormatReaderDelegate()
         at System.Runtime.Serialization.ClassDataContract.get_XmlFormatReaderDelegate()
         at System.Runtime.Serialization.ClassDataContract.ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context)
         at System.Runtime.Serialization.XmlObjectSerializerReadContext.ReadDataContractValue(DataContract dataContract, XmlReaderDelegator reader)
         at System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator reader, String name, String ns, Type declaredType, DataContract& dataContract)
         at System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator xmlReader, Type declaredType, DataContract dataContract, String name, String ns)
         at System.Runtime.Serialization.DataContractSerializer.InternalReadObject(XmlReaderDelegator xmlReader, Boolean verifyObjectName, DataContractResolver dataContractResolver)
         at System.Runtime.Serialization.XmlObjectSerializer.ReadObjectHandleExceptions(XmlReaderDelegator reader, Boolean verifyObjectName, DataContractResolver dataContractResolver)
         at System.Runtime.Serialization.XmlObjectSerializer.ReadObjectHandleExceptions(XmlReaderDelegator reader, Boolean verifyObjectName)
         at System.Runtime.Serialization.XmlObjectSerializer.ReadObject(XmlDictionaryReader reader)
         at System.Runtime.Serialization.XmlObjectSerializer.ReadObject(Stream stream)
         at MyApplication.Blazor.Library.Helpers.SerializationHelper.DeserializeDataContract[AuthState](String serialized)
         at MyApplication.Blazor.Library.Classes.HttpClientXml.<GetAsync>d__5`1[[MyApplication.Blazor.Shared.Types.AuthState, MyApplication.Blazor.Shared, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext()

The failing code is:

        public async Task<AuthState> GetAuthState()
        {
            try
            {
                var url = GetUrl("getauthstate");
                return await _httpClientXml.GetAsync<AuthState>(url);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "getauthstate failed");
                throw;
            }
        }
        ------------ HttpClientXml ------------
        public async Task<T> GetAsync<T>(string requestUri)
        {
            var request = new HttpRequestMessage(HttpMethod.Get, requestUri);
            request.Headers.Add(HttpRequestHeader.Accept.ToString(), "application/xml");
            try
            {
                _logger.LogDebug($"GetAsync {requestUri}");
                var sendTask = await HttpClient.SendAsync(request);
                var requestBody = await sendTask.Content.ReadAsStringAsync();
                _logger.LogDebug("Deserializing String: {0}", requestBody);
                return SerializationHelper.DeserializeDataContract<T>(requestBody);
            }
            catch (Exception ex)
            {
                _logger.LogDebug($@"Error in GetAsync: {ex}");
                throw;
            }
        }

        ------------ SerializationHelper ------------
        public static T DeserializeDataContract<T>(string serialized)
        {
            using (var inStream = new MemoryStream(new UTF8Encoding().GetBytes(serialized)))
            {
                Console.WriteLine($"{inStream.Length} bytes to deserialize for type {typeof(T).Name}");
                var ser = new DataContractSerializer(typeof(T));
                Console.WriteLine("Calling ReadObject");
                return (T)ser.ReadObject(inStream); // <---- FAILS HERE
            }
        }

The type that's being serialized looks like this:

    public class AuthState
    {
        public AuthState()
        {
        }

        public AuthState(bool isAuthenticated, string name, string givenName)
        {
            IsAuthenticated = isAuthenticated;
            Name = name;
            GivenName = givenName;
        }

        public bool IsAuthenticated { get; set; }
        public string Name { get; set; }
        public string GivenName { get; set; }
    }

I can see both from the Network tab of the browser and from debugging that the XML is being returned OK from the webapi and looks like this:

<AuthState xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/MyApplication.Blazor.Shared.Types"> <GivenName>Admin User</GivenName> <IsAuthenticated>true</IsAuthenticated> <Name>admin@fmdevsql.onmicrosoft.com</Name> </AuthState>

I appreciate this is a bit of an odd circumstance - but just wondered if anyone might have a clue?

@LaughingJohn
Copy link
Author

I came across this which might be related: dotnet/runtime#41525 ?

@pranavkm pranavkm added the area-blazor Includes: Blazor, Razor Components label Sep 15, 2020
@pranavkm
Copy link
Contributor

@LaughingJohn the linked bug does appear to be related. @eerhardt would you happen to know what's a workaround for this? Would configuring the trim mode for System.Runtime.Serialization.Xml work?

@LaughingJohn
Copy link
Author

LaughingJohn commented Sep 15, 2020

@pranavkm Thank you so much, I was pulling out what little hair I have left! :)

I added <PublishTrimmed>false</PublishTrimmed> to the Blazor WASM project file and it's all working now.

I will try excluding System.Runtime.Serialization.Xml and let you know.

@LaughingJohn
Copy link
Author

LaughingJohn commented Sep 16, 2020

Hi @pranavkm, after trying a variety of different assemblies for exclusion, the one that seemed to do the trick is System.Private.DataContractSerialization:

<ItemGroup> <TrimmerRootAssembly Include="System.Private.DataContractSerialization" /> </ItemGroup>

Thank you!

@mkArtakMSFT mkArtakMSFT added the External This is an issue in a component not contained in this repository. It is open for tracking purposes. label Sep 16, 2020
@eerhardt
Copy link
Member

FYI - the underlying issue above is being tracked with dotnet/runtime#42754.

@LaughingJohn
Copy link
Author

Thank you @eerhardt !

@danmoseley
Copy link
Member

Should be fixed in final release.

@ghost ghost locked as resolved and limited conversation to collaborators Oct 31, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-blazor Includes: Blazor, Razor Components External This is an issue in a component not contained in this repository. It is open for tracking purposes.
Projects
None yet
Development

No branches or pull requests

5 participants