using modal box for file upload - asp.net-mvc

In my MVC application am allowing the user to upload a file. Whenever user clicks on upload file link this is the link
<a class="upload" onclick="upload(this);">
the file upload should get open in modal box.
function upload(box) {
var box = dhtmlx.modalbox({
title: "Upload File",
text: "<div id='form_in_box'><div>Choose a PDF file to upload <hr/><label>Enter the URL <input type='file' name='file' id='file' style='width: 400px; height: 27px;'></label><br></div><div><span class='dhtmlx_button'><input type='submit' value='Upload File' style='width: 86px' onclick='save_file(this)'></span><span class='dhtmlx_button'><input type='button' value='Cancel' onclick='close_file(this)' style='width:80px;'></span></label></div></div>",
width: "300px"
});
}
function close_file(box) {
dhtmlx.modalbox.hide(box);
}
function save_file(box) {
var file = $("#file").val();
if (file == "") {
alert("Enter the URL");
return false;
dhtmlx.modalbox.hide(box);
dhtmlx.message("Uploading the file");
$.post("/FileUpload/Upload",
{ file: '' + file + '' });
}
and the controller code is
[HttpPost]
public ActionResult Upload(HttpPostedFileBase file)
{
SaveFile(file);
return RedirectToAction("Index");
}
but the problem is am getting error i.e. file = null

You cannot upload files using an AJAX request ($.post). If your browser supports the HTML5 File API you could use the new XHR2 object. If not, you could use a file upload plugin such as Uploadify, Fine Uploader or PLUpload. All those plugins will detect whether the client browser supports the HTML5 File API and use it if so and if it doesn't they will fallback to standard techniques such as using hidden iframes or Flash movies. The advantage of using one of them is that you don't need to be coding for all the possible cases.
Here's an example of how you could upload the file using the HTML5 File API:
function save_file(box) {
var file = document.getElementById('file');
if (file.value == '') {
alert('Enter the URL');
return false;
}
dhtmlx.modalbox.hide(box);
dhtmlx.message('Uploading the file');
var fd = new FormData();
fd.append('file', file.files[0]);
var xhr = new XMLHttpRequest();
xhr.open('POST', '/FileUpload/Upload', true);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
alert('file successfully uploaded to the server');
}
};
xhr.send(fd);
}

Related

Post a file /contents of a file to endpoint with Formik

I would like to create a form that allows the user to upload a file (a JSON object) and then post the contents of that file to an api.
I would like to see (for now just in a console log) the contents of the file I am about to post before I post it. So the flow should go like this
User sees a blank form with an upload file field
User selects a file from their computer
Once selected, I would like to log the contents of the file to the console
Once form is submitted, I would like to post the file to an endpoint with axios
I am using the useFormik hook because I have used it elsewhere and found it more intuitive than some of Formiks other options, and because I think it will be useful for when I build a few more features, so there may be some redundant lines of code here (e.g. initialValues) but for now I'm just focused on step one - seeing the values in a file before I post them.
It seems like I should be able to upload the file, read the contents of the file, store the contents of the file in a result, then pass that result to the onSubmit callback in the eventual axios.post() request I will make.
But I don't think I'm understanding the fundamentals here.
Should I use new FormData instead of a FileReader?
Should I bother reading the contents of the file before posting?
Here's my current code:
import { useFormik } from 'formik';
export const MyUploadPerfectAssetForm = () => {
const onChange = (event: any) => {
const file = event.target.files[0];
const reader = new FileReader();
reader.onload = (e) => {
// The file's text will be printed here
console.log(e.target?.result)
const result = e.target?.result;
console.log("logging result from reader.onload " + result)
return result;
};
//shows the files values properly
reader.readAsText(file);
}
//redundant for now?
const formik = useFormik({
initialValues: {
name: null,
tags: null,
type: null,
s3URL: null,
thumbnailImageURL: null,
},
onSubmit: (values, result) => {
console.log("logging values" + JSON.stringify(values))
alert(JSON.stringify(values, null, 2));
console.log("logging values from onSubmit " + JSON.stringify(values))
const uploadPerfectAsset = async (perfectAssetValues: any) => {
//there will be an axios post request here,
console.log("upload perfect asset ran")
console.log("testing uploadPerfectAsset with result from onChange file reader result" + JSON.stringify(perfectAssetValues))
}
uploadPerfectAsset(result)
},
});
return (
<div>
<form onSubmit={formik.handleSubmit}>
<div>
<input id="file"
name="test"
type="file"
onChange={onChange}></input>
</div>
<div>
<button type="submit">Submit</button></div>
</form>
</div >
);
}
Thanks
You're almost there mate 😃 A couple of small changes are needed:
add file to initialState
move onChange function to after the hook useFormik() and add formik.setFieldValue("file", file); to set the value
remove argument perfectAssetValues from function uploadPerfectAsset() - it's unnecessary
export const MyUploadPerfectAssetForm = () => {
const formik = useFormik({
initialValues: {
name: null,
tags: null,
type: null,
s3URL: null,
thumbnailImageURL: null,
file: null
},
onSubmit: (values) => {
console.log("logging values from onSubmit ", values);
const uploadPerfectAsset = async () => {
//there will be an axios post request here,
console.log("upload perfect asset ran");
console.log(
"File info: ",
JSON.stringify(
{
fileName: values.file.name,
type: values.file.type,
size: `${values.file.size} bytes`
},
null,
2
)
);
};
uploadPerfectAsset();
}
});
const onChange = (event) => {
const file = event.target.files[0];
formik.setFieldValue("file", file);
const reader = new FileReader();
// temporarily show file contentx
reader.onload = (e) => {
// The file's text will be printed here
const result = e.target.result;
console.log("logging result from reader.onload " + result);
return result;
};
//shows the files values properly
reader.readAsText(file);
};
return (
<div>
<form onSubmit={formik.handleSubmit}>
<div>
<input id="file" name="test" type="file" onChange={onChange}></input>
</div>
<div>
<button type="submit">Submit</button>
</div>
</form>
</div>
);
};
Live demo

ion icons not showing up on ipad / edge

I have a stenciljs component deployed in an nginx server behind an authentication service. In order to get anything the request must include a cookie containing an access_token. the component is dipslyaed with no preoblem on android devices and on chrome/firfox/IE11/ in desktop devices. the problem is with microsoft edge and on ipad (any navigator) and its due to the browser not sending the cookie to the server. Any hint ?
header.tsx
import { Component, Prop, State, Element } from '#stencil/core';
#Component({
tag: 'pm-header',
styleUrl: 'pm-header.scss',
shadow: true
})
export class PmHeader {
...
render() {
return (
<nav>
<ul>
<li id="menu-icon" class="left menu-icon"
onClick={() => this.toggleFocus('menu-icon')} >
<a>
<ion-icon name="md-apps"></ion-icon>
</a>
</li>
<li id="user-icon" class="right menu-icon"
onClick={() => this.toggleFocus('user-icon')} >
<a>
<ion-icon name="md-contact"></ion-icon>
</a>
</li>
</ul>
</nav>
);
}
}
PS: I'm using stencil/core v0.15.2
So after some digging it turned out that the issue is with ionicons implementation.
They fetch the svgs without sending the credentials which result in an authenticated request. Of course some navigator such as chrome and firefox and even IE11 manages to send the cookies even though it's not explicitly specified that they should.
Anyway, to solve this I had to create a script file that run after the build. This script adds credentials: "include" option to the fetch call so that the cookie get sent.
fix-icons-script.js
/**
* Workaround to fix this ion-icons bug https://github.com/ionic-team/ionicons/issues/640
* To be removed when this bug is fixed
*/
const fs = require('fs');
const workDir = 'dist/component-dir';
fs.readdir(workDir, function(err, items) {
if (err) { return console.log(err); }
for (var i=0; i<items.length; i++) {
if (items[i].endsWith('.entry.js')) {
insertString(workDir + '/' + items[i], '"force-cache"', ',credentials:"include"');
}
}
});
function insertString(file, searchValue, insertValue){
fs.readFile(file, 'utf8', function (err, content) {
if (err) { return console.log(err); }
let newContent = content.substr(0, content.indexOf(searchValue) + searchValue.length);
content = content.substr(newContent.length, content.length);
newContent += insertValue + content;
fs.writeFile(file, newContent, function (err) {
if (err) { return console.log(err); }
console.log('Successfully rewrote ' + file);
});
});
}

Image upload working in localhost but not in IIS server [ Asp.net Mvc ]

I am working on a MVC project where I am trying to upload an image through ajax; This is absolutely working fine on localhost, however it does not work on IIS web server. Once i pressed submit button, it shows error on console, saying :
"http://blahblahmywebsite.com/UserRegistration/UserPhoto 500 (Internal Server Error)".
I am struggling with this issue for 2 days now, Any suggestion?
N.B.
-> I have tried already : url: '#Url.Action("FunctionName", "Controller")'
-> Manipulation in application pool (suggested by other online posts)
->I have hosted this site on godaddy server which is using IIS 8.
->I am using .NET 4.5.2 for local server
This is my jQuery:
$("#fileUserImage").change(function () {
userImage();
});
function userImage() {
var formData = new FormData();
var totalFiles = document.getElementById("fileUserImage").files.length;
for (var i = 0; i < totalFiles; i++) {
var file = document.getElementById("fileUserImage").files[i];
formData.append("fileUserImage", file);
}
$.ajax({
type: "POST",
url: '/UserRegistration/UserPhoto',
data: formData,
dataType: 'json',
contentType: false,
processData: false,
success: function (image) {
$("#imgUserImage").attr('src', '../' + image);
alert("Entered into success block");
},
error: function (error) {
alert("Entered into error block");
}
});
}
This is my Html:
<div class="form-group">
<label class="col-md-5 control-label">Photo</label>
<div class="col-md-7">
<input type="file" id="fileUserImage" name="fileUserImage">
</div>
</div>
<div class="form-group">
<div class="img-wrap col-md-offset-5">
<img class="example-image" id="imgUserImage" width="220" style="padding-left:17px;" />
</div>
</div>
This is my Controller:
[HttpPost]
public JsonResult UserPhoto()
{
var userPic = "";
for (int i = 0; i < Request.Files.Count; i++)
{
var file = Request.Files[i];
if (file != null)
{
var fileName = Path.GetFileName(file.FileName);
var path = Path.Combine(Server.MapPath("~/Images/User/"), DateTime.Now.Day + "" + DateTime.Now.Month + "" + DateTime.Now.Year + fileName);
file.SaveAs(path);
userPic = "Images/User/" + DateTime.Now.Day + "" + DateTime.Now.Month + "" + DateTime.Now.Year + fileName;
}
else
{
userPic = "";
}
}
return Json(userPic, JsonRequestBehavior.AllowGet);
}
Check Your Destination Folder --> Right Click the folder --> Properties --> Security Tab --> Edit Button--> Allow the Security. See the image below.
I hosted my website on a remote server and had the same issue. Later on I found that application users did not have add/edit permission for images folder.

Open dynamically generated PDF in Tab or iframe

Please help.
I am obviously no expert but using suggestions from this site, I think I am really close to doing the following
Be able to open a dynamically generated PDF in
a) a new Tab
b) an iframe
Hopefully, I just need a couple of lines of the correct syntax and I will be there.
I am dynamically generating the PDF in a controller using itextSharp
CONTROLLER
public FileStreamResult GetPdf()
{
...
return new FileStreamResult(Response.OutputStream, "application/pdf"){FileDownloadName = "download.pdf"};
}
VIEW
<input id="btnNewTab" type="button" value="New Tab" />
<input id="btnIframe" type="button" value="Iframe" />
<div id="pdfDiv"></div>
<script type="text/javascript">
$(function () {
$("#btnIframe").click(function () {
$.get('/PDFTest/GetPdf', function (pdf) {
alert(pdf.length); // Works as expected
// What do I need to put here to get the pdf to appear in a iframe
});
});
$("#btnNewTab").click(function () {
// asks me if I want to Open or Save the PDF.
// If I choose Open, the PDF opens in a completely new Window.
// Instead of the dialog, I just want the PDF to open in a new Tab
// I am probably going about this in completely the wrong way.
var HTML = "<iframe src='/PDFTest/GetPdf' style='width: 100%; height: 600px' ></iframe>";
$('#pdfDiv').html(HTML);
});
});
</script>
In response to your suggestion Darin, I changed the Controller to:
public FileStreamResult GetPdf(someInfo from View)
{
...
Response.ContentType = "application/pdf";
Response.AddHeader("Content-Disposition", "inline;test.pdf");
Response.Buffer = true;
Response.Clear();
Response.OutputStream.Write(ms.GetBuffer(), 0, ms.GetBuffer().Length);
Response.OutputStream.Flush();
Response.End();
return new FileStreamResult(Response.OutputStream, "application/pdf");
}
Having done that, your suggestions worked fine but I realise that I did not explain my intentions clearly enough. I have therefore changed the VIEW to reflect what i am trying to do.
input id="btnNewTab" type="button" value="New Tab" />
<input id="btnIframe" type="button" value="Iframe" />
<iframe id="iframe"></iframe>
<div id="pdfDiv">
</div>
<script type="text/javascript">
$(function () {
$("#btnIframe").click(function () {
$.ajax({
url: '/PDFTest/GetPdf',
type: "GET",
data: json, // This line will not be a problem
dataType: "json",
contentType: "application/pdf", // This line might be a problem
success: function (pdf) {
// What to I need to need to do to display the PDF in the above iframe
$("#iframe").attr("src", pdf); // HTTP Error 400 - Bad Request.
}
});
});
$("#btnNewTab").click(function () {
$.ajax({
url: '/PDFTest/GetPdf',
type: "GET",
data: json, // This line will not be a problem
dataType: "json",
contentType: "application/pdf", // This line might be a problem
success: function (pdf) {
// What to I need to need to do to disply the PDF in a new window
}
});
});
});
</script>
Action:
public ActionResult GetPdf()
{
byte[] pdf = ...
Response.AppendHeader("Content-Disposition", "inline;test.pdf");
return File(pdf, "application/pdf");
}
To open in new Tab/Window:
#Html.ActionLink("view pdf", "getpdf", "somecontroller", null, new { target = "_blank" })
To open in an iframe your code looks fine. Just make sure to set the Content-Disposition header to inline.

How to display preloader while uploading file in ASP MVC

I have implemented image upload but can't find a way to display some animated gif image while uploading files. Here what I got so far:
<form method="post" action="/Images/Upload" enctype="multipart/form-data">
<input type="file" multiple name="ImageUploaded">
<input type="submit">
</form>
[HttpPost]
public ActionResult Upload()
{
for (int i = 0; i < Request.Files.Count; i++)
{
HttpPostedFileBase hpf = Request.Files[i] as HttpPostedFileBase;
if (hpf.ContentLength == 0)
continue;
string savedFileNameThumb = Path.Combine(
AppDomain.CurrentDomain.BaseDirectory,
"Content", "Images", "Thumb",
Path.GetFileName(hpf.FileName));
string savedFileName = Path.Combine(
AppDomain.CurrentDomain.BaseDirectory,
"Content", "Images", "Full",
Path.GetFileName(hpf.FileName));
ImageModel.ResizeAndSave(savedFileNameThumb, hpf.FileName, hpf.InputStream, 80, true);
ImageModel.ResizeAndSave(savedFileName, hpf.FileName, hpf.InputStream, int.MaxValue, false);
}
return View();
}
I added now jquery form plugin and it works. Selected images are uploaded I show/hide preloader image.
I just still need to return view or uploaded image to display it after upload finish...
I return view from controller but nothing happens after upload.
$(function () {
$("#Form").ajaxForm({
iframe: true,
dataType: "html",
url: "/Images/Upload",
success: function (result) {
$('#loadingGif').remove();
},
beforeSubmit: function () {
$('<img id="loadingGif" src="../../Content/loader.gif" />').appendTo('body');
},
error: function (response) {
alert(response);
$('#loadingGif').remove();
}
});
});
you can use jQuery to post the form asynchronously and display an animated gif while you wait for the call to return.
$('form').submit(function () {
$(this).before('<img src="loader.gif" alt="Loading..." />');
// code to submit the form
return false;
});
EDIT:
When the view is returned in the success handler, if you e.g. return an <img> tag with the url of the uploaded image, you can use jQuery to display it:
$('body').append(result);

Resources