Passing JSON object to PageMethod works in DEV, not PROD - asp.net

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.

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

Can't receive JSON array being posted to me by third party

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

How to call non static method from AJAX?

Here is my code behind I am calling from AJAX...
[WebMethod]
[ScriptMethod]
public static string save(string parameter)
{
country_master obj_country = new country_master();
obj_country.Country_Name = Page.Request.Params["name"].ToString().Trim();
obj_country.saved();
return "";
}
Here I am not able to access parameters passed from the page via Page.Request.
string name = HttpContext.Current.Request.QueryString["name"].Trim();
return "error";
after writing the first line, return statement does not return anything to the AJAX.
Please Help me how to do that.
Thanks...
To get the current context you can use HttpContext.Current, which is a static property.
Once you have that you can access things like session or profile and get information about the state of the site
HttpContext.Current.Session etc..
This link may help you : Call Server Side via AJAX without a Static Method
The reason behind restricting the web method to be static is to avoid it access the controls of the instance page.
Yo could use the HttpContext.Current static class, however you can skip that if you declare on your method the parameters you want to use and just pass the parameters with your AJAX call
You should pass parameters directly to the method.
I have several working examples on my Github repository, feel free to browse the code.
As a summary, to call a PageMethod:
Note: how using AJAX the jobID PageMethod parameter is being passed along with the request and how is used inside the PageMethod transparently
AJAX call
$.ajax({
type: 'POST',
url: '<%: this.ResolveClientUrl("~/Topics/JQuery/Ajax/PageMethods_JQueryAJAX.aspx/GetEmployees") %>',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
data: '{"jobID" : ' + jobID +'}',
async: false,
cache: false,
success: function (data) {
$('#employees').find('option').remove();
$.each(data.d, function (i, item) {
$('<option />').val(item.EmployeeID).text(item.FirstName).appendTo('#employees');
});
},
error: function (xhr) {
alert(xhr.responseText);
}
});
Page Method
[WebMethod]
public static List<EmployeeModel> GetEmployees(int jobID)
{
var ctx = new PubsDataContext();
return (from e in ctx.employee
where e.job_id == jobID
orderby e.fname
select new EmployeeModel
{
EmployeeID = e.emp_id,
FirstName = e.fname
}).ToList();
}

Sending a complex object as parameter to Asp.Net PageMethod

I am trying to send an object created in JavaScript to an ASP.NET PageMethod. This object mirrors the properties of an existing custom business object, so i was hoping that i could pass a single object instead of a parameter for each property. I am getting an error "Unknown web method SavePart when attempting to use this method.
Javascript:
function() {
var pt = { Id: 1, Onhand: 20, LowPoint: 30, __type: 'Custom.Objects.Part'};
$.ajax({
type: 'POST',
url: 'partlist.aspx/SavePart',
data: JSON.stringify(pt),
contentType: 'application/json; charset: utf-8;'
dataType: 'json',
success: function(results) { alert('Success!'); }
});
}
Code Behind:
<WebMethod()> _
Public Shared Function SavePart(pt as Custom.Objects.Part) as Boolean
Dim repo as new PartRepository()
return repo.Save(pt)
End Function
I am using another PageMethod which just accepts an int, and this works fine.
I ended up solving my problem by sending the object this way through the jQuery ajax command:
data: '{"pt":' + JSON.stringify(pt) + '}'
this serialized the object automatically and returned it to my WebMethod. When i tried sending the object as is, i got an error saying "invalid JSON primitive".
You are attempting to pass a string to the method. You will need to accept the string, and deserialize it with fx. JavascriptSerializer or JSON.NET
I know this is incredibly old, but its not very intuitive when you're using this to figure out what the issues are. You are very close but I wanted to add a bit more to this in case someone else later wants to do the same thing. This works with nested objects as well, the one thing I can say is CASE matters in your JS variables that map to .NET POCOs on the page method.
Your "answer" is where I will start with. And as in the comments below it, yes you have to pass the object wrapped in its page method variable name.
Ill say it again, this is CASE-Sensitive, and can trip you up not just on the object's name but its properties as well. So to combat this I usually create my POCO object in .NET then copy that to the page so I know the names, capitalization and all are correct.
Something like this:
POCO:
Public Class CustomObject
Public Property Id as integer
Public Property ReqDate as DateTime
Public Property Message as string
End Sub
Now with a defined POCO for page method, replicate that "model" exactly as it is for the JS/AJAX to post with, being vigilant about case-sensitivity.
function ParseAndPostData()
{
var data = { custobj: {
Id: 1,
ReqDate: "04/12/2018",
Message:"Hello!"
}
};
//Stringify the data so it goes through page method parser
var postdata = JSON.stringify(data);
$.ajax({
type: 'POST',
url: '/BasePath/SomePage.aspx/SomeMethod',
data: postdata,
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: function (msg) {
var parsedACData = JSON.parse(msg.d);
alert(parsedACData);
},
error: function (msg) {
alert(msg);
}
});
}
Page Method (Note custobj in the parameters):
<WebMethod()> _
Public Shared Function PostCustomObject(custobj as CustomObject) as String
return custobj.Message
End Function

Resources