I have a use case where I am posting a complex object with an array member using jQuery. E.g.:
data: {
obj1: obj1,
arr1: [ ... ]
}
On the server I have implemented a ServiceStack service. The automatic request mapping on the server produces nulls for the request members, but if I extract the Request.GetRawBody(), and then use ServiceStack.Text.JsonSerializer.DeserializeFromString, I get what I need.
It would be useful to debug the actual deserialization and see what is missing. Anyone know how to do this?
Examples:
Pass in a flat object
Define a simple request object with a few fields:
public class Request
{
public string Name { get; set; }
}
Make a jQuery ajax call:
$.ajax({
//...
data: {
name: 'John Doe'
}
});
The call works, the server receives the object with "John Doe" name property.
Pass object with child-object
public class Request
{
public Caller Caller { get; set; }
}
public class Caller
{
public string Name { get; set; }
}
Then make a call from jQuery:
$.ajax({
// ...
data: {
caller: {
name: 'John Doe'
}
}
});
After the call, the "caller" property of the request on the service is "null", so this approach is not working.
Conclusion
In my original assessment I was referring to an object and array combination. I guess the problem is in getting a simple sub-object to serialize/deserialize. Does this means the concept is not supported, or am I passing the object in incorrectly?
If you really think its something wrong with the actual deserialization then I would recommend downloading the source code from github and trying to create failing unit tests. If you think its with the json deserialization then download the ServiceStack.Text project. Otherwise you should download the main ServiceStack project. Reading the existing unit tests are quite informative to how the entire project works.
However, chances are it is invalid json notation. It is often useful to reverse engineer the json by comparing the results from Serializing your DTO to what you are actually passing into the ajax call.
Updated: Your json should look like this:
{"Caller":{"Name":"John Doe"}}
The easy way to check this is to do the following:
var r = new MyRequest() {Caller = new Caller() {Name = "John Doe"}};
var json = r.ToJson();
I have figured out the issue, hope the answer helps others. It turns out that $.ajax is sending the content type as form url encoded (which is clearly documented in the jQuery documentation, I had just missed it):
http://api.jquery.com/jQuery.ajax/
Setting the contentType to 'application/json' resolved the issue, now all data is properly deserialized on the server.
Related
I am using GetOrgChart, and I really like it. They have a load from JSON example and their javascript code from their demos looks like this:
<script type="text/javascript">
$.getJSON("http://www.getorgchart.com/JsonInitialization/Read?callback=?", function (source) {
var peopleElement = document.getElementById("people");
var orgChart = new getOrgChart(peopleElement, {
theme: "helen",
primaryFields: ["Name", "Title"],
photoFields: ["Image"],
linkType: "M",
enableEdit: false,
enableDetailsView: false,
dataSource: source
});
});
</script>
The URL to get the JSON looks like:
http://www.getorgchart.com/JsonInitialization/Read?callback=?
but really, you just need:
http://www.getorgchart.com/JsonInitialization/Read
and this gets back this code:
callback( ...JSON here ... );
so, not just JSON, but a callback function.
Now, I have a Spring 4 MVC RESTful function that returns the correct JSON.
But, If I just use the URL to get the JSON, such as:
http://127.0.0.1:8080/myapp-be/api/orgCharts/contactId/7
I get two nodes that I am expecting, but no lines to connect them. In this case I think I need to change the URL to:
http://127.0.0.1:8080/myapp-be/api/orgCharts/contactId/7?callback=?
and I think instead of returning just JSON data, I need to return:
callback( ...JSON here ... );
My RESTful web-service I have defined in Spring is as follows:
#RequestMapping(value = "/opportunityId/{opportunityId}",
method = RequestMethod.GET,
headers = "Accept=application/json",
produces = MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody List<ChartNodeDTO> getOrgChartData(#PathVariable long contactId)
{
List<ChartNodeDTO> orgChartList = orgChartService.getOrgChartByContactId(contactId);
return orgChartList;
}
The question is ... do I change this to return a String? On the back-end, I can create a String such as: String data = "callback(" + json + ");";
But this doesn't seem like the correct way.
I want to return the Javascript code, but I am just tweaking the Spring REST parameters, and doing trial and error before finding the correct solution.
I figured if someone can save me some time, that would be great ... and in the meantime, I will keep trying different things.
Thanks!
I am new to JAX-RS and trying to build a simple website interface.
So I have written a function returning a JSON object
like this:
#GET
#Path("/mypath")
#Produces (Mediatype.APPLICATION_JSON)
public String returnJson() {
String json = //.... fill String
return json;
}
which works well when browsing to this path.
On the other hand I have a UI page like this:
#GET
Produces(MediaType.TEXT_HTML)
public InputStream viewUI() throws FileNotFoundException {
File page = new File("page.html");
return new FileInputStream(page);
}
which works also.
Next thing I want to do is filling a dropdown list in my page.html with JavaScript, which also should not be a problem.
But I dont know how to get the JSON object to the JavaScript array (in page.html).
First of all, when using jaxrs, you don't need to convert objects to json. This is done automatically by jaxrs. Your method should return an object. As you asking to convert json into array, I assume, your method should return a List. Regarding of how to call and consume results from the rest service, as per Luts Horn comment, you need to use some sort of client side library, for example jquery.
You can look here http://www.tutorialspoint.com/jquery/jquery-ajax.htm
I am building a SPA and are using BreezeJS for data management. Now I want to be able to set processed data on my model class that are not present in the database and send it up the client. The problem is that breeze also ignores these properties.
public class MyModel{
public int Id{get; set;}
public string Name{get; set;}
public string ProcessedData{get; set;}
}
...
Ignore(model=> model.ProcessedData);
I realize that Breeze uses the same metadata as my datacontext, but there should be a way to override it.
The ignored properties is sent by the controller as json, it's just a matter of making breeze parse it as I need it to.
I haven't confirmed this but I think that if your are sure that the data is being returned from the server then you can add "unmapped" properties with the correct names to the Breeze client and it will materialize these as well. See the "unmapped" discussion here: http://www.breezejs.com/documentation/extending-entities .
Or you could try this ( I haven't actually tested this) AFTER the metadata has already been returned.
var dp = new breeze.DataProperty( {
nameOnServer: "ProcessedData",
dataType: "String",
isUnmapped: true
});
myEntityManager.metadataStore.getEntityType("MyModel").addProperty(dp);
and then try your query.
Note: only "unmapped" properties can be added to the EntityType after the EntityType has been itself added to a MetadataStore.
I'm trying to POST JSON formatted data from Javascript (using Prototype) to Grails. My Javascript code is:
var JSONObject = new Object;
JSONObject.id = "23";
JSONObject.name = "Test 1";
JSONstring = JSON.stringify(JSONObject);
var url = "${createLink(controller:'testController', action:'receiveJson')}";
new Ajax.Request(url, {
method:'post',
contentType:'application/json',
parameters:JSONstring,
asynchronous:true,
onSuccess: function (req) {
sendInfoResponse(req.responseText);
}
});
and the code in my Grails controller is:
def receiveJson = {
def json = request.JSON;
}
However, the 'json' variable appears to be empty in my tests. I'd be so grateful if someone could explain what I'm doing wrong. Many thanks.
In your Ajax.Request options change
parameters:JSONstring,
to
postBody:JSONstring,
The problem with using parameters is that it URL encodes the data so that the request body ends up looking like this:
%7B%22id%22%3A%2223%22%2C%22name%22%3A%22Test%201%22%7D&_=
Instead of the desired (which is what you get with postBody):
{"id":"23","name":"Test 1"}
Good question mfloryan - I was doing the testing manually, i.e. not as part of a unit or integration test.
Thanks very much for the help hvgotcodes. I made the changes to my code as you have suggested, but unfortunately to no avail. Interestingly, if I print request.JSON I get {}, whereas if I print request.json I get null.
EDIT: By 'printing' I mean using: request.JSON.toString()
EDIT: Thank you all so much for the help. Once I'd made the final change John Wagenleitne suggested the code began working properly. I'm very grateful indeed for all your help.
I don't think you are invoking the Ajax.Request correctly. From the documentation, the parameters option:
"The parameters for the request, which will be encoded into the URL for a 'get' method, or into the request body for the other methods. This can be provided either as a URL-encoded string or as any Hash-compatible object (basically anything), with properties representing parameters."
I think you need to do something like
...
parameters: {json: JSONString}
...
and then in your controller
request.json
note the form of the parameters object literal - it tells the Prototype library to make the request key 'json' and the request value be the json string. You access the key off the request object in the controller.
EDIT -- I just realized you're javascript block is jacked up.
This:
var JSONObject = new Object;
should be something like
var JSONObject = new Object();
...
you might also be able to do just an object literal, so
var jsonObject = {};
....
I have the following test method:
Imports System.Web
Imports System.Web.Services
Imports System.Web.Services.Protocols
<WebService(Namespace:="http://tempuri.org/")> _
<WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _
<System.Web.Script.Services.ScriptService()> _
Public Class DemoService
Inherits System.Web.Services.WebService
<WebMethod()> _
Public Function GetCustomer() As String
Return "Microsoft"
End Function
End Class
Even with the ResponseFormat attribute added the response is still being returned as XML rather than JSON.
Thoughts appreciated.
I'm a bit late to this question, but hopefully this helps you or anyone else stumbling onto this thread later.
You definitely can use ASMX services to communicate in JSON.
Your service code looks okay. Since you aren't showing how you're calling it, I'll bet that's where your problem lies. One requirement for getting JSON out of ASMX "ScriptServices" is that you must call them with the correct content-type header and you must use a POST request. Scott Guthrie has a good post about the reasoning behind those requirements.
So, if you just request DemoService.asmx/GetCustomer in a browser, you're going to get XML. However, if you make a POST request with an application/json content-type, you'll get the same result serialized as JSON.
If you're using jQuery, here's an example of how you would request your DemoService on the client-side:
$.ajax({
type: "POST",
contentType: "application/json",
url: "DemoService.asmx/GetCustomer",
data: "{}",
dataType: "json",
success: function(response) {
// Prints your "Microsoft" response to the browser console.
console.log(response.d);
}
});
More here: http://encosia.com/2008/03/27/using-jquery-to-consume-aspnet-json-web-services/
Do you have .NET 3.5 or greater installed?
ScriptServiceAttribute is in .NET 3.5 and 4.0.
Also, clear your ASP.NET temp files, the dynamic proxy could be cached.
Why not just use an ashx file? It's a generic handler. Very easy to use and return data. I use these often in place of creating a web service as they are much lighter.
An example of the implementation in the ashx would be:
// ASHX details
DataLayer dl = GetDataLayer();
List<SomeObject> lst = dl.ListSomeObjects();
string result = "";
if (lst != null)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
result = serializer.Serialize(lst);
}
context.Response.ContentType = "application/json";
context.Response.Write(result);
context.Response.End();
If you do need to use a web service though you could set the ResponseFormat. Check out this SO question that has what you are looking for:
How to let an ASMX file output JSON
This is what I do, though there is probably a better approach, it works for me:
[WebMethod]
[ScriptMethod(UseHttpGet = false, ResponseFormat = ResponseFormat.Json)]
public string retrieveWorkActivities(int TrackNumber)
{
String s = {'result': 'success'};
return s.ToJSON();
}
If you're restricted to the 2.0 Framework, you can use the JavaScriptSerializer, from the System.Web.Extensions assembly, like this (in C#):
[WebMethod()]
[ScriptMethod()]
public static string GetJsonData() {
// data is some object instance
return new JavaScriptSerializer().Serialize(data);
}
I've used ashxes for this problem too. To be honest I didn't know webservices had that ResponseFormat attribute. That said I think I still prefer the ashx route for lightness and control.
There's some peripheral details left out here, to concentrate on the bit you'd need.
Imports Newtonsoft.Json
Imports Newtonsoft.Json.Linq
Namespace Handlers.Reports
Public MustInherit Class Base
Implements IHttpHandler, SessionState.IRequiresSessionState
Protected data As String()() = Nothing
Private Shared ReadOnly JsonContentType As String = "application/json"
Public Sub ProcessRequest(ByVal context As System.Web.HttpContext) Implements System.Web.IHttpHandler.ProcessRequest
Try
Me.GetData()
Me.BuildJsonResponse(context)
Catch ex As Exception
End Try
context.Response.End()
End Sub
Private Sub BuildJsonResponse(ByVal context As System.Web.HttpContext)
context.Response.AddHeader("Content-type", Base.JsonContentType)
Dim json = Me.BuildJson()
context.Response.Write(json)
End Sub
Private Function BuildJson() As String
If Not Me.data Is Nothing Then
Return String.Format("{{data: {0}, pageInfo: {{totalRowNum:{1}}}, recordType: 'array'}}", JsonConvert.SerializeObject(Me.data), Me.totalRows)
End If
Return String.Empty
End Function
End Class
End Namespace
Sorry to answer for old post. if we need to return json of a specific object then we can follow this approach too.
[WebService(Namespace = "http://contoso.com/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]System.Web.Services.WebService
[ScriptService]
public class services :WebService
{
[WebMethod(CacheDuration = 60)]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public List<TestObject> GetObjectCollection()
{
return YourService.GetObjectCollection().ToList();
}
}
good article exist from this link https://cmatskas.com/getting-json-data-using-an-asmx-web-service/