Issues downloading a file from inside an Ajax form - asp.net-mvc

I've got a page that's being used to display a report with an Ajax form. I would like to allow the user to pick if they would like the report in HTML, CSV or some other downloadable format. The HTML portion is working fine but when I try to download the CSV version the contents of the file is being displayed on the page instead of prompting the user to download.
If I change the form so it's no longer an Ajax form the file download works but then displaying the HTML version isn't as nice. Is there a way to do what I'm trying?
My controller has code like so:
switch (reportType)
{
case ReportType.Csv:
return File(reportDataAsBytes, "text/csv", "report.csv");
default:
return PartialView("DisplayAllOrders", reportData);
}
And this is in my view
#using (Ajax.BeginForm("ViewAllOrders", "Report", new AjaxOptions { UpdateTargetId = "reportContent", InsertionMode = InsertionMode.Replace }))
{
Format:
<select id="ReportType" name="ReportType">
<option value="1">HTML</option>
<option value="2">CSV</option>
</select>
<input type="submit" />
}

You cannot use AJAX to cause file download from the main HTML response.
A common way to overcome this is to use an invisible IFrame... tell the AJAX call to refresh the IFrame and set the IFrame's src to the file you want to send in its load event.

Related

Posting form to different MVC post action depending on the clicked submit button

I am using ASP.Net MVC 4. I have multiple buttons on a view.. At present I am calling the same action method; and I am distinguishing the clicked button using a name attribute.
#using (Html.BeginForm("Submit", "SearchDisplay", new { id = Model == null ? Guid.NewGuid().ToString() : Model.SavedSearch }, FormMethod.Post))
{
<div class="leftSideDiv">
<input type="submit" id="btnExport" class="exporttoexcelButton"
name="Command" value="Export to Excel" />
</div>
<div class="pageWrapperForSearchSubmit">
<input type="submit" class="submitButton"
value="Submit" id="btnSubmitChange" />
</div>
}
//ACTION
[HttpPost]
public ActionResult Submit(SearchCostPage searchModel, string Command)
{
SessionHelper.ProjectCase = searchModel.ProjectCaseNumber;
if (string.Equals(Command, Constants.SearchPage.ExportToExcel))
{
}
}
QUESTIONS
Is there a way to direct to different POST action methods on different button clicks (without custom routing)?
If there is no way without custom routing, how can we do it with custom routing?
References:
Jimmy Bogard - Cleaning up POSTs in ASP.NET MVC
You can choose the url where the form must be posted (and thus, the invoked action) in different ways, depending on the browser support:
for newer browsers that support HTML5, you can use formaction attribute of a submit button
for older browsers that don't support this, you need to use some JavaScript that changes the form's action attribute, when the button is clicked, and before submitting
In this way you don't need to do anything special on the server side.
Of course, you can use Url extensions methods in your Razor to specify the form action.
For browsers supporting HMTL5: simply define your submit buttons like this:
<input type='submit' value='...' formaction='#Url.Action(...)' />
For older browsers I recommend using an unobtrusive script like this (include it in your "master layout"):
$(document).on('click', '[type="submit"][data-form-action]', function (event) {
var $this = $(this);
var formAction = $this.attr('data-form-action');
$this.closest('form').attr('action', formAction);
});
NOTE: This script will handle the click for any element in the page that has type=submit and data-form-action attributes. When this happens, it takes the value of data-form-action attribute and set the containing form's action to the value of this attribute. As it's a delegated event, it will work even for HTML loaded using AJAX, without taking extra steps.
Then you simply have to add a data-form-action attribute with the desired action URL to your button, like this:
<input type='submit' data-form-action='#Url.Action(...)' value='...'/>
Note that clicking the button changes the form's action, and, right after that, the browser posts the form to the desired action.
As you can see, this requires no custom routing, you can use the standard Url extension methods, and you have nothing special to do in modern browsers.
BEST ANSWER 1:
ActionNameSelectorAttribute mentioned in
How do you handle multiple submit buttons in ASP.NET MVC Framework?
ASP.Net MVC 4 Form with 2 submit buttons/actions
http://weblogs.asp.net/scottgu/archive/2007/12/09/asp-net-mvc-framework-part-4-handling-form-edit-and-post-scenarios.aspx
ANSWER 2
Reference: dotnet-tricks - Handling multiple submit buttons on the same form - MVC Razor
Second Approach
Adding a new Form for handling Cancel button click. Now, on Cancel button click we will post the second form and will redirect to the home page.
Third Approach: Client Script
<button name="ClientCancel" type="button"
onclick=" document.location.href = $('#cancelUrl').attr('href');">Cancel (Client Side)
</button>
<a id="cancelUrl" href="#Html.AttributeEncode(Url.Action("Index", "Home"))"
style="display:none;"></a>
This sounds to me like what you have is one command with 2 outputs, I would opt for making the change in both client and server for this.
At the client, use JS to build up the URL you want to post to (use JQuery for simplicity) i.e.
<script type="text/javascript">
$(function() {
// this code detects a button click and sets an `option` attribute
// in the form to be the `name` attribute of whichever button was clicked
$('form input[type=submit]').click(function() {
var $form = $('form');
form.removeAttr('option');
form.attr('option', $(this).attr('name'));
});
// this code updates the URL before the form is submitted
$("form").submit(function(e) {
var option = $(this).attr("option");
if (option) {
e.preventDefault();
var currentUrl = $(this).attr("action");
$(this).attr('action', currentUrl + "/" + option).submit();
}
});
});
</script>
...
<input type="submit" ... />
<input type="submit" name="excel" ... />
Now at the server side we can add a new route to handle the excel request
routes.MapRoute(
name: "ExcelExport",
url: "SearchDisplay/Submit/excel",
defaults: new
{
controller = "SearchDisplay",
action = "SubmitExcel",
});
You can setup 2 distinct actions
public ActionResult SubmitExcel(SearchCostPage model)
{
...
}
public ActionResult Submit(SearchCostPage model)
{
...
}
Or you can use the ActionName attribute as an alias
public ActionResult Submit(SearchCostPage model)
{
...
}
[ActionName("SubmitExcel")]
public ActionResult Submit(SearchCostPage model)
{
...
}
you can use ajax calls to call different methods without a postback
$.ajax({
type: "POST",
url: "#(Url.Action("Action", "Controller"))",
data: {id: 'id', id1: 'id1' },
contentType: "application/json; charset=utf-8",
cache: false,
async: true,
success: function (result) {
//do something
}
});

