Upload a File using AngularJS to .NET Web API - c#

I referred some Stack overflow Questions and I tried the following code. The following code was not hitting the Web API. I tried with normal Text, then its hitting but not for the FILE. Finally I concluded the Web API Path and method all are fine, only issue is File. Kindly assist me how to upload File using AngularJS to .NET Web API.
My HTML Code
<input id="file_input_file" ng-files="getTheFiles($files)" type="file" accept=".csv" />
<input type="button" data-ng-click="ImplortCSVData()" id="btnMainLoginForm" value="Upload File" />
My AngularJS Directive for ng-files is
app.directive('ngFiles', ['$parse', function ($parse) {
function fn_link(scope, element, attrs) {
var onChange = $parse(attrs.ngFiles);
element.on('change', function (event) {
onChange(scope, { $files: event.target.files });
});
};
return {
link: fn_link
}
}]);
My AnagularJS Controller is
app.controller('ProcessCSVController', function ($rootScope, $scope, HTTPService) {
$scope.CSVfile = {};
$scope.getTheFiles = function ($files) {
angular.forEach($files, function (value, key) {
$scope.CSVfile.append(key, value);
});
};
$scope.ImplortCSVData = function () {
HTTPService.uploadCSV($scope.CSVfile).then(function (result) {
alert("CSV");
});
}
});
My HTTPService is
app.factory('HTTPService', function ($http, $q) {
formatCSV: function (_resultObj) {
var result = $http({
url: "localhost:8085/api/TAdmin/UploadCSVData",
method: 'POST',
data: _resultObj,
headers: {
"Content-Type": undefined
},
}).success(function (response) {
return {
errorCode: 0,
errorString: "",
result: response
}
}).error(function (error) {
return {
errorCode: 100,
errorString: "",
result: error
}
});
return result;
}
});
My WebAPI C# Code is
[HttpPost]
public HttpResponseMessage UploadCSVData(object csv)
{
// Check if the request contains multipart/form-data.
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
string root = HttpContext.Current.Server.MapPath("~/App_Data");
var provider = new MultipartFormDataStreamProvider(root);
try
{
BinaryFormatter bf = new BinaryFormatter();
using (var ms = new MemoryStream())
{
bf.Serialize(ms, csv);
var x = ms.ToArray();
}
return Request.CreateResponse(HttpStatusCode.OK);
}
catch (System.Exception e)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
}
}

Related

Ajax call to async method returning file successfully but success/complete part of an Ajax request is not getting executed

