.NET 中的文件扩展名和 MIME 类型

发布于 2024-08-08 21:37:15 字数 1035 浏览 5 评论 0原文

我想从给定的扩展名获取 MIME 内容类型(最好不访问物理文件)。我已经看到了一些与此相关的问题,并且可以在以下位置恢复描述的执行此操作的方法:

  1. 使用 注册表信息
  2. 使用 urlmon.dll 的 FindMimeFromData
  3. 使用 IIS 信息
  4. 推出您自己的 MIME 映射函数。例如,基于此表

我已经使用no.1有一段时间了,但我意识到注册表提供的信息并不一致,并且取决于机器上安装的软件。某些扩展名(例如 .zip)不用于指定内容类型。

解决方案 2 迫使我将文件放在磁盘上才能读取第一个字节,虽然速度很慢,但可能会得到很好的结果。

第三种方法基于目录服务和所有这些东西,这是我不太喜欢的方法,因为我必须添加 COM 引用,而且我不确定它在 IIS6 和 IIS7 之间是否一致。另外,我不知道这个方法的性能。

最后,我不想使用自己的表,但如果我想要平台(甚至 Mono)之间的结果具有良好的性能和一致性,那么最后似乎是最好的选择。

您认为有比使用我自己的表更好的选择还是其他描述的方法之一更好?你的经验是什么?

I want to get a MIME Content-Type from a given extension (preferably without accessing the physical file). I have seen some questions about this and the methods described to perform this can be resumed in:

  1. Use registry information.
  2. Use urlmon.dll's FindMimeFromData.
  3. Use IIS information.
  4. Roll your own MIME mapping function. Based on this table, for example.

I've been using no.1 for some time but I realized that the information provided by the registry is not consistent and depends on the software installed on the machine. Some extensions, like .zip don't use to have a Content-Type specified.

Solution no.2 forces me to have the file on disk in order to read the first bytes, which is something slow but may get good results.

The third method is based on Directory Services and all that stuff, which is something I don't like much because I have to add COM references and I'm not sure it's consistent between IIS6 and IIS7. Also, I don't know the performance of this method.

Finally, I didn't want to use my own table but at the end seems the best option if I want a decent performance and consistency of the results between platforms (even Mono).

Do you think there's a better option than using my own table or one of other described methods are better? What's your experience?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

鹿港巷口少年归 2024-08-15 21:37:15

这取决于您需要 MIME 类型的用途。一般来说,对于服务(Web 应用程序、Web 服务等),建议不要使用依赖于操作系统设置的 MIME 列表,或者仅在无法找到 MIME 信息时作为后备。

我认为这也是 MS 选择将常量 MIME 类型放入其 System.Web.MimeMapping 类中的原因(不幸的是,无论出于何种原因,它是内部的)。

编辑:

包装器 (<= .NET 3.5)

public static class MimeExtensionHelper
{
    static object locker = new object();
    static object mimeMapping;
    static MethodInfo getMimeMappingMethodInfo;

    static MimeExtensionHelper()
    {
        Type mimeMappingType = Assembly.GetAssembly(typeof(HttpRuntime)).GetType("System.Web.MimeMapping");
        if (mimeMappingType == null)
            throw new SystemException("Couldnt find MimeMapping type");
        ConstructorInfo constructorInfo = mimeMappingType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null);
        if (constructorInfo == null)
            throw new SystemException("Couldnt find default constructor for MimeMapping");
        mimeMapping = constructorInfo.Invoke(null);
        if (mimeMapping == null)
            throw new SystemException("Couldnt find MimeMapping");
        getMimeMappingMethodInfo = mimeMappingType.GetMethod("GetMimeMapping", BindingFlags.Static | BindingFlags.NonPublic);
        if (getMimeMappingMethodInfo == null)
            throw new SystemException("Couldnt find GetMimeMapping method");
        if (getMimeMappingMethodInfo.ReturnType != typeof(string))
            throw new SystemException("GetMimeMapping method has invalid return type");
        if (getMimeMappingMethodInfo.GetParameters().Length != 1 && getMimeMappingMethodInfo.GetParameters()[0].ParameterType != typeof(string))
            throw new SystemException("GetMimeMapping method has invalid parameters");
    }
    public static string GetMimeType(string filename)
    {
        lock (locker)
            return (string)getMimeMappingMethodInfo.Invoke(mimeMapping, new object[] { filename });
    }
}

包装器 (.NET 4.0)

