Json Formatting in ABP Getting Started Series

  • 2021-09-16 06:38:39
  • OfStack

Having finished the paging function, we are not in a hurry to implement the new function in this section. To briefly introduce the usage of Json in Abp. Why do you want to talk about it in this section 1? Of course, it is to pave the way. The following series of articles will often deal with Json.

1. What does Json do

JSON (JavaScript Object Notation) is a lightweight data exchange format. Easy to read and write. At the same time, it is easy to analyze and generate by machine. JSON uses a completely language-independent text format, but also uses habits similar to the C language family (including C, C + +, C #, Java, JavaScript, Perl, Python, etc.). These features make JSON an ideal data exchange language.

Json1 is used to denote:

Name/value pair:


{"firstName":"Brett","lastName":"McLaughlin","email":"aaaa"}

Array:


{ "people":[
  {"firstName":"Brett","lastName":"McLaughlin","email":"aaaa"},
  {"firstName":"Jason","lastName":"Hunter","email":"bbbb"},
  {"firstName":"Elliotte","lastName":"Harold","email":"cccc"}
 ]
}

2. JsonResult in Asp. net Mvc

JsonResult is provided by default in JsonResult to handle the need to return data in Json format.

1 We can use it like this:


public ActionResult Movies()
{
 var movies = new List<object>();
 movies.Add(new { Title = "Ghostbusters", Genre = "Comedy", ReleaseDate = new DateTime(2017,1,1) });
 movies.Add(new { Title = "Gone with Wind", Genre = "Drama", ReleaseDate = new DateTime(2017, 1, 3) });
 movies.Add(new { Title = "Star Wars", Genre = "Science Fiction", ReleaseDate = new DateTime(2017, 1, 23) });
 return Json(movies, JsonRequestBehavior.AllowGet);
}

Where Json () is the virtual method provided in the Controller base class.

The returned json result is formatted as:


[
 {
 "Title": "Ghostbusters",
 "Genre": "Comedy",
 "ReleaseDate": "\/Date(1483200000000)\/"
 },
 {
 "Title": "Gone with Wind",
 "Genre": "Drama",
 "ReleaseDate": "\/Date(1483372800000)\/"
 },
 {
 "Title": "Star Wars",
 "Genre": "Science Fiction",
 "ReleaseDate": "\/Date(1485100800000)\/"
 }
]

Looking closely at the returned json results, there are the following shortcomings:

The case of the returned field is the same as 1 in the code. This requires us to use the case of 1 in the front end and the code (item. Title, item. Genre, item. ReleaseDate).

Does not contain success or failure information: If we were to determine whether the request was successful, we would manually fetch through the length fetch of the json packet.

The returned date is not formatted, and the output needs to be formatted by itself at the front end.

3. Encapsulation of Json in Abp

So Abp encapsulates the inheritance of AbpJsonResult from JsonResult, which mainly adds two attributes:

CamelCase: Large and small hump (default is true, that is, small hump format)

Indented: Indent or not (default is false, that is, unformatted)

The Json () method of Controller is overloaded in AbpController, forcing all returned Json format data to be AbpJsonResult type, and the virtual method of AbpJson () is provided.


/// <summary>
/// Json the specified data, contentType, contentEncoding and behavior.
/// </summary>
/// <param name="data">Data.</param>
/// <param name="contentType">Content type.</param>
/// <param name="contentEncoding">Content encoding.</param>
/// <param name="behavior">Behavior.</param>
protected override JsonResult Json(object data, string contentType, 
 Encoding contentEncoding, JsonRequestBehavior behavior)
{
 if (_wrapResultAttribute != null && !_wrapResultAttribute.WrapOnSuccess)
 {
  return base.Json(data, contentType, contentEncoding, behavior);
 }
 return AbpJson(data, contentType, contentEncoding, behavior);
}
protected virtual AbpJsonResult AbpJson(
 object data,
 string contentType = null,
 Encoding contentEncoding = null,
 JsonRequestBehavior behavior = JsonRequestBehavior.DenyGet,
 bool wrapResult = true,
 bool camelCase = true,
 bool indented = false)
{
 if (wrapResult)
 {
  if (data == null)
  {
   data = new AjaxResponse();
  }
  else if (!(data is AjaxResponseBase))
  {
   data = new AjaxResponse(data);
  }
 }
 return new AbpJsonResult
 {
  Data = data,
  ContentType = contentType,
  ContentEncoding = contentEncoding,
  JsonRequestBehavior = behavior,
  CamelCase = camelCase,
  Indented = indented
 };
}

Inherit from AbpController with Controler in ABP, use return Json () directly, and format the returned Json result:


{
 "result": [
 {
  "title": "Ghostbusters",
  "genre": "Comedy",
  "releaseDate": "2017-01-01T00:00:00"
 },
 {
  "title": "Gone with Wind",
  "genre": "Drama",
  "releaseDate": "2017-01-03T00:00:00"
 },
 {
  "title": "Star Wars",
  "genre": "Science Fiction",
  "releaseDate": "2017-01-23T00:00:00"
 }
 ],
 "targetUrl": null,
 "success": true,
 "error": null,
 "unAuthorizedRequest": false,
 "__abp": true
}

Where result is the returned data specified in the code. Several other key-value pairs are ABP encapsulated and contain authentication, success, error messages, and the target Url. These parameters are not very sweet.

You can also specify parameters for json formatted output by calling return AbpJson ().

If you look closely, you will find that the date format is still strange. 2017-01-23T00: 00:00, with one more T. Looking at the source code of AbpJsonReult, it is found that JsonConvert. SerializeObject in Newtonsoft. Json serialization component is called (obj, settings); Serialize.

To see the introduction of Newtonsoft. Json official website, you need to specify DateTimeFormat of IsoDateTimeConverter for date formatting output.


IsoDateTimeConverter timeFormat = new IsoDateTimeConverter();
   timeFormat.DateTimeFormat = "yyyy-MM-dd HH:mm:ss";
JsonConvert.SerializeObject(dt, Formatting.Indented, timeFormat)

So how do we specify this DateTimeFormat in our Abp?

The AbpDateTimeConverter class provided in ABP inherits from IsoDateTimeConverter.

But look at the Json serialization extension classes integrated in ABP:


public static class JsonExtensions
 {
 /// <summary>Converts given object to JSON string.</summary>
 /// <returns></returns>
 public static string ToJsonString(this object obj, bool camelCase = false, bool indented = false)
 {
  JsonSerializerSettings settings = new JsonSerializerSettings();
  if (camelCase)
  settings.ContractResolver = (IContractResolver) new CamelCasePropertyNamesContractResolver();
  if (indented)
  settings.Formatting = Formatting.Indented;
  settings.Converters.Insert(0, (JsonConverter) new AbpDateTimeConverter());
  return JsonConvert.SerializeObject(obj, settings);
 }
 }

Obviously, DateTimeFormat is not specified, so we can only do it ourselves. Please refer to the fourth of the four methods to solve the date format problem of json for specific code.

When an exception occurs, the Json format returned by Abp outputs the following results:


{
 "targetUrl": null,
 "result": null,
 "success": false,
 "error": {
 "message": "An internal error occured during your request!",
 "details": "..."
 },
 "unAuthorizedRequest": false
}

What if you don't need abp to wrap json?

Simple. You only need to mark the [DontWrapResult] attribute on the method. This feature is actually a shortcut to tell ABP not to wrap me with AbpJsonResult, see the source code to understand:


namespace Abp.Web.Models
{
 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Method)]
 public class DontWrapResultAttribute : WrapResultAttribute
 {
  /// <summary>
  /// Initializes a new instance of the <see cref="DontWrapResultAttribute"/> class.
  /// </summary>
  public DontWrapResultAttribute()
   : base(false, false)
  {
  }
 }
 /// <summary>
 /// Used to determine how ABP should wrap response on the web layer.
 /// </summary>
 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Method)]
 public class WrapResultAttribute : Attribute
 {
  /// <summary>
  /// Wrap result on success.
  /// </summary>
  public bool WrapOnSuccess { get; set; }
  /// <summary>
  /// Wrap result on error.
  /// </summary>
  public bool WrapOnError { get; set; }
  /// <summary>
  /// Log errors.
  /// Default: true.
  /// </summary>
  public bool LogError { get; set; }
  /// <summary>
  /// Initializes a new instance of the <see cref="WrapResultAttribute"/> class.
  /// </summary>
  /// <param name="wrapOnSuccess">Wrap result on success.</param>
  /// <param name="wrapOnError">Wrap result on error.</param>
  public WrapResultAttribute(bool wrapOnSuccess = true, bool wrapOnError = true)
  {
   WrapOnSuccess = wrapOnSuccess;
   WrapOnError = wrapOnError;
   LogError = true;
  }
 }
}

