How to Call Controller Method in File Upload Using Angularjs Webapi - c#

i am trying to upload multiple file using Angularjs and webapi..
This is my html table:
<body ng-app="fupApp">
<div ng-controller="fupController">
<input type="file" id="file" name="file" multiple
onchange="angular.element(this).scope().getFileDetails(this)" />
<input type="button" ng-click="uploadFiles()" value="Upload" />
<!--ADD A PROGRESS BAR ELEMENT.-->
<p><progress id="pro" value="0"></progress></p>
</div>
</body>
Here is my Angularjs Code for multiple file upload(fileupload.js):
var myApp = angular.module('fupApp', []);
myApp.controller('fupController', function ($scope) {
// GET THE FILE INFORMATION.
$scope.getFileDetails = function (e) {
debugger;
$scope.files = [];
$scope.$apply(function () {
debugger;
// STORE THE FILE OBJECT IN AN ARRAY.
for (var i = 0; i < e.files.length; i++) {
$scope.files.push(e.files[i])
}
});
};
// NOW UPLOAD THE FILES.
$scope.uploadFiles = function () {
debugger;
//FILL FormData WITH FILE DETAILS.
var data = new FormData();
for (var i in $scope.files) {
data.append("uploadedFile", $scope.files[i]);
}
// ADD LISTENERS.
var objXhr = new XMLHttpRequest();
objXhr.addEventListener("progress", updateProgress, false);
objXhr.addEventListener("load", transferComplete, false);
// SEND FILE DETAILS TO THE API.
objXhr.open("POST","MailRoute/getDataForUploadFiles");
objXhr.send(data);
}
// UPDATE PROGRESS BAR.
function updateProgress(e) {
debugger;
if (e.lengthComputable) {
document.getElementById('pro').setAttribute('value', e.loaded);
document.getElementById('pro').setAttribute('max', e.total);
}
}
// CONFIRMATION.
function transferComplete(e) {
debugger;
alert("Files uploaded successfully.");
}
});
here is my function in webapi:
public async Task<HttpResponseMessage> getDataForUploadFiles()
{
}
but how to read the file deatils and access the file details from the controller method(getDataForUploadFiles)

Try this
<div ng-controller="Ctrl">
<input type="file" file-upload multiple/>
<ul>
<li ng-repeat="file in files">{{file.name}}</li>
</ul>
</div>
Controller Code
function Ctrl($scope, $http) {
//a simple model to bind to and send to the server
$scope.model = {
name: "",
comments: ""
};
//an array of files selected
$scope.files = [];
//listen for the file selected event
$scope.$on("fileSelected", function (event, args) {
$scope.$apply(function () {
//add the file object to the scope's files collection
$scope.files.push(args.file);
});
});
//the save method
$scope.save = function() {
$http({
method: 'POST',
url: "/MailRoute/getDataForUploadFiles",
//IMPORTANT!!! You might think this should be set to 'multipart/form-data'
headers: { 'Content-Type': false },
transformRequest: function (data) {
var formData = new FormData();
formData.append("model", angular.toJson(data.model));
//now add all of the assigned files
for (var i = 0; i < data.files; i++) {
//add each file to the form data and iteratively name them
formData.append("file" + i, data.files[i]);
}
return formData;
},
//Create an object that contains the model and files which will be transformed
// in the above transformRequest method
data: { model: $scope.model, files: $scope.files }
}).
success(function (data, status, headers, config) {
alert("success!");
}).
error(function (data, status, headers, config) {
alert("failed!");
});
};
};
Handling the data server-side
public async Task<HttpResponseMessage> getDataForUploadFiles()
{
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
var root = HttpContext.Current.Server.MapPath("~/App_Data/Temp/FileUploads");
Directory.CreateDirectory(root);
var provider = new MultipartFormDataStreamProvider(root);
var result = await Request.Content.ReadAsMultipartAsync(provider);
if (result.FormData["model"] == null)
{
throw new HttpResponseException(HttpStatusCode.BadRequest);
}
var model = result.FormData["model"];
//TODO: Do something with the json model which is currently a string
//get the files
foreach (var file in result.FileData)
{
//TODO: Do something with each uploaded file
}
return Request.CreateResponse(HttpStatusCode.OK, "success!");
}

Related

Posting files and model to controller in ASP.NET Core MVC6

