asmx round trip json - c#

I am calling an asmx webservice which returns json (msg.d) that is consumed properly by knockout.js. When I attempt to return the identical json to asmx, I get error messages. Is there something obvious I'm missing? ... msg.d is a well formed object array.
calling storeGroupCategories(msg.d); returns webservice error ...
{"Message":"Invalid JSON primitive: Baby+Books."
calling storeGroupCategories(msg); returns webservice error ...
{"Message":"Invalid JSON primitive: d."
WebService
public class kbo_inexcludecategories : WebService
{
[WebMethod]
public List<Group> GetIncludeExcludeJson()
{
var Groups = new List<Group>();
ShopAssistGroupHandler.getInExCategories(Groups);
return Groups;
}
[WebMethod]
public GroupGuid StoreGroupCategories(List<InExCategory> inExCategories)
{
var inExString = JsonConvert.SerializeObject(inExCategories);
var returnGuid = DataHandler.SaveGroupJsonString(inExString);
return new GroupGuid(returnGuid);
}
}
Associated json ...
var _url = "kbo-inexcludecategories.asmx/";
var _method = "GetIncludeExcludeJson";
var _jsonData = "{}";
function storeGroupCategories(groupCategories) {
if(groupCategories != ""){
showProgressBar("Storing Group Categories");
getJsonData(_url, "StoreGroupCategories", groupCategories);
}
}
function getGroupMatrix() {
showProgressBar("Loading Group Categories");
getJsonData(_url, _method, _jsonData);
}
function getJsonData(url, method, jsonData) {
var myUrl = url + method;
$.ajax({
type: "POST",
url: myUrl,
data: jsonData,
contentType: "application/json; charset=utf-8",
dataType: "json",
async: false, //blocks window close
success: onSuccess,
error: onError
});
}
function onSuccess(msg) {
// Hide the fake progress indicator graphic.
hideProgressBar("");
if(msg.d.hasOwnProperty("Guid")) {
saveGroupGuid(msg.d);
}
else {
storeGroupCategories(msg.d);
//showGroupAccordion(msg.d);
//OpenAdvancedDialog();
}
}
json sample ...
"{\"groups\":[{\"__type\":\"group\",\"id\":1488,\"name\":\"Baby Books\",\"categories\":
[{\"__type\":\"groupcategory\",\"id\":152,\"name\":\"Activity Books\",\"value\":\"Included\"},
{\"__type\":\"groupcategory\",\"id\":167,\"name\":\"Bedtime and Dreams\",\"value\":\"Excluded\"}

To begin with I think you need to pass your json in like this:
storeGroupCategories(msg.d)
But within this function you also need to create valid json parameters to the post, which would look like this:
getJsonData(_url, "StoreGroupCategories", "{ inExCategories: " + groupCategories + " }");
I would also change your signature to the following, so groups matches the argument you are passing across:
public GroupGuid StoreGroupCategories(List<InExCategory> groups)
If you put a break point in the web page method, you will see exactly what is coming across, and check that it is what you are expecting.

Related

.NET (ApiController) / jQuery .ajax : what to return from POST?

In a Post method within a Controller derived from ApiController what should I return to indicate success to jQuery ?
I've tried HttpResponseMessage but jQuery sees this as an error (even though the argument the jQuery error handler clearly has a 200 status).
The jQuery looks like this :
processParticipantEvent: function(parID, evtType, evtNotes, successFunction, errorFunction){
debugger;
var requestURL = '/api/participantevent';
var json = {"parId" : parID, "evtType": evtType, "evtNotes": evtNotes};
var jsonArray=JSON.stringify(json);
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: requestURL,
data: jsonArray ,
dataType: "json",
success: function (data) { successFunction(data); },
error: function (data) { errorFunction(data); }
});
},
I've read this : Ajax request returns 200 OK, but an error event is fired instead of success which seems like it's touching on the same issue but I suspect it's out of data as it won't work for me ?
Just to be clear all I want to do is to return a plain old 2xx with no data.
As per the documentation:
"json": Evaluates the response as JSON and returns a JavaScript
object. Cross-domain "json" requests are converted to "jsonp" unless
the request includes jsonp: false in its request options. The JSON
data is parsed in a strict manner; any malformed JSON is rejected and
a parse error is thrown. As of jQuery 1.9, an empty response is also
rejected; the server should return a response of null or {} instead.
So if you want to use jQuery ajax you have to return a valid json string, just use the following in your API controller:
return Ok(new {});
Note this is a jQuery ajax "feature", using Angular for example to do an ajax post I can use return Ok(); inside my controller and everything works as expected.
As mentioned by #Beyers the return with OK() just works.
I've created the same structure here and worked.
My Controller has this:
[Route("api/participantevent")]
public IHttpActionResult Test()
{
return Ok("");
}
And at client I've changed your function just to simplify:
processParticipantEvent= function(){
debugger;
var requestURL = '/api/participantevent';
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: requestURL,
data: [{'test': '1'}] ,
dataType: "json",
success: function (data) { alert('success'); },
error: function (data) { alert('error'); }
});
}
Your error is with the requestURL. Its value is absolute and http://api/participantevent does not exist. Try using a relative value.
var requestURL = './api/participantevent';
It seems that if you get an OK response, It is probably not a valid JSON.
I would recommend to you to check the HTTP response in the browser and try to run the JSON.parse function with the responseText and see whether it fails.
I usually declare a class like below:
public class AjaxResult
{
private bool success = true;
private List<string> messages;
public bool Success { get { return success; } set { success = value; } }
public List<string> Messages { get { return messages; } }
public AjaxResult()
{
messages = new List<string>();
}
}
In the controller, the action(to which the ajax request is made) should have JsonResult as return type.
[HttpPost]
public JsonResult Action(string id)
{
AjaxResult result = new AjaxResult();
//Set the properties of result here...
result.Success = true;
result.messages.Add("Success");
return Json(result);
}
3.And your ajax call will look like this:
$.ajax({
type: "POST",
dataType: 'json',
url: /ControllerName/Action,
data: { id: "Test"},
success: function (data) { alert('success'); },
error: function (data) { alert('error'); }
});

Convert to Json and call page method

I have been trying to get this working for too long and thought I might ask for help here. I am trying to pass a javascript object to server side and then back to client side. Kind of like, on every postback I want to update the value of the object code behind or client side depending upon certain conditions. I can use hiddenfield here but I am trying to learn ajax so.
I have declared a global variable client side called sortList which stores the info about what task is stored in what slot. So its like:
var sortList = {};
sortList[tid] = sid;
Next I wrote a web method:
[WebMethod]
public static string storeList(DragList dict)
{
DragList dl = dict;
int i = 0;
return "success";
}
public class DragList
{
public string taskName { get; set; }
public string slotName { get; set; }
}
and on the client side I am calling it using:
console.log(JSON.stringify(sortList));
$.ajax({
type: "POST",
url: "Jobs.aspx/storeList",
data: JSON.stringify({dict: sortList}),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(msg) {
}});
}
My problem is in the webmethod, the DragList object dict is always null, though in the request, dict is a json object with value in it.
I have been stuck too long now on this and almost planning to move to hidden field to get the task done. But would really appreciate if some one could point me in the right direction.
Changes I made after:
I am using tid as a key to find sid in the object array, so if I break it into parts, I will lose the key value pairing. Instead, I created a new string in a proper JSON format:
jsonStr = "{";
var w = 0;
for (var key in sortList) {
var obj = sortList[key];
jsonStr += '"key":{"taskName":"' + key + '", "slotName":"' + obj + '"},';
w++;
}
jsonStr = jsonStr.substring(0, jsonStr.length - 1);
jsonStr += '}';
console.log(jsonStr);
$.ajax({
type: "POST",
url: "Jobs.aspx/storeList",
data: {dict: jsonStr},
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(msg) {
}});
}
But now, I get the following error:
Your Json is wrong:
You are sending it as
{"taskName:mainContent_ptask5":"alotName:mainContent_palot0"}
Instead of
{"taskName":"mainContent_ptask5", "alotName":"mainContent_palot0"}
Former considers the property name as taskName:mainContent_ptask5 so it cannot deserilaize to your argument name taskName or slotName
The culprit must be:
var sortList = {};
sortList[tid] = sid; // here i guess tid is "taskName:mainContent_ptask5" and sid is "alotName:mainContent_palot0"
Instead try something like this:
var tidParts = tid.split(':');
var sidParts = sid.split(':');
var sortList = {
};
sortList[tidParts[0]] = tidParts[1];
sortList[sidParts[0]] = sidParts[1];

