A few months ago I wrote a post about learnings from the Umbraco Discord that week and then.. it went quiet 😅
With the best of intentions to keep that series going, it turns out there's just not enough hours in the day! I have ideas though to open up the information from Discord more but that will have to be bit more long term.
In the mean time, we did go down a fun exploration path with Dean Leigh yesterday thinking about adding custom MIME types to Umbraco and overriding existing ones if needed.
This turned into a thread where explored the actual needs and some solutions.
Program.cs
vs Startup.cs
First off, I understand the confusion, Umbraco 9 was built on .net 5 and that required us to have Startup.cs
and Program.cs
.
In .net 6, Microsoft consolidated the two into Program.cs
and updated all of their documentation to that effect. We're not ready yet in Umbraco to do the same, so there will be some confusion for a while.
So for now, in Umbraco you're encouraged never to touch Program.cs
and only ever make changes to Startup.cs
.
Mime types
As it turns out, Dean's original question was about trying to figure out how to host and serve the new(-ish) avif
format, an image format with really great compression.
Image credit: Jake Archibald
Since .net doesn't yet support avif and neither does ImageSharp, files of this type just didn't have a MIME type available and trying to use them would result in a 404 error.
I remembered seeing an example recently to help cache static assets. These are specifically listing file types that ImageSharp doesn't touch. If you added something like jpg
in that list, the request would be cached very early and never hit the ImageSharp middleware.
Adding/changing MIME types is pretty similar to adding cache control headers, so I played with that code to see how far we could get.
As it turns out, I was trying my code on webp
files first, changing their MIME type from image/webp
to image/text
to see if it would work. It didn't! I was close though and with some great help from my colleague Ronald I understood that I was only changing the MIME type for .net and then the next thing kicked in: ImageSharp. When ImageSharp sees a request for a webp
file, it reads the metadata from the file and sets the MIME type (correctly!) back to image/webp
. So after a bit of experimenting we came up with the following code:
⚡⚠️ danger danger, this messes with the default webp content type, don't use in production⚡⚠️
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.StaticFiles;
using SixLabors.ImageSharp.Web;
using SixLabors.ImageSharp.Web.Middleware;
using Umbraco.Cms.Core.Composing;
public class ContentTypeComposer : IComposer
{
public void Compose(IUmbracoBuilder builder)
{
var contentTypeProvider = new FileExtensionContentTypeProvider();
contentTypeProvider.Mappings[".webp"] = "image/text";
builder.Services.Configure<StaticFileOptions>(options => options.ContentTypeProvider = contentTypeProvider);
builder.Services.Configure<ImageSharpMiddlewareOptions>(options =>
{
var prepareResponseAsync = options.OnPrepareResponseAsync;
options.OnPrepareResponseAsync = async (context) =>
{
var formatUtilities = context.RequestServices.GetRequiredService<FormatUtilities>();
if (formatUtilities.TryGetExtensionFromUri(context.Request.GetDisplayUrl(), out var extension) &&
contentTypeProvider.TryGetContentType('.' + extension, out var contentType))
{
context.Response.ContentType = contentType;
}
await prepareResponseAsync(context);
};
});
}
}
Cool, that worked!
One caveat though, as you can see in the code above, this is updating the Mappings for an existing content type, and as we learned earlier, avif
is not supported in .net yet and therefore there is no existing content type. We also don't have to think about ImageSharp since it doesn't support avif
yet either.
So to make avif
get a proper MIME type, the code needed to change a bit:
using Microsoft.AspNetCore.StaticFiles;
using Umbraco.Cms.Core.Composing;
public class ContentTypeComposer : IComposer
{
public void Compose(IUmbracoBuilder builder)
{
var contentTypeProvider = new FileExtensionContentTypeProvider();
if (!contentTypeProvider.Mappings.ContainsKey(".avif"))
{
contentTypeProvider.Mappings.Add(".avif", "image/avif");
}
builder.Services.Configure<StaticFileOptions>(options => options.ContentTypeProvider = contentTypeProvider);
}
}
Here we added the MIME type if the mapping doesn't yet exist, if it ever starts to exist in the future we assume it gets the correct mapping anyway.
Bonus
If you want to learn more about headers and CORS, my colleague Warren has a great Hack Make Do video on this topic as well!
Conclusion
And there we have it, now we can add a MIME type to any unknown file format and we learned at the same time how to override MIME types for ImageSharp. Plus.. now that we know how to hook into the ImageSharp middleware options, we could probably think of more fun things to do in there as well.
Top comments (0)