dropzone.js and ASP.NET MVC file posted is null?

I am trying to use dropzone.js to upload images in my ASP.NET MVC app. I am able to set-up the dropzone programatically, click on it, select the image and when I click "Open" in the file dialog, the correct Action is hit in the controller. However, the HttpPostedFileBase always comes back as null so I can't do anything with the image. ON the client-side, however, it shows the image thumbnail correctly, eventhough I can't get it on the server side.
This is the HTML:
<div style="float:left;margin-right:2px;" id="mainImage">
<img src="/images/AddImage_button.png" class="dz-message" />
</div>
This is the js code I call after the doc is ready:
var myDropzone = new Dropzone("div#mainImage", { url: "/Market/UploadImage" });
And this is the action call inside of the controller:
public ContentResult UploadImage(HttpPostedFileBase imageFile)
{
if (imageFile == null || imageFile.ContentLength == 0)
{
//.....
}
}
The action is hit but imageFile is null. Does anyone has any ideas? By the way, the "dz-message" class was added in the image placeholder inside the dropzone because before that it was not clickable. I read it somewhere that was a fix for that issue and it worked.
Any ideas why I am getting null for imageFile?
Default parameter name that Dropzone uses is file, and yours is imageFile. Change imageFile to file and it will work
There is a small tweak you may miss.
Happened to me lots of times,
The form element you use, must have it's enctype attribute set like this:
<form action="~/Home/SaveUploadedFile" method="post" enctype="multipart/form-data"/>

How to upload an image using jQuery / AJAX in an ASP.NET MVC website?

I'm trying to find a decent way of allowing users to upload a profile photo on an edit profile page.
I've tried out Uploadify but this doesn't appear to work under some of the more recent Google Chrome browser releases.
Ideally, I just want to offer the user the ability to replace a placeholder profile image with an image of their own, via a simple upload button (preferably ajax), and once an image has been upload, to show a 'delete' button to remove the uploaded photo and re-instate the default placeholder image.
Are there any other alternatives that play nicely across all the main browsers and integrate easily into an MVC application?
To upload with jQuery only with HTML 5, and not all browser are able to this.
You can do something like this.
You need to have a IFRAME that 'll be use to make the post with the file.
Like this:
<iframe id="targetUpload" name="targetUpload"></iframe>
In the form you set the target to the iframe.
<form target="targetUpload" name="file" runat="server" method="post" id="file" enctype="multipart/form-data" action="#Url.Content("~/Controller/Upload")">
And a submit button
<input type="Submit" value="Upload">
This is a way to upload files without refresh the page.
You can treat the files before upload with jquery. (File type, size, etc...)
And in yout controller you recive the files:
public ActionResult Upload(HttpPostedFileBase file)
{
if (file != null && file.ContentLength > 0)
{
//Save the file in the server path
string savePath = Server.MapPath("~/Upload/");
string fileName = file.FileName;
savePath += fileName;
file.SaveAs(savePath);
}
return RedirectToAction("Index");
}