Passing object to a WebMethod through jquery ajax [duplicate]

This question already has answers here:
Pass a user defined object to ASP.NET Webmethod from jQuery, using JSON
(2 answers)
Closed 4 years ago.
I am trying to pass an object to a page method defined. I'm trying to pass data to it collected from three textboxes.
Page Method
[System.Web.Services.WebMethod]
public static string saveDataToServer(object csObj)
{
// Function Body.
}
Javascript/jQuery
$("#osmSendMsg").click(function () {
debugger;
var cntDetails = {
cntName : $("#osmContactName").val(),
cntEmail : $("#osmContactEmail").val(),
cntMsg : $("#osmContactMessage").val()
}
PostDataToServer(cntDetails,"Please wait...","/ContactUs.aspx/saveDataToServer","csObj");
});
PostDataToServer
// Post data to server (ajax call).
function PostDataToServer(dataToSend, strMessagetoShow, strMethodToCall, jsonObjectName) {
debugger;
/*
dataToSend Contains the JSON Object.
submitType 1 == Normal Submit; 2 == Submit and Print.
strMessagetoShow Text that is displayed in the Please Wait Window.
*/
var tempurl = strMethodToCall;
var tempdata;
$.ajax({
url: tempurl,
type: "POST",
async: false,
dataType: "json",
data: "{" + jsonObjectName + ":" + JSON.stringify(dataToSend) + "}",
//timeout: 30000,
contentType: "application/json; charset=utf-8",
success: function (data) {
tempdata = data;
},
error: function (result) {
tempdata = null;
}
}); //end of the ajax call
return tempdata;
} //End of the post Data
Now the call is reaching the web method. No problem. I'm getting the object as well.But how do I process the object?
As you can see, that's what I'm getting. I also tried declaring a class and passing it as the parameter..but all it's properties are empty. If you notice the data is appearing as a key, value pair. I could convert it into a Dictionary, but I believe that's a complicated solution.
A simpler solution would be welcomed!
Your result collection is being returned in the 'data' parameter of your success method. You can simply process this parameter directly like data[0].cntName.
As you are able to reach your webmethod, you need to modify your webmethod to read the data from the object as follows:
[System.Web.Services.WebMethod]
public static string saveDataToServer(Dictionary<string, string> csObj)
{
try
{
string Name = csObj["cntName"].ToString();
string Email = csObj["cntEmail"].ToString();
//you can read values like this and can do your operation
return "";//return your value
}
catch(Exception ex)
{
throw new Exception(Ex.Message);
}
}

