Refactor and enhance JSON handling with extensions

Refactored `ConfigExtensions.cs` to move `ConfigurationExtensions`
to the `ReC.API.Extensions` namespace and re-added the
`GetFakeProfileId` method. Introduced `JsonExtensions.cs` with
a `JsonToDynamic` method for recursive JSON deserialization,
simplifying nested JSON handling. Updated `OutResController.cs`
and `RecActionController.cs` to use the new `JsonToDynamic`
method, improving code readability and reducing duplication.
Overall, modularized and cleaned up code for better maintainability.
This commit is contained in:
tekh 2025-12-04 13:44:10 +01:00
parent 9165f9d746
commit d02bebc6e2
4 changed files with 62 additions and 6 deletions

View File

@ -1,9 +1,8 @@
using MediatR; using MediatR;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using ReC.API.Models; using ReC.API.Extensions;
using ReC.Application.OutResults.Queries; using ReC.Application.OutResults.Queries;
using System.Net.Mime; using System.Net.Mime;
using System.Text.Json;
namespace ReC.API.Controllers; namespace ReC.API.Controllers;
@ -34,8 +33,8 @@ public class OutResController(IMediator mediator, IConfiguration config) : Contr
return resultType switch return resultType switch
{ {
ResultType.Body => res.Body is null ? Ok(new object { }) : Ok(JsonSerializer.Deserialize<dynamic>(res.Body)), ResultType.Body => res.Body is null ? Ok(new object { }) : Ok(res.Body.JsonToDynamic()),
ResultType.Header => res.Header is null ? Ok(new object { }) : Ok(JsonSerializer.Deserialize<dynamic>(res.Header)), ResultType.Header => res.Header is null ? Ok(new object { }) : Ok(res.Header.JsonToDynamic()),
_ => Ok(res), _ => Ok(res),
}; };
} }

View File

@ -1,5 +1,6 @@
using MediatR; using MediatR;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using ReC.API.Extensions;
using ReC.API.Models; using ReC.API.Models;
using ReC.Application.RecActions.Commands; using ReC.Application.RecActions.Commands;
using ReC.Application.RecActions.Queries; using ReC.Application.RecActions.Queries;

View File

@ -1,6 +1,6 @@
namespace ReC.API; namespace ReC.API.Extensions;
public static class ConfigurationExtensions public static class ConfigurationExtensions
{ {
public static int GetFakeProfileId(this IConfiguration config) => config.GetValue<int>("FakeProfileId", 2); public static int GetFakeProfileId(this IConfiguration config) => config.GetValue("FakeProfileId", 2);
} }

View File

@ -0,0 +1,56 @@
using System.Text.Json;
public static class JsonExtensions
{
/// <summary>
/// Deserialize JSON string and automatically parse nested JSON strings.
/// </summary>
public static dynamic? JsonToDynamic(this string json)
{
// Deserialize the top-level JSON
var result = JsonSerializer.Deserialize<JsonElement>(json);
// Recursively fix stringified JSON objects
return JsonToDynamic(result);
}
private static dynamic? JsonToDynamic(JsonElement obj)
{
switch (obj.ValueKind)
{
case JsonValueKind.Object:
var dict = new Dictionary<string, dynamic?>();
foreach (var prop in obj.EnumerateObject())
{
dict[prop.Name] = JsonToDynamic(prop.Value);
}
return dict;
case JsonValueKind.Array:
var list = new List<dynamic>();
foreach (var item in obj.EnumerateArray())
{
list.Add(JsonToDynamic(item));
}
return list;
case JsonValueKind.String:
var str = obj.GetString();
// Try to parse string as JSON
if (!string.IsNullOrWhiteSpace(str) && (str.StartsWith('{') || str.StartsWith('[')))
{
try
{
return JsonToDynamic(JsonSerializer.Deserialize<JsonElement>(str));
}
catch
{
return str; // Not valid JSON, return original string
}
}
return str;
default:
return obj.GetRawText();
}
}
}