I am trying to export selected records in to a file and reload the page to update the records in a current view. I am calling web api asynchronously to get all the records. An AJAX call is executing an action in a controller successfully and returning expected data without any error but none of the 'success', 'complete' or 'error' part of ajax function is executing. There are no errors in a developer tool of the browser, no exception, nothing unusual so its getting trickier for me to investigate this issue further. Can I request your a suggestions on this please? Thanks
View :
#Html.ActionLink("Export records", "Index", null, new { Id = "myExportLinkId")
Script :
$("a#myExportLinkId").click(function (e) {
var selected = "";
$('input#myCheckBoxList').each(function () {
if (this.checked == true) {
selected += $(this).val() + ',';
}
});
if (selected != "") {
$.ajax({
url: '/MyController/MyAction',
type: 'GET',
contentType: "application/json; charset=utf-8",
dataType: "json",
data: {
'MyString': 'stringValue'
},
success: function (data) {
alert("success");
},
error: function () {
alert("error");
}
});
})
And the action/method looks like this :
[HttpGet]
public async Task<ActionResult> ExportNewOrders(string OrderIdString)
{
//code to create and store file
//actually want to send the file details as json/jsonResult but for testing only returning
//string here
return Json( "Success", "application/json", JsonRequestBehavior.AllowGet);
}
Finally I have resolved this with Promisify functionality of an AJAX call. Obviously the json response I was returning had an issue so I have replaced
return Json( "Success", "application/json", JsonRequestBehavior.AllowGet);
to
return new JsonResult(){
Data = new { success = true, guid = handle, fileName = exportFileName },
ContentType = "application/json",
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
which has fixed the bug and the success function of ajax call got executed.
But other than this there were issues to wait until the file download (which involved encryption decryption, server validations etc) completes and then refresh the page. This I have resolved by implementing an ajax call with Promisify fuctionality. You can find codepen example here and the original post here.
Here is the complete code.
View/HTML
#Html.ActionLink("Export", "yourActionName", null, new { Id = "exportRequest", #onclick = "letMeKnowMyFileIsDownloaded();" })
Script/Ajax
function letMeKnowMyFileIsDownloaded() {
return new Promise(function (resolve, reject) {
$("a#exportRequest").on("click", function () {
$.ajax({
url: this.href + "?param=whatever params you want to pass",
dataType: "json",
data: {
'param1': 'value'
},
success: function (data) {
var a = document.createElement("a");
var url = '/yourControllerName/Download?fileGuid=' + data.guid + '&filename=' + data.fileName;//window.URL.createObjectURL(data);
a.href = url;
a.download = data.fileName;
document.body.append(a);
a.click();
a.remove();
window.URL.revokeObjectURL(url);
resolve(true);
},
error: function (error) {
reject(error);
}
});
});
});
}
letMeKnowMyFileIsDownloaded()
.then(function (bool) {
if (bool) {
//alert("File downloaded 👇");
window.location.reload(1);
}
})
.catch(function (error) {
alert("error");
});
I have used nuget package ClosedXML to handle excel file functionality. Using the stream to create and download the data in excel file without storing the file physically on the server.
And in the controller
//can be async or sync action
public async Task<ActionResult> Index(YourModel model)
{
//do stuff you want
var exportOrders = your_object;
//using DataTable as datasource
var dataSource = new DataTable();
//write your own function to convert your_object to your_dataSource_type
dataSource = FormatTypeToDataTable(exportOrders);
if (dataSource != null && dataSource.Rows.Count > 0)
{
//install ClosedXML.Excel from nuget
using (XLWorkbook wb = new XLWorkbook())
{
try
{
var handle = Guid.NewGuid().ToString();
wb.Worksheets.Add(dataSource, "anyNameForSheet");
string exportFileName = "yourFileName" + ".xlsx";
MemoryStream stream = GetStream(wb);
TempData[handle] = stream; exportFileName);
return new JsonResult()
{
Data = new { success = true, guid = handle, fileName = exportFileName },
ContentType = "application/json",
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
catch (Exception ex)
{
//ModelState.AddModelError("", ex.Message);
}
}
}
}
public virtual ActionResult Download(string fileGuid, string fileName)
{
if (TempData[fileGuid] != null)
{
var stream = TempData[fileGuid] as MemoryStream;
var data = stream.ToArray();
return File(data, "application/vnd.ms-excel", fileName);
}
else
{
return new EmptyResult();
}
}

Read Excel Content After Uploading File in MVC And Fill Some Textboxes

I'm uploading an excel file and want to read file content and with jquery ajax fill some textboxes with excel content after uploading.
the file uploading correctly but I have Problem when I want read excel content.
can anybody help me?
public JsonResult ImportExcelToTextBoxes()
{
try
{
var ExcelFile = Request.Files[0];
if (ExcelFile != null && ExcelFile.ContentLength > 0)
{
//// .xlsx
//IExcelDataReader reader = ExcelReaderFactory.CreateOpenXmlReader(ExcelFile.InputStream);
// .xls
IExcelDataReader reader = ExcelReaderFactory.CreateBinaryReader(ExcelFile.InputStream);
var result = reader.AsDataSet(new ExcelDataSetConfiguration() {
ConfigureDataTable = (_) => new ExcelDataTableConfiguration() {
UseHeaderRow = true
}
});
}
//foreach (var item in ExcelFile)
{
IList lst = new List<ET.Reservation.Classes.PassengerSaleSeat>();
ET.Reservation.Classes.PassengerSaleSeat pass = new ET.Reservation.Classes.PassengerSaleSeat();
pass.FirstName = "testtt";//this section is for test
pass.LastName = "tttttt";//this section is for test
pass.Gender = ET.Public.Enumerations.GENDER.Female;//this section is for test
lst.Add(pass);//this section is for test
}
return Json(lst);
}
catch (Exception ex)
{
Console.WriteLine(ex);
throw ex;
}
return null;
}
and js section:
$('#btnUploadExcel').click(function () {
var formData = new FormData();
formData.append('file', fileInput.files[0]);
$.ajax({
type: "POST",
url: "/PassengerSaleSeat/ImportExcelToDatabase",
data: formData,
processData: false,
contentType: false,
success: function (data) {
for (var i = 0; i < data.length; i++) {
alert(data[i].FirstName);
}
},
error: function(err) {
alert('error');
}
});
});
and input is:
<input id="fileInput" type="file">
<button type="button" id="btnUploadExcel" class="btn btn-labeled btn btn-success">Send</button>
JSON Return:
image

How To Wrap Parameters into JSON Object and Pass to the Controller via HttpGet?

Currently I'm creating an Angular web Api Client to pass JSON Object to MVC Web Api Controller. The controller is using HttpGet method.
Here's the code for Angular web api Client:
var AngularModule = angular.module('contentApp', []);
var parameter = JSON.stringify({ contentid: 1, contenttitle: "Lorem Ipsum" });
AngularModule.controller('contentCtrl', function ($scope, $http, ApiCall) {
var result = ApiCall.GetApiCall("http://localhost:8000/api/content/search?" + parameter).success(function (data) {
console.log(data);
$scope.ContentList = data;
});
});
AngularModule.service('ApiCall', ['$http', function ($http) {
var result;
this.GetApiCall = function (EndPoint) {
result = $http.get(EndPoint).success(function (data, status) {
result = (data);
}).error(function () {
alert("Error Occured");
});
return result;
};
}]);
Here's the code for the Controller (Service):
[HttpGet("Search")]
public async Task<IActionResult> Search([System.Web.Http.FromUri] Content list)
{
try
{
return new ObjectResult(new { status = 1, message = await ContentRepo.Search(new Models.Content())});
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
I already tried this, but whenever it hit the controller, the object couldn't be read because of different format type (always null).
My question is : is that even possible to read JSON object from the URL (QueryString)? and if it's possible, how to handle it?
Any help will be appreciated :)
Thanks
Have you tried passing your parameter object to the data parameter of the $http.get?
Please check AngularJS' doc for $http:
https://docs.angularjs.org/api/ng/service/$http#get
Also, you need to use then since $http.get returns a promise.
var AngularModule = angular.module('contentApp', []);
var parameter = { contentid: 1, contenttitle: "Lorem Ipsum" };
AngularModule.controller('contentCtrl', function ($scope, $http, ApiCall) {
var result = ApiCall.getApiCall("http://localhost:8000/api/content/search", { data: parameter }).then(function successCallback(data) {
console.log(data);
$scope.ContentList = data;
}, function errorCallback(errData) {
alert('Error Occurred');
});
});
AngularModule.service('ApiCall', ['$http', function ($http) {
this.getApiCall = function (endPoint, data) {
return $http.get(endPoint, data);
};
}]);

Web API to upload images with c# (code behind)

I need the c# code to upload images to my web api. (c# code that will do the same as my ajax call below)
Here is my working example that I use to upload images from my web project via ajax call.
HTML
<form>
<span>Select file(s) to upload :</span>
<input id="file1" name="file1" type="file" multiple="multiple" />
<input id="button1" type="button" value="Upload" />
</form>
ajax Call
$(document).ready(function () {
$("#button1").click(function (evt) {
var files = $("#file1").get(0).files;
if (files.length > 0) {
var data = new FormData();
for (i = 0; i < files.length; i++) {
data.append("file" + i, files[i]);
}
$.ajax({
type: "POST",
url: window.apiuri + "/api/book/UploadCover()",
contentType: false,
processData: false,
data: data,
success: function (messages) {
for (i = 0; i < messages.length; i++) {
$.smkAlert({ text: messages[i], type: 'success' });
}
},
error: function () {
$.smkAlert({ text: "Error while invoking the Web API", type: 'success' });
}
});
}
});
});
API Code in c#
public async Task<List<string>> UploadCover()
{
try
{
List<string> messages = new List<string>();
if (Request.Content.IsMimeMultipartContent())
{
string path = string.Format(#"C:\");
API.Classes.ImageUploads.MyStreamProvider streamProvider = new API.Classes.ImageUploads.MyStreamProvider(path);
await Request.Content.ReadAsMultipartAsync(streamProvider);
foreach (var file in streamProvider.FileData)
{
FileInfo fi = new FileInfo(file.LocalFileName);
try
{
messages.Add("<b>Book Cover Uploaded</b>");
}
catch (Exception ex)
{
messages.Add("<b>Upload Failed</b>");
}
}
return messages;
}
else
{
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.BadRequest, "Invalid Request!");
throw new HttpResponseException(response);
}
}
catch (Exception ex)
{
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.BadRequest, "Request Failed!");
throw new HttpResponseException(response);
}
}
Please help me with c# code to upload images to my web api. Thank you

Adding image to AngularJS model for upload

I am new to this wonderful framework AngularJS. I have a C# API controller where I would like to upload data from a form that includes an image. Normally (razor) I would upload a form as json and include the image as a HttpPostedFileBase:
public ArtWork SaveArtWork(ArtWork artWork, HttpPostedFileBase file)
{ // save in db and return object }
I have found a lot of different ways for uploading the file wrapped in a FormData object ([AngularJS Uploading An Image With ng-upload):
$scope.uploadFile = function(files) {
var fd = new FormData();
//Take the first selected file
fd.append("file", files[0]);
$http.post(uploadUrl, fd, {
withCredentials: true,
headers: {'Content-Type': undefined },
transformRequest: angular.identity
}).success( ...all right!... ).error( ..damn!... );
};
But I have some other properties I have parsed to a json object, and now I would like to upload it all in a bundle. Or is it possible to get the image data as a base64 and add it to my json object? I know that a base64 is 1/3 bigger than a byte stream, but it's so easy to work with :)
Here's my Angular Controller:
'use strict';
(function () {
// Factory
angular.module('umbraco').factory('artworkResource', function ($http) {
return {
getById: function (id) {
return $http.get("backoffice/Trapholt/ArtWorkApi/GetById/" + id);
},
save: function (artwork) {
return $http.post("backoffice/Trapholt/ArtWorkApi/SaveArtWork", angular.toJson(artwork));
},
save2: function (artwork, fd) {
return $http.post("backoffice/Trapholt/ArtWorkApi/SaveArtWork", angular.toJson(artwork), fd);
}
};
});
// Controller
function artworkController($scope, $routeParams, artworkResource, $http) {
$scope.categories = ['Keramik', 'Maleri', 'Møbel', 'Skulptur'];
artworkResource.getById($routeParams.id).then(function (response) {
$scope.curatorSubject = response.data;
});
var fd;
$scope.uploadFile = function(files) {
fd = new FormData();
fd.append("file", files[0]);
};
$scope.save = function (artwork) {
artworkResource.save(artwork, fd).then(function (response) {
$scope.artwork = response.data;
alert("Success", artwork.Title + " er gemt");
});
};
};
//register the controller
angular.module("umbraco").controller('ArtworkTree.EditController', artworkController);
})();
So how can I combine my image and the other properties in one json object or two arguments? Please leave a comment if I need to explain some more, any help would really be appreciated :)
I found a solution, where I added the file and the model to the form data. So it was actually pretty easy to expand solution from here. This is my Angular controller:
function artworkController($scope, $routeParams, artworkResource, $http) {
$scope.categories = ['Keramik', 'Maleri', 'Møbel', 'Skulptur'];
artworkResource.getById($routeParams.id).then(function (response) {
$scope.curatorSubject = response.data;
});
var fd;
$scope.uploadFile = function(files) {
fd = new FormData();
fd.append("file", files[0]);
};
$scope.save = function (artwork) {
fd.append("ArtWork", angular.toJson(artwork));
$http.post("backoffice/Trapholt/ArtWorkApi/Post", fd, {
transformRequest: angular.identity,
headers: { 'Content-Type': undefined }
});
};
};
And this i my C# mvc API controller:
public HttpResponseMessage Post()
{
HttpResponseMessage result = null;
var httpRequest = HttpContext.Current.Request;
if (httpRequest.Files.Count > 0)
{
var file = httpRequest.Files[0];
var artworkjson = httpRequest.Form[0];
var artwork = JsonConvert.DeserializeObject<ArtWork>(artworkjson);
if (artwork == null)
{
return Request.CreateResponse(HttpStatusCode.BadRequest, "No saved");
}
using (var binaryReader = new BinaryReader(file.InputStream))
{
artwork.Picture = binaryReader.ReadBytes(file.ContentLength);
}
result = Request.CreateResponse(HttpStatusCode.Created, "ok");
}
else
{
result = Request.CreateResponse(HttpStatusCode.BadRequest);
}
return result;
}
The html view is a normal form where all the inputs are bound with the model, expect the file input field:
<input type="file" id="file" name="picture" onchange="angular.element(this).scope().uploadFile(this.files)"/>

Categories

Resources