I am newish to events, and new to flash. I have managed to get files uploaded to my folder using Plupload. I am using a generic handler (New to that too!)
Here's my code:
<style type="text/css">
#import url(/plupload/js/jquery.plupload.queue/css/jquery.plupload.queue.css);
</style>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
<script type="text/javascript" src="http://bp.yahooapis.com/2.4.21/browserplus-min.js"></script>
<script type="text/javascript" src="/plupload/js/plupload.full.js"></script>
<script type="text/javascript" src="/plupload/js/jquery.plupload.queue/jquery.plupload.queue.js"></script>
<script type="text/javascript">
$(function () {
$("#uploader").pluploadQueue({
// General settings
runtimes: 'gears,flash,silverlight,browserplus,html5',
url: '/uploader.ashx',
max_file_size: '10mb',
chunk_size: '1mb',
unique_names: true,
preinit: attachCallbacks,
// Resize images on clientside if we can
//resize: { width: 320, height: 240, quality: 90 },
// Specify what files to browse for
filters: [
{ title: "Image files", extensions: "jpg,gif,png" },
{ title: "Zip files", extensions: "zip" }
],
// Flash settings
flash_swf_url: '/plupload/js/plupload.flash.swf',
// Silverlight settings
silverlight_xap_url: '/plupload/js/plupload.silverlight.xap'
});
// Client side form validation
$('form').submit(function (e) {
var uploader = $('#uploader').pluploadQueue();
// Validate number of uploaded files
if (uploader.total.uploaded == 0) {
// Files in queue upload them first
if (uploader.files.length > 0) {
// When all files are uploaded submit form
uploader.bind('UploadProgress', function () {
if (uploader.total.uploaded == uploader.files.length)
$('form').submit();
});
uploader.start();
} else
alert('You must at least upload one file.');
e.preventDefault();
}
function attachCallbacks(Uploader) {
Uploader.bind('FileUploaded', function(Up, File, Response) {
if ((Uploader.total.uploaded + 1) == Uploader.files.length) {
window.location = '/display.aspx';
}
});
}
});
And then in my code, my handler:
public class uploader : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
int chunk = context.Request["chunk"] != null ? int.Parse(context.Request["chunk"]) : 0;
string fileName = context.Request["name"] ?? string.Empty;
HttpPostedFile fileUpload = context.Request.Files[0];
var uploadPath = context.Server.MapPath(GlobalVariables.UploadPath);
using (
var fs = new FileStream(Path.Combine(uploadPath, fileName),
chunk == 0 ? FileMode.Create : FileMode.Append))
{
var buffer = new byte[fileUpload.InputStream.Length];
fileUpload.InputStream.Read(buffer, 0, buffer.Length);
fs.Write(buffer, 0, buffer.Length);
}
context.Response.ContentType = "text/plain";
context.Response.Write("Success");
}
public bool IsReusable
{
get { return false; }
}
}
This is working 100%
Problem is, when it complete the upload, nothing happens. It displayed the fact that the files were uploaded.
I need to somehow tell a new method to fire. That is, I need to process the uploaded files. Move them to the right folder ... name them better ... add them to a database, and maybe redirect to the display screen.
So, I need the flash control to tell my code to do something (An event) and also, tell my code which files it can now process (The list of files uploaded).
Is this possible?
Edit: I added the attachCallbacks method, and it's attached. It now redirects to a page, but I need to it somehow send the list of files uploaded to a method (generic handler maybe?) and process the files. How do I redirect to a method?
........
uploader.bind('UploadProgress', function () {
if (uploader.total.uploaded == uploader.files.length)
$('form').submit();
});
uploader.bind('UploadComplete', function (up, files) {
//files are uploaded, call script for each file...etc
});
uploader.start();
..........
Related
I'm a little lost on what should I do. I'm trying to upload a file along with its form data in one click, but I can't get the file. I tried to check the file in client and it's okay, but when receiving the file in the Controller, it's empty.
Problem
How do I upload the file along its formData using jQuery?
View
Assuming the other fields
<form id="_RegisterProduct" enctype="multipart/form-data">
<div>
<label>Product Description</label>
<textarea id="product_description" name="_product_description"></textarea>
<input type="file"
id="product_file"
name="product_file"
class="dropify" />
</div>
<button type="submit" id="snippet_new_save">Register Product</button>
</form>
<script>
$(function() {
rules: {
text: { required: true, minlength: 5 },
number: { required: true, minlength: 1 }
},
submitHandler: function (form) {
var fileUpload = $("#product_file").val();
var formData = $("#_RegisterForm").serialize();
var url = "#Url.Action("RegisterProduct", "Product")";
$.get(url, { fileUpload: fileUpload, formData }, function (e) {
if (e >= 1) {
console.log("success");
} else {
console.log("error");
}
});
}
})
</script>
Controller
public string RegisterProduct(HttpPostedFileBase fileUpload, AB_ProductModel formData)
{
var data = "";
using (var con = new SqlConnection(Conn.MyConn()))
{
var path = Server.MapPath("~/Content/uploads/products");
var Extension = "";
var fileName = "";
try
{
if(fileUpload.ContentLength > 0)
{
Extension = Path.GetExtension(fileUpload.FileName);
fileName = Path.GetFileName(fileUpload.FileName);
var com = new SqlCommand("dbo.sp_some_stored_procedure_for_saving_data",
con);
con.Open
data = Convert.ToString(com.ExecuteScalar());
var file_path = Path.Combine(path, data + Extension);
fileUpload.SaveAs(file_path);
}
}
catch (Exception ex)
{
data = ex.Message;
}
// data returns id if success or error message
}
return data;
}
Why serialize the form? This method creates a string that can be sent over to the server, but that is not what you want to do... In case of a file upload; see .serialize() function description here.
FormData type automatically manages the enctype for your forms (see here on MDN), so you can omit that—although you should consider using it, because it helps other members on the team understand the intent. If you want to use plain jQuery, you can simply attach the formData variable to the data field of the $.ajax call. See like here,
/*
* i know id-based selection should only have 1 element,
* otherwise HTML is invalid for containing multiple elements
* with the same id, but this is the exact code i used back then, so using it again.
**/
var formData = new FormData($('#form')[0]);
$.ajax({
type: 'POST',
processData: false,
contentType: false,
data: formData,
success: function (data) {
// The file was uploaded successfully...
$('.result').text('File was uploaded.');
},
error: function (data) {
// there was an error.
$('.result').text('Whoops! There was an error in the request.');
}
});
This of course requires that your HTML DOM contains these elements—I used the code I wrote for my article quite a few years back. Secondly, for my other part of the feature, I used Request.Files to capture the files that might have been uploaded with the request.
files = Request.Files.Count;
if(files > 0) {
// Files are sent!
for (int i = 0; i < files; i++) {
var file = Request.Files[i];
// Got the image...
string fileName = Path.GetFileName(file.FileName);
// Save the file...
file.SaveAs(Server.MapPath("~/" + fileName));
}
}
This way, I uploaded the files using jQuery and FormData.
You can check out the complete article I posted here, Uploading the files — HTML5 and jQuery Way!
Oh, and do not forget the suggestion made in the comment,
using (var com = new SqlCommand("dbo.sp_some_stored_procedure_for_saving_data", con))
{
con.Open(); // missed call?
data = Convert.ToString(com.ExecuteScalar());
// although, using should close here!
var file_path = Path.Combine(path, data + Extension);
fileUpload.SaveAs(file_path);
}
So, this was pretty much how you can do this.
HTML:
<a href="mysite.com/uploads/asd4a4d5a.pdf" download="foo.pdf">
Uploads get a unique file name while there real name is kept in database. I want to realize a simple file download. But the code above redirects to / because of:
$routeProvider.otherwise({
redirectTo: '/',
controller: MainController
});
I tried with
$scope.download = function(resource){
window.open(resource);
}
but this just opens the file in a new window.
Any ideas how to enable a real download for any file type?
https://docs.angularjs.org/guide/$location#html-link-rewriting
In cases like the following, links are not rewritten; instead, the
browser will perform a full page reload to the original link.
Links that contain target element Example:
link
Absolute links that go to a different domain Example:
link
Links starting with '/' that lead to a different base path when base is defined Example:
link
So in your case, you should add a target attribute like so...
<a target="_self" href="example.com/uploads/asd4a4d5a.pdf" download="foo.pdf">
We also had to develop a solution which would even work with APIs requiring authentication (see this article)
Using AngularJS in a nutshell here is how we did it:
Step 1: Create a dedicated directive
// jQuery needed, uses Bootstrap classes, adjust the path of templateUrl
app.directive('pdfDownload', function() {
return {
restrict: 'E',
templateUrl: '/path/to/pdfDownload.tpl.html',
scope: true,
link: function(scope, element, attr) {
var anchor = element.children()[0];
// When the download starts, disable the link
scope.$on('download-start', function() {
$(anchor).attr('disabled', 'disabled');
});
// When the download finishes, attach the data to the link. Enable the link and change its appearance.
scope.$on('downloaded', function(event, data) {
$(anchor).attr({
href: 'data:application/pdf;base64,' + data,
download: attr.filename
})
.removeAttr('disabled')
.text('Save')
.removeClass('btn-primary')
.addClass('btn-success');
// Also overwrite the download pdf function to do nothing.
scope.downloadPdf = function() {
};
});
},
controller: ['$scope', '$attrs', '$http', function($scope, $attrs, $http) {
$scope.downloadPdf = function() {
$scope.$emit('download-start');
$http.get($attrs.url).then(function(response) {
$scope.$emit('downloaded', response.data);
});
};
}]
});
Step 2: Create a template
Download
Step 3: Use it
<pdf-download url="/some/path/to/a.pdf" filename="my-awesome-pdf"></pdf-download>
This will render a blue button. When clicked, a PDF will be downloaded (Caution: the backend has to deliver the PDF in Base64 encoding!) and put into the href. The button turns green and switches the text to Save. The user can click again and will be presented with a standard download file dialog for the file my-awesome.pdf.
Our example uses PDF files, but apparently you could provide any binary format given it's properly encoded.
If you need a directive more advanced, I recomend the solution that I implemnted, correctly tested on Internet Explorer 11, Chrome and FireFox.
I hope it, will be helpfull.
HTML :
<i class="fa fa-file-excel-o"></i>
DIRECTIVE :
directive('fileDownload',function(){
return{
restrict:'A',
scope:{
fileDownload:'=',
fileName:'=',
},
link:function(scope,elem,atrs){
scope.$watch('fileDownload',function(newValue, oldValue){
if(newValue!=undefined && newValue!=null){
console.debug('Downloading a new file');
var isFirefox = typeof InstallTrigger !== 'undefined';
var isSafari = Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0;
var isIE = /*#cc_on!#*/false || !!document.documentMode;
var isEdge = !isIE && !!window.StyleMedia;
var isChrome = !!window.chrome && !!window.chrome.webstore;
var isOpera = (!!window.opr && !!opr.addons) || !!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0;
var isBlink = (isChrome || isOpera) && !!window.CSS;
if(isFirefox || isIE || isChrome){
if(isChrome){
console.log('Manage Google Chrome download');
var url = window.URL || window.webkitURL;
var fileURL = url.createObjectURL(scope.fileDownload);
var downloadLink = angular.element('<a></a>');//create a new <a> tag element
downloadLink.attr('href',fileURL);
downloadLink.attr('download',scope.fileName);
downloadLink.attr('target','_self');
downloadLink[0].click();//call click function
url.revokeObjectURL(fileURL);//revoke the object from URL
}
if(isIE){
console.log('Manage IE download>10');
window.navigator.msSaveOrOpenBlob(scope.fileDownload,scope.fileName);
}
if(isFirefox){
console.log('Manage Mozilla Firefox download');
var url = window.URL || window.webkitURL;
var fileURL = url.createObjectURL(scope.fileDownload);
var a=elem[0];//recover the <a> tag from directive
a.href=fileURL;
a.download=scope.fileName;
a.target='_self';
a.click();//we call click function
}
}else{
alert('SORRY YOUR BROWSER IS NOT COMPATIBLE');
}
}
});
}
}
})
IN CONTROLLER:
$scope.myBlobObject=undefined;
$scope.getFile=function(){
console.log('download started, you can show a wating animation');
serviceAsPromise.getStream({param1:'data1',param1:'data2', ...})
.then(function(data){//is important that the data was returned as Aray Buffer
console.log('Stream download complete, stop animation!');
$scope.myBlobObject=new Blob([data],{ type:'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'});
},function(fail){
console.log('Download Error, stop animation and show error message');
$scope.myBlobObject=[];
});
};
IN SERVICE:
function getStream(params){
console.log("RUNNING");
var deferred = $q.defer();
$http({
url:'../downloadURL/',
method:"PUT",//you can use also GET or POST
data:params,
headers:{'Content-type': 'application/json'},
responseType : 'arraybuffer',//THIS IS IMPORTANT
})
.success(function (data) {
console.debug("SUCCESS");
deferred.resolve(data);
}).error(function (data) {
console.error("ERROR");
deferred.reject(data);
});
return deferred.promise;
};
BACKEND(on SPRING):
#RequestMapping(value = "/downloadURL/", method = RequestMethod.PUT)
public void downloadExcel(HttpServletResponse response,
#RequestBody Map<String,String> spParams
) throws IOException {
OutputStream outStream=null;
outStream = response.getOutputStream();//is important manage the exceptions here
ObjectThatWritesOnOutputStream myWriter= new ObjectThatWritesOnOutputStream();// note that this object doesn exist on JAVA,
ObjectThatWritesOnOutputStream.write(outStream);//you can configure more things here
outStream.flush();
return;
}
in template
<md-button class="md-fab md-mini md-warn md-ink-ripple" ng-click="export()" aria-label="Export">
<md-icon class="material-icons" alt="Export" title="Export" aria-label="Export">
system_update_alt
</md-icon></md-button>
in controller
$scope.export = function(){ $window.location.href = $scope.export; };
I'm trying to allow users to upload an image to my site. I found a demo but it is written in PHP. I am using CSHTML in Webmatrix, and it doesn't seem to be compatible with the PHP file. Does anyone have any resources, recommendations, or links to information for writing a similar code as below but in a compatible format to Webmatrix/ASP.NET? Also, is there a way to rename the file when it's uploaded and save it to a certain location?
Are there any security precautions I should take when allowing users to upload to the site?
$fn = (isset($_SERVER['HTTP_X_FILENAME']) ? $_SERVER['HTTP_X_FILENAME'] : false);
if ($fn) {
// AJAX call
file_put_contents(
'uploads/' . $fn,
file_get_contents('php://input')
);
echo "$fn uploaded";
exit();
}
else {
// form submit
$files = $_FILES['fileselect'];
foreach ($files['error'] as $id => $err) {
if ($err == UPLOAD_ERR_OK) {
$fn = $files['name'][$id];
move_uploaded_file(
$files['tmp_name'][$id],
'uploads/' . $fn
);
echo "<p>File $fn uploaded.</p>";
}
}
}
use fileupload.js
<script src="#Url.Content("/Scripts/jquery.fileupload.js")" type="text/javascript"></script>
<input type="file" name="resume" onchange="onChangeResume()" id="txtImageUpload" style="width: 76px;" />
function onChangeResume(){
$('#txtImageUpload').fileupload({
dataType: 'json',
url: '/CandidateManagement.aspx/ImageUpload',
autoUpload: true,
done: function (e, data) {
//Statements
}
});
}
code behind
HttpPostedFileBase resume = Request.Files["txtImageUpload"];
if (resume != null && resume.ContentLength > 0)
{
var fileName = Path.GetFileName(resume.FileName);
var path = Path.Combine(Server.MapPath("~/Resumes"), fileName);//you can give what ever you want
resume.SaveAs(path);
}
I know how the xtype: filefield works and I also realized that file upload does not use the regular ajax method to read and write data to database...
I can set up filefield normally and when I click the browse button I can select the necessary file.
this.fp = Ext.create('Ext.form.Panel', {
scope: this,
width: 200,
frame: true,
title: 'File Upload Form',
autoHeight: true,
bodyStyle: 'padding: 10px 10px 0 10px;',
items: [
{
xtype: 'filefield'
}
],
buttons: [
{ text: 'Upload',
handler: function () {
var form = this.up('form').getForm();
if (form.isValid()) {
form.submit({
url: 'Upload.aspx',
waitMsg: 'Uploading your file...',
success: function (form, action) {
alert("OK:" + action.result.message);
},
failure: function (form, action) {
alert("Error:" + action.result.message);
}
});
}
}
}
]
});
What happens after the upload button is clicked is the problem... How would I get the file uploaded to server side...(sql db)... using c#
I tried creating an upload.aspx page with upload.aspx.cs and did this just to see if it worked...
public partial class Upload : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
HttpContext context = HttpContext.Current;
if (context.Request.Files.Count > 0)
{
BinaryReader file = new BinaryReader(context.Request.Files[0].InputStream);
string line;
while ((line = file.ReadString()) != null)
{
// sql connection?
}
}
// prepare response
MessageOb result = new MessageOb();
result.success = true;
result.message = "Success";
}
}
But I get this error
Ext.Error: You're trying to decode an invalid JSON String:
Has someone documented where I can see the usual step to upload a file to sql db from extjs on client side and c# on serverside... or I'd really appreciate if someone can show me how it's done
The problem is probably related to how you return data from the upload form submit. Ext.JS requires the response to be JSON or XML, I would verify you are not returning a html document.
I presume MessageOb handles this somehow...maybe?
Uncaught Ext.Error: You're trying to decode an invalid JSON String: Form Submission using Ext JS and Spring MVC
I know how to create a form that browses and selects a file, that's not my question. What I need is to get the content of the selected file, to send it to a server and proccess it. For now I only can get the file location.
I think it will be better if I get my file on client side (extjs), then send it to server, but I have no idea how to do this.
{
xtype: 'fileuploadfield',
hideLabel: true,
emptyText: 'Select a file to upload...',
id: 'upfile',
//name:'file',
width: 220
},
buttons:
[
{
text: 'Upload',
handler: function () {
obj.Import(Ext.getCmp('upfile').getValue())
}
}
]
Import(...) is my server function. I need to give it the file not only its path!!
Thank you in advance for your time
AFAIK Ext doesn't use HTML5 File API, so getting file content on JS side isn't straightforward. Probably simplest way to achieve that is to create custom handler. Eg:
{
xtype: 'fileuploadfield',
hideLabel: true,
emptyText: 'Select a file to upload...',
id: 'upfile',
//name:'file',
width: 220
},
buttons:
[
{
text: 'Upload',
handler: function () {
var file = Ext.getCmp('upfile').getEl().down('input[type=file]').dom.files[0]; // fibasic is fileuploadfield
var reader = new FileReader();
reader.onload = (function(theFile) {
return function(e) {
obj.Import(e.target.result);
};
})(file);
reader.readAsBinaryString(file);
}
}
]
What you are doing Ext.getCmp('upfile').getValue() is clearly passing the file location to Import method. How do you expect the file content then? In order to upload a file, you need to submit a ExtJS form. You can do something like this:
handler: function() {
form.submit({
url: '/Gallery/Upload',
waitMsg: 'Uploading your file...',
success: function(form, action) {
alert('File form done!');
}
});
}
}
And on server side:
public void ProcessRequest(HttpContext context)
{
HttpPostedFile fileupload = context.Request.Files["file"];
// process your fileupload...
context.Response.ContentType = "text/plain";
context.Response.Write("Ok");
}
Update: You need to uncomment the name property of your fileuploadfield.