I have a Generic Handler (DownloadHandler.cs) which serves as both generating a pdf and downloading a pdf. When generating I use a jQuery ajax call and when downloading I use a form element which is submitted. The problem is that the form element cancels the generate request and therefore the "success" event never gets called (See image below).
Generate code (Gets called from a button):
$.ajax({
type: "POST",
url: "/DownloadHandler.ashx",
data: {
GeneratePdf: true
},
success: function (result) {
console.log(result);
},
error: function (errorMessage) {
console.log(errorMessage);
}
});
Download code (Gets called from a button):
var data = { "GeneratePdf": false }
var inputs = '';
$.each(data, function (key, value) {
inputs += '<input type="hidden" name="' + key + '" value="' + value + '" />';
});
$('<form action="/DownloadHandler.ashx" method="POST">' + inputs + '</form>').appendTo('body').submit().remove();
DownloadHandler:
public void ProcessRequest(HttpContext context)
{
if (!String.IsNullOrEmpty(context.Request["GeneratePdf"]) && Convert.ToBoolean(context.Request["GeneratePdf"]))
{
Thread.Sleep(3000);
context.Response.Clear();
context.Response.Write("GENERATING");
context.Response.Flush();
}
else
{
Thread.Sleep(3000);
FileInfo pdfFile = new FileInfo(#"C:\1.pdf");
context.Response.Clear();
context.Response.AddHeader("Content-Disposition", "attachment; filename=" + pdfFile.Name);
context.Response.AddHeader("Content-Length", pdfFile.Length.ToString());
context.Response.ContentType = "application/octet-stream";
context.Response.WriteFile(pdfFile.FullName);
context.Response.Flush();
}
}
public bool IsReusable
{
get
{
return false;
}
}
I just added a Thread.Sleep to demonstrate the generation of the pdf. Am I missing something or should I use some other method?
Maybe you can try targetting a tiny dynamic iframe on your page with your form. Something like :
var data = { "GeneratePdf": false }
var inputs = '';
$.each(data, function (key, value) {
inputs += '<input type="hidden" name="' + key + '" value="' + value + '" />';
});
var f = $('<form action="/DownloadHandler.ashx" method="POST">' + inputs + '</form>');
var iframe = $('<iframe src="about:blank"/>') // should be made tiny/transparent with some css
.appendTo('body');
iframe.contents().find('html').append(f);
f.submit().remove();
Related
Fiddled with every imaginable combination of webapi controller and jquery ajax script which, when debugging, does make a get call to the controller, but it won't parse the data (in debug, the data is there!). PostMan and typing URL into browser works perfectly, so I believe there is (yet another) trick to get jquery.ajax to work.
the WebAPI controller method (which works):
namespace SearchWebsite.Controllers
{
public class MoreInfoController : ApiController
{
private string DBConnStr;
public MoreInfoController()
{
DBConnStr = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
LiveItem_Data.DBConnStr = DBConnStr;
}
[Route("api/getmoreinfo/{lid}")]
[HttpGet]
public async Task<IHttpActionResult> GetMoreInfo(string lid)
{
var retval = new AppCore.MoreInfo();
if (lid.Length == 36)
{
if (IsGUID(lid))
{
retval = await LiveItem_Data.GetMoreInfoAsync(lid);
}
}
return Ok(retval);
}
}
}
And I get the expected results when I call it via postman or the browser, like so:
https://localhost:44371/api/getmoreinfo/2A116FF3-E6C8-4EE3-88E5-99001DCCE36A
The jquery ajax method:
$(".popInfo").bind("click", function (e) {
var ListID = $(this).parent().parent().find('[id*=hidlid]').val();
$.ajax({
type: "get",
url: "../../api/GetMoreInfo/" + ListID,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) {
try {
var mi = jQuery.parseJSON(data);
var img = "";
if (mi.IMGLNK != "") { img = "<img src='" + mi.IMGLNK + "' class='img-responsive' />"; }
var title = "<a href='redir?lid=" + ListID + "' target='_blank' >" + mi.NAME + "</a>";
var btnV = "<a href='redir?lid=" + ListID + "' target='_blank' class='btn btn-success' ><span class='glyphicon glyphicon-shopping-cart'></span> Visit Website</a>";
var btnR = '</span> Report Problem';
var details = "<p><p>SKU: " + mi.SKU + "</p><p>MPN: " + mi.MPN + "</p><p>UPC: " + mi.UPC + "</p><p>Ship Weight: " + mi.WT + " lbs</p><p>Last Updated: " + formatJSONDate(mi.MD) + "</p></p>"
$('#moreinfo').find('.modal-title').html(title);
$('#moreinfo').find('.modal-body').html(img + '<p class="descr">' + mi.DESC + '</p>' + details);
$('#moreinfo').find('#btnVisit').html(btnV);
$('#moreinfo').find('#btnReport').html(btnR);
$('#moreinfo').off().modal('show');
} catch (e) {
alert("ERROR:" + e + " data: " + data + " mi: " + mi);
}
},
error: function (err) {
alert("error: " + err);
}
});
});
the try catch and alerts are for troubleshooting, however even though the data is in the data variable while stepping through and debugging, the "data" becomes undefined immediately after using parseJSON(), and, naturally, the variable "mi" is undefined as well and the error I trapped is "SyntaxError: Unexpected token u in JSON at position 0 data: [object Object]".
I'm at a loss as how to remedy this issue. (note: I am in the process of converting old ASMX services into MVC5 WebAPI 2.1 services, so DotNetCore answers won't work as it's a completely different beast, as is MVC4 and below)
In my GridView in C# ASP.NET 4 I insert a button to edit the row of GridView that open a new webpage on the browser in this mode
protected void btn1_Click(object sender, EventArgs e)
{
ImageButton btn1 = (ImageButton)sender;
GridViewRow row = (GridViewRow)btn.NamingContainer;
int oID = Convert.ToInt32(gv.DataKeys[row.RowIndex].Values[0]);
string queryString = "newpage.aspx?oID=" + oID.ToString();
string newWin = "window.open('" + queryString + "','_blank');";
ClientScript.RegisterStartupScript(this.GetType(), "pop", newWin, true);
}
The newpage.aspx use Ajax and JSON for save an image on the server and close window in this mode
<script type="text/javascript">
$(function () {
$("#btnSave").click(function () {
var image = document.getElementById("cc").toDataURL("image/png");
image = image.replace('data:image/png;base64,', '');
var qString = "?" + window.location.href.split("?")[1];
$.ajax({
type: 'POST',
url: 'newpage.aspx/oImage' + qString,
data: '{ "imageData" : "' + image + '" }',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: function (msg) {
alert('Ok');
window.close();
},
failure: function (msg) {
alert(response.d);
},
error: function (msg) {
alert(response.d);
},
error: function (xhr, ajaxOptions, thrownError) {
alert("error : " + thrownError + JSON.stringify(image));
}
});
});
});
</script>
Now i need refresh the Gridview after closing window
I have tried withous success these single solution, but the parent page with the GridView is not refreshed and the edited row is always available
window.opener.location.reload(true);
window.close();
Or
parent.location.reload(true);
window.close();
Or
location.href = 'gv.aspx' + qString;
window.close();
Or
window.location.replace("gv.aspx")
window.close();
Or
window.location = result.getResponseHeader('gv.aspx');
window.close();
Any suggestion?
Thanks for help.
code-behind
[WebMethod()]
public static void oImage(string imageData)
{
string folderLocation = path + "\\" + DateTime.Now.ToString("ddMMyyyy") + "\\";
bool exists = Directory.Exists(folderLocation);
if (!exists)
{
Directory.CreateDirectory(folderLocation);
}
string fileNameWitPath = folderLocation +
Guid.NewGuid() + "_" + DateTime.Now.ToString("ddMMyyyyHHmmss") + ".png";
mtsp(fileNameWitPath);
using (FileStream fs = new FileStream(fileNameWitPath, FileMode.Create))
{
using (BinaryWriter bw = new BinaryWriter(fs))
{
byte[] data = Convert.FromBase64String(imageData);
bw.Write(data);
bw.Close();
}
}
}
I am adding some html/css in div.InnerHtml by applying foreach loop reading each directory contents to post images, and i want to call function showfile(dynamic parameter) into it.
how should i do this?
the showfiles(dynamic parameter) function is working fine, but i want to make it work after user clicks the controls generated in div, which is not working, please have a look on my code and give me suggestion.
public void Showimages( string fname)
{
string name = Path.GetFileName(fname); //select only name.ext
str2 = "<div style='max-width:250px; max-height:170px;'>"
+ "<a href ='" + filepath2 + "/" + name + "' >"
+ "<img class='img-responsive' src='" + filepath2 + "/" + name + "'>"+name+"</a></div>"; //post image + name in loop
imgcontainer.InnerHtml += str2;
}
public void Generatecontrol(string dp)
{
//linkdiv.InnerHtml += "<asp:LinkButton runat='server' class='linkb' OnClick='Showfiles(" + dp.ToString()+ ")' >" + dp.ToString() + "</asp:LinkButton><br />";
linkdiv.InnerHtml += "<span class='col-lg-4'><asp:LinkButton runat='server' class='col-lg-4 linkb' OnClick='Showfiles' CommandArgument=" + dp.ToString()+ " ><img src='/pimages/folder.jpg' height='75' width='75' border='0'/><br />" + dp.ToString() + "<br /></asp:LinkButton></span>";
}
See you are passing the value as CommandArgument, so you have to take the same from CommandArgument. Change the signature of Showimages like the following:
public void Showimages(object sender, CommandEventArgs e)
{
string name = Path.GetFileName(e.CommandArgument.ToString());
// your code here
}
Pritesh,
If your main concern is only displaying images dynamically, then you can use jquery, here below I prepared a small snippet, please look at once,
Backend code:
public List<string> GetImages()
{
string fileName = "";
string[] files = System.IO.Directory.GetFiles("");
List<string> listImages = new List<string>();
foreach (string file in files)
{
fileName = System.IO.Path.GetFileName(file);
listImages.Add(fileName);
}
return listImages;
}
HTML:
<div class="row" style="margin-top:20px;">
<div id="imgPreview"></div>
</div>
<button id="btnShowImage" onclick="ShowImages()">Show Image</button>
Jquery
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
$(document).ready(function () {
function ShowImages() {
$("#imgPreview").html("");
$.ajax({
type: 'post',
url: '/xyz/GetImages',
data: formData,
success: function (response) {
if (response != null) {
var imageList =DisplayImages(response);
$("#imgPreview").append(imageList);
}
},
processData: false,
contentType: false,
error: function () {
alert("Whoops something went wrong!");
}
});
}
)};
function DisplayImages(data) {
var imageDiv ="";
if (data != null) {
$.each(data, function (index, value) {
//This is for dynamically generating image div. You can manipulate this section as per you need.
imageDiv = "<div style='max-width:250px; max-height:170px;'>";
imageDiv += "<a href ='~/your static path/" + value + "' >";
imageDiv += "<img class='img-responsive' src='='~/your static path/" + value + "'>" + value + "</a></div>";
});
}
return imageDiv;
}
</script>
Let me know if it helped.
The table rows are generated at page load using ajax as shown below.
$.ajax({
url: '/consultation/GetPrescHistoryList',
type: 'POST',
data: $('#frmPrescHistoryTable').serialize(), // it will serialize the form data
//dataType: 'json',
success: function (data) {
var rowNo = 0;
for (var i = 0; i < data.length; i++) {
rowNo += 1;
$("#LoadPrescHistoryTable tbody").append("<tr Class='odd gradeX'>" +
"<td>" + rowNo + "</td>" +
"<td>" + data[i].description + "</td>" +
"<td>" + data[i].UserName + "</td>" +
"<td><button type='button' class='repeat btn btn-default' data-id='" + data[i].dgid + "'>Repeat</button></td>" +
"</tr>");
}
alert('LoadPrescHistoryTable has been loaded.');
},
error: function () {
alert('Ajax Submit Failed ...');
}
}); // end ajax
var baseUrl = '#Url.Action("GetPrescDetailsObj", "consultation")';
$("#LoadPrescHistoryTable tbody").on('click', '.repeat', function () {
location.href = baseUrl + '?dgid=' + $(this).data('id');
});
I wanted so that when i click on repeat button in the table row, the details from the chosen id will display in a label and textbox in the same page. How can i replace the location.href in order to not redirect the data, but to simply show the data that was called to the textbox and label?
$('#btnPrescRepeat').on('click', function (e) {
e.preventDefault(); // Prevent Default Submission
$.ajax({
url: '/consultation/GetPrescDetailsObj',
type: 'POST',
data: $('#frmBtnPrescRepeat').serialize(), // it will serialize the form data
dataType: 'json',
success: function (data) {
$('#PHOtherInstruction').val(data.remarks);
$('#tradename').val(data.tradename);
},
error: function () {
alert("something seems wrong");
}
}); // ajax
}); // #btnPrescRepeat
Below is the controller which is used to pass the objects back to the view, one in textbox and another in label.
public ActionResult GetPrescDetailsObj(string dgid)
{
PrescriptionVM Prescription = new PrescriptionVM();
PatientLookupVM Patient = new PatientLookupVM(Prescription);
Patient.LoadDrugObj = Prescription.GetDrugObj(dgid);
dynamic data = new
{
tradename = Patient.LoadDrugObj.tradename,
remarks = Patient.LoadDrugObj.remarks
};
return Json(data, JsonRequestBehavior.AllowGet);
}
When i click the repeat button, the page is replaced with an array of data that i called. Can anyone please tell me what am i doing wrong?
I want to upload a image with a description like:
data = '{"filename":"' + myfilename + '", "file":"' + file + '", "description":"' +
description + '"}';
$.ajax({
type: "POST",
url: "filehandler.ashx",
data: data,
success: function (result) {
alert(result);
},
error: function () {
alert("There was error uploading file!");
}
});
how can I do it? I can't read file as HttpPostedFile in generic handler.
context.Request.Form also doesn't have any keys.
I'm sorry, If I not posted fully what I did in question. Anyway I got it to work.
var data = new FormData();
data.append("name", filename);
data.append("file", file);
In generic handler
HttpPostedFile file = context.Request.Files["file"];
string fileName = context.Request.Form["filename"];
Using FormData Objects
you cant post files with ajax you have to post it in a iframe to have the same result
this is what I did
var form = "#myform";
var url = "http://post.it/";
var iframeName = 'iframePost' + (new Date()).getTime();
$('<iframe id="'+iframeName+'" name="' + iframeName + '" style="display:none;"/>').appendTo('body');
$(form).attr('target',iframeName)
.attr('action',url)
.attr('enctype','multipart/form-data')
.append('<input type="hidden" name="_iframe" value="' + iframeName + '" />');
form.submit();
to have a callback let the iframe return a script with something like
window.parent.callBack(data);