MVC3 - Without saving file to server, output for user download - asp.net-mvc-3

I have been up the wall and back again with this. The idea is that when a user clicks a link on a page, the controller method will prepare the data, save it to a memory stream and then serve the file to the user. This is my current code:
public ActionResult Export(int id1, int id2)
{
using (ExcelPackage excelPackage = new ExcelPackage())
{
ExcelWorksheet workSheet = excelPackage.Workbook.Worksheets.Add("Test1");
//Populate worksheet with data...
MemoryStream stream = new MemoryStream();
excelPackage.SaveAs(stream);
stream.Position = 0;
return File(stream, "application/vnd.ms-excel", "myfilename.xlsx");
}
}
My issue is that when this button is clicked, the user is not prompted to grab the file. I have stepped through the method and nothing seems off, but I am reasonably new to MVC and may be missing something.
Any assistance would be welcome.
--EDIT--
I should mention that for the button I am handling the click in a jquery.click function, and I am reaching the above method through AJAX. Would this be an issue in returning a file?
$(".export").click(function () {
var ID1 = '<%: Model.ID1%>';
var ID2= '<%: ViewData["ID2"] %>';
$.ajax({
url: '<%= Url.Action("Export", "Export") %>',
type: "GET",
data: { id1: ID1, id2: ID2},
async: false,
success: function () {
}
});
});

