I'm doing a simple c# generic handler that should receive a form post. Here's the form...
<form id="frmUploadImage" action="../Handlers/LocalImageUploadHandler.ashx" method="post" style="display: none">
<div>
<input style="display: none; margin-bottom: 20px" type="file" id="uploadImage" />
</div>
</form>
I have some code that, upon the click of a button invokes the click event of the input. When the input is loaded, the following is invoked (I can set a breakpoint and it gets here).
var jqxhr = $.post('../Handlers/LocalImageUploadHandler.ashx', $('#frmUploadImage').serialize())
.success(function() {
alert('worked');
})
.error(function() {
alert('failed');
});
It will show an alert for "failed". Server-side, it is calling this in the handler (I can verify that it is getting invoked by setting a breakpoint).
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "application/octet-stream";
var file = Convert.FromBase64String(context.Request.Form["uploadedFile"]);
//other stuff
}
What's interesting is that the context.Request.Form and context.Request.Files properties have no items in them, even though they are being sent. Nothing I've done has worked. I've tried posting with XHR, jQuery, etc. I've tried pulling the data out of the file upload control as a DataUrl and serializing it to a base64 encoded string and putting it in an ajax call. The handler will receive a post, but the data is being stripped.
You need to tryout following code to make it working
User Side Code
$('#btnUpload').click(function () {
var fileUpload = $("#FileUpload1").get(0);
var files = fileUpload.files;
var test = new FormData();
for (var i = 0; i < files.length; i++) {
test.append(files[i].name, files[i]);
}
$.ajax({
url: "LocalImageUploadHandler.ashx",
type: "POST",
contentType: false,
processData: false,
data: test,
// dataType: "json",
success: function (result) {
alert(result);
},
error: function (err) {
alert(err.statusText);
}
});
});
Server Side Code
public void ProcessRequest (HttpContext context) {
if (context.Request.Files.Count > 0)
{
HttpFileCollection files = context.Request.Files;
for (int i = 0; i < files.Count; i++)
{
HttpPostedFile file = files[i];
string fname;
if (HttpContext.Current.Request.Browser.Browser.ToUpper() == "IE" || HttpContext.Current.Request.Browser.Browser.ToUpper() == "INTERNETEXPLORER")
{
string[] testfiles = file.FileName.Split(new char[] { '\\' });
fname = testfiles[testfiles.Length - 1];
}
else
{
fname = file.FileName;
}
fname=Path.Combine(context.Server.MapPath("~/uploads/"), fname);
file.SaveAs(fname);
}
}
context.Response.ContentType = "text/plain";
context.Response.Write("File Uploaded Successfully!");
}
public bool IsReusable {
get {
return false;
}
}
Related
Problem: Can't parse File object to JSON string, when doing that only null values are gotten, while trying to send complex type to MVC controller.
I tried adding it into FormData object and passing it to controller, however, passing List of them was not successful, because it would either return an empty array or just plain null
model:
public class UploadedDocument
{
public HttpPostedFile File { get; set;}
public string DocumentId { get; set;}
public string DocumentType { get; set; }
}
controller:
[HttpPost]
[ActionName("UploadFile")]
public ActionResult Upload(IEnumerable<UploadedDocument> documents)
{
return View();
}
upload function:
var _documents = [];
for (var i = 0; i < arrayOfFiles.length; i++) {
var document = {
"File": arrayOfFiles[i].file,
"DocumentId": arrayOfFiles[i].documentId,
"DocumentType": arrayOfFiles[i].documentName
};
_documents.push(document);
}
$.ajax({
url: "#Url.Action("UploadFile", "Home")",
type: "POST",
data: {"documents":_documents}
});
}
});
Basically, I manage to handle single upload via ajax like below
Input Element
<input type="file" name="customerpicture" id="customerpicture" />
Formdata
function getFormData() {
var data = new FormData();
var files = $("#customerpicture").get(0).files;
if (files.length > 0) {
data.append("file", files[0]);
}
//data.append("Name", $("#name").val());
return data;
}
Ajax Method
$('#InsertCustomer').click(function () {
debugger;
var antiForgeryToken = $("input[name=__RequestVerificationToken]").val();
var url = '#Url.Action("Add_Customer", "Customer")';
$.ajax({
type: 'POST',
headers: { "__RequestVerificationToken": antiForgeryToken },
url: url,
contentType: false,
processData: false,
data: getFormData(),
success: function (res) {
$('#custinsertmodal').modal('hide');
$('#custinsertmodal').find("input,textarea,select")
.val('')
.end()
.find("input[type=checkbox], input[type=radio]")
.prop("checked", "")
.end();
bootbox.alert({ message: res.result });
}
});
});
Controller
[HttpPost, ValidateHeaderAntiForgeryToken]
public JsonResult Add_Customer()
{
var errMsg = string.Empty;
byte[] tmpImage;
try
{
//Customer Image Processing
var file = Request.Files.Get("file");
if (file != null && file.ContentLength > 0)
{
//Image Saving to Folder
UploadHelper.UploadFile(file);
//Image Saving to Database
tmpImage = new byte[file.ContentLength];
file.InputStream.Read(tmpImage, 0, file.ContentLength);
CustomerModel model = new CustomerModel
{
Signature = tmpImage
};
_setupRepo.CreateSignatory(model);
return Json(new { error = false, result = $"Customer was successfully created" }, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
errMsg = ex.Message.ToString();
return Json(new { error = true, result = errMsg }, JsonRequestBehavior.AllowGet);
}
}
If you want to specifically use an ajax call to upload files: you need to use a FormData object. Files must be sent up as a single item within the FormData object and therefore cannot be passed to your ActionResult as part of a list.
Assuming you have a dynamic amount of file inputs on your page with custom fields the user can fill in, your code could look like the following:
HTML / Javascript:
<form id="File_Form">
<input type="file" name="File_1" />
<input type="text" name="DocumentName_File_1" value="doc1" />
<input type="text" name="DocumentId_File_1" value="1" />
<input type="file" name="File_2" />
<input type="text" name="DocumentName_File_2" value="doc2" />
<input type="text" name="DocumentId_File_2" value="2" />
<button>Upload Files</button>
</form>
<script>
$("#File_Form").submit(function() {
var formData = new FormData(this);
$.ajax({
url: '#Url.Action("UploadFiles")',
type: 'POST',
data: formData,
processData: false,
contentType: false,
cache: false
});
return false;
});
</script>
C#:
[HttpPost]
public ActionResult UploadFiles() {
foreach (string fileName in Request.Files) {
HttpPostedFileWrapper file = Request.Files[fileName];
string documentName = Request.Form[$"DocumentName_{fileName}"]?.ToString();
string documentId = Request.Form[$"DocumentId_{fileName}"]?.ToString();
// Do things with your file here.
}
return new HttpStatusCodeResult(System.Net.HttpStatusCode.OK);
}
It may not automatically serialize into your model object, but you can still obtain the result you want with clever naming of your form elements.
Try this.
var _documents = [];
for (var i = 0; i < arrayOfFiles.length; i++) {
var document = {
"File": arrayOfFiles[i].file,
"DocumentId": arrayOfFiles[i].documentId,
"DocumentType": arrayOfFiles[i].documentName
};
_documents.push(document);
}
var formData = new FormData();
formData.append("documents", documents);
$.ajax({
url: "#Url.Action("UploadFile", "Home")",
type: "POST",
data: formData,
processData: false,
contentType: false,
});
}
});
Currently I am using JQuery AJAX and connect it to the Generic Handler (.ashx), inside the Generic Handler, I am doing the template for the Excel File that is going to save the computer (prompt save). i can achieve that while using the .aspx.cs , the reason I am doing from Generic Handler (.ashx), is because I don't know any way to hide the loading overlay after the dialog box for us to save to the computer is appear. (means the loading overlay just stick there). $(element).show() or $(element).hide() is to show or hide the loading overlay.
I am using EPPlus Library to generate the template for Excel File, however I don't know how to pass the object into client side and then prompt to save, it keeps gives me an error.
The problem I was encountered while using the Generic Handler is always gives me the parsererror message.
Here is the code that I am using:
JQuery AJAX:
var loading = $("#loading");
$("#template").click(function () {
loading.show();
$.ajax({
type: "POST",
url: "TemplateService.ashx?Month=" + $("#Month").val() + "&Year=" + $("#Year").val(),
data: {},
contentType: "application/json",
dataType: "json",
success: function (data) {
loading.hide();
console.log(data);
alert("Success");
},
error: function (xhr, text) {
loading.hide();
console.log(JSON.stringify(xhr.responseText));
console.log(JSON.stringify(text));
alert("There is a problem while processing your request");
}
});
});
Generic Handler (.ashx):
public class TemplateService : IHttpHandler, IRequiresSessionState
{
private int Month = 0;
private int Year = 0;
public void ProcessRequest(HttpContext context)
{
Month = Convert.ToInt32(context.Request.Params["Month"]);
Year = Convert.ToInt32(context.Request.Params["Year"]);
try
{
string MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(Month);
string fileName = string.Format("{0} - {1} {2}.xlsx", "Excel Template", MonthName, Year);
using (var package = new ExcelPackage())
{
package.Export();
using (var stream = new MemoryStream())
{
context.Response.Clear();
context.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
context.Response.AddHeader("Content-Disposition", string.Format("attachment; filename={0}", fileName));
package.SaveAs(stream);
stream.WriteTo(context.Response.OutputStream);
context.Response.Write(stream);
}
}
}
catch (Exception)
{
ProcessResponse(context, Response());
}
}
private string Response(bool isSuccess = false)
{
string status = (isSuccess) ? Constant.SUCCESS : Constant.FAILED;
return JsonConvert.SerializeObject(new
{
Status = status
});
}
private void ProcessResponse(HttpContext context, string response)
{
context.Response.Clear();
context.Response.ContentType = "application/json";
context.Response.Write(response);
}
public bool IsReusable
{
get
{
return false;
}
}
}
Export function:
public void Export(this ExcelPackage package)
{
try
{
package.Workbook.Worksheets.Add("Excel Template");
var workSheet = package.Workbook.Worksheets["Excel Template"];
var columnNames = new string[]
{
"First Column",
"Second Column",
"Third Column"
};
var headerRow = new List<string[]>()
{
columnNames
};
var cells = workSheet.Cells[1, 1, 1, 3];
cells.LoadFromArrays(headerRow);
cells.AutoFilter = true;
cells.AutoFitColumns();
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
HTML:
<form>
<asp:Button ID="Submission" runat="server" OnClick="Submission_Click" Text="Upload" />
<input type="button" id="Template" value="Template" />
</form>
<script type="text/javascript">
var loading = $("#loading");
$("form").submit(function () {
loading.show();
});
$("#template").click(function () {
loading.show();
$.ajax({
type: "POST",
url: "TemplateService.ashx?Month=" + $("#Month").val() + "&Year=" + $("#Year").val(),
data: {},
contentType: "application/json",
dataType: "json",
success: function (data) {
loading.hide();
console.log(data);
alert("Success");
},
error: function (xhr, text) {
loading.hide();
console.log(JSON.stringify(xhr.responseText));
console.log(JSON.stringify(text));
alert("There is a problem while processing your request");
}
});
});
</script>
Your answer much appreciated.
Thank you.
UploadHandler.ashx.cs
public class UploadHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
try
{
string dirFullPath = HttpContext.Current.Server.MapPath("~/Uploader/");
string[] files;
int numFiles;
files = System.IO.Directory.GetFiles(dirFullPath);
numFiles = files.Length;
numFiles = numFiles + 1;
string str_image = "";
foreach (string s in context.Request.Files)
{
HttpPostedFile file = context.Request.Files[s];
string fileName = file.FileName;
string fileExtension = file.ContentType;
if (!string.IsNullOrEmpty(fileName))
{
fileExtension = Path.GetExtension(fileName);
str_image = "MyPHOTO_" + numFiles.ToString() + fileExtension;
string pathToSave_100 = HttpContext.Current.Server.MapPath("~/Uploader/") + str_image;
file.SaveAs(pathToSave_100);
}
}
// database record update logic here ()
context.Response.Write(str_image);
}
catch (Exception ac)
{
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
JsCode
/Image Upload code
function sendFile(file) {
var formData = new FormData();
formData.append('file', $('#f_UploadImage')[0].files[0]);
$.ajax({
url: 'UploadHandler.ashx',
type: 'POST',
data: formData,
cache: false,
processData: false,
contentType: false,
success: function(result) {
if (result != 'error') {
var my_path = "Uploader/" + result;
$("#myUploadedImg").attr("src", my_path);
}
},
error: function(err) {
alert(err.statusText);
}
});
}
function callImgUploader() {
var _URL = window.URL || window.webkitURL;
$("#f_UploadImage").on('change', function() {
var file, img;
if ((file = this.files[0])) {
img = new Image();
img.onload = function() {
sendFile(file);
};
img.onerror = function() {
alert("Not a valid file:" + file.type);
};
img.src = _URL.createObjectURL(file);
}
});
}
Note: My Aspx page is different folder and Image Folder and UploadHandler.ashx.cs is route folder its wrong?
after run ajax request every time its give Not-Found error how can its fixed.
Thanks.
You didn't mentioned which upload control you are using , i'm assuming it is a server side and you need to access it as follows
Change
$('#f_UploadImage')
to
$('#<%= f_UploadImage.ClientID %>')
As you said
My Aspx page is different folder and Image Folder and UploadHandler.ashx.cs
You have to change
url: 'UploadHandler.ashx',
to
url: '/UploadHandler.ashx',
Otherwise it will try to search UploadHandler.ashx in the same folder as of ajax page and give 404.
I think the problem is with the contentType try
contentType: 'multipart/form-data',
Thanks for all of your valuable feedback,
now my problem has been fixed,
problem in UploadHandler.ashx setting
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="UploadHandler.ashx.cs" Inherits="Customer.UploadHandler" %>
inherits value are not matching my UploadHandler.ashx.cs namespace that's the problem, now its fixed.
Thanks everyone.
This form i want to send using ajax call with file, but it is not calling the c# function and not showing any error.
//form to submit
<form id="formfile" enctype="multipart/form-data">
<div class="modal-body">
<input type="file" id="fileupload1"/>
</div>
<div class="modal-footer">
<input type="submit" id="savefiles" class="buttonType" onclick="saveFile();return false" value="Save File" />
</div>
</form>
This ajax call is used to call c# code and also send file(.pdf)
//ajax call in .aspx file
function saveFile() {
debugger;
var file = $('input[type="file"]').val();
var exts = ['pdf', 'PDF'];
var formData = new FormData();
formData.append("imageFile", $('#fileupload1')[0].files[0]);
if (file) {
var extension = file.substring(file.lastIndexOf('.') + 1, file.length);
if ($.inArray(extension, exts) > -1)
{
//var formData = new FormData($('#form1')[0]);
var fileUpload = $('#fileupload1').get(0);
var files = fileUpload.files;
for (var i = 0; i < files.length; i++) {
formData.append(files[i].name, files[i]);
}
formData.append(fileUpload.name, fileUpload);
//alert('File Uploaded Successfully!');
}
else
{
alert('Invalid file, Only pdf files can be uploaded!!!');
}
}
//var str = "abc";
$.ajax({
url: "FileUploader.aspx/savepdfFiles",
type: "POST",
//cache: false,
contentType: false,
processData: false,
data: formData,
success: function (data) {
debugger;
},
error: function (data) {
debugger
}
});
}
It will come into success section also, but not calling following method.
//c# code
[webMethod]
public static void savepdfFiles()
{
//code
}
In ajax call it goes into success. but not calling savepdfFiles() method.
EDIT 24/08/2016
You can convert your blob data to base 64 and send it in JSON
var filesLength = 0;
function SaveFileToTemp() {
var file = $('input[type="file"]').val();
var exts = ['pdf', 'PDF'];
var pdfList = [];
// var pdfFile = { FileName: '', B64Data: '' };
if (file) {
var extension = file.substring(file.lastIndexOf('.') + 1, file.length);
if ($.inArray(extension, exts) > -1) {
var fileUpload = $('#fileupload1').get(0);
var files = fileUpload.files;
filesLength = files.length;
for (var i = 0; i < files.length; i++) {
var reader = new window.FileReader();
reader.myFileIndex = i;
reader.onloadend = function () {
base64data = reader.result;
pdfList.push({ FileName: files[this.myFileIndex].name, B64Data: base64data.substr(base64data.indexOf(',') + 1) });
console.log(base64data);
filesLength--;
if (filesLength === 0) {
$.ajax({
url: "/FileUploader.aspx/savepdfFiles",
type: "POST",
//cache: false,
contentType: "application/json; charset=utf-8",
dataType: "json",
data: JSON.stringify({ listPdf: pdfList }),
success: function (data) {
//alert('File Uploaded Successfully!');
debugger;
},
error: function (data) {
debugger
}
});
}
}
reader.readAsDataURL(files[i]);
}
}
else {
alert('Invalid file, Only pdf files can be uploaded!!!');
}
}
}
and in C#
[WebMethod]
public static void savepdfFiles(List<PdfFile> listPdf)
{
//code
foreach (var item in listPdf)
{
byte[] data = Convert.FromBase64String(item.B64Data);
System.IO.File.WriteAllBytes(string.Format("d:\\temp\\{0}",item.FileName), data) ;
}
}
this is my clas PdfFile for info
public class PdfFile
{
public string FileName { get; set; }
public string B64Data { get; set; }
}
Maybe you have to add this to your web.config to allow big json serialization :
<system.web.extensions>
<scripting>
<webServices>
<jsonSerialization maxJsonLength="10240000"/>
</webServices>
</scripting>
</system.web.extensions>
You have to set the appropiate value for maxJsonLength
Previous answer
I think I had this problem before from what i remember there is mechanism that doesn't allow you to this.
Maybe I'm wrong but I share you a link.
You will have to handle this with an ashx.
here is a built-in validation layer of protection that ASP.NET
enforces for both GET and POST based ASP.NET AJAX web methods, which
is that regardless of the HTTP verb being used, ASP.NET always
requires that the HTTP Content-Type header is set to the value
application/json. It this content type header is not sent, ASP.NET
AJAX will reject the request on the server.
I know this problem and it's easy to solve just you have to use Generic Handler.
Using generic handler with your AJAX call you can send any file to asp.net C# function.
In Generic Handler you have to write following c# code.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
namespace UploadFile
{
/// <summary>
/// Summary description for UploadFileHandler
/// </summary>
public class UploadFileHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
//context.Response.ContentType = "text/plain";
//context.Response.Write("Hello World");
if (context.Request.Files.Count > 0)
{
HttpFileCollection files = context.Request.Files;
for (int i = 0; i < files.Count; i++)
{
HttpPostedFile file = files[i];
string fname;
if (HttpContext.Current.Request.Browser.Browser.ToUpper() == "IE" || HttpContext.Current.Request.Browser.Browser.ToUpper() == "INTERNETEXPLORER")
{
string[] testfiles = file.FileName.Split(new char[] { '\\' });
fname = testfiles[testfiles.Length - 1];
}
else
{
fname = file.FileName;
}
fname = Path.Combine(context.Server.MapPath("~/Uploads/"), fname);
file.SaveAs(fname);
}
}
context.Response.ContentType = "text/plain";
context.Response.Write("File Uploaded Successfully!");
}
public bool IsReusable
{
get
{
return false;
}
}
}
}
Here is the example...
If you want Full Example Click here!
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