Jquery AJAX (json) cross domain request and ASP.NET MVC - asp.net-mvc

Seemed to me to be a beaten theme, but i couldn't find the answer. =(
I make jquery ajax requst to
localhost:666 from localhost:555 application
$.ajax({
url: "http://localhost:666/request",
dataType: 'json',
timeout: 5000,
success:...
i've got in chrome:
XMLHttpRequest cannot load http://localhost:666/request. Origin http://localhost:555 is not allowed by Access-Control-Allow-Origin.
What is the solution of the problem?

You can initiate cross-domain request in your webpage by creating either XMLHttpRequest object or XDomainRequest object. End user's web-browser will request data from the domain's server by sending an "Origin" header with the value of origin. If server responds with an "Access-Control-Allow-Origin: * | Origin" then we are permitted to access data; otherwise response will be unauthorized request.
protected void Application_BeginRequest(object sender, EventArgs e)
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
// HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "http://AllowedDomain.com");
}
An article here: Cross-Origin requests and ASP.NET MVC

ajax calls are confined to parent domain only. for this a site on localhost:666 can not open ajax connection to localhost:555 since they belongs to different domain (or origin)
you need to try jsonp: http://www.google.com/search?q=jsonp

Try using dataType: 'jsonp', or $.getJSON function.

Related

jQuery axax lifecycle and response in ASP.NET MVC application or API in general

I need a clarification on jQuery Ajax lifecycle when calling an endpoint, in my specific case an ASP.NET MVC (Net core/Net 5) application.
What I specifically need is to know how the success/error event chain works and when exactly the control is returned to jquery once the http call is fired.
Let's imagine a jquery ajax like this
postData = JSON.stringify({test: 1, anotherVariable : "YEEEE"});
$.ajax({
url: '#Url.Action("MyAspNetAction", "MyAspNetController")',
type: "POST",
contentType: 'application/json; charset=utf-8',
dataType: "json",
data: postData,
success: function (result) {
showMessage(result.responseText, result.success ? 'success' : 'error', 3000)
},
error: function (error) {
showMessage(result.responseText, 'success', 3000)
}
});
On the server I have an async Task controller which we could define as:
public async Task<JsonResult> MyAspNetAction([FromBody] MyAspNetActionModel){
try{
await someLongAction();
return some jsonresult { success = true, responseText = "HELLO"}
}
catch(Exception ex)
{
return some jsonresult { success = false, responseText = "ERROR"}
}
}
which gets executed async from asp net (I guess).
Now, Let's suppose I do various risky task in this action, like manipulating
HttpContext.Session["key"]
ViewData["Key"]
calls to other async stuff which takes some time to get executed (let's say 30 seconds for the sake of putting up a worst-case scenario.
All this togheter.
Now,
WHEN javascript gets control back and WHEN SUCCESS???
Am I handling this right?
I mean, all that async stuff is happening (ajax async, mvc action is async and so on.
Will the jquery action go to succes only after my MVC action is completed and gets the result?
Or the mere fact that jquery ajax managed to call my action will result in a HTTP 200 (so it's ok/success) and it will ignore all the code called inside, which has to be handled in another way, and the following javascript will be executed?
Basically I want to know if I can execute all the code in the MVC action being sure that ajax will enter in succes/error only when the action completed all the code
AND
if the javascript following the jquery ajax will continue executing and the control to the ajax action will return later
The client and the server on an HTTP request work independently.
The client issues a request.
The server handles the request and sends the response.
The client receives the response.
Each end can be running on any architecture and, if possible, the client can block during 2 or asynchronously await for 3 during 2.
The server (2) can be synchronous or asynchronous, but it sequentially does:
Receive the request.
Handle the request.
Send the response.
Regarding ASP.NET, you should not be concurrently messing with HTTP-related components or view components.
Your action method should:
Collect data from HTTP (model binding and other data).
Call any model/services needed to handle the request.
Produce the response (View, or any other response type).

Preventing CSRF in Angular 2 / ASP.NET MVC application

I am working on a sample SPA using ASP.NET MVC for back end and Angular 2 for front end.
I followed below steps to prevent cross site request forgery attacks in my application
Since ASP.NET MVC sends a cookie with name "__RequestVerificationToken", and expects a header with name "__RequestVerificationToken" in the HTTP request to prevent CSRF , I have added below code in my angular module
{provide: XSRFStrategy, useFactory: xsrfFactory}
where xsrfFactory is below function
export function xsrfFactory() {
return new CookieXSRFStrategy('__RequestVerificationToken', '__RequestVerificationToken');
}
And below is the controller action code with "[ValidateAntiForgeryToken]" attribute , to which an AJAX call will be made using Http service of Angular 2.
[CustomAuth]
[ValidateAntiForgeryToken]
public ActionResult GetAuthors()
{
List<BookStoreAdmin.ViewModels.Author> authors = BookStoreAdmin.BAL.Author.GetAuthors();
BookStoreAdmin.ViewModels.Response<List<BookStoreAdmin.ViewModels.Author>> response = new Response<List<ViewModels.Author>>();
response.success = true;
response.errorMessage = null;
response.data = authors;
return Json(response, JsonRequestBehavior.AllowGet);
}
Below is the code which makes the AJAX call .
loadAuthors(): Observable<AuthorModel[]> {
return this.http.get('http://localhost:57599/author/GetAuthors')
.map((data) => data.json());
}
When my application makes an AJAX call using Http angular service , I was expecting it to have request header with name "__RequestVerificationToken" , but this
header is missing , any idea what could be the reason ?
Please let me know if more information needs to be provided ?
I can't see if you are passing a header in angular2 http call.
You can use RequestOptions API which allows you to add header. After adding header when you make request, ValidateAntiForgeryToken should be able to receive sent header.
Read more of RequestOptions here :
https://angular.io/docs/ts/latest/api/http/index/RequestOptions-class.html
Late answer but might be useful for someone.
I think the header is not set because this is a GET request. Though this is Angular 2, the angular 4 security docs might be relevant here as they state that
By default, an interceptor sends this cookie on all mutating requests (POST, etc.) to relative URLs but not on GET/HEAD requests or on requests with an absolute URL.
In order to explicitly include this header as #micronyks states in his answer you can use the RequestOptions API. Here's a code sample
var headers = new Headers();
headers.append('__RequestVerificationToken', <token>);
return this.http.get(url, {headers: headers});

return Json will redirects to another view when Url specified

When you do return Json(...) you are specifically telling MVC not to use a view, and to serve serialized JSON data. Your browser opens a download dialog because it doesn't know what to do with this data.
i got the above information from below link
How to return Json object from MVC controller to view
when i give this below code in some action result
return Json(new { Url = "sep/employee"}
whether it will redirect to specified action ? how it redirects to the URl ?
for this case why i cant use return RedirectToAction("sep/employee").
how return Json code redirects to action which specified in the Url.
ex:
public ActionResult Index()
{
................................
return Json(new { Url = "sep/employee"}
}
public ActionResult employee()
{
....................
}
what is the difference b/s redirectaction and return Json
You return the following line to an ajax success call
return Json(new { Url = "sep/employee"});
you then need to specify where to redirect to the new page
success: function(result) {
window.location.href=result.Url;
}
RedirectToAction simply returns 302 code to your browser with URL telling where the browser should redirect to. The browser immediately makes yet another call to the server to that URL obtained from redirection response.
RedirectToAction internals are:
Construct redirection url from parameters passed to RedirectToAction
Return new RedirectToRouteResult
In ExecuteResult of RedirectToRouteResult you can find the following line:
context.HttpContext.Response.Redirect(destinationUrl, endResponse: false);
which is merely returning 302 with redirection URL. More info - look at source code here.
Returning JSON data simply returns JSON serialized object to your browser. Is not meant to do any redirect. To consume such a result you will likely call the server using $.ajax:
$.ajax({
url: 'sep/employee',
type: 'POST'
success: function(result) {
// handle the result from the server, i.e. process returned JSON data
}
});
ExecuteResult of JsonResult just serializes passed CLR object to the response stream, which lands in your browser after response is fully received. Then you can handle such response in JavaScript code.
EDIT:
You of course can mimic 302 redirection by returning Json like
return Json(new { Url = "redirectionUrl"}
and at client side handle it like
$.ajax({
url: 'sep/employee',
type: 'POST'
success: function(result) {
// mimic the 302 redirection
windows.location.href = result.Url
}
});
although IMHO it should be avoided since you reinvent MVC infrastructure and enlarge your code base.
whether it will redirect to specified action ? how it redirects to the URl ?
I assume you mean to ask, "will it redirect to specified action? how will it redirect the the URI?"
To answer your question: How it redirects to the URL?
In your example it will redirect to the URL, if you made the HTTP request as AJAX and that you will explicitly handle the resulting HTTP response to actually redirect to the URL that you received. So your view should have something like this:
$.ajax({
url: '{your controller}/index',
type: 'GET'
success: function(url) {
// write code to redirect to the URL
// example:
// window.navigate(url)
}
});
If your view does not have anything that, then it will not redirect. You did not post your view, so I am assuming it just a normal page load.
Your next question, what is the difference b/s redirection and return Json?
If you really just want to redirect then do RedirectToAction from your controller, that is exactly what it is for. You can do the same effect using AJAX and JSON to be able to redirect, but AJAX and JSON serves a much wider purpose than just redirecting and in most cases (unless you have very good reasons) you probably will not want replace RedirectToAction with that approach.

ASP Web API POST request with CORS and IE9 (XDomainRequest object)

I've been going crazy here trying to get jquery.ajax to work with ie9. So I have a ASP Web API 2 Rest API that implements CORS. CORS requests from all browsers work. IE9 didnt work since it uses the XDomainRequest. I managed to get it too work by making a custom implementation of ajaxTransport for IE9.
Right now GET requests seem to work fine. But when I do a post request from IE9 I get a HTTP error 415 - unsuportted media type.
I've set the content-type to:"application/json" and I've also tried "application/x-www-form-urlencoded", but from what I understood XDomainRequest doesnt support everything with custom headers? Does anybody know if something specific needs to be setup on the WebAPI or do I need to tweak the request?
My request looks like this:
$.ajax({
url: hostname + "/api/DDC/Book",
type: "POST",
contentType: "application/json",
data: {
DealID: function () {
return viewModel.get("DealID");
},
LocationID: function () {
return viewModel.get("LocationID");
},
Time: function () {
return viewModel.get("selectedDateTime.Time");
}
}
})
On the server I have this:
[HttpPost("DDC/Book")]
[EnableCors(origins: "*", headers: "*", methods: "POST, GET, OPTIONS, PUT, DELETE")]
public dynamic Post(BookModel model)
{
.........
When I analyze the failed request in the IE debugger this are the request headers that get sent out:
Key Value
Request POST //api/DDC/Book HTTP/1.1
Accept */*
Origin http://myurl.com
Accept-Language hr-HR
Accept-Encoding gzip, deflate
User-Agent Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
Host www.somehost.com
Content-Length 55
DNT 1
Connection Keep-Alive
Cache-Control no-cache
I'm really losing all hope here and IE is making my go crazy (damn you Microsoft :D ), so any help or advice is much appriciated.
EDIT: From more reasearch I found out that WebAPI requires a content-type to work and XDomainRequest doesnt send out one. So the only solution I see is too tweak my webapi to have a default content-type when nothing is set. Don't know how to this yet though
EDIT2: Hacked my way through temporarily by transforming all my POSTs, to GETs, dont know how smart is this, but I see no bigger problem with it now, so it will do until I fix the problem
Managed to solve it myself. As pointed by Ray Nicholus when there is no Content-Type ASP Web API defaults to an "application/octet-stream" Content-Type. I need a default of "application/x-www-form-urlencoded".
I managed to achive this by writing my own simple message handler that checks an incoming requests "Content-Type" and if nothing is present it adds an "application/x-www-form-urlencoded" one.
This is the code:
public class DefaultContentTypeMessageHandler : DelegatingHandler
{
protected async override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
if (request.Content.Headers.ContentType == null)
request.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/x-www-form-urlencoded");
var response = await base.SendAsync(request, cancellationToken);
return response;
}
}
UPDATE:
As written by Robert Christ in the comment below I am extending the answer a bit for those who have not worked with message handlers before:
For those who don't understand at first glance, DelegatingHandlers
allow you to modify requests / response objects before they really hit
the WebAPI framework internals. Nothing else in the framework really
lets you modify the incoming request before model binding, without
actually writing custom model binders (eugh). so instead, here, you
can sniff out a null content type (which is guaranteed by shortcomings
in the XDomainRequest spec), update it to xml or json, and you will be
able to parse the incoming request correctly.
After you have written a message handler you need to register it with WebAPI. You do that in the WebApiConfig class:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MessageHandlers.Add(new DefaultContentTypeMessageHandler());
// Rest of your code
}
}
Just to confirm what you have already edited into your question over several updates: yes, XDomainRequest does not include a Content-Type header in the request. As you may know by now, you can't set any headers via this transport.
The lack of a Content-Type is particularly problematic for most server-side frameworks, as this means they will be unable to parse the content of the response automatically. In the absence of a Content-Type header, RFC 2616 says the body is assumed to be application/octet-stream, which is likely not what you want in this case. So, you'll need to "manually" parse the request body server-side by hard-coding the expected Content-Type for the associated request in this case.
I would strongly recommend you not simply convert all of your POSTs to GETs. GET requests should be "safe", per RFC 2616. By simply renaming all of your POSTs to GETs, you are no longer following the defined and accepted semantics of GET requests. In other words, don't do this.
Dennis' answer above uses async which is only available in .NET 4.5. For .NET 4 and possibly lower, use the following delegating handler instead:
public class DefaultContentTypeMessageHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (request.Method == HttpMethod.Post && request.Content.Headers.ContentType == null)
{
request.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/x-www-form-urlencoded");
}
return base.SendAsync(request, cancellationToken);
}
}
Also, don't forget your USING statements, you will need:
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

MVC - Identify Page Form Authentication time out

we are developing MVC3 application such that most of our action methods are called via ajax calls and return partialviews. we come across a situation where we need to identify if the action method is called from Form Authentication time out.
public ActionResult LogOn()
{
// I want to return View("LogOn"); if the call is coming from
// Form Authentication time out
return PartialView(Model);
}
here is my web.config looks like:
<authentication mode="Forms">
<forms loginUrl="~/Home/LogOn" timeout="20" />
</authentication>
Appreciate your input.
Your action will never be hit if the authentication cookie has timed out. The forms authentication module directly redirects to the logon page. One possibility for you to detect this happening from client scripting is to set a custom HTTP header in the controller action serving this logon page:
public ActionResult LogOn()
{
var model = ...
Response.AppendHeader("X-LOGON", "true");
return View(model);
}
and then when performing your AJAX request you could use the getResponseHeader method on the XHR object in order to verify if the X-LOGON header was set meaning that the server redirected to the logon page. In this case in your success AJAX handler instead of simply injecting the server response into the DOM or relying on the returned JSON you could show some alert message informing the user that his authentication session has timed out and he needs to login again. Another possibility is to automatically redirect him to the logon page using the window.location.href method:
$.ajax({
url: '/home/some_protected_action',
success: function (data, textStatus, XMLHttpRequest) {
if (XMLHttpRequest.getResponseHeader('X-LOGON') === 'true') {
// the LogOn page was displayed as a result of this request
// probably timeout => act accordingly
}
}
});
There is no way from the server to distinguish between the user loading the page normally versus performing a page refresh.
There are ways to tell the difference between a regular request and an AJAX request, but it doesn't sound like that's what you're asking for.
There is no easy way but if you apply Post-Redirect-Get, I am not sure you will have that problem.

Resources