Saturday 3 April 2021

Delivering files to the Browser

Sometimes you want to embed files in a browser, such as images or PDF files.

With modern browsers it is easy to just add some HTML to display a file.

 <object data="documents/Hello World.pdf" type="application/pdf" width="100%" height="800px">

 <p>It appears you don't have a PDF plugin for this browser.</p>

</object>

The file to be displayed needs to be in a valid location on a web server, either the webserver delivering the page or an external one accessed with a full URL.

This is fine if you do not care that it potentially exposes your file structure.


If your webserver runs a scripting language it is possible to script the delivery of the file - the file does not have to be located in a similar location to the web server files, nor does it need to be accessible by HTTP (though it can be but hidden on a SharePoint or cloud location).


The following uses ASP.NET Core to build a RESTFul interface to deliver selected files on receipt of a request.

If you have not built a Web API project before, it is worth running through the tutorial here (https://docs.microsoft.com/en-us/aspnet/core/tutorials/first-web-api?view=aspnetcore-5.0&tabs=visual-studio).

Web API to deliver selected files

This Web API uses a RESTFul interface to request a file, the file request is included within the URL, and in this case is just an integer.

Requests to the Web API have the form:

http://<domanin name>/getpdf/<file id>

The test web page builds on the HTML above, the data attribute containing the RESTFul URL to select the files.

<object data="https://localhost:44310/getpdf/0" type="application/pdf" width="100%" height="800px">

 <p>It appears you don't have a PDF plugin for this browser.</p>

</object>


GetPDFController.cs

The following code is for a controller (additional  code is required, use the set up from the tutorial).

using Microsoft.AspNetCore.Mvc;

using Microsoft.Extensions.Logging;

using System;

/// <summary>

/// Web App controller

/// Controller for RESTful access to PDFs

/// The last part of the URL is an integer that selects a specific PDF

/// https://&lt;host&gt;/getpdf/&lt;pdfID&gt;

/// </summary>

namespace GetPDF.Controllers

{

    [ApiController]

    [Route("[controller]")]

    public class GetPDFController : ControllerBase

    {

        private readonly ILogger<GetPDFController> _logger;


        public GetPDFController(ILogger<GetPDFController> logger)

        {

            _logger = logger;

        }


        /// <summary>

        /// Returns a PDF selected by <paramref name="pdfID"/

        /// THis example uses a simple switch to select the PDF,

        /// in a real application this might be search parameters or 

        /// >multiple values that build into the file path

        /// 

        /// Additionally, in a real application there would be a 

        /// requirement for the authentication of the requester.

        /// Additionally the PDF could be watermarked before being

        /// sent.

        /// </summary>

        /// <param name="pdfID">PDF identifier</param>

        /// <returns>PDF or 404</returns>

        [HttpGet]

        [Route("{pdfID:int}")]

        public IActionResult Get(int pdfID)

        {

            string filename;

            // This is for demonstration purposes only.

            // This would require a more complicated solution

            switch (pdfID)

            {

                case 0:

                    filename = @"C:\inetpub\wwwroot\documents\file-0.pdf";

                    return new PhysicalFileResult(filename, "application/pdf");

                case 1:

                    filename = @"C:\inetpub\wwwroot\documents\file-1.pdf";

                    return new PhysicalFileResult(filename, "application/pdf");

               default:

                    return NotFound();

            }


        }

    }

}

References

https://en.wikipedia.org/wiki/ASP.NET_Core

https://docs.microsoft.com/en-us/aspnet/core/tutorials/first-web-api?view=aspnetcore-5.0&tabs=visual-studio

https://docs.microsoft.com/en-us/aspnet/core/web-api/action-return-types?view=aspnetcore-5.0

https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.physicalfileresult?view=aspnetcore-5.0