MSBuild:如何动态包含生成的*.razor文件并完成编译
解决Razor文件生成后无法在单次构建中编译的问题
看起来你遇到的核心问题是MSBuild目标执行顺序错误:你的生成器在Razor组件编译的准备阶段之后才生成文件,导致MSBuild没把新生成的.razor文件纳入编译流程——只有重建时,因为会清理之前的构建状态、重新扫描所有文件,才能正确识别这些新文件。
下面是针对你的csproj的具体修复方案:
1. 调整生成与文件包含的顺序
当前你的CompileDocs目标依赖IncludeGeneratedFiles,但逻辑上应该先生成文件,再包含文件。同时要确保整个流程在Razor组件生成的关键阶段PrepareForRazorComponentGenerate之前完成。
修改CompileDocs和IncludeGeneratedFiles的定义:
<!--Execute the code generator first, then include generated files--> <Target Name="CompileDocs" BeforeTargets="PrepareForRazorComponentGenerate"> <Message Text="Generating Docs and Tests using $(RunCommand)" Importance="high"/> <Exec Command='$(RunCommand)' /> </Target> <Target Name="IncludeGeneratedFiles" AfterTargets="CompileDocs" BeforeTargets="PrepareForRazorComponentGenerate" > <ItemGroup> <!-- 修正条件:只有文件存在时才包含(生成后才会加入编译) --> <Compile Include="Models\Snippets.generated.cs" Condition="Exists('Models\Snippets.generated.cs')" /> <Compile Include="Models\DocStrings.generated.cs" Condition="Exists('Models\DocStrings.generated.cs')" /> <!-- 强制重新扫描所有ExampleCode.razor文件,避免MSBuild缓存旧的文件列表 --> <RazorComponent Remove="**/*ExampleCode.razor" /> <RazorComponent Include="**/*ExampleCode.razor" /> </ItemGroup> </Target>
修改说明:
- 把
CompileDocs的BeforeTargets改为PrepareForRazorComponentGenerate,确保生成文件在Razor编译准备之前完成。 IncludeGeneratedFiles改为在CompileDocs之后执行,这样生成的文件已经存在,能正确被包含。- 对
RazorComponent先执行Remove再Include,强制MSBuild重新扫描文件,避免遗漏新生成的.razor文件。 - 把
Compile的条件从!Exists改为Exists,确保只有文件生成后才会加入编译流程。
2. 移除冗余的ExampleCode目标
你的ExampleCode目标逻辑和IncludeGeneratedFiles重复,而且条件!Exists('Models\DocStrings.generated.cs')会导致文件生成后反而不被包含,直接移除这个目标即可:
<!-- 移除这个冲突的目标 --> <!-- <Target Name="ExampleCode" BeforeTargets="PrepareForRazorComponentGenerate" > <ItemGroup> <RazorComponent Include="**/*ExampleCode.razor" Condition="!Exists('Models\DocStrings.generated.cs')" /> <Content Update="$(_RazorComponentInclude)"> <Generator>MSBuild:RazorGenerateComponentDeclarationDesignTime</Generator> <CopyToPublishDirectory>Never</CopyToPublishDirectory> </Content> </ItemGroup> </Target> -->
3. 简化BuildDependsOn配置
原来的BuildDependsOn把CompileDocs放在前面,但现在我们已经通过BeforeTargets精准控制了生成时机,可以简化这个配置避免冲突:
<PropertyGroup> <!-- 移除原来的BuildDependsOn配置,依赖关系已通过BeforeTargets控制 --> <!-- <BuildDependsOn> CompileDocs; $(BuildDependsOn) </BuildDependsOn> --> </PropertyGroup>
验证修改效果
做完以上修改后,执行常规构建(无需重建):
- 生成器会先运行,生成
.razor和.generated.cs文件 - MSBuild会重新扫描并包含这些新文件
- Razor编译器会为
.razor文件生成对应的.g.cs文件,并编译进项目
这样就能实现生成与构建一步完成的需求。
内容的提问来源于stack exchange,提问作者mikes-so
相关产品推荐
相关产品推荐

