JSONP + ASP.NET - Response is incomplete - c#

We have been wrestling with the confines of ASP.NET trying to get JSONP working. We're trying to check whether a file exists on a different server and return a boolean value. The function is called on jquery's ready() function, so it should happened after all DOM elements are loaded.
We've used the HTTPModule request/response rewriter linked here:
http://www.codeproject.com/KB/webservices/ASPNET_JSONP.aspx
The AJAX call:
function CheckFileExists() {
var _FileID = $('#FileID').val();
var button = $('#btnViewFiles');
button.val('Checking...').css('color', '');
$.ajax({
type: "GET",
url: localAdminUrl + "WebServices.asmx/CheckFileExists",
data: { FileID: _FileID },
contentType: "application/json; charset=utf-8",
dataType: "jsonp",
success: function (data, textStatus, jqXHR) {
if (data.d == true) {
button.attr('onClick', 'ViewFiles(_FileID,false);').removeAttr('disabled').val('View documents').css('color', '#22CA00');
} else {
button.val('No documents').css('color', '#DD3BB3').removeAttr('onClick').attr('disabled', 'disabled');
}
},
error: function (jqXHR, textStatus, errorThrown) {
button.val('Error occurred').css('color', '#DD3BB3').removeAttr('onClick').attr('disabled', 'disabled');
}
});
}
Now, for some reason the response occasionally decides to omit the end parentheses and semicolon, leaving an incomplete response, and JSON crying "parsererror".
example:
jQuery<numbers>_<numbers>({"d":false}
instead of the expected:
jQuery<numbers>_<numbers>({"d":false});
The baffling thing is that it only happens occasionally - some requests end up complete and parse correctly. What on earth is going on?
I've tried rewriting the HTTPModule such that the response is written once instead of three times:
public override void Write(byte[] buffer, int offset, int count)
{
var b1 = Encoding.UTF8.GetBytes(_context.Request.Params["callback"] + "(");
var b2 = Encoding.UTF8.GetBytes(");");
byte[] finalResponse = new byte[b1.Length + buffer.Length + b2.Length];
b1.CopyTo(finalResponse,0);
buffer.CopyTo(finalResponse, b1.Length);
b2.CopyTo(finalResponse, b1.Length + buffer.Length);
_responseStream.Write(finalResponse, 0, finalResponse.Length);
/* Old way
_responseStream.Write(b1, 0, b1.Length);
_responseStream.Write(buffer, offset, count);
var b2 = Encoding.UTF8.GetBytes(");");
_responseStream.Write(b2, 0, b2.Length);
*/
}
Doesn't seem to have helped though.

It turns out the GZIPStream compression module which we use is buggy, see here: GZipStream And DeflateStream will not decompress all bytes
We've removed the module from use for the time being and the responses are now being returned consistently complete.

Related

Laravel API returning blank/null to RestSharp C#

I'm using Laravel as a web API that communicates with my C# app.
I'm trying to make a post request:
if ($validate){
// Store query results in a variable
$user = Login::where([
['BR_ID', $BR_ID],
['ClientID', $ClientID],
['ClientChkID', $ClientChkID],
['LastName', $LastName]
])->get();
// Format contact number
$ContactNo = $user[0]->ContactNo;
$otpController = new \App\Http\Controllers\OTPController();
$phone = $otpController->CheckContactValidity($ContactNo);
// Append formatted number to laravel's collection object
$user[0]->ValidContactNo = $phone;
// send back a response
return response()->json($user[0], 200);
} else {
return response()->json(["error"=>"Client does not exist"], 204);
}
The code in the if statement works well and returns everything fine. The else part though, does not return anything at all.
Basically, the line return response()->json(["error"=>"Client does not exist"], 204); always returns "" instead of { "error":"Client does not exist" }
This is nonsense. 204 status code is a no-content response, so why you want to return something?
https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#2xx_Success
you can check the response code by
$.ajax({
url: "/test",
type: 'GET',
contentType: "application/json; charset=utf-8",
dataType: 'json',
success: function(res) {
}
})
.done(function ( data, textStatus, jqXHR) {
console.log(jqXHR.status); // 204
});

XMLHttpRequest Exception 101 on IOS devices

I recently started getting the following message on a jquery ajax call only on IOS devices:
ERROR: NETWORK_ERR:
XMLHttpRequest Exception 101
The ajax call worked well for months on all devices but one of my clients started getting this message last week.
I have read some about it being a cross domain request problem but that should not be applicable in this case.
I have also read that changing async to true will fix the problem but I want to avoid that if I can.
Here is the ajax call:
the serverSideFunction parameter is in the form "AdvancedDistribution.aspx/SaveClicked"
where AdvancedDistribution.aspx is of course the aspx file and SaveClicked is the static WebMethod(C#).
para is just a 2d array with the parameter values.
function ajaxCall(serverSideFunction, para)
{
ajaxReturn = "";
var dataPara = "{";
for (var i = 0; i < para.length; i++)
{
dataPara += "'" + para[i][0] + "':'" + para[i][1] + "'";
if (i < para.length - 1)
dataPara += ",";
}
dataPara += "}";
$.ajax({
type: "POST",
url: serverSideFunction,
data: dataPara,
async: false,
//&&JS01112013.2 Fix bug caused by IOS6 ajax caching
headers: {"cache-control": "no-cache"},
beforeSend: function (xhr)
{
xhr.setRequestHeader("Content-type", "application/json; charset=utf-8");
},
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (msg, status)
{
ajaxReturn = msg.d;
},
error: function (xhr, msg, e)
{
alert(e); //Error Callback
alert('Ajax Callback Failed');
}
});
return ajaxReturn;
}
Since this is still working on most devices I'm hoping that it will be as simple as just adding and IOS required header to the ajax call.
Any Ideas?
Thanks.

response text undefined asp.net code behind

var req = $.ajax({
type: 'GET',
cache: false,
url: 'loc.aspx?count=' + str,
dataType: 'json',
contentType: "application/json; charset=utf-8",
async: false,
data:'{}',
success: function (data) {
alert(data.responseText);
}
});
req.fail(function (data) {
TINY.box.show({ html: 'Server Error. Try again: ' + data.responseText, animate: false, close: false, boxid: 'error', top: 100 });
});
the above code used to work right in jsp, now i am trying to use in asp.net c#, any way I am getting correct data in error block which i want it in success block. Even data.d is not helping,
If i write something like alert(data) i am getting the complete html, I need just the response text, When i use like this data.responseText, I am getting undefined. Someone help pls.
Thanks
Code below should work fine. I've added some comments where you are doing a mistake
var req = $.ajax({
type: 'GET',
cache: false,
url: 'loc.aspx?count=' + str,
dataType: 'html',// as you return a simple html dataType:json will throw an error as jquery will not be able to parse received string
contentType: "application/json; charset=utf-8",
async: false,
data:'{}',
success: function (data) {
alert(data);// data is not an XHR object. it is a processed response. In your case - simple string with HTML which, of course, has no method responseText
}
});
req.fail(function (data) {
TINY.box.show({ html: 'Server Error. Try again: ' + data.responseText, animate: false, close: false, boxid: 'error', top: 100 });
});
In .fail function you have data.responseText because in this case XHR object is passed as a first parameter (See this). At the same time, first parameter of success callback is a clean data received with request. If without details, you can think that data == xhr.responseText in success callback. See success property description in this section
upd
As appeared, problem is not only with JS. I guess you have a simple .aspx page which is called with ajax. There are two solutions:
1) Use webservice instead. It will be better because it does not go through complete page load cycle and should be executed faster. And it will not produce unused HTML
2) aspx page will output some HTML by default. Before you return a response for ajax request, you should clear response (so HTML which is already generated will not be sent to a server), write your response and immediately end it:
Response.Clear();
Response.Write("hello");
Response.End();
This way you should receive only hello in success.

