Can't receive JSON array being posted to me by third party - asp.net

The format I am receiving is:
[{"item1": "value1","item2": "value2"},{"item1": "value2","item2": "value4"}]
The main issue seems to be that no matter what I try I receive the error "Type System.Collections.Generic.IDictionary'2 Is Not supported for deserialization of an array."
Scouring the internet only comes up with my needing to wrap the array in a top level variable (ie. the array cannot be on the root level). Unfortunately I am unable to change what and how I am receiving the data.
Here is all my code with the things I have attempted commented out:
My test ajax used to simulate what the third party will be sending to me:
Head of "test.html":
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
<SCRIPT type="text/javascript">
<!--
function testPost() {
var theData;
theData = '[{"item1": "value1","item2": "value2"},{"item1": "value2","item2": "value4"}]';
//theData = '{"item1": "value1","item2": "value2"}'; //I can make a single array element work, but that is not what I will receive
$.ajax({
type: "POST",
contentType: "application/json",
url: "test2.aspx/test_array",
data: theData,
dataType: "json",
success: function(msg) {
alert(msg);
}
});
}
//-->
</SCRIPT>
Body of "test.html"
<input type="submit" value="test Post" onClick="testPost();" /><br>
Test.aspx.vb in it's entirety:
Imports System.Collections.Generic
Imports System.Web.Script.Serialization
Partial Class test2
Inherits System.Web.UI.Page
' Public Shared Function test_array(ByVal item1 As String, ByVal item2 As String) As String ' works if I am passing a single array element
' Public Shared Function test_array(ByVal theobj As Object) As String ' "Type System.Collections.Generic.IDictionary`2 Is Not supported for deserialization of an array."
' Public Shared Function test_array(ByVal theobj As List(Of Object)) As String' "Type System.Collections.Generic.IDictionary`2 Is Not supported for deserialization of an array."
' Public Shared Function test_array(ByVal theobj As Test_Request) As String ' "Type System.Collections.Generic.IDictionary`2 Is Not supported for deserialization of an array."
' Public Shared Function test_array(ByVal theobj As List(Of Test_Request)) As String' "Type System.Collections.Generic.IDictionary`2 Is Not supported for deserialization of an array."
' Public Shared Function test_array(ByVal theobj As Dictionary(Of String, String)) As String' "Type System.Collections.Generic.IDictionary`2 Is Not supported for deserialization of an array."
<System.Web.Services.WebMethod> _
Public Shared Function test_array(ByVal d As List(Of Test_Request)) As String
Return "test"
End Function
End Class
The "Test_Request" class:
Public Class Test_Request
Property item1 As String
Get
Return m_item1
End Get
Set(value As String)
m_item1 = value
End Set
End Property
Private m_item1 As String
Property item2 As String
Get
Return m_item2
End Get
Set(value As String)
m_item2 = value
End Set
End Property
Private m_item2 As String
End Class
Please let me know if I failed to include any needed data. I have been going in circles for a few days now and before deciding to post here I attempted to recreate all my failed attempts in this test mock up. Hopefully there is simply something I am overlooking.

It seems to me that you are trying to deserialize an array of dictionary objects. I would do something like as follows.
On the server side:
<HttpPost>
<Route("test")>
Public Function test(data As YourArray) As String
Return "done"
End Function
-----------
Public Class YourArray
Inherits List(Of YourDictionaryObject )
End Class
Public Class YourDictionaryObject
Inherits Dictionary(Of String, String)
End Class
I just tested and I can confirm that the following does work:
function doTest() {
var theData = [];
theData.push({
item1: "value1",
item2: "value2"
});
theData.push({
item1: "value3",
item2: "value4"
});
$.ajax({
type: "POST",
contentType: "application/json",
url: "somewhere/test",
data: JSON.stringify(theData),
dataType: "json",
success: function(msg) {
alert(msg);
}
});
}
I checked and the Request Payload looks like this:
[{"item1":"value1","item2":"value2"},{"item1":"value3","item2":"value4"}]
This gets deserialized on the server side as YourArray. By the way, I am using Asp.net Web Api (not WCF where serializing/deserializing dictionaries can be tricky).

Your poco is wrong. Item1 and Item2 need to be string arrays
Public Class RootObject
Public Property item1() As String
Public Property item2() As String
End Class

Related

Getting data from database in a webmethod return null in vb.net

