Escaped JSON response with [WebMethod] - asp.net

The JSON response from the following code is wrongly escaped as described below.
My webmethod is like this:
[WebMethod (Description="doc here")]
[ScriptMethod(ResponseFormat=ResponseFormat.Json)]
public string responseMyObject() {
if (!Setup()) return "";
...
Proxy pu = new Proxy(...);
...
string toReturn = JavaScriptConvert.SerializeObject(pu.getMyObject());
Console.WriteLine(toReturn);
return toReturn;
}
from the console I get:
{"field1":vaule1,"field2":value2}
from JS:
$.ajax({
type: "POST",
url: "/myapi/myClass.asmx/responseMyObject",
data: "{}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(msg) {
var object = msg.d;
alert(object.field1);
}
});
The problem is that in the HTTP response header I can see that the JSON response is wrongly (?) escaped in the following way:
{"d":"{\"field1\":value1,\"field2\":value2}"}
What's strange is that the console print is fine (but not yet encapsulated in {d: ...}
{"field1":value1,"field2":value2}
With similar code, if I call a [WebMethod] that returns basic types (no object) the JSON response is ok. Like:
{"d":8080}

[WebService]
[ScriptService]
public class MyWebService : WebService
{
[WebMethod (Description="doc here")]
[ScriptMethod( UseHttpGet=false, ResponseFormat=ResponseFormat.Json)]
public MyObjectType responseMyObject()
{
Proxy pu = new Proxy(...);
return pu.GetMyObject();
}
}
You dont need a JSON serializer, tagging it with the ScriptService attribute gives it tie ability to serialize JSON out. You were pre serializing the JSON and then serializing it again :(

Why are you calling JavaScriptConvert.SerializeObject?
Can't you just change the return type of your method to be the type returned by pu.getMyObject() and the framework will do the rest?
In other words...
[WebMethod (Description="doc here")]
[ScriptMethod(ResponseFormat=ResponseFormat.Json)]
public MyObjectType responseMyObject()
{
Proxy pu = new Proxy(...);
...
return pu.GetMyObject();
}
At the moment I think you're serializing your object into a JSON format and then, when you return from the method, the framework is serializing that string (which contains JSON formatted data) into a JSON format.

Related

AJAX Passing multiple parameter to WebApi

AJAX request:
$.ajax({
url: url,
dataType: 'json',
type: 'Post',
data: {token:"4", feed:{"id":0,"message":"Hello World","userId":4} }
});
Server Side Web API:
[HttpPost]
public HttpResponseMessage Post(string token, Feed feed)
{
/* Some code */
return new HttpResponseMessage(HttpStatusCode.Created);
}
Error Code 404: {"message":"No HTTP resource was found that matches
the request URI 'localhost:8080/api/feed'.","messageDetail":"No action
was found on the controller 'Feed' that matches the request."}
Why I am getting this error and Why I am not able POST multiple parameters to my API?
Start by writing a view model:
public class MyViewModel
{
public string Token { get; set; }
public Feed Feed { get; set; }
}
that your controller action will take as parameter:
[HttpPost]
public HttpResponseMessage Post(MyViewModel model)
{
/* Some code */
return new HttpResponseMessage(HttpStatusCode.Created);
}
and finally adapt your jQuery call to send it as JSON:
$.ajax({
url: url,
type: 'POST',
contentType: 'application/json',
data: JSON.stringify({
token: '4',
feed: {
id: 0,
message: 'Hello World',
userId: 4
}
})
});
Important things to note for the AJAX call:
setting the request contentType to application/json
wrapping the data in a JSON.stringify function to effectively convert the javascript object to a JSON string
removed the useless dataType: 'json' parameter. jQuery will automatically use the Content-Type response header sent by the server to deduce how to parse the result passed to the success callback.
Try this server-side (from memory you can only have a single FromBody parameter so it needs to contain all the incoming properties):
public class TokenAndFeed
{
public String token {get; set;}
public Feed feed {get; set;}
}
public HttpResponseMessage Post([FromBody]TokenAndFeed tokenAndFeed)
{
/* Some code */
return new HttpResponseMessage(HttpStatusCode.Created);
}
I had a similar problem recently and here's some info on how I solved it. I think the problem is to do with how WebApi handles parameters. You can read a bit about it here and here but essentially there are two ways to post parameters, in the body or in the uri. The body can only contain one parameter, but it can be a complex parameter, whereas the uri can contain any number of parameters (up to the uri character limit) but they must be simple. When jquery does a POST ajax call it tries to pass all data parameters in the body, which does not work in your case since the body can only have one parameter.
In code terms I think you need something like this:
var token = "4";
var feed = {Id:0, Message:"Hello World", UserId:4};
$.ajax({
url: "/api/Feed/?token=" + token,
dataType: 'json',
type: 'Post',
data: JSON.stringify(feed)
});
Hope that helps.
Can you post your Feed class, just to make sure the properies match up.
var data = {
token: "4",
feed: {Id:0,Message:"Hello World",UserId:4}
}
$.ajax({
url: "/api/Feed/",
dataType: 'json',
type: 'Post',
data: JSON.stringify(data)
});
Try with this one. You have to get json object data from body. Read Request's input streem and map it to your data model.
public class TokenAndFeed
{
public string Token { get; set; }
public Feed Feed { get; set; }
}
[HttpPost]
public HttpResponseMessage Post()
{
System.IO.Stream str;
String jsonContents;
Int32 strLen, strRead;
str = HttpContext.Current.Request.InputStream;
strLen = Convert.ToInt32(str.Length);
byte[] byteArray = new byte[strLen];
strRead = str.Read(byteArray, 0, strLen);
jsonContents = Encoding.UTF8.GetString(byteArray);
TokenAndFeed tAndf = JsonConvert.DeserializeObject<TokenAndFeed>(jsonContents);
// some code here
return new HttpResponseMessage(HttpStatusCode.Created);
}
hope this will help.

ASP.NET WebAPI throw 404 if method parameter is string or int

I did a very simple test on ASP.NET MVC4 WebAPI and found some interesting issue:
When a method is taking complex type, it will work, but when it takes string or int, it will throw 404, as the screen shot given: The "AddProduct" works, but "Test" and "Test1" is always not found.
How should I invoke the method correctly?
You need to decorate your string or int parameter with the [FromBody] attribute.
[HttpPost]
public string Test([FromBody]string username)
[HttpPost]
public int Test1([FromBody]int value)
try this:
the website is accept the value by "[FormBody]", so you should be post by "={0}"
({0} is replaced by your string data)
$.ajax({
url: "api/values",
data: "='hello world'",
dataType: "text",
type: "POST",
success: function (data) {
$("#result").val(data);
},
fail: function (data) {
alert(data);
}
});
see also this answer:
POST a string to Web API controller in ASP.NET 4.5 and VS 2012 RC
Have you tried,
$.ajax({
url : "/api/product/test",
data : { username : "edi" },
dataType : "json",
type : "POST",
success : function(res){ console.log(res); },
error : function(req, stat, err){ console.log(stat + ": " + err); }
});
Right now it's failing becuase you've wrapped your entire json object (in the jquery ajax method) in quotes.
Try without the quotes and let me know!
Also,
When testing single variables like string username and int value take a note that WEB API will expect it exactly like that.
This guy,
[HttpPost]
public string Test1(int value) { ... }
Will look for a post that matches this url signature (im using HTTPIE)...
$ http POST http://yourwebsite.com/api/test1 value=1
Where the "4" is the value of the variable "value" in that Test1 method.
More about HTTPIE here: Scott Hanselman on installing HTTPIE
Hope that helps!
I searched nearly a day for this because I want my data to be a JSON, so assuming you need to post one value here it is:
INT:
$.post('/api/mywebmethod', { "": 10 })
STRING
$.post('api/mywebmethod', { "": "10" });
CONTROLLER
[HttpPost]
public IHttpActionResult MyWebMethod([FromBody]int id)
{
//do work
}
using Route
[RoutePrefix("api/Product")]
public class ProductController:ApiController
{
[Route("Add"),HttpPost]
public string AddProduct(Product productModel)
[Route("Test"),HttpPost]
public string Test(string userName){}
}
call: localhost:xx//api/product/Add

Response.Write() in WebService

I want to return JSON data back to the client, in my web service method. One way is to create SoapExtension and use it as attribute on my web method, etc. Another way is to simply add [ScriptService] attribute to the web service, and let .NET framework return the result as {"d": "something"} JSON, back to the user (d here being something out of my control). However, I want to return something like:
{"message": "action was successful!"}
The simplest approach could be writing a web method like:
[WebMethod]
public static void StopSite(int siteId)
{
HttpResponse response = HttpContext.Current.Response;
try
{
// Doing something here
response.Write("{{\"message\": \"action was successful!\"}}");
}
catch (Exception ex)
{
response.StatusCode = 500;
response.Write("{{\"message\": \"action failed!\"}}");
}
}
This way, what I'll get at client is:
{ "message": "action was successful!"} { "d": null}
Which means that ASP.NET is appending its success result to my JSON result. If on the other hand I flush the response after writing the success message, (like response.Flush();), the exception happens that says:
Server cannot clear headers after HTTP headers have been sent.
So, what to do to just get my JSON result, without changing the approach?
This works for me:
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public void ReturnExactValueFromWebMethod(string AuthCode)
{
string r = "return my exact response without ASP.NET added junk";
HttpContext.Current.Response.BufferOutput = true;
HttpContext.Current.Response.Write(r);
HttpContext.Current.Response.Flush();
}
Why don't you return an object and then in your client you can call as response.d?
I don't know how you are calling your Web Service but I made an example making some assumptions:
I made this example using jquery ajax
function Test(a) {
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: "TestRW.asmx/HelloWorld",
data: "{'id':" + a + "}",
dataType: "json",
success: function (response) {
alert(JSON.stringify(response.d));
}
});
}
And your code could be like this (you need to allow the web service to be called from script first: '[System.Web.Script.Services.ScriptService]'):
[WebMethod]
public object HelloWorld(int id)
{
Dictionary<string, string> dic = new Dictionary<string, string>();
dic.Add("message","success");
return dic;
}
In this example I used dictionary but you could use any object with a field "message" for example.
I'm sorry if I missunderstood what you meant but I don't really understand why you want to do a 'response.write' thing.
Hope I've helped at least. :)

