mvc3 and evopdf - display "processing" message while the pdf is being generated - asp.net-mvc-3

I am using MVC3 and evopdf (http://www.evopdf.com/) to create a pdf when user clicks on a print button.
I have the initial view that contains a form and print button and a 2nd view specifically designed for printing.
Clicking on the print button calls javascript to submit the form, which calls the print action.
What I would like to happen is that once the print button has been clicked, a "processing" message is displayed.
Once the pdf has been generated I would like the message to be removed.
This is the javascript (I have not included all of my javascript as there are parts that are not relevant)
$(document).ready(function () {
$(".btn").click(function () {
var delay = 10;
$("#AjaxDelay").val(delay);
$.blockUI();
$('#printForm').submit();
});
$('#printForm').submit(function () {
$.blockUI();
$.ajax({
url: this.action,
type: this.method,
success: function (data) {
$.unblockUI();
//I need to open the pdf in appropriate app, adobe pdf viewer or similar
},
failure:function(data) {
alert("error");
$.unblockUI();
}
});
return false;
});
});
The form
#using (Html.BeginForm("PrintView", "Index", new { format = "pdf/", id = Model.ID, AjaxDelay = Model.AjaxDelay }, FormMethod.Get, new { id="printForm" }))
{
#Html.HiddenFor(m=>m.AjaxDelay)
<button type="button" class="btn print" >Print</button>
}
IndexController
public ActionResult PrintView(int id)
{
var model = GetData(id);
return View(model);
}
This is my HttpHandler
public void ProcessRequest(HttpContext context)
{
if (!context.Request.IsAuthenticated) return;
ProducePDF(context, "pdf title", 20);
}
private void ProducePDF(HttpContext context, string title,int delay)
{
var pdfConverter = GetPdfConverter();
// set the license key
pdfConverter.LicenseKey = "licence key here";
pdfConverter.JavaScriptEnabled = true;
var pdfBytes = pdfConverter.GetPdfBytesFromUrl(context.Request.Url.ToString().Replace(".pdf/", ""));
// send the PDF document as a response to the browser for download
var response = HttpContext.Current.Response;
response.Clear();
response.AddHeader("Content-Type", "application/pdf");
response.AddHeader("Content-Disposition", String.Format("attachment; filename=" + title + ".pdf; size={0}", pdfBytes.Length));
response.BinaryWrite(pdfBytes);
response.End();
}
Thanks.

I found a solution that uses the jquery cookie plugin and appending a cookie to the response as described in this stackoverflow article.
Hide image using Javascript after controller action is complete MVC3
I did have to make a small change in that I had to specify the path when removing the cookie.

Related

asp.net mvc index action is called automatically after ajax

I have an action that creates a record in the database:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "Id,Name,Description")] SampleViewModel sampleVM)
{
try
{
_service.Add(sampleVM);
this.ShowMessage(new ToastMessage(ToastType.Success, "Record Added", ToastrDisplayType.TopLeft));
}
catch (Exception ex)
{
this.ShowMessage(new ToastMessage(ToastType.Error, ex.Message, ToastrDisplayType.TopLeft));
return Json("failed");
}
return Json("success");
}
this Action is called by AJAX:
$().ready(function () {
$("#btnSave").click(function () {
var serviceURL = '';
var sample = {
"Id": $('#hdnId').val(),
"Name": $("#txtName").val(),
"Description": $("#txtDescription").val(),
};
if (save_method == 'add') {
serviceURL = '#Url.Action("Create", "Samples")';
}
else if (save_method == 'edit') {
serviceURL = '#Url.Action("Edit", "Samples")';
}
$.ajax({
type: "POST",
url: serviceURL,
data: addRequestVerificationToken(sample),
success: function (data, textStatus, jqXHR) {
handleAjaxMessages();
},
});
});
});
The problem is that the Index Action is called automatically after the Create Action:
[HttpGet]
public ActionResult Index()
{
return View();
}
Fiddler snapshot
The Toast message is not displayed because the Index Action is called, How can I call the Create Action only (without calling the Index Action)?
So your "#btnSave" is a <button type="submit" /> button. The browser will do the following in order:
Invoke your own click handler, that you have shown in your code.
Post the <form> that your button is in to the server and reload the page with the answer that it gives.
You have two options: either you remove the form and have a regular <button> (without type="submit"), or you modify your click handler a little:
$("#btnSave").click(function (event) {
event.preventDefault(); // notice this line
var serviceURL = '';

Submit Multipart/form-data form to ASP Web Api using ajax

I know this question has been asked alot and i tried every single solution, but it just won't work for me.
I have a ASP WEB API which looks like this:
private string uploadFolder = ("~/uploads");
[HttpPost]
public async Task<HttpResponseMessage> PostFile()
{
var provider = new MultipartFormDataStreamProvider(uploadFolder);
try
{
StringBuilder sb = new StringBuilder();
await Request.Content.ReadAsMultipartAsync(provider);
foreach (var key in provider.FormData.AllKeys)
{
foreach (var a in provider.FormData.GetValues(key))
{
sb.Append(a.ToString());
}
}
return Request.CreateResponse(HttpStatusCode.OK);
}
catch (Exception e)
{
return null;
}
}
As you can see, it is a pretty simple one that is able too accept multipart/form-data.
The Ajax code i am using is the following:
$("#form1").submit(function (e) {
var formData = $(this).serializeArray();
var submitUrl = "api/upload";
$.ajax({
url: submitUrl,
type: "POST",
data: formData,
success: function() {
//window.location("Upload.html");
alert("Success");
},
error: function() {
alert("Error");
}
});
e.preventDefault();
});
$(this).submit();
The form i am sending only contains a textfield and a submit button. When i click the submit button, i get an error: 405 Method not allowed.
When i insert the script into chrome and run it from there it gets to the API, but on
await Request.Content.ReadAsMultipartAsync(provider)
it throws an exception in my catch.
Any idea what could cause this?

JsonLogOn via https

I've just introduced SSL to my MVC website. I made the whole default AccountContorller use it. It works fine unless I'm currently on http page and try to log on with ajax (the logon action is vredirected to httpS). This popup logon window doesn't even show up.
For the controller a used a custom attribute:
public class RequireSSL : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.ActionDescriptor.IsDefined(typeof(NoSSL), true) ||
filterContext.ActionDescriptor.IsDefined(typeof(OptionalSSL), true))
{
base.OnActionExecuting(filterContext);
return;
}
HttpRequestBase req = filterContext.HttpContext.Request;
HttpResponseBase res = filterContext.HttpContext.Response;
//Check if we're secure or not and if we're on the local box
if (!req.IsSecureConnection && (!req.IsLocal || Properties.Settings.Default.UseSSLForLocalRequests))
{
var builder = new UriBuilder(req.Url)
{
Scheme = Uri.UriSchemeHttps,
Port = Properties.Settings.Default.HttpsPort,
};
res.Redirect(builder.Uri.ToString());
}
base.OnActionExecuting(filterContext);
}
}
How can I make it work?
EDIT
The whole rest was generated by MVC. (Project with built in authentications)
That's the link.
#Html.ActionLink(#Labels.LogOn, "LogOn", "Account", routeValues: null, htmlAttributes: new { id = "logonLink", data_dialog_title = "Identification" })
JS somehow hooks into that link and performs ajax logon . Probably with this code: (JajaxLogin.js - also out of the box)
/// <reference path="jquery-1.6.2.js" />
/// <reference path="jquery.validate.js" />
$(function () {
// Cache for dialogs
var dialogs = {};
var getValidationSummaryErrors = function ($form) {
// We verify if we created it beforehand
var errorSummary = $form.data('validation-summary-errors');
if (!errorSummary) {
errorSummary = $('<div class="validation-summary-errors"><span>Please correct the errors and try again.</span><ul></ul></div>')
.insertBefore($form);
// Remember that we created it
$form.data('validation-summary-errors', errorSummary);
}
return errorSummary;
};
var formSubmitHandler = function (e) {
var $form = $(this);
// We check if jQuery.validator exists on the form
if (!$form.valid || $form.valid()) {
$.post($form.attr('action'), $form.serializeArray())
.done(function (json) {
json = json || {};
// In case of success, we redirect to the provided URL or the same page.
if (json.success) {
location = json.redirect || location.href;
} else if (json.errors) {
var errorSummary = getValidationSummaryErrors($form);
var items = $.map(json.errors, function (error) {
return '<li>' + error + '</li>';
}).join('');
var ul = errorSummary
.find('ul')
.empty()
.append(items);
}
});
}
// Prevent the normal behavior since we opened the dialog
e.preventDefault();
};
var loadAndShowDialog = function (id, link, url) {
var separator = url.indexOf('?') >= 0 ? '&' : '?';
// Save an empty jQuery in our cache for now.
dialogs[id] = $();
// Load the dialog with the content=1 QueryString in order to get a PartialView
$.get(url + separator + 'content=1')
.done(function (content) {
dialogs[id] = $('<div class="modal-popup">' + content + '</div>')
.hide() // Hide the dialog for now so we prevent flicker
.appendTo(document.body)
.filter('div') // Filter for the div tag only, script tags could surface
.dialog({ // Create the jQuery UI dialog
title: link.data('dialog-title'),
modal: true,
resizable: true,
draggable: true,
width: link.data('dialog-width') || 300
})
.find('form') // Attach logic on forms
.submit(formSubmitHandler)
.end();
});
};
// List of link ids to have an ajax dialog
var links = ['logonLink', 'registerLink'];
$.each(links, function (i, id) {
$('#' + id).click(function (e) {
var link = $(this),
url = link.attr('href');
if (!dialogs[id]) {
loadAndShowDialog(id, link, url);
} else {
dialogs[id].dialog('open');
}
// Prevent the normal behavior since we use a dialog
e.preventDefault();
});
});
});