I am trying to get data from a stored procedure in a webmethod inside an asmx service but whatever I try it returns null.
<WebMethod()>
<ScriptMethod(ResponseFormat:=ResponseFormat.Json, UseHttpGet:=False,
XmlSerializeString:=False)>
Public Function SendIdDocuments(ByVal idReferto As String)
'This id has been sent from ajax as json and now I am converting it to string
'in order to use it as parameter in stored procedure.
Dim idRef As String = JsonConvert.DeserializeObject(idReferto)
Dim dtRefertoDocIndex As DataTable = operations.G_REPORT_BY_ID(idRef)
Dim version As String = dtRefertoDocIndex.Rows(0)("VERSION")
MsgBox(Cstr(version))
End If
I have tried these:
1) Dim dtRefertoDocIndex As DataTable = operations.G_REPORT_BY_ID(Cstr(idRef))
2) Dim dtRefertoDocIndex As DataTable = operations.G_REPORT_BY_ID(idRef.ToString)
These dont work too. I have checked the idRef that has a value and also data from database isn't returning null and version has a value, but in the code dtRefertoDocIndex is null and for this reason version comes as null too. Any help would be appriciated.
A few things. Obviously you can't really use msgbox.
Next up, .net should return JSON without you having to specify it, but we can leave that.
Your web method WILL automatic split out the parameters for you.
So, your web method ALSO needs to be a function that RETURNS a value, say a string
thus it should be:
<WebMethod()>
Public Function SendIdDocuments(ByVal idReferto As String) as string
Dim dtRefertoDocIndex As DataTable = operations.G_REPORT_BY_ID(idRef)
Dim strResult as string = dtRefertoDocIndex.Rows(0)("VERSION")
return strResult
End If
Note this part: Public function bla bla bla) as string <---- your function HAS to return something, right?
Now WHY did I create a string to hold the return value and THEN return it?
Answer:
Because I do NOT want to take a chance that the return type is a column cell, or ANY OTHER data type OTHER then a string. So, to be 100%, 200%, 300% of the correct data type being returned? I create a nice separate string, and stuff the value into that string, and THEN return that SIMPLE string type. This removes ANY doubt that we ARE in fact returning a simple string type. When we execute the return strResult?
It will be converted back into a json result.
Ok, now, lets setup the JavaScript (client side) ajax call.
jQuery:
function GetDocByID() {
var MyDocID = 123;
$.ajax({
type: "POST",
url: 'WebService1.asmx/MakeName',
data: JSON.stringify({idReferto: MyDocID}),
contentType: "application/json; charset=utf-8",
datatype: "json",
success: function (em) {
alert('VERSION result = ' + em.d);
}
});
}
If you not using jQuery, then of course you have to re-write above.
So, .net will automatic convert to and from json for you. And ALSO VERY careful note how the parameter name in JavaScript (jQuery) MUST match the parameters in the public function you created.
Here is another simple example. We pass firstname, last name, and return the two as a single string:
<WebMethod()>
Public Function MakeName(FirstName As String, LastName As String) As String
Dim strResult As String = ""
strResult = FirstName & " " & LastName
Return strResult
End Function
and the js/jQuery is:
function GetNameTest() {
var MyFirstName = 'Albert';
var MyLastName = 'Kallal';
$.ajax({
type: "POST",
url: 'WebService1.asmx/MakeName',
data: JSON.stringify({ FirstName: MyFirstName, LastName: MyLastName }),
contentType: "application/json; charset=utf-8",
datatype: "json",
success: function (em) {
alert('name result = ' + em.d);
}
});
}
Note again HOW we used the actual vb.net FirstName and LastName DEFINED in the public function.
Note again: the function has a return value (string).
And if you look at the web service template, note that you WANT to un-comment the FIRST line as outlined like this:
' To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
<System.Web.Script.Services.ScriptService()>

ASP.NET - WebMethod not getting called when using Class, jsonerror