I'm migrating a project from ASP.NET RC1 to ASP.NET Core 1.0.
I have a view that allows users to upload one of more files, which I post using Jquery Ajax. I also serialize and post some settings within the same post.
The following all worked in RC1 (and pre-asp.net core):
Js:
$('#submit').click(function () {
var postData = $('#fields :input').serializeArray();
var fileSelect = document.getElementById('file-select');
var files = fileSelect.files;
var data = new FormData();
for (var i = 0; i < files.length; i++) {
data.append('file' + i, files[i]);
}
$.each(postData, function (key, input) {
data.append(input.name, input.value);
});
var url = '/ajax/uploadfile';
$.ajax({
url: url,
type: "POST",
contentType: false,
processData: false,
cache: false,
data: data,
success: function (result) {
alert('success');
},
error: function () {
alert('error');
}
});
});
Controller:
public IActionResult UploadFile(UploadFileModel model)
{
var result = new JsonResultData();
try
{
if (Request.Form.Files.Count > 0)
{
IFormFile file = Request.Form.Files[0];
//etc
}
}
}
So the above does not work anymore, no file uploaded and no model bound.
I managed to fix half the issues so now I can get the model to bind with the following code. However, the controller will still give me an exception on the Request.Files. I added the 'headers' property, and I used serializeObject (custom method). In the controller I added FromBody.
Js:
$('#submit').click(function () {
var postData = $('#fields :input').serializeArray();
var fileSelect = document.getElementById('file-select');
var files = fileSelect.files;
var data = new FormData();
for (var i = 0; i < files.length; i++) {
data.append('file' + i, files[i]);
}
$.each(postData, function (key, input) {
data.append(input.name, input.value);
});
var url = '/ajax/uploadfile';
$.ajax({
url: url,
type: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
processData: false,
cache: false,
data: serializeAndStingifyArray(data),
success: function (result) {
alert('success');
},
error: function () {
alert('error');
}
});
});
function serializeAndStingifyArray(array) {
var o = {};
var a = array;
$.each(a, function () {
if (o[this.name] !== undefined) {
if (!o[this.name].push) {
o[this.name] = [o[this.name]];
}
o[this.name].push(this.value || '');
} else {
o[this.name] = this.value || '';
}
});
return JSON.stringify(o);
};
Controller:
[HttpPost]
public IActionResult UploadFile([FromBody]UploadFileModel model)
{
var result = new JsonResultData();
try
{
if (Request.Form.Files.Count > 0)
{
IFormFile file = Request.Form.Files[0];
//etc
}
}
}
html:
<div id="file-list">
<input type="file" name="file" class="file-select" accept="application/pdf,application">
<input type="file" name="file" class="file-select" accept="application/pdf,application" />
</div>
I started from this article which has some code that is almost the same as yours Upload Files In ASP.NET Core 1.0 (see Ajax case).
That worked for me fine on 1.0.0, so I implemented your changes and what I saw is that it failed to send the files in the request (client side issue).
This is how the payload should look like when working ok using F12 in chrome: (not sure why the file contents are hidden by chrome).
A little debugging and you are passing wrong data to data.append
The fix is in this line
$(".file-select").each(function () { data.append($(this).val(), $(this).get(0).files[0]); i++; })
Full code:
$(document).ready(function () {
$("#submit").click(function (evt) {
var data = new FormData();
i = 0;
$(".file-select").each(function () { data.append($(this).val(), $(this).get(0).files[0]); i++; })
var postData = $('#fields :input');
$.each(postData, function (key, input) {
data.append(input.name, input.value);
});
$.ajax({
type: "POST",
url: "/ajax/uploadfile", // <--- Double check this url.
contentType: false,
processData: false,
data: data,
success: function (message) {
alert(message);
},
error: function () {
alert("There was error uploading files!");
}
});
});
});
No need to use [FromBody] or serializeArray()
[HttpPost]
public IActionResult UploadFilesAjax(MyViewModel xxx )
{
This is my html, just in case:
<form method="post" enctype="multipart/form-data">
<div id="file-list">
<input type="file" name="file" class="file-select" accept="application/pdf,application">
<input type="file" name="file" class="file-select" accept="application/pdf,application" />
</div>
<div id="fields">
<input type="text" name="Email" />
</div>
<input type="button"
id="submit"
value="Upload Selected Files" />
</form>

Unable to upload multiple files

I am using ASP.NET MVC 5,jquery latest version.
I am trying to upload multiple files using jquery fileupload but I am unable to recieve multiple files.
View:
<input id="fileupload" type="file" multiple="multiple" name="files[]" >
<script type="text/javascript">
$(document).ready(function () {
$('#fileupload').fileupload({
dataType: 'json',
url: '/Media/UploadFiles',
autoUpload: true,
done: function (e, data) {
}
}).on('fileuploadprogressall', function (e, data) {
var progress = parseInt(data.loaded / data.total * 100, 10);
$('.progress .progress-bar').css('width', progress + '%');
});
});
</script>
Controller:
[HttpPost]
public ContentResult UploadFiles()
{
foreach (string file in Request.Files)
{ }
}
Here in Request.Files I am recieving only one file.
Your uploaded files are actually sent one by one.
You can change your serve code
[HttpPost]
public JsonResult UploadFiles()
{
IList<string> filesSaved = new List<string>();
foreach (string file in Request.Files)
{
HttpPostedFileBase hpf = Request.Files[file];
if (hpf.ContentLength > 0)
{
var fileName = hpf.FileName;
filesSaved.Add(fileName);
}
}
return Json(new {files = filesSaved}, JsonRequestBehavior.DenyGet);
}
and insert a breakpoint and you will see that the request goes through once for each file you're sending.
The problem is in your client code. There's an option in that plugin singleFileUploads which defaults to true, as you can read here.
You can change your client code setting singleFileUploads: false :
$(document).ready(function () {
$('#fileupload').fileupload({
dataType: 'json',
url: '/Media/UploadFiles',
autoUpload: true,
singleFileUploads: false,
done: function (e, data) {
}
}).on('fileuploadprogressall', function (e, data) {
var progress = parseInt(data.loaded / data.total * 100, 10);
$('.progress .progress-bar').css('width', progress + '%');
});
});
and everything should work as expected.

Refresh page after POST

I have created a solution where I post an array of string to my controller.
The setup works fine but I have to manually refresh the page before I can see the results of my method.
How do I make the solution refresh the page after I posted?
My view (tree.html):
<form>
<textarea class="form-control auto-input-field" rows="10" cols="80" id="autoGenerateInputField" ng-model="fighterList" ng-list="/\n/" />
<input class="btn btn-primary" type="submit" ng-click="GenerateTournamentTree(data)" value="Generer kamptræ" />
</form>
My js (angular):
$scope.GenerateTournamentTree = function(matches){
var stringOfFighters = new Array();
var categoryId = $scope.CategoryId;
stringOfFighters = $scope.fighterList;
var postData = { fighters: stringOfFighters };
if (stringOfFighters != null) {
$.ajax({
type: "POST",
url: "/Api/Match/GenerateTournamentTree",
contentType: 'application/json; charset=utf-8',
data: JSON.stringify(stringOfFighters),
success: function (data) {
alert(data.Result);
},
dataType: "json",
traditional: true
});
} else {
$modal.open({
templateUrl: 'generateTreeMessage.html',
scope: $scope,
controller: function ($scope) {
$scope.ok = function () {
$scope.$dismiss();
}
$scope.cancel = function () {
$scope.$dismiss();
}
}
})
}
}
My controller:
[Route("api/Match/GenerateTournamentTree")]
public IHttpActionResult GenerateTournamentTree(List<String> fighters)
{
fighters.Shuffle();
var nodeTree = InsertNode(new TreeNode(), fighters);
var matches = new List<MatchRecord>();
GenerateMatch(matches, nodeTree);
foreach(var match in matches)
{
match.CategoryId = new Guid("425d750e-56bd-412c-8a48-38c2fbe5b24c");
match.EventId = 18;
}
db.Matches.AddRange(matches);
try
{
db.SaveChanges();
}
catch (DbUpdateException)
{
throw;
}
//return CreatedAtRoute("DefaultApi", new { id = "18" }, fighters);
//I tried this but with no succes.
return Json(new { Result = fighters });
//this is only created to return something.
}

how to send upload control data to jquery ajax wihout plugins

I am trying to upload file/files to server through Ajax request in MVC, but the file is always returning null in the controller, can you please suggest the way to pass the file data in the ajax request?
<form method="post" enctype="multipart/form-data">
<div>
#Html.AntiForgeryToken()
<input type="file" name="file" id="files" multiple><br>
<input type="button" value="Upload File to Server" id="submit">
</div>
</form>
<script type="text/javascript">
$("#submit").click(function () {
var formData = $('#files').val();
alert(formData);
$.ajax({
url: 'home/index',
type: 'POST',
datatype: 'json',
enctype: "multipart/form-data",
data: { file: formData },
//processData: false, // Don't process the files
//contentType: false, // Set content type to false as jQuery will tell the server its a query string request
success: function (data) {
alert(data);
},
error: function () {
alert("failed");
}
});
});
</script>
[HttpPost]
[ActionName("Index")]
public ActionResult Index_Post(HttpPostedFileBase file)
{
string errormsg = string.Empty;
if (file != null)
{
// Verify that the user selected a file
if (file != null && file.ContentLength > 0)
{
// extract only the fielname
var fileName = Path.GetFileName(file.FileName);
// TODO: need to define destination
var path = Path.Combine(Server.MapPath("~/Upload"), fileName);
try
{
file.SaveAs(path);
errormsg = "uploaded";
return Json(fileName + errormsg);
}
catch
{
errormsg = "failed to upload";
return Json(fileName + errormsg);
}
}
}
else
{
errormsg = "No file selected";
return Json(errormsg);
}
return View();
}
}
Take normal button instead of submit button and try below code
$("#submit").click(function () {
var formData = new FormData();
var opmlFile = $('#myFile')[0];
formData.append("opmlFile", opmlFile.files[0]);
$.ajax({
url: 'home/index',
type: 'POST',
datatype: 'json',
enctype: "multipart/form-data",
data: formData ,
//processData: false, // Don't process the files
//contentType: false, // Set content type to false as jQuery will tell the server its a query string request
success: function (data) {
alert(data);
},
error: function () {
alert("failed");
}
});
});
});
and controller action :-
[HttpPost]
[ActionName("Index")]
public HttpResponseMessage Index()
{
HttpResponseMessage result = null;
var httpRequest = HttpContext.Current.Request;
// Check if files are available
if (httpRequest.Files.Count > 0)
{
var files = new List<string>();
// interate the files and save on the server
foreach (string file in httpRequest.Files)
{
var postedFile = httpRequest.Files[file];
var filePath = HttpContext.Current.Server.MapPath("~/" + postedFile.FileName);
postedFile.SaveAs(filePath);
files.Add(filePath);
}
// return result
result = Request.CreateResponse(HttpStatusCode.Created, files);
}
else
{
// return BadRequest (no file(s) available)
result = Request.CreateResponse(HttpStatusCode.BadRequest);
}
return result;
}

