Ajax Call Not Marked as IsAjaxRequest in MVC Controller - asp.net-mvc

I'm just looking at some Ajax requests in Fiddler whilst testing some exception handling classes and code in my application and I'm not sure my requests are well formed and as they should be.
My Javascript is:
$(function () {
$('#createentry').submit(function () {
e.preventDefault();
$.ajax({
url: this.action,
type: this.method,
dataType: "json",
data: $(this).serialize(),
success: function(result) {
$('#entries-list').append("<li>" + $('#newentry').val() + "</li>");
$('#newentry').val('').blur();
},
error: function (xhr)
{
try
{
var json = $.parseJSON(xhr.responseText);
alert(json.errorMessage);
}
catch (e)
{
alert('something bad happened');
}
}
});
return false;
});
});
In Fiddler the request looks like:
Host: localhost:54275
User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64; rv:20.0) Gecko/20100101 Firefox/20.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-gb,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://localhost:54275/Diary
Cookie: __RequestVerificationToken= <snipped for brevity>
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 216
I would expect the Accept: header to be set to json automatically I guess that's an incorrect assumption on my part, how is this set?
Also if I looks at the result of this in my action method the value is always false:
[HttpPost, ValidateAntiForgeryToken, JsonExceptionFilter]
public JsonResult PostNewEntry(DiaryEntryViewModel diaryEntry)
{
var req = Request.IsAjaxRequest();
req always = false so my JsonExceptionFilter isn't kicking in and taking care of the error reporting as expected.
Is there also a defined way of forcing only accepting requests correctly setup as Ajax requests in MVC?

I found this bug that is over five years old that says using .ajax() with a dataType of script or JSON would result in the header missing is a feature. But I would imagine Request.IsAjaxRequest() is looking for that exact header.
As a work around you could try doing something like:
$(document).ajaxSend(function (event, request, settings) {
request.setRequestHeader("X-Requested-With", "XMLHttpRequest");
});
which would append that header to every Ajax call jQuery sends.

After trying pretty much every solution I could find on the web with absolutely no success, I opted to start using the jQuery Form Plugin and I am now getting well formed Ajax requests on the server side.
Download the plugin from the link above and I then replaced my Ajax JavaScript with:
$(document).ready(function () {
$('#createentry').ajaxForm(function () {
alert("Thank you for your comment!");
});
});
After including this script and testing a call to:
Request.IsAjaxRequest();
Now correctly returns true.
Using Firebug to examine the requests being posted the required header that denotes the request as an Ajax request is present:
X-Requested-With XMLHttpRequest

Related

Render FileContentResult using javascript

I have an Web API written in Core 2 that returns a FileContentResult.
You need to do a GET with an Auth Token in the header for it to work.
If you try it with postman, the file renders fine and it also renders well in an MVC View.
Now we have an external Salesforce system trying to consume the API but due to the limitations of the APEX language they have to use Javascript to inject the token into the GET method.
Example code:
$(document).ready(function() {
$.ajax({
type: 'GET',
url: 'https://file-store.com/document/{! docId}',
headers: {
'Authorization': 'Bearer {! oauthToken}',
'Content-Type': 'application/json',
'Accept': 'application/json'
}
}).done(function (data) {
console.log(data);
});
});
This seems to work as the "data" that is returns contains a file - or at least an array of squiggles that look like the file serialized.
However, there seems to be no way to get the web view to render this.
I tried using embed
var object = '<embed scr="' + data + '" />';
or using an iframe
$('#iFrame').html(data);
or
$('#iFrame').html(object);
and lots of other things but so far had no success.
I do understand that in MVC this is simple, but is it at all feasible using javascript?
We do successfully receive the file, and we do have the data in memory, I just need way to render it on the browser.
Any suggestion is very welcome

Ajax calls to TFS 15 Rest Api stopped working after upgrade

In TFS 2015 Update 3 everything was working without issues. I used to consume all apis using the npm package request without any problems.
Using jquery the following call also would always complete correctly:
//this used to work in 2015 Update 3
var request = {
url: "https://my_server/tfs/DefaultCollection/_apis/projects?api-version=2.0",
type:'GET',
contentType: "application/json",
accepts: "application/json",
dataType: 'json',
data: JSON.stringify(data),
beforeSend: function (xhr) {
xhr.setRequestHeader("Authorization", "Basic " + btoa("my_username:my_password"));
}
};
$.ajax(request);
After upgrading to TFS 15 RC2 the above mechanism is not working anymore. The server always returns a 401 - Unauthorized error.
Testing the same call via curl, everything worked out well:
//this works well
curl -u my_username:my_password https://my_server/tfs/DefaultCollectiopis/projects?api-version=2.0
But again failed when I tried to send the credentials in the header, something like this:
//this will fail
curl https://my_server/tfs/DefaultCollection/_apis/projects?api-version=2.0 \
-H "Accept: application/json" \
-H "Authorization: Basic eNjPllEmF1emEuYmFuNppOUlOnVuZGVmaW5lZA=="
Same 401 - Unauthorized error.
I tried to set up my Personal Access token, since it is included in TFS 15 RC2, and do a test as indicated here
$( document ).ready(function() {
$.ajax({
url: 'https://my_server/defaultcollection/_apis/projects?api-version=2.0',
dataType: 'json',
headers: {
'Authorization': 'Basic ' + btoa("" + ":" + myPatToken)
}
}).done(function( results ) {
console.log( results.value[0].id + " " + results.value[0].name );
});
});
and it also fails. However, after replacing myPatToken for my actual password and passing my username as well, then the request completed successfully:
//everything works correctly with the headers like this
headers: {
'Authorization': 'Basic ' + btoa("my_username:my_password")
}
In the nutshell, something is going wrong when I setup the header like this (using jquery):
//this fails
beforeSend: function (xhr) {
xhr.setRequestHeader("Authorization", "Basic " + btoa("my_username:my_password"));
}
And looks like the package npm request, which is the one I'm using, also probably uses the beforeSend property or similar and it's failing.
//this used to work with 2015 Update 3, not anymore after upgrading to 15 RC2
var options = {
url: 'https://my_server/defaultcollection/_apis/projects?api-version=2.0',
method:'GET',
headers: {
'Authorization': "Basic " + btoa("my_username:my_password")
},
json: data
};
request(options, (error, response, body) => {
if (!error && response.statusCode == 200) {
console.log(response);
} else {
console.log(error);
}
});
It makes me think it is probably something in the IIS configuration but Basic Authentication is properly configured. Is there a way to get this working using the package request?
Something changed in the IIS configuration after the upgrade?
The problems got solved after restarting the server, so I guess my case was an isolated situation, not related with TFS it self.
Now sending the request using the request package seems to work well.
However, it is strange that testing it in the browser using jquery still fails. I noticed that
var username = "my_username",
password = "my_password";
btoa(my_username + ":" + my_password); //generates wrong encoded string
generates a different encoded string then simply
btoa("my_username:my_password") //generates right encoded string
The right one is a few characters shorter, this is an example:
eXVuaWQuYmZGV12lpmaW5lZA== //wrong
eXVuaWQuYmZGVsbEAxMw== //correct
No idea why, though.

Ajax request with content type set to application/json interpreted by Rails as text

I have 2 domains: language.com and bonjour.language.com.
I want to make a POST request from bonjour.language.com to the root domain.
I'm using Backbone:
model.save(null,
xhrFields:
withCredentials: true
)
I see the preflight request, then the actual request.
The request
Content-Type:application/json
Accept:application/json, text/javascript, /; q=0.01
the cookie is passed (Cookie: mp_3b2796f7...)
Host:language.com
Origin: bonjour.language.com
When a request is cross domain, the csrf token is obviously not passed, so I disabled the verification on the server for the create action.
In the controller, when I log request.format, I get text/html. Any ideas why?
(the response is a 406 Unacceptable, since I don't have a block handling the html format).
Found the solution, and it's pretty ironic.
Here's what ended up working:
model.save(null,
xhrFields:
withCredentials: true
crossDomain: false
)
crossDomain: false for a cross domain request? Weird right?
This tricks jQuery into sending the X-Requested-with header set to XMLHttpRequest.
It is not set by default for cross domain requests.
But it is necessary for Rails to know that the request is an XMLHttpRequest though, and so that it can use the content type to set the request format!
Another approach, lengthier but maybe more explicit would be to set the header yourself:
model.save(null,
xhrFields:
withCredentials: true
beforeSend: (request) ->
request.setRequestHeader('X-Requested-with', 'XMLHttpRequest')
)

JIRA Worklog API not working

I am trying to log work in JIRA using the Web API :-
My data is:
var post = {};
post.commment = "Test";
post.timeSpent = "6h";
My Ajax call is:
$.ajax({
url: lv_url,
type : 'POST',
data : post,
headers: {
Accept : "application/json; charset=utf-8",
},
contentType: "application/json; charset=utf-8",
dataType : 'json',
xhrFields: {
withCredentials: true
},
async: false,
success : function(data) {
}
});
https://jiraserver.co/rest/api/2/issue/SOCOMPT-1575/worklog
"GET" call is working fine but when i try to POST i get the error:-
1) OPTIONS https://jiraserver.co/rest/api/2/issue/SOCOMPT-1575/worklog 500 (Internal Server Error)
2) XMLHttpRequest cannot load https://jiraserver.co/rest/api/2/issue/SOCOMPT-1575/worklog. Invalid HTTP status code 500
These are the 2 errors is get.
Please Help Guys i really need to get this working.
Thanks in advance,
Vishesh.
I was also strugging on this one as I kept getting HTTP 500 when trying to post to the worklog endpoint.
if you are able check the jira server logs (under logs/catalina.out)
jira seems to be very picky with the iso8601 date format
Try setting also the "started" timestamp in your payload as I believe this is required (for the API like the web UI) even if the documentation is not really clear on that.
post.started = '2015-02-25T14:01:30.000-0500';