Working example of AJAX file upload to WCF service

I'm looking for an example of an ajax call for streaming data to a WCF service. I am always getting an error.
Any help appreciated, or even links to blogs with a solution.
This is my WCF service class
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class Images : IImages
{
string IImages.UploadImage(string fileKey, Stream imageStream)
{
using (var fileStream = File.Create(#"Images\" + fileKey))
{
imageStream.CopyTo(fileStream);
}
return "done";
}
}
and my contract is
[OperationContract(Name = "UploadImage")]
[WebInvoke(UriTemplate = "?file_key={fileKey}", Method = "POST", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare)]
string UploadImage(string fileKey, Stream imageStream);
I have web.config stream binding
<binding name="PublicStreamBinding"
maxReceivedMessageSize="2000000000" transferMode="Streamed">
<security mode="None" />
</binding>
my ajax client call is like this
var data = '{"image":"' + uri + '"}'
$.ajax({
url: GetServerUrl()+"images.svc/?file_key="+options.fileKey,
type: "POST",
contentType: "application/json",
data: data,
success: function (result) {
console.log("SUCCESS");
},
error: function (jqXHR, textStatus, errorThrown) {
console.log("error in transfer::" + jqXHR.responceText);
}
});
I can't comment on the server-side code, but client-side :
the data variable should be a plain javascript object, not a JSON representation
url shouldn't need the GetServerUrl() prefix; try a leading "/" instead
for a POST request it's more normal to include all parameters in the data object rather than tacking them onto the URL, which is the GET approach. It depends what the server-side code is set up to expect but as far as I can tell, it expects file_key to be in the POST.
You should end up with something like this :
var data = {
image: uri,
file_key: options.fileKey
};
$.ajax({
url: "/images.svc/",//probably
type: "POST",
contentType: "application/json",
data: data,
success: function (result) {
console.log("SUCCESS");
},
error: function (jqXHR, textStatus, errorThrown) {
console.log("errror in transfer::" + jqXHR.responceText);
}
});
Install Fiddler ( www.telerik.com/fiddler ). Launch it. Make the web service call. Click on the record of the call in Fiddler. Click on the 'Raw' tabs for request and response. It will be enlightening and you will see exactly what is passed between server and client. Perhaps some addition WCF troubleshooting data as well in the response.
Also, don't forget to check your Application event log on the machine running the WCF service. You can also add a Global.asax to the WCF project (if its a web project) and put logging code in the Application_Error method. Something like this:
protected void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
if (ex is ThreadAbortException)
{
// Nothing to do here. The thread abended.
}
else
{
activityMgr.Add(System.Reflection.MethodBase.GetCurrentMethod(), ex);
}
}

Error calling web method from jQuery

I am calling a WebMethod from jQuery doing the following:
function WebMethod(fn, paramArray, successFn, errorFn) {
var paramList = {};
if (paramArray.length > 0) {
for (var i = 0; i < paramArray.length; i += 2) {
paramList[paramArray[i]] = paramArray[i + 1];
}
}
var params = $.toJSON(paramList);
$.ajax({
type: 'POST',
url: '../../PricingEngine/ContractView.aspx' + '/' + fn,
contentType: 'application/json; charset=utf-8',
data: params,
dataType: 'json',
success: successFn,
error: function(xhr, status, error) {
// Display a generic error for now.
alert("AJAX Error!");
}
});
}
// Used returned object to populate every field
function updateTextFields(result) {
//do some processing here
}
function failed(result) {
alert('failed');
}
// EVENTS
// ------------------------------------------------------------
$(".editableField").keydown(function(e) {
WebMethod('PriceContract',
[
'AQ', aq.val(),
'SOQ', soq.val()
], updateTextFields, failed);
});
The JSON string after the .toJSON has been called:
{"AQ":"140000","SOQ":"1169"}
The C# method
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public static ContractsListPricing PriceContract(string AQ, string SOQ)
{
ContractsListPricing clp = new ContractsListPricing();
clp.Aq = 1;
clp.Soq = 2;
return clp;
}
This is returning the following error:
Invalid JSON: (Followed by the complete HTML of the current page).
Please take no notice of the logic in the C# as this isn't implemented yet. I am using the jquery-json plugin to parse the JSON.
Thanks
Ive run a demo of your code and got it working fine. Have you checked that you have the ScriptModule Handler set correctly in your web.config?
You're sure the exact url is '../../PricingEngine/ContractView.aspx' + '/' + fn ?
Because ContractView.aspx IS your current webpage

Categories

Resources