I required a way of being able to dynamically upload images using a form and then serve the images from a URL for readers to enhance the blogs and improve certain topics with imagery and in the future videos and other files.

The plan

  1. The blog author uploads the image using an HTML Form in ASP.NET Web Pages (Razor).
  2. On submission, the HTML form the image is stored (after security checks have passed).
    • There are many storing potentials. I opted to store the files binary data within a database.
  3. The author can reference the added images anywhere within the post.

The HTML Form

Before adding the ability to serve the image, we first need to create a solution for authors to upload their image's. I built a standard HTML form and implemented a standard IFormFile to upload the files, following the documentation Upload files in ASP.NET Core. Implementing the recommended security checks as well as opting for database storage to store the files binary data.

Improving authors post creation experience

The form is created using mainly standard HTML form inputs and models with the main customisations being:

  • The author's content editor utilising markdown use the easymde library.
  • Data optimisations techniques clear any uploaded files if the creation form is cancelled (For example, the author closes the browser window).
  • Custom JavaScript to implement smart tagging, temporary persistence of form data on multi-form POST requests.

Storing the file

As mentioned before, I opted to use a database to store the binary contents of the files. On the internet, you can find many articles discussing the pros and cons of various data storage solutions; database, physical storage, and cloud blob storage services are the more common approaches. However, for my use case, a database offers a quick and convenient way of accessing files with the built-in architecture of Entity Framework already present across the site.

Accessing the file

Next was adding the ability to access the uploaded files within the database for a post using a URL. Writing a custom middleware which on requests looks for a URL like dynamic/images/<guid>.<image-extension> was the method I used. It creates a simple user experience of accessing any file using a URL generated and provided to the authors of the post. The user story for the functionality can be explained simply:

  • If the URL does not match the criteria /dynamic/images/<guid>.<image-extension> the middleware will call the next delegate/middleware in the pipeline.
  • If the path matches but the image is not found, the response will be the expected 404 Not Found response.
  • If the image exists the image binary data is written into memory and becomes the body content of the response; rendering the image as desired.

Using the file within a post

The post creation form

The post creation form supports markdown for the content of blog articles to allow for a rich authoring experience. Once the image is uploaded the author can copy the image URL that was generated and reference it however they like. The generated snippet on the form currently allows it easy for authors to copy directly into:

![](/dynamic/images/<guid>.<image-extension>)

Of course, the author can also go to the URL directly to view the image directly or utilise it how they like.

Future improvements

  • Adding cache; would improve the performance of the site. However, as I'm not expecting 100s of hits at the moment I haven't implemented an in-memory cache. Currently, the response utilises the Expires header which would cache the images for users requests in their browsers.
  • Improving how the author can insert images or files to download within the authoring page; the idea is for users to simply be able to drag and drog, or click "Insert File" directly within the controls of the markdown editor, which will intern place the markdown attachment in place.
  • Improve how temporary the images are handled, if the article is cancelled with lots of images added it then needs to be purged from the database. Currently, these will then be removed at a later date by an out-of-process service that runs through the database with any orphaned image.

References


Comments

Be the first to comment!