Generate PDF then Print C# - c#

After calling API to get data, I need to generate the PDF file to PRINT using the default available.
Currently, Im able to get the data but then PDF not generated or downloaded.
AJAX codes to call controller to process request.
$(document).on('click', '#RePrint', function (event) {
var checkedVals = $('.ExportOrder:checkbox:checked').map(function () {
var orderId = this.value;
var status = document.getElementById(orderId).innerText;
if (status != "Received")
{
return this.value;
}
}).get();
if (checkedVals.length > 0) {
$.ajax({
url: '/Orders/RePrintLabel',
type: 'POST',
data: { ExportOrder: checkedVals },
dataType: "json",
async: true
});
}
});
Controller:
public ActionResult RePrintLabel(string[] ExportOrder)
{
var orders = ExtractOrders(ExportOrder, "Reprint");
if (orders.Count() > 0)
{
foreach (var item in orders)
{
var label = _orderMgr.RePrintLabel(item);
//Generate PDF For Label
if (label != null)
{
if (label.success)
{
byte[] byteContent = label.labels[0];
MemoryStream pdf = new MemoryStream(byteContent);
Response.Clear();
Response.ContentType = "application/pdf";
string pdfName = label.order_number;
Response.AddHeader("Content-Disposition", "attachment; filename=" + pdfName + ".pdf");
Response.ContentType = "application/pdf";
Response.Buffer = true;
Response.Cache.SetCacheability(System.Web.HttpCacheability.NoCache);
Response.BinaryWrite(byteContent);
Response.End();
Response.Close();
}
}
}
}
return RedirectToAction("Export");
}
The data is successfully returned and able to execute until this code Response.Close(); pdf was not downloaded or displayed to print.
Is there a way that I could automatically print the PDF file right after it is generated or the data is returned successfully using a default printer?
Thank you in advance for your help. Really appreciated.

Related

how to allow file download in asp.net from dynamically generated table

I am using elasticsearch to query in index of PDFs on a asp.net mvc app. When I get the result I would like the user to be able to click the returned filename to download that file. Researching how to enable this functionality has returned plenty of results but none seem to work for me. I would simply like the user to be able to click on the filename and have the file download for them. I am using the below code.
To generate the dynamic table with search results
var row = $("<tr><th>" + "Search Results" + "</th><th>" + "File Name" + "</th>");
$("#myTable").append(row);
for (var i = 0; i < response.datasend.length; i++) {
var pos = response.datasend[i].Attachment.Content.indexOf(obj.searchterm);
var row = $("<tr><td>" + response.datasend[i].Attachment.Content.slice((pos - 100), (pos + 100)) + "</td><td><a href=# id=fileName>"
+ response.datasend[i].filename + "</a></td></tr>");
$("#myTable").append(row);
}
To detect the requested filename and call the function to start the download process
var table = document.getElementById("myTable");
table.addEventListener("click", function(e) {
if (e.target && e.target.id == "fileName")
{
var apiUrl = "/AllSearch/Download";
var obj = {};
obj.searchterm = e.target.innerHTML;
var params = e.target.innerHTML;
$.ajax({
contentType: 'application/json',
url: apiUrl,
dataType: "json",
data: {fileName: obj.searchterm},
success: function(data) {
alert("success");
},
error: function (xhr, err) {
alert("ready state: " + xhr.readyStat + " " + xhr.status);
}
});
}
});
To start download the file
public ActionResult Download(string fileName)
{
string filename = fileName;
string filePath = #"C:;at\to\file\Documents\" + fileName;
byte[] filedata = System.IO.File.ReadAllBytes(filePath);
string contentType = MimeMapping.GetMimeMapping(filePath);
var cd = new System.Net.Mime.ContentDisposition
{
FileName = filename,
Inline = true,
};
Response.AppendHeader("Content-Disposition", cd.ToString());
return File(filedata, contentType);
}
The Download function is from Returning a file to View/Download in ASP.NET MVC but it returns an error when I run it. Not sure what I am missing here. Any help is appreciated

Why downloading a file throws multiple disposition error ?

