FormData doesn't get passed back to MVC Controller - javascript

I am trying to upload images and couple of form elements to a MVC Controller. The problem here isn't the model not being populated, because it works with application/x-www-form-urlencoded but seems to have trouble with multipart/form-data. The core of the problem is, that Request.Form is not being populated...
Converting Form to FormData:
function frmValuesAsFormData(submittedForm) {
return new FormData(submittedForm);
}
AJAX Function (asFormData is passed in as True in this case and method is POST and dataType is JSON):
function executeAJAX(method, url, data, asFormData, silent, callbackFunc, receiveFunc, dataType, targetDiv, appendToExistingContent, uid) {
var cType = "application/x-www-form-urlencoded";
var processData = true;
if (asFormData) {
cType = "multipart/form-data";
processData = false;
}
$.ajax({
method: method,
url: url,
data: data,
contentType: cType,
cache: false,
dataType: dataType,
processData: processData,
success: function (d, t, j) {
// Do something with result from controller...
}
});
}
POST Headers (From FireBug)
Accept application/json, text/javascript, /; q=0.01
Accept-Encoding gzip, deflate Accept-Language en-GB,en;q=0.5
Content-Length 936 Content-Type multipart/form-data Cookie
ASP.NET_SessionId=mzppxvimv03qb0smtyrgdw3z Host localhost:64727
Referer http://localhost:64727/Home/Contact User-Agent Mozilla/5.0
(Windows NT 10.0; Win64; x64; rv:50.0) Gecko/20100101 Firefox/50.0
X-Requested-With XMLHttpRequest
POST Example (From FireBug):
-----------------------------26439188689323 Content-Disposition: form-data; name="imageFiles"; filename="WWKDK33.jpg" Content-Type:
image/jpeg
PNG ��� IHDR��"��"����xÕj��7IDATxÚíÚKÂ
ÐÞÿÒz�B3~Þ,Õb|nHàøÈ!B"D"D!B$!B"D"D!B$
!B"Dcdtå]µ
B"D!BÔKtb_xv-!B"Dunð+¯uÔ"D!BÑS*ï"B"D!B(Õl
B"D!B
ô¢ïü·½ä~"D!B¢URi,ÖÕ"D!BQ/Q:ò[*E"D!B¨a¼ÙôWÿéf"D!B¢]
HæL~eD!B"DöÍ_ÉòGGkA"D!BèD±}Çõò4
!B"DZôÀ½rª�"D!B¢eD¡¡y¡éøk!B
"D!ZGÔ;¯49ÛD!B"D"cöÊ#fåQ^D!B"D®I4_à|Ci#J!B"DÝ(s°
"D!B¢{7 £ÌÁ"D!B"D½DgBæant¿"D!BÑÖý¤ôm
"D!B"D"D!B$!B"A"D!D!B"A"D!ß|ÜYÆ
®«����IEND®B`
-----------------------------26439188689323 Content-Disposition: form-data; name="uploaderMode"
tournament
-----------------------------26439188689323--
Anyone any clues as to why it doesn't work? Thanks!

The issue is because when you send a FormData object in the request you have to set contentType to false so that no content-type header is sent. Try this:
if (asFormData) {
cType = false;
processData = false;
}
Also note that you could remove the need to send the asFormData property to your function entirely by just checking the type of the data property:
if (data.constructor == FormData) {
cType = false;
processData = false;
}

Related

How to send file along with form data via AJAX to MVC?

I'm trying to send form data along with (optional) file from Javascript to ASP.NET MVC WebAPI controller. Data for sending is prepared in the following way:
var save = function () {
if (!validate())
return;
var details = new RecipeDetails();
details.id = recipeDetails.id;
details.name = name();
details.description = description() !== "" ? description() : null;
details.preparationTime = preparationTime();
details.totalTime = totalTime();
details.portions = portions() !== "" ? portions() : null;
var formData = new FormData();
formData.append("id", details.id);
formData.append("name", details.name);
formData.append("description", details.description);
formData.append("preparationTime", details.preparationTime);
formData.append("totalTime", details.totalTime);
formData.append("portions", details.portions);
recipeService.updateRecipeDetails(formData, saveSucceeded, saveFailed);
spinnerVisible(true);
};
I don't send picture yet. Service sends data in the following way:
var postFormData = function (url, formData, success, failure) {
$.ajax({
type: "POST",
url: url,
contentType: false,
data: formData,
cache: false,
processData: false,
success: success,
error: failure
});
};
It looks like Javascript sends data correctly, request payload looks like following:
------WebKitFormBoundaryo4APLG1O4LUg7fSf
Content-Disposition: form-data; name="id"
1
------WebKitFormBoundaryo4APLG1O4LUg7fSf
Content-Disposition: form-data; name="name"
Naleśniki1
------WebKitFormBoundaryo4APLG1O4LUg7fSf
Content-Disposition: form-data; name="description"
Opis
------WebKitFormBoundaryo4APLG1O4LUg7fSf
Content-Disposition: form-data; name="preparationTime"
00:15:00
------WebKitFormBoundaryo4APLG1O4LUg7fSf
Content-Disposition: form-data; name="totalTime"
00:20:00
------WebKitFormBoundaryo4APLG1O4LUg7fSf
Content-Disposition: form-data; name="portions"
4
------WebKitFormBoundaryo4APLG1O4LUg7fSf--
The controller's action looks like following:
[HttpPost]
[Authorize]
public HttpResponseMessage UpdateRecipeDetails(RecipeDetailsDto details)
{
int userId = User.Identity.GetId();
recipeService.UpdateRecipeDetails(userId, details);
return Request.CreateResponse(details);
}
Now the problem is, that Javascript receives 500 error and control never enters the UpdateRecipeDetails method.
Now to clarify:
I was first sending the form simply through POST body and everything worked, so it doesn't seem to be a problem with deserializing JSON;
I looked into IIS Express logs for clues, but there are none;
Nothing is inside Output/Debug pane in VS
Why cannot I send form data through FormData?
Response headers:
Request URL:http://localhost:6868/api/RecipeBackend/UpdateRecipeDetails
Request Method:POST
Status Code:500 Internal Server Error
Remote Address:[::1]:6868
Referrer Policy:no-referrer-when-downgrade
Cache-Control:no-cache
Content-Length:0
Date:Mon, 30 Oct 2017 10:47:36 GMT
Expires:-1
Pragma:no-cache
Server:Microsoft-IIS/10.0
X-AspNet-Version:4.0.30319
X-Powered-By:ASP.NET
X-SourceFiles:=(...)=

angular state change after ng-file-upload success without any error or any reason

I am trying to upload a file to the server , I do that successfully but after success, angular or browser or I don't know how just redirect me back to my initial state in angular js
the success callback hit and I have no error
ng-fileupload version 3.2.5.
here is my function in the controller :
$scope.uploadIssueAttachment = function (files, issue) {
if (files && files.length) {
for (var i = 0; i < files.length; i++) {
var file = files[i];
$upload.upload({
url: '/Handlers/UploadHandler.ashx?des=HelpDesk'
, method: 'POST'
, file: file
, }).progress(function (evt) {}).then(function (data) {
var _fileName = data.headers('fileName');
var _originalFileName = data.headers('orgName');
var _type = data.headers('format');
$scope.newIssueAttachments.push({
fileName: _originalFileName
, temporaryName: _fileName
, fileType: _type
});
}).catch(function (error) {
console.log(error);
});
}
}
};
and here is my html markup
<span ng-file-select ng-file-change="uploadIssueAttachment($files,newIssue)" class="file-input btn btn-sm btn-file" >
the function hit and I upload a file, browser response with 200 status
Request URL:http://localhost:3080/Handlers/UploadHandler.ashx?des=HelpDesk
Request Method:POST
Status Code:200 OK
Remote Address:[::1]:3080
Referrer Policy:no-referrer-when-downgrade
Response Headers
view source
Cache-Control:private
Content-Length:0
Date:Mon, 17 Jul 2017 10:33:56 GMT
fileName:ea8c8799-0f48-49f4-a33c-dca0726af929.png
format:image/png
name:ea8c8799-0f48-49f4-a33c-dca0726af929.png
orgname:avator.png
Server:Microsoft-IIS/10.0
X-AspNet-Version:4.0.30319
X-Powered-By:ASP.NET
X-SourceFiles:=?UTF-8?B?RDpcU291cmNlXFdvcmtzcGFjZXNcUE1PLkFDQVxEZXZcQk1TXFJheWthbS5Ccm9rZXJzLldlYi5NVkNcSGFuZGxlcnNcVXBsb2FkSGFuZGxlci5hc2h4?=
Request Headers
view source
Accept:application/json, text/plain, */*
Accept-Encoding:gzip, deflate, br
Accept-Language:en-US,en;q=0.8
Connection:keep-alive
Content-Length:16544
Content-Type:multipart/form-data; boundary=----WebKitFormBoundarylgAXmkMLtLGhRRU4
Cookie:ASP.NET_SessionId=ska22gomunzfvxqv1wwihbmh; .ASPXAUTH=A8E3E65AECDBB20189E01D261B3580E6997A7763615AD085A0E92F5F44B2D7DFA2C0E39BA47876EAE614EF06C56E692B71982D9035F84075C466E63632653E3E7CC03F042B850200EFBC2867E8A0F7EA3F8A7989AAB68E267891CB819AB9024D04DB430D6B8D8E692D64652CA2645681
Host:localhost:3080
Origin:http://localhost:3080
Referer:http://localhost:3080/admin/
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36
Query String Parameters
view source
view URL encoded
des:HelpDesk
Request Payload
------WebKitFormBoundarylgAXmkMLtLGhRRU4
Content-Disposition: form-data; name="file"; filename="avator.png"
Content-Type: image/png
------WebKitFormBoundarylgAXmkMLtLGhRRU4--
and then with no error I just get redirected to my start page, I don't know how to track the event that changed state.
the interesting thing are when I heat breakpoint in dev console and I wait just for few minute, then there is no state change and everything goes well.
near to pull my hair.
any suggestion?
You havent wrote which version you are using but I think this structure will help you .Its always good to use then...catch in angular success is now deprecated.
You can see it here
upload Structure(with then...catch)
$upload.upload({
url: '<YOUR URL>'
file: <file>
}).progress(function (evt) {
// progress = parseFloat(evt.loaded / evt.total)*100;
}).then(function(result) {
//handle successful result
}).catch(function(errorCallback){
//you can see error here
});
Let me know if it wont work.
Edited
$rootScope.$on('$stateChangeStart',
function(event, toState, toParams, fromState, fromParams) {
console.log(toState); //put break point over here try to debug
console.log(fromState);
});

Angularjs Rest endpoint with username password

I am trying to write a Single Page App (SPA) based on AngularJS. The app should connect to a webserver that provides a RestFul services, but each end point requires username and password along with other parameters. Since I am a beginner in this area, before moving towards the actual development, I tried PostMan/Advanced Rest Client chrome extensions to verify the basic connections. A sample request preview :
POST /servicesNS/admin/search/search/jobs/export HTTP/1.1
Host: localhost:8089
Cache-Control: no-cache
Content-Type: application/x-www-form-urlencoded
search=search+error+|+table+host&output_data=xml&username=admin&password=unity3d
This is actually equivalent to the cURL command:
curl -k -u admin:unity3d --data-urlencode search="search error | table host" -d "output_mode=xml" https://localhost:8089/servicesNS/admin/search/search/jobs/result
After getting successful results in above mentioned ways, I am now looking for equivalent way of doing it in AngularJS.
var app = angular.module('TabsApp', []);
app.controller('TabsCtrl', function ($scope, $http)
{
login = function () {
$scope.userName ="admin";
$scope.password ="unity3d"
$http({
method :"POST",
url:"https://localhost:8089/servicesNS/admin/search/search/jobs/export",
data: { "username" : "admin" , "password": "unity3d", "search" : "search error"},
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
}).success(function (data, status, headers, config) {
console.log('status',status);
console.log('data',status);
console.log('headers',status);
});
}
});
This gives me error 401 Unauthorized, the headers of the response:
> Remote Address:127.0.0.1:8089 Request
> URL:https://localhost:8089/servicesNS/admin/search/search/jobs/export
> Request Method:POST Status Code:401 Unauthorized Request Headersview
> source Accept:application/json, text/plain, */* Accept-Encoding:gzip,
> deflate Accept-Language:en-US,en;q=0.8 Connection:keep-alive
> Content-Length:65 Content-Type:application/x-www-form-urlencoded
> Host:localhost:8089 Origin:http://localhost:63342
> Referer:http://localhost:63342/UI/UI1.html User-Agent:Mozilla/5.0
> (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)
> Chrome/39.0.2171.71 Safari/537.36 Form Dataview sourceview URL encoded
> {"username":"admin","password":"unity3d","search":"search error"}:
> Response Headersview source Access-Control-Allow-Credentials:true
> Access-Control-Allow-Headers:Authorization
> Access-Control-Allow-Methods:GET,POST,PUT,DELETE,HEAD,OPTIONS
> Access-Control-Allow-Origin:* Cache-Control:private
> Connection:Keep-Alive Content-Length:130 Content-Type:text/xml;
> charset=UTF-8 Date:Sat, 29 Nov 2014 19:53:59 GMT Server:Splunkd
> Vary:Cookie, Authorization WWW-Authenticate:Basic realm="/splunk"
> X-Content-Type-Options:nosniff X-Frame-Options:SAMEORIGIN
And the output is :
<?xml version="1.0" encoding="UTF-8"?> <response> <messages>
<msg type="ERROR">Unauthorized</msg> </messages> </response>
Any idea what is going wrong?
If you are sending response in the format of 'application/x-www-form-urlencoded' the actual data format should be the same.
What you are sending currently is a JSON object. You would need to use $http tranformer to tranform the request: Something in line of
transformRequest: function (data) {
var postData = [];
for (var prop in data)
postData.push(encodeURIComponent(prop) + "=" + encodeURIComponent(data[prop]));
return postData.join("&");
},
See a working fiddle here http://jsfiddle.net/cmyworld/doLhmgL6/

Catch a Server Redirect's URL

I have a URL
ex. www.siteA.com/?UGLY_KEY_12312432342SSDFSD
It then redirects you to:
www.siteB.com/?ANOTHER_UGLY_KEY_ASDASDFS2342342
What i need is some way to catch the redirect URL of siteB
I've tried JQuery $.ajax
and I am swamped with
No 'Access-Control-Allow-Origin' header is present on the requested resource.
I am aware that CORS is the typical way to go, but it is impossible in my case.
Shouldn't this be easier security wise as it is a mere, GET?
$.ajax({
type: "GET",
url: "www.siteA.com/?UGLY_KEY_12312432342SSDFSD",
dataType: "json",
success: function (response, status, request) {
// data.redirect contains the string URL to redirect to
alert(response.redirectUrl);
}
}
I need to use a HttpWebRequest on the server side because of CORS Permission issues.
Here it is:
var httpWebRequest = (HttpWebRequest)WebRequest.Create("http://www...");
httpWebRequest.ContentType = "text/json";
httpWebRequest.Method = "GET";
httpWebRequest.AllowAutoRedirect = false;
httpWebRequest.Timeout = 10000;
httpWebRequest.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8";
httpWebRequest.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36";
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
string THEREDIRECTURL = httpResponse.GetResponseHeader("Location");

Import page in Mediawiki

I create a script ( js ) to import a page in my mediawiki.
I have a "incorrect token". What's wrong ?
var xhttp = new ActiveXObject("Microsoft.XmlHttp");
xmlHttp2.open("POST", url, false);
xmlHttp2.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlHttp2.send("action=query&prop=info&intoken=import&titles=Test2");
var result2 = xmlHttp2.responseText;
var resultTokenImport = extractTokenImport(result2);
//return me 'dsa7u6ds6u7asd76das67sad+\' ( more or less :D )
xmlHttp2.open("POST", url, false);
xmlHttp2.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlHttp2.send("action=import&format=xml&xml="+dump+"&token="+resultTokenImport);
Well, the problem is that 'import' need 'another' type of Token.
now, my problem is:
xmlHttp2.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
give me an error "nofile"
and for this code :
xmlHttp2.setRequestHeader("Content-Type", "multipart/form-data");
it send me a:
Missing boundary in multipart/form-data POST data in Unknown on line 0
If it says "no file" it is expecting a file in a POST body. You can easily POST using FormData.
To quote from /api.php
xml - Uploaded XML file
Must be posted as a file upload using multipart/form-data
Example
Here is what is working for me. For simplicity, the following code is reading from a textarea and makes use of MediaWiki's JavaScript includes:
var apiUrl = mw.util.wikiScript( 'api' );
var onreadystatechange = function() {
if ( 4 !== this.readyState ) return;
if ( 200 === this.status ) {
console.log( this.response );
}
};
function continueWithToken ( token ) {
var fd = new FormData();
var xhr = new XMLHttpRequest();
// First argument is an array!
var bXml = new Blob( [$( 'textarea' ).val()], {
type: 'text/xml'
} );
fd.append( 'format', 'json' );
fd.append( 'action', 'import' );
// Third parameter is not required but
// You're likely on the safe side using it
fd.append( 'xml', bXml, 'file.xml' );
fd.append( 'token', token );
xhr.onreadystatechange = onreadystatechange;
xhr.open( 'POST', apiUrl );
xhr.send( fd );
}
$.get( apiUrl, {
format: 'json',
type: 'import',
action: 'tokens'
} ).done( function(r) {
var token = r.tokens.importtoken;
continueWithToken( token );
} );
This is just a minimal implementation. Do not forget error-handling. If you have the exports as files for upload and want to make it working in older browsers not sufficiently supporting Blobs and FormData, just build a form! The form's target could be an iframe so you can read the response from it without exposing the blank API result page to your users.
Expected response
{"import":[{"ns":0,"title":"Main Page2","revisions":1}]}
Complete request
The request that is composed by the client and sent to the server for reference. Note the file's in a POST body.
POST http://localhost/api.php HTTP/1.1
Host: localhost
User-Agent: <ua string>
Accept-Language: de,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://localhost/index.php?title=Special:Export&action=submit
Content-Length: 3231
Content-Type: multipart/form-data; boundary=---------------------768648126486
Cookie: <redacted>; mwdbUserID=1; mwdbUserName=Rillke
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
-----------------------768648126486
Content-Disposition: form-data; name="format"
json
-----------------------768648126486
Content-Disposition: form-data; name="action"
import
-----------------------768648126486
Content-Disposition: form-data; name="xml"; filename="file.xml"
Content-Type: text/xml
<mediawiki ...schemas... version="0.8" xml:lang="en">
<siteinfo>
<sitename>Sample Wiki</sitename>
<!-- .... -->
</mediawiki>
-----------------------768648126486
Content-Disposition: form-data; name="token"
XX39e9fd22a9de7675c71eadcfd2XXXX+\
-----------------------768648126486--
As for the "Missing boundary in multipart/form-data POST data" error, this is because you send it url-encoded but claim it would be multipart/form-data. MediaWiki is looking for a boundary in the header but cannot find it.

Categories