File upload using ajax request

I am trying to upload image, using ajax. i am sending request like this:
#using (Ajax.BeginForm("SaveReferral", "ReferralIM", new AjaxOptions
{
HttpMethod = "POST",
OnSuccess = "OnSuccessReferralSent"
}, new { id = "frmReferral", onSubmit = "OnControlMapping(this);" }))
{
}
if i send request like this:
#using (Html.BeginForm("SaveReferral", "ReferralIM", FormMethod.Post, new { id = "frmReferral", enctype = "multipart/form-data" }))
{
File uploaded successfully, but i want to use ajax ,Please help me how i should do for file uploading with ajax.
Thanks
I am not using MVC BUT if you want to use $.ajax then here it is...
$('.file-uploadID').on('click', function (e) {
e.preventDefault();
var fileInput = $('.file-uploadID');
var fileData = fileInput.prop("files")[0]; // Getting the properties of file from file field
formData.append("file", fileData); // Appending parameter named file with properties of file_field to form_data
formData.append("user_email", email); //adding email address as parameter if you have
$.ajax({
url: '/FileUploadHandler.ashx',
data: formData,
processData: formData.processData,
contentType: formData.contentType,
type: 'POST',
success: function (data) {
var obj = $.parseJSON(data);
if (obj.StatusCode == "OK") {
alert("file upload done");
} else if (obj.StatusCode == "ERROR") {
alert("file upload error");
}
},
error: function (errorData) {
$('.result-message').html("There was a problem uploading the file. Please try again.").show();
}
});
});
Handler
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
context.Response.Expires = -1;
var email = context.Request.Params["user_email"];
var fileData = context.Request.Files["file"];
try
{
var result = UploadImageToServer(email, fileData);
context.Response.Write(result);
}
catch (Exception ex)
{
context.Response.Write("error while uploading file to the server, please try again.");
}
}

Categories