0

I have a data class:

public Data
{
    Foo MyFoo
    Bar MyBar
}

Foo is something that needs to a lot of changes and cleaning up to be useful. So I have an interface

public IFooTransformation
{
    Foo Transform(Foo foo)
}

Users create lists of IFooTransformation that are stored in JSON files and loaded at runtime.

var transformations = JsonSerializer.Deserialize<IFooTransformation>(jsonText);

foreach (var transformation in transformations)
{
    foo = transformation.Transform(foo);
}

This worked great until now I need to create an AddBarTransformation. All the other transformations include all the properties they need in the JSON, but MyBar is only available at runtime.

Is there a design pattern to help me get MyBar into the AddBarTransformation?

So far I've thinking:

  1. Using a custom JsonConverter that would Set AddBarTransformation's Bar to MyBar.
    • This might work but is a little janky and I haven't figured it out yet.
  2. Changing the interface to accept a Data rather than a Foo
    • This feels bad since the other Transformations only need Foo
  3. Using reflection to loop over the transformations and fill in if any need a Bar.
  4. Separate the logic and data of the IFooTransformation into and use a Builder or a Factory to get the matching logic class while knowing this one needs a Bar passed in.
    • Seems like a lot of complexity when something like 2 is really easy.

Edit: For my option 1, because I'm deserializing an interface I'm using the Json.Abstractions nuget package. It's JsonAbstractionConverter is being called before my CustomConverter. The JsonAbstractionConverter is not set up to call other CustomConverters that may exist when it's constructing an object.

1 Answers1

0

You can use Newtonsoft.Json.Serialization's ContractResolver for this purpose, define all the property-to-property mapping for json that needs to be serialized or de-serialized. Sample:

public class CustomContractResolver : DefaultContractResolver
{
    private Dictionary<string, string> PropertyMappings { get; set; }

    public CustomContractResolver()
    {
        this.PropertyMappings = new Dictionary<string, string>
        {
            {"Number", "Nmb"},
            {"Street", "Str"},
            //all properties,
        };
    }

    protected override string ResolvePropertyName(string propertyName)
    {
        string resolvedName = null;
        var resolved = this.PropertyMappings.TryGetValue(propertyName, out resolvedName);
        return (resolved) ? resolvedName : base.ResolvePropertyName(propertyName);
    }
}

Here is how to use it:

var jsonObject = JsonConvert.DeserializeObject(jsonString, new JsonSerializerSettings{ ContractResolver = new CustomContractResolver() });
Rithik Banerjee
  • 447
  • 4
  • 16