I am using a webgrid and I have put a download button inside it to download a file from the grid.
But it throws an error: localhost sent an invalid response.
ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION
[HttpGet]
public ActionResult DownloadStories()
{
string filename = "saddam.png";
string filepath = Server.MapPath("~/UploadedFiles/") + filename; //AppDomain.CurrentDomain.BaseDirectory + "/UploadedFiles/" + filename;
byte[] filedata = System.IO.File.ReadAllBytes(filepath);
string contentType = MimeMapping.GetMimeMapping(filepath);
var cd = new System.Net.Mime.ContentDisposition
{
FileName = filename,
Inline = true,
};
// Response.AppendHeader("Content-Disposition", cd.ToString());
Response.AddHeader("Content-Disposition", "attachment;filename=\"" + filename + "\"");
return File(filedata, contentType, cd.FileName);
}
View:
WebGrid wgImages = new WebGrid(listData, rowsPerPage: 20);
#wgImages.GetHtml(tableStyle: "table table-condensed table-bordered table-striped table-responsive",
columns: wgImages.Columns(
wgImages.Column
(columnName: "Image", header:"Image"),
wgImages.Column
(columnName:"Story", header: "Story"),
wgImages.Column
(columnName:"Image", header:"Download", format: (testItem)=> Html.ActionLink("Download", "DownloadStories", "Stories")
))
);
}
I have tried the code which I have commented now and that doesn't work too.
Why not use simple HTML & JAVASCRIPT TO download the file by making an ajax call
1. Call this funcation by ajax post
[HttpPost]
public JsonResult DownloadStories(String someParamsIfany)
{
//do your thing
return Json(file,JsonRequestBehavior.AllowGet);
}
2. create an Img file with the data & download it on Html Side
$.ajax({
type: "POST",
url: '/Home/DownloadStories',
data: {someParamsIfany :someParamsIfany},
success: function (result) {
DownLoadTheFile(result);
}
});
3 now function DownLoadTheFile
function DownLoadTheFile(file){
var a = document.createElement('a');
a.href = file.filepath ;
a.download = file.filename;
a.click();
}

WCF REST Downloading pdf with jquery

