Send files through AJAX using FormData to ASP.NET MVC - javascript

I have a simple model:
public class MyModel {
public string Description { get; set; }
public HttpPostedFileBase File {get; set; }
}
and my MVC action:
[HttpPost]
public ActionResult Upload(List<MyModel> data) {
// do soemthing
}
and finally JavaScript:
$("#chooseFile").on("change", function (){
var files = $(this).prop("files");
var array = [];
for(int i=0; i<files.length; i++) {
var obj = {};
obj.Description = "My custom description" + i;
obj.File = files[i];
array.push(obj);
}
var formData = new FormData();
formData.append("data", array);
var xmlHttpRequest = new XMLHttpRequest();
xmlHttpRequest.open("POST", "/test/Upload");
xmlHttpRequest.send(formData);
});
The problem is that data from the Upload action always has Count = 0 . Where is my mistake ?

In order bind to a collection of complex objects, the names (in the name/value pairs) must include indexers. Your script needs to add the names to FormData in the following format - '[0].Files', '[0].Description', '[1].Files', '[1].Description' etc
$("#chooseFile").on("change", function() {
var files = $(this).prop("files");
var formData = new FormData();
for(int i=0; i<files.length; i++) {
formData.append('[' + i + '].File', files[i]);
formData.append('[' + i + '].Description', 'My custom description' + i);
}
var xmlHttpRequest = new XMLHttpRequest();
....

Related

How to read the content from a C# HttpResponseMessage in javascript?

I have a string called csv that is literally just that, things like "name,lastname,age,height,etc"
Then I send it to the backend like this..
var csv = exportRequests.GetCSV();
var filename = string.Format("{0}-{1}-{2:yyyy-MM-dd_hh-mm-ss-tt}.csv", "Request", requestStatus.ToUpperInvariant(), DateTime.Now);
var stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
writer.Write(csv);
writer.Flush();
var result = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new ByteArrayContent(stream.GetBuffer())
};
result.Content.Headers.ContentDisposition =
new ContentDispositionHeaderValue("attachment")
{
FileName = filename
};
result.Content.Headers.ContentType =
new MediaTypeHeaderValue("text/csv");
//var test = new FileDetailViewModel();
//test.Name = filename;
//test.Rows = csv;
return Ok(result);
I then read it on the backend, but where is the actual content?? Surely the bytes should be somewhere. The content property only has the headers.. This is taking place on an old system using $.ajax to make the call.
Thanks
I do not think it is possible to read content via HttpResponseMessage in JavaScript. You can only download content.
public HttpResponseMessage GetCsv()
{
var csv = exportRequests.GetCSV();
var filename = string.Format("{0}-{1}-{2:yyyy-MM-dd_hh-mm-ss-tt}.csv", "Request", requestStatus.ToUpperInvariant(), DateTime.Now);
var stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
writer.Write(csv);
writer.Flush();
var result = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new ByteArrayContent(stream.GetBuffer())
};
result.Content.Headers.ContentDisposition =
new ContentDispositionHeaderValue("attachment")
{
FileName = filename
};
result.Content.Headers.ContentType = new MediaTypeHeaderValue("text/csv");
return result;
}
download script
window.open('/api/controller/GetCsv', '_blank', '');
If you want to display csv content you can use the following code
[HttpPost]
public String GetCsv()
{
return exportRequests.GetCSV();
}
script
$('#btngetcsv').click(function() {
$.ajax({
url: "/api/controller/GetCsv",
data: {},
type: "Post",
dataType: "Json",
success: function(result) {
var arr = csvToArray(result);
for (var i = 0; i < arr.length; i++) {
var name = arr[i].name;
var lastname = arr[i].lastname;
//etc...........
}
},
error: function() {
}
});
});
function csvToArray(str, delimiter = ",") {
// slice from start of text to the first \n index
// use split to create an array from string by delimiter
const headers = str.slice(0, str.indexOf("\n")).split(delimiter);
// slice from \n index + 1 to the end of the text
// use split to create an array of each csv value row
const rows = str.slice(str.indexOf("\n") + 1).split("\n");
// Map the rows
// split values from each row into an array
// use headers.reduce to create an object
// object properties derived from headers:values
// the object passed as an element of the array
const arr = rows.map(function(row) {
const values = row.split(delimiter);
const el = headers.reduce(function(object, header, index) {
object[header] = values[index];
return object;
}, {});
return el;
});
// return the array
return arr;
}

DateTime is not displayed as expected [duplicate]

