1

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>&nbsp;

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:

  • Have the user click on a link in a Razor page, then
  • Read an "attachment" (of some arbitrary MIME type) from a database, and finally
  • Display it to the user in a new browser tab

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:

  • .png, .gif, etc.: <a ... target="_blank"> successfully displays the requested attachment in a new browser tab.
  • *.pdf, *.html, etc: brings up a new browser tab, but displays "broken image" icon instead of the attachment.
FoggyDay
  • 11,962
  • 4
  • 34
  • 48
  • You want to navigate in a new browser : https://www.c-sharpcorner.com/UploadFile/de41d6/navigation-techniques-in-Asp-Net/?force_isolation=true – jdweng May 30 '23 at 17:23
  • @jdweng - I appreciate the suggestion: thank you. But I'm not sure how it helps me a) click on a link in a Razor page, then b) read an "attachment" (of some arbitrary MIME type) from a database, and finally c) display it to the user in a new browser tab. Please clarify. – FoggyDay May 30 '23 at 19:20
  • Maybe you can put `attachments` into `iframe` then show in the new tab. – Xinran Shen May 31 '23 at 01:36

1 Answers1

2

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">
  • Your modified 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;
}
  • Remove OnGetPreview
brads3290
  • 1,926
  • 1
  • 14
  • 20
  • You're exactly right. The whole whole problem was adding "FileDownloadName = fileName" to the ASP.NET FileStream object. Once I removed it: everything worked perfectly! Thank you! – FoggyDay May 31 '23 at 03:22