Display image returned as byte array from MVC Controller through Ajax call

When a row in the HTML table is clicked , the ajax call is made to the MVC3 Controller that returns a json object with a byte array of the image , but Empty image getting displayed in the view. This should work from IE 7 TO 9
The controller code is :
[HttpPost]
public ActionResult RenderImage(string code)
{
ImageVM viewmodel = GetImage(code)
return Json(viewmodel.Chart, "image/png");
}
The javascript code for raising the ajax call and display the image is
$(document).ready(function () {
$('#Table tr').click(function (event) {
var id= $(this).attr('id')
$.post("/Gateway/RenderImage", { "code": id },
function (data) {
alert(data);
$('#ChartDiv').html('<img height="200" width="250" src="data:image/png;base64,' + data + '" />');
});
});
});
I changed your code a bit and this is working with me :)
[HttpPost]
public virtual JsonResult RenderImage(string code)
{
//for test data Im using the below, you can use yours : GetImage(code)
var data =
#"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD///+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4Ug9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC";
return Json(data);
}
and in the Javascript (removed one backslash)
$('#Table tr').click(function (event) {
var id = $(this).attr('id')
$.post("Gateway/RenderImage", { "code": id },
function (data) {
alert(data);
$('#ChartDiv').html('<img height="200" width="250" src="data:image/png;base64,' + data + '" />');
});
});
[Edit]
to make the above code work with a png file we can change the controller action to the below:
[HttpPost]
public virtual JsonResult RenderImage(string code)
{
var filePath = "~/Images/PngExampleImag.png";
var ImageBytes = System.IO.File.ReadAllBytes(Server.MapPath(filePath));
var data = Convert.ToBase64String(ImageBytes);
return Json(data);
}

