4

Controller code:

[HttpGet]
public FileStreamResult GETPDF(string guid)
{
  var stream = XeroHelper.GetXeroPdf(guid).Result;
  stream.Position = 0;
  var cd = new ContentDisposition
  {
     FileName = $"{guid}.pdf",
     Inline = true
  };

  Response.AppendHeader("Content-Disposition", cd.ToString());
  return File(stream, "application/pdf");
}

As you can see the method's name is GETPDF. You can also see that I am configuring the name of the file name in the ContentDisposition header. If you see below, you will see that the method name is used as the title in the toolbar, rather than the file name.

enter image description here

The file name does get perpetuated. When I click "Download" the filename is the default value that is used in the file picker (note i changed the name to hide the sensitive guid):

enter image description here

If anyone has any ideas how to rename the title of that toolbar, it would be greatly appreciated.

As an aside, this is NOT a duplicate of: C# MVC: Chrome using the action name to set inline PDF title as no answer was accepted and the only one with upvotes has been implemented in my method above and still does not work.

Edit- For clarification, I do not want to open the PDF in a new tab. I want to display it in a viewer in my page. This behavior is already happening with the code I provided, it is just the Title that is wrong and coming from my controller method name. Using the controller code, I am then showing it in the view like so:

<h1>Quote</h1>
<object data="@Url.Action("GETPDF", new { guid = @Model.QuoteGuid })" type="application/pdf" width="800" height="650"></object>

Jacob Alley
  • 767
  • 8
  • 34

2 Answers2

0

try something like this:

    [HttpGet]
    public FileResult GETPDF(string guid)
    {
      var stream = XeroHelper.GetXeroPdf(guid).Result;

      using (MemoryStream ms = new MemoryStream())
      {
        stream.CopyTo(ms);

        // Download
        //return File(ms.ToArray(), "application/pdf", $"{guid}.pdf");

        // Open **(use window.open in JS)**
        return File(ms.ToArray(), "application/pdf")
      }           
   }

UPDATE: based on mention of viewer.

To embed in a page you can try the <embed> tag or <object> tag

here is an example Recommended way to embed PDF in HTML?

ie:

<embed src="https://drive.google.com/viewerng/
viewer?embedded=true&url=[YOUR ACTION]" width="500" height="375">

Might need to try the File method with the 3rd parameter to see which works. If the title is set in the filename, maybe this will display as the title. (not sure what a download will do though, maybe set a download link with athe pdf name)

UPDATE 2: Another idea:

How are you calling the url?

Are you specifying: GETPDF?guid=XXXX

Maybe try: GETPDF/XXXX (you may need to adjust the routing for this or call the parameter "id" if this is the default)

Mark Redman
  • 24,079
  • 20
  • 92
  • 147
0

You could do this simply by adding your filename as part of URL:

<object data="@Url.Action("GETPDF/MyFileName", new { guid = @Model.QuoteGuid })" type="application/pdf" width="800" height="650"></object>`

You should ignore MyFileName in rout config. Chrome and Firefox are using PDFjs internally. PDFjs try to extract display name from URL.

According to the PDFjs code, it uses the following function to extract display name from URL:

function pdfViewSetTitleUsingUrl(url) {
  this.url = url;
  var title = pdfjsLib.getFilenameFromUrl(url) || url;
  try {
    title = decodeURIComponent(title);
  } catch (e) {
    // decodeURIComponent may throw URIError,
    // fall back to using the unprocessed url in that case
  }
  this.setTitle(title);
}

function getFilenameFromUrl(url) {
  const anchor = url.indexOf("#");
  const query = url.indexOf("?");
  const end = Math.min(
    anchor > 0 ? anchor : url.length,
    query > 0 ? query : url.length
  );
  return url.substring(url.lastIndexOf("/", end) + 1, end);
}

As you can see this code uses the last position of "/" to find the file name.

The following code is from PDFjs, I don't know why PDFjs doesn't use this instead of getFilenameFromUrl. This code use query string to detect file name and it uses as a fallback to find the file name.

function getPDFFileNameFromURL(url, defaultFilename = "document.pdf") {
  if (typeof url !== "string") {
    return defaultFilename;
  }
  if (isDataSchema(url)) {
    console.warn(
      "getPDFFileNameFromURL: " +
        'ignoring "data:" URL for performance reasons.'
    );
    return defaultFilename;
  }
  const reURI = /^(?:(?:[^:]+:)?\/\/[^\/]+)?([^?#]*)(\?[^#]*)?(#.*)?$/;
  //            SCHEME        HOST         1.PATH  2.QUERY   3.REF
  // Pattern to get last matching NAME.pdf
  const reFilename = /[^\/?#=]+\.pdf\b(?!.*\.pdf\b)/i;
  const splitURI = reURI.exec(url);
  let suggestedFilename =
    reFilename.exec(splitURI[1]) ||
    reFilename.exec(splitURI[2]) ||
    reFilename.exec(splitURI[3]);
  if (suggestedFilename) {
    suggestedFilename = suggestedFilename[0];
    if (suggestedFilename.includes("%")) {
      // URL-encoded %2Fpath%2Fto%2Ffile.pdf should be file.pdf
      try {
        suggestedFilename = reFilename.exec(
          decodeURIComponent(suggestedFilename)
        )[0];
      } catch (ex) {
        // Possible (extremely rare) errors:
        // URIError "Malformed URI", e.g. for "%AA.pdf"
        // TypeError "null has no properties", e.g. for "%2F.pdf"
      }
    }
  }
  return suggestedFilename || defaultFilename;
}
Fred
  • 3,365
  • 4
  • 36
  • 57