0

I have a List<DTOModule> that I'm serializing

  public class DTOModule
  {
    public string? Name { get; set; }
    public string? Prefix { get; set; }
    public string? Description { get; set; }
    public string? ImagePath { get; set; }
    [JsonIgnore]
    public DateTime? ExpiryDate { get; set; }
    [JsonIgnore]
    public bool? Visible { get; set; }
    [JsonIgnore]
    public bool? Enabled { get; set; }
    [JsonIgnore]
    public virtual bool? IsEnabled
    {
      get { return (Visible == false || Enabled == false || ExpiryDate < DateTime.Now) ? false : null; }
    }
    [JsonIgnore]
    public string? DisabledDescription { get; set; }
  }

By default the following method produces a JSON string with only the Name, Prefix, Description and ImagePath.

private void GetModules(List<DTOModule> moduleClaims)
{
  var moduleJson = Newtonsoft.Json.JsonConvert.SerializeObject(modules);
  ...

In another section of my code I would like to override the default serialization and have the object produce the following properties:

Prefix, ExpiryDate, IsEnabled and DisabledDescription

I realize I could do a linq query and select into a new anonymous object and just serialize that, but I'd like to have something a little more solid in place.

What are my options for serializing the same object multiple ways?

Hank
  • 2,456
  • 3
  • 35
  • 83
  • 1
    It's not really clear what you mean by *I'd like to have something a little more solid in place.* There are many existing questions on this topic including [Conditional member serialization based on query parameter?](https://stackoverflow.com/q/29713847/3744182), [Serializing only selected properties with Json.Net](https://stackoverflow.com/q/54710790), [NewtonSoft add JSONIGNORE at runTime](https://stackoverflow.com/q/25157511), [Exclude property from serialization via custom attribute (json.net)](https://stackoverflow.com/q/13588022/3744182), etc etc. Do any of those work for you? – dbc Oct 07 '22 at 23:34
  • 1
    See also [JSON.net ContractResolver vs. JsonConverter](https://stackoverflow.com/q/41088492/3744182) whose answer has an overview of what can be done with a converter and what can be done with a contract resolver. Using a DTO inside a `JsonConverter` would be one option. – dbc Oct 07 '22 at 23:35
  • Thanks dbc, yes there are many, my search didn't come across any of those from your first comment – Hank Oct 08 '22 at 06:34
  • The first question you listed was an answer by yourself, I really liked the flexibility in that one. – Hank Oct 08 '22 at 08:06

1 Answers1

2

You can produce a new class that won't inherit the json ignore property. An example will be as follows:

public class Foo
{
    [JsonIgnore]
    public int ParentId { get; set; }
}

public class Bar: Foo
{
    [JsonProperty("ParentId")]
    public new int ParentId { get; set; }
}

The new modifier tells the compiler to replace the property and not inherit it from the base class. As it now does not inherit JsonIgnore anymore it will be serialized.

So yours would look like this:

  public class DTOModuleExt : DTOModule
  {
    public new virtual bool? IsEnabled
    {
      get { return (Visible == false || Enabled == false || ExpiryDate < DateTime.Now) ? false : null; }
    }
  }

Here is a full working example with your code above:

void Main()
{
    DTOModule dto = new DTOModule {
        Description = "Some Description",
        DisabledDescription = "Some DisabledDescription",
        Enabled = false,
        ExpiryDate = DateTime.Now,
        ImagePath = "Some Path",
        Name = "Some Name",
        Prefix = "Some Prefix",
        Visible = false
    };
    
    var dtoJson = JsonConvert.SerializeObject(dto);
    dtoJson.Dump();
    //Outputs: {"Name":"Some Name","Prefix":"Some Prefix","Description":"Some Description","ImagePath":"Some Path"}
    
    DTOModuleExt dtoExt = new DTOModuleExt
    {
        Description = "Some Description",
        DisabledDescription = "Some DisabledDescription",
        Enabled = false,
        ExpiryDate = DateTime.Now,
        ImagePath = "Some Path",
        Name = "Some Name",
        Prefix = "Some Prefix",
        Visible = false
    };


    var dtoExtJson = JsonConvert.SerializeObject(dtoExt);
    
    dtoExtJson.Dump();
    //Outputs: {"IsEnabled":false,"Name":"Some Name","Prefix":"Some Prefix","Description":"Some Description","ImagePath":"Some Path"}
    
}

// You can define other methods, fields, classes and namespaces here
public class DTOModule
{
    public string? Name { get; set; }
    public string? Prefix { get; set; }
    public string? Description { get; set; }
    public string? ImagePath { get; set; }
    [JsonIgnore]
    public DateTime? ExpiryDate { get; set; }
    [JsonIgnore]
    public bool? Visible { get; set; }
    [JsonIgnore]
    public bool? Enabled { get; set; }
    [JsonIgnore]
    public virtual bool? IsEnabled
    {
        get { return (Visible == false || Enabled == false || ExpiryDate < DateTime.Now) ? false : null; }
    }
    [JsonIgnore]
    public string? DisabledDescription { get; set; }
}

public class DTOModuleExt : DTOModule
{
    public new virtual bool? IsEnabled
    {
        get { return (Visible == false || Enabled == false || ExpiryDate < DateTime.Now) ? false : null; }
    }
}

First one produce this json string:

{"Name":"Some Name","Prefix":"Some Prefix","Description":"Some Description","ImagePath":"Some Path"}

Second produces your example string:

{"IsEnabled":false,"Name":"Some Name","Prefix":"Some Prefix","Description":"Some Description","ImagePath":"Some Path"}

You can add the rest of your variables into the class or make a new one depending on your serialization needs. Personally I would make a class where none of them are ignored, and then make classes where you ignore them. That might make more sense.

mathis1337
  • 1,426
  • 8
  • 13
  • 2
    This is a decent solution. You can pretty much create an infinite number of combos doing it this way. – TravTanker Oct 08 '22 at 03:28
  • 1
    I like this as well, great anwser! – Hank Oct 08 '22 at 06:35
  • Glad this worked for you. Like I said at end it probably makes more sense to make the parent class have none of them ignored, and then create your custom extensions for when you have custom ignore cases/non ignore cases. – mathis1337 Oct 10 '22 at 16:40