I have a Razor page with a list of "attachments" I'd like users to be able to "preview". Each "preview" link calls a controller action, which does a database looking, and returns the attachment as an ASP.NET FileStreamResult.
Problem:
When I click on the link, it "downloads" the file. Instead, I need it to display to a new browser tab.
Razor.cshtml:
<a href="@Model.ParseUrl(Model.MSServiceArea.QE042)" target="_blank" >@Model.ParseFileName(Model.MSServiceArea.QE042)</a>
Dynamically generated href:
https://localhost:44342/LifeCycle/Attachments/Download?ModuleName=MSServiceArea&LookupKey=abc
Controller:
public IActionResult OnGet(string ModuleName, string LookupKey)
{
string fileName, mimeType;
Stream stream = Attachment.Download(ctx, null, ModuleName, LookupKey, out fileName, out mimeType);
stream.Position = 0;
var fileStreamResult = new FileStreamResult(stream, mimeType)
{
FileDownloadName = fileName
};
return fileStreamResult;
}
Goal::
I'd like to be able to:
Q: I THOUGHT adding target="_blank"
to my anchor element would be sufficient. What am I missing?
Update
I got PARTIAL success by returning HTML (which now successfully displays in a new browser tab, instead of "downloading" the file). The HTML wraps an element, whose "src" is the original controller, renamed "OnGetDownload()". OnGetDownload() does the DB lookup and returns the binary "attachment" data.
Current problem:
It works fine if the "attachment" happens to be an image file... but DOESN'T work correctly for other file types (e.g. HTML)>
"Old" controller (simply returns the binary attachment data):
public IActionResult OnGetDownload(string ModuleName, string LookupKey)
{
string fileName, mimeType;
Stream stream = Attachment.Download(ctx, null, ModuleName, LookupKey, out fileName, out mimeType);
stream.Position = 0;
var fileStreamResult = new FileStreamResult(stream, mimeType)
{
FileDownloadName = fileName
};
return fileStreamResult;
}
New "Preview" controller (wraps the attachment in static HTML):
public IActionResult OnGetPreview(string ModuleName, string LookupKey)
{
string html = "<html><body><img src=\"URL\" ></body></html>";
string url = "./Download/" + HttpContext.Request.QueryString;
html = html.Replace("URL", url);
return base.Content(html, "text/html");
}
Results:
<a ... target="_blank">
successfully displays the requested attachment in a new browser tab.You can't always control what the browser is doing here; at the end of the day, you're starting to get towards territory that is up to the user and their preferences.
However, you can give the browser hints about what you want to do, and in most cases it will follow them (unless the user has indicated otherwise).
Currently, you're telling the browser to download the file by setting the FileDownloadName
property on FileStreamResult
. Removing this should give you the results you're after (no need for the separate preview controller).
If you want to try to force the browser to preview it despite user settings, you could use your preview method, but use an iframe
instead of an image. As far as I know, there's no absolute guarantee that the browser won't still download the file out of the iframe, but in 99% of cases it should just display.
So, here's a summary of what you need:
<a target="_blank" href="/path/to/handler">
public IActionResult OnGetDownload(string ModuleName, string LookupKey)
{
string fileName, mimeType;
Stream stream = Attachment.Download(ctx, null, ModuleName, LookupKey, out fileName, out mimeType);
stream.Position = 0;
var fileStreamResult = new FileStreamResult(stream, mimeType);
// Notice no initialiser for FileDownloadName
return fileStreamResult;
}
OnGetPreview