Is there a Request.IsMvcAjaxRequest() equivalent for jQuery? - javascript

I prefer to use jQuery with my ASP.NET MVC apps than the Microsoft Ajax library. I have been adding a parameter called "mode" to my actions, which I set in my ajax calls. If it is provided, I return a JsonViewResult. If it isn't supplied, I assume it was a standard Http post and I return a ViewResult.
I'd like to be able to use something similar to the IsMvcAjaxRequest in my controllers when using jQuery so I could eliminate the extra parameter in my Actions.
Is there anything out there that would provide this capability within my controllers or some simple way to accomplish it? I don't want to go crazy writing code since adding a single parameter works, it just isn't ideal.

Here's an except from MVC RC1 release notes - Jan 2009
IsMvcAjaxRequest Renamed to IsAjaxRequest
The IsMvcAjaxRequest method been
renamed to IsAjaxRequest. As part of
this change, the IsAjaxRequest method
was updated to recognize the
X-Requested-With HTTP header. This is
a well known header sent by the major
JavaScript libraries such as
Prototype.js, jQuery, and Dojo.
The ASP.NET AJAX helpers were updated to send this header in
requests. However, they continue to
also send it in the body of the form
post in order to work around the issue
of firewalls that strip unknown
headers.
In other words - it was specifically renamed to be more 'compatible' with other libraries.
In addition, for anyone who hasnt read the full release notes but has been using previous versions - even as recent as the beta - I STRONGLY recommend you read them in full. It will save you time in future and most likely excite you with some of the new features. Its quite surprising how much new stuff is in there.
Important note: You will need to make sure you upgrade the .js file for MicrosoftAjax.MVC (not the exact name) if upgrading to RC1 from the Beta - otherwise this method won't work. It isn't listed in the release notes as a required task for upgrading so don't forget to.

See Simons answer below. The method I describe here is no longer needed in the latest version of ASP.NET MVC.
The way the IsMvcAjaxRequest extension method currently works is that it checks Request["__MVCASYNCPOST"] == "true", and it only works when the method is a HTTP POST request.
If you are making HTTP POST requests throug jQuery you could dynamically insert the __MVCASYNCPOST value into your request and then you could take advantage of the IsMvcAjaxRequest extension method.
Here is a link to the source of the IsMvcAjaxRequest extension method for your convenience.
Alternatively, you could create a clone of the IsMvcAjaxRequest extension method called
IsjQueryAjaxRequest that checks Request["__JQUERYASYNCPOST"] == "true" and you could dynamically insert that value into the HTTP POST.
Update
I decided to go ahead and give this a shot here is what I came up with.
Extension Method
public static class HttpRequestBaseExtensions
{
public static bool IsjQueryAjaxRequest(this HttpRequestBase request)
{
if (request == null)
throw new ArgumentNullException("request");
return request["__JQUERYASYNCPOST"] == "true";
}
}
Checking from an action if a method is a jQuery $.ajax() request:
if (Request.IsjQueryAjaxRequest())
//some code here
JavaScript
$('form input[type=submit]').click(function(evt) {
//intercept submit button and use AJAX instead
evt.preventDefault();
$.ajax(
{
type: "POST",
url: "<%= Url.Action("Create") %>",
dataType: "json",
data: { "__JQUERYASYNCPOST": "true" },
success: function(data) {alert(':)');},
error: function(res, textStatus, errorThrown) {alert(':(');}
}
);
});

Why don't you simply check the "X-Requested-With" HTTP header sent automatically by most Javascript libraries (like jQuery) ?
It has the value 'XMLHttpRequest' when a GET or POST request is sent.
In order to test it you should just need to check the "Request.Headers" NameValueCollection in your action, that is :
if (Request.Headers["X-Requested-With"] == "XMLHttpRequest")
return Json(...);
else
return View();
This way, you can simply differentiate regular browser requests from Ajax requests.

