Introduction
As I started to based my web apps around sending json back and forth, I started to notice the many different ways there are to format and manipulate the responses. There seem to be three main ways to return json from an MVC app. Even the style of building the response within those three can differ with different features of the language. This tip will hopefully help me, as well as you to find a method that best fits our needs. If you know of any others, please let me know in the comments and I will try to include them.
Using the Code
I will show three different return types for Json responses:
JsonResult
- The preferred method to use when you have an object to send ContentResult
- The preferred method when you have a serialized response (i.e., string
) already String
- Not preferred but still possible
JsonResult
*When looking at the JsonResult
examples, you will see the json function set with the JsonRequestBehavior.AllowGet
parameter passed. If this is left out of a GET
, you will get a 500 message saying that the get
method is insecure.*
If your database columns have the same names that you want your json properties to have, it is super easy to send back the response to the client using the json method to convert to a jsonresult and serialized to the client.
Function get_people_jsonresult(Optional id As Integer = 0) As JsonResult
Dim peoples = From c In db.dtb_people.OrderBy(Function(x) x.c_lastname).ToList
Return Json(peoples, JsonRequestBehavior.AllowGet)
End Function
You can also just create a new JsonResult
.
Function get_people_jsonresult(Optional id As Integer = 0) As JsonResult
Dim peoples = From c In db.dtb_people.OrderBy(Function(x) x.c_lastname).ToList
Return New JsonResult With {.Data = peoples, .JsonRequestBehavior = JsonRequestBehavior.AllowGet}
End Function
Since your database is probably not setup the same as your expected response, the most common way you'll see Json returned is by taking the data from a database and mapping it to a class. This class will then be serialized to the client. This is perfect if your class is setup to have the same properties as a class. You'll commonly see the classes using JsonProperty
which is used to easily deserialize json from a client in order to map it to a class. Unfortunately, this can't be used the other way around and have the class names serialize to the jsonproperties
. In that case, you can always create a new class.
Function get_people_jsonresult(Optional id As Integer = 0) As JsonResult
Dim peoples As New List(Of people)
For Each c As dtb_people In db.dtb_people.OrderBy(Function(x) x.c_lastname).ToArray
Dim peep As New people
peep.firstname = c.c_firstname
peep.lastname = c.c_lastname
peep.id = c.c_Id
peoples.Add(peep)
Next
Return Json(peoples, JsonRequestBehavior.AllowGet)
End Function
Public Class class_people
<JsonProperty(PropertyName:="fname")> Public Property firstname As String
<JsonProperty(PropertyName:="lname")> Public Property lastname As String
<JsonProperty(PropertyName:="id")> Public Property id As Integer
End Class
However, sometimes it is easier and more readable if the class is defined where it is actually used. Here, we see an anonymous class used to select and reassign column names from the list of rows in the database. I've also shortened the class definition using the with
keyword. The Json function will, again, convert this to the expected json response as well.
Function get_people_jsonresult(Optional id As Integer = 0) As JsonResult
Dim c As Object = From c In db.dtb_people.OrderBy(Function(x) x.c_lastname).ToList
Dim q = New With {
.firstname = c.c_firstname,
.lastname = c.c_lastname,
.id = c.c_Id
}
Return Json(q, JsonRequestBehavior.AllowGet)
End Function
You can even go further to shorten this to my favorite version:
Function get_people_jsonresult(Optional id As Integer = 0) As JsonResult
Dim q As Object = From c In db.dtb_people.OrderBy(Function(x) x.c_lastname).ToList Select New With {
.firstname = c.c_firstname,
.lastname = c.c_lastname,
.id = c.c_Id
}
Return Json(q, JsonRequestBehavior.AllowGet)
End Function
All of these give the following output:
[
{
"firstname": "santa",
"lastname": "clause",
"id": 2
},
{
"firstname": "john",
"lastname": "smith",
"id": 1
}
]
When needing a single item vs. a list, you can reformat the query putting the select
statement in the where
clause and then picking the single element to return a non-array.
Function get_people_jsonresult(Optional id As Integer = 0) As JsonResult
Dim q As Object = (From c In db.dtb_people.Where(Function(x) x.c_Id = id) Select New With {
.firstname = c.c_firstname,
.lastname = c.c_lastname,
.id = c.c_Id
}).Single()
Return Json(q, JsonRequestBehavior.AllowGet)
End Function
Output:
{
"firstname": "john",
"lastname": "smith",
"id": 1
}
You can again separate the anonymous class if you prefer it that way:
Function get_people_jsonresult(Optional id As Integer = 0) As JsonResult
Dim c As dtb_people = db.dtb_people.Where(Function(x) x.c_Id = 1).Single
q = New With {
.firstname = c.c_firstname,
.lastname = c.c_lastname,
.id = c.c_Id
}
Return Json(q, JsonRequestBehavior.AllowGet)
End Function
The Json function not only does classes, but it can also convert a multidimensional dictionary
as well:
Function get_people_jsonresult(Optional id As Integer = 0) As JsonResult
Dim c As dtb_people = db.dtb_people.Where(Function(x) x.c_Id = 1).Single
Dim d As New Dictionary(Of String, String) From {
{"firstname", c.c_firstname},
{"lastname", c.c_lastname},
{"id", c.c_Id}
}
Return Json(d, JsonRequestBehavior.AllowGet)
End Function
However, it is unable to convert a string
! The reason is that it is expecting to serialize something. If you have a string
, your content is already serialized.
However, if you must, you can deserialize it to a dictionary
and then have the Json function serialize it again.
Function get_people_jsonresult(Optional id As Integer = 0) As JsonResult
Dim c As dtb_people = db.dtb_people.Where(Function(x) x.c_Id = 1).Single
Dim jsonstr As String = "{
'firstname':'" + c.c_firstname + "',
'lastname':'" + c.c_lastname + "',
'id':" + c.c_Id.ToString + "
}"
Dim d As Dictionary(Of String, String) = _
JsonConvert.DeserializeObject(Of Dictionary(Of String, String))(jsonstr)
Return Json(d, JsonRequestBehavior.AllowGet)
End Function
You can even skip the Json function and just create a new JsonResult
directly:
Return New JsonResult With {.Data = JsonConvert.DeserializeObject_
(Of Dictionary(Of String, String))(jsonstr), .JsonRequestBehavior = JsonRequestBehavior.AllowGet}
ContentResult
The next most common return method would be ContentResult
. ContentResult
comes in where you would like to use a string
either by manually creating one like that below. (If using double quotes, you need to escape them.)
Function get_people_ContentResult(Optional id As Integer = 0) As ContentResult
Dim c As dtb_people = db.dtb_people.Where(Function(x) x.c_Id = 1).Single
Dim jsonstr As String = "{
""firstname"":""" + c.c_firstname + """,
""lastname"":""" + c.c_lastname + """,
""id"":" + c.c_Id.ToString + "
}"
Return Content(jsonstr.Replace(vbCrLf, ""), "application/json")
End Function
Or if you are using the Newtonsoft library:
Function get_people_ContentResult(Optional id As Integer = 0) As ContentResult
Dim c As dtb_people = db.dtb_people.Where(Function(x) x.c_Id = 1).Single
Dim jsonstr As JObject = New JObject(
New JProperty("firstname", c.c_firstname),
New JProperty("lastname", c.c_lastname),
New JProperty("id", c.c_Id)
)
Return Content(jsonstr.ToString(), "application/json")
End Function
Here, we are using the Content
function to send the string
as is without re-serializing it. Since it doesn't know what type of data is being sent, we need to specifiy the mime type.
String
However, there a number of other ways to serialize content. Instead of serializing using Content
to return a ContentResult
, you can use any of these other methods and return the string
directly.
Function get_people_string(Optional id As Integer = 0) As String
Dim c As dtb_people = db.dtb_people.Where(Function(x) x.c_Id = id).Single
Dim m As Object = New With {.firstname = c.c_firstname, .lastname = c.c_lastname, .id = c.c_Id}
Dim serializer As New Script.Serialization.JavaScriptSerializer()
Return serializer.Serialize(m)
End Function
However, Microsoft suggests to use JSON.NET instead of this solution: https://msdn.microsoft.com/en-us/library/system.web.script.serialization.javascriptserializer.aspx
Here, I've used a string
literal to assemble the string
and call the response method directly.
Function get_people_string(Optional id As Integer = 0) As String
Dim jsonstr2 As String = $"{{
'firstname': '{c.c_firstname}',
'lastname':'{c.c_lastname}' ,
'id':{c.c_Id.ToString}
}}"
Response.Clear()
Response.ContentType = "application/json; charset=utf-8"
Response.Write(jsonstr)
Response.End()
End Function
And one last function that can be used is the JsonConvert
to serialize an object which requires the import of Newtonsoft.Json
.
Function get_people_ContentResult(Optional id As Integer = 0) As String
Dim d As New Dictionary(Of String, String) From {
{"James", 9001},
{"Jo", 3474},
{"Jess", 11926}
}
Return JsonConvert.SerializeObject(d, Formatting.Indented)
End Function
Wow, that's a lot of different ways! Hopefully you find this useful.
History
- 23rd January, 2018: Initial tip