Search code examples
c#json.netasp.net-coresystem.text.json

Get class via reflection to deserialize JSON


I have message, that coming from Service bus, it's Json string

Here is example

{
"JobType": "DispatcherWeb.Infrastructure.BackgroundJobs.ImportJob",
"JobArgsType": "DispatcherWeb.Infrastructure.BackgroundJobs.ImportJobArgs",
"JobArgs": {
    "RequestorUser": {
        "TenantId": 2,
        "UserId": 10005
    },
    "File": "fc0df99f-273c-41f0-e1b1-08dcace4d7c5/Import_20240815081947.csv",
    "FieldMap": [
        {
            "UserField": "Truck Code",
            "StandardField": "truck code"
        },
        {
            "UserField": "Office",
            "StandardField": ""
        },
        {
            "UserField": "Category",
            "StandardField": "category"
        },
        {
            "UserField": "Apportioned",
            "StandardField": "apportioned"
        },
        {
            "UserField": "Bed Construction",
            "StandardField": "bed construction"
        },
        {
            "UserField": "Can Pull Trailer",
            "StandardField": "can pull trailer"
        },
        {
            "UserField": "Default Driver",
            "StandardField": ""
        },
        {
            "UserField": "Current Trailer",
            "StandardField": ""
        },
        {
            "UserField": "IsActive",
            "StandardField": ""
        },
        {
            "UserField": "Inactivation Date",
            "StandardField": ""
        },
        {
            "UserField": "Out of Service",
            "StandardField": "out of service"
        },
        {
            "UserField": "Reason",
            "StandardField": ""
        },
        {
            "UserField": "Always show on schedule",
            "StandardField": "always show on schedule"
        },
        {
            "UserField": "Year",
            "StandardField": "year"
        },
        {
            "UserField": "Make",
            "StandardField": "make"
        },
        {
            "UserField": "Model",
            "StandardField": "model"
        },
        {
            "UserField": "In Service Date",
            "StandardField": "in service date"
        },
        {
            "UserField": "VIN",
            "StandardField": "vin"
        },
        {
            "UserField": "Plate",
            "StandardField": "plate"
        },
        {
            "UserField": "Plate Expiration",
            "StandardField": "plate expiration"
        },
        {
            "UserField": "Ave Load(Tons)",
            "StandardField": ""
        },
        {
            "UserField": "Ave Load(Cyds)",
            "StandardField": ""
        },
        {
            "UserField": "Insurance Policy Number",
            "StandardField": "insurance policy number"
        },
        {
            "UserField": "Insurance Valid Until",
            "StandardField": "insurance valid until"
        },
        {
            "UserField": "Purchase Date",
            "StandardField": "purchase date"
        },
        {
            "UserField": "Purchase Price",
            "StandardField": "purchase price"
        },
        {
            "UserField": "Sold Date",
            "StandardField": "sold date"
        },
        {
            "UserField": "Sold Price",
            "StandardField": "sold price"
        },
        {
            "UserField": "Fuel Type",
            "StandardField": "fuel type"
        },
        {
            "UserField": "Fuel Capacity",
            "StandardField": "fuel capacity"
        },
        {
            "UserField": "Steer Tires",
            "StandardField": "steer tires"
        },
        {
            "UserField": "Drive Axle Tires",
            "StandardField": "drive axle tires"
        },
        {
            "UserField": "Drop Axle Tires",
            "StandardField": "drop axle tires"
        },
        {
            "UserField": "Trailer Tires",
            "StandardField": "trailer tires"
        },
        {
            "UserField": "Transmission",
            "StandardField": "transmission"
        },
        {
            "UserField": "Engine",
            "StandardField": "engine"
        },
        {
            "UserField": "Rear End",
            "StandardField": "rear end"
        },
        {
            "UserField": "Current Mileage",
            "StandardField": "current mileage"
        },
        {
            "UserField": "Current Hours",
            "StandardField": "current hours"
        },
        {
            "UserField": "Trux Truck Id",
            "StandardField": ""
        },
        {
            "UserField": "Unique Id",
            "StandardField": ""
        },
        {
            "UserField": "Notes",
            "StandardField": ""
        },
        {
            "UserField": "Tablet Make",
            "StandardField": ""
        },
        {
            "UserField": "Tablet Model",
            "StandardField": ""
        },
        {
            "UserField": "Tablet IMEI",
            "StandardField": ""
        },
        {
            "UserField": "Tablet SIM Id",
            "StandardField": ""
        },
        {
            "UserField": "GPS Device Make",
            "StandardField": ""
        },
        {
            "UserField": "GPS Device Model",
            "StandardField": ""
        },
        {
            "UserField": "GPS Device IMEI",
            "StandardField": ""
        },
        {
            "UserField": "GPS Device SIM Id",
            "StandardField": ""
        },
        {
            "UserField": "Camera Make",
            "StandardField": ""
        },
        {
            "UserField": "Camera Model",
            "StandardField": ""
        },
        {
            "UserField": "Camera IMEI",
            "StandardField": ""
        },
        {
            "UserField": "Camera SIM Id",
            "StandardField": ""
        }
    ],
    "ImportType": 7,
    "JacobusEnergy": false
}

}