Hide image using Javascript after controller action is complete MVC3

My application has been implemeted using MVC 3, .net.
I am trying to generate an excel file at the click of a button.
The call to the controller action is made using Ajax.
My main problem is: During the file generation i am trying to display an image on the screen to let the user know of the ingoing operation. I can very well display the image but i cannot hide it after the operation is completed. The codei am using is :
Javascript code:
$("input.DownloadExcelReport").click(function (e) {
e.preventDefault();
var parameter = -- code to fetch parameter value;
var outputViewUrl = (the url is created here);
showLoading(); -- This function displays the image
window.location.href = outputViewUrl;
});
Controller Action code:
public ActionResult DownExcelReportForAssortment(Guid parameter)
{
try
{
//the contents for the file generation are fetched here..
// Write contents to excel file
if (memoryStream != null)
{
var documentName = "Report.xls";
byte[] byteArrary = memoryStream.ToArray();
return File(byteArrary, "application/vnd.ms-excel", documentName);
}
}
catch (Exception ex)
{
LogManager.LogException(ex);
}
}
I do not return a Json result to the calling javascript method where i can write the code to hide the image.
I am returning a file which can be saved by the user and the action is completed.
Can somone please suggect/help me of how can i hide the image once the file generation operation is complete?
Appreciate the help...
You may checkout the following article and put this into action. So we start by defining a controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult DownExcelReportForAssortment(Guid parameter, string tokenId)
{
// Simulate some heavy work to fetch the report
Thread.Sleep(5000);
// we fake it
byte[] byteArray = System.IO.File.ReadAllBytes(#"c:\test.xls");
var cookie = new HttpCookie("fileDownloadToken", tokenId);
Response.AppendCookie(cookie);
return File(byteArray, "application/vnd.ms-excel", "report.xls");
}
}
and in the view:
#Html.ActionLink(
"download report",
"DownExcelReportForAssortment",
"Home",
new { parameter = Guid.NewGuid(), tokenId = "__token__" },
new { #class = "download" }
)
Now the last step is to include the jquery.cookie plugin:
<script type="text/javascript" src="#Url.Content("~/scripts/jquery.cookie.js")"></script>
and write a script to subscribe to the click event of the anchor and track the download progress:
$(function () {
var fileDownloadCheckTimer;
$('.download').click(function () {
var token = new Date().getTime();
$(this).attr('href', function () {
return this.href.replace('__token__', token);
});
// Show the download spinner
$('body').append('<span id="progress">Downloading ...</span>');
// Start polling for the cookie
fileDownloadCheckTimer = window.setInterval(function () {
var cookieValue = $.cookie('fileDownloadToken');
if (cookieValue == token) {
window.clearInterval(fileDownloadCheckTimer);
$.cookie('fileDownloadToken', null);
// Hide the download spinner
$('#progress').remove();
}
}, 1000);
});
});

Resources