Trouble sending JavaScript mp3 file to asp.net generic handler via Ajax? - javascript

I have an Input FileUpload and a button as html elements
<input id='track' type='file' style='display: none' accept='.mp3' />
<input type="button" id="btnUpload" value="Upload" />
and has a javascript event handler which saves the uploaded file as a javascript variable.
document.getElementById("track").addEventListener("change",upload_track_audio_eventhandler, false);
var currentTrackAudioFile;
function upload_track_audio_eventhandler() {
var files = event.target.files;
currentTrackAudioFile = files[0];
}
and then there is another function which is suppose to upload the audio file (currentTrackAudioFile) to asp.net Generic Handler.
document.getElementById("btnUpload").addEventListener("click", butttonclick)
function butttonclick() {
$.ajax({
url: 'Handler1.ashx',
type: 'POST',
data: currentTrackAudioFile,
cache: false,
contentType: false,
processData: false,
success: function (file) {
alert("uploaded");
}
});
}
public class Handler1 : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
if (context.Request.Files.Count > 0)
{
HttpPostedFile postedFile = context.Request.Files[0];
string folderPath = context.Server.MapPath("~/Uploads/");
string fileName = Path.GetFileName(postedFile.FileName);
postedFile.SaveAs(folderPath + fileName);
string json = new JavaScriptSerializer().Serialize(
new
{
name = fileName
});
context.Response.StatusCode = (int)HttpStatusCode.OK;
context.Response.ContentType = "text/json";
context.Response.Write(json);
context.Response.End();
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
But its not receiving the file. context.Request.Files.Count is 0.
What am i doing wrong ?
p.s. I don't want to send directly from the DOM ( i.e. data: new FormData($('form')[0]))

Related

POST file list to controller in ajax post

I tried to upload documents but I couldnt pass to list my controllers parameter. My scenario is:
user click to "choose file" button and pick the files and press done
then my some functions get file list and pass to controller for save locally via POST merhod like below:
view side: (get file list)
function saveDocuments(documentList) {
if (documentList.length > 0)
{
var formList = new Array;
for (var i = 0; i < documentList.length; i++) {
var form = new FormData();
var file = documentList[i];
form.append('FormFile', file);
formList.push(form);
}
savePhysicalFile(formList);
}
}
view side: (post file list)
function savePhysicalFile(formData)
{
if (formData != null)
{
$.ajax({
url: "Installation/SavePhysicalPath",
type: 'POST',
dataType: "json",
contentType: "multipart/form-data",
data:formData,
processData: false,
contentType: false,
success: function (result) {
console.log("Success", result);
},
error: function (data) {
console.log(data);
}
});
}
}
In my controller side; the parameter "model" is always null. I couldnt pass view side list here. How can I figure out ?
controller side
public JsonResult SavePhysicalPath([FromForm] List<FileModel> model)
{
var savingRootPath = #"C:\MyDocuments";
//I'm doing save locally
return Json(savingRootPath);
}
model side
public class FileModel
{
public string Files { get; set; }
public IFormFile FormFile { get; set; }
}
From your code,you may pay attention to two things here:
1.For each property of the complex type, model binding looks through the sources for the name pattern prefix.property_name. If nothing is found, it looks for just property_name without the prefix.For model you receive in backend is a List,you need give the name like:[index].FormFile or model[index].FormFile.
2.Your model has a IFormFile and your action receives a list model,if you only pass the IFormFile you need remove FromForm attribute and be sure do not have [ApiController].It is a known github issue and this has been moved to Next sprint planning milestone.
Here is a whole working demo:
View:
<input type="file" multiple onchange="saveDocuments(this.files)"/>
<div class="form-group">
<input type="button" value="Submit" id="submit" class="btn btn-primary" />
</div>
#section Scripts
{
<script>
function saveDocuments(documentList) {
if (documentList.length > 0) {
var form = new FormData();
for (var i = 0; i < documentList.length; i++) {
var file = documentList[i];
//change here
form.append('model['+i+'].FormFile', file);
}
savePhysicalFile(form);
}
}
function savePhysicalFile(formData) {
if (formData != null) {
$.ajax({
url: "/Installation/SavePhysicalPath",
type: 'POST',
dataType: "json",
contentType: "multipart/form-data",
data: formData,
processData: false,
contentType: false,
success: function (result) {
console.log("Success", result);
},
error: function (data) {
console.log(data);
}
});
}
}
</script>
}
Controller:
[HttpPost]
public JsonResult SavePhysicalPath(List<FileModel> model)
{
var savingRootPath = #"C:\MyDocuments";
//I'm doing save locally
return Json(savingRootPath);
}
Result:

How can I send a viewmodel to controller through Ajax

The user is able to write text and upload a file.
Using Javascript, I create an object with the file and text as properties, then send it to the controller using Ajax.
Using debugging, it seems that the problem is in the Ajax part. Everything before that(file upload, object creation) seems to be fine.
Here is the Javascript/JQuery:
function AddPost() {
var fileInput = document.getElementById('file').files;
var textInput = document.getElementById('addPostText').value;
if (fileInput != null || textInput != null) {
file = null;
if (fileInput.length > 0) {
file = fileInput[length-1];
}
var AddPostViewModel =
{
"Text": textInput,
"File": file
};
$.ajax(
{
url: "#Url.Action('AddPost')",
type: "POST",
dataType: "json",
data: JSON.stringify(AddPostViewModel),
contentType: 'application/json; charset=utf-8'
}
);
}
}
Here is the method in the controller:
[HttpPost]
public void AddPost(AddPostViewModel viewModel)
{
}
And here is the object:
public class AddPostViewModel
{
[DataType(DataType.MultilineText)]
public string Text { get; set; }
public IFormFile File { get; set; }
}
The HTML:
<textarea id="addPostText"></textarea>
<div class="upload-button">
<div class="label">Add image</div>
<input id="file" type="file" size="1" />
</div>
You can't send the File inside a json. Also, you've a bug in line file = fileInput[length-1]; (length is wrong, should be 0 or fileInput.length-1.
Here is a working function. This function should be inside a Razor Page because it needs to build the form action url #Url.Action("AddPost").
function AddPost() {
var fileInput = document.getElementById('file').files;
var textInput = document.getElementById('addPostText').value;
if (fileInput != null || textInput != null) {
var file = null;
if (fileInput.length > 0) {
file = fileInput[0];
}
var form = new FormData();
form.append("Text", textInput);
form.append("File", file);
$.ajax(
{
url: '#Url.Action("AddPost")',
type: "POST",
data: form,
processData: false,
contentType: false
}
);
}
}
EDIT Here is a full demo using the tag helpers asp-action, asp-for and a small JS/jQuery code to intercept the form submission and use Ajax.
1: Controller.
public class FileController : Controller
{
public IActionResult AddPost()
{
return View();
}
[HttpPost]
public void AddPost(AddPostViewModel viewModel)
{
//process the viewModel here
}
}
2: View
#model AddPostViewModel
<form asp-action="AddPost" id="theForm">
<textarea asp-for="Text"></textarea>
<input asp-for="File" size="1" />
<button type="submit">Send</button>
</form>
#section Scripts{
<script>
$("#theForm").submit(function(event) {
event.preventDefault();
$.ajax(
{
url: $(this).prop("action"),
type: "POST",
data: new FormData(this),
processData: false,
contentType: false,
success: function() {
console.log("form sent!");
}
}
);
});
</script>
}
You cant stringify a file data and you cant send file as JSON. You should use FormData to send file with ajax request.
Try to send request as follow
function AddPost() {
var fileInput = document.getElementById('file').files;
var textInput = document.getElementById('addPostText').value;
if (fileInput != null || textInput != null) {
file = null;
if (fileInput.length > 0) {
file = fileInput[length-1];
}
var AddPostViewModel =
{
"Text": textInput,
"File": file
};
var formData = new FormData();
Object.getOwnPropertyNames(AddPostViewModel).forEach(function ( attr, index ) {
var value = AddPostViewModel[attr];
formData.append(attr, value)
});
$.ajax(
{
url: "#Url.Action('AddPost')",
type: "POST",
contentType: false,
processData: false,
data: formData,
}
);
}
}

Submit a Form using AJAX in ASP.Net Core MVC

I am working with ASP.Net Core 2.1, and trying to upload a file while returning it's url, without refreshing the page.
I am trying to write the JavaScript in site.js as the _RenderPartial("scripts") renders all scripts at the end of the page and hence directly using script tag in the razor view is not working. Secondly, adding it to site.js gives me an opportunity to call the script across the site views.
My Controller action looks like :
[HttpPost]
[DisableRequestSizeLimit]
public async Task<IActionResult> Upload()
{
// Read & copy to stream the content of MultiPart-Form
// Return the URL of the uploaded file
return Content(FileName);
}
My view looks like :
<form id="FileUploadForm" action="~/Resources/Upload" method="post" enctype="multipart/form-data">
<input name="uploadfile" type="file" />
<button name="uploadbtn" type="submit" onclick="SubmitForm(this.parentElement, event)">Upload</button>
The site.js currently looks like :
function SubmitForm(form, caller) {
caller.preventDefault();
$.ajax(
{
type: form.method,
url: form.action,
data: form.serialize(),
success: function (data) { alert(data); },
error: function (data) { alert(data); }
})}
Presently, the code bypasses the entire script and the file is uploaded and new view displaying the file name is returned. I need help to create the javascript.
Unfortunately the jQuery serialize() method will not include input file elements. So the file user selected is not going to be included in the serialized value (which is basically a string).
What you may do is, create a FormData object, append the file(s) to that. When making the
ajax call, you need to specify processData and contentType property values to false
<form id="FileUploadForm" asp-action="Upload" asp-controller="Home"
method="post" enctype="multipart/form-data">
<input id="uploadfile" type="file" />
<button name="uploadbtn" type="submit">Upload</button>
</form>
and here in the unobutrusive way to handle the form submit event where we will stop the regular behavior and do an ajax submit instead.
$(function () {
$("#FileUploadForm").submit(function (e) {
e.preventDefault();
console.log('Doing ajax submit');
var formAction = $(this).attr("action");
var fdata = new FormData();
var fileInput = $('#uploadfile')[0];
var file = fileInput.files[0];
fdata.append("file", file);
$.ajax({
type: 'post',
url: formAction,
data: fdata,
processData: false,
contentType: false
}).done(function (result) {
// do something with the result now
console.log(result);
if (result.status === "success") {
alert(result.url);
} else {
alert(result.message);
}
});
});
})
Assuming your server side method has a parameter of with name same as the one we used when we created the FormData object entry(file). Here is a sample where it will upload the image to the uploads directory inside wwwwroot.
The action method returns a JSON object with a status and url/message property and you can use that in the success/done handler of the ajax call to whatever you want to do.
public class HomeController : Controller
{
private readonly IHostingEnvironment hostingEnvironment;
public HomeController(IHostingEnvironment environment)
{
_context = context;
hostingEnvironment = environment;
}
[HttpPost]
public async Task<IActionResult> Upload(IFormFile file)
{
try
{
var uniqueFileName = GetUniqueFileName(file.FileName);
var uploads = Path.Combine(hostingEnvironment.WebRootPath, "uploads");
var filePath = Path.Combine(uploads, uniqueFileName);
file.CopyTo(new FileStream(filePath, FileMode.Create));
var url = Url.Content("~/uploads/" + uniqueFileName);
return Json(new { status = "success", url = url });
}
catch(Exception ex)
{
// to do : log error
return Json(new { status = "error", message = ex.Message });
}
}
private string GetUniqueFileName(string fileName)
{
fileName = Path.GetFileName(fileName);
return Path.GetFileNameWithoutExtension(fileName)
+ "_"
+ Guid.NewGuid().ToString().Substring(0, 4)
+ Path.GetExtension(fileName);
}
}
Sharing the code that worked for me, implementing #Shyju's answer.
View ( Razor Page ):
<form name="UploadForm" action="~/Resources/Upload" method="post" enctype="multipart/form-data">
<input name="uploadfile" type="file" />
<button name="uploadbtn" type="submit" onclick="SubmitForm(this.parentElement, event)">Upload</button>
AJAX code added in Site.js (to make it a reusable):
// The function takes Form and the event object as parameter
function SubmitForm(frm, caller) {
caller.preventDefault();
var fdata = new FormData();
var file = $(frm).find('input:file[name="uploadfile"]')[0].files[0];
fdata.append("file", file);
$.ajax(
{
type: frm.method,
url: frm.action,
data: fdata,
processData: false,
contentType: false,
success: function (data) {
alert(data);
},
error: function (data) {
alert(data);
}
})
};
if you want to submit the form without using ajax request
var form = document.getElementById('formId');
form.submit();

Ajax image uploader issue

I have a issue with a image uploader i am making in ASP. I want to upload a image to the projects folder using ajax.
my html and js:
<form id="form1" runat="server">
<div>
<asp:FileUpload ID="FileUpload1" runat="server" />
<br />
<br />
UPLOAD
</div>
</form>
<script>
function uploadImg(){
var formData = new FormData();
formData.append('FileUpload1', $('#btnImg')[0].files[0]);
$.ajax({
type: "POST",
url: 'Default.aspx/imageUpload',
data: formData,
contentType: 'application/json; charset=utf-8',
success: function (data) {
alert(data);
}
});
}
</script>
my image upload code(c#):
[WebMethod]
protected void imageUpload(object sender, EventArgs e)
{
if (FileUpload1.HasFile)
{
string fileName = Path.GetFileName(FileUpload1.PostedFile.FileName);
Guid _fileNameRandom = Guid.NewGuid();
string _fileNameStr = _fileNameRandom.ToString();
FileUpload1.PostedFile.SaveAs(Server.MapPath("/Images/") + (_fileNameStr + fileName));
Response.Redirect(Request.Url.AbsoluteUri);
}
}
IN console i get the following errors:
Uncaught TypeError: Cannot read property '0' of undefined
at uploadImg (Default.aspx:32)
at HTMLAnchorElement.onclick (Default.aspx:21)
line 32 in default.aspx is: }); of the js script.
and line 21 is: function uploadImg(){
Hope anyone can help me resolve this.
$('#btnImg')[0] is the culprit.
$('#btnImg')[0] will never have a files collection, because that's an anchor element, try changing it to $('#FileUpload1')[0], and see if that works? If not, you need to reference the input[type='file'] element which I think the ASP helper should render for you with that id.
It works for me, to Show the image and Upload the image:
HTML:
<label asp-for="Image"></label>
<input type="file" id="FileUpload" onchange="ShowImage(this)" name="file" />
<input type="button" id="but_upload" class="button" value="Upload">
<img src="#" id="imgBox" class="img-responsive" width="100%"/>
js:
Show the image
function ShowImage(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
$('#imgBox').attr("src", e.target.result);
};
reader.readAsDataURL(input.files[0]);
}
}
Upload the image:
var fd = new FormData();
$(document).ready(function () {
$('#but_upload').click(function () {
var file = $("#FileUpload").get(0).files;
if (file != undefined) {
fd.append('fillle', file[0]);
}
else {
alert("undefined");
}
$.ajax({
url: "/Admin/Person/UploadFile",
type: "POST",
data: fd,
processData: false,
contentType: false,
success: function (data) {
if (data.success) {
alert(data.message);
}
else {
alert(data.message);
}
}
});
});
});
C# code:
private readonly IWebHostEnvironment _hostEnvironment;
//It needs to inject to the constructor
[HttpPost]
public IActionResult UploadFile(IFormFile fillle)
{
string wwwRoothPath = _hostEnvironment.WebRootPath;
if (fillle != null)
{
string fileName = "TempFile"; // Or: Guid.NewGuid().ToString();
var upload = Path.Combine(wwwRoothPath, #"images\Person"); //First make a folder Person in images route
var extension = Path.GetExtension(fillle.FileName);
using (var filestream = new FileStream(Path.Combine(upload, fileName + extension), FileMode.Create))
{
fillle.CopyTo(filestream);
}
return Json(new { success = true, message = "Image Uploaded Succesfully" });
}
else
{
return Json(new { success = false, message = "Error Uploading File" });
}
}
I hope this would be useful.

javascript File to post function with $http angular service and web-api

I want to upload javascript fileor basically transmit a javascript file to post function, on client side I've used angularjs $http service to send data to client as shown below:
$http({
method: "POST",
url: "/api/fileupload",
data: JSON.stringify(scope.c.model),//scope.c.model is javascript File
contentType: "application/json"
}).then(successResponse => {
this.scope["text"] = "Succes...";
}, errorResponse=> {
this.scope["text"] = "Error...";
});
and here is web-api controller
public void Post(HttpPostedFile file)
{
//do stuff...
}
file is null but scope.c.model is filled with correct data. if I change the Type of data is transmitted to an array (for example), everything is fine..It seems that the post method does not recognize the file.
seocnd below way also does not work, file.count is zero.
public void Post()//HttpPostedFile file)
{
var httpRequest = HttpContext.Current.Request;
if (httpRequest.Files.Count > 0)
{
//do stuff...
}
}
Here is a solution for the problem..with code below I am totally able to save any file locally or on server.
client side
scope.c.model is the type of Javascript FILE API. behind the scene is the model which is like this ng-model = model , c is controller and becasue this code is in link function of my directive I can access the model trough scope.c.model . model here could be any name.
as I want to read the File I should use FileReader.
scope.$watch('c.model', () => {
if (scope.c.model != null) {
var reader = new FileReader();
reader.onload = () => {
var base64 = reader.result.split("base64,")[1];
var file =
{
content: base64,
name: scope.c.model.name,
type: scope.c.model.type,
size: scope.c.model.size
};
var t = file.content;
$http({
method: "POST",
url: "/api/fileupload",//web-api contorller
data: file,// scope.c.model is javascript File
contentType: "application/octet-stream"
}).then(successResponse => {
this.scope["text"] = "Succes...";
}, errorResponse=> {
this.scope["text"] = "Error...";
});
};
reader.readAsDataURL(scope.c.model);
}
});
server side
public class File
{
public string Content;
public string Name;
public string Type;
public string Size;
}
public class FileUploadController : ApiController
{
public void Post(File file)
{
var bytes = Convert.FromBase64String(file.Content);
using (var imageFile = new FileStream(#"C:\fileupload\"+file.Name + ".jpg", FileMode.Create))
{
imageFile.Write(bytes, 0, bytes.Length);
imageFile.Flush();
}
}
}

Categories

Resources