I'm trying to download a pdf file from a WCF REST service, using jquery ajax call but I think there's an encoding issue.
Here's the service interface method definition
[OperationContract]
[WebInvoke(
BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Json,
RequestFormat = WebMessageFormat.Json,
Method="POST",
UriTemplate = "DownloadFile")]
Stream DownloadFile(RequestDownloadFile fileDownload);
and then the implementation
public Stream DownloadFile(RequestDownloadFile fileDownload)
{
DBCepPortaleEntities cepPortale = CEP.DAL.DbConnections.GetConnessionePortale(ConnString); //connection with entity framework to SQLServer DB
var cerco = from cc in cepPortale.WEB_DOCUMENTI
where cc.IdDocumento == fileDownload.ID
select cc; //retrieving a Pdf VARBINARY Field
if (cerco.Count() > 0)
{
WEB_DOCUMENTI doc = cerco.First();
String nomeFile = #"test.pdf";
String tmp = Encoding.Default.GetString(doc.DocPDF);
File.WriteAllText(nomeFile, tmp, Encoding.Default);//test: pdf file is written correctly and I can read it
WebOperationContext.Current.OutgoingResponse.ContentType = "application/pdf";
WebOperationContext.Current.OutgoingResponse.Headers.Add("Content-disposition", "inline; filename=circolare" + fileDownload.ID + ".pdf");
WebOperationContext.Current.OutgoingResponse.Headers.Add("Content-Transfer-Encoding", "binary");
WebOperationContext.Current.OutgoingResponse.Headers.Add("Content-Encoding", "none");
FileStream f = new FileStream(nomeFile, FileMode.Open);
int length = (int)f.Length;
WebOperationContext.Current.OutgoingResponse.ContentLength = length;
byte[] buffer = new byte[length];
int sum = 0;
int count;
while ((count = f.Read(buffer, sum, length - sum)) > 0)
{
sum += count;
}
f.Close();
return new MemoryStream(buffer);
}
else
return null;
}
This method write correctly the pdf file called "test.pdf".
Now I'm trying to consume it with a ajax call:
$.ajax({
method: "POST",
url: "http://testwcfcircolari.bresciapaghe.it/Service.svc/DownloadFile",
data: '{"Token":"abc", "ID":"20"}',
contentType: "application/json",
success: function (response, status, xhr) {
console.log(response);
//self.settings.onSuccessStart(response, status, xhr, self);
// Check if a filename is existing on the response headers.
var filename = "";
var disposition = xhr.getResponseHeader("Content-Disposition");
if (disposition && disposition.indexOf("attachment") !== -1) {
var filenameRegex = /filename[^;=\n]*=(([""]).*?\2|[^;\n]*)/;
var matches = filenameRegex.exec(disposition);
if (matches != null && matches[1])
filename = matches[1].replace(/[""]/g, "");
}
filename = "prova.pdf";
var type = xhr.getResponseHeader("Content-Type");
var blob = new Blob([response], { type: "application/pdf; charset=UTF-8" });
if (typeof window.navigator.msSaveBlob !== "undefined") {
// IE workaround for "HTML7007: One or more blob URLs were revoked by closing the blob for which they were created. These URLs will no longer resolve as the data backing the URL has been freed.
window.navigator.msSaveBlob(blob, filename);
} else {
var URL = window.URL || window.webkitURL;
var downloadUrl = URL.createObjectURL(blob);
alert(filename);
if (filename) {
// Use HTML5 a[download] attribute to specify filename.
var a = document.createElement("a");
// Safari doesn"t support this yet.
if (typeof a.download === "undefined") {
window.location = downloadUrl;
} else {
a.href = downloadUrl;
a.download = filename;
document.body.appendChild(a);
a.click();
}
} else {
window.location = downloadUrl;
}
//console.log(downloadUrl);
setTimeout(function () {
URL.revokeObjectURL(downloadUrl);
}, 100); // Cleanup
}
// Final custom event.
//self.settings.onSuccessFinish(response, status, xhr, self, filename);
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert('Error occurred while opening fax template' + XMLHttpRequest + " " +
+textStatus + " " + errorThrown);
}
});
The result is a pdf file that have the same page of the original, but the content is all blank.
Watching with a text editor content of the downloaded pdf, it's different from the starter file.
Any suggestion?
Thank you.
C#
String[] filename=filepath.Split('\\');
WebOperationContext.Current.OutgoingResponse.ContentType = "application/octet-stream";
if(File.Exists(filepath)
{
String header = "attachment; filename=" + filename[filename.Length - 1];
WebOperationContext.Current.OutgoingResponse.Headers["Content-Disposition"] = header;
return File.OpenRead(filepath);
}
JS
function downloadfile(filepath)
{
var url="https://myfile.ololo?v="+filepath;
window.open(url,"windowname","width:400,height:300");
}
binding
<bindings>
<webHttpBinding>
<binding name="MyWcfRestService.WebHttp" maxBufferSize="2147483637"
maxBufferPoolSize="2147483637"
maxReceivedMessageSize="2147483637"
transferMode="Streamed"
sendTimeout="00:05:00">
<readerQuotas maxDepth="2147483637"
maxStringContentLength="2147483637"
maxArrayLength="2147483647"
maxBytesPerRead="2147483647"
maxNameTableCharCount="2147483637"/>
<security mode="None" />
</binding>
</webHttpBinding>
</bindings>

Download a file using angularjs, asp.net

I'm trying to download an excel file (generated on the fly) on a button click. The functionality works fine when the code is placed server side (Reports.aspx.cs) and there is a postback on the button click.
But, now, the front-end technology is Angular. So no postbacks. Tried to use the same download code in a handler and the download doesnt occur. No Save prompts, no errors. The breakpoint hits the handler.cs though.
Reports.aspx:
<button type="button" data-ng-click="DownloadExcelReport()">Download Report</button>
ReportsCtrl.js --controller
$scope.DownloadExcelReport = function () {
ReportsFactory.DownloadReport($scope.ReportId,$scope.SetId);
}
ReportsFactory.js --service
factory.DownloadReport = function (reportId, setId) {
return $http({
url: "http://localhost:62102/download.ashx?reportId=" + reportId + "&setId=" + setId,
method: "GET"
}).success(function (data, status) {
}).error(function (data, status) {
});
}
download.ashx.cs --handler
public void ProcessRequest(HttpContext context)
{
int reportId = Convert.ToInt32(context.Request.QueryString["reportId"]);
int setId = Convert.ToInt32(context.Request.QueryString["setId"]);
switch (reportId)
{
case 1:
DataTable dt = GetData(reportId, setId);
if (dt != null)
{
string FileName = "Responses";
ExportExcel obj = new ExportExcel();
obj.showGridLines = true;
obj.headerStyle = new Style(Color.SlateGray, Color.White, Color.SlateGray, ExcelBorderStyle.Thin);
MemoryStream ms = obj.GenerateDocument(dt);
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment; filename=\"" + FileName + ".xlsx" + "\"");
HttpContext.Current.Response.BinaryWrite(ms.ToArray());
HttpContext.Current.Response.Flush();
HttpContext.Current.Response.End();
}
break;
}
}
EDIT:
I have later been taught that, when using Javascript to download, the approach is different.You create a form and then submit the form with parameters. I have added the working solution.
This might help someone.
ReportsFactory.js --service
factory.DownloadReport = function (reportId, setId) {
var form = document.createElement("form");
form.action = "http://localhost:62102/download.asmx/DownloadReport";
form.method = "POST";
form.target = "_self";
var input = document.createElement("input");
input.type = "text";
input.name = "params";
input.value = reportId + "," + setId;
form.appendChild(input);
form.style.display = 'none';
document.body.appendChild(form);
form.submit();
};
Using a asmx file now instead of handler.
download.asmx.cs
[WebMethod]
public void DownloadReport()
{
string[] Params = Convert.ToString(HttpContext.Current.Request.Form["params"]).Split(',');
string FileName = "Reports_";
int reportId = Convert.ToInt32(Params[0]);
int setId = Convert.ToInt32(Params[1]);
DataTable dt = GetData(reportId,setId);
ExportExcel obj = new ExportExcel();
MemoryStream ms = obj.GenerateDocument(dt);
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment; filename=\"" + FileName + ".xlsx" + "\"");
HttpContext.Current.Response.BinaryWrite(ms.ToArray());
HttpContext.Current.Response.Flush();
HttpContext.Current.Response.End();
}