try next:
$(".export").click(function () {
var ID1 = '<%: Model.ID1%>';
var ID2= '<%: ViewData["ID2"] %>';
var url = '<%= Url.Action("Export", "Export") %>?id1'+ ID1+'$id2'+ID2; // format your url
window.location=url;
}
Not sure about url formatting but you got the point. This worked for me. Let me know if it works for you.

Related

Unable to receive object FormData from JQuery Ajax in WebApi method: HttpContext.Current.Request.Files[0] returns null

I have tried many suggestions from stack overflow earlier threads, but the issue still do not seem to be resolving.
Client Side Code:
var file = document.getElementById('MainForm_main_panel_company_code_change_file').files[0];
var formData = new FormData();
formData.append("file", file);
data = '[0, {"data":{"args":"'+formData+'"}}]';
$.ajax({
url: 'Control/MainForm.main_panel.company_code_change/GetData',
type: 'POST',
data: data,
contentType: false,
processData: false,
dataType: 'json',
success: function (result) {
if (result.msg === undefined) {
JSMessage.show("Success", "Report Generated Successfully");
} else
JSMessage.show("Error", "Report Generation Failed:" +result.msg.text);
}
Note: If I don't mention data = '[0, {"data":{"args":"......., it throws error: 'data is required'
Server Side Code:
public class CompanyCodeChangeArg
{
public string args;
public CompanyCodeChangeArg()
{
F<IMNull<CompanyCodeChangeArg>>.Instance.SetNull(this);
}
}
[HttpPost]public string GetData(CompanyCodeChangeArg arg)
{
var file = System.Web.HttpContext.Current.Request.Files[0];
HttpPostedFileBase filebase = new HttpPostedFileWrapper(file);
var fileName = Path.GetFileName(filebase.FileName);
var path = Path.Combine(System.Web.Hosting.HostingEnvironment.MapPath("~/App_Data/Uploads/"), fileName);
filebase.SaveAs(path);
return "";
}
Please help me here, I need to upload the file using WebApi Method and JQuery AJAX,
Tried various suggestions on stack overflow but it did not worked

Sending data to controller using Ajax

I have a form that contains different fields for user to fill in and also allow user to attach image. Below is my code to send data to the controller, I can see the image in my controller but I am not sure how to access rest of form data in controller:
$(function () {
var ajaxFormSubmit = function () {
var $form = $(this);
var data = new FormData();
var files = $("#File").get(0).files;
if (files.length > 0) { data.append("File", files[0]); }
else {
common.showNotification('warning', 'Please select file to upload.', 'top', 'right');
return false;
}
var options = {
url: $form.attr("action"),
type: $form.attr("method"),
data: data,
processData: false,
dataType: "html",
contentType: false
};
$.ajax(options).done(function (data) {
$('#ProdList').html(data);
});
return false;
};
$("form[data-ajax='true']").submit(ajaxFormSubmit);
});
My controller :
public ActionResult Create(PostViewProduct postProduct)
{
//code......
}
PostViewProduct model shows only image fields with data rest showing null:
Do I have to add each field using formdata.append() or is there better way to send all the data to controller and then access the data in controller.
Thanks
Try this:
var data = new FormData($(this)[0]);
instead of var data = new FormData();
Try following, this will put the data in right format if all input is within the form.
data = $form.serialize();
You basically need to send the files in FormData along with other form element data.
$(function () {
var ajaxFormSubmit = function () {
var fdata = new FormData();
$('input[name="Image"]').each(function (a, b) {
var fileInput = $('input[name="Image"]')[a];
if (fileInput.files.length > 0) {
var file = fileInput.files[0];
fdata.append("Image", file);
}
});
// You can update the jquery selector to use a css class if you want
$("input[type='text'").each(function (x, y) {
fdata.append($(y).attr("name"), $(y).val());
});
var frmUrl = $(this).attr('action');
$.ajax({
type: 'post',
url: frmUrl,
data: fdata,
processData: false,
contentType: false,
success: function (e) {
console.log(e);
}
});
return false;
};
$("form[data-ajax='true']").submit(ajaxFormSubmit);
});
Assuming your view model has a property called Image of type HttpPostedFileBase for accepting the posted file and your form has an input for that
public class YourViewModel
{
public HttpPostedFileBase Image { set;get;}
//Your other existing properties
}
and your form has an file input tag with name "Image".
<input type="file" name="Image" />

Kendo UI FileUpload via AJAX with JSON

I am using Kendo with MVC 5. I have several form inputs including a fileupload control. Onclick of a button I am building a json object with the values of the inputs and sending it through via an AJAX call.
I want to know how I can include the selected file from the file upload control in the json object that is sent. Here is the code for the upload control:
$(document).ready(function () {
$("#files").kendoUpload({
multiple: false
});
});
And then the ajax call sending the form data:
var ro = new Object();
// ...... //populate some properties
var jsonString = JSON.stringify(ro);
$.ajax({
url: '#Url.Action("Save", "Service")',
data: jsonString ,
type: 'POST',
dataType: 'json',
contentType: 'application/json',
});
The receiving controller action look like this:
public ActionResult Save(MyViewModel model)
{
var obj = //call something here then return resulting obj
return this.Json(obj, JsonRequestBehavior.AllowGet);
}
Any help is appreciated.
Try
$("#files").kendoUpload({
multiple: false,
async: {
saveUrl: '#Url.Action("Save", "Service")',
autoUpload: true
},
upload: function (e) {
var ro = new Object();
//......//populate some properties
var jsonString = JSON.stringify(ro);
e.data = jsonString;
}
});
In your controller:
public ActionResult Save(IEnumerable<HttpPostedFileBase> files, string model)
// string because you used JSON.stringify and it is a string, do not stringify, if you need an object
{
var js = new JavaScriptSerializer();
var objetModel = js.Deserialize<MyViewModel>(model);
var obj = //call something here then return resulting obj
return Json(obj, JsonRequestBehavior.AllowGet);
}
I did not test it - it is just to get you an idea how to pass an additional information along with the uploaded binary file

AJAX issues with IE9

I have a facebook app that works in all other browsers but IE. Here is my javascript code:
(function(d){
var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
if (d.getElementById(id)) {return;}
js = d.createElement('script'); js.id = id; js.async = true;
js.src = "//connect.facebook.net/en_US/all.js";
ref.parentNode.insertBefore(js, ref);
}(document));
window.fbAsyncInit = function() {
FB.init({
appId : '123456789', // App ID
channelUrl : 'http://test/channel.php', // Channel File
status : true, // check login status
cookie : true, // enable cookies to allow the server to access the session
xfbml : true, // parse XFBML
oauth : true // turn on oauth
});
// Additional initialization code here
};
function start() {
//send initial AJAX request
var bike_var = $("select#bike").val();
var reason_var = $("textarea#reason").val();
var dataString = 'bike='+ bike_var + '&reason=' + reason_var;
$.ajax({
type: "POST",
url: "save.php",
data: dataString,
success: function(data) {
//set ID in the form
$("input#recordID").val(data);
doLogin();
}
});
}
function doLogin() {
//Do request to Facebook to get user details and then post to wall and the submit the form
FB.login(function(response) {
if (response.authResponse) {
getUserInfo();
} else {
alert("Sorry! We can't enter you into the competition unless you allow our Facebook app!");
}
}, {scope: 'email, publish_stream'});
}
function getUserInfo() {
FB.api('/me', function(info) {
$("input#name").val(info.name);
$("input#email").val(info.email);
$("input#FID").val(info.id);
var params = {};
params['message'] = $("textarea#reason").val();
params['name'] = 'Test';
params['description'] = '';
params['link'] = 'http://www.facebook.com/ChainReactionCycles';
params['picture'] = 'http://crc.test/img/logo.gif';
params['caption'] = 'Test';
postToWall(params);
});
}
function postToWall(param) {
FB.api('/me/feed', 'post', param, function(wall) {
  if (!wall || wall.error) {
  } else {
document.forms["comp-entry"].submit();
  }
});
}
Here is code for my submit button that kicks off the code, currently working in all other browsers:
<input type="submit" name="submit_button" value="Enter Competition" onclick="start(); return false;">
In IE, this just goes to a blank page with the record ID of the new record, but in my database none of the required facebook fields are filled. The error in IE when i debug is 'SCRIPT5002: Function expected'. If anyone has any ideas i would be eternally grateful
I had the same error message on my script and googled for that error code, so I accidently stumbled across your question. your line of code, that kicks the error helped me, so I can help you now.
Obviously IE 9 does not like "start" as a function name. I had the same function in my code, and after I found that redundancy between my own code and yours, I replaced the function name, et voila, everything works fine now.

Ajax response and anonymous function scope

In the following code
var entryTemplate = document.getElementById('entryTemplate');
entryTemplate = entryTemplate.firstChild;
for (var ipost in posts)
{
var post = posts[ipost];
var clone = entryTemplate.cloneNode(true);
clone = $(clone);
if (post.imageURL)
{
var imgElement = document.createElement('img');
var largeImageURL = post.largeImageURL ? post.largeImageURL : post.imageURL;
imgElement.src = post.thumbPresent ? POST_THUMB_URL + '/' + post.postID : largeImageURL;
imgElement.alt = '';
clone.find('div.BlogImageURL a').attr('href', largeImageURL).text(largeImageURL);
clone.find('div.BlogImage a').attr('href', imgElement.src).append(imgElement);
// get bytesize
var postdata = 'inline_image_url=' + encodeURIComponent(post.imageURL);
postdata += '&linked_image_url=' + encodeURIComponent(post.largeImageURL);
$.ajax({
type: 'POST',
url: ASYNC_GET_BYTESIZE_URL,
data: postdata,
success: function(bytesize) {
clone.find('.BlogImageBytesize').html(bytesize);
}
});
}
else
{
clone.find('div.BlogImageURL').text('(This post contains no images)');
clone.find('div.BlogImage').remove();
}
$('#outputDiv').append(clone);
}
clone.find('.BlogImageBytesize').html(bytesize);
All ajax responses (bold line) modify the last clone, probably because the loop is finished when the first response arrives and clone points to the last clone.
How can I fix this?
Thanks.
Perhaps you could set clone as the context of your ajax call. (See docs here.) Then, I think it would work something like this:
$.ajax({
type: 'POST',
url: ASYNC_GET_BYTESIZE_URL,
data: postdata,
context: clone,
success: function(bytesize) {
$(this).find('.BlogImageBytesize').html(bytesize);
}
});
I don't know for sure if the context has to be a plain DOM element or if it can be a jQuery object, but hopefully this gets you on the right track.

Resources