R – Web Deployment Project: Publish without Precompilation


The Question

Is it possible to publish a web application project using a web deployment project without precompilation?


In order to split out web controls and pages into a separate assembly, I am using a custom VirtualPathProvider to load these resources. I am using web deployment projects and msbuild at cmd line to deploy these projects.

The crux of the matter is that VirtualPathProviders are not supported for precompiled applications. I have found a workaround for regular files here. However, this does not work for application files such as ascx and aspx pages. It throws an exception along the lines of "the file has not been pre-compiled, and cannot be requested".

As a result, I have decided to attempt to abandon precompilation altogether and take the initial request performance hit since our site traffic isn't particularly high. However, I can't figure out how to do this using Web Deployment Projects, which are already very baked into our build process.


I am looking into customizing the Microsoft.WebDeployment.targets file in order to accomplish this, but I haven't had any luck so far.


In digging around in the Microsoft.WebDeployment.targets file, I have found that there is no straightforward way of decoupling Web Deployment projects from Web Application Precompilation. In fact, I'm not certain there's any need to. What I am now using instead is something akin to the following snippet. I just put it into the project file with a condition attr to not deploy for Debug builds.

<Target Name="AfterBuild">
    <!-- clean output dir -->
    <CreateItem Include="$(output)**\*.*">
        <Output TaskParameter="Include" ItemName="OldFiles"/>
    <Delete ContinueOnError="true"
        TreatErrorsAsWarnings="true" Files="@(OldFiles)"/>
    <!-- copy content -->
    <Copy SourceFiles="@(Content)"
        DestinationFolder="$(output)%(Content.RelativeDir)" />
    <CreateItem Include="$(OutputPath)\*">
        <Output TaskParameter="Include" ItemName="Binaries" />
    <Copy SourceFiles="@(Binaries)" DestinationFolder="$(output)bin" />
    <ReplaceConfigSections RootPath="$(output)"

It seems as though this is all that's needed in order to deploy a project without precompilation. Let me know if you find anything better.

Best Solution

To make VirtualPathProvider work with precompiled website (or at most partially precompiled), you need to do what Alconja say in conjunction to this http://sunali.com/2008/01/09/virtualpathprovider-in-precompiled-web-sites/

Instead common "AppInitialize":

public static void AppInitialize()
    HostingEnvironment.RegisterVirtualPathProvider(new MyVirtualPathProvider())

Use this:

public static void AppInitialize()
    HostingEnvironment hostingEnvironmentInstance=(HostingEnvironment)typeof(HostingEnvironment).InvokeMember("_theHostingEnvironment",  BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.GetField, null, null, null);

    MethodInfo mi = typeof(HostingEnvironment).GetMethod("RegisterVirtualPathProviderInternal", BindingFlags.NonPublic | BindingFlags.Static);

    mi.Invoke(hostingEnvironmentInstance, new object[] { (VirtualPathProvider)new MyVirtualPathProvider()});

According to reference, original action filter precompiled websites. You can achieve what you want intercepting RegisterVirtualPathProviderInternal using reflection, besides normal RegisterVirtualPathProvider method.

Related Question