Complex type is getting null in a ApiController parameter

I don´t know why my parameter "ParametroFiltro Filtro" is getting null, the other parameters "page" and "pageSize" is getting OK.
public class ParametroFiltro
{
public string Codigo { get; set; }
public string Descricao { get; set; }
}
My ApiController Get method:
public PagedDataModel<ParametroDTO> Get(ParametroFiltro Filtro, int page, int pageSize)
My ajax call:
var fullUrl = "/api/" + self.Api;
$.ajax({
url: fullUrl,
type: 'GET',
dataType: 'json',
data: { Filtro: { Codigo: '_1', Descricao: 'TESTE' }, page: 1, pageSize: 10 },
success: function (result) {
alert(result.Data.length);
self.Parametros(result.Data);
}
});
You are trying to send a complex object with GET method. The reason this is failing is that GET method can't have a body and all the values are being encoded into the URL. You can make this work by using [FromUri], but first you need to change your client side code:
$.ajax({
url: fullUrl,
type: 'GET',
dataType: 'json',
data: { Codigo: '_1', Descricao: 'TESTE', page: 1, pageSize: 10 },
success: function (result) {
alert(result.Data.length);
self.Parametros(result.Data);
}
});
This way [FromUri] will be able to pick up your complex object properties directly from the URL if you change your action method like this:
public PagedDataModel<ParametroDTO> Get([FromUri]ParametroFiltro Filtro, int page, int pageSize)
Your previous approach would rather work with POST method which can have a body (but you would still need to use JSON.stringify() to format body as JSON).
Provide the contentType property when you make the ajax call. Use JSON.stringify method to build the JSON data to post. change the type to POST and MVC Model binding will bind the posted data to your class object.
var filter = { "Filtro": { "Codigo": "_1", "Descricao": "TESTE" },
"page": "1", "pageSize": "10" };
$.ajax({
url: fullUrl,
type: 'POST',
dataType: 'json',
contentType: 'application/json',
data: JSON.stringify(filter),
success: function (result) {
alert(result.Data.length);
self.Parametros(result.Data);
}
});
It's also possible to access POST variables via a Newtonsoft.Json.Linq JObject.
For example, this POST:
$.ajax({
type: 'POST',
url: 'URL',
data: { 'Note': note, 'Story': story },
dataType: 'text',
success: function (data) { }
});
Can be accessed in an APIController like so:
public void Update([FromBody]JObject data)
{
var Note = (String)data["Note"];
var Story = (String)data["Story"];
}
If you append json data to query string, and parse it later in web api side. you can parse complex object too. It's useful rather than post json object, espeicaly in some special httpget requirement case.
//javascript file
var data = { UserID: "10", UserName: "Long", AppInstanceID: "100", ProcessGUID: "BF1CC2EB-D9BD-45FD-BF87-939DD8FF9071" };
var request = JSON.stringify(data);
request = encodeURIComponent(request);
doAjaxGet("/ProductWebApi/api/Workflow/StartProcess?data=", request, function (result) {
window.console.log(result);
});
//webapi file:
[HttpGet]
public ResponseResult StartProcess()
{
dynamic queryJson = ParseHttpGetJson(Request.RequestUri.Query);
int appInstanceID = int.Parse(queryJson.AppInstanceID.Value);
Guid processGUID = Guid.Parse(queryJson.ProcessGUID.Value);
int userID = int.Parse(queryJson.UserID.Value);
string userName = queryJson.UserName.Value;
}
//utility function:
public static dynamic ParseHttpGetJson(string query)
{
if (!string.IsNullOrEmpty(query))
{
try
{
var json = query.Substring(7, query.Length - 7); //seperate ?data= characters
json = System.Web.HttpUtility.UrlDecode(json);
dynamic queryJson = JsonConvert.DeserializeObject<dynamic>(json);
return queryJson;
}
catch (System.Exception e)
{
throw new ApplicationException("can't deserialize object as wrong string content!", e);
}
}
else
{
return null;
}
}
In .NET Core, the HttpClient sets the transfer-encoding: chunked header by default. This can cause the .NET Web API controller parameters to be null.
To get around this, you'll need to set the ContentLength header explicitly:
var json = JsonConvert.SerializeObject(myObject);
var content = new StringContent(json, Encoding.UTF8, "application/json");
content.Headers.ContentLength = json.Length;
var response = await client.PostAsync("http://my-api.com", content);
SO answer if you already know the transfer-encoding header is the issue: How to disable Chunked Transfer Encoding in ASP.Net C# using HttpClient
Related bug which won't be fixed, which gives some insight into the problem: https://github.com/dotnet/runtime/issues/30283

