Custom Virtual Path Provider in IIS

asp.netiis-7.5

What is the correct configuration to implement a custom virtual path provider in IIS 7.5? The following code works as expected when run from Visual Studio using the ASP.NET Development Server but does not load the image when run from IIS.

.NET 4.0 Project File

CustomVirtualPathProvider.zip – SkyDrive file

Web.config

<?xml version="1.0"?>
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.webServer>
     <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>
</configuration>

Default.aspx

<%@ Page Title="Home Page" Language="C#" AutoEventWireup="true" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Virtual Path Provider</title>
    </head>
    <body>
        <img src="Box.png" />
    </body>
</html>

Global.asax

public class Global : System.Web.HttpApplication
{
    void Application_Start(object sender, EventArgs e)
    {
        System.Web.Hosting.HostingEnvironment.RegisterVirtualPathProvider(new WebApplication1.CustomVirtualPathProvider());
    }
}

CustomVirtualFile.cs

public class CustomVirtualFile : System.Web.Hosting.VirtualFile
{
    private string _VirtualPath;

    public CustomVirtualFile(string virtualPath) : base(virtualPath)
    {
        _VirtualPath = virtualPath.Replace("/", string.Empty);
    }

    public override Stream Open()
    {
        string ImageFile =
            System.IO.Path.Combine(HttpContext.Current.Request.PhysicalApplicationPath, @"Crazy\Image\Path", _VirtualPath);
        return System.IO.File.Open(ImageFile, FileMode.Open, FileAccess.Read);
    }
}

CustomVirtualPathProvider.cs

public class CustomVirtualPathProvider : System.Web.Hosting.VirtualPathProvider
{
    Collection<string> ImageTypes;

    public CustomVirtualPathProvider() : base()
    {
        ImageTypes = new Collection<string>();
        ImageTypes.Add(".PNG");
        ImageTypes.Add(".GIF");
    }

    public override bool FileExists(string virtualPath)
    {
        if (IsImage(virtualPath))
        {
            return true;
        }
        return base.FileExists(virtualPath);
    }

    public override System.Web.Hosting.VirtualFile GetFile(string virtualPath)
    {
        if (IsImage(virtualPath))
        {
            return new CustomVirtualFile(virtualPath);
        }
        return base.GetFile(virtualPath);
    }

    private bool IsImage(string file)
    {
        return ImageTypes.IndexOf(file.ToUpperInvariant().Substring(file.Length - 4, 4)) > -1;
    }
}

Filesystem

\Crazy\Image\Path\Box.png

IIS Configuration

Default site with no configuration changes.

Best Answer

Here is what I found to "fix" my issue.

http://sunali.com/2008/01/09/virtualpathprovider-in-precompiled-web-sites/

In brief:

HostingEnviornment explicitly ignores Virtual Path Providers in precompiled sites. You can circumvent this limitation by using reflection to call an internal version that omits this check. Thus, instead of calling

HostingEnviornment.RegisterVirtualPathProvider(new EmbeddedViewVirtualPathProvider();

call this instead:

typeof(HostingEnvironment).GetMethod("RegisterVirtualPathProviderInternal",
      BindingFlags.Static | BindingFlags.InvokeMethod | BindingFlags.NonPublic)
    .Invoke(null, new object[] {new EmbeddedViewPathProvider()});
Related Topic