How to MVC Download file in AsyncControl?

I have
public class FileController : AsyncController
{
public ActionResult Download(FormCollection form)
{
FileContentResult file = new FileContentResult(Encoding.UTF8.GetBytes("10k file size"),"application/vnd.xls");
file.FileDownloadName = "test.xls";
return file;
}
}
and ofcourse, ajax form
<% var form = Ajax.BeginForm(...) %>
<input type="image" src="...gif" /> // this is my 1st attempt
<%= Ajax.ActionLink(...) %> // 2nd attempt
<% form.EndForm(); %>
i try first method(input type=image). it reach correct Action. but no file download in client side.
Then i try to use Ajax.ActionLink which i really hate. i want nice image button, not link text. Again, it reach correct Action and no file download. But if i open link in another window, there's file download !!
Q. How to make a nice file downlaod with AsyncController
Q. How to make Ajax.ActionLink lok nice
You cannot use Ajax to download files from the server. The reason for this is that even if you succeed to make the async request to the server in the success callback you will get the file contents as sent from the server and you cannot do much with this file on the client side. Remember that javascript cannot access the file system so you won't be able to save it. The way to achieve this is to have a normal HTML <form> which will point to the Download action. When this form is submitted the user will be asked to choose where he wants to save the file and the download will proceed. Also you don't need an AsyncController for this.
Here's an example:
public class FileController : Controller
{
[HttpPost]
public ActionResult Download()
{
return File(
Encoding.UTF8.GetBytes("10k file size"),
"application/vnd.xls",
"test.xls"
);
}
}
and inside your view:
<% using (Html.BeginForm("download", "file", FormMethod.Post)) { %>
<input
type="image"
src="<%: Url.Content("~/content/images/download.png") %>"
value="download"
alt="download"
/>
<% } %>
And in order to make the download button look nice, you could create a nice download.png image which will be used as form submit button.
I use this:
to disable
$('form').removeAttr("data-ajax");
to enable
$('form').attr("data-ajax", "true");
for a form with 3 submit 1 to refresh 2 to download file
All post to the same ActionResult but 2 of them have param to download as csv or as pdf
when download just disable ajax submission.
i found a way!!
just create iframe that has regular form and use jquery to trigger to.
$("iframe").contents().find("form").submit();
:D
ps credit to Firebug + Google Doc.

SWFUpload Authentication

I am using SWFUpload to do file uploading in a ASP.NET MVC 1.0 website. It is working fine, but I am not able to authenticate the upload method. The HttpContext.User.Identity.Name returns an empty string. I am assuming this is because the Flash movie is making the post. I am also using the wrapper provided here: http://blog.codeville.net/2008/11/24/jquery-ajax-uploader-plugin-with-progress-bar/.
The controller action below gets fired, but as mentiond above the user object is not passed.
Any help is appreciated!
View
HTML
<form enctype="multipart/form-data" method="post" action="/Media/Upload/Photo">
<input type="file" id="userPhoto_Photo" name="userPhoto_Photo" />
</form>
Javascript
$(function() {
$("#userPhoto").makeAsyncUploader({
upload_url: '/Media/Upload',
flash_url: '<%= Url.Content("~/Content/Flash/swfUpload-2.2.0.1.swf") %>',
file_size_limit: '1 MB',
file_types: '*.jpg; *.png; *.gif',
button_action: SWFUpload.BUTTON_ACTION.SELECT_FILE,
button_width: 210,
button_height: 35,
button_image_url: '<%= Url.Content("~/Content/Images/UploadPhoto.png") %>',
button_text: '',
button_cursor: SWFUpload.CURSOR.HAND,
button_window_mode: SWFUpload.WINDOW_MODE.TRANSPARENT
});
});
Controller Action
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Upload()
{
if (Request.Files.Count == 1)
{
//Upload work
}
return RedirectToAction("Index", "Profile");
}
This was easily resolved with passing a post parameter, which is part of the swfUpload API. Passing user name or user id is then authenticated on the action manually using forms authentication.
You should also check out this post:
http://trycatchfail.com/blog/post/2009/05/13/Using-Flash-with-ASPNET-MVC-and-Authentication.aspx
It perfectly explains what you need to do to keep your app secure and still use Flash upload plugins like Uploadify or swfupload.
I believe this is because flash does not persist browser sessions when making requests. You would have to somehow explicitly have flash pass along some information regarding the user's session.
One way you could do this is set a cookie. Have JavaScript read the cookie and pass it off to flash. Then have flash send it along when doing uploads. This way, you are not passing in a cookie value with flash vars.
Are you using windows integrated auth?

Resources