This question already has answers here:
Javascript serialization of DateTime in asp.net is not giving a javascript date object?
(10 answers)
Closed 6 years ago.
I have a C# code to get some dates from a Sql Table, these dates are filled by mssql getdate() the problem here is that my dates are displayed in the following structure:
/Date(1480343496517)/
And what I expect is this:
2016-11-28 08:13:23.820 //This is what I get executing my query in MSSQL
This is my full code:
C# Class
public MyDate(DateTime date)
{
Date = date;
}
public DateTime Date { get; set; }
WebMethod
[WebMethod]
public string ShowDate()
{
DataTable dt = new DataTable();
dt = conn.CheckTable("date");
MyDate fch;
List<MyDate> list = new List<MyDate>();
for (int i = 0; i < dt.Rows.Count; i++)
{
fch = new Fecha();
fch.Date = Convert.ToDateTime(dt.Rows[i]["Date"]);
list.Add(fch);
fch = null;
}
JavaScriptSerializer js = new JavaScriptSerializer();
string lines = js.Serialize(list);
return lines;
}
CheckTable
public DataTable CheckTable(string table)
{
dt = new DataTable();
ds = new DataSet();
string sql = "";
switch (table)
{
case "date":
sql = "SELECT Date FROM dbo.Table_1";
break;
}
try
{
Open();
SqlDataAdapter da = new SqlDataAdapter(sql, conn);
da.Fill(ds);
dt = ds.Tables[0];
}
catch (Exception ex)
{
}
finally
{
Close();
}
return dt;
}
And my JS function:
$.ajax({
type: 'POST', //POST | GET
url: "WebService.asmx/ShowDate", //Direccion del ws
dataType: 'json',
contentType: 'application/json',
timeout: 600000,
error: function (xhr) {
$('#dates').html('<option>Error</option>');
},
success: function (data) {
var datas = JSON.parse(data.d);
for (var i = 0; i < datos.length; i++) {
var myDate= datas[i].Date;
options += '<option value ="' + myDate+ '">';
options += myDate;
options += '</option>';
}
$('#dates').html(options);
}
});
What I'm doing wrong and what can I do to solve it?
I don't know what the other classes you're using are, but if you just want a list of dates from the query then this should do it...
[WebMethod]
public string ShowDate()
{
DataTable dt = new DataTable();
dt = conn.CheckTable("date");
List<DateTime> list = new List<DateTime>();
for (int i = 0; i < dt.Rows.Count; i++)
{
list.Add(Convert.ToDateTime(dt.Rows[i]["Date"]).ToString());
}
JavaScriptSerializer js = new JavaScriptSerializer();
string lines = js.Serialize(list);
return lines;
}
then in the JavaScript, change this one line...
var myDate = datas[i];
The web method will now just return a serialised list of dates, so no need to get a .date property of the list objects any more.

How to Post images using XMLHttpRequest and ASP.net MVC

I am trying to upload multiple image with AngularJS. As i have to track the progress of each file i decide to use XMLHttpRequest to Post the image to ASP.net MVC controller. the js code is as follows
$scope.UploadImage=function()
{
var reqObj = new XMLHttpRequest();
//event Handler
reqObj.upload.addEventListener("progress", uploadProgress, false)
reqObj.addEventListener("load", uploadComplete, false)
reqObj.addEventListener("error", uploadFailed, false)
reqObj.addEventListener("abort", uploadCanceled, false)
for (var i = 0; i < $scope.fileList.length; i++)
{
var fileToUpload = $scope.fileList[i].file;
var fd = new FormData();
fd.append('file', fileToUpload);
reqObj.open("POST", "/WebDevelopment/SaveImage", false);
reqObj.setRequestHeader("Content-Type", "multipart/form-data");
reqObj.send(fd);
}
function uploadProgress(evt) {
$scope.uploadProgressCount = Math.round(evt.loaded * 100 / evt.total);
$scope.$apply();
}
function uploadComplete(evt) {
/* This event is raised when the server send back a response */
alert(evt.target.responseText)
}
function uploadFailed(evt) {
alert("There was an error attempting to upload the file.")
}
function uploadCanceled(evt) {
alert("The upload has been canceled by the user or the browser dropped the connection.")
}
}
I tried the following ASP.net MCV Controller to receive the file
public JsonResult SaveImage()
{
string path = "";
var httpRequest = System.Web.HttpContext.Current.Request;
if (httpRequest.Files.Count > 0)
{
// do something
}
}
the problem is i found httpRequest.Files.Count is zero all time. Why? i googling many time but do not understand what is going wrong. any one there to help me
I had problems with Request.Files but it helped me to take an approach, it might be useful for you as well
public class WebDevelopmentController : Controller
{
[HttpPost]
public JsonResult SaveImage()
{
var fileContents = new byte[Request.ContentLength];
Request.InputStream.Read(fileContents, 0, Request.ContentLength);
var filename = Request.Headers["X-File-Name"];
var fileType = Request.Headers["X-File-Type"];
var file = new UploadedFile() {
Filename = filename,
ContentType = fileType,
FileSize = fileContents != null ? fileContents.Length : 0,
Contents = fileContents
};
// save the file.
var saveToFileLoc = string.Format("{0}\\{1}",
Server.MapPath("/Content"),
file.Filename);
var fileStream = new FileStream(saveToFileLoc, FileMode.Create, FileAccess.ReadWrite);
fileStream.Write(file.Contents, 0, file.FileSize);
fileStream.Close();
return null;
}
public class UploadedFile
{
public int FileSize { get; set; }
public string Filename { get; set; }
public string ContentType { get; set; }
public byte[] Contents { get; set; }
}
}
And move your XHR object to the loop:
$scope.UploadImage = function() {
for (var i = 0; i < $scope.fileList.length; i++) {
var reqObj = new XMLHttpRequest();
//event Handler
reqObj.upload.addEventListener("progress", uploadProgress, false)
reqObj.addEventListener("load", uploadComplete, false)
reqObj.addEventListener("error", uploadFailed, false)
reqObj.addEventListener("abort", uploadCanceled, false)
var fileToUpload = $scope.fileList[i].file;
var fd = new FormData();
fd.append('file', fileToUpload);
reqObj.open("POST", "/WebDevelopment/SaveImage", false);
reqObj.setRequestHeader("Content-Type", "multipart/form-data");
reqObj.send(fd);
}
function uploadProgress(evt) {
$scope.uploadProgressCount = Math.round(evt.loaded * 100 / evt.total);
$scope.$apply();
}
function uploadComplete(evt) {
/* This event is raised when the server send back a response */
alert(evt.target.responseText)
}
function uploadFailed(evt) {
alert("There was an error attempting to upload the file.")
}
function uploadCanceled(evt) {
alert("The upload has been canceled by the user or the browser dropped the connection.")
}
}

