How do I upload files with several records using an Angular-js http call to an MVC action method? - angularjs

In design, I have multi records with one file upload in tabular form.
in every ng-change of the file, I am getting the file and storing it into a global variable like below.
app.controller('AngController', function ($http, $scope) {
$scope.EqFiles = '';
$scope.UploadFiles = function (files) {
$scope.EqFiles = files;
};
on every 'Add' action (plus button) I am pulling all values into one array like below
$scope.SystemAccesories = [];
$scope.Add = function () {
var systemdetail = {};
systemdetail.SystemAcsId = 0;
systemdetail.AcsName = $scope.txtAccessoryName;
.
.
.
systemdetail.Remarks = $scope.txtSysRemarks;
if ($scope.EqFiles.length != 0) {
systemdetail.ManualFile = $scope.EqFiles;
systemdetail.IsManualFileAvailable = true;
}
else {
systemdetail.IsManualFileAvailable = false;
}
$scope.SystemAccesories.push(systemdetail);
};
at final I am sending it to the MVC controller's method
$http({
method: 'POST',
url: '/Equipment/UpdateEquipment',
data: { EquipmentAllFields: scope.SystemAccesories },
headers: { 'content-type': 'application/json' }
}).then(function (response) {
});
with the below parameters.
public class SystemAccessories
{
public int SystemAcsId { get; set; }
public string AcsName { get; set; }
.
.
.
public string Remarks { get; set; }
public Nullable<bool> IsManualFileAvailable { get; set; }
public HttpPostedFileBase ManualFile { get; set; }
}
on c# side getting all text values as expected but all 'ManualFile' parameters getting null values.
so how to catch it then I can store with exact related data.

in every ng-change of the file, I am getting the file and storing it into a global variable like below in the form of Base64 Serialization.
$scope.UploadSysFiles = function (event, sysAccId, rowIndex) {
var file = event.target.files;
if (file[0].size < 5000000) {
var reader = new FileReader();
reader.readAsDataURL(file[0]);
reader.onload = () => {
$scope.SysFileByteCode = reader.result;
};
cntSysMan = file.length;
$scope.SysFiles = file[0];
setTimeout(function () {
if (sysAccId === 0 && rowIndex !== -1) {
if (cntSysMan != 0) {
$scope.editedEquipmentList.SystemAccesories[rowIndex].ManualFile = $scope.SysFileByteCode;
}
}
else if (sysAccId !== 0 && rowIndex !== -1) {
if (cntSysMan != 0) {
if ($window.confirm("Do you really like to replace the file '" + $scope.editedEquipmentList.SystemAccesories[rowIndex].FileName + "' by '" + $scope.SysFiles.name + "' ?")) {
$scope.editedEquipmentList.SystemAccesories[rowIndex].ManualFile = $scope.SysFileByteCode;
}
}
}
}, 3000);
}
else {
alert('File size exceeded');
}
};
set time out to get the file because after getting the image to converting it to base64 and on-load event fire.
at final I am sending it to the MVC controller's method
$http({
method: 'POST',
url: '/Equipment/UpdateEquipment',
data: { EquipmentAllFields: scope.SystemAccesories },
headers: { 'content-type': 'application/json' }
}).then(function (response) {
});
MVC Controller
[HttpPost]
public ActionResult UpdateEquipment(EquipmentAllFields objEquipmentAllFields)
{.
.
.
foreach (var systemAcs in objEquipmentAllFields.objSystemAcs)
{
string removedAcsUnwantedString = systemAcs.ManualFile.Substring(systemAcs.ManualFile.LastIndexOf(',') + 1);
var base64AcsEncodedBytes = Convert.FromBase64String(removedAcsUnwantedString);
System.IO.File.WriteAllBytes(severFilePath + newFile, base64AcsEncodedBytes);
}
.
.
}

Related

How to pass a list of object for WEB API in angularjs

Hi i need to get input values from ng-repeat, i am having Item class like as follows
public class Item
{
private String _DesignId;
public String DesignId
{
get { return _DesignId; }
set { _DesignId = value; }
}
private String _DesignName;
public String DesignName
{
get { return _DesignName; }
set { _DesignName = value; }
}
private String _Unit;
public String Unit
{
get { return _Unit; }
set { _Unit = value; }
}
private String _Price;
public String Price
{
get { return _Price; }
set { _Price = value; }
}
}
Here my angularjs
$scope.saveAllValues = function() {
$scope.mylist = {};
angular.forEach($scope.invoice.items , function(value, key){
var objclsu = {
"DesignId" : value.DesignId,
"DesignName" : $scope.ctrl.DesignName,
"Unit" : value.unit,
"Price" : value.price,
};
$scope.mylist.push({objclsu});
});
Here I can not use push. objclsu is not an array. Here how to add objclsu into $scope.mylist.
Here my web method i am using generic list as a parameter
[WebMethod()]
public static void SaveList(List<Item> mylist)
{
}
var httpreq = {
method: 'POST',
url: 'Requirementapi/SaveList',
headers: { 'Content-Type': 'application/json; charset=utf-8', 'dataType': 'json' },
data: { mylist : $scope.mylist }
}
$http(httpreq).success(function (response) {
callmsg(" invoice Saved successfully.");
});

HttpClient post body param is not sent correctly when using 'application/x-www-form-urlencoded' content type request header

I am posting request using httpClient like:
I have imported HttpClientModule in app.module.js for http get and post request.
const httpOptionsWithCookie = {
headers: new HttpHeaders({ 'Content-Type': 'application/x-www-form-urlencoded'}),
withCredentials: true
};
this.baseUrl ("link of API")
postArguments is an object like " {name:"xyz",company:"abc"}"
this.http.post(this.baseUrl, postArguments, httpOptionsWithCookie);
I am using angular5 in front end and spring mvc at back end
I am new in angular5.
API side code :
**spring mvc imports
#RestController
#RequestMapping(value = "/api/leavePeriod")
public class LeavePeriodControllerApi {
private static LogHelper logHelper = LogHelper
.getInstance(LeaveApplicationControllerApi.class);
#Autowired
HttpSession session;
#Autowired
Environment env;
#Autowired
ILeavePeriodService service;
#Autowired
ISecurityCommonService securityCommonService;
#Autowired
ILeaveCategoryService leaveCategoryService;
#Autowired
ICompanyService companyService;
#Autowired
LeavePeriodValidator leavePeriodValidator;
private User user = new User();
private String LOGINUSER = "";
#RequestMapping(value = "/viewLeavePeriod", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public Map<String, Object> viewLeavePeriod( #ModelAttribute LeavePeriodForm form,HttpServletRequest request,#RequestParam(value ="companyId" ,required = false)
String companyId, #RequestParam(value ="leaveCategoryId", required = false)
String leaveCategoryId )throws HRAlignBaseException {
user = (User) session.getAttribute("user");
LOGINUSER = "LoginUser " + user.getEmpName() + " loginuser empCode "
+ user.getEmpCode();
Map<String, Object> returnMap = new HashMap<String, Object>();
try{
if(companyId!= null && companyId!="")
{
form.setCompanyId(Integer.parseInt(companyId));
}
if(leaveCategoryId!= null && leaveCategoryId!="")
{
form.setLeaveCategoryId(Integer.parseInt(leaveCategoryId));
}
returnMap = service.view(form);
returnMap.put("periodList", form.getLeavePeriodVoList());
returnMap.put("comId", form.getCompanyId());
returnMap.put("leaveCatId", form.getLeaveCategoryId());
} catch (Exception e) {
e.printStackTrace();
}
logHelper
.info("################"
+ LOGINUSER
+ "############# END Enter LeavePeriodController viewLeavePeriod");
return returnMap;
}
}
the same http post request work in angularjs but it's not working in angular5.
Also when doing the same http post from ARC, it's working fine but not working for angular5
for 'Content-Type': 'application/x-www-form-urlencoded' form data should be sent like "menuId=5&buttonRights=adfasdfad&abc=aasdfasdfd" and not in json format so this feature available in angularjs(ngResource)but not in angular 5(HttpClient).
this is a standard way to post data.
Below code is for simple object.
import { URLSearchParams } from "#angular/http"
testRequest() {
let data = new URLSearchParams();
data.append('username', username);
data.append('password', password);
this.http
.post('/api', data)
.subscribe(data => {
alert('ok');
}, error => {
console.log(error.json());
});
}
if you want to post object or nested object ,you have to manually convert the object to query string using below code.
jsonTransformRequest (data) {
var param = function (obj) {
var query = '';
var name, value, fullSubName, subValue, innerObj, i;
for (name in obj) {
value = obj[name];
if (value instanceof Array) {
for (i = 0; i < value.length; ++i) {
subValue = value[i];
fullSubName = name + '[' + i + ']';
innerObj = {};
innerObj[fullSubName] = subValue;
query += param(innerObj) + '&';
}
} else if (value instanceof Object) {
for (let subName in value) {
subValue = value[subName];
fullSubName = name + '.' + subName;
innerObj = {};
innerObj[fullSubName] = subValue;
query += param(innerObj) + '&';
}
} else if (value !== undefined && value !== null) {
query += encodeURIComponent(name) + '=' + encodeURIComponent(value) + '&';
}
}
return query.length ? query.substr(0, query.length - 1) : query;
};
var ret = (data != null && typeof data === 'object') ? param(data) :
data;
return ret;
};

Posting JavaScript objects with Ajax and ASP.NET MVC

How can I post a list from view to controller using ajax? I have this code in client side:
$(".js-save").click(function (e) {
e.preventDefault();
var button = $(this);
var lstERegistroVenta = [];
var ERegistroVenta = new Object();
ERegistroVenta.IdProducto = 1;
ERegistroVenta.IdInventario = 2;
ERegistroVenta.MontoProducto = 12.5;
ERegistroVenta.CantidadProducto = 1;
ERegistroVenta.MontoTotalSinIGV = 20.5
ERegistroVenta.MontoTotal = 23.5
lstERegistroVenta.push(ERegistroVenta);
$.ajax({
dataType: 'json',
type: 'POST',
url: "/API/Inventario/Venta/1",
data: JSON.stringify({ lstERegistroVenta: lstERegistroVenta }),
success: function () {
toastr.success("Correcto");
},
error: function () {
toastr.error("Error");
}
});
});
When I try to pass the data I receive only empty list. In server side I have this API
[HttpPost]
[Route("API/Inventario/{Venta}/{IdProducto}")]
public IHttpActionResult AsignarProducto(int IdProducto,List<ERegistroVenta> lstERegistroVenta)
{
return Ok();
}
public class ERegistroVenta
{
public int IdProducto { get; set; }
public int IdInventario { get; set; }
public double MontoProducto { get; set; }
public int CantidadProducto { get; set; }
public double MontoTotalSinIGV { get; set; }
public double MontoTotal { get; set; }
}
First of all, I wouldn't suggest calling an API method directly from a View. Instead, call a controller method which should internally call the API method. The code for this would look something like below.
$.ajax({
dataType: 'json',
type: 'POST',
url: "/TestController/TestMethod",
data: { "IdProducto" : "1", "lstERegistroVenta": lstERegistroVenta },
success: function () {
toastr.success("Correcto");
},
error: function () {
toastr.error("Error");
}
});
[HttpPost]
public void TestMethod(int IdProducto,List<ERegistroVenta> lstERegistroVenta)
{
// Your Logic Here
}
I found a solution. Maybe my mistake was that I didn't send an anonymous list of objects.
Take a look to this:https://kwilson.io/blog/post-an-array-of-objects-to-webapi-using-jquery/
My solution below:
$(".js-save").click(function (e) {
e.preventDefault();
var button = $(this);
var lstERegistroVenta = [];
var ERegistroVenta = new Object();
ERegistroVenta.IdProducto = 1;
ERegistroVenta.IdInventario = 2;
ERegistroVenta.MontoProducto = 12.5;
ERegistroVenta.CantidadProducto = 1;
ERegistroVenta.MontoTotalSinIGV = 20.5
ERegistroVenta.MontoTotal = 23.5
lstERegistroVenta.push(ERegistroVenta);
$.ajax({
dataType: 'json',
method: 'POST',
url: "/API/Inventario/Venta/1",
data: { '': lstERegistroVenta },
success: function () {
toastr.success("Correcto");
},
error: function () {
toastr.error("Error");
}
});
});
And in server side:
[HttpPost]
[Route("API/Inventario/{Venta}/{IdProducto}")]
public IHttpActionResult AsignarProducto(int IdProducto,List<ERegistroVenta> lstERegistroVenta)
{
// Logic Here
}
Hope this helps to another user.

Return image from DB and display with .NET API and AngularJS

I wanna achieve a simple task, which is to retrieve the binary image, and display it in my html
public class Artwork
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid artworkID { get; set; }
public string artworkName { get; set; }
public string artworkMimeType { get; set; }
public byte[] artworkMeta { get; set; }
public string artworkBase64String { get; set; }
}
Gets the artwork from DB
public Artwork GetArtwork(Guid id)
{
return _context.Artworks.SingleOrDefault(a => a.artworkID == id);
}
The API Controller
public IHttpActionResult Get(Guid id)
{
if (id == null)
{
return BadRequest();
}
var artwork = _repository.GetArtwork(id);
if (artwork == null)
return NotFound();
else
return Ok(artwork);
}
I've also used this method and it returns the data I want, but I still don't know how to use it to achieve my goal.
[HttpGet]
public HttpResponseMessage Get(Guid id)
{
HttpResponseMessage result = null;
try
{
var artwork = _repository.GetArtwork(id);
if (artwork == null)
{
result = Request.CreateResponse(HttpStatusCode.Gone);
}
else
{
// sendo file to client
byte[] bytes = artwork.artworkMeta ;
result = Request.CreateResponse(HttpStatusCode.OK);
result.Content = new ByteArrayContent(bytes);
result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentDisposition.FileName = artwork.artworkName;
}
return result;
}
catch (Exception ex)
{
return Request.CreateResponse(HttpStatusCode.Gone);
}
}
And here's my angular request
$scope.getCity = function (id) {
$http.get('/api/artwork/' + $RouteParams.id).success(function (response) {
$scope.artwork= response;
//I've seen dudes using Blob here, but I'm not sure how that works
});
}
My problem is my angular request and my html, how do I display the artwork without doing this:
<img ng-src="data:{{artwork.artworkartworkMimeType}};base64,{{artwork.artworkBase64String}}" class="img-responsive" />
This displays the image, but I don't like how clumsy it looks, and I'm gonna be working with audio files as well, so I need a clean and understandable way. Please help!
As you said, this can be done by using a blob.
First step is to set the content type to application/octet-stream in the api method
[HttpGet]
public HttpResponseMessage Get(Guid id)
{
HttpResponseMessage result = null;
try
{
var artwork = _repository.GetArtwork(id);
if (artwork == null)
{
result = Request.CreateResponse(HttpStatusCode.Gone);
}
else
{
// sendo file to client
byte[] bytes = artwork.artworkMeta ;
result = Request.CreateResponse(HttpStatusCode.OK);
result.Content = new ByteArrayContent(bytes);
result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentDisposition.FileName = artwork.artworkName;
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
}
return result;
}
catch (Exception ex)
{
return Request.CreateResponse(HttpStatusCode.Gone);
}
}
Then add the client request where you create a blob from the response. An url is then created for the blob which will be the source for the img
$scope.fileURL = '';
$http({
method: 'GET',
url: '/api/artwork/' + $RouteParams.id,
responseType: 'arraybuffer',
headers: {
'Access-Control-Allow-Origin': '*',
}
}).success(function (data, status, headers) {
headers = headers();
var contentType = headers['content-type'];
var blob = new Blob([data], { type: contentType });
//Create a url to the blob
$scope.fileURL = window.URL.createObjectURL(blob);
}).error(function (message) {
console.log(message);
});
Then bind url to the ngSrc
<img ng-src="{{fileURL}}" class="img-responsive" />
You could store image in binary format without encoding it to base64. Then it would be simpler to retrive image from DB.
In your asp controller:
[HttpGet]
public FileResult GetPhoto(int id) {
return File(_repository.GetArtwork(id).artworkMeta, "image/jpg");
}
And in angular view:
<img ng-src="/Home/GetPhoto/2" />

HttpPostedFileBase is null - Posting files from AngularJS to MVC

Similar questions have been asked so many times, but there are no clear answers, I still have trouble getting mine to work.
This is the model in C#
public class SubmitModel
{
public string Name { get; set; }
public HttpPostedFileBase File { get; set; }
public IEnumerable<HttpPostedFileBase> Files { get; set; }
}
This is the MVC code
[HttpPost]
public ActionResult Test(SubmitModel model)
{
// Here model.File and model.Files is always null
}
This is what I submitted using AngularJS
var data = {
name: scope.name, // This is passed to MVC successfully
file: scope.files[0], // Doesn't even work with single file
files: scope.files // This is a FileList
};
$http.post("/umbraco/surface/MyController/Test", data).success(...);
If you want to know how I assign scope.files:
$('#upload').on('change', function (e) {
scope.$apply(function () {
scope.files = e.target.files;
});
});
Could someone see what I am missing?
Solved it!
This is how it should be submitted
var data = new FormData();
angular.forEach(scope.item, function (value, key) {
if (key == "files") {
for (var i = 0; i < value.length; i++) {
data.append(value[i].name, value[i]); // Filename:File
}
} else {
data.append(key, value);
}
});
$http.post("/umbraco/surface/MyController/Test", data, {
transformRequest: angular.identity,
headers: { 'Content-Type': undefined }
}).success(...);
Then in MVC, we get the files from Request.Files, it won't be in the model.
[HttpPost]
public ActionResult Test(SubmitModel model)
{
var files = Request.Files; // a collection of HttpPostedFileBase
Save(model, files);
}
More info:
https://uncorkedstudios.com/blog/multipartformdata-file-upload-with-angularjs
http://www.codeproject.com/Tips/878730/File-Upload-Using-AngularJS-and-ASP-NET-MVC

Resources