File extensions and MIME Types in .NET

Marc Climent picture Marc Climent · Oct 23, 2009 · Viewed 70.9k times · Source

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?

Answer

Lucero picture Lucero · Oct 23, 2009

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.