Generating array of arrays

I have a Web-API method that is returning JSON and I want the array structure to look like this:
[ [123, 1.1], [222, 3.9] ]
My Web API controller is returning JSON in the following format:
[{"CreatedDate":1314736440,"Reading":20.0}, "CreatedDate":1314779640,"Reading":7.9}]
Web API Controller:
[HttpGet]
public HttpResponseMessage AllJson()
{
using (var ctx = new SomeContext())
{
var records = ctx.DataX.ToList();
var dtos = Mapper.Map<...>(records);
return new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent(JsonConvert.SerializeObject(dtos), Encoding.UTF8, "application/json")
};
}
}
DTO
public class DtoModel
{
public int CreatedDate { get; set; }
public double Reading { get; set; }
}
Sample Javascipt:
var seriesData = [];
$.getJSON("api/xxx/AllJson ", function (data) {
$.each(data, function (key, val) {
seriesData.push(val.CreatedDate.toString() + " ," + val.Reading.toString());
console.log(val.CreatedDate + " ," + val.Reading);
});
});
You need to create an a single array containing many arrays of length 2.
See this code:
$.getJSON("api/xxx/AllJson")
.done(function (data) {
var processedJson = new Array();
$.map(data, function (obj, i) {
processedJson.push([obj.CreatedDate, obj.Reading]);
});
FunctionToDoSomethingWithYourDataStructure(processedJson);
});
I think this might solve your problem..
structure wise, this should look like [[a,b],[c,d]];
var createSeriesData = function(){
seriesData = [];
JSON_obj = JSON.parse('[{"CreatedDate":1314736440,"Reading":20.0},{"CreatedDate":1314779640,"Reading":7.9}]');
for(var key in JSON_obj){
if(JSON_obj.hasOwnProperty(key)){
seriesData[key] = [];
seriesData[key].push(JSON_obj[key].CreatedDate.toString());
seriesData[key].push(JSON_obj[key].Reading.toString());
}
}
console.log(seriesData);
}

Getting C# Method With jQuery in asp.net

I am using the code below to display an uploaded picture in asp.net . The Image name is change to a unique name and args.get_fileName retrieves the original name of the file instead of the new unique name.
How can I retrieve the new unique name:
protected void FileUploadComplete(object sender, EventArgs e)
{
var date = DateTime.Now.ToString("yyyy-MM-dd-hh_mm_ss");
string filename = System.IO.Path.GetFileName(AsyncFileUpload1.FileName);
AsyncFileUpload1.SaveAs("~/listingImages/" + date + filename);
}
Script:
function uploadStarted() {
$get("imgDisplay").style.display = "none";
}
function uploadComplete(sender, args) {
var imgDisplay = $get("imgDisplay");
imgDisplay.src = "images/loader.gif";
imgDisplay.style.cssText = "";
var img = new Image();
img.onload = function () {
imgDisplay.style.cssText = "height:100px;width:100px";
imgDisplay.src = img.src;
};
img.src = "/listingImages/" + args.get_fileName();
$('#bodyContent_Label1').html("/listingImages/" + args.get_fileName());
}
You should use password generating concept
private static string CreateRandomPassword(int passwordLength)
{
string allowedChars = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789!#$?_-";
char[] chars = new char[passwordLength];
Random rd = new Random();
for (int i = 0; i < passwordLength; i++)
{
chars[i] = allowedChars[rd.Next(0, allowedChars.Length)];
}
return new string(chars);
}

Categories

Resources