jQuery.Load() not triggering Request.IsAjaxRequest in ASP.NET MVC2

I'm using the Jquery full calendar plugin, and i want to be able to click on an event and the details of the event to be populated via AJAX into a div with the id of #details.
here is my controller action that i'm trying to load. When debugging, the action does not consider the incoming request to be AJAX and returns the full view instead of the partial. Does it matter if the full view is called the same as the partial view? Ie; 'Details.aspx' & 'Details.ascx'?
public ActionResult Details(int id)
{
Pol_Event pol_Event = eventRepo.GetEvent(id);
ViewData["EventTypes"] = et.GetEventType(id);
if (pol_Event == null)
return View("NotFound");
else
{
if(HttpContext.Request.IsAjaxRequest()){
return PartialView("Details");
}
else
return View(pol_Event);
}
}
Here is the jquery code i'm using. Am i missing not using .load() correctly in the eventClick function? The Developer of the calendar plugin has confirmed that eventClick has nothing to do with AJAX so the fault must lie in my code.
$(document).ready(function() {
$('#calendar').fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek,agendaDay'
},
events: "/Events/CalendarData",
allDayDefault: false,
selectable: true,
eventClick: function(event) {
$('details').load(event.url);
},
eventRender: function(event, element) {
element.qtip({
content: event.title + " # " + event.venue,
position: {
corner: {
target: 'topLeft',
tooltip: 'bottomLeft'
}
}
});
}
});
});
So am i using the Jquery.Load() function incorrectly, or is there something wrong with my controller?
More updates: I finally caught the problem. The XMLHttpRequest is being sent but i'm encountering a 500 internal server error, not solved yet as i can't figure out what's causing the error.
Host: localhost:4296
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.8) Gecko/20100722
Firefox/3.6.8
Accept: text/html, */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
X-Requested-With: XMLHttpRequest
Referer: http://localhost:4296/Events/EventCalendar
Cookie: .ASPXAUTH=56C5F4FD536564FF684F3F00E9FB51A5F2F1B22D566C517923D71FEAF599D266531CAC52BF49D2700E048DD420A4575456855303CC2DCB5875D4E1AD8883821EA62E5169969503776C78EB3685DAA48C
UPDATE: I finally figured out what the problem was. I wasn't passing in the model to the partial so the line
return PartialView("Details");
Should have been
return PartialView("Details", pol_Event);
this was generating the 500 internal service error.
When you make an Ajax request you're suppose to set the 'X-Requested-With' HTTP header to something like 'XMLHttpRequest' eg.
Host www.google.com
User-Agent Mozilla/5.0 (Windows; U; Windows NT 6.1; (snip...)
Accept */*
Accept-Language en-us,en;q=0.5
Accept-Encoding gzip,deflate
Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive 115
Connection keep-alive
X-Requested-With XMLHttpRequest
Referer http://www.google.com
This 'X-Requested-With' header is what the 'IsAjaxRequest()' method looks for. Normally, jQuery's Ajax methods will send this header automatically. My guess is that for some reason the jQuery Calendar plugin isn't sending this header.
I would download something like fiddler, or install Firebug for Firefox and check the raw HTTP Request/Response data when the Ajax request/Calendar control is fired/initialised. See if the X-Requested-With header is being included.
Yes. Although it doesn't have to be sent as a HTTP Request Header. You can POST it in a form data or in the query string of a GET. www.example.com?x-requested-with=XMLHttpRequest (case sensitive value)
Seems ridiculous but true. I've tried it and it works :) Reflection on the IsAjaxRequest() extension method will prove this:
return ((request["X-Requested-With"] == "XMLHttpRequest") || ((request.Headers != null) && (request.Headers["X-Requested-With"] == "XMLHttpRequest")));

Resources