Why is this jQuery ajax call to C# web method not working

Here is my JS:
function declassifyAjax(e) {
var items = getSelected();
var docIds = new Array();
items.each(get);
//get ids of QcItem/docId we are dealing with
function get(count, el) {
docIds[count] = $(el).parent().attr('id');
}
var dataObj = new Object();
dataObj.batchId = batchId;
dataObj.docIds = docIds;
var dataString = JSON.stringify(dataObj)
//make call to webservice to get html to recreate view showing
//pending declassification
$.ajax({
type: "POST",
url: applicationRoot + 'Models/BatchQC.asmx/declassify',
data: dataString,
contentType: "application/json; charset=utf-8",
success: function (data) {
if (ProcessWebMethodResult.processWebMethodResult(data) == true) {
declassifyProcess(data, e);
}
},
error: function (e) {
alert("Failed to Get declassification details");
}
});
}
And here is my Web Service:
//type to represent the input the declassify method
public class DeclassifyType
{
public int batchId;
public string[] docIds;
}
[WebMethod(EnableSession = true)]
public WebMethodResult declassify(DeclassifyType dataString)
{
}
Any and all help appreciated!
Debugging in Firebug shows that the variables dataObj, batchId, docIds and dataString are correct. There is something wrong with the way my Web Method signature is setup I think, because the Ajax is never fired off. When stepping through the .ajax method, it goes to error, not success.
Your web methods expects one parameter, the data object you already have, but you're passing multiple parameters since you're passing the object directly.
Instead, you need to have an object with one property, dataString, and that property's value should be your object, like this:
var dataString = JSON.stringify({ dataString: dataObj });
▲--should match--▼
public WebMethodResult declassify(DeclassifyType dataString)
Ah, I just fixed it,
just changed the signature to
[WebMethod(EnableSession = true)]
public WebMethodResult declassify(int batchId, string[] docIds)
{
}
Simple really. Thanks for checking my post!

Categories