Export to Excel not working

Having some trouble exporting to downloadable Excel content, using AngularJS & ASP.NET MVC. My end results is nothing happens.
Sample ASP.NET Controller method:
[HttpPost]
public ActionResult ExportToExcel(Model form)
{
var gv = new GridView();
gv.DataSource = _service.getSomeStuff(form);
gv.DataBind();
Response.ClearContent();
Response.Buffer = true;
Response.AddHeader("content-disposition", "attachment; filename=Stuff.xls");
Response.ContentType = "application/ms-excel";
Response.Charset = "";
var sw = new StringWriter();
var htw = new HtmlTextWriter(sw);
gv.RenderControl(htw);
Response.Output.Write(sw.ToString());
Response.Flush();
Response.End();
byte[] temp = System.Text.Encoding.UTF8.GetBytes(sw.ToString());
return File(temp, "application/ms-excel");
}
Angular Controller Method: -> triggered via ng-click handler
function exportToExcel() {
$http.post('/Controller/ExportToExcel/', vm.Model)
.success(function (data) {
})
.error(function (data) {
alerts.error(data);
});
}
View:
click me
Any suggestions of what I might be doing wrong?
I have done something like this, without the need for AJAX or any JS. Tweaking the Razor code is all that is required.
Secondly, my personal suggestion would be to not convert to Excel file at all. The reason being, the user is required to have Office on his local machine. It also means, should you upload your project to a website, that server machine will need Office installed in order to produce your excel file.
That being said, I would suggest just using a CSV file. If a user has Office installed, they would be able to use Excel to view the file like any spreadsheet.
Here is some code that will create a CSV called Export.csv from a dbset in your dbcontext, done using StringBuilder and Reflection.
public ActionResult Export()
{
StringBuilder str = new StringBuilder();
var tmp = db.Users.FirstOrDefault();
Type comp = tmp.GetType(); // get type
foreach (PropertyInfo prop in comp.GetProperties())
{
str.Append(prop.Name + ","); //set column names
}
str.Replace(",", "\n", str.Length - 1, 1);
foreach (object item in db.Users)
{
foreach (PropertyInfo prop in item.GetType().GetProperties())
{
try
{
string a = prop.GetValue(item, null).ToString();
str.Append(a + ",");
}
catch (NullReferenceException)
{
str.Append("null" + ","); //for nulls, append string with "null"
}
}
str.Replace(",", "\n", str.Length - 1, 1);
}
string csv = str.ToString();
return File(new System.Text.UTF8Encoding().GetBytes(csv), "text/csv", "Export.csv");
}
You can then access download the file with a link on your view like this:
click me
Hope this helps.

Categories