Media File System doesn't work for backoffice logo and background

After the migration to v17 we had to reimplement the opensource AWS S3 Media File System Provider which is practically a copy of Azure implementation of a storage provider . It works good, the media can be uploaded and is visible in the backoffice, works as expected on FE with crops and everything.

builder.SetMediaFileSystem(provider => provider.GetRequiredService<IAWSS3FileSystemProvider>().GetFileSystem(S3StorageSettings.MediaFileSystemName));

We set up the custom backoffice background and logo links in appsettings (the configured files exists in S3):

"LoginBackgroundImage": "/media/21qljjy3/background.png",
"LoginLogoImage": "/media/iymp1133/logo.svg",

but the images failed to load. It seems that the BackOfficeGraphicsController controller doesn’t respect the media file system.

Is this a bug, intentional behaviour or did I register my media file provider in a wrong way?

Here is the method that serves the images in the abovementioned controller:

private IActionResult HandleFileRequest(string virtualPath)
{
    var filePath = $"{Constants.SystemDirectories.Umbraco}/{virtualPath}".TrimStart(Constants.CharArrays.Tilde);
    IFileInfo fileInfo = _webHostEnvironment.WebRootFileProvider.GetFileInfo(filePath);

    if (fileInfo.PhysicalPath is null)
    {
        return NotFound();
    }

    if (_contentTypeProvider.TryGetContentType(fileInfo.PhysicalPath, out var contentType))
    {
        Stream fileStream = fileInfo.CreateReadStream();
        return File(fileStream, contentType);
    }

    return StatusCode(StatusCodes.Status412PreconditionFailed);
}

Quite a large thread here.. and a solution?

It works fine if I have the images in the solution and in its wwwroot directory, but doesn’t work if I try to reference the images that reside in S3 media file system. So the linked discussion doesn’t really help.

Ah yes right there infront of us.. the handler should be using MediaFileManager

The recommended approach to obtain a file’s content as a stream is to utilize the MediaFileManager . It is advised to avoid reading the file directly from the server using methods like Server.MapPath . This will ensure that, regardless of the file system provider, the stream will be returned correctly.

FileSystemProviders Configuration | CMS | Umbraco Documentation

As it’s only using fileInfo then the file has to physically exist on the disk in wwwroot.
Looks like by design.. but might be worth raising an issue/pr to alter to MediaFileManager which would support local and remote images for this?

I wonder if you could hack around it by adding a mediaSaved Notification handler to copy from aws to the wwwroot?
Or maybe with middleware intercept/proxy the call to the management api endpoints?

/umbraco/management/api/v1/security/back-office/graphics/login-background
/umbraco/management/api/v1/security/back-office/graphics/login-logo
/umbraco/management/api/v1/security/back-office/graphics/login-logo-alternative

and implement your own handler?

using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.Controllers;
using Umbraco.Cms.Api.Management.Routing;
using Umbraco.Cms.Core.IO;

namespace MyProject.Controllers;

// We use the exact same route as the core API to intercept it
[ApiExplorerSettings(GroupName = "Security")]
[VersionedApiBackOfficeRoute("security/back-office/graphics/login-background")]
public class CustomLoginBackgroundController : ManagementApiControllerBase
{
    private readonly MediaFileManager _mediaFileManager;

    public CustomLoginBackgroundController(MediaFileManager mediaFileManager)
    {
        _mediaFileManager = mediaFileManager;
    }

    [HttpGet]
    [ProducesResponseType(typeof(FileStreamResult), 200)]
    public async Task<IActionResult> GetBackground()
    {
        // 1. Logic to get your specific Media path (e.g., from a constant or setting)
        // Hardcoded example path, but you could fetch this from IMediaService
        var mediaPath = "media/12345/my-blob-bg.jpg";

        if (_mediaFileManager.FileSystem.FileExists(mediaPath))
        {
            // 2. This works with Blob Storage because MediaFileManager 
            // uses the underlying IFileSystem (Azure/S3) provider.
            var stream = _mediaFileManager.FileSystem.OpenFile(mediaPath);
            return File(stream, "image/jpeg");
        }

        return NotFound();
    }
}

Or could css come to the rescue… (add as a simple package?)

:root {
  --umb-login-image: url('/media/iymp1133/logo.svg);
}
1 Like

Opened Features or ideas disucssion: