Asmx response to json and call via ajax - json

I have the following problem
I am trying to connect a HTML page with a asmx service, using jquery.
The service is in my local IIS, and I have configured it for allow cross-domain request:
This is my service code:
[WebService(Namespace = "http://myservices.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ToolboxItem(false)]
[ScriptService]
public class Test : WebService
{
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public Employee TestMethod()
{
return new Employee { Id = 1, Name = "John"};
}
}
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
}
This is my web.config service code:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
<webServices>
<protocols>
<add name="HttpGet"/>
<add name="HttpPost"/>
</protocols>
</webServices>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
</customHeaders>
</httpProtocol>
<handlers>
<add name="ScriptHandlerFactory"
verb="*" path="*.asmx"
type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
resourceType="Unspecified" />
</handlers>
</system.webServer>
</configuration>
So, with that I can call to service method from anywhere (different domains) using this url
http://localhost/WsTest/Test.asmx/TestMethod
But, the response is in xml, why? ... I don't know what I need
<Employee xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://myservices.org/">
<Id>1</Id>
<Name>John</Name>
</Employee>
That is my first question.
Second, When I try to get the service response using ajax with the following code:
$.ajax({
url: "http://localhost/WsTest/Test.asmx/TestMethod",
beforeSend: function () {},
data: {},
contentType: "application/json; charset=utf-8",
type: "POST",
dataType: "jsonp",
processData: false,
cache: false,
success: function(data) {
alert(data)
},
error: function(jqXHR, textStatus, errorThrown) {
console.log("Retrieve Failed (AJAX Error): " + jqXHR.statusText + " | " + textStatus + " | " + errorThrown);
}
});
I get the following response:
TestMethod?callback=jQuery220045970173459500074_1454084649739&[object Object]&_=1454084649740:1
Uncaught SyntaxError: Unexpected token <
Retrieve Failed (AJAX Error): load | parsererror | Error: jQuery220045970173459500074_1454084649739 was not called
I have read several answers about this question, but i cannot find the appropriate answer for my problem.
Thanks in advance!

I think you are not properly serializing the response before sending it back to the client.
You have to make your class serializable into a Json string. To do that follow the instructions provided in the following MSDN link:
How to: Serialize and Deserialize JSON Data
Then, you should change your web method to return a String value, and just before returning the response to the client, do the serialization trick, something like this:
var objectSerializer = new JavascriptSerializer();
//serialization
return objectSerializer.Serialize(data); //this will return a Json string
For more details about the JavascriptSerializer class check out the following link:
JavaScriptSerializer Class
And about your error, it is because your response is returning in XML format (the standard SOAP response) thus the javascript code you are using is expecting a Json format. The trick is to simply return a Json string.
The other option you have is to use WCF instead of ASMX, but that is another path you can check out here:
How do I return clean JSON from a WCF Service?
Beware about the security risks involved in exposing your service like that. Use unique ids or other mechanisms to secure your web service invocations from Javascript.

Related

Ajax call fails when passing Json over certain size

I have the following code that passes a JSON object to an AJAX call...
var jsonResultStr = $j("#HiddenLiveJson").val();
var jsonResult = JSON.parse(jsonResultStr);
var serviceURL = appRoot + 'Register/ImportTasks'
$j.ajax({
type: "get",
url: serviceURL,
data: { 'jsonResultsStr': jsonResultStr },
contentType: "application/json; charset=utf-8",
dataType: "json",
success: successFunc,
error: errorFunc
});
The Json is sourced from an XLSX file so could potentially be any size.
If a relatively small JSON set is passed, say 7 items in the JSON, then the AJAX call passes successfully, the controller action is hit and my data is imported. However, if a larger JSON dataset is passed then it consistently fails (HTTP Status 400) without even going anywhere near the controller action. I don't seem to be able to find any suggestion anywhere what is causing this. My first guess, obviously, is the size of the XLSX file.
btw... The JSON used in my testing should be sound as the data that is failing is just the same data that succeeds but duplicated to double its size.
So far, I have tried
Adding this to my web.config:
<system.web.extensions>
<scripting>
<webServices>
<jsonSerialization maxJsonLength="1000000000">
</jsonSerialization>
</webServices>
</scripting>
</system.web.extensions>
And also this to the appSettings in web.config:
<add key="aspnet:MaxJsonDeserializerMembers" value="1500000000" />
And also setting the following:
<httpRuntime maxRequestLength="1000000000" .../>
None of which have made any difference.
Any more suggestions are greatly welcomed!
You need to use a POST request for large JSON object and also stringify the JSON data with contentType as "application/json" and dataType as "json".
Replace the 'data' parameter in the ajax call as :
data: JSON.stringify(jsonResult)
also in the server size script catch the client side data with a get POST method.
Hope this helps :)