I am trying to pass an object to a WebMethod which takes parameters as a class.
If I pass the parameters separately, it works, but not as a class. What am I missing?
My ajax call:
var obj = {Id: 1234};
var item = JSON.stringify(obj);
$.ajax({
url: 'InventoryItems.aspx/Update',
data: item,
type: 'POST',
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function () {
console.log("in success");
}
})
WebMethod:
The version that works:
<WebMethod(EnableSession:=True)>
Public Shared Function Update(Id As string) As String
Dim res As String = ""
Return res
End Function
WebMethod:
The version that does not work:
<WebMethod(EnableSession:=True)>
Public Shared Function Update(item As Item) As String
Dim res As String = ""
Return res
End Function
The class Item:
Public Class Item
Public Property Id As String = String.Empty
End Class
I get a 500 error in Google Chrome dev tool. So, in gist, the WebMethod does not get hit if I put a breakpoint there. If I use just the Id as the parameter in the WebMethod, it gets hit. My original object has about 20 properties, so I would like to pass an object with 20 fields rather than passing 20 parameters separately.
Am I missing anything? Any reference or settings?
Thank you for helping me in advance.
The problem on my end is FriendlyUrls.
There's probably a better way to do this, but I excluded it from the project in the bin folder; and commented-out references to it in RouteConfig.cs and ViewSwitcher.ascx. (You may have others.)
This was just for testing, but the problems I was having are gone on this page. I also have a script manager on my test-page, and the script manager and bundling are commented-out on the master page, but now I'm not convinced that that's an issue.
I guess the ASP.NET AJAX proxy class PageMethods looks for a complete url to find the code-behind method and bombs without it.
When you are using input parameter as integer, its working fine as your JSON is compliant with the parameter
For parameter as an object, use following
{ "item": { "Id": "1234" } }
If the underlying Id property is a number, remove the corresponding quotes on 1234.
Note that the parameter name are case sensitive and hence "item" should have i in lower case and "Id" has in upper case.
You follow the convention of :-
Opening and closing braces marks the boundary of field
Variable name has to be 1st ('item' in this case)
Variable value follows after a colon (an object with property "Id' and its corresponding value
2) & 3) gets repeated for the whole hierarchy of the concerned object.
The following worked for me:
The ajax call:
var obj = {Id: 1234};
var item = JSON.stringify(obj);
$.ajax({
url: 'InventoryItems.aspx/Update',
data: JSON.stringify({item:item}),
type: 'POST',
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function () {
console.log("in success");
}
})
<WebMethod(EnableSession:=True)>
Public Shared Function Update(item As string) As String
Dim res As String = ""
Return res
End Function
And then in that WebMethod, I could do something like:
Dim jss As New JavaScriptSerializer()
Dim itemDetails As Item = jss.Deserialize(Of Item)(item)
dim id as string = itemDetails.Id

allow webservice to be called from script

