User Controls and the Publish Web Site command
Visual Studio 2010’s Publish Web Site command offers the option “Allow this precompiled site to be updatable”. When used and your application has User Control (.ascx) files, the published application no longer contains your user controls! Instead, the \bin folder contains new files ending in the .compiled extension, one for each User Control. Your User Controls still work though, just through some hidden behaviors that I will discuss here.
First, the Page.LoadControl() method still works. LoadControl() creates a User Control on demand. In the past, it had to build it from the User Control’s file contents. Without the file present, it knows about the missing files through those new files in the .bin folder.
In my case, I was calling LoadControl after checking for a specific User Control file via a FileExists() function. I used System.Web.Hosting.VirtualPathProvider.FileExists() function. It turns out that VirtualPathProvider.FileExists() does not support the .compiled files and always returns false.
The solution comes from how ASP.NET Dynamic Data v4 does it: Use the System.Web.Compilation.BuildManager.GetObjectFactory() method. Always pass false for the ThrowException parameter and test the result for null. If not null, the file exists.
Here is a method that replaces the Page.LoadControl() method, loading a User Control if it exists. It works with the Publish Web Site feature as discussed.
public System.Web.UI.WebControls.UserControl LoadUserControlIfExists(string pVirtualFilePath)
{
if (System.Web.Compilation.BuildManager.GetObjectFactory(pVirtualFilePath, false) != null)
return Page.LoadControl(pVirtualFilePath);
return null;
}