I try to get it and deserialize the model.

Here is the code of how I do this

  private static async Task ReceiveMessage(string serviceBusQueueName, ServiceBusClient client)
        {
            var processor = client.CreateProcessor(serviceBusQueueName, new ServiceBusProcessorOptions());
            processor.ProcessMessageAsync += async (messageArgs) =>
            {
                var messageObject = JsonSerializer.Deserialize<MessageObject>(messageArgs.Message?.Body.ToString());
                var className = Type.GetType(messageObject.JobArgsType).;
                var data = JsonSerializer.Deserialize<className>(messageObject.JobArgs.ToString());
                //var test = messageArgs.Message?.Body.ToString();

                await messageArgs.CompleteMessageAsync(messageArgs.Message);
            };

            processor.ProcessErrorAsync += async (messageArgs) =>
            {
                Console.WriteLine(messageArgs.Exception.Message);
            };

            await processor.StartProcessingAsync();
        }

        internal class MessageObject
        {
            public string JobType { get; set; }

            public string JobArgsType { get; set; }

            public object JobArgs { get; set; }
        }

in row var className = Type.GetType(messageObject.JobArgsType); I try to get "DispatcherWeb.Infrastructure.BackgroundJobs.ImportJobArgs class to serialize object in it. But I have error now in this row var data = JsonSerializer.Deserialize<className>(messageObject.JobArgs.ToString()); - Cannot resolve symbol 'className'

UPDATE

I rewrote code like this

  processor.ProcessMessageAsync += async (messageArgs) =>
        {
            var messageObject = JsonSerializer.Deserialize<MessageObject>(messageArgs.Message?.Body.ToString());
            var className = Type.GetType(messageObject.JobArgsType);
            var data = JsonSerializer.Deserialize(messageObject.JobArgs.ToString(), className);
            //var test = messageArgs.Message?.Body.ToString();

            await messageArgs.CompleteMessageAsync(messageArgs.Message);
        };

but in var className = Type.GetType(messageObject.JobArgsType); I got null

How can I resolve this?


Solution

  • Here you can find a working example: https://dotnetfiddle.net/ly852c

    The parsing logic

    public class Program
    {
        public static void Main()
        {
            var json = @"{ 
                ""dataType"": ""X+Y"",
                ""data"": { ""Z"": 42 }
            }";
            
            var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
            var message = JsonSerializer.Deserialize<Message>(json, options);
            var dataType = Type.GetType(message.DataType);
            var data = (X.Y)JsonSerializer.Deserialize(message.Data, dataType);
            data.Z.Dump();
        }
    }
    

    The message class

    public class Message
    {
        public string DataType {get; set;}
        public JsonElement Data {get; set;}
    }
    

    The data class

    public class X
    {
        public class Y
        {
            public int Z {get; set;}
        }
    }
    

    The tricks

    • You should deserialize the JobArgs as JsonElement not as object
    • You should use the non-generic Deserialize method which accepts the return type