public static class MimeExtensionHelper
    {
        static object locker = new object();
        static object mimeMapping;
        static MethodInfo getMimeMappingMethodInfo;

        static MimeExtensionHelper()
        {
            Type mimeMappingType = Assembly.GetAssembly(typeof(HttpRuntime)).GetType("System.Web.MimeMapping");
            if (mimeMappingType == null)
                throw new SystemException("Couldnt find MimeMapping type");            
            getMimeMappingMethodInfo = mimeMappingType.GetMethod("GetMimeMapping", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
            if (getMimeMappingMethodInfo == null)
                throw new SystemException("Couldnt find GetMimeMapping method");
            if (getMimeMappingMethodInfo.ReturnType != typeof(string))
                throw new SystemException("GetMimeMapping method has invalid return type");
            if (getMimeMappingMethodInfo.GetParameters().Length != 1 && getMimeMappingMethodInfo.GetParameters()[0].ParameterType != typeof(string))
                throw new SystemException("GetMimeMapping method has invalid parameters");
        }
        public static string GetMimeType(string filename)
        {
            lock (locker)
                return (string)getMimeMappingMethodInfo.Invoke(mimeMapping, new object[] { filename });
        }
    }

.NET 4.5+

不需要包装器,调用公共方法 System.Web.MimeMapping.GetMimeMapping

It depends what you need the MIME type for. In general, for services (web apps, web service, etc.), it's advisable not to use a MIME list which is dependent on the OS settings, or only as fallback if you cannot find MIME information otherwise.

I think that this is also the reason why MS chose to put constant MIME types in their System.Web.MimeMapping class (unfortunately it's internal, for whatever reason).

Edit:

Wrapper (<= .NET 3.5)

public static class MimeExtensionHelper
{
    static object locker = new object();
    static object mimeMapping;
    static MethodInfo getMimeMappingMethodInfo;

    static MimeExtensionHelper()
    {
        Type mimeMappingType = Assembly.GetAssembly(typeof(HttpRuntime)).GetType("System.Web.MimeMapping");
        if (mimeMappingType == null)
            throw new SystemException("Couldnt find MimeMapping type");
        ConstructorInfo constructorInfo = mimeMappingType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null);
        if (constructorInfo == null)
            throw new SystemException("Couldnt find default constructor for MimeMapping");
        mimeMapping = constructorInfo.Invoke(null);
        if (mimeMapping == null)
            throw new SystemException("Couldnt find MimeMapping");
        getMimeMappingMethodInfo = mimeMappingType.GetMethod("GetMimeMapping", BindingFlags.Static | BindingFlags.NonPublic);
        if (getMimeMappingMethodInfo == null)
            throw new SystemException("Couldnt find GetMimeMapping method");
        if (getMimeMappingMethodInfo.ReturnType != typeof(string))
            throw new SystemException("GetMimeMapping method has invalid return type");
        if (getMimeMappingMethodInfo.GetParameters().Length != 1 && getMimeMappingMethodInfo.GetParameters()[0].ParameterType != typeof(string))
            throw new SystemException("GetMimeMapping method has invalid parameters");
    }
    public static string GetMimeType(string filename)
    {
        lock (locker)
            return (string)getMimeMappingMethodInfo.Invoke(mimeMapping, new object[] { filename });
    }
}

Wrapper (.NET 4.0)

public static class MimeExtensionHelper
    {
        static object locker = new object();
        static object mimeMapping;
        static MethodInfo getMimeMappingMethodInfo;

        static MimeExtensionHelper()
        {
            Type mimeMappingType = Assembly.GetAssembly(typeof(HttpRuntime)).GetType("System.Web.MimeMapping");
            if (mimeMappingType == null)
                throw new SystemException("Couldnt find MimeMapping type");            
            getMimeMappingMethodInfo = mimeMappingType.GetMethod("GetMimeMapping", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
            if (getMimeMappingMethodInfo == null)
                throw new SystemException("Couldnt find GetMimeMapping method");
            if (getMimeMappingMethodInfo.ReturnType != typeof(string))
                throw new SystemException("GetMimeMapping method has invalid return type");
            if (getMimeMappingMethodInfo.GetParameters().Length != 1 && getMimeMappingMethodInfo.GetParameters()[0].ParameterType != typeof(string))
                throw new SystemException("GetMimeMapping method has invalid parameters");
        }
        public static string GetMimeType(string filename)
        {
            lock (locker)
                return (string)getMimeMappingMethodInfo.Invoke(mimeMapping, new object[] { filename });
        }
    }

.NET 4.5+

No wrapper required, call the public method System.Web.MimeMapping.GetMimeMapping directly.

寄人书 2024-08-15 21:37:15

我已将所有这些方法组合到我的实用程序库中,除了第 3 种方法。
顺便说一句,no.2(urlmon.dll)不需要静态文件,它只需要一些字节,无论它们来自哪里。
这是我当前的课程

namespace Components
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Runtime.InteropServices;
    using System.Text;
    using System.Xml.Serialization;
    using Microsoft.Win32;

    public sealed class MimeExtensionHelper
    {
        private MimeExtensionHelper() { }

        /// <summary>Finds extension associated with specified mime type</summary>
        /// <param name="mimeType">mime type you search extension for, e.g.: "application/octet-stream"</param>
        /// <returns>most used extension, associated with provided type, e.g.: ".bin"</returns>
        public static string FindExtension(string mimeType)
        {
            return ExtensionTypes.GetExtension(mimeType);
        }

        /// <summary>Finds mime type using provided extension and/or file's binary content.</summary>
        /// <param name="file">Full file path</param>
        /// <param name="verifyFromContent">Should the file's content be examined to verify founded value.</param>
        /// <returns>mime type of file, e.g.: "application/octet-stream"</returns>
        public static string FindMime(string file,bool verifyFromContent)
        {
            string extension = Path.GetExtension(file);
            string mimeType = string.Empty;
            try
            {
                if (!String.IsNullOrEmpty(extension))
                    mimeType = ExtensionTypes.GetMimeType(extension);
                if (verifyFromContent
                    || (String.IsNullOrEmpty(mimeType) && File.Exists(file)))
                    mimeType = FindMimeByContent(file,mimeType);
            }
            catch { }
            return (mimeType ?? string.Empty).Trim();//"application/octet-stream"
        }

        /// <summary>Finds mime type for file using it's binary data.</summary>
        /// <param name="file">Full path to file.</param>
        /// <param name="proposedType">Optional. Expected file's type.</param>
        /// <returns>mime type, e.g.: "application/octet-stream"</returns>
        public static string FindMimeByContent(string file
            ,string proposedType)
        {
            FileInfo fi = new FileInfo(file);
            if (!fi.Exists)
                throw new FileNotFoundException(file);
            byte[] buf = new byte[Math.Min(4096L,fi.Length)];
            using (FileStream fs = File.OpenRead(file))
                fs.Read(buf,0,buf.Length);
            return FindMimeByData(buf,proposedType);
        }

        /// <summary>Finds mime type for binary data.</summary>
        /// <param name="dataBytes">Binary data to examine.</param>
        /// <param name="mimeProposed">Optional. Expected mime type.</param>
        /// <returns>mime type, e.g.: "application/octet-stream"</returns>
        public static string FindMimeByData(byte[] dataBytes,string mimeProposed)
        {
            if (dataBytes == null || dataBytes.Length == 0)
                throw new ArgumentNullException("dataBytes");
            string mimeRet = String.Empty;
            IntPtr outPtr = IntPtr.Zero;
            if (!String.IsNullOrEmpty(mimeProposed))
                mimeRet = mimeProposed;
            int result = FindMimeFromData(IntPtr.Zero
                ,null
                ,dataBytes
                ,dataBytes.Length
                ,String.IsNullOrEmpty(mimeProposed) ? null : mimeProposed
                ,0
                ,out outPtr
                ,0);
            if (result != 0)
                throw Marshal.GetExceptionForHR(result);
            if (outPtr != null && outPtr != IntPtr.Zero)
            {
                mimeRet = Marshal.PtrToStringUni(outPtr);
                Marshal.FreeCoTaskMem(outPtr);
            }
            return mimeRet;
        }

        [DllImport("urlmon.dll"
            ,CharSet = CharSet.Unicode
            ,ExactSpelling = true
            ,SetLastError = true)]
        static extern Int32 FindMimeFromData(IntPtr pBC
            ,[MarshalAs(UnmanagedType.LPWStr)] String pwzUrl
            ,[MarshalAs(UnmanagedType.LPArray,ArraySubType = UnmanagedType.I1,SizeParamIndex = 3)] Byte[] pBuffer
            ,Int32 cbSize
            ,[MarshalAs(UnmanagedType.LPWStr)] String pwzMimeProposed
            ,Int32 dwMimeFlags
            ,out IntPtr ppwzMimeOut
            ,Int32 dwReserved);

        private static MimeTypeCollection _extensionTypes = null;
        private static MimeTypeCollection ExtensionTypes
        {
            get
            {
                if (_extensionTypes == null)
                    _extensionTypes = new MimeTypeCollection();
                return _extensionTypes;
            }
        }

        [Serializable]
        [XmlRoot(ElementName = "mimeTypes")]
        private class MimeTypeCollection : List<MimeTypeCollection.mimeTypeInfo>
        {
            private SortedList<string,string> _extensions;
            private SortedList<string,List<string>> _mimes;

            private void Init()
            {
                if (_extensions == null || _mimes == null
                    || _extensions.Count == 0 || _mimes.Count == 0)
                {
                    _extensions = new SortedList<string,string>(StringComparer.OrdinalIgnoreCase);
                    _mimes = new SortedList<string,List<string>>(StringComparer.OrdinalIgnoreCase);
                    foreach (var mime in this)
                    {
                        _mimes.Add(mime.MimeType,new List<string>(mime.Extensions));
                        foreach (string ext in mime.Extensions)
                            if (!_extensions.ContainsKey(ext))
                                _extensions.Add(ext,mime.MimeType);
                    }
                }
            }

            public String GetExtension(string type)
            {
                Init();
                return _mimes.ContainsKey(type) ? _mimes[type][0] : string.Empty;
            }

            public String GetMimeType(string extension)
            {
                Init();
                return _extensions.ContainsKey(extension) ? _extensions[extension] : string.Empty;
            }

        public MimeTypeCollection()
        {
            this.Add(new mimeTypeInfo("application/applixware",new List<string>(new[] { ".aw" })));
            this.Add(new mimeTypeInfo("application/atom+xml",new List<string>(new[] { ".atom" })));
            // ... Whole list from apache's site
            this.Add(new mimeTypeInfo("x-x509-ca-cert",new List<string>(new[] { ".cer" })));
            try
            {
                using (RegistryKey classesRoot = Registry.ClassesRoot)
                using (RegistryKey typeKey = classesRoot.OpenSubKey(@"MIME\Database\Content Type"))
                {
                    string[] subKeyNames = typeKey.GetSubKeyNames();
                    string extension = string.Empty;
                    foreach (string keyname in subKeyNames)
                    {
                        string trimmed = (keyname ?? string.Empty).Trim();
                        if (string.IsNullOrEmpty(trimmed))
                            continue;
                        if (!String.IsNullOrEmpty(GetExtension(trimmed)))
                            continue;
                        string subKey = "MIME\\Database\\Content Type\\" + trimmed;
                        using (RegistryKey curKey = classesRoot.OpenSubKey(subKey))
                        {
                            extension = (curKey.GetValue("Extension") as string ?? string.Empty).Trim();
                            if (extension.Length > 0)
                                this.Add(new mimeTypeInfo(trimmed
                                    ,new List<string>(new[] { extension })));
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                string s = ex.ToString();
            }
        }

        [Serializable]
        public class mimeTypeInfo
        {
            [XmlAttribute(AttributeName = "mimeType")]
            public String MimeType { get; set; }

            [XmlElement("extension")]
            public List<String> Extensions { get; set; }

            public mimeTypeInfo(string mimeType,List<string> extensions)
            {
                MimeType = mimeType;
                Extensions = extensions;
            }

            public mimeTypeInfo() { }
        }
    }
}

}

I have combined all these approaches in my utility lib, except maybe no.3.
Btw, no.2 (urlmon.dll) doesn't require static file, it simply takes some bytes no matter where they had come from.
Here's my current class

namespace Components
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Runtime.InteropServices;
    using System.Text;
    using System.Xml.Serialization;
    using Microsoft.Win32;

    public sealed class MimeExtensionHelper
    {
        private MimeExtensionHelper() { }

        /// <summary>Finds extension associated with specified mime type</summary>
        /// <param name="mimeType">mime type you search extension for, e.g.: "application/octet-stream"</param>
        /// <returns>most used extension, associated with provided type, e.g.: ".bin"</returns>
        public static string FindExtension(string mimeType)
        {
            return ExtensionTypes.GetExtension(mimeType);
        }

        /// <summary>Finds mime type using provided extension and/or file's binary content.</summary>
        /// <param name="file">Full file path</param>
        /// <param name="verifyFromContent">Should the file's content be examined to verify founded value.</param>
        /// <returns>mime type of file, e.g.: "application/octet-stream"</returns>
        public static string FindMime(string file,bool verifyFromContent)
        {
            string extension = Path.GetExtension(file);
            string mimeType = string.Empty;
            try
            {
                if (!String.IsNullOrEmpty(extension))
                    mimeType = ExtensionTypes.GetMimeType(extension);
                if (verifyFromContent
                    || (String.IsNullOrEmpty(mimeType) && File.Exists(file)))
                    mimeType = FindMimeByContent(file,mimeType);
            }
            catch { }
            return (mimeType ?? string.Empty).Trim();//"application/octet-stream"
        }

        /// <summary>Finds mime type for file using it's binary data.</summary>
        /// <param name="file">Full path to file.</param>
        /// <param name="proposedType">Optional. Expected file's type.</param>
        /// <returns>mime type, e.g.: "application/octet-stream"</returns>
        public static string FindMimeByContent(string file
            ,string proposedType)
        {
            FileInfo fi = new FileInfo(file);
            if (!fi.Exists)
                throw new FileNotFoundException(file);
            byte[] buf = new byte[Math.Min(4096L,fi.Length)];
            using (FileStream fs = File.OpenRead(file))
                fs.Read(buf,0,buf.Length);
            return FindMimeByData(buf,proposedType);
        }

        /// <summary>Finds mime type for binary data.</summary>
        /// <param name="dataBytes">Binary data to examine.</param>
        /// <param name="mimeProposed">Optional. Expected mime type.</param>
        /// <returns>mime type, e.g.: "application/octet-stream"</returns>
        public static string FindMimeByData(byte[] dataBytes,string mimeProposed)
        {
            if (dataBytes == null || dataBytes.Length == 0)
                throw new ArgumentNullException("dataBytes");
            string mimeRet = String.Empty;
            IntPtr outPtr = IntPtr.Zero;
            if (!String.IsNullOrEmpty(mimeProposed))
                mimeRet = mimeProposed;
            int result = FindMimeFromData(IntPtr.Zero
                ,null
                ,dataBytes
                ,dataBytes.Length
                ,String.IsNullOrEmpty(mimeProposed) ? null : mimeProposed
                ,0
                ,out outPtr
                ,0);
            if (result != 0)
                throw Marshal.GetExceptionForHR(result);
            if (outPtr != null && outPtr != IntPtr.Zero)
            {
                mimeRet = Marshal.PtrToStringUni(outPtr);
                Marshal.FreeCoTaskMem(outPtr);
            }
            return mimeRet;
        }

        [DllImport("urlmon.dll"
            ,CharSet = CharSet.Unicode
            ,ExactSpelling = true
            ,SetLastError = true)]
        static extern Int32 FindMimeFromData(IntPtr pBC
            ,[MarshalAs(UnmanagedType.LPWStr)] String pwzUrl
            ,[MarshalAs(UnmanagedType.LPArray,ArraySubType = UnmanagedType.I1,SizeParamIndex = 3)] Byte[] pBuffer
            ,Int32 cbSize
            ,[MarshalAs(UnmanagedType.LPWStr)] String pwzMimeProposed
            ,Int32 dwMimeFlags
            ,out IntPtr ppwzMimeOut
            ,Int32 dwReserved);

        private static MimeTypeCollection _extensionTypes = null;
        private static MimeTypeCollection ExtensionTypes
        {
            get
            {
                if (_extensionTypes == null)
                    _extensionTypes = new MimeTypeCollection();
                return _extensionTypes;
            }
        }

        [Serializable]
        [XmlRoot(ElementName = "mimeTypes")]
        private class MimeTypeCollection : List<MimeTypeCollection.mimeTypeInfo>
        {
            private SortedList<string,string> _extensions;
            private SortedList<string,List<string>> _mimes;

            private void Init()
            {
                if (_extensions == null || _mimes == null
                    || _extensions.Count == 0 || _mimes.Count == 0)
                {
                    _extensions = new SortedList<string,string>(StringComparer.OrdinalIgnoreCase);
                    _mimes = new SortedList<string,List<string>>(StringComparer.OrdinalIgnoreCase);
                    foreach (var mime in this)
                    {
                        _mimes.Add(mime.MimeType,new List<string>(mime.Extensions));
                        foreach (string ext in mime.Extensions)
                            if (!_extensions.ContainsKey(ext))
                                _extensions.Add(ext,mime.MimeType);
                    }
                }
            }

            public String GetExtension(string type)
            {
                Init();
                return _mimes.ContainsKey(type) ? _mimes[type][0] : string.Empty;
            }

            public String GetMimeType(string extension)
            {
                Init();
                return _extensions.ContainsKey(extension) ? _extensions[extension] : string.Empty;
            }

        public MimeTypeCollection()
        {
            this.Add(new mimeTypeInfo("application/applixware",new List<string>(new[] { ".aw" })));
            this.Add(new mimeTypeInfo("application/atom+xml",new List<string>(new[] { ".atom" })));
            // ... Whole list from apache's site
            this.Add(new mimeTypeInfo("x-x509-ca-cert",new List<string>(new[] { ".cer" })));
            try
            {
                using (RegistryKey classesRoot = Registry.ClassesRoot)
                using (RegistryKey typeKey = classesRoot.OpenSubKey(@"MIME\Database\Content Type"))
                {
                    string[] subKeyNames = typeKey.GetSubKeyNames();
                    string extension = string.Empty;
                    foreach (string keyname in subKeyNames)
                    {
                        string trimmed = (keyname ?? string.Empty).Trim();
                        if (string.IsNullOrEmpty(trimmed))
                            continue;
                        if (!String.IsNullOrEmpty(GetExtension(trimmed)))
                            continue;
                        string subKey = "MIME\\Database\\Content Type\\" + trimmed;
                        using (RegistryKey curKey = classesRoot.OpenSubKey(subKey))
                        {
                            extension = (curKey.GetValue("Extension") as string ?? string.Empty).Trim();
                            if (extension.Length > 0)
                                this.Add(new mimeTypeInfo(trimmed
                                    ,new List<string>(new[] { extension })));
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                string s = ex.ToString();
            }
        }

        [Serializable]
        public class mimeTypeInfo
        {
            [XmlAttribute(AttributeName = "mimeType")]
            public String MimeType { get; set; }

            [XmlElement("extension")]
            public List<String> Extensions { get; set; }

            public mimeTypeInfo(string mimeType,List<string> extensions)
            {
                MimeType = mimeType;
                Extensions = extensions;
            }

            public mimeTypeInfo() { }
        }
    }
}

}

故事和酒 2024-08-15 21:37:15

System.Web.MimeMapping 有 3 个版本 - 两个版本 4.0(其中之一是内部版本),然后是也是内部版本 2.0。正如所指出的,在 .NET 4.5 框架的 System.Web 4.0 版中有一个该类的公共版本。

对于 RoadkillWiki,我基本上对其进行了逆向工程,以节省每次反射的麻烦,Wiki 的文件处理程序默认情况下尝试使用 IIS/applicationhost.config,然后落入 MimeMapping 类:

private string GetMimeType(string fileExtension, ServerManager serverManager)
{
    try
    {
        string mimeType = "text/plain";

        Microsoft.Web.Administration.Configuration config = serverManager.GetApplicationHostConfiguration();
        ConfigurationSection staticContentSection = config.GetSection("system.webServer/staticContent");
        ConfigurationElementCollection mimemaps = staticContentSection.GetCollection();

        ConfigurationElement element = mimemaps.FirstOrDefault(m => m.Attributes["fileExtension"].Value.ToString() == fileExtension);

        if (element != null)
            mimeType = element.Attributes["mimeType"].Value.ToString();

        return mimeType;
    }
    catch (UnauthorizedAccessException)
    {
        // Shared hosting won't have access to the applicationhost.config file
        return MimeMapping.GetMimeMapping("." +fileExtension);
    }
}

和 MimeMapping:

public class MimeMapping
{
    private static Dictionary<string, string> ExtensionMap = new Dictionary<string, string>();

    static MimeMapping()
    {
        ExtensionMap.Add(".323", "text/h323");
        ExtensionMap.Add(".asx", "video/x-ms-asf");
        ExtensionMap.Add(".acx", "application/internet-property-stream");
        ExtensionMap.Add(".ai", "application/postscript");
        ExtensionMap.Add(".aif", "audio/x-aiff");
        ExtensionMap.Add(".aiff", "audio/aiff");
        ExtensionMap.Add(".axs", "application/olescript");
        ExtensionMap.Add(".aifc", "audio/aiff");
        ExtensionMap.Add(".asr", "video/x-ms-asf");
        ExtensionMap.Add(".avi", "video/x-msvideo");
        ExtensionMap.Add(".asf", "video/x-ms-asf");
        ExtensionMap.Add(".au", "audio/basic");
        ExtensionMap.Add(".application", "application/x-ms-application");
        ExtensionMap.Add(".bin", "application/octet-stream");
        ExtensionMap.Add(".bas", "text/plain");
        ExtensionMap.Add(".bcpio", "application/x-bcpio");
        ExtensionMap.Add(".bmp", "image/bmp");
        ExtensionMap.Add(".cdf", "application/x-cdf");
        ExtensionMap.Add(".cat", "application/vndms-pkiseccat");
        ExtensionMap.Add(".crt", "application/x-x509-ca-cert");
        ExtensionMap.Add(".c", "text/plain");
        ExtensionMap.Add(".css", "text/css");
        ExtensionMap.Add(".cer", "application/x-x509-ca-cert");
        ExtensionMap.Add(".crl", "application/pkix-crl");
        ExtensionMap.Add(".cmx", "image/x-cmx");
        ExtensionMap.Add(".csh", "application/x-csh");
        ExtensionMap.Add(".cod", "image/cis-cod");
        ExtensionMap.Add(".cpio", "application/x-cpio");
        ExtensionMap.Add(".clp", "application/x-msclip");
        ExtensionMap.Add(".crd", "application/x-mscardfile");
        ExtensionMap.Add(".deploy", "application/octet-stream");
        ExtensionMap.Add(".dll", "application/x-msdownload");
        ExtensionMap.Add(".dot", "application/msword");
        ExtensionMap.Add(".doc", "application/msword");
        ExtensionMap.Add(".dvi", "application/x-dvi");
        ExtensionMap.Add(".dir", "application/x-director");
        ExtensionMap.Add(".dxr", "application/x-director");
        ExtensionMap.Add(".der", "application/x-x509-ca-cert");
        ExtensionMap.Add(".dib", "image/bmp");
        ExtensionMap.Add(".dcr", "application/x-director");
        ExtensionMap.Add(".disco", "text/xml");
        ExtensionMap.Add(".exe", "application/octet-stream");
        ExtensionMap.Add(".etx", "text/x-setext");
        ExtensionMap.Add(".evy", "application/envoy");
        ExtensionMap.Add(".eml", "message/rfc822");
        ExtensionMap.Add(".eps", "application/postscript");
        ExtensionMap.Add(".flr", "x-world/x-vrml");
        ExtensionMap.Add(".fif", "application/fractals");
        ExtensionMap.Add(".gtar", "application/x-gtar");
        ExtensionMap.Add(".gif", "image/gif");
        ExtensionMap.Add(".gz", "application/x-gzip");
        ExtensionMap.Add(".hta", "application/hta");
        ExtensionMap.Add(".htc", "text/x-component");
        ExtensionMap.Add(".htt", "text/webviewhtml");
        ExtensionMap.Add(".h", "text/plain");
        ExtensionMap.Add(".hdf", "application/x-hdf");
        ExtensionMap.Add(".hlp", "application/winhlp");
        ExtensionMap.Add(".html", "text/html");
        ExtensionMap.Add(".htm", "text/html");
        ExtensionMap.Add(".hqx", "application/mac-binhex40");
        ExtensionMap.Add(".isp", "application/x-internet-signup");
        ExtensionMap.Add(".iii", "application/x-iphone");
        ExtensionMap.Add(".ief", "image/ief");
        ExtensionMap.Add(".ivf", "video/x-ivf");
        ExtensionMap.Add(".ins", "application/x-internet-signup");
        ExtensionMap.Add(".ico", "image/x-icon");
        ExtensionMap.Add(".jpg", "image/jpeg");
        ExtensionMap.Add(".jfif", "image/pjpeg");
        ExtensionMap.Add(".jpe", "image/jpeg");
        ExtensionMap.Add(".jpeg", "image/jpeg");
        ExtensionMap.Add(".js", "application/x-javascript");
        ExtensionMap.Add(".lsx", "video/x-la-asf");
        ExtensionMap.Add(".latex", "application/x-latex");
        ExtensionMap.Add(".lsf", "video/x-la-asf");
        ExtensionMap.Add(".manifest", "application/x-ms-manifest");
        ExtensionMap.Add(".mhtml", "message/rfc822");
        ExtensionMap.Add(".mny", "application/x-msmoney");
        ExtensionMap.Add(".mht", "message/rfc822");
        ExtensionMap.Add(".mid", "audio/mid");
        ExtensionMap.Add(".mpv2", "video/mpeg");
        ExtensionMap.Add(".man", "application/x-troff-man");
        ExtensionMap.Add(".mvb", "application/x-msmediaview");
        ExtensionMap.Add(".mpeg", "video/mpeg");
        ExtensionMap.Add(".m3u", "audio/x-mpegurl");
        ExtensionMap.Add(".mdb", "application/x-msaccess");
        ExtensionMap.Add(".mpp", "application/vnd.ms-project");
        ExtensionMap.Add(".m1v", "video/mpeg");
        ExtensionMap.Add(".mpa", "video/mpeg");
        ExtensionMap.Add(".me", "application/x-troff-me");
        ExtensionMap.Add(".m13", "application/x-msmediaview");
        ExtensionMap.Add(".movie", "video/x-sgi-movie");
        ExtensionMap.Add(".m14", "application/x-msmediaview");
        ExtensionMap.Add(".mpe", "video/mpeg");
        ExtensionMap.Add(".mp2", "video/mpeg");
        ExtensionMap.Add(".mov", "video/quicktime");
        ExtensionMap.Add(".mp3", "audio/mpeg");
        ExtensionMap.Add(".mpg", "video/mpeg");
        ExtensionMap.Add(".ms", "application/x-troff-ms");
        ExtensionMap.Add(".nc", "application/x-netcdf");
        ExtensionMap.Add(".nws", "message/rfc822");
        ExtensionMap.Add(".oda", "application/oda");
        ExtensionMap.Add(".ods", "application/oleobject");
        ExtensionMap.Add(".pmc", "application/x-perfmon");
        ExtensionMap.Add(".p7r", "application/x-pkcs7-certreqresp");
        ExtensionMap.Add(".p7b", "application/x-pkcs7-certificates");
        ExtensionMap.Add(".p7s", "application/pkcs7-signature");
        ExtensionMap.Add(".pmw", "application/x-perfmon");
        ExtensionMap.Add(".ps", "application/postscript");
        ExtensionMap.Add(".p7c", "application/pkcs7-mime");
        ExtensionMap.Add(".pbm", "image/x-portable-bitmap");
        ExtensionMap.Add(".ppm", "image/x-portable-pixmap");
        ExtensionMap.Add(".pub", "application/x-mspublisher");
        ExtensionMap.Add(".pnm", "image/x-portable-anymap");
        ExtensionMap.Add(".pml", "application/x-perfmon");
        ExtensionMap.Add(".p10", "application/pkcs10");
        ExtensionMap.Add(".pfx", "application/x-pkcs12");
        ExtensionMap.Add(".p12", "application/x-pkcs12");
        ExtensionMap.Add(".pdf", "application/pdf");
        ExtensionMap.Add(".pps", "application/vnd.ms-powerpoint");
        ExtensionMap.Add(".p7m", "application/pkcs7-mime");
        ExtensionMap.Add(".pko", "application/vndms-pkipko");
        ExtensionMap.Add(".ppt", "application/vnd.ms-powerpoint");
        ExtensionMap.Add(".pmr", "application/x-perfmon");
        ExtensionMap.Add(".pma", "application/x-perfmon");
        ExtensionMap.Add(".pot", "application/vnd.ms-powerpoint");
        ExtensionMap.Add(".prf", "application/pics-rules");
        ExtensionMap.Add(".pgm", "image/x-portable-graymap");
        ExtensionMap.Add(".qt", "video/quicktime");
        ExtensionMap.Add(".ra", "audio/x-pn-realaudio");
        ExtensionMap.Add(".rgb", "image/x-rgb");
        ExtensionMap.Add(".ram", "audio/x-pn-realaudio");
        ExtensionMap.Add(".rmi", "audio/mid");
        ExtensionMap.Add(".ras", "image/x-cmu-raster");
        ExtensionMap.Add(".roff", "application/x-troff");
        ExtensionMap.Add(".rtf", "application/rtf");
        ExtensionMap.Add(".rtx", "text/richtext");
        ExtensionMap.Add(".sv4crc", "application/x-sv4crc");
        ExtensionMap.Add(".spc", "application/x-pkcs7-certificates");
        ExtensionMap.Add(".setreg", "application/set-registration-initiation");
        ExtensionMap.Add(".snd", "audio/basic");
        ExtensionMap.Add(".stl", "application/vndms-pkistl");
        ExtensionMap.Add(".setpay", "application/set-payment-initiation");
        ExtensionMap.Add(".stm", "text/html");
        ExtensionMap.Add(".shar", "application/x-shar");
        ExtensionMap.Add(".sh", "application/x-sh");
        ExtensionMap.Add(".sit", "application/x-stuffit");
        ExtensionMap.Add(".spl", "application/futuresplash");
        ExtensionMap.Add(".sct", "text/scriptlet");
        ExtensionMap.Add(".scd", "application/x-msschedule");
        ExtensionMap.Add(".sst", "application/vndms-pkicertstore");
        ExtensionMap.Add(".src", "application/x-wais-source");
        ExtensionMap.Add(".sv4cpio", "application/x-sv4cpio");
        ExtensionMap.Add(".tex", "application/x-tex");
        ExtensionMap.Add(".tgz", "application/x-compressed");
        ExtensionMap.Add(".t", "application/x-troff");
        ExtensionMap.Add(".tar", "application/x-tar");
        ExtensionMap.Add(".tr", "application/x-troff");
        ExtensionMap.Add(".tif", "image/tiff");
        ExtensionMap.Add(".txt", "text/plain");
        ExtensionMap.Add(".texinfo", "application/x-texinfo");
        ExtensionMap.Add(".trm", "application/x-msterminal");
        ExtensionMap.Add(".tiff", "image/tiff");
        ExtensionMap.Add(".tcl", "application/x-tcl");
        ExtensionMap.Add(".texi", "application/x-texinfo");
        ExtensionMap.Add(".tsv", "text/tab-separated-values");
        ExtensionMap.Add(".ustar", "application/x-ustar");
        ExtensionMap.Add(".uls", "text/iuls");
        ExtensionMap.Add(".vcf", "text/x-vcard");
        ExtensionMap.Add(".wps", "application/vnd.ms-works");
        ExtensionMap.Add(".wav", "audio/wav");
        ExtensionMap.Add(".wrz", "x-world/x-vrml");
        ExtensionMap.Add(".wri", "application/x-mswrite");
        ExtensionMap.Add(".wks", "application/vnd.ms-works");
        ExtensionMap.Add(".wmf", "application/x-msmetafile");
        ExtensionMap.Add(".wcm", "application/vnd.ms-works");
        ExtensionMap.Add(".wrl", "x-world/x-vrml");
        ExtensionMap.Add(".wdb", "application/vnd.ms-works");
        ExtensionMap.Add(".wsdl", "text/xml");
        ExtensionMap.Add(".xml", "text/xml");
        ExtensionMap.Add(".xlm", "application/vnd.ms-excel");
        ExtensionMap.Add(".xaf", "x-world/x-vrml");
        ExtensionMap.Add(".xla", "application/vnd.ms-excel");
        ExtensionMap.Add(".xls", "application/vnd.ms-excel");
        ExtensionMap.Add(".xof", "x-world/x-vrml");
        ExtensionMap.Add(".xlt", "application/vnd.ms-excel");
        ExtensionMap.Add(".xlc", "application/vnd.ms-excel");
        ExtensionMap.Add(".xsl", "text/xml");
        ExtensionMap.Add(".xbm", "image/x-xbitmap");
        ExtensionMap.Add(".xlw", "application/vnd.ms-excel");
        ExtensionMap.Add(".xpm", "image/x-xpixmap");
        ExtensionMap.Add(".xwd", "image/x-xwindowdump");
        ExtensionMap.Add(".xsd", "text/xml");
        ExtensionMap.Add(".z", "application/x-compress");
        ExtensionMap.Add(".zip", "application/x-zip-compressed");
        ExtensionMap.Add(".*", "application/octet-stream");
    }

    public static string GetMimeMapping(string fileExtension)
    {
        if (ExtensionMap.ContainsKey(fileExtension))
            return ExtensionMap[fileExtension];
        else
            return ExtensionMap[".*"];
    }
}

The System.Web.MimeMapping has 3 versions - two version 4.0s (where one of these is internal), and then a version 2.0 which is also internal. As pointed out, there is a public version of the class in System.Web version 4.0 for the .NET 4.5 framework.

For RoadkillWiki I've basically reverse engineered it to save the bother of reflecting each time, the Wiki's file handler tries to the use IIS/applicationhost.config by default, and then falls through to the MimeMapping class:

private string GetMimeType(string fileExtension, ServerManager serverManager)
{
    try
    {
        string mimeType = "text/plain";

        Microsoft.Web.Administration.Configuration config = serverManager.GetApplicationHostConfiguration();
        ConfigurationSection staticContentSection = config.GetSection("system.webServer/staticContent");
        ConfigurationElementCollection mimemaps = staticContentSection.GetCollection();

        ConfigurationElement element = mimemaps.FirstOrDefault(m => m.Attributes["fileExtension"].Value.ToString() == fileExtension);

        if (element != null)
            mimeType = element.Attributes["mimeType"].Value.ToString();

        return mimeType;
    }
    catch (UnauthorizedAccessException)
    {
        // Shared hosting won't have access to the applicationhost.config file
        return MimeMapping.GetMimeMapping("." +fileExtension);
    }
}

And MimeMapping:

public class MimeMapping
{
    private static Dictionary<string, string> ExtensionMap = new Dictionary<string, string>();

    static MimeMapping()
    {
        ExtensionMap.Add(".323", "text/h323");
        ExtensionMap.Add(".asx", "video/x-ms-asf");
        ExtensionMap.Add(".acx", "application/internet-property-stream");
        ExtensionMap.Add(".ai", "application/postscript");
        ExtensionMap.Add(".aif", "audio/x-aiff");
        ExtensionMap.Add(".aiff", "audio/aiff");
        ExtensionMap.Add(".axs", "application/olescript");
        ExtensionMap.Add(".aifc", "audio/aiff");
        ExtensionMap.Add(".asr", "video/x-ms-asf");
        ExtensionMap.Add(".avi", "video/x-msvideo");
        ExtensionMap.Add(".asf", "video/x-ms-asf");
        ExtensionMap.Add(".au", "audio/basic");
        ExtensionMap.Add(".application", "application/x-ms-application");
        ExtensionMap.Add(".bin", "application/octet-stream");
        ExtensionMap.Add(".bas", "text/plain");
        ExtensionMap.Add(".bcpio", "application/x-bcpio");
        ExtensionMap.Add(".bmp", "image/bmp");
        ExtensionMap.Add(".cdf", "application/x-cdf");
        ExtensionMap.Add(".cat", "application/vndms-pkiseccat");
        ExtensionMap.Add(".crt", "application/x-x509-ca-cert");
        ExtensionMap.Add(".c", "text/plain");
        ExtensionMap.Add(".css", "text/css");
        ExtensionMap.Add(".cer", "application/x-x509-ca-cert");
        ExtensionMap.Add(".crl", "application/pkix-crl");
        ExtensionMap.Add(".cmx", "image/x-cmx");
        ExtensionMap.Add(".csh", "application/x-csh");
        ExtensionMap.Add(".cod", "image/cis-cod");
        ExtensionMap.Add(".cpio", "application/x-cpio");
        ExtensionMap.Add(".clp", "application/x-msclip");
        ExtensionMap.Add(".crd", "application/x-mscardfile");
        ExtensionMap.Add(".deploy", "application/octet-stream");
        ExtensionMap.Add(".dll", "application/x-msdownload");
        ExtensionMap.Add(".dot", "application/msword");
        ExtensionMap.Add(".doc", "application/msword");
        ExtensionMap.Add(".dvi", "application/x-dvi");
        ExtensionMap.Add(".dir", "application/x-director");
        ExtensionMap.Add(".dxr", "application/x-director");
        ExtensionMap.Add(".der", "application/x-x509-ca-cert");
        ExtensionMap.Add(".dib", "image/bmp");
        ExtensionMap.Add(".dcr", "application/x-director");
        ExtensionMap.Add(".disco", "text/xml");
        ExtensionMap.Add(".exe", "application/octet-stream");
        ExtensionMap.Add(".etx", "text/x-setext");
        ExtensionMap.Add(".evy", "application/envoy");
        ExtensionMap.Add(".eml", "message/rfc822");
        ExtensionMap.Add(".eps", "application/postscript");
        ExtensionMap.Add(".flr", "x-world/x-vrml");
        ExtensionMap.Add(".fif", "application/fractals");
        ExtensionMap.Add(".gtar", "application/x-gtar");
        ExtensionMap.Add(".gif", "image/gif");
        ExtensionMap.Add(".gz", "application/x-gzip");
        ExtensionMap.Add(".hta", "application/hta");
        ExtensionMap.Add(".htc", "text/x-component");
        ExtensionMap.Add(".htt", "text/webviewhtml");
        ExtensionMap.Add(".h", "text/plain");
        ExtensionMap.Add(".hdf", "application/x-hdf");
        ExtensionMap.Add(".hlp", "application/winhlp");
        ExtensionMap.Add(".html", "text/html");
        ExtensionMap.Add(".htm", "text/html");
        ExtensionMap.Add(".hqx", "application/mac-binhex40");
        ExtensionMap.Add(".isp", "application/x-internet-signup");
        ExtensionMap.Add(".iii", "application/x-iphone");
        ExtensionMap.Add(".ief", "image/ief");
        ExtensionMap.Add(".ivf", "video/x-ivf");
        ExtensionMap.Add(".ins", "application/x-internet-signup");
        ExtensionMap.Add(".ico", "image/x-icon");
        ExtensionMap.Add(".jpg", "image/jpeg");
        ExtensionMap.Add(".jfif", "image/pjpeg");
        ExtensionMap.Add(".jpe", "image/jpeg");
        ExtensionMap.Add(".jpeg", "image/jpeg");
        ExtensionMap.Add(".js", "application/x-javascript");
        ExtensionMap.Add(".lsx", "video/x-la-asf");
        ExtensionMap.Add(".latex", "application/x-latex");
        ExtensionMap.Add(".lsf", "video/x-la-asf");
        ExtensionMap.Add(".manifest", "application/x-ms-manifest");
        ExtensionMap.Add(".mhtml", "message/rfc822");
        ExtensionMap.Add(".mny", "application/x-msmoney");
        ExtensionMap.Add(".mht", "message/rfc822");
        ExtensionMap.Add(".mid", "audio/mid");
        ExtensionMap.Add(".mpv2", "video/mpeg");
        ExtensionMap.Add(".man", "application/x-troff-man");
        ExtensionMap.Add(".mvb", "application/x-msmediaview");
        ExtensionMap.Add(".mpeg", "video/mpeg");
        ExtensionMap.Add(".m3u", "audio/x-mpegurl");
        ExtensionMap.Add(".mdb", "application/x-msaccess");
        ExtensionMap.Add(".mpp", "application/vnd.ms-project");
        ExtensionMap.Add(".m1v", "video/mpeg");
        ExtensionMap.Add(".mpa", "video/mpeg");
        ExtensionMap.Add(".me", "application/x-troff-me");
        ExtensionMap.Add(".m13", "application/x-msmediaview");
        ExtensionMap.Add(".movie", "video/x-sgi-movie");
        ExtensionMap.Add(".m14", "application/x-msmediaview");
        ExtensionMap.Add(".mpe", "video/mpeg");
        ExtensionMap.Add(".mp2", "video/mpeg");
        ExtensionMap.Add(".mov", "video/quicktime");
        ExtensionMap.Add(".mp3", "audio/mpeg");
        ExtensionMap.Add(".mpg", "video/mpeg");
        ExtensionMap.Add(".ms", "application/x-troff-ms");
        ExtensionMap.Add(".nc", "application/x-netcdf");
        ExtensionMap.Add(".nws", "message/rfc822");
        ExtensionMap.Add(".oda", "application/oda");
        ExtensionMap.Add(".ods", "application/oleobject");
        ExtensionMap.Add(".pmc", "application/x-perfmon");
        ExtensionMap.Add(".p7r", "application/x-pkcs7-certreqresp");
        ExtensionMap.Add(".p7b", "application/x-pkcs7-certificates");
        ExtensionMap.Add(".p7s", "application/pkcs7-signature");
        ExtensionMap.Add(".pmw", "application/x-perfmon");
        ExtensionMap.Add(".ps", "application/postscript");
        ExtensionMap.Add(".p7c", "application/pkcs7-mime");
        ExtensionMap.Add(".pbm", "image/x-portable-bitmap");
        ExtensionMap.Add(".ppm", "image/x-portable-pixmap");
        ExtensionMap.Add(".pub", "application/x-mspublisher");
        ExtensionMap.Add(".pnm", "image/x-portable-anymap");
        ExtensionMap.Add(".pml", "application/x-perfmon");
        ExtensionMap.Add(".p10", "application/pkcs10");
        ExtensionMap.Add(".pfx", "application/x-pkcs12");
        ExtensionMap.Add(".p12", "application/x-pkcs12");
        ExtensionMap.Add(".pdf", "application/pdf");
        ExtensionMap.Add(".pps", "application/vnd.ms-powerpoint");
        ExtensionMap.Add(".p7m", "application/pkcs7-mime");
        ExtensionMap.Add(".pko", "application/vndms-pkipko");
        ExtensionMap.Add(".ppt", "application/vnd.ms-powerpoint");
        ExtensionMap.Add(".pmr", "application/x-perfmon");
        ExtensionMap.Add(".pma", "application/x-perfmon");
        ExtensionMap.Add(".pot", "application/vnd.ms-powerpoint");
        ExtensionMap.Add(".prf", "application/pics-rules");
        ExtensionMap.Add(".pgm", "image/x-portable-graymap");
        ExtensionMap.Add(".qt", "video/quicktime");
        ExtensionMap.Add(".ra", "audio/x-pn-realaudio");
        ExtensionMap.Add(".rgb", "image/x-rgb");
        ExtensionMap.Add(".ram", "audio/x-pn-realaudio");
        ExtensionMap.Add(".rmi", "audio/mid");
        ExtensionMap.Add(".ras", "image/x-cmu-raster");
        ExtensionMap.Add(".roff", "application/x-troff");
        ExtensionMap.Add(".rtf", "application/rtf");
        ExtensionMap.Add(".rtx", "text/richtext");
        ExtensionMap.Add(".sv4crc", "application/x-sv4crc");
        ExtensionMap.Add(".spc", "application/x-pkcs7-certificates");
        ExtensionMap.Add(".setreg", "application/set-registration-initiation");
        ExtensionMap.Add(".snd", "audio/basic");
        ExtensionMap.Add(".stl", "application/vndms-pkistl");
        ExtensionMap.Add(".setpay", "application/set-payment-initiation");
        ExtensionMap.Add(".stm", "text/html");
        ExtensionMap.Add(".shar", "application/x-shar");
        ExtensionMap.Add(".sh", "application/x-sh");
        ExtensionMap.Add(".sit", "application/x-stuffit");
        ExtensionMap.Add(".spl", "application/futuresplash");
        ExtensionMap.Add(".sct", "text/scriptlet");
        ExtensionMap.Add(".scd", "application/x-msschedule");
        ExtensionMap.Add(".sst", "application/vndms-pkicertstore");
        ExtensionMap.Add(".src", "application/x-wais-source");
        ExtensionMap.Add(".sv4cpio", "application/x-sv4cpio");
        ExtensionMap.Add(".tex", "application/x-tex");
        ExtensionMap.Add(".tgz", "application/x-compressed");
        ExtensionMap.Add(".t", "application/x-troff");
        ExtensionMap.Add(".tar", "application/x-tar");
        ExtensionMap.Add(".tr", "application/x-troff");
        ExtensionMap.Add(".tif", "image/tiff");
        ExtensionMap.Add(".txt", "text/plain");
        ExtensionMap.Add(".texinfo", "application/x-texinfo");
        ExtensionMap.Add(".trm", "application/x-msterminal");
        ExtensionMap.Add(".tiff", "image/tiff");
        ExtensionMap.Add(".tcl", "application/x-tcl");
        ExtensionMap.Add(".texi", "application/x-texinfo");
        ExtensionMap.Add(".tsv", "text/tab-separated-values");
        ExtensionMap.Add(".ustar", "application/x-ustar");
        ExtensionMap.Add(".uls", "text/iuls");
        ExtensionMap.Add(".vcf", "text/x-vcard");
        ExtensionMap.Add(".wps", "application/vnd.ms-works");
        ExtensionMap.Add(".wav", "audio/wav");
        ExtensionMap.Add(".wrz", "x-world/x-vrml");
        ExtensionMap.Add(".wri", "application/x-mswrite");
        ExtensionMap.Add(".wks", "application/vnd.ms-works");
        ExtensionMap.Add(".wmf", "application/x-msmetafile");
        ExtensionMap.Add(".wcm", "application/vnd.ms-works");
        ExtensionMap.Add(".wrl", "x-world/x-vrml");
        ExtensionMap.Add(".wdb", "application/vnd.ms-works");
        ExtensionMap.Add(".wsdl", "text/xml");
        ExtensionMap.Add(".xml", "text/xml");
        ExtensionMap.Add(".xlm", "application/vnd.ms-excel");
        ExtensionMap.Add(".xaf", "x-world/x-vrml");
        ExtensionMap.Add(".xla", "application/vnd.ms-excel");
        ExtensionMap.Add(".xls", "application/vnd.ms-excel");
        ExtensionMap.Add(".xof", "x-world/x-vrml");
        ExtensionMap.Add(".xlt", "application/vnd.ms-excel");
        ExtensionMap.Add(".xlc", "application/vnd.ms-excel");
        ExtensionMap.Add(".xsl", "text/xml");
        ExtensionMap.Add(".xbm", "image/x-xbitmap");
        ExtensionMap.Add(".xlw", "application/vnd.ms-excel");
        ExtensionMap.Add(".xpm", "image/x-xpixmap");
        ExtensionMap.Add(".xwd", "image/x-xwindowdump");
        ExtensionMap.Add(".xsd", "text/xml");
        ExtensionMap.Add(".z", "application/x-compress");
        ExtensionMap.Add(".zip", "application/x-zip-compressed");
        ExtensionMap.Add(".*", "application/octet-stream");
    }

    public static string GetMimeMapping(string fileExtension)
    {
        if (ExtensionMap.ContainsKey(fileExtension))
            return ExtensionMap[fileExtension];
        else
            return ExtensionMap[".*"];
    }
}
疯狂的代价 2024-08-15 21:37:15

我编写了一个程序来获取 Apache mime.types 文件并将其转换为按文件扩展名键入的 C# Dictionary。它在这里:

https://github.com/cymen/ApacheMimeTypesToDotNet

实际输出是这个文件:

https://github.com/cymen/ApacheMimeTypesToDotNet/blob/master/ApacheMimeTypes.cs

希望其他人也发现它有用!

I've written a program to fetch and convert the Apache mime.types file to a C# Dictionary<string, string> keyed by file extension. It's here:

https://github.com/cymen/ApacheMimeTypesToDotNet

The actual output is this file:

https://github.com/cymen/ApacheMimeTypesToDotNet/blob/master/ApacheMimeTypes.cs

Hopefully someone else finds it useful too!

_失温 2024-08-15 21:37:15

Nisus - 您愿意将您的实用程序的完整源代码发布到某个地方吗?这真的很有帮助。谢谢!

没关系......

我编辑了 apache 定义文件,使其仅包含具有定义的扩展名的条目,然后扩展代码以在运行时从文本文件加载类型/扩展名。也许不太优雅,但肯定比为 mime 类型创建/维护 630 行源代码要好。

[在 MimeTypeCollection 的构造函数中而不是这个东西:
this.Add(new mimeTypeInfo("application/applixware",new List(new[] { ".aw" })));]

        // import mime/extension definition list to facilitate maintenance
    string dir = AppDomain.CurrentDomain.BaseDirectory;
    using (TextReader streamReader = new StreamReader(Path.Combine(dir, "MimeDefinitions.txt")))
    {
      string input;
      while ((input = streamReader.ReadLine()) != null)
      {
        if (input.Substring(0, 1) != "#")
        {
          // text line format ::= [contenttype]<tab>[space delimited list of extensions, without dot]
          string contentType = input.Group("0\t1");
          string extensionList = input.Group("1\t1");
          string[] extensions = extensionList.Split(" ".ToCharArray());
          List<string> extensionSet = new List<string>();
          foreach (string term in extensions)
          {
            extensionSet.Add("."+term);
          }
          this.Add(new mimeTypeInfo(contentType, extensionSet));
        }
      }
    }

我还发现 Init() 方法会被调用,而 _extensions 和 _mime 成员不会已完全初始化,因此我将其更改为:

if (_extensions == null || _mimes == null || _mimes.Count != this.Count)

无论如何,我现在如何创建一个可以处理我需要的外部定义和本地注册表的类。

谢谢!

Nisus - would you be willing to post the entire source code for your utility somewhere? that would really be helpful. thanks!

Never mind....

I edited the apache definition file to only contain entries with defined extensions, then extended the code to load in the types/extensions from the text file at run time. Not elegant perhaps but sure beats creating/maintaining 630 lines of source code for the mime types.

[in the constructor for MimeTypeCollection instead of this stuff:
this.Add(new mimeTypeInfo("application/applixware",new List(new[] { ".aw" })));]

        // import mime/extension definition list to facilitate maintenance
    string dir = AppDomain.CurrentDomain.BaseDirectory;
    using (TextReader streamReader = new StreamReader(Path.Combine(dir, "MimeDefinitions.txt")))
    {
      string input;
      while ((input = streamReader.ReadLine()) != null)
      {
        if (input.Substring(0, 1) != "#")
        {
          // text line format ::= [contenttype]<tab>[space delimited list of extensions, without dot]
          string contentType = input.Group("0\t1");
          string extensionList = input.Group("1\t1");
          string[] extensions = extensionList.Split(" ".ToCharArray());
          List<string> extensionSet = new List<string>();
          foreach (string term in extensions)
          {
            extensionSet.Add("."+term);
          }
          this.Add(new mimeTypeInfo(contentType, extensionSet));
        }
      }
    }

I also found that the Init() method would be called and the _extensions and _mime members would not be completely initialized so I changed it to read:

if (_extensions == null || _mimes == null || _mimes.Count != this.Count)

Anyway, I now how a class that can handle the external defs and local registry I needed.

Thanks!

森罗 2024-08-15 21:37:15

我还发现会调用 Init() 方法,并且 _extensions 和 _mime 成员不会完全初始化,所以我将其更改为读取,最好的方法是从 MimeTypeCollection 的构造函数中删除调用 GetExtension:

        public MimeTypeCollection()
        {
            this.Add(new mimeTypeInfo("application/applixware", new List<string>(new[] { ".aw" })));
            this.Add(new mimeTypeInfo("application/atom+xml", new List<string>(new[] { ".atom" })));
            // ... Whole list from apache's site
            this.Add(new mimeTypeInfo("x-x509-ca-cert", new List<string>(new[] { ".cer" })));
            try
            {
                using (RegistryKey classesRoot = Registry.ClassesRoot)
                using (RegistryKey typeKey = classesRoot.OpenSubKey(@"MIME\Database\Content Type"))
                {
                    string[] subKeyNames = typeKey.GetSubKeyNames();
                    string extension = string.Empty;
                    foreach (string keyname in subKeyNames)
                    {
                        string trimmed = (keyname ?? string.Empty).Trim();
                        if (string.IsNullOrEmpty(trimmed))
                            continue;
                        if (this.Exists(mime => mime.MimeType == trimmed))
                            continue;
                        //if (!String.IsNullOrEmpty(GetExtension(trimmed)))
                        //  continue;
                        string subKey = "MIME\\Database\\Content Type\\" + trimmed;
                        using (RegistryKey curKey = classesRoot.OpenSubKey(subKey))
                        {
                            extension = (curKey.GetValue("Extension") as string ?? string.Empty).Trim();
                            if (extension.Length > 0)
                                this.Add(new mimeTypeInfo(trimmed
                                        , new List<string>(new[] { extension })));
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                string s = ex.ToString();
            }
        }

I also found that the Init() method would be called and the _extensions and _mime members would not be completely initialized so I changed it to read, and the best way is, remove call GetExtension in constructor from MimeTypeCollection:

        public MimeTypeCollection()
        {
            this.Add(new mimeTypeInfo("application/applixware", new List<string>(new[] { ".aw" })));
            this.Add(new mimeTypeInfo("application/atom+xml", new List<string>(new[] { ".atom" })));
            // ... Whole list from apache's site
            this.Add(new mimeTypeInfo("x-x509-ca-cert", new List<string>(new[] { ".cer" })));
            try
            {
                using (RegistryKey classesRoot = Registry.ClassesRoot)
                using (RegistryKey typeKey = classesRoot.OpenSubKey(@"MIME\Database\Content Type"))
                {
                    string[] subKeyNames = typeKey.GetSubKeyNames();
                    string extension = string.Empty;
                    foreach (string keyname in subKeyNames)
                    {
                        string trimmed = (keyname ?? string.Empty).Trim();
                        if (string.IsNullOrEmpty(trimmed))
                            continue;
                        if (this.Exists(mime => mime.MimeType == trimmed))
                            continue;
                        //if (!String.IsNullOrEmpty(GetExtension(trimmed)))
                        //  continue;
                        string subKey = "MIME\\Database\\Content Type\\" + trimmed;
                        using (RegistryKey curKey = classesRoot.OpenSubKey(subKey))
                        {
                            extension = (curKey.GetValue("Extension") as string ?? string.Empty).Trim();
                            if (extension.Length > 0)
                                this.Add(new mimeTypeInfo(trimmed
                                        , new List<string>(new[] { extension })));
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                string s = ex.ToString();
            }
        }
心是晴朗的。 2024-08-15 21:37:15

我想提醒您,不要在未根据文件的实际内容进行验证的情况下检索文件的 Mime/内容类型,因为这可能会给您的系统和用户带来严重的安全风险。

尽管存在此类的有效用例,但攻击者可能会攻击您的系统,或通过将可执行文件或脚本伪装成其他非可疑文件类型,将其用作向其他用户传播恶意文件的机制。

建议您在继续处理(或提供下载)之前认真考虑沙箱并对上传的文件执行深度内容检查。

I would just like to caution you against retrieving the Mime / content type of a file without validating it against the actual content of the file, as it could pose a serious security risk to your system and users.

Although there are valid use cases for something like this, attackers can potentially attack your system or use it as a mechanism to propagate malicious files to other users, by disguising executables or scripts as other, non-suspect file types.

It is advisable that you seriously consider sandboxing and performing deep content inspection on uploaded files before continuing to process it (or making it available for download).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文