1. Olivier PAVLIN
  2. SnapDevelop
  3. Wednesday, 20 November 2019 15:20 PM UTC

Hi there,

In my MVC .Net Web API i have this auto-generated GET function in my controller which works fine and return the list of all the elements in my table (SimpleJson.png).

[HttpGet]
[ProducesResponseType(typeof(IEnumerable<Ds_Invit_Sydrtcml>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult<IEnumerable<Ds_Invit_Sydrtcml>> Get()
{
      var modelList = _ids_invit_sydrtcmlservice.Retrieve();
            
      if (modelList.Count() == 0)
      {
           return NotFound();
      }
            
      return new ActionResult<IEnumerable<Ds_Invit_Sydrtcml>>(modelList);
}

But i would like to add more infos ("count", "duration", "success"...) in the JSON response and embed the current result in a "data" [ ... ] container to be compliant with this format :

{
    "count": 10,
    "data": [
        {
            "label": null,
            "machineId": "TEST",
            "uuid": "38d17263-cfdd-4d91-97c6-e1938012c4f8" 
        },
        {
            "label": "Laveuse 01",
            "machineId": "LAV01",
            "uuid": "DEMO_MACH_WS01_PL01_CL04_LAV01" 
        }
        ... etc...
    ],
    "duration": "125.860",
    "meta": {
        "offset": 0,
        "size": 1000,
        "total": 10
    },
    "size": 3728,
    "success": true,
    "total": 10
}

 

Attachments (1)
Accepted Answer
Olivier PAVLIN Accepted Answer Pending Moderation
  1. Thursday, 21 November 2019 16:24 PM UTC
  2. SnapDevelop
  3. # Permalink

Actually i solved it with a class model container which contains my model object and the additional information i need as properties (those will be automatically added to my Json):

public abstract class JsonBaseFormatter
{
     public bool Success { get; set; } = true;
     public int Duration { get; set; }
}

public class JsonFormatter<T> : JsonBaseFormatter
{
     public T Data { get; set; }

     public JsonFormatter(T data)
     {
        Data = data;
     }
}

Then in my controller i used this class container in the HttpGet retreive method:

[HttpGet("{cd_drt_cml}")]
[ProducesResponseType(typeof(Ds_Invit_Sydrtcml), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult<JsonFormatter<Ds_Invit_Sydrtcml>> RetrieveOne(string cd_drt_cml)
{
        var model = _ids_invit_sydrtcmlservice.RetrieveOne(cd_drt_cml);

        if (model == null)
        {
             return NotFound();
        }

        var response = new JsonFormatter<Ds_Invit_Sydrtcml>(model);
            
        return new ActionResult<JsonFormatter<Ds_Invit_Sydrtcml>>(response);

}

And then the beauty of it, I created an ActionFilter that is called automatically when http requests are sent or received by the controller:

 public class ResponseTimeActionFilter : IActionFilter
 {
     private const string ResponseTimeKey = "ResponseTimeKey";
     public void OnActionExecuting(ActionExecutingContext context)
     {
         // Start the timer   
         context.HttpContext.Items[ResponseTimeKey] = Stopwatch.StartNew();
     }


     public void OnActionExecuted(ActionExecutedContext context)
     {
         var res = context.Result as ObjectResult;
         if (res != null)
         {
             Stopwatch stopwatch = (Stopwatch)context.HttpContext.Items[ResponseTimeKey];
             // Calculate the time elapsed   
             var timeElapsed = stopwatch.Elapsed;
             var success = context.HttpContext.Response.StatusCode == StatusCodes.Status200OK;
                
             var json = ((ObjectResult)context.Result).Value as JsonBaseFormatter;
             if (json != null)
             {                   
                 json.Success = success;
                 json.Duration = timeElapsed.Milliseconds;
             }
          }
      }
 }

To make the filter works you have to register it in the Startup->ConfigureService method:  services.AddScoped<ResponseTimeActionFilter>();

And also decorate your controller so that it automatically calls the filter at each http request operation:  [ServiceFilter(typeof(ResponseTimeActionFilter))]

all infos about how filters work here https://damienbod.com/2015/09/15/asp-net-5-action-filters/ 

The request result can be found in attachment.

Attachments (1)
Comment
  1. Armeen Mazda @Appeon
  2. Friday, 22 November 2019 00:59 AM UTC
Thanks for sharing the solution.
  1. Helpful
There are no comments made yet.
Logan Liu @Appeon Accepted Answer Pending Moderation
  1. Thursday, 21 November 2019 00:41 AM UTC
  2. SnapDevelop
  3. # 1

Hi Olivier,

You can either add mutiple data elements to an IDataPacker object, or call the IDataStore.ExportPlainJson method to get the JSON string from DataStore and write your own logic to build the new JSON string.

IDataPacker

https://docs.appeon.com/appeon_online_help/snapobjects/api_reference/SnapObjects.Data/IDataPacker/IDataPacker.html

IDataPacker.AddDataStore

https://docs.appeon.com/appeon_online_help/powerbuilder/api_reference/PowerBuilder.Data/DataStoreExtensions/Method/AddDataStore.html

IDataStore.ExportPlainJson

https://docs.appeon.com/appeon_online_help/powerbuilder/api_reference/PowerBuilder.Data/DataStore/IDataStore/Method/ExportPlainJson.html

Regards,

Logan

 

Comment
  1. Michael Kramer
  2. Thursday, 21 November 2019 01:46 AM UTC
Agree, customization requires some add-on work but IDataPacker is an excellent component for such kind of code. I suggest for try to just use IDataPacker to put the resultset from DataStore in the "data" property of an outer object. Then add the remaining extra data one by one. All the time testing for every extra data item. So much easier to find and fix issues if you continuously test your progress towards the end goal.

HTH /Michael
  1. Helpful
There are no comments made yet.
  • Page :
  • 1


There are no replies made for this question yet.
However, you are not allowed to reply to this question.