In AbpResultFilter and AbpExceptionFilter filters, the corresponding filtering will be carried out according to the characteristics of WrapResultAttribute and DontWrapResultAttribute.

4. Json date formatting

Method 1: Front-end JS conversion:


{ "people":[
  {"firstName":"Brett","lastName":"McLaughlin","email":"aaaa"},
  {"firstName":"Jason","lastName":"Hunter","email":"bbbb"},
  {"firstName":"Elliotte","lastName":"Harold","email":"cccc"}
 ]
}
0

Option 2: Specify the time serialization time format of JsonFormatter in WepApiModule (module) of Abp.


{ "people":[
  {"firstName":"Brett","lastName":"McLaughlin","email":"aaaa"},
  {"firstName":"Jason","lastName":"Hunter","email":"bbbb"},
  {"firstName":"Elliotte","lastName":"Harold","email":"cccc"}
 ]
}
1

PS: This method works only for WebApi.

Summarize

This section mainly explains the following questions:

Implementation of JsonResult in Asp. net.

The ABP re-encapsulates the JsonResult, and supports Json formatting with specified hump size and indentation or not.

How to format the output of DateTime type objects.

The Web layer specifies the time format by extending the AbpJsonResult.

Front end, format the output by converting the Json date to the Date type of js.

WebApi, by specifying DateFormatString in Moduel.


Related articles: