Dojo file upload C# MVC.NET HttpPost without Uploader - c#

I have tried to find a good example with HTML/JavaScript/C# code to provide instruction on uploading only one file to the server for saving it to a directory on the server. My code gives me my variable, 'file', as null when I debug it.
HTML form:
<form id="uploadForm" method="post" data-dojo-type="dijit/form/Form" enctype="multipart/form-data">
<input
id="fileUploadInput"
type="file"
name="fileUploadInput"
>
<br />
<br />
<button
id="fileUploadButton"
data-dojo-attach-point="fileUploadButton"
onClick="click"
>
Upload
</button>
</form>
Dojo/JavaScript code:
ioIframe.send({
url: this.proxyPostFile,
form: "uploadForm",
method: "POST",
handleAs: "text",
// Callback on successful data call:
load: function (response, ioArgs) {
return response;
},
// Callback on errors
error: function (response, ioArgs) {
console.info(response)
}
});
c# code:
[HttpPost]
public JsonResult Upload(HttpPostedFileBase file)
{
JsonResult FileData = null;
if (Request != null)
{
try
{
if (file!=null && file.ContentLength > 0)
{
... do some stuff with the file
}
}
catch (Exception ex)
{
Dictionary<string,string> error = new Dictionary<string,string>();
error.Add("error", "ERROR:" + ex.Message.ToString());
FileData = Json(error);
}
}
else
{
Dictionary<string,string> callResponse = new Dictionary<string,string>();
callResponse.Add("filename", "You have not specified a file.");
FileData = Json(callResponse);
}
return FileData;
}
Any thoughts or help would be appreciated.
Thank You

Your generating the file input with name="fileUploadInput" but your parameter in the POST method is named file - they need to match in order for the parameter in the POST method to bind to the value of the form control.
Change the input to match the parameter
<input name="file" ... />