Calling ASP.NET web service function via GET method with jQuery

I'm trying to call web service function via GET method using jQuery, but having a problem. This is a web service code:
[WebService(Namespace = "http://something.com/samples")]
[ScriptService]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class TestWebService : System.Web.Services.WebService {
[WebMethod]
public string Test2()
{
string result = null;
try
{
result = "{'result':'success', 'datetime':'" + DateTime.Now.ToString() + "'";
}
catch (Exception ex)
{
result = "Something wrong happened";
}
return result;
}
}
That's the way I call the function:
$.ajax({ type: "GET",
url: "http://localhost/testwebsite/TestWebService.asmx/Test2",
data: "{}",
contentType: "application/json",
dataType: "json",
error: function (xhr, status, error) {
alert(xhr.responseText);
},
success: function (msg) {
alert('Call was successful!');
}
});
Method is called successfully, but result string gets covered by XML tags, like this:
<string>
{'result':'success', 'datetime':'4/26/2010 12:11:18 PM'
</string>
And I get an error because of this (error handler is called). Does anybody know what can be done about this?
Enable ASP.NET ASMX web service for HTTP POST / GET requests
[WebMethod]
[ScriptMethod(UseHttpGet = true)]
public string Test2()
{
[...]
}
Rule for json:
You can only access data from the same domain!
The only exception is when using jsonp (which is quite complicated to implement since there is no jsonp serializer in the .NET framework).
If your are using a standard web service (and not WCF) you can find guidance howto implement this here.
Make sure to add this to your ajax options:
contentType: "application/json; charset=utf-8"
Your overall request should look like this to get json back instead of XML:
$.ajax({ type: "GET",
url: "http://localhost/testwebsite/TestWebService.asmx/Test2",
data: "{}",
contentType: "application/json",
dataType: "json",
contentType: "application/json; charset=utf-8".
error: function (xhr, status, error) {
alert(xhr.responseText);
},
success: function (msg) {
alert('Call was successful!');
}
});
ScottGu has a full breakdown on what's required here, but it looks like the missing contentType in your case (that one drove me nuts for a while too).
You might try setting the ResponseFormat on your methods. See http://williamsportwebdeveloper.com/cgi/wp/?p=494 to see how they did it for JSON. It probably just defaults to XML.
You need to decorate the method with the ScriptMethodAttribute:
[WebService(Namespace = "http://something.com/samples")]
[ScriptService]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class TestWebService : System.Web.Services.WebService {
[WebMethod]
[ScriptMethod]
public string Test2()
{
[...]
}
}
This will ensure that the method returns JSON by default (the default value of ResponseFormat is Json).
Did you try WebInvokeAttribute, it has members that define Request & Response formats where you can set to WebMessageFormat.Json.
Something like:
[WebInvoke(UriTemplate = "ServiceName", RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare,
Method = "POST")]
You can use http handler instead of
web service.
You can parse xml response with
javascript on the client.

jQuery and parsing JSON in the callback

I'm using jQuery to call an asmx and return some data. I'm making the call like this
function getRequestInfo(event) {
var id = $('#<%= RequestDaysId.ClientID %>').val();
var formattedId = "{'id': '115'}";
$.ajax({
type: "Post",
url: "services/VacationServices.asmx/GetVacationInfo",
data: "{'id': '" + id + "'}",
dataType: "json",
contentType: "application/json; charset=utf-8",
processdata: true,
success: function(data) {
$('#<%=Note.ClientID %>').val(data.Note);
$('.pendingrequestinfo').show().fadeIn(2000);
},
error: function(result, errortype, exceptionobject) {
$('.failureMessage').fadeIn(2000).fadeOut(2000);
}
})
};
Everything seems to be working fine, I set a break point in my success function and inspect the data object and see this.
"{"Note":"this is a note","dayInfo":[{"ShortDate":"3/4/2010","DayType":"Vacation","HalfDay":""},{"ShortDate":"3/5/2010","DayType":"Vacation","HalfDay":""}]}"
The problem comes when I try to get the values out of the JSON. If I do something like data.Note, I get undefined back.
It's late, It's Saturday and I've been at it all day, I sure would like a push in the right direction when it comes to parsing though my JSON.
EDIT:
I'm using Asp.net and JavaScriptSerializer.Serialize() to create the JSON. When I set a break point and inspect the 'data' object it looks to have a property d that contains the string that should be JSON.
ANOTHER EDIT:
If I do something like this in my success
$('#<%=Note.ClientID %>').val(data.d.[0]);
I get the { opening curly brace. I guess i'm getting a string instead of JSON, but it seems to go against what the jquery api states about the return value when the datatype is set to JSON.
Thanks guys.
Jim
First make sure that the JSON string exists in the "d" variable in the response returned in the success callback. Next, in order to get the JSON object you will need to convert the string into the JSON. You can use the eval function or the JQuery built in function to convert string to JSON. I like the jquery-json plug in to convert string into JSON representation.
Your code will look something like this:
var jsonObject = eval('(' + data.d + ')');
Now, you can use jsonObject.Note or any other property.
With jquery-json plugin you can do the following:
var note = $.evalJSON(data.d).Note;
That's not a valid JSON format. Remove the doublequotes at beginning and end to make it fullworthy JSON.
This one is so silly...sorry guys. When returning data from the asmx there is no need to serialize it into JSON
I have the following class that I'm populating and returing from my web method
public class VacationInfo
{
public string Note { get; set; }
public List<DayInfo> dayInfo { get; set; }
public VacationInfo(string note, List<DayInfo> dayinfo)
{
this.Note = note;
this.dayInfo = dayinfo;
}
public class DayInfo
{
public string ShortDate { get; set; }
public string DayType { get; set; }
public string HalfDay { get; set; }
public DayInfo(string shortdate, string daytype, string halfday)
{
this.ShortDate = shortdate;
this.DayType = daytype;
this.HalfDay = halfday;
}
}
}
as long as your web service is decorated with
[System.Web.Script.Services.ScriptService]
your object will be serialized and returned as JSON at no charge to you. :)
then I'm able to do this
data.d.Note
in my call back.
Thanks for the help guys.
Credit where credit is due
Here is how I process. Note the dataFilter: part - this makes it work with either newer or older asp.net stuff.
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
data: objectSaveData,
dataFilter: function(data)
{
var msg;
if (typeof (JSON) !== 'undefined' &&
typeof (JSON.parse) === 'function')
msg = JSON.parse(data);
else
msg = eval('(' + data + ')');
if (msg.hasOwnProperty('d'))
return msg.d;
else
return msg;
},
url: "/mywebservice.asmx/myMethodName",
success: function(msg)
{
//do stuff
},
failure: function(msg)
{
//handlefail
}
});

Resources