Search code examples
c#json.net-coreasp.net-core-mvcsystem.text.json

net 6.0: dynamically returning child object in response


I have a response class.

public class Response
{
      [JsonPropertyName("number")]
      public int? number { get; set; }
      [JsonIgnore]
      public string WithClientInfo { get; set; }
      [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
      public ClientResponse client
      {
         get { return WithClientInfo == "J" ? client : null; }
         set { }
      }
}

Query:

  var query = from table1 in _unitOfWork.table1.All(_pageParameters)
              from table2 in _unitOfWork.table2.All(null).Where(x => x.Nr_X == table1.Nr_X).DefaultIfEmpty()
              from table3 in _unitOfWork.table3.All(null).Where(x => x.Nr_Y == table1.Nr_Y).DefaultIfEmpty()
              select new Response
              {
                number = table1.Nr_X,
                WithClientInfo = "N",
                Client = new ClientResponse
                {
                    //fields
                }
              }

How can i conditionally fill the response with the Client information. I mean based on a condition i want the Client in the response or not. I'm using System.Text.Json and .net 6. I have tried the [JsonIgnore] attribute but the no results. The app crashes.

This is a MVC app with uses controller.


Solution

  • Is this a WebAPI or a MVC app which uses Controllers?

    Here's an example of how I do that in my .NET 6.0 WebAPI using a Controller.

    public ActionResult DeleteData(String key){
    
      // Notice that this method returns an ActionResult type.
    
      // We do the work to attempt to delete the item.
      // I've removed the code to simplify the example
       // then we return the result
     // deletedCount gets set to a value great than 0 if record(s) were deleted
     // set up a basic nullable JsonResult object (ActionResult) 
     Object? jsonResult = null;
            if (deletedCount > 0){
                jsonResult = new {success=(deletedCount > 0),message="Encrypted data & all associated data has been deleted."};
            }
            else{
                jsonResult = new {success=(deletedCount > 0),message="Data does not exist for associated Cya Secret ID (MainToken). No data deleted."};
            }
            return new JsonResult(jsonResult);
    
    }
    

    The resulting JSON will look something like the following:

    {success:true,message:"Encrypted data & all associated data has been deleted."}
    

    or

    {success:false,message="Data does not exist for associated Cya Secret ID (MainToken). No data deleted."}
    

    Returning a Model Object As JsonResult

    Maybe you're trying to return a Model object as a JsonResult? You can do that by defining your normal class for example:

    public class Thing{
        public Int64 Id{get;set;}
        
        // We don't want this value exposed to end user
        [System.Text.Json.Serialization.JsonIgnore]
        public Int64 MainTokenId{get;set;}
        public String Data{get;set;}
        public String AnotherField{get;set;}
        public DateTime? Created {get;set;}
        public DateTime? Updated{get;set;}
        public bool Active{get;set;}
    
        public Thing(Int64 mainTokenId){
            MainTokenId = mainTokenId;
        }
    }
    

    Next, in our Controller we might have an action method that returns this object like the following:

    public ActionResult GetThing(Int64 id){
        // do work to load item from DB
        // .
        // .
        // .
        Thing t = LoadThingFromDb();
        // return object as JSON
        return new JsonResult(t);
    }
    

    Looks like you just need to do the following:

    public class Response
        {
          [JsonPropertyName("number")]
          public int? number { get; set; }
          [JsonIgnore]
          public string WithClientInfo { get; set; }
    
          // ### Add this attribute #####
          [System.Text.Json.Serialization.JsonIgnore]
          public ClientResponse client
          {
             get { return WithClientInfo == "J" ? client : null; }
             set { }
          }
    
    }
    

    Custom DTO (Data Transfer Object)

    If you want to return specific object properties based upon a condition you'll have create a DTO.

    Somewhere in your code you have your ClientResponse object.

    You can create a anonymous object and return it after wrapping it in a JsonResult

    // I guess your main class is named Response so...
        Response r = new Response();
    
    if (conditionYouWantIsTrue){
        return JsonResult(new { prop1 = r.Prop1, prop2 = r.Prop2, prop3 = r.Prop3, prop4 = r.Prop4});
    }
    else {
         return JsonResult(new { prop3 = r.Prop3, prop4 = r.Prop4});
    }
    

    Update

    This is because you are using Functional programming paradigm within your algorithmic code.

    That means you are making a huge functional call then not knowing where to handle your logic.

    You'll have to handle the logic after the query object is filled.

    Something like:

    var query = from table1 in _unitOfWork.table1.All(_pageParameters)
                  from table2 in _unitOfWork.table2.All(null).Where(x => x.Nr_X == table1.Nr_X).DefaultIfEmpty()
                  from table3 in _unitOfWork.table3.All(null).Where(x => x.Nr_Y == table1.Nr_Y).DefaultIfEmpty()
                  select new Response
                  {
                    number = table1.Nr_X,
                    WithClientInfo = "N",
                    Client = new ClientResponse
                    {
                        //fields
                    }
                  }
    
    // this code runs after the query result is filled
        if (conditionYouWant){
            return JsonResult(new {prop1 = query.prop1, prop2 = query.prop2, prop3 = query.prop3});
        }
        else{
                return JsonResult(new {prop1 = query.prop1});
        }