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>
Related
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
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.
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();
}
I have an AJAX file upload by call to MVC C# driver, but the browser refreshes and reloads the page.
But if I comment the line that saves the file in the driver does not happen that is only when the file is saved on the server. File.SaveAs (fname);
MVC controller:
[HttpPost]
public ActionResult UploadDocument()
{
if (Request.Files.Count > 0)
{
try
{
FileUpdateDto fileModal = new FileUpdateDto();
HttpFileCollectionBase files = Request.Files;
for (int i = 0; i < files.Count; i++)
{
HttpPostedFileBase file = files[i];
string fname;
DirectoryInfo directory = new DirectoryInfo(Server.MapPath("~/Content/Document/" + UserId).ToString());
if (!directory.Exists)
{
Directory.CreateDirectory(Server.MapPath("~/Content/Document/" + UserId).ToString());
}
if (Request.Browser.Browser.ToUpper() == "IE" || Request.Browser.Browser.ToUpper() == "INTERNETEXPLORER")
{
string[] testfiles = file.FileName.Split(new char[] { '\\' });
fname = testfiles[testfiles.Length - 1];
}
else
{
fname = file.FileName;
}
var guidnew = Guid.NewGuid();
fname = Path.Combine(Server.MapPath("~/Content/Document/" + UserId), guidnew + "." + fname.Split('.')[1].ToString());
fileModal.FileName = fname;
fileModal.Path = directory.ToString();
fileModal.DateFileUpload = DateTime.Now;
file.SaveAs(fname); // If I comment this line without refreshing the browser but does not save the file
}
return Json(fileModal);
}
catch (Exception ex)
{
return Json("Error occurred. Error details: " + ex.Message);
}
}
else
{
return Json("No files selected.");
}
}
Call Ajax in JavaScript:
UploadDocument: function () {
if (window.FormData !== undefined) {
var fileUpload = $("#AdviserFileUpload").get(0);
var files = fileUpload.files;
var fileData = new FormData();
for (var i = 0; i < files.length; i++) {
fileData.append(files[i].name, files[i]);
}
//fileData.append('username', 'Manas');
$.ajax({
url: site.baseUrl + '/Api/Upload/Document',
type: "POST",
contentType: false,
processData: false,
data: fileData,
success: function (result) {
__this._AdviserDocumentFile = result;
},
error: function (err) {
alert(err.statusText);
}
});
} else {
alert("FormData is not supported.");
}
}
I believe I found the solution. The cause is that Visual Studio's "Enable Reload on Save" property is True.
Go to Tools - Options - Web - Browser Reload on Save - Enable Reload on Save and make it false.
Im working with VS2015 and this worked for me, hope it works for you too.
Source
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();
}