Browser display json response from ActionResult on Azure Web app, but not on localhost

I am posting data to an Action, get json data as a result, and then, process the result in javascript.
It's work well on dev server, but when i publish it on Azure WebApp, when I post my data, it display the json on the screen.
The begining of my Form to post data :
#using (Ajax.BeginForm("UpdateAccount", "Loging",
new AjaxOptions
{
HttpMethod = "POST",
OnSuccess = "processAccountUpdateResult"
}))
{
Note: processAccountUpdateResult is the javascript function which process the json result.
Here is my action :
[HttpPost]
public ActionResult UpdateAccount(string newName)
{
return Json(new { result = "ok" }, "text/html", JsonRequestBehavior.AllowGet);
}
Note : I added the "text/html" mime type after I read this
But no luck.
I tried to add the json mimetype in the web.config, but still no luck :
<configuration>
<system.webServer>
<staticContent>
<mimeMap fileExtension=".json" mimeType="application/json"/>
</staticContent>
</system.webServer>
</configuration>
Thanks
To make it working, we need to add this to the web.config :
<add key="UnobtrusiveJavaScriptEnabled" value="true" />

Cross domain ajax request

I want to get the HTML response page from the cross-domain URL.
for this I am using the ajax request as,
$.ajax({
type: 'GET',
url: "http://wcidevapps.com/salescentral/idisk/0001000383/iDisk",
dataType: "json",
success: function (response) {
$(response).find('li a').each(function () {
listHref.push($(this).attr('href'));
});
}
});
But after requesting it doesn't respond with any result back.
<script src="Scripts/jquery-1.4.1.js" type="text/javascript"></script>
<script type="text/javascript">
function NameAFunctionName() {
$.ajax({
url: 'http://wcidevapps.com/salescentral/idisk/0001000383/iDisk',
type: 'GET',
dataType: 'json',
headers: {
//WRITE IF THEIR HAVE SOME HEADER REQUEST OR DATA
},
crossDomain: true,
success: function (data, textStatus, xhr) {
console.log(data);
},
error: function (xhr, textStatus, errorThrown) {
console.log(errorThrown);
}
});
}
</script>
Check documentation :
http://api.jquery.com/jQuery.ajax/
crossDomain (default: false for same-domain requests, true for cross-domain requests)
Type: Boolean
If you wish to force a crossDomain request (such as JSONP) on the same domain, set the value of crossDomain to true. This allows, for example, server-side redirection to another domain. (version added: 1.5)
My suspicion is that you see the issue because the page you're requesting does not respond with a json(p) response, but responds with a redirect to:
http://wcidevapps.com/salescentral/idisk/0001000383/iDisk/
(note the trailing slash)
which then returns content type:
Content-Type:text/html;charset=ISO-8859-1
Edit: If your intention is to retrieve the above site's data cross-domain, for further parsing by your script, I suggest that you choose one of the following:
Assumption 1: YOU are in control of the pages on server "http://wcidevapps.com"
In that case, you have two options: Either add CORS header "Access-Control-Allow-Origin: *" to the response (and configure the client ajax() call with dataType:"html"), or create a special JSON(P) page that delivers the same data as JSON (with padding) (and configure the client ajax() call like in the OP, with dataType:"jsonp")
Assumption 2: YOU are NOT in control of the pages on server http://wcidevapps.com
In that case, the only option I can think of is setup a proxy on a site that you control. Have that proxy "proxy" the requests/responses to "http://wcidevapps.com", but add the CORS header "Access-Control-Allow-Origin: *" to the response (and configure the client ajax() call with dataType:"html")
If you are using asp.net web service then you need to add this to webconfig file;
<system.webServer>
<directoryBrowse enabled="true"/>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
</customHeaders>
</httpProtocol>
</system.webServer>

JSON - Spring MVC : How to post json data to spring MVC controller

I have a problem posting JSON data from jsp to controller. Everytime I try I get an ajax error Bad Request. Im so new to JSON and I really don't know what I am doing wrong. I searched and tried some samples I can find in this site but still Im having a problem.
In my controller:
#RequestMapping (method = RequestMethod.POST, headers ={"Accept=application/json"}, value = "/form")
public String postJournalEntry (#RequestParam ("json") String json, Model model) {
System.out.println(json);
return "successfullySaved";
}
In my jsp:
$("#btnPostGlEntry").click(function () {
var glEntries = '{"glEntries":[{"generalLedgerId":"1"},{"accountId":"4"},{"amount":"344.44"},{"description":"Test Entry"},{"debit":"Yes"}]}';
$.ajax({
type: "POST",
contentType: "application/json",
dataType: "json",
url: contextPath + "/generalLedger/journalEntries/form",
data : JSON.stringify(glEntries),
success: function(data) {
alert("Success!!!");
},
error: function (jqXHR, textStatus, errorThrown) {
alert(jqXHR + " : " + textStatus + " : " + errorThrown);
}
});
});
NOTE : Im not even sure if my function in my controller is correct. I think my controller and my ajax are wrong. Please help.
If you want your JSON to be deserialized into some class, than you have to define method like this (and don't forget to add jsonConverter, as in previous answer):
.... method(#RequestBody MyClass data){ ... }
But, if you want your method to accept JSON as String than do this:
.... method(#RequestBody String json){ ... }
So, basically, if you post JSON, it means that JSON is not a parameter, it is body of the request. And eventually you have to use #RequestBody annotation, instead of #RequestParam.
You can find beautifull video tutorial of Spring Mvc and JSON here: sites.google.com/site/upida4j/example
it seems you dont have a Json Converter configured properly
like this one
<bean id="jacksonMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="jacksonMessageConverter"/>
</list>
</property>
</bean>

Calling WCF services from Javascript with UriTemplate and POST data

I've got a WCF 4.0 service that's currently set up for HTTP GET requests. I'm trying to modify it so that it uses POST, but keep backwards compatibility with the existing GET URIs. The web service is being called with jQuery and JSON data. Therefore, my requirements are the following:
Match the existing GET URI, presumably by using the UriTemplate parameter of the WebInvoke attribute.
Get the existing parameters from JSON data in the POST body, presumably by using WebMessageBodyStyle.Wrapped and WebMessageFormat.Json with the WebInvoke attribute.
Preferably have a way to pull large blobs of a data out of the POST body, probably also wrapped in a JSON object.
Alright, with that out of the way, here's what I've got so far. My little test service is called AjaxService and it's got one method called ToUpper. First, my web.config:
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="WebApplication2.AjaxServiceAspNetAjaxBehavior">
<!--<enableWebScript />-->
<webHttp helpEnabled="true" />
</behavior>
</endpointBehaviors>
</behaviors>
<protocolMapping>
<remove scheme="http" />
<add scheme="http" binding="webHttpBinding" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<services>
<service name="WebApplication2.AjaxService">
<endpoint address=""
behaviorConfiguration="WebApplication2.AjaxServiceAspNetAjaxBehavior"
binding="webHttpBinding"
contract="WebApplication2.AjaxService" />
</service>
</services>
</system.serviceModel>
</configuration>
The following version of my ToUpper function allows me to pass its argument in the URI just like an HTTP GET.
[OperationContract]
[WebInvoke( UriTemplate="ToUpper?str={str}",
Method = "POST",
BodyStyle = WebMessageBodyStyle.WrappedRequest,
RequestFormat=WebMessageFormat.Json,
ResponseFormat=WebMessageFormat.Json)]
public string ToUpper(string str)
{
return str.ToUpper();
}
It's used in Javascript as follows and correctly returns "THIS IS FROM THE URI".
$(document).ready(function () {
$.ajax({
type: "POST",
url: "AjaxService.svc/ToUpper?str=this%20is%20from%20the%20uri",
contentType: "application/json; charset=utf-8",
success: function (data) {
console.log("result: " + JSON.stringify(data));
},
error: function (jqXHR, textStatus, errorThrown) {
console.log("error", jqXHR, textStatus, errorThrown);
}
});
});
I can put the parameter in the POST data instead of the URI by removing UriTemplate="ToUpper?str={str}" from the WebInvoke parameters and using this javascript instead. It correctly returns "THIS IS FROM THE POST".
$(document).ready(function () {
$.ajax({
type: "POST",
url: "AjaxService.svc/ToUpper",
data: JSON.stringify({str:"This is from the POST"}),
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function (data) {
console.log("result: " + JSON.stringify(data));
},
error: function (jqXHR, textStatus, errorThrown) {
console.log("error", jqXHR, textStatus, errorThrown);
}
});
});
I was hoping that if I left the UriTemplate="ToUpper?str={str}" in place and use the above javascript, it would be smart enough to pull the str parameter out of the POST data instead of the URI. Unfortunately, it just gives me an error 400. Is there a way to make that work?
One other thing I tried is using the optional Stream parameter to get at the raw contents of the POST data. But as this blog post points out, you can only get that stream if you set the content type to plain text instead of JSON. I could do that and manually parse the stream, but I think I'd also need to manually examine the URL to figure out if I got real values or defaults. Yuck.
If there's no way to make this work with the system bindings/settings, I was thinking about trying to write a custom binding that would be smart about pulling parameters out of the POST and URI, and also give you that raw stream even when you're using JSON. I spent a few hours trying to figure out how to do that but I'm stumped!
Has anyone else tackled this one or have any ideas on how to make it work? I can't imagine I'm the first one to have tried doing this, but I've come up empty handed after doing lots of searching.