hi there i have a demo page in my web site, i am learning how to call webservice from script
this is my page
http://applicazioni.vsc300.it/Mediweb2015/Prova.aspx
$(document).ready(function () {
var params = { 'IDPaziente': 6586 }
$.ajax({
"dataType": 'json',
"contentType": "application/json; charset=utf-8",
"type": "GET", "url":"http://applicazioni.vsc300.it/Service.asmx/CercaPaziente",
"data": params,
"success": function (msg) {
var json = jQuery.parseJSON(msg.d);
//valorizza texbox
$("#TXT_CognomePaziente").val(json.Denominazione);
},
error: function (xhr, textStatus, error) {
alert(error);
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<input name="TXT_CognomePaziente" type="text" id="TXT_CognomePaziente" name="TXT_CognomePaziente" />
and this is the service:
' To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
<System.Web.Script.Services.ScriptService()> _
<WebService(Namespace:="http://tempuri.org/")> _
<WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Public Class Service
Inherits System.Web.Services.WebService
' <WebInvoke(RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest, Method = "GET")>
<WebMethod()> _
<ScriptMethod(ResponseFormat:=ResponseFormat.Json)> _
Public Function CercaPaziente(IDPaziente As Integer) As String
Dim serialiser As JavaScriptSerializer = New JavaScriptSerializer()
Dim Paz As New CLS_Paziente
Paz.GetCercaAnagrafica(IDPaziente)
Dim serializer As JavaScriptSerializer = New JavaScriptSerializer()
Dim serializedItems As String = serializer.Serialize(Paz)
Return serializedItems
End Function
End Class
it returns an error, that Only Web services with a [ScriptService] attribute on the class definition can be called from script.
but i enabled it!!!
what can i do?
From this doc:
If more than one attribute is applied to a single program element, the attributes are enclosed in a single set of angle brackets and delimited from one another by a comma. For example:
<Obsolete(), WebMethod()>
Public Function PageCount(strURL As String) As Integer
(This was hard to find, by the way. I couldn't find it anywhere on MSDN.) So, this isn't what your code does, and the .NET compiler is probably ignoring your attributes altogether. Try this and see if it works:
<System.Web.Script.Services.ScriptService(), _
WebService(Namespace:="http://tempuri.org/"), _
WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1), _
Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()>
Public Class Service
Inherits System.Web.Services.WebService

My jQuery ajax doesn't work

Just started to learn jQuery ajax today, followed what tutorial said but it did not work.
HelloWorld is the method name, but it seems not be recognized as a method name but a page name based on the error message.
jQuery
$(document).ready(function () {
//alert("hello world");
$('.ordernumber').on('click', function () {
var orderNum = $(this).text();
$.ajax({
type: "POST",
url: "./OrderDetail.asmx/HelloWorld",
data: "{}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (msg) {
alert(msg);
// Do interesting things here.
}
});
//alert($(this).text());
});
});
OrderDetail.asmx.vb
Imports System
Imports System.Web.Services
Public Class OrderDetail
Inherits System.Web.Services.WebService
<WebMethod()> _
Public Function HelloWorld() As String
Return "Hello World"
End Function
End Class
Error Message:
POST http://localhost:64616/OrderDetail.asmx/HelloWorld 500 (Internal Server Error)
I think you need to add <System.Web.Script.Services.ScriptService()> to your class;
<System.Web.Script.Services.ScriptService()> _
Public Class OrderDetails
Inherits System.Web.Services.WebService
'' rest of your code
End Class
Also to return Json you need to decorate your methods with;
<ScriptMethod(ResponseFormat:=ResponseFormat.Json)> _
Update
When creating a fresh ASMX Web Service, the default code states;
' To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
' <System.Web.Script.Services.ScriptService()> _
You are expecting a JSON back, but an asmx webservice returns a XML instead you need to add
<WebMethod()> _
<ScriptMethod(ResponseFormat:=ResponseFormat.Json)>_
Public Function HelloWorld() As String
Return "Hello World"
End Function
The link for more explanaiton

Passing JSON object to PageMethod works in DEV, not PROD

I have a PageMethod and an AJAX call to that method that passes an array of product SKUs and the number of requested SKUs. It works perfectly fine in DEV(IIS7), but returns a 500 error in PROD(IIS6):
Message: Object reference not set to an instance of an object.
StackTrace: at ViewProduct.GetInventory(List`1 orderedSkus)
ExceptionType: System.NullReferenceException
Here is the relevant code. If you need specific snippets from my web.config, I can grab those, too, although I don't see anything there that would have any affect on anything.
I have tried to use two different Object definitions in the PageMethod, orderedSkus As Object() and orderedSkus As List(Of Object). Same difference, but also same result... null reference.
AJAX:
var editedSkus = [];
function checkInventory() {
editedSkus.length = 0;
var textBoxes = $('input:text', '.table-orderMatrix');
if (formEdited(textBoxes)) {
var DTO = { 'orderedSkus': editedSkus };
$.ajax({
type: "POST",
url: BasePath + "ViewProduct.aspx/GetInventory",
data: JSON.stringify(DTO),
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function (msg) {
var skus = msg.d;
$.each(skus, function () {
//do stuff
});
}
});
} else {
// Do other stuff
}
}
var formEdited = function (textBoxes) {
var edited = 0;
$.each(textBoxes, function (i) {
if (this.value > 0) {
var sku = {};
sku.skuNumber = $(this).prev().val();
sku.orderAmount = this.value;
editedSkus.push(sku);
edited += 1;
}
});
return edited;
}
PAGEMETHOD:
<WebMethod()> _
Public Shared Function GetInventory(orderedSkus As List(Of Object)) As List(Of Object)
Dim _skus As SKUCollection
Dim _sku As SKU = Nothing
Dim warnings As New List(Of Object)
Dim qty As Integer
_skus = CurrentStyle.SKUs
For Each _orderedSku As Object In orderedSkus
Dim dicValues As New Dictionary(Of String, Object)()
dicValues = DirectCast(_orderedSku, Dictionary(Of String, Object))
Dim orderedSkuNumber As String = dicValues("skuNumber").ToString()
Dim orderAmount As String = CType(dicValues("orderAmount"), Integer)
Try
'Stuff
Catch ex As Exception
'Health Monitoring
End Try
Next
Return warnings
End Function
EDIT: Adding the "minor detail" that our DEV servers are running IIS7 (where the pagemethod works), while PROD is still under IIS6 (where it does not). I know... don't get me started. Adding this because I feel it may bear significance to the situation.
I figured it out. The object was being passed just fine. However, a bit of code was failing in the Try...Catch in PROD that worked fine in DEV (which was completely unrelated to the AJAX call). In turn, instead of providing an appropriate error message (even after adding some error handling in the Catch), I just received the error that the object I sent was null. Weird, but there you go.

Resources