File upload with JQuery and ASP.NET Generic Handler - Is it possible? - javascript

I am trying to solve a small issue. I have built an entire web ASP.NET application using mostly client side (JQuery/JavaScript) code. I use generic handlers to do some lazy loading of data, as well as for auto-completes and the likes.
One of the requirements is that one page needs to be able to upload a file, as well as display meta information about the uploadead files.
I as wondering if there is a way to upload a file entirely out of JQuery/JavaScript. I researched a whole ot of plugins but they all rely on having a php backend.
My thought was to create a post:
$(function(){
$('#submit').live('click', function(event){
$.post('/SomeOtherHandler.ashx', //can be '/someotherpage.aspx'
{
filename: $('#fileUpload').val(),
timestamp: (new Date()).toString()
}, function(data){
//do something if the post is successful.
});
});
});
Would that work? I know that if you include the json object { filename: value, timestamp: value } it will show up in the HttpContext.Request.Params collection where I can read it without problems.
The problem is however that I don't know how this will work since the FileUpload html control only stores the file name in its value. Therefore I would be sending a string to my server with the filename, not an array of bytes.
Any thoughts on this would be greatly appreciated!

I'm using the uploadify plugin (http://www.uploadify.com/) - as Jeremy said, it's not in javascript - It's not possible. It's in flash. It's very easy to install.
$('#file_upload').uploadify({
'uploader' : '/uploadify/uploadify.swf',
'script' : '/uploadify/uploadify.ashx',
'cancelImg' : '/uploadify/cancel.png',
'folder' : '/uploads',
'auto' : true,
'fileExt': '*.xls;*.xlsx;*.csv',
'buttonText': 'Select your file',
'onError' : function (event,ID,fileObj,errorObj) {
alert(errorObj.type + ' Error: ' + errorObj.info);
},
'onComplete' : function(event, ID, fileObj, response, data)
{
var obj = jQuery.parseJSON(response);
if (obj.error != "" & obj.errror != null)
{
lblTable.html("error : " + obj.error);
}
else
{
lblTable.html(obj.table);
lblEditData.show();
lblTable.hide();
}
}
});
And on the uploadify.ashx :
public class uploadify : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
System.Web.HttpPostedFile file = context.Request.Files["Filedata"];
//Check extension
string extension = "";
try
{
extension = file.FileName.Split('.')[file.FileName.Split('.').Length - 1];
if (extension != "xls" & extension != "xlsx" & extension != "csv") throw new Exception("Error of the extension");
}
catch
{
context.Response.Write("{\"error\",\"Error with the extension of the file\"");
}
string linkFile = System.Web.HttpContext.Current.Server.MapPath("~") + "uploads" + "\\" + DateTime.Now.ToString("yyMMddHHmm") + APIReportPro.DocumentPDF.RandomString(4) + "." + extension;
file.SaveAs(linkFile);
...etc...
This is the nicest solution I found for asp.net

You have what boils down to three options when you are uploading files to a server. You can use native html file-upload features, Flash or Java. Javascript cannot upload a file to a server, it can only decorate the built in html functionality. With that said I can only assume you are attempting to mimic ajax like uploading functionality. If that is so there is a way to upload files using an iframe which will look like you are using ajax.
You will be creating a form
<form id="file_upload_form" method="post" enctype="multipart/form-data" action="upload.aspx">
<input name="file" id="file" size="27" type="file" /><br />
<input type="submit" name="action" value="Upload" /><br />
<iframe id="upload_target" name="upload_target" src="" style="width:0;height:0;border:0px solid #fff;"></iframe>
</form>
This form uses the iframe to post the file, which will cause the main page to never refresh. You can hook up your jquery to process the response the iframe returns and handle user information.
If this is not the part of the equation you were looking for please feel free to comment and clarify what it is you are looking to accomplish.

