Getting InvalidDataContractException while serializing with DataContractJsonSerializer

853 views Asked by At

I have the following Json stored as Dynamics Environment Variable:

{
"LogLevel": 3,
"ServiceEndpointId": "11111111-2222-3333-4444-555555555555",
"ServiceEndpointType": 1
}

What I get when I retrieve the configuration is the following:

Seen in the "QuickWatch":

Quick Watch

Formatted it looks like this:

Quick Watch formatted

So far so good. But When I serialize the result I get the following error:

'System.Runtime.Serialization.InvalidDataContractException: Type 'Common.Logging.LogConfigCurrent' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute.  If the type is a collection, consider marking it with the CollectionDataContractAttribute.  See the Microsoft .NET Framework documentation for other supported types.
   at System.Runtime.Serialization.DataContract.DataContractCriticalHelper.ThrowInvalidDataContractException(String message, Type type)
   at System.Runtime.Serialization.DataContract.DataContractCriticalHelper.CreateDataContract(Int32 id, RuntimeTypeHandle typeHandle, Type type)
   at System.Runtime.Serialization.DataContract.DataContractCriticalHelper.GetDataContractSkipValidation(Int32 id, RuntimeTypeHandle typeHandle, Type type)
   at System.Runtime.Serialization.Json.DataContractJsonSerializer.get_RootContract()
   at System.Runtime.Serialization.Json.DataContractJsonSerializer.InternalIsStartObject(XmlReaderDelegator reader)
   at System.Runtime.Serialization.Json.DataContractJsonSerializer.InternalReadObject(XmlReaderDelegator xmlReader, Boolean verifyObjectName)
   at System.Runtime.Serialization.XmlObjectSerializer.ReadObjectHandleExceptions(XmlReaderDelegator reader, Boolean verifyObjectName, DataContractResolver dataContractResolver)
   at System.Runtime.Serialization.Json.DataContractJsonSerializer.ReadObject(XmlDictionaryReader reader)
   at Common.Serializer.JsonSerializer.GetObjectsFromJson[T](String json)
   at Common.Logging.LogConfig.InitLoggerConfig(IOrganizationService orgService, ITracingService tracer)'
   at Common.Logging.LoggingConfig..ctor(IOrganizationService orgService, ITracingService tracer)
   at Common.Logging..ctor(IOrganizationService orgService, IServiceEndpointNotificationService serviceEndpointNotificationService, IExecutionContext context, ITracingService traceService)'

I serialize like this:

UPDATE: Adding the DataContractAttribute did not help. I removed the suggestion in the Exception since this worked without issues a few days ago.

var logSettings = JsonSerializer.GetObjectsFromJson<LogConfigCurrent>(result.Entities[0].GetAttributeValue<string>("value"));

and the corresponding method coming from NameSpace "Common.Serializer":

public static T GetObjectsFromJson<T>(string json) where T : class
        {
            using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(json)))
            {
                var ser = new DataContractJsonSerializer(typeof(T));
                var rootObject = ser.ReadObject(ms) as T;
                ms.Close();
                return rootObject;
            }
        } 

and class:

using Microsoft.Crm.Sdk.Messages;
using Microsoft.Xrm.Sdk;
using System;
using System.Diagnostics;
using System.Linq;
using System.ServiceModel.Dispatcher;
using System.Text.RegularExpressions;
using Common.Serializer;

namespace Common.Logging
{
    public sealed class LogConfigCurrent
    {
        public int LogLevel { get; set; }
        public string ServiceEndpointId { get; set; }
        public int ServiceEndpointType { get; set; }
    }

    public sealed class LoggingConfig
    {
        public TraceLevel LogLevel { get; private set; } = TraceLevel.Info;

        public Guid ServiceEndpointId { get; private set; }

        public ServiceEndpointType EndpointType { get; private set; }

        public LoggingConfig(IOrganizationService orgService, ITracingService tracer)
        {
            try
            {
                InitLoggerConfig(orgService, tracer);
            }
            catch(Exception ex)
            {
                throw ex;
            }
        }

         private void InitLoggerConfig(IOrganizationService orgService, ITracingService tracer)
        {
            try
            {
                var fetchXml = "<fetch>" +
                                   "<entity name='environmentvariablevalue'>" +
                                    "<attribute name='value'/>" +
                                     "<link-entity name='environmentvariabledefinition' from='environmentvariabledefinitionid' to='environmentvariabledefinitionid' link-type='inner' alias='ah'>" +
                                      "<filter type='and'>" +
                                        "<condition attribute='schemaname' operator='eq' value='configuration' />" +
                                      "</filter>" +
                                     "</link-entity>" +
                                   "</entity>" +
                                  "</fetch>";

                var conversionRequest = new FetchXmlToQueryExpressionRequest
                {
                    FetchXml = fetchXml
                };

                var conversionResponse = (FetchXmlToQueryExpressionResponse)orgService.Execute(conversionRequest);

                var queryExpression = conversionResponse.Query;

                var result = orgService.RetrieveMultiple(queryExpression);

                if (result.Entities.Any())
                {
                    var logSettings = JsonSerializer.GetObjectsFromJson<LogConfigCurrent>(result.Entities[0].GetAttributeValue<string>("value"));
                    EndpointType = (ServiceEndpointType)logSettings.ServiceEndpointType;
                    ServiceEndpointId = new Guid(logSettings.ServiceEndpointId);
                    LogLevel = (TraceLevel)logSettings.LogLevel;
                }
                else
                {
                    EndpointType = ServiceEndpointType.ServiceEndpoint;
                    ServiceEndpointId = Guid.Empty;
                    LogLevel = TraceLevel.Off;
                    tracer.Trace($"No Configuration found! LogLevel was set to {TraceLevel.Off}");
                }
            }
            catch(Exception ex)
            {
                throw new Exception($"Configuration could not be loaded: Error '{ex.ToString()}'");
            }
        }
    }
}

Could this be a possible issue with escaping or do I miss something important here? Can anybody give me a hint?

1

There are 1 answers

0
Paul Richardson On

UPDATE I WANT TO SHARE:

I have found a solution for this issue but I don't understand the reason why this happens.

The code of the JsonSerializer mentioned above

JsonSerializer.GetObjectsFromJson<....>(....);

which serializes/deserializes was originally implemented in a custom nuget developed by me. This nuget was then referenced and available in the main project.

So I tried to remove the Serializer-Class from nuget and added the exact same class in the project directly. After that the exception was not thrown anymore and the data was deserialized without problems.

The plugin assembly and the nuget had the same .net version.

Does anybody have an idea why it can cause an issue like this when having such code in a nuget instead of having it in the project itself?

Any hint is highly appreciated!