Failed to load PDF document in MVC - asp.net-mvc

When I first tested this code it seemed to work just fine, but now I am getting a bug.
Failed to load PDF document
I upload a pdf via my admin function, it goes into a database, and then I have an action in my controller that allows a person to download that pdf when it is clicked on.
However, it doesn't seem to work all the time. I also haven't been able to really identify what is causing it to break. If the file size is over 78 kb it seems that Chrome can't open the document while Firefox/Edge can. If the file is under 75 kb Chrome/IE opens it just fine. I am unsure of why this is happening.
I have included my controller below
public ActionResult DownloadPdf(int Id) {
var dbTest = _testRepository.FindId(Id);
var cd = new System.Net.Mime.ContentDisposition { FileName = dbTest.PdfName, Inline = true };
Response.AddHeader("Content-Disposition", cd.ToString());
return File(dbTest.PdfData, "application/pdf");
}
Here is my View
#if (Model.Test.HasPdf)
{
<a data-bind="css: { disabled: !form() }" href="#Url.Action("DownloadPdf", "Test", new { Id = Model.Test.Id })" target="_blank" id="launchBtn" class="btn btn-pdf">Download PDF Form</a>
}
Has anyone else ever had an error like this? If so, how did you fix it?

I figured it out. It had nothing to do with my download feature, it was in my HTTPPost
if (vm.FileData != null)
{
using (var stream = new System.IO.MemoryStream(vm.FileData.ContentLength\\This code between the parenthesis was missing))
{
vm.FileData.InputStream.CopyTo(stream);
test.FileData = stream.GetBuffer();
test.FileName = vm.FileData.FileName;
}

Supposing that your "dbTest" has a property with the PDF content as byte array (byte[]).
To direct download the file
public ActionResult DownloadPdf(int Id) {
var dbTest = _testRepository.FindId(Id);
Response.ContentType = "application/pdf";
Response.AppendHeader("Content-Disposition", $"filename={dbTest.PdfName}");
Response.AppendHeader("Content-Length", dbTest.PdfData.Length.ToString(CultureInfo.InvariantCulture));
Response.BinaryWrite(dbTest.PdfData);
Response.End();
return null;
}
or to open the file in a new browser tab
public ActionResult DownloadPdf(int Id) {
var dbTest = _testRepository.FindId(Id);
return File(dbTest.PdfData, "application/pdf", dbTest.PdfName);
}
I hope this helps you

Related

How can i download a file from ajax call and force the results do be downloaded

I have post the similar question yesterday and i haven't get the results. I have loaded data on my kendo grid and when i
click download, i want to download the file but it is not returning results. The folder that i am downloading from is on the server not on project solution.
I created a controller to test the download without a button click and it works but i want to download from kendo button click. No error on console
Function for getting the selected Id from the grid
function showDetails(e) {
e.preventDefault();
var dataItem = this.dataItem($(e.currentTarget).closest("tr"));
DownloadIndexController(dataItem.possID);
}
Ajax call to the controller
function DownloadIndexController(possID) {
$.ajax({
url: '#Url.Action("DownloadIndex", "Poss")',
type: "GET",
data: { possID: possID },
dataType: "json",
success: function (data) {
window.location = '#Url.Action("DownloadIndex", "Poss")';
}
})
}
Controller
public ActionResult DownloadIndex(int possID)
{
string Filelocation = "myserverlocation"
FileContentResult ff = null;
try
{
OnePossModel md = new Models.OnePossModel();
JsonParamBuilder myBuilder = new JsonParamBuilder();
myBuilder.AddParam<Guid>("submittingUserID", System.Guid.Parse(User.Identity.GetUserId()));
myBuilder.AddParam<int>("possID", Convert.ToInt32(possID));
string jsonReq = Models.JsonWrapper.JsonPOST(ApiBaseUrl + ApiPOSSSubBaseUrl + "/WritePOSSFile", myBuilder.GetJSonParam());
string possFilename = Models.DeserialiseFromJson<string>.DeserialiseApiResponse(jsonReq);
possFilename = possFilename.Replace(",", ",");
string x = Filelocation + possFilename.ToString();
var type = System.Net.Mime.MediaTypeNames.Application.Octet;
byte[] fileBytes = System.IO.File.ReadAllBytes(x);
string myfileName = possFilename;
ff = File(fileBytes, type,myfileName);
Response.AppendHeader("Content-Disposition", "attachment; filename=" + myfileName);
Response.BinaryWrite(fileBytes);
return ff;
}
catch (Exception ex)
{
throw ex;
}
}
In your controller, just add this:
public FileResult DownloadIndex(int possID)
{
. . . .
return File(fileBytes, type,myfileName);
}
I don't think it can be done the way you are trying to. Take a look here for a workaround to simulate "ajax file download".
In your code you are making 2 requests, the first creates the file and stream it in the response (and cant be downloaded with ajax), and then the second request by setting the window.location - But the file is not "alive" any more since it was allocated to the first response.
If using the FileResult Action then give away the ajax call (depends on your requirements) and just use a plain link: /poss/downloadindex/123

ASP NET MVC and HTML5 audio - file not playing

I am trying to create a table containing audio files, which should start playing when the user clicks the play button. This is what I've tried so far:
Controller:
[HttpGet]
public ActionResult PlayFile(string FilePath)
{
WebClient WC = new WebClient();
WC.Credentials = new System.Net.NetworkCredential("username", "password");
byte[] buff = WC.DownloadData(FilePath);
var SplitFileName = FilePath.Split('\\');
string FileName = "Recording_" + SplitFileName[SplitFileName.Count() - 1];
Response.AddHeader("Content-Disposition", "inline; filename=" + FileName);
MemoryStream stream = new MemoryStream(buff);
return new FileStreamResult(stream, "audio/wav");
//I have also tried:
//return File(buff, "audio/wav");
}
The audio tags look like this:
<td>
<audio controls preload='none'>
<source src='/Components/PlayFile?FilePath=[filename.wav]' type='audio/wav'>
</audio>
</td>
When running the site locally in Chrome, all the files have the length 0:00, and you can click the play button once but the file is not played. After the play button has been clicked once it is not possible to click it again. It is however possible to download the file
and play it. When running the site locally in Firefox, the files also have the length 0:00, and when you click the play button the control disappears. It is also possible to download the file in Firefox. Does anyone know what could be causing this?
The problem was that the audio files were in GSM format and needed to be converted to PCM. This code works:
[HttpGet]
public ActionResult PlayFile(string FilePath)
{
WebClient WC = new WebClient();
WC.Credentials = new System.Net.NetworkCredential("username", "password");
byte[] buff = WC.DownloadData(FilePath);
var SplitFileName = FilePath.Split('\\');
string FileName = "Recording_" + SplitFileName[SplitFileName.Count() - 1];
MemoryStream ms = new MemoryStream();
ms.Write(buff, 0, buff.Length);
ms.Seek(0, SeekOrigin.Begin);
MemoryStream outputStream = new MemoryStream();
using (NAudio.Wave.WaveFileReader reader = new WaveFileReader(ms))
using (NAudio.Wave.WaveStream waveStream = NAudio.Wave.WaveFormatConversionStream.CreatePcmStream(reader))
using (NAudio.Wave.WaveFileWriter waveFileWriter = new WaveFileWriter(outputStream, waveStream.WaveFormat))
{
byte[] bytes = new byte[waveStream.Length];
waveStream.Position = 0;
waveStream.Read(bytes, 0, (int)waveStream.Length);
waveFileWriter.Write(bytes, 0, bytes.Length);
waveFileWriter.Flush();
}
return File(outputStream.ToArray(), "audio/wav");
}
Can you try with below as its working for me.
public FileResult PlayFile(string FilePath)
{
return new FilePathResult(FilePath, "audio/wav");
}
Also, try changing "audio/wav" to "audio/mp3", if it helps.

asp.net mvc 5 sent email attachments are damaged

I am trying to send an email using the method described in this tutorial with a model structure form this tutorial and im partially successfull in doing so. The only issue I am having is the fact that files sent as attachments are damaged. I have tried to get it working in so many ways that I lost count. Obviously haven't been trying hard enough since I didn't find the answer, but decided to ask while I continue looking for an answer.
My controller action is as follows:
public async Task<ActionResult> Index( [Bind(Include = "column names..")] Contact contact, HttpPostedFileBase upload){
if (ModelState.IsValid && status)
{
var message = new MailMessage();
if (upload != null && upload.ContentLength > 0)
{
// 4MB -> 4000 * 1024
const int maxFileSize = 4096000;
if (upload.ContentLength < maxFileSize)
{
var document = new File
{
FileName = System.IO.Path.GetFileName(upload.FileName),
FileType = FileType.Document,
ContentType = upload.ContentType
};
var supportedTypes = new[] {"doc", "docx", "pdf", "jpg"};
var extension = System.IO.Path.GetExtension(document.FileName);
if (extension != null)
{
var fileExt = extension.Substring(1);
if (!supportedTypes.Contains(fileExt))
{
ModelState.AddModelError("document", "Wrong format");
return View();
}
//this is the line that sends damaged attachments,
//I believe I should be using document in some way (using reader bit below),
//but whatever I use the code complains or crashes.
message.Attachments.Add(new Attachment(upload.InputStream, Path.GetFileName(upload.FileName)));
using (var reader = new System.IO.BinaryReader(upload.InputStream))
{
document.Content = reader.ReadBytes(upload.ContentLength);
//message.Attachments.Add(new Attachment(document.Content, document.FileName));
}
contact.Files = new List<File> {document};
}
}else
{
ModelState.AddModelError("document", "File too big. Max 4MB.");
}
}
EDIT: A lot of times the code cannot find the file, how do I make sure I give it correct path each time?

Download file Server Error: The handle is invalid?

public ActionResult FileLink(string hashname)
{
try
{
const string basePath = #"\\WINDHOVERDOCUMENTS\";
const string adminSamples = #"Beta\students\";
return File(basePath + adminSamples + hashname, "application/force-download", hashname);
}
catch (Exception)
{
return null; //no file
}
}
This action simple force user to download the file when the action is triggered. Everything works fine locally. But after publishing to server, it gives me this error. Below is the screenshot. Can anyone help? Thank you. please zoom in to see the screenshot. Sorry.
I solved that by reading the file to byte array then return file content result
var fileBytes = System.IO.File.ReadAllBytes(#"\\path\fileP12.zip");
return File(fileBytes, "application/zip", "package.zip");

Mobile web application: download attachments on iOS

In my mobile web application i have one page within user can view attachments.
The attachment can be any type of file (jpg,png,txt,doc,zip, etc).
The view attachment action is in the form of <a> tag that points to an aspx file that process the request.
HTML:
<a class="attachBtn" href="_layouts/ViewFile.aspx?messageAttachmentInstanceId={some id}"></a>
ViewFile.aspx:
public partial class ViewFile : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
System.IO.BinaryWriter bw = null;
System.IO.MemoryStream ms = null;
System.IO.StreamReader sr = null;
try
{
string contentType = string.Empty;
byte[] content = null;
string fileName = string.Empty;
if (!string.IsNullOrEmpty(Request.QueryString["messageAttachmentInstanceId"]) &&
!string.IsNullOrEmpty(Request.QueryString["messageInstanceId"]))
{
int messageInstanceId = Int32.Parse(Request.QueryString["messageInstanceId"]);
Guid attachmentInstanceId;
GuidUtil.TryParse(Request.QueryString["messageAttachmentInstanceId"], out attachmentInstanceId);
MessageInstance messageInstance = WorkflowEngineHttpModule.Engine.GetService<IMessagingService>()
.GetMessageInstance(messageInstanceId);
if (messageInstance != null)
{
MessageAttachmentInstance attachmentInstnace = messageInstance.Attachments[attachmentInstanceId];
contentType = attachmentInstnace.ContentType;
fileName = attachmentInstnace.FileName;
content = attachmentInstnace.Content;
}
}
this.Response.ContentType = contentType;
string headerValue = string.Format("attachment;filename={0}",
this.Server.UrlPathEncode(fileName));
Response.AddHeader("content-disposition", headerValue);
bw = new System.IO.BinaryWriter(this.Response.OutputStream);
bw.Write(content);
}
catch (Exception ex)
{
LogError("ViewFile.aspx, "
+ ex.InnerException, ex);
}
finally
{
if (sr != null)
sr.Close();
if (ms != null)
ms.Close();
if (bw != null)
bw.Close();
}
}
}
The Problem:
in Android devices when user click on attachment the file is downloaded automatically which is the desirable behavior because the user can open the file later with any tool he wants and even if the file type is not supported user can later on download a tool which can open it.
but in iOS devices the file is not downloaded but instead redirects to ViewFile.aspx and tries to open the file within the browser and if the file type is not supported it shows alert: "safari cannot download this file".
even if the file type is supported i want it to be downloaded and not open by default.
How can i achieve this behavior?
AFAIK, you cannot download files on iOS.
Known files that Safari (or any app that has registered a file type, e.g. ZIP) supports will open or show a dialog letting the user choose how to open the file.
You can't control the behavior from your web app/site.

Resources