How to precompile views in ASP.NET Core 2.0?

2020-07-05 02:19发布

问题:

I set up my solution according to this article. I left out some of the things because according to this, ASP.NET Core 2.0 precompiles views by default. In the end, I publish it to a folder, which ends successfully, but my precompiledviews.dll is missing. I tried setting it explicitly in .csproj, but no luck.

Edit: Both of the projects inside the solution are just default MVC templates.

回答1:

I bet you use Self-contained deployment, i.e. publish with command like

dotnet publish --configuration Release --runtime win-x64

that results to executable file with all dependencies including .NET Core binaries.

Razor view compilation and precompilation article contains following warning:

Razor view precompilation is currently unavailable when performing a self-contained deployment (SCD) in ASP.NET Core 2.0. The feature will be available for SCDs when 2.1 releases.

So if you want to use precompiled Razor views, you should use Framework-dependent deployment, i.e. publish with the following command:

dotnet publish --configuration Release

In this case Razor views are precompiled (by default) and you will find YourAppName.PrecompiledViews.dll among other application binaries.

UPDATE (for Precompiled Views in Library project)

My original answer relates to usual ASP.NET Core MVC application, however the question is specific to project library holding precompiled views aka Self-Contained UI.

ASP.NET Core precompiles views by default during the publish, however this is not the case for the views stored in library project. There is a github issue devoted to this problem. That discussion is pretty much long, however it ends up with the conclusion that for this moment we still need to use solution with custom targets for Razor Views precompilation. It basically the same approach as described in the article referenced by the question.

I've setup test solution with ChildApplication and main MvcApplication and made precompiled views working both for the build and publish.

Here is csproj for ChildApplication (skipping sections of default ASP.NET Core MVC project):

<PropertyGroup>
    <TargetFramework>netcoreapp2.0</TargetFramework>
    <MvcRazorCompileOnPublish>true</MvcRazorCompileOnPublish>
</PropertyGroup>

<!-- ... -->

<Target Name="SetMvcRazorOutputPath">
    <PropertyGroup>
        <MvcRazorOutputPath>$(OutputPath)</MvcRazorOutputPath>
    </PropertyGroup>
</Target>
<Target Name="_MvcRazorPrecompileOnBuild" DependsOnTargets="SetMvcRazorOutputPath;MvcRazorPrecompile" AfterTargets="Build" Condition=" '$(IsCrossTargetingBuild)' != 'true' " />
<Target Name="IncludePrecompiledViewsInPublishOutput" DependsOnTargets="_MvcRazorPrecompileOnBuild" BeforeTargets="PrepareForPublish" Condition=" '$(IsCrossTargetingBuild)' != 'true' ">
    <ItemGroup>
        <_PrecompiledViewsOutput Include="$(MvcRazorOutputPath)$(MSBuildProjectName).PrecompiledViews.dll" />
        <_PrecompiledViewsOutput Include="$(MvcRazorOutputPath)$(MSBuildProjectName).PrecompiledViews.pdb" />
        <ContentWithTargetPath Include="@(_PrecompiledViewsOutput->'%(FullPath)')" RelativePath="%(_PrecompiledViewsOutput.Identity)" TargetPath="%(_PrecompiledViewsOutput.Filename)%(_PrecompiledViewsOutput.Extension)" CopyToPublishDirectory="PreserveNewest" />
    </ItemGroup>
</Target>

Here is csproj for parent MvcApplication:

<!-- ... -->

<ItemGroup>
    <ProjectReference Include="..\ChildApplication\ChildApplication.csproj" />
</ItemGroup>

<Target Name="PostBuild" AfterTargets="PostBuildEvent">
    <Exec Command="xcopy &quot;$(ProjectDir)\..\ChildApplication\bin\$(ConfigurationName)\netcoreapp2.0\ChildApplication.PrecompiledViews.dll&quot; &quot;$(TargetDir)&quot; /Y /I" />
</Target>

<Target Name="AddPayloadsFolder" AfterTargets="Publish">
    <Exec Command="xcopy &quot;$(ProjectDir)\..\ChildApplication\bin\$(ConfigurationName)\netcoreapp2.0\ChildApplication.PrecompiledViews.dll&quot; &quot;$(PublishDir)&quot; /Y /I" />
</Target>

Dean North in his original article adds direct reference to assembly with precompiled views.

<ItemGroup>
    <Reference Include="DashboardExample.PrecompiledViews">
        <HintPath>..\DashboardExample\bin\Debug\netcoreapp1.1\DashboardExample.PrecompiledViews.dll</HintPath>
    </Reference>
</ItemGroup>

Such approach isn't perfect because it uses assembly built with specific configuration (Debug here). In my project file above, I use separate targets that copy ChildApplication.PrecompiledViews.dll during the build and publish.

Here is Sample Solution on GitHub with both parent and child projects.



回答2:

I usually just add these to the .csproj. No need to copy files or any of that mess.

    <PropertyGroup>
       <TargetFramework>netcoreapp2.2</...
       ...
       <MvcRazorCompileOnPublish>true</MvcRazorCompileOnPublish>
       <PreserveCompilationContext>true</PreserveCompilationContext>
    </PropertyGroup>

    <ItemGroup>
        ...
       <PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.ViewCompilation" Version="2.2.0" />    
    </ItemGroup>