Getting A Mime Type From A File Name In .NET Core
Getting a mime type based on a file name (Or file extension), is one of those weird things you never really think about until you really, really need it. I recently ran into the issue when trying to return a file from an API (Probably not the best practice, but I had to make it happen), and I wanted to specify the mime type to the caller. I was amazed with how things “used” to be done both in the .NET Framework, and people’s answers on Stack Overflow.
How We Used To Work Out The Mime Type Based On a File Name (aka The Old Way)
If you were using the .NET Framework, you had two ways to get going. Now I know this is a .NET Core blog, but I still found it interesting to see how we got to where we are now.
The first way is that you build up a huge dictionary yourself of mappings between file extensions and mime types. This actually isn’t a bad way of doing things if you only expect a few different types of files need to be mapped.
The second was that in the System.Web namespace of the .NET Framework there is a static class for mapping classes. We can actually see the source code for this mapping here : https://referencesource.microsoft.com/#system.web/MimeMapping.cs. If you were expecting some sort of mime mapping magic to be happening well, just check out this code snippet.
|
1
2
3
4
5
6
7
8
9
10
11
12
|
private sealed class MimeMappingDictionaryClassic : MimeMappingDictionaryBase {
protected override void PopulateMappings() {
// This list was copied from the IIS7 configuration file located at:
// %windir%\system32\inetsrv\config\applicationHost.config
AddMapping(".323", "text/h323");
AddMapping(".aaf", "application/octet-stream");
AddMapping(".aca", "application/octet-stream");
AddMapping(".accdb", "application/msaccess");
[...]
}
}
|
400+ lines of manual mappings that were copied and pasted from the default IIS7 list. So, not that great.
But the main issue with all of this is that it’s too hard (close to impossible) to add and remove custom mappings. So if your file extension isn’t in the list, you are out of luck.
The .NET Core Way
.NET Core obviously has it’s own way of doing things that may seem a bit more complicated but does work well.
First, we need to install the following nuget package :
|
1
|
Install-Package Microsoft.AspNetCore.StaticFiles
|
Annoyingly the class we want to use lives inside this static files nuget package. I would say if that becomes an issue for you, to look at the source code and make it work for you in whatever way you need. But for now, let’s use the package.
Now we have access to a nifty little class called FileExtensionContentTypeProvider . Here’s some example code using it. I’ve created a simple API action that takes a filename, and returns the mime type :
|
1
2
3
4
5
6
7
8
9
10
11
|
[HttpGet]
public string Get(string fileName)
{
var provider = new FileExtensionContentTypeProvider();
string contentType;
if(!provider.TryGetContentType(fileName, out contentType))
{
contentType = "application/octet-stream";
}
return contentType;
}
|
Nothing too crazy and it works! We also catch if it doesn’t manage to map it, and just map it ourselves to a default content type. This is one thing that the .NET Framework MimeMapping class did have, was that if it couldn’t find the correct mapping, it returned application/octet-stream. But I can see how this is far more definitive as to what’s going on.
But here’s the thing, if we look at the source code of this here, we can see we are no better off in terms of doing things by “magic”, it’s still one big dictionary under the hood. And the really interesting part? We can actually add our own mappings! Let’s modify our code a bit :
|
1
2
3
4
5
6
7
8
9
10
11
12
|
[HttpGet]
public string Get(string fileName)
{
var provider = new FileExtensionContentTypeProvider();
provider.Mappings.Add(".dnct", "application/dotnetcoretutorials");
string contentType;
if(!provider.TryGetContentType(fileName, out contentType))
{
contentType = "application/octet-stream";
}
return contentType;
}
|
I’ve gone mad with power and created a new file extension called .dnct and mapped it to it’s own mimetype. Everything is a cinch!
But our last problem. What if we want to use this in multiple places? What if we need better control for unit testing that “instantiating” everytime won’t really give us? Let’s create a nice mime type mapping service!
We could create this static, but then we lose a little flexibility around unit testing. So I’m going to create an interface too. Our service looks like so :
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
public interface IMimeMappingService
{
string Map(string fileName);
}
public class MimeMappingService : IMimeMappingService
{
private readonly FileExtensionContentTypeProvider _contentTypeProvider;
public MimeMappingService(FileExtensionContentTypeProvider contentTypeProvider)
{
_contentTypeProvider = contentTypeProvider;
}
public string Map(string fileName)
{
string contentType;
if (!_contentTypeProvider.TryGetContentType(fileName, out contentType))
{
contentType = "application/octet-stream";
}
return contentType;
}
}
|
So we provide a single method called “Map”. And when creating our MimeMappingService, we take in a content service provider.
Now we need to head to our startup.cs and in our ConfigureServices method we need to wire up the service. That looks a bit like this :
|
1
2
3
4
5
6
7
8
|
public void ConfigureServices(IServiceCollection services)
{
var provider = new FileExtensionContentTypeProvider();
provider.Mappings.Add(".dnct", "application/dotnetcoretutorials");
services.AddSingleton<IMimeMappingService>(new MimeMappingService(provider));
services.AddMvc();
}
|
So we instantiate our FileExtensionContentTypeProvider, give it our extra mappings, then bind our MimeMappingService all up so it can be injected.
In our controller we change out code to look a bit like this :
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public class ValuesController : Controller
{
private readonly IMimeMappingService _mimeMappingService;
public ValuesController(IMimeMappingService mimeMappingService)
{
_mimeMappingService = mimeMappingService;
}
[HttpGet]
public string Get(string fileName)
{
return _mimeMappingService.Map(fileName);
}
}
|
Nice and clean. And it means that any time we inject our MimeMappingService around, it has all our customer mappings contained within it!
.NET Core Static Files
There is one extra little piece of info I should really give out too. And that is if you are using the .NET Core static files middleware to serve raw files, you can also use this provider to return the correct mime type. So for example you can do things like this :
|
1
2
3
4
5
6
7
8
9
10
11
|
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
var provider = new FileExtensionContentTypeProvider();
provider.Mappings.Add(".dnct", "application/dotnetcoretutorials");
app.UseStaticFiles(new StaticFileOptions
{
ContentTypeProvider = provider
});
}
|
So now when outside of C# code, and we are just serving the raw file of type .dnct, we will still return the correct MimeType.
Related Posts
Getting A Mime Type From A File Name In .NET Core的更多相关文章
- File upload - MIME type
Your goal is to hack this photo galery by uploading PHP code.Retrieve the validation password in the ...
- solr异常--Expected mime type application/octet-stream but got text/html.
Exception in thread "main" org.apache.solr.client.solrj.impl.HttpSolrServer$RemoteSolrExce ...
- nginx: [warn] duplicate MIME type "text/html"错误
检查配置文件时提示:nginx: [warn] duplicate MIME type "text/html" in /home/web/nginx/inc/gzip.conf:9 ...
- php 获取 mime type 类型,fileinfo扩展
背景: version < php-5.3 没有API能够查看文件的 mime_type, 故需要编译扩展 fileinfo 来扩展PHP的API(finfo_*系列函数).php-5.3 以后 ...
- [笔记] C# 如何获取文件的 MIME Type
MIME Type 为何物: MIME 参考手册 svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types 常规方式 对于有文件后 ...
- Unable to guess the mime type as no guessers are available 2 9
做了一个上传图片的功能,在本地上传通过,服务器报 bug Unable to guess the mime type as no guessers are available(Did you enab ...
- MIME Type
一.首先,我们要了解浏览器是如何处理内容的.在浏览器中显示的内容有 HTML.有 XML.有 GIF.还有 Flash --那么,浏览器是如何区分它们,决定什么内容用什么形式来显示呢?答案是 MIME ...
- Chrome: Resource interpreted as Font but transferred with MIME type font/x-woff
最近,项目中加入了Bootstrap进行界面优化,但是,项目加载运行之后,控制台总是提示以下错误信息: GET http://localhost:8080/.../fonts/fontawesome- ...
- Resource interpreted as Script but transferred with MIME type text/plain:
我用script做ajax跨域,请求返回的是个文本字符串,chrome提示:Resource interpreted as Script but transferred with MIME type ...
随机推荐
- FusionInsight大数据开发---sorl应用开发
sorl应用开发 要求: 了解Solr应用开发适用场景 熟悉Solr应用开发流程 熟悉并使用Solr常用API 理解Collection设计基本原则 应用开发实践 Solr简介 Solr是一个高性能, ...
- ES7.3.0配置
# elasticsearch.yml cluster.name: my-application node.name: node-1 node.master: true node.ingest: tr ...
- HTML转换特效相关插件
Arctext.js Arctext.js 是基于 Lettering.js 的文字旋转插件,根据设置的旋转半径准确计算每个字母的旋转弧度并均匀分布. 虽然 CSS3 也能够实现字符旋转效果,但是要让 ...
- API之Scanner,Random,ArrayList基础运用。重点是ArrayList
有关API的这些类可以参考JDK的官方中文文档,看我的另一篇文章有下载==> https://www.cnblogs.com/gz18221/p/11968505.html<==文章地址 ...
- jQuery 前端复选框 全选 反选 下拉菜单联动
jQuery 页面中复选框全选.反选.下拉联动(级联) <!DOCTYPE html> <html lang="en"> <head> < ...
- Js数组语法
js数组整理导向图 ---欢迎收藏^ - ^
- CSS3实现0.5px边框
用CSS设置边框宽度为0.5px,可以使边框看起来更加细腻,特别是在移动端,设计师会有这样的要求. 但遗憾的是,大多数Android手机并不能识别0.5px.因此我们可以使用CSS3来变通的实现0.5 ...
- OCR1:开源库
OCR (Optical Character Recognition,光学字符识别)是指电子设备(例如扫描仪或数码相机)检查纸上打印的字符,通过检测暗.亮的模式确定其形状,然后用字符识别方法将形状翻译 ...
- 【原】python 检查网站访问是否超时,并用钉钉机器人报警
#!/usr/bin/env python import requests import json import logging webhook="上面创建钉钉机器人的webhook地址&q ...
- LVS负载均衡部署
一.lvs-nat模式 1.1.环境介绍 本实验用三台虚拟机完成,一台虚拟机模拟lvs调度器,两块网卡,一块模拟公网一块模拟私网,公网地址192.168.0.201/24,私网地址192.168.4. ...