jQuery ajax request response is empty in Internet Explorer - asp.net

I'm doing the following ajax call:
//exif loader
function LoadExif(cImage) {
$.ajax({
type: "POST",
url: "http://localhost:62414/Default1.aspx/GetImageExif",
data: "{iCurrentImage:" + cImage + "}",
contentType: "application/json; charset=utf-8",
dataType: "json",
error: ajaxFailed,
success: function (data, status) {
var sStr = '';
for (var count in data.d) {
sStr = sStr + data.d[count];
};
alert(sStr);
}
});
};
In Firefox the request works really fine. When I try to run the code in Internet Explorer, the response is empty.
Here is the webmethod witch is called:
<WebMethod()> _
<ScriptMethod(ResponseFormat:=ResponseFormat.Json)> _
Public Shared Function GetImageExif(ByVal iCurrentImage As Integer) As String
Dim sbTable As New StringBuilder
sbTable.AppendLine("<table>")
sbTable.AppendLine("<tr>")
sbTable.AppendLine("<td>Name</td><td>" & gGallery.Images(iCurrentImage).File.Name & "</td>")
sbTable.AppendLine("</tr>")
sbTable.AppendLine("</table>")
Return sbTable.ToString
End Function
Any ideas?
Jan

When you have alert(data); what do you see?
Thanks for this hint. This was the issue. I've copied the code from another of my projects.
alert(data.d);
... works in both browsers. Thanks for the quick answers.
Jan

Starting with ASP.NET 3.5 MS introduced a security feature where they encapsulate any JSON response in a parent object ("d").
Doing this helps against a XSS vulnerability (described here: http://haacked.com/archive/2009/06/25/json-hijacking.aspx)
That's the reason why it exists.
Here's how to handle it, if you code against multiple versions of ASP.NET, you can simply use the following check in your success function to detect it's existence:
if (data.hasOwnProperty('d'))
//use data.d in your code;
else
//use data in your code
As for why Firefox handles it appropriately and IE8 does not, I would assume it has something to do how each parses the JSON object.

Related

Can we call ASP.NET webservice without soap envelop? Like a simple REST api

Can we create a simple post method in ASP.NET web service which runs like a REST API method?
Because I don't want to provide an envelop for post and get request.
Can anyone provide a solution for this?
Not only can you do this, but in fact, if you create a web method in .net, right out of the box:
It can accept soap 1.1, 1.2 - no extra code on your part
It can accept a rest call - even json data - no extra code on your part
It can accept a plane jane URL (again rest) call - no extra code on your part
So, in fact, you get all 3 of the above - in fact the above counts as 4, since your ajax call can use (data) or the URL to pass the information.
Say, I add a I create a web service page like this:
Do note, you don't HAVE to crate a web service page, you can drop into a EXISTING page a function (returns values), or drop in a sub into that page. As long as you ta the function/sub with WebMethod(), then you are good to go.
So, with above page, lets add a simple function. It will take a paramter FirstName, and LastName, and return the full name.
So, we have this code in the above web service page:
<WebMethod()>
Public Function GetName(FirstName As String, LastName As String) As String
Dim sResult As String = ""
sResult = FirstName & " " & LastName
Return sResult
End Function
Above is VERY simple.
So, you can use jQuery, and call this method via post like this:
<asp:Button ID="cSoap" runat="server" Text="Soap Example"
OnClientClick="webcalltest();return false" />
<script>
function webcalltest() {
var First = 'Albert'
var Last = 'Kallal'
var url = '../WebService1.asmx/GetName'
$.ajax({
type: "POST",
url: url,
dataType: "json",
data: JSON.stringify({ FirstName: First, LastName: Last }),
contentType: "application/json; charset=utf-8",
success: function (msg) {
alert(msg.d)
},
error: function (msg) {
alert("Failed: " + msg.status + ": " + msg.statusText);
}
});
As noted, that web method will also accept soap calls.
And you can even skip the headers (in the above post), and toss out a 100% plane jane REST call - just the URL, say like this:
<asp:Button ID="Button2" runat="server" Text="Soap Example"
OnClientClick="webtest2();return false" />
<script>
function webtest2() {
var First = 'Albert'
var Last = 'Kallal'
var url = '../WebService1.asmx/GetName?FirstName=' + First + '&LastName=' + Last
$.get(url, function (data, status) {
alert($(data).find('string').text())
alert("Data: " + data + "\nStatus: " + status);
})
}
</script>
So, in above, we just used the URL for the rest call. (and did not set up any headers, or even a soap xml record). So, just keep in mind, even older legacy soap methods in most cases can be passed and consume JSON data - and you in general don't have to re-write or even change the web methods.
And as above shows, you can just feed the URL with the parameters, and not pass any headers at all - let alone the soap ones.

asp.net page not returning ajax request

I am attempting to send an AJAX request from an ASP.NET Gridview row. Each row in the gridview shows completed jobs. Some jobs have files that can be downloaded. The end goal here is to show the download urls in a colorbox overlay, but I am having trouble just returning the list of files to the base page now. To show that there are files to download from an order I unhide a button control in the order number column. Javascript on the page follows.
$(document).ready(function () {
$("#<%=gvMessenger.ClientID%> input").filter(":not(:has(table, th))").click(function (e) {
e.preventDefault();
var $cell = $(e.target).closest("td");
//$("#<%=gvMessenger.ClientID%> td").removeClass("highlight"); $cell.addClass("highlight"); $("#message").text('You have selected: ' + $cell.text());
$("#Message").html("");
var orderID = $cell.text()
orderID = $.trim(orderID);
sendData(orderID);
function sendData(orderID) {
var loc = window.location.href;
loc = (loc.substr(loc.length - 1, 1) == "/") ?
loc + "CompletedOrdersNew.aspx" : loc;
$.ajax({
type: "POST",
url: loc + "/GetFiles",
data: "{'orderID':'" + orderID + "'}",
contentType: "application/jason; charset=utf-8",
datatype: "json",
success: function (msg) {
$("ContentArea").html(msg.d);
},
error: function () {
alert("An error occured in getting your files.");
}
});
}
});
});
The function in the page codebehind that should fire on the ajax request follows.
<WebMethod()> _
Public Shared Function GetFiles(ByRef orderID As Integer) As String
Dim dict As New Dictionary(Of String, Object)
Dim dt As DataTable
dt = Dac.ExecuteDataTable("GetS3Files", Parameter("#OrderID", orderID))
Dim arrr(dt.Rows.Count) As Object
For i As Integer = 0 To dt.Rows.Count - 1
arrr(i) = dt.Rows(i).ItemArray
Next
Dim json As New JavaScriptSerializer
Return json.Serialize(dict)
End Function
When watching the page in FireBug I see the request go out to the GetFiles function with the orderID number {'orderID':'10000315'}
POST http://localhost:57210/AMSSite/Customer/CompletedOrdersNew.aspx/GetFiles
But the call does not fire the GetFiles function and the response I am getting is the page html.
Not sure what is going on here.
Try sending orderID as a number since you webmethod expects an int, also in JSON keys and strings are quoted with double quotes(")
data: "{\"orderID\":" + orderID + "}",
You made a typo in contentType option. Should be: contentType: "application/json; charset=utf-8"
I'll answer my question for the sake of any other VB.NET/ASP.NET folks running into this problem. Aside from my misspelling the issue here was that my WebMethod function was ByRef. It needs to be BYVAL. After banging my head against the wall and reading some great stuff on javascript and json services I found the real answer at http://projectsmm.com/technet/asp/index.shtml. VB.Net by default sets function variables to ByRef. For some reason .NET web services don't accept this. Change to ByVal and it works.
Hope this helps some one else not spend the hours I looked at this.

autocomplete with asp.net generated json

I have the folowing script which does not seem to work. The aspx page returns json similar to the json in the script below which has been commented out. If I stick that json directly into the source as an array, it works perfectly.
But as soon as I try to use the script below, I get no error messages or anything, nothing happens when i type into the autocomplete field.
$(document).ready(function(){
$('#button').click(function() {
alert($("#txtAllowSearchID").val());
});
//var $local_source = [ {id:0,value:"c++"}, {id:1,value:"java"}, {id:2,value:"php"}, {id:3,value:"coldfusion"}, {id:4,value:"javascript"}, {id:5,value:"asp"}, {id:6,value:"ruby"} ];
$("#txtAllowSearch").autocomplete({
source: function(request, response) {
$.ajax({
type: "POST",
url: "test_array.aspx",
data: "{'prefixText': '" + $('#txtAllowSearch').val() + "'}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(data) {
response(data.d);
},
failure: function(errMsg) {
$('#errMessage').text(errMsg);
}
});
},
select: function (event, ui) {
$("#txtAllowSearch").val(ui.item.value); // display the selected text
$("#txtAllowSearchID").val(ui.item.id); // save selected id to hidden input
}
});
});
EDIT: I think the problem is in the aspx page:
objSQLCommand = New SqlCommand("select id, value from table1 where value like '%#prefixText%'", objSQLConnection)
objSQLCommand.Parameters.Add("#prefixText", SqlDbType.VarChar, 255).Value = "ing"
I believe that you have to make the source of the ajax call to a web service, which in your case seems to be a Page Method. So if you have a function in your code behind page look like this:
public static List<string> GetData(string prefixText){ }
You would need to decorate that method with [WebMethod] from the System.Web.Services namespace.
So it would finally look like:
using System.Web.Services;
...
[WebMethod()]
public static List<string> GetData(string prefixText){ }
HTH
EDIT: also you would need to update your ajax call to look like this for the source:
source: 'test_array.aspx/GetData'
It looks to me like the issue might be the source function. When you make the ajax call, it is done asynchronously. So, the function kicks off the ajax call and continues, which returns nothing for the source.
I discovered this when I was doing loading screens. If I put the close for the loading screen after the ajax call, the loading screen would not appear. I had to move it inside the ajax call success and error events to get it to appear and disappear correctly.
Your source should just be a reference to the url
source: "test_array.aspx",
From the documentation:
The datasource is a server-side script
which returns JSON data, specified via
a simple URL for the source-option.

What is the recommended method to read JSON data posted with JQuery AJAX in ASP.NET?

I currently have a JQuery Ajax method as below;
$.ajax({
type:"POST",
url: "default.aspx/UpdateData",
data: jsonString,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(msg){
alert('saved');
}
});
In the ASP.NET UpdateData method I'm using;
System.IO.StreamReader sr = new System.IO.StreamReader(Request.InputStream);
string line = sr.ReadToEnd();
I will then serialise this data using DataContractJsonSerializer.
Is using Request.InputStream the right way to read the JSON data? Can I retrieve it as a method parameter, or any other way that may be considered better?
Thanks
You can retrieve the data posted as a method parameter:
JS:
$.ajax({
url: "default.aspx/UpdateData"
data: '{ testString: "test", testInt: 123 }',
...
});
default.aspx:
[WebMethod]
public static void UpdateData(string testString, int testInt)
{
...
}
I would definitely recommend this approach as opposed to parsing the posted JSON. You can get a more complete example here: jQuery and ASP.NET AJAX PageMethods (see the second example)
You should send the JSON data in a POST variable. Then all you would have to do is access the request variable collection and pass the value into the parse method.

Localize javascript messages and validation text

I'm working on a web project that is multilingual. For example, one portion of the project involves some custom google mapping that utilizes a client-side interace using jquery/.net to add points to a map and save them to the database.
There will be some validation and other informational messaging (ex. 'Please add at least one point to the map') that will have to be localized.
The only options I can think of right now are:
Use a code render block in the javascript to pull in the localized message from a resource file
Use hidden fields with meta:resourcekey to automatically grab the proper localized message from the resource file using the current culture, and get the .val() in jquery when necessary.
Make a webservice call to get the correct message by key/language each time a message is required.
Any thoughts, experiences?
EDIT:
I'd prefer to use the .net resource files to keep things consistent with the rest of the application.
Ok, I built a generic web service to allow me to grab resources and return them in a dictionary (probably a better way to convert to the dictionary)...
<WebMethod()> _
<ScriptMethod(ResponseFormat:=ResponseFormat.Json, UseHttpGet:=False, XmlSerializeString:=True)> _
Public Function GetResources(ByVal resourceFileName As String, ByVal culture As String) As Dictionary(Of String, String)
Dim reader As New System.Resources.ResXResourceReader(String.Format(Server.MapPath("/App_GlobalResources/{0}.{1}.resx"), resourceFileName, culture))
If reader IsNot Nothing Then
Dim d As New Dictionary(Of String, String)
Dim enumerator As System.Collections.IDictionaryEnumerator = reader.GetEnumerator()
While enumerator.MoveNext
d.Add(enumerator.Key, enumerator.Value)
End While
Return d
End If
Return Nothing
End Function
Then, I can grab this json result and assign it to a local variable:
// load resources
$.ajax({
type: "POST",
url: "mapping.asmx/GetResources",
contentType: "application/json; charset=utf-8",
dataType: "json",
data: '{"resourceFileName":"common","culture":"en-CA"}',
cache: true,
async: false,
success: function(data) {
localizations = data.d;
}
});
Then, you can grab your value from the local variable like so:
localizations.Key1
The only catch here is that if you want to assign the localizations to a global variable you have to run it async=false, otherwise you won't have the translations available when you need them. I'm trying to use 'get' so I can cache the response, but it's not working for me. See this question:
Can't return Dictionary(Of String, String) via GET ajax web request, works with POST
I've done this before where there are hidden fields that have their values set on Page_Init() and Page_Load() with the appropriate values from the global and local resource files. The javascript code would then work with those hidden values.
Code Behind
this.hfInvalidCheckDateMessage.Value = this.GetLocalResourceObject("DatesRequired").ToString();
Page.aspx
$('#<%= btnSearch.ClientID %>').click(function(e) {
if (!RequiredFieldCheck()) {
var message = $("#<%= hfInvalidCheckDateMessage.ClientID %>").val();
alert(message);
e.preventDefault();
$("#<%= txtAuthDateFrom.ClientID %>").focus();
}
});
Disclaimer... Not sure if this was the best route or not, but it does seem to work well.
I've implemented a modified version of the solution described here: http://madskristensen.net/post/Localize-text-in-JavaScript-files-in-ASPNET.aspx
I changed it to allow for multiple resource file names, if the need for it arises, by changing the regular expression and by using the HttpContext.GetGlobalResourceObject method to retrieve the resource string.
I use this technique. It makes it easy for anyone with little coding experience to edit the phrase JavaScript file.
var lang = 0 // 0 = english, 1 = french
var phrases=[]
phrases["plans"] = "Rate Plans and Features|Forfaits et options").split("|")
then you output it as:
phrases["plans"][lang]
...add more columns as required.

Resources