Take a look at this fiddle link. Dojo provides OOTB feature to upload file(s) to a server side (you can pass url like /test.php
http://jsfiddle.net/kolban/e47YU/
If you don't want to pass the server url or if you don't have one, then you need to manually upload the file using dijit.byId("uploader').upload();

Sorry, I am little confused, I don't know if you are trying to upload a file using ajax or a form. If you are using a form try to put enctype="multipart/form-data" attribute. Hope this helps.

Related

Print out values from text file to text area

so my first attempt at asking the question was idiotic - I do apologise
So I am reading the contents of a text file - which is just rows of numbers. I am trying to calculate the sum of each row and print the answer out individually in descending order.
Here is the code in my controller :
public void ReadFromText()
{
Array LogFileData = null;
var logFileNameWithPath = Server.MapPath(#"~/Docs/Q1InputFile.txt");
if (System.IO.File.Exists(logFileNameWithPath))
{
LogFileData = System.IO.File.ReadAllLines(logFileNameWithPath);
foreach (var line in LogFileData)
{
//code goes here
}
}
ViewBag.logFileContent = LogFileData;
}
I am struggling to send the content from the text file to the text area and with the for each in order to calculate the sum of each row.
Here is the code for the view :
<h2>Question1</h2>
<div class="jumbotron">
<p class="lead">Please click the button to load the results</p>
<input type="button" title="LoadAnswer" value="Click me" id ="btn_run")
onclick="location.href='#Url.Action("ReadFromText", "Question1")'" />
#if (ViewBag.logFileContent != null)
{
foreach (string dataLine in ViewBag.logFileContent)
{
#dataLine
<br />
}
}
</div>
#Html.TextArea("ReadFromText", "Question1")
<div>
#Html.ActionLink("Back to Home", "Index", "Home")
</div>
Sorry this a basic question - but I new and trying to learn from this
Please advise
Assuming that your button is html and in browser on client side and file is residing on server in your solution directory (not on client side)
I would do following
When a button in browser is pressed I will fire an ajax call to server.
On server controller would open a file stream to this file and read lines one by one or whatever way you want to do with them and get the output sent out in json format.
When server returns output to ajax response i will replace the text area with that response or append it if needed.
All these three steps can be done individually with test data. I would first create an ajax test and on controller return a number and work on js to populate it in text field. Once that is done you only need to work on file read function in controller and return what is in file or summed from file etc.
On click of button make an AJAX call
Sample Ajax code:
$.ajax({
type : 'POST',
url : '#Url.Action("your controller and actions goes here")',
dataType : 'json',
data : {
//Send file path if it is dynamic
},
success : function (data) {
//Logic to format and display your text file data
},
error : function (ex) {}
});
C# - Server side code:
string text;
var fileStream = new FileStream(#"c:\file.txt",FileMode.Open,FileAccess.Read);
using (var streamReader = new StreamReader(fileStream, Encoding.UTF8))
{
text = streamReader.ReadToEnd();
}
send text in the JSON format to the client and display it as per your requirment
Refer this link for AJAX implementation http://dotnetmentors.com/mvc/jquery-ajax-call-with-jsonresult-in-asp-net-mvc.aspx
I prefer to read line by line from txt file and then I create a stringBuilder and send it to a textare element like this.
List<string> linesFromFile= File.ReadAllLines(filePath).ToList();
StringBuilder str = new StringBuilder();
foreach (string item in linesFromFile)
{
str.AppendLine(item);
}
ViewBag.RobotsTxt = str;

ASP.NET MVC - How to call void controller method without leaving the view?

Question background:
I am implementing some basic 'shopping cart' logic to an MVC app. Currently when I click a link - denoted as 'Add To Cart' on the screen shot below this calls to an 'AddToCart' method in the 'ProductController' as shown:
Product.cshtml code:
#Html.ActionLink("Add To Cart", "AddToCart")
'AddToCart' method in the ProductController:
public void AddToCart()
{
//Logic to add item to the cart.
}
The issue:
Not an issue as such but currently when I click the 'Add To Cart' button on the ActionLink on the ProductDetail.cshtml view the page calls the 'AddToCart' method on the ProductController and gives a blank view on the page - as shown below. I want the view to stay on 'ProductDetail.cshtml' and just call the 'AddToCart' method, how do I do this?
Basically #Html.ActionLink() or <a></a> tag uses get request to locate the page. Hence whenever you clicked it, you request to your AddToCart action method in ProductController and if that action method returns null or void so a blank or empty page is shown as you experienced (because or #Html.ActionLink() get request by Default).
So if you want to add your value to cart then call AddToCart method using ajax i.e:
HTML:
#Html.ActionLink("Add To Cart", "AddToCart", null, new { id="myLink"})
Jquery or Javascript:
$("#myLink").click(function(e){
e.preventDefault();
$.ajax({
url:$(this).attr("href"), // comma here instead of semicolon
success: function(){
alert("Value Added"); // or any other indication if you want to show
}
});
});
'AddToCart' method in the ProductController:
public void AddToCart()
{
//Logic to add item to the cart.
}
Now this time when the call goes to AddToCart method it goes by using ajax hence the whole page will not redirect or change, but its an asynchronous call which execute the AddToCart action method in your ProductController and the current page will remains same. Hence the product will also added to cart and page will not change to blank.
Hope this helps.
The answer of Syed Muhammad Zeeshan is what you are looking for, however you may return an EmptyResult.
public ActionResult AddToCart()
{
//Logic to add item to the cart.
return new EmptyResult();
}
According to this it has no impact on your code ASP.Net MVC Controller Actions that return void
But maybe sometime you want to return data and then you could do something like this:
if (a)
{
return JSon(data);
}
else
{
return new EmptyResult();
}
As many people mentioned here you will need to use AJAX if your using asp.net MVC to hit a controller POST function without having to leave your view.
A good use case for this is if you want to upload a file without refreshing the page and save that on the server.
All of the
return new EmptyResult();
Wont work, they will still redirect you.
Here is how you do it, in your view have the follow form as an example:
<form enctype="multipart/form-data" id="my-form">
<p>
The CSV you want to upload:
</p>
<input type="file" class="file-upload" name="FileUpload" />
</div>
<div>
<button type="submit" class="btn btn-default" name="Submit" value="Upload">Upload</button>
</div>
</form>
Then in the JavaScript side you need to add this to your view with within Script tags.
$("#my-form").on('submit', function (event) {
event.preventDefault();
// create form data
var formData = new FormData();
//grab the file that was provided by the user
var file = $('.file-upload')[0].files[0];
// Loop through each of the selected files.
formData.append('file', file);
if (file) {
// Perform the ajax post
$.ajax({
url: '/YourController/UploadCsv',
data: formData,
processData: false,
contentType: false,
type: 'POST',
success: function (data) {
alert(data);
}
});
}
});
Your controller might look something like this to process this type of file:
[HttpPost]
public void UploadCsv()
{
var listOfObjects = new List<ObjectModel>();
var FileUpload = Request.Files[0]; //Uploaded file
//check we have a file
if (FileUpload.ContentLength > 0)
{
//Workout our file path
string fileName = Path.GetFileName(FileUpload.FileName);
string path = Path.Combine(Server.MapPath("~/App_Data/"), fileName);
//Try and upload
try
{
//save the file
FileUpload.SaveAs(path);
var sr = new StreamReader(FileUpload.InputStream);
string csvData = sr.ReadToEnd();
foreach (string r in csvData.Split('\n').Skip(1))
{
var row = r;
if (!string.IsNullOrEmpty(row))
{
//do something with your data
var dataArray = row.Split(',');
}
}
}
catch (Exception ex)
{
//Catch errors
//log an error
}
}
else
{
//log an error
}
}
There are many ways to accomplish what you want, but some of them require a lot more advanced knowledge of things like JavaScript than you seem aware of.
When you write ASP.NET MVC applications, you are required to have more intimate knowledge of how browsers interact with the web server. This happens over a protocol called HTTP. It's a simple protocol on the surface, but it has many subtle details that you need to understand to successfully write ASP.NET MVC apps. You also need to know more about Html, CSS, and JavaScript.
In your case, you are creating an anchor tag (<a href="..."/>), which when click upon, instructs the browser to navigate to the url in the href. That is why you get a different page.
If you don't want that, there are a number of ways change your application. The first would be, instead of using an ActionLink, you instead simply have a form and post values back to your current controller. And call your "add to cart" code from your post action method.
Another way would be have your AddToCart method look at the referrer header (again, part of that more subtle knowledge of http) and redirect back to that page after it has processed its work.
Yet another way would be to use Ajax, as suggested by Syed, in which data is sent to your controller asynchronously by the browser. This requires that you learn more about JavaScript.
Another option is to use an embedded iframe and have your "add to cart" be it's own page within that iframe. I wouldn't necessarily suggest that approach, but it's a possibility.
Controller should return ActionResult. In this case a redirect to the caller page.
using System.Web.Mvc;
using System.Web.Mvc.Html;
public ActionResult Index()
{
HtmlHelper helper = new HtmlHelper(new ViewContext(ControllerContext, new WebFormView(ControllerContext, "Index"), new ViewDataDictionary(), new TempDataDictionary(), new System.IO.StringWriter()), new ViewPage());
helper.RenderAction("Index2");
return View();
}
public void Index2(/*your arg*/)
{
//your code
}
I was struggling with this and couldn't get it working with ajax.
Eventually got a working solution by making my controller method return type ActionResult rather than void and returning a RedirectToAction() and inputting the action relating to the view I wanted to remain on when calling the controller method.
public ActionResult Method()
{
// logic
return RedirectToAction("ActionName");
}

jquery, how to upload image of input(file) via webservice to codebehind and read there

i want to save a input (type = file) image to database (asp.net & mssql),
in this case i use web service, so i can't use runat= server, or i can't use server side controls.
in client side, user chose a picture, and i must save it binary to database.
var exts = ['jpg', 'jpeg', 'png', 'gif'];
var file = $(this).val();
if (file) {
var get_ext = file.split('.');
get_ext = get_ext.reverse();
if ($.inArray(get_ext[0].toLowerCase(), exts) > -1) {
if ((Math.round((this.files[0].size) / 1024)) > 35) {
alert("PLEASE REDUCE FILE SIZE");
} else {
//everything is ok
}
} else {
alert("PLEASE CORRECT FORMAT");
}
} else {
alert("PLEASE DEFINE FILE");
}
i can check file selected, type and size and know need to upload.
what can i do?
is it possible to support, ie? if yes which version?
thank you
You have to upload the image in a form using the next tag:
<form id='fileUploadForm' enctype="multipart/form-data" method="post" action="yourAction">
<input type="hidden" value="your max value in bytes" name="MAX_FILE_SIZE">
<input type="file" name="userImage">
</form>
It will be submitted for any browser.
But if you want to submit the form using ajax, you should use a plugin. I used recently this one: http://malsup.github.io/jquery.form.js. It is very simply to use.
There is another issue: files[0] will return undefined if using IE.
I use this so that IE also works:
var file = $('input[type=file]')
file.bind('change', function(e) {
e.preventDefault();
if (typeof this.files === "undefined") fileOk = file;
else fileOk = this.files[0];
....
Then, and after validation on client side, you can use this method from jquery.form plugin:
$('#fileUploadForm').ajaxSubmit(){
beforeSend: function() {},
uploadProgress: function(event, position, total, percentComplete) {},
success: function() {},
complete: function(xhr) {}
}
And the file will be submitted.

MVC-4 FileUpload success message

I am having few problems with displaying a success message after a file has been uploaded.
I first tried with using the ViewBag.Message , and it works good and display the Success message after the file has been uploaded, which is what I want. But then I cant find a way on how to , after a few seconds change that message back to: "Choose a file to upload !" , so that the user understand he can now upload a new file.
I tried to implement a javascript feature to handle the success message instead. The problem with that is that the success message then shows up before the file upload is completed, which is no good, and if its a very small file, the message will only show for a millisecond.
Do you have any suggestion on how I can fine tune this ? Im not sure if I should try work further using javascript or viewbag, or something different ?
What I am looking for is a success message that are display for around 5 seconds after a successful upload, it then changes back to the "Choose a file to upload message" again.
https://github.com/xoxotw/mvc_fileUploader
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Web;
using System.Web.Mvc;
namespace Mvc_fileUploader.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
//ViewBag.Message = "Choose a file to upload !";
return View("FileUpload");
}
[HttpPost]
public ActionResult FileUpload(HttpPostedFileBase fileToUpload)
{
if (ModelState.IsValid)
{
if (fileToUpload != null && fileToUpload.ContentLength > (1024 * 1024 * 2000)) // 1MB limit
{
ModelState.AddModelError("fileToUpload", "Your file is to large. Maximum size allowed is 1MB !");
}
else
{
string fileName = Path.GetFileName(fileToUpload.FileName);
string directory = Server.MapPath("~/fileUploads/");
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
string path = Path.Combine(directory, fileName);
fileToUpload.SaveAs(path);
ModelState.Clear();
//ViewBag.Message = "File uploaded successfully !";
}
}
return View("FileUpload");
}
public ActionResult About()
{
ViewBag.Message = "Your app description page.";
return View();
}
public ActionResult Contact()
{
ViewBag.Message = "Your contact page.";
return View();
}
}
}
FileUpload view:
#{
ViewBag.Title = "FileUpload";
}
<h2>FileUpload</h2>
<h3>Upload a File:</h3>
#using (Html.BeginForm("FileUpload", "Home", FormMethod.Post, new {enctype = "multipart/form-data"}))
{
#Html.ValidationSummary();
<input type="file" name="fileToUpload" /><br />
<input type="submit" onclick="successMessage()" name="Submit" value="upload" />
//#ViewBag.Message
<span id="sM">Choose a file to upload !</span>
}
<script>
function successMessage()
{
x = document.getElementById("sM");
x.innerHTML = "File upload successful !";
}
</script>
Few things,
First, you need a Model to indicate a successful upload, we can just use a bool in your instance to indicate it.
Add this at the top of your view:
#model bool
Then you can do (keeping your view as is):
#{
ViewBag.Title = "FileUpload";
}
<h2>FileUpload</h2>
<h3>Upload a File:</h3>
#using (Html.BeginForm("FileUpload", "Home", FormMethod.Post, new {enctype = "multipart/form-data"}))
{
#Html.ValidationSummary();
<input type="file" name="fileToUpload" /><br />
<input type="submit" onclick="successMessage()" name="Submit" value="upload" />
<span id="sM">Choose a file to upload !</span>
}
We can manipulate the sM in JS dependent upon the model value
<script>
#if(Model)
{
var x = document.getElementById("sM");
x.innerHTML = "File upload successful !";
setTimeout("revertSuccessMessage()", 5000);
}
function revertSuccessMessage()
{
var x = document.getElementById("sM");
x.innerHTML = "Choose a file to upload !";
}
</script>
Then in your else statement in your action method, just make sure you return true on success, otherwise false. Like so
else
{
string fileName = Path.GetFileName(fileToUpload.FileName);
string directory = Server.MapPath("~/fileUploads/");
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
string path = Path.Combine(directory, fileName);
fileToUpload.SaveAs(path);
ModelState.Clear();
return View("FileUpload", true);
}
return View("FileUpload", false);
You could do the following:
$('form').submit(function(e) {
var form = $(this);
if (form.valid()) {
e.preventDefault();
$.ajax(form.attr('action'), {
data: new FormData(form[0]),
xhr: function() {
var myXhr = $.ajaxSettings.xhr();
var progress = $('progress', form);
if (myXhr.upload && progress.length > 0) {
progress.show();
myXhr.upload.addEventListener('progress', function(e) {
if (e.lengthComputable)
progress.attr({ value: e.loaded, max: e.total });
}, false);
}
return myXhr;
},
success: function(e) {
alert('Upload complete!');
},
// Options to tell JQuery not to process data or worry about content-type
contentType: false,
processData: false
});
}
});
However it will only work in modern browsers. You could use Modernizr to detect this. For example, if you wrap the code within the form's submit event handler with the following, it will fall back to a regular submit if it is not supported.
if (Modernizr.input.multiple) {
...
}
This also supports progress indication. Simply put a progress tag within the form.
The above code simply alerts the the user when the upload is complete. I use a nice little library called toastr instead.
Perhaps you could just use alert() on it's success? Not the most elegant solution but it sounds like it may suffice. Otherwise, you should look into JQuery

Remote file extension validation in ASP.NET MVC3 with C#?

I have an MVC3 application that uploads a file from the users' hard drive and manipulates it. One requirement is that the file extension should be .xls(or xlsx).
I would like to validate the file name but I would like to know what is the best option in terms of reusability and performance (and of course best coding practices).
I have the following Index view:
#using (Html.BeginForm("Index", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<br />
<p><input type="file" id="file" name="file" size="23"/></p><br />
<p><input type="submit" value="Upload file" /></p>
}
Called by the controller action method Index:
public ActionResult Index()
{
return View("Index");
}
And the user response is handled by the Index action method (HttpPost):
[HttpPost]
public ActionResult Index(HttpPostedFileBase file)
{
FileServices lfileServices = new FileServices();
var lfilePath = lfileServices.UploadFile(file, "~/App_Data/uploads");
//Manipulation;
}
Now I can use the Path.GetExtension(filename) in the FileServices to get the extension and then perform the check but it will be performed just after the upload completes.
I would like to do it once the user attempts to upload the file. The only thing that came up to my mind is create a Model(or better a ViewModel) and use the remote validation from DataAnnotations.
I saw a demonstration from Scott Hanselman live but it seemed like he was not really confortable with that because the application was compiling but was not performing the check.
Has anybody a good approach in order to perform such kind of remote validation or any other solution (jQuery for instance)?
Thanks
Francesco
You could do this using javascript:
$(function () {
$('form').submit(function () {
var selectedFile = $('#file').val();
var matches = selectedFile.match(/\.(xlsx?)$/i);
if (matches == null) {
alert('please select an Excel file');
return false;
}
return true;
});
});
Of course this doesn't in any case free you from the obligation of performing the same check on the server because if the client has no javascript enabled that will be the only way. And even this wouldn't be 100% reliable as there is nothing preventing users from renaming any garbage file to .xls and upload it. Heuristics could be used on the server to try to guess the actual file type by looking at some known byte sequences.
UPDATE:
Example with remote AJAX validation (due to demand in the comments, I don't recommend it though). You could use the excellent jquery.validate plugin which by the way comes bundled with ASP.NET MVC 3:
<script src="#Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
#using (Html.BeginForm("Index", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<input type="file" id="file" name="file" size="23" data-remote-val-url="#Url.Action("CheckExtension")"/>
<br />
<input type="submit" value="Upload file" />
}
<script type="text/javascript">
$('form').validate({
rules: {
file: {
remote: $('#file').data('remote-val-url')
}
},
messages: {
file: {
remote: 'Please select an Excel file'
}
}
});
</script>
and on the server:
public ActionResult CheckExtension(string file)
{
var extension = Path.GetExtension(file ?? string.Empty);
var validExtensions = new[] { ".xls", ".xlsx" };
var isValid = validExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase);
return Json(isValid, JsonRequestBehavior.AllowGet);
}

Categories

Resources