Search code examples
asp.netwebprecompiled

Check if ascx control exist in precompiled asp.net website


I would like to check if an ASCX file exists before I open it because it is loadded dynamically. That should be easy by using the following code:System.IO.File.Exists(Server.MapPath(controlPath)). But this doesn't work in precompiled website because ASCX files don't exist anymore.

Any help will be appreciated.

Update: I precompile a website without "Allow precompiled site to be updatable" option.


Solution

  • File.Exists will not work because when an .ascx is precompiled it will not be physically present on the disk.

    HostingEnvironment.VirtualPathProvider.FileExists will not work as well, the default implementation is MapPathBasedVirtualPathProvider, which expects files to be physically present on the disk.

    In such scenario, TemplateControl.LoadControl use the BuildManager which already cached those virtual files, so their physical presence is not checked.

    Using reflection, it's possible to check if these files are cached (read: exist):

    public static bool IsPrecompiledFileExists(string virtualPath)
    {
        Type virtualPathType = BuildManager.GetType("System.Web.VirtualPath", true);
        MethodInfo createMethodInfo = virtualPathType.GetMethod("Create", new Type[] {typeof(string)});
        object virtualPathObject = createMethodInfo.Invoke(null, new object[] { virtualPath });
    
        MethodInfo getVPathBuildResultFromCacheMethodInfo = typeof(BuildManager).GetMethod("GetVPathBuildResultFromCache", BindingFlags.Static | BindingFlags.NonPublic);
        object buildResult = getVPathBuildResultFromCacheMethodInfo.Invoke(null, new object[] { virtualPathObject });
        return buildResult != null;
    }
    

    To make the solution compatible with additional deployment scenarios, you may probably want to use:

    public static bool IsVirtualFileExists(string virtualPath)
    {
        return HostingEnvironment.VirtualPathProvider.FileExists(virtualPath) ||
               IsPrecompiledFileExists(virtualPath);
    }
    

    Edit: Peter Blum has a better and faster solution.

    p.s. For .Net Framework 2.0, BuildManager.CreateInstanceFromVirtualPath could be used as well (We can learn if the file exist or not based on the exception thrown).