Ok, I have taken this one step farther and modified my jQuery file to load the additional parameter into the post data, so I don't have to repeat the "__JQUERYASYNCPOST: true" for every call to post. For anybody that's interested, here's what my new definition for $.post looks like:
post: function(url, data, callback, type) {
var postIdentifier = {};
if (jQuery.isFunction(data)) {
callback = data;
data = {};
}
else {
postIdentifier = { __JQUERYASYNCPOST: true };
jQuery.extend(data, postIdentifier);
}
return jQuery.ajax({
type: "POST",
url: url,
data: data,
success: callback,
dataType: type
});
}
I added the "postIdentifier" variable as well as the call to jQuery.extend. Now the Helper explained in spoon16's response works without having to add any thing special to my page-level jQuery code.

Related

Get jQuery $.ajax to send data in body for GET [duplicate]

The service API I am consuming has a given GET method that requires the data be sent in the body of the request.
The data required in the body is a list of id's separated by hypen and could potentially be very large and thus it must be sent in the body otherwise it will likely foobar somewhere in the browsers/proxies/webservers etc chain. Note I don't have control over the service or API so please don't make suggestions to change it.
I am using the following jQuery code however observing the request/response in fiddler I can see that the "data" I am sending is ALWAYS converted and appended to the query string despite me setting the "processData" option to false...
$.ajax({
url: "htttp://api.com/entity/list($body)",
type: "GET",
data: "id1-id2-id3",
contentType: "text/plain",
dataType: "json",
processData: false, // avoid the data being parsed to query string params
success: onSuccess,
error: onError
});
Anyone know how I can force the "data" value to be sent in the body of the request?
In general, that's not how systems use GET requests. So, it will be hard to get your libraries to play along. In fact, the spec says that "If the request method is a case-sensitive match for GET or HEAD act as if data is null." So, I think you are out of luck unless the browser you are using doesn't respect that part of the spec.
You can probably setup an endpoint on your own server for a POST ajax request, then redirect that in your server code to a GET request with a body.
If you aren't absolutely tied to GET requests with the body being the data, you have two options.
POST with data: This is probably what you want. If you are passing data along, that probably means you are modifying some model or performing some action on the server. These types of actions are typically done with POST requests.
GET with query string data: You can convert your data to query string parameters and pass them along to the server that way.
url: 'somesite.com/models/thing?ids=1,2,3'
we all know generally that for sending the data according to the http standards we generally use POST request.
But if you really want to use Get for sending the data in your scenario
I would suggest you to use the query-string or query-parameters.
1.GET use of Query string as.
{{url}}admin/recordings/some_id
here the some_id is mendatory parameter to send and can be used and req.params.some_id at server side.
2.GET use of query string as{{url}}admin/recordings?durationExact=34&isFavourite=true
here the durationExact ,isFavourite is optional strings to send and can be used and req.query.durationExact and req.query.isFavourite at server side.
3.GET Sending arrays
{{url}}admin/recordings/sessions/?os["Windows","Linux","Macintosh"]
and you can access those array values at server side like this
let osValues = JSON.parse(req.query.os);
if(osValues.length > 0)
{
for (let i=0; i<osValues.length; i++)
{
console.log(osValues[i])
//do whatever you want to do here
}
}
Just in case somebody ist still coming along this question:
There is a body query object in any request. You do not need to parse it yourself.
E.g. if you want to send an accessToken from a client with GET, you could do it like this:
const request = require('superagent');
request.get(`http://localhost:3000/download?accessToken=${accessToken}`).end((err, res) => {
if (err) throw new Error(err);
console.log(res);
});
The server request object then looks like {request: { ... query: { accessToken: abcfed } ... } }
You know, I have a not so standard way around this. I typically use nextjs. I like to make things restful if at all possible. If I need to make a get request I instead use post and in the body I add a submethod parameter which is GET. At which point my server side handles it. I know it's still a post method technically but this makes the intention clear and I don't need to add any query parameters. Then the get method handles a get request using the data provided in the post method. Hopefully this helps. It's a bit of a side step around proper protocol but it does mean there's no crazy work around and the code on the server side can handle it without any problems. The first thing present in the server side is if(subMethod === "GET"){|DO WHATEVER YOU NEED|}

IE not show newest data

I use AngularJS to get data from server. It work well in chrome and firefox if data in server changed. But in IE, It does not show the newest data. I think because IE save data in cache so I send request to server to get new data but IE still shows old data.
How to fix this bug.
Try to use this: https://github.com/saintmac/angular-cache-buster
It adds a query string to the requests like ?timestamp=123456789 to disallow IE to cache it.
Basically if you don't want to use that, you have just to add a different query string to the url requested each time. This prevents IE from caching the request.
IE caches the call, and if you are going to send the same call, then IE will return the cached data.
If you are using $http for your calls, then you can simply add the following code in config function
$httpProvider.defaults.headers.common['Cache-Control'] = 'no-cache, no-store, must-revalidate';
$httpProvider.defaults.headers.common['Pragma'] = 'no-cache';
$httpProvider.defaults.headers.common["If-Modified-Since"] = "0";
However, if you are using jQuery or even $http (another solution), add timestamp in the call along with existing parameters.
jQuery.ajax({
url: "your_url",
data: {
param1 : value1 ,
timestamp : new Date().getTime()
},
success: successCallbackFn
});

Fail to send html content to webservice gives error not found

I am trying to send html content as a string to a webservice but failing with an error not found although the same call works if i send a simple string like "test".
Webservice Code:
public string List(DateTime showdate, string viewtype, int timezone, string test)
{
------ whatever ------
}
Javascript Code:
var showdate = "22/05/2014",
viewtype = "rest",
timezone = 2,
test = $("body").html(); // if i change to something like: test = "My name is Inigo Montoya" it works fine.
$.ajax({
type: option.method,
url: option.url,
data: {"showdate": showdate, "viewtype": viewtype, "timezone": timezone, "test": test},
success: function(data){ //--- whatever --- },
error: function(data){ //--- whatever --- }
});
You can open the chrome inspector on your code testing page, and directly paste the above javascript code to see what kind of error is returned.
I can think of 2 problems now:
Over-lengthy URL
The jQuery code that you used to fire the ajax call should be fine, but those 2 params type and data can leads to the problem.
For example, if $("body").html() is over 2000 characters and the request method is set as GET, the ajax call won't work because the URL will be too long to be understood by the browser.
Given that you mentioned
if i change to something like: test = "My name is Inigo Montoya" it works fine.
I believe the possiblility of this issue is quite high.
Cross-domain ajax
If the target location is a foreign domain, they can potential deny the access by your AJAX call.
Same as above, it is highly recommended to check this problem via Chrome inspector for this issue.
Try this, as you tagged under webservices and json, Hope this should work for you,
var data={"showdate": showdate, "viewtype": viewtype, "timezone": timezone, "test": test};
var jsonData= JSON.stringify(data);
$.ajax({
type: option.method,
url: option.url,
data: jsonData,
success: function(data){ //--- whatever --- },
error: function(data){ //--- whatever --- }
});
I believe you may be hitting ASP's built-in request validation which is used to prevent XSS (Cross-site-scripting).
By default, posting a field which contains HTML can cause it reject a request.
Request validation is a feature in ASP.NET that examines an HTTP request and determines whether it contains potentially dangerous content. In this context, potentially dangerous content is any HTML markup or JavaScript code in the body, header, query string, or cookies of the request. ASP.NET performs this check because markup or code in the URL query string, cookies, or posted form values might have been added for malicious purposes.
Have a look at this MSDN page for more information.
Note that it is possible to disable request validation for a single field instead of doing it site-wide...
(taken from this Stack Overflow question)
On a controller action:
[ValidateInput(false)]
ActionResult SomeAction(string validationIgnored){...}
or a specific model property:
[AllowHtml]
string SomeProperty {get; set;}
Note thst this protection is here for a reason, and if you disable it, you're accepting responsibility for validating the input yourself. Have a look at this blog post by Rick Strahl for some suggestions and alternatives.

Difference between $("#id").load and $.ajax?

Does anyone know what is the difference between $("#id").load and $.ajax?
Let me clarify things for you a little bit :
$.ajax() is the basic and low-level ajax function jQuery provides which means you can do what ever you want to like you can work with XmlHttpRequest object. But once upon a time jQuery Developers thought that actually besides $.ajax(), they could provide more specific methods to developers so they wouldn't need to pass more parameters to make $.ajax() method work the way they want. For example they said instead of passing json as a parameter to $.ajax() to indicate return data type, they provided $.getJSON() so we would all know that the return type we expected was json, or instead of indicating send method as post or get, you could use $.post() or $.get() respectively.
So load() is the same thing, it can help you inject html data into your html. with load() method you know that an html portion is being expected.
Isn't that cool ?
I think I've been fallen in love.
For more information, you can visit jquery.com, they are even providing their new library and api tutorial page.
Edit :
$.ajax({
type: "POST",
url: "some.php",
data: "name=John&location=Boston",
success: function(msg){
alert( "Data Saved: " + msg );
}
});
is the same as below :
$.post("some.php", { name: "John", time: "2pm" },
function(data){
alert("Data Loaded: " + data);
});
Now as you can see it is the simplified version of $.ajax(), to make post call, you need to pass some information of send method type which is post as shown at the first example but instead of doing this you can use $.post() because you know what you are doing is post so this version is more simplified and easy to work on.
But don't forget something. Except for load(), all other ajax methods return XHR (XmlHttpRequest instance) so you can treat them as if you were working with XmlHttpRequest, actually you are working with it tho :) and but load() returns jQuery which means :
$("#objectID").load("test.php", { 'choices[]': ["Jon", "Susan"] } );
in the example above, you can easly inject the return html into #objectID element. Isn't it cool ? If it wasn't returning jQuery, you should have been working with callback function where you probably get the result out of like data object and inject it manually into the html element you want. So it would be hassle but with $.load() method, it is really simplified in jQuery.
$("#feeds").load("feeds.php", {limit: 25}, function(){
alert("The last 25 entries in the feed have been loaded");
});
You can even post parameters, so according to those parameters you can do some work at server-side and send html portion back to the client and your cute jQuery code takes it and inject it into #feeds html element in the example right above.
load() initiates an Ajax request to retrieve HTML that, when returned, is set to the given selector.
All the jQuery Ajax functions are simply wrappers for $.ajax() so:
$("#id").load(...);
is probably equivalent to:
$.ajax({
url: "...",
dataType: "html",
success: function(data) {
$("#id").html(data);
}
});
A more concise summary and the most important difference is that $.ajax allows you to set content-type and datatype.
These two are important for making JSON requests, or XML requests. ASP.NET is more fussy with a missing content-type field (atleast when you use [WebMethod]) and will simply return the HTML of the page instead of JSON.
$.load() is intended to simply return straight HTML. $.ajax also gives you
caching
error handling
filtering of data
password
plus others.
From the documentation ...
$(selector).load(..)
Load HTML from a remote file and inject it into the DOM.
$.ajax(...)
Load a remote page using an HTTP request. This is jQuery's low-level AJAX implementation.
load is specifically for fetching (via GET unless parameters are provided, then POST is used) an HTML page and directly inserting it into the selected nodes (those selected by the $(selector) portion of $(selector).load(...).
$.ajax(...) is a more general method that allows you to make GET and POST requests, and does nothing specific with the response.
I encourage you to read the documentation.
Here's the source code for the load function: http://github.com/jquery/jquery/blob/master/src/ajax.js#L15
As you can see, it's a $ajax with some options handling. In other words, a convenience method.
The above answer may not be valid anymore in light of the use of deferred and promise objects. I believe that with .ajax you can use .when but you cannot do so with .load. In short, I believe that .ajax is more powerful than .load. For example:
some_promise = $.ajax({....});
.when(some_promise).done(function(){.... });
You get more granular control over the html loading. There is also .fail and .always for failure and "no matter what" cases. You don't get this in load. Hope I am correct on this.

Error when calling webservice with jquery

I have read a lot about jquery and i have a webservice where i convert a companyID to the real companyName. Now i want to call that webservice with jquery or javascript. The webservice is on host http://webservice/service.asmx en i'm working on http://tlmos. I don't work and i always get an error
Here is my code:
<script type="text/javascript" src="http://kmosvi24/_layouts/jquery-1.3.2.min.js"></script>
<script type="text/javascript">
var test = "KBEACDNV";
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: "http://webservice/service.asmx/getCompanyByCompanyID",
data: "{'sCompanyID:' + 'test'}",
dataType: "json",
succes:function(response){ alert("good"); },
error: function(response) { alert("Uh oh"); },
complete: function(response) { alert("" + response); }
});
</script>
Can someone help me?
thx
Umm.. you spelled success wrong on line 11
.. and you probably want to format your data as
data: "sCompanyID=test"
Take a quick pass through the jQuery API page on this one to verify you are passing the parameters that your service expects. It looks like you are expecting a SOAP packet with an ASMX service, and jQuery is more suited to hitting a restful service generated from an ASHX file or WCF service.
You can make a request to a different server, but only if the call uses GET. Since all you do is lookup anyway, a GET request should be fine.
As some othe people have pointed out you cannot call a webservice on another domain, however as you are using ASP.NET, you can write a raw HTTP handler (normally with an .ashx extension to proxy your request from client to server.) Which you'd place on your "timos" server
so in your ashx file you can write something along the lines of...
public void ProcessRequest (HttpContext context)
{
XmlDocument wsResponse = new XmlDocument();
string url = "http://webservice/service.asmx/getCompanyByCompanyID?CompanyID="
context.Request.Form["CompanyID"].ToString()
wsResponse.Load(url);
string XMLDocument = wsResponse.InnerXml;
context.Response.ContentType = "text/xml";
context.Response.Write(XMLDocument);
}
Hope this helps.
You can't do AJAX calls to hosts other than your own. If you really have to do this make a call to your own server and use a simple proxy to redirect to the domain you need.
You could do this for example by using a ProxyPass-directive in your webserver:
ProxyPass /service/ http://webservice/service.asmx
ProxyPassReverse /service/ http://webservice/service.asmx
Then you can issue an AJAX-request to /service/getCompanyByCompanyID and it will be proxied to the correct URL.
I don't think you are using the data parameter right, usually it's a key-value pair like:
data: {sCompanyID: 'test'}
I believe that they way you are using it will result in jQuery attempting to post to http://webservice/service.asmx/getCompanyByCompanyID?sCompanyID:blah
Also aren't .NET web services SOAP? I don't think jQuery can parse that...
edit: Nevermind, didn't realize you were passing these as json data. Thanks commenters!
In order to run your web-services from Jquery, you should use either WCF or just usual web services, but you should add [ScriptMethod] to your service's method and [ScriptService] to your webservice description.
Wow wow
just noticed that you're trying to call the service from one host to another... that one won't work. service should be hosted on the same domain as the page where it's being called from.
as a reply to Jeff's answer, correct way to format data is data: {key: "value"}
With jQuery Ajax Requests you need to use the following format when defining the variables to be sent in the request:
data: "variableName=variableContent",
You wrote:
data: "{'sCompanyID:' + 'test'}"
This won't work for two reasons:
- You have included curly brackets which don't need to be there.
- You have used a semi-colon,":", instead of an equals sign,"=".
So long as you change these it should work.
P.S I only just realized that Jeff Fritz has already given you the right answer. His answer is spot on!

Categories