If you can dictate which browsers your app is accessed through (e.g. it's an internal business app), it's worth checking out the new File API which is part of the "HTML5" stack of technologies that are beginning to show up in the latest browsers. This gives you direct access to files via clientside Javascript without the need to post the file to the server first.
If your app is public-facing then you can still use the File API, but you will need to check for support for it in your code and apply some kind of fallback mechanism (such as Uploadify) for those with older browsers.
You can read more about the File API here and here amongst other places.

I'm pretty sure it's not possible; if it is then it's a big security hole - Javascript should not be able to get bytes from the user's hard drive.
So you're stuck using the native input type=file or using pre-existing desktop bytes, like Flash. Several popular uploaders use this method...my favorite is Uploadify. Take a look at that, and see if that doesn't suit your needs.
HTH.

I have implemented an ASP.NET Handler for uploading file using Valums ajax Upload control. You can check solution here. You can also upload large file. This handler supports IE, FF and Chrome browser. You can also drag drop multiple files from FF and Chrome (HTML 5)
http://ciintelligence.blogspot.com/2011/05/aspnet-server-side-handler-for-valums.html

Using jquery you can do something like:
<input type="file" name="file" id="file1" runat="server" />
$("#<%=file1.ClientID%>").change(function () {
//Do stuff
$(this).upload('youHandler.ashx', function (res) {
//do stuff on success
}
}
Now on yourHandler.ashx you can do something like that:
public void ProcessRequest(HttpContext context)
{
if (context.Request.Files.Count > 0)
{
var fileCount = context.Request.Files.Count;
var fileStram = var file = context.Request.Files[0].InputStream;
//Do whatever you want
}
}

Related

Upload file to Google Drive with React and Google App script

I am trying to upload file with Google App script and React.
Google Script:
function uploadArquivoParaDrive(base64Data, nomeArq, idPasta) {
try{
var splitBase = base64Data.split(','),
type = splitBase[0].split(';')[0].replace('data:','');
var byteCharacters = Utilities.base64Decode(splitBase[1]);
var ss = Utilities.newBlob(byteCharacters, type);
ss.setName(nomeArq);
var file = DriveApp.getFolderById(idPasta).createFile(ss);
return file.getName();
}catch(e){
return 'Erro: ' + e.toString();
}
}
I can run this ant it works:
function uploadFile() {
var image = UrlFetchApp.fetch('url to some image').getBlob();
var file = {
title: 'google_logo.png',
mimeType: 'image/png'
};
file = Drive.Files.insert(file, image);
Logger.log('ID: %s, File size (bytes): %s', file.id, file.fileSize);
}
This is React script:
onSubmit = (e) => {
e.preventDefault();
axios.get(url, {...this.state}, {
headers: {
'Content-Type': 'multipart/form-data'
}
}, (response) => {
console.log(response);
})
};
setFile = (event) => {
console.log(event.target.files)
this.setState({file: event.target.files[0]});
};
render() {
return (
<form>
<input type="file" id="file" onChange={this.setFile} />
<button onClick={this.onSubmit}>ADD</button>
</form>
)
}
I am trying with POST, but I am getting 400 response. I know that this can't be GET request, but and with it, I am getting - 200 with no response.
I can insert rows in sheets, but I want to upload files to Google Drive with Google App Scripts.
I know that there is a way to upload files via Google Scripts and React, because, there is a way without React (google.script.run).
Here are two different approaches that are used in mixed mode. It's unacceptable in some contexts.
Let's say softly 'React is a dummy'. This is an add-on that you should always avoid when somewhat comes to something that you depend on, but you cannot change. See what SOLID is.
Below it is always assumed that you are working in a browser. Your web-pages are hosted in the web application of the Google Apps Script.
The first approach. Using XMLHttpRequests
On client side you have to use XMLHttpRequests call from your browser.
On server side you have to use doGet doPost reserved functions. Always transfer data in a clear and simple format. This will save time searching for errors.
Example https://stackoverflow.com/a/11300412/1393023
The second approach. Using Client-side API
On client side you have to use google.script.run call from your browser.
On server side you have to use your functions. Always transfer data in a clear and simple format. This will save time searching for errors.
Example https://stackoverflow.com/a/15790713/1393023
Consequence
Your example has signs of mixing approaches. Unfortunately, it cannot be quickly debugged.
There is no reason that React is causing the problem. If so, then your architecture is incorrect.
If you want to use axios, then you need to consider the first approach.
If you want to use google.script.run then you need to catch onSubmit then you need to call an interface that implement google.script.run. Usually asynchronously, since the last call will still be completed with a callback.

Fill HTML5 Input Fields with Uploaded XML File

I built an HTML5/JS web application that performs fairly complicated mathematical calculations based on user-provided data. The application works by having several different input fields where users manually type in the information, then submit it for processing. Much of the information that the users input will not change very often (but often enough where hard-coding it would not be economical), and I was interested in seeing if there was a way to allow users to upload XML files with all of the required data custom tailored to each user. The fields would be filled automatically. The user would change their particular XML file as needed to reflect new values prior to getting new computations. Just as an aside, anything server-side is not an option.
Is it possible using HTML5/JS to upload an XML file, read the file contents, and fill input fields automatically?
As I mentioned in my comment, you can accomplish this task without any server-side intervention, provided the browser has proper File API and FileReader support.
Let's say you have a file input element, where your user will select one of these XML files:
<input id="fileChooser" type="file">
Now, you can access whatever file the user selects, grab the associated text/XML, parse it, and assign the values to text input fields on your page. Your code would look something like this:
var fileChooser = document.getElementById('fileChooser');
function parseTextAsXml(text) {
var parser = new DOMParser(),
xmlDom = parser.parseFromString(text, "text/xml");
//now, extract items from xmlDom and assign to appropriate text input fields
}
function waitForTextReadComplete(reader) {
reader.onloadend = function(event) {
var text = event.target.result;
parseTextAsXml(text);
}
}
function handleFileSelection() {
var file = fileChooser.files[0],
reader = new FileReader();
waitForTextReadComplete(reader);
reader.readAsText(file);
}
fileChooser.addEventListener('change', handleFileSelection, false);
Sounds like an ideal candidate for a Saxon-CE application.
However, I don't think you can make it work without any kind of server support. You talk of "uploading" files; that means uploading to the server, and you need to do something on the server to make that possible. It's not possible for a browser application to interact with filestore on the local machine unless you ask your users to turn off security settings which would be unwise (and I don't even know if that's possible any more).
you must use some server-side code anyway, because JS doesn't allow to upload file and even access it on users computer
so you can not get the contents of this file if not uploading it to server (upd: actually you can do it, so this is only a suggestion)
but you can do it in very simple way e.g. submit a form with file input
<form enctype="multipart/form-data" action="/path/to/script" method="post">
<input name="myFile" type="file" />
</form>
to send it using ajax and get the contents of it as a response from the easy script like this:
<?php
if (!$_FILES["myFile"]["error"]) {
header("Content-Type: text/xml");
echo file_get_contents($_FILES["myFile"]["tmp_name"]);
}
?>
I'm using php, but I'm sure it's not a problem to perform it in another language. Of course I know that file uploading is supported only by XHR2 in major browsers, but as far as you are asking about HTML5 this solution will work.
Next step is to add success handler to your ajax request
success: function(data) {
// and parse it
if (window.DOMParser)
{
parser=new DOMParser();
xmlDoc=parser.parseFromString(data,"text/xml");
}
else // Internet Explorer
{
xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async=false;
xmlDoc.loadXML(data);
}
}
Great tutorial here. Now you can access xml contents using xmlDoc var like simple DOM document.

How can I get an ASP.NET Session variable into a javascript file?

I am refactoring a legacy web app. This app has a is using the onload event inside the body tag (On the Master page) to run this javascript script. Note this script tag is after the form element in the doc. I know the syntax looks hideous (or Visual Studio at least tells it is by the squiggles), but I'll be darned, the thing DOES indeed work.
function DisplayPDF()
{
var strPDF
strPDF = "<%=SESSION("PDF")%>";
if (strPDF.length != 0)
{
window.open(strPDF);
<%Session("PDF") = ""%>
}
}
My question is I'm trying to develop a more elegant solution. I have ASP.NET ajax and jQuery both available to me. I wrote a tiny asp.net ajax component that I want to use to handle this.
Type.registerNamespace("ck");
ck.pdfOpener = function() {
ck.pdfOpener.initializeBase(this);
}
ck.pdfOpener.prototype = {
initialize: function() {
ck.pdfOpener.callBaseMethod(this, 'initialize');
},
dispose: function() {
ck.pdfOpener.callBaseMethod(this, 'dispose');
},
openPDF: function(){
//HOW CAN I RETRIEVE A SESSION VARIABLE HERE???
}
}
ck.ClientControl.registerClass('ck.pdfOpener', Sys.Component);
if (typeof(Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();
Can/Should I be doing it this way? Or should I create a WebService that returns said variable. Thanks for any advice.
Cheers,
~ck in San Diego
Use the Page.ClientScript.RegisterClientScriptBlock(typeof(YOURPAGECLASS), "KEY", "ACTUALJSCODE"); in your code behind (i.e. the Page_Load event handler)
Alternatlively, you could send the PDF file directly from the asp.net page instead of within the client script.
string pdfFile = Session("PDF");
if (!string.IsNullOrEmpty(pdfFile))
{
Session.Remove("PDF");
Response.ContentType = "application/pdf";
FileInfo fi = new FileInfo(pdfFile);
Response.AddHeader("Content-Disposition", "attachment; filename=\"" + Path.GetFileName(pdfFile) + "\"");
Response.AddHeader("Content-Length", fi.Length.ToString());
Response.WriteFile(pdfFile);
Response.Flush();
return;
}
A simple way to do this would be as you said simply make an Ajax call to a page method, MVC action, HttpHandler or web service that returns the required value from the session. The bigger question here is why you are storing the path to a PDF file in your session state?

Is robust javascript-only upload of file possible

I want a robust way to upload a file. That means that I want to be able to handle interruptions, error and pauses.
So my question is: Is something like the following possible using javascript only on the client.
If so I would like pointers to libraries, tutorials, books or implementations.
If not I would like an explanation to why it's not possible.
Scenario:
Open a large file
Split it into parts
For each part I would like to
Create checksum and append to data
Post data to server (the server would check if data uploaded correctly)
Check a web page on server to see if upload is ok
If yes upload next part if no retry
Assume all posts to server is accompanied by relevant meta data (sessionid and whatnot).
No. You can, through a certain amount of hackery, begin a file upload with AJAX, in which case you'll be able to tell when it's finished uploading. That's it.
JavaScript does not have any direct access to files on the visitor's computer for security reasons. The most you'll be able to see from within your script is the filename.
Firefox 3.5 adds support for DOM progress event monitoring of XMLHttpRequest transfers which allow you to keep track of at least upload status as well as completion and cancellation of uploads.
It's also possible to simulate progress tracking with iframes in clients that don't support this newer XMLHTTPRequest additions.
For an example of script that does just this, take a look at NoSWFUpload. I've been using it succesfully for about few months now.
It's possible in Firefox 3 to open a local file as chosen by a file upload field and read it into a JavaScript variable using the field's files array. That would allow you to do your own chunking, hashing and sending by AJAX.
There is some talk of getting something like this standardised by W3, but for the immediate future no other browser supports this.
Yes. Please look at the following file -
function Upload() {
var self = this;
this.btnUpload;
this.frmUpload;
this.inputFile;
this.divUploadArea;
this.upload = function(event, target) {
event.stopPropagation();
if (!$('.upload-button').length) {
return false;
}
if (!$('.form').length) {
return false;
}
self.btnUpload = target;
self.frmUpload = $(self.btnUpload).parents('form:first');
self.inputFile = $(self.btnUpload).prev('.upload-input');
self.divUploadArea = $(self.btnUpload).next('.uploaded-area');
var target = $(self.frmUpload).attr('target');
var action = $(self.frmUpload).attr('action');
$(self.frmUpload).attr('target', 'upload_target'); //change the form's target to the iframe's id
$(self.frmUpload).attr('action', '/trnUpload/upload'); //change the form's action to the upload iframe function page
$(self.frmUpload).parent("div").prepend(self.iframe);
$('#upload_target').load(function(event){
if (!$("#upload_target").contents().find('.upload-success:first').length) {
$('#upload_target').remove();
return false;
} else if($("#upload_target").contents().find('.upload-success:first') == 'false') {
$('#upload_target').remove();
return false;
}
var fid = $("#upload_target").contents().find('.fid:first').html();
var filename = $("#upload_target").contents().find('.filename:first').html();
var filetype = $("#upload_target").contents().find('.filetype:first').html();
var filesize = $("#upload_target").contents().find('.filesize:first').html();
$(self.frmUpload).attr('target', target); //change the form's target to the iframe's id
$(self.frmUpload).attr('action', action); //change the form's
$('#upload_target').remove();
self.insertUploadLink(fid, filename, filetype, filesize);
});
};
this.iframe = '' +
'false' +
'';
this.insertUploadLink = function (fid, filename, filetype, filesize) {
$('#upload-value').attr('value', fid);
}
}
$(document).ready(event) {
var myupload = new Upload();
myupload.upload(event, event.target);
}
With also using PHP's APC to query the status of how much of the file has been uploaded, you can do a progress bar with a periodical updater (I would use jQuery, which the above class requires also). You can use PHP to output both the periodical results, and the results of the upload in the iframe that is temporarily created.
This is hackish. You will need to spend a lot of time to get it to work. You will need admin access to whatever server you want to run it on so you can install APC. You will also need to setup the HTML form to correspond to the js Upload class. A reference on how to do this can be found here http://www.ultramegatech.com/blog/2008/12/creating-upload-progress-bar-php/

Using jQuery, Restricting File Size Before Uploading

On PHP, they have a way to restrict file size AFTER uploading, but not BEFORE uploading. I use the Malsup jQuery Form Plugin for my form posting, and it supports image file posting.
I was wondering if perhaps there's a restriction where I can set how many bytes can pass through that AJAX stream up to the server? That could permit me to check that file size and return an error if the file is too big.
By doing this on the client side, it blocks those newbies who take a 10MB photo shot from their Pentax and try to upload that.
This is a copy from my answers in a very similar question: How to check file input size with jQuery?
You actually don't have access to the filesystem (for example reading and writing local files). However, due to the HTML5 File API specification, there are some file properties that you do have access to, and the file size is one of them.
For this HTML:
<input type="file" id="myFile" />
try the following:
//binds to onchange event of your input field
$('#myFile').bind('change', function() {
//this.files[0].size gets the size of your file.
alert(this.files[0].size);
});
As it is a part of the HTML5 specification, it will only work for modern browsers (v10 required for IE) and I added here more details and links about other file information you should know: http://felipe.sabino.me/javascript/2012/01/30/javascipt-checking-the-file-size/
Old browsers support
Be aware that old browsers will return a null value for the previous this.files call, so accessing this.files[0] will raise an exception and you should check for File API support before using it
I don't think it's possible unless you use a flash, activex or java uploader.
For security reasons ajax / javascript isn't allowed to access the file stream or file properties before or during upload.
I tried it this way and I am getting the results in IE*, and Mozilla 3.6.16, didnt check in older versions.
<img id="myImage" src="" style="display:none;"><br>
<button onclick="findSize();">Image Size</button>
<input type="file" id="loadfile" />
<input type="button" value="find size" onclick="findSize()" />
<script type="text/javascript">
function findSize() {
if ( $.browser.msie ) {
var a = document.getElementById('loadfile').value;
$('#myImage').attr('src',a);
var imgbytes = document.getElementById('myImage').size;
var imgkbytes = Math.round(parseInt(imgbytes)/1024);
alert(imgkbytes+' KB');
}else {
var fileInput = $("#loadfile")[0];
var imgbytes = fileInput.files[0].fileSize; // Size returned in bytes.
var imgkbytes = Math.round(parseInt(imgbytes)/1024);
alert(imgkbytes+' KB');
}
}
</script>
Add Jquery library also.
I encountered the same issue. You have to use ActiveX or Flash (or Java). The good thing is that it doesn't have to be invasive. I have a simple ActiveX method that will return the size of the to-be-uploaded file.
If you go with Flash, you can even do some fancy js/css to cusomize the uploading experience--only using Flash (as a 1x1 "movie") to access it's file uploading features.
I found that Apache2 (you might want to also check Apache 1.5) has a way to restrict this before uploading by dropping this in your .htaccess file:
LimitRequestBody 2097152
This restricts it to 2 megabytes (2 * 1024 * 1024) on file upload (if I did my byte math properly).
Note when you do this, the Apache error log will generate this entry when you exceed this limit on a form post or get request:
Requested content-length of 4000107 is larger than the configured limit of 2097152
And it will also display this message back in the web browser:
<h1>Request Entity Too Large</h1>
So, if you're doing AJAX form posts with something like the Malsup jQuery Form Plugin, you could trap for the H1 response like this and show an error result.
By the way, the error number returned is 413. So, you could use a directive in your .htaccess file like...
Redirect 413 413.html
...and provide a more graceful error result back.
$(".jq_fileUploader").change(function () {
var fileSize = this.files[0];
var sizeInMb = fileSize.size/1024;
var sizeLimit= 1024*10;
if (sizeInMb > sizeLimit) {
}
else {
}
});
Try below code:
var sizeInKB = input.files[0].size/1024; //Normally files are in bytes but for KB divide by 1024 and so on
var sizeLimit= 30;
if (sizeInKB >= sizeLimit) {
alert("Max file size 30KB");
return false;
}
Like others have said, it's not possible with just JavaScript due to the security model of such.
If you are able to, I'd recommend one of the below solutions..both of which use a flash component for the client side validations; however, are wired up using Javascript/jQuery. Both work very well and can be used with any server-side tech.
http://www.uploadify.com/
http://swfupload.org/
It's not possible to verify the image size, width or height on the client side. You need to have this file uploaded on the server and use PHP to verify all this info.
PHP has special functions like: getimagesize()
list($width, $height, $type, $attr) = getimagesize("img/flag.jpg");
echo "<img src=\"img/flag.jpg\" $attr alt=\"getimagesize() example\" />";

Categories

Resources