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.

Getting A Mime Type From A File Name In .NET Core的更多相关文章

  1. File upload - MIME type

    Your goal is to hack this photo galery by uploading PHP code.Retrieve the validation password in the ...

  2. solr异常--Expected mime type application/octet-stream but got text/html.

    Exception in thread "main" org.apache.solr.client.solrj.impl.HttpSolrServer$RemoteSolrExce ...

  3. nginx: [warn] duplicate MIME type "text/html"错误

    检查配置文件时提示:nginx: [warn] duplicate MIME type "text/html" in /home/web/nginx/inc/gzip.conf:9 ...

  4. php 获取 mime type 类型,fileinfo扩展

    背景: version < php-5.3 没有API能够查看文件的 mime_type, 故需要编译扩展 fileinfo 来扩展PHP的API(finfo_*系列函数).php-5.3 以后 ...

  5. [笔记] C# 如何获取文件的 MIME Type

    MIME Type 为何物: MIME 参考手册 svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types 常规方式 对于有文件后 ...

  6. 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 ...

  7. MIME Type

    一.首先,我们要了解浏览器是如何处理内容的.在浏览器中显示的内容有 HTML.有 XML.有 GIF.还有 Flash --那么,浏览器是如何区分它们,决定什么内容用什么形式来显示呢?答案是 MIME ...

  8. Chrome: Resource interpreted as Font but transferred with MIME type font/x-woff

    最近,项目中加入了Bootstrap进行界面优化,但是,项目加载运行之后,控制台总是提示以下错误信息: GET http://localhost:8080/.../fonts/fontawesome- ...

  9. Resource interpreted as Script but transferred with MIME type text/plain:

    我用script做ajax跨域,请求返回的是个文本字符串,chrome提示:Resource interpreted as Script but transferred with MIME type ...

随机推荐

  1. Java自学-类和对象 包

    Java中的 包 包: package 把比较接近的类,规划在同一个包下 步骤 1 : 把比较接近的类,规划在同一个包下 Hero,ADHero 规划在一个包,叫做charactor(角色) Item ...

  2. Beego 学习笔记9:Boostrap使用介绍

    BootStrap布局 1>     下载地址: http://v3.bootcss.com/getting-started/#download 根据自己的需要,下载不同的版本.我这里使用的是1 ...

  3. JavaScript设计模式与开发实践随笔(一)

    编程语言按照数据类型大体可以分为两类,一类是静态类型语言,另一类是动态类型语言. 静态类型语言在编译时便已确定变量的类型,而动态类型语言的变量类型要到程序运行的时 候,待变量被赋予某个值之后,才会具有 ...

  4. idea搭建一个简单的springboot项目

    1.file->new->project 2.选中Spring  Initializr 3.填写项目信息: 4.选中Web -> Spring Web

  5. IP切换小技巧

    说到这个问题很多人都有同感.公司一般使用的都是静态的IP(如图:使用下面的IP地址),而我们在外面是用的一般是动态获取的IP(如图:自动获得IP地址),因此就产生了一个问题,需要来回切换IP,也就是需 ...

  6. MFC For循环中实时更新显示Edit内容

    在for(){}循环中如果有处理函数,然后需要显示的时候,简单的UpdateData(false);是不行的: for (int i=0;i<10000;i++) { m_nT1.Format( ...

  7. Mycat配置项详解

     schema.xml文件配置中的balance属性和writeType属性: . balance=", 不开启读写分离机制,所有读操作都发送到当前可用的 writeHost 上. . ba ...

  8. k8s如何访问pod

    1. 通过 Service 访问 Pod 我们不应该期望 Kubernetes Pod 是健壮的,而是要假设 Pod 中的容器很可能因为各种原因发生故障而死掉.Deployment 等 control ...

  9. pandas用法总结

    pandas用法总结 2018年06月07日 10:49:03 一夜了 阅读数 38705更多 分类专栏: 杂项   一.生成数据表 1.首先导入pandas库,一般都会用到numpy库,所以我们先导 ...

  10. C语言结构体变量字节对齐问题总结

    结构体字节对齐 在用sizeof运算符求算某结构体所占空间时,并不是简单地将结构体中所有元素各自占的空间相加,这里涉及到内存字节对齐的问题.从理论上讲,对于任何 变量的访问都可以从任何地址开始访问,但 ...