So I want to POST
fileUpload along with AntiForgeryToken
via AJAX. Here's my code :
View
@using (Html.BeginForm("Upload", "RX", FormMethod.Post, new {id = "frmRXUpload", enctype = "multipart/form-data"}))
{
@Html.AntiForgeryToken()
@Html.TextBoxFor(m => m.RXFile, new {.type = "file"})
...rest of code here
}
<script>
$(document).ready(function(){
$('#btnRXUpload').click(function () {
var form = $('#frmRXUpload')
if (form.valid()) {
var formData = new FormData(form);
formData.append('files', $('#frmRXUpload input[type="file"]')[0].files[0]);
formData.append('__RequestVerificationToken', fnGetToken());
$.ajax({
type: 'POST',
url: '/RX/Upload',
data: formData,
contentType: false,
processData: false
})
}
})
})
</script>
Controller
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Upload()
{
//rest of code here
}
I get
The anti-forgery token could not be decrypted. If this application is hosted by a Web Farm or cluster
error via fiddler. Any idea how to solve this issue?
I FOUND THE ANSWER :
<script>
$(document).ready(function(){
$('#btnRXUpload').click(function () {
var form = $('#frmRXUpload')
if (form.valid()) {
var formData = new FormData(form.get(0)); //add .get(0)
formData.append('files', $('#frmRXUpload input[type="file"]')[0].files[0]);
$.ajax({
type: 'POST',
url: '/RX/Upload',
data: formData,
contentType: false,
processData: false
})
}
})
})
</script>
FINALLY FOUND THE ANSWER :
I just need to add .get(0)
in the form, here's the code :
<script>
$(document).ready(function(){
$('#btnRXUpload').click(function () {
var form = $('#frmRXUpload')
if (form.valid()) {
var formData = new FormData(form.get(0)); //add .get(0)
formData.append('files', $('#frmRXUpload input[type="file"]')[0].files[0]);
//formData.append('__RequestVerificationToken', fnGetToken()); //remark this line
$.ajax({
type: 'POST',
url: '/RX/Upload',
data: formData,
contentType: false,
processData: false
})
}
})
})
</script>
You need to add the token to the request headers, not the form. Like this:
if (form.valid()) {
var formData = new FormData(form);
formData.append('files', $('#frmRXUpload input[type="file"]')[0].files[0]);
$.ajax({
type: 'POST',
url: '/RX/Upload',
data: formData,
contentType: 'multipart/form-data',
processData: false,
headers: {
'__RequestVerificationToken': fnGetToken()
}
})
}
Edit
Looking back at how I solved this problem myself, I remember that the standard ValidateAntiForgeryTokenAttribute looks in the Request.Form object which doesn't always get populated for an AJAX request. (In your case, the file upload needs a multipart/form-data
content type, whereas a form post for the CSRF token needs application/x-www-form-urlencoded
. You set contentType=false
, but the two operations need conflicting content types, which may be part of your problem). So, in order to validate the token on the server, you will need to write a custom attribute for your action method that checks for the token in the request header:
public sealed class ValidateJsonAntiForgeryTokenAttribute
: FilterAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
var httpContext = filterContext.HttpContext;
var cookie = httpContext.Request.Cookies[AntiForgeryConfig.CookieName];
AntiForgery.Validate(cookie != null ? cookie.Value : null,
httpContext.Request.Headers["__RequestVerificationToken"]);
}
}
More info (a bit out of date now) here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With