0

I am using System.Text.Json in .NET 6 and I have some data classes that have properties annotated with JsonPropertyName to be able to communicate with another API, but now I need to use the original properties names for another business reason and was looking for a way to make the serializer ignore those annotations and use the actual property names. I've found that in Newtonsoft I could've used ContractResolver to do it like suggested here, but I couldn't find an alternative in System.Text.Json. Now I am thinking of using DTOs to do it but I am looking for a simpler solution if it's available.

Here's a quick example, say we have this Account class:

public class Account {
    [JsonPropertyName("fname")]
    public string FirstName { get; set; }
    [JsonPropertyName("lname")]
    public string LastName { get; set; }
    [JsonPropertyName("years_old")]
    public int Age {get; set; }
}

In one use I want the response sent to be of the format:

{
    "fname": "John",
    "lname": "Doe",
    "years_old": 25
}

And in another response, I need:

{
    "firstname": "John",
    "lastname": "Doe",
    "age": 25
}

Now this is just a sample, but my actual classes have a lot of properties, and making DTOs isn't for each use case is too much work. Hence why I am looking for a solution using something like Newtonsoft DefaultContractResolver but using System.Text.Json.

PS: I can't afford to move back to Newtonsoft.Json.

dbc
  • 104,963
  • 20
  • 228
  • 340
Isu
  • 330
  • 1
  • 4
  • 16
  • Just remove JsonPropertyName from your properties – Serge Jun 09 '23 at 11:41
  • @Serge I explicitly said that I needed those for other requests, so removing them isn't really an option. I was looking for some way to disable them for a given serialization. – Isu Jun 09 '23 at 11:46
  • Your question is not clear. There are two operations - serialization and deserialization. What do you need what for? – Serge Jun 09 '23 at 11:49
  • The class is used in communication with 2 different APIs, where in one it needs to use properties names defined using the `JsonPropertyName`, whilst the other requires the actual properties names. Something like what's required in the question I linked. – Isu Jun 09 '23 at 11:56
  • Data from API usually needs to be deserialized only. In any case it is getting even more confused now. – Serge Jun 09 '23 at 12:01
  • I made an edit, I hope it's a bit more clear now. – Isu Jun 09 '23 at 12:11
  • I think it's better to create two classes of Account, with fields that API's required. And then implement some basic logic to clone/copy one class to another if needed. If it's different API's with a different fields names, at one point you will require to pass some additional field to one of them, but not for another. – dima_horror Jun 09 '23 at 13:45
  • 2
    In .NET 7 MSFT introduced `DefaultJsonTypeInfoResolver` which is equivalent to `DefaultContractResolver`, see [System.Text.Json API is there something like IContractResolver](https://stackoverflow.com/a/74284215/3744182). You could cancel the `JsonPropertyNameAttribute` using that. See e.g. [Asymmetric Field Names for serialisation and deserialisation using System.Text.Json](https://stackoverflow.com/q/76250152/3744182). But in .NET 6 your options are much more limited. Can you more to .NET 7? – dbc Jun 10 '23 at 19:18
  • @dbc I reached the same conclusion too in my research, before deciding on doing anything I thought I'd ask here to check if there is maybe some way to do it in .NET 6 but sadly there doesn't seem to be any. – Isu Jun 10 '23 at 19:35
  • There's nothing easy. Obviously you could create your own custom converter that cycles through the properties and serializes each one using reflection. – dbc Jun 10 '23 at 19:38
  • I would consider using different DTOs for different APIs. – Alexander Petrov Jun 10 '23 at 21:27

1 Answers1

-1

If you don't want to use a mapper and dto, the only way I see ( and I think it is more effective)

    var origJson = @"{
    ""fname"": ""John"",
    ""lname"": ""Doe"",
    ""years_old"": 25
}";

    var fixedJson = FixPropertyNames(origJson);

public string FixPropertyNames(string json)
{
    StringBuilder sb = new StringBuilder(json);

    sb.Replace("\"fname\"", "\"firstname\"");
    sb.Replace("\"lname\"", "\"lastname\"");
    sb.Replace("\"years_old\"", "\"age\"");

    return sb.ToString();
}

or if your classes are small, you can remove a string builder and put all code in one line.

fixedJson= origJson.Replace("\"fname\"", "\"firstname\"").Replace("\"lname\"", "\"lastname\"").Replace("\"years_old\"", "\"age\"");

And I guess your API should return a content, since you have created a json string already

 return Content(jsonString, "application/json");
Serge
  • 40,935
  • 4
  • 18
  • 45