Skip to content

Commit 413d3ab

Browse files
authored
Add support for building 2.1 Razor projects using the RazorSDK (#35121)
This is a port of dotnet/sdk#19094 to 5.0 that changes the RazorSDK to use the in-box compiler when building 2.1 apps.
1 parent d298bc4 commit 413d3ab

File tree

21 files changed

+372
-35
lines changed

21 files changed

+372
-35
lines changed

src/Razor/Microsoft.AspNetCore.Razor.Language/src/Legacy/CSharpCodeParser.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -959,10 +959,18 @@ private void EnsureDirectiveIsAtStartOfLine()
959959
}
960960
}
961961

962-
protected void MapDirectives(Action<SyntaxListBuilder<RazorSyntaxNode>, CSharpTransitionSyntax> handler, params string[] directives)
962+
// Internal for unit testing
963+
internal void MapDirectives(Action<SyntaxListBuilder<RazorSyntaxNode>, CSharpTransitionSyntax> handler, params string[] directives)
963964
{
964965
foreach (var directive in directives)
965966
{
967+
if (_directiveParserMap.ContainsKey(directive))
968+
{
969+
// It is possible for the list to contain duplicates in cases when the project is misconfigured.
970+
// In those cases, we shouldn't register multiple handlers per keyword.
971+
continue;
972+
}
973+
966974
_directiveParserMap.Add(directive, (builder, transition) =>
967975
{
968976
handler(builder, transition);

src/Razor/Microsoft.AspNetCore.Razor.Language/test/Legacy/CSharpCodeParserTest.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,5 +211,19 @@ public void TagHelperPrefixDirective_DuplicatesCauseError()
211211
var diagnostic = Assert.Single(chunkGenerator.Diagnostics);
212212
Assert.Equal(expectedDiagnostic, diagnostic);
213213
}
214+
215+
[Fact]
216+
public void MapDirectives_HandlesDuplicates()
217+
{
218+
// Arrange
219+
var source = TestRazorSourceDocument.Create();
220+
var options = RazorParserOptions.CreateDefault();
221+
var context = new ParserContext(source, options);
222+
var parser = new CSharpCodeParser(context);
223+
224+
// Act & Assert (Does not throw)
225+
parser.MapDirectives((b, t) => { }, "test");
226+
parser.MapDirectives((b, t) => { }, "test");
227+
}
214228
}
215229
}

src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/BuildPerformanceTest.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ public async Task BuildMvcApp()
2626
Assert.BuildPassed(result);
2727
var summary = ParseTaskPerformanceSummary(result.Output);
2828

29-
Assert.Equal(1, summary.First(f => f.Name == "RazorGenerate").Calls);
30-
Assert.Equal(1, summary.First(f => f.Name == "RazorTagHelper").Calls);
29+
Assert.Equal(1, summary.First(f => f.Name == "SdkRazorGenerate").Calls);
30+
Assert.Equal(1, summary.First(f => f.Name == "SdkRazorTagHelper").Calls);
3131

3232
// Incremental builds
3333
for (var i = 0; i < 2; i++)
@@ -37,8 +37,8 @@ public async Task BuildMvcApp()
3737
Assert.BuildPassed(result);
3838
summary = ParseTaskPerformanceSummary(result.Output);
3939

40-
Assert.DoesNotContain(summary, item => item.Name == "RazorGenerate");
41-
Assert.DoesNotContain(summary, item => item.Name == "RazorTagHelper");
40+
Assert.DoesNotContain(summary, item => item.Name == "SdkRazorGenerate");
41+
Assert.DoesNotContain(summary, item => item.Name == "SdkRazorTagHelper");
4242
}
4343
}
4444

@@ -52,8 +52,8 @@ public async Task BuildMvcAppWithComponents()
5252
var summary = ParseTaskPerformanceSummary(result.Output);
5353

5454
// One for declaration build, one for the "real" code gen
55-
Assert.Equal(2, summary.First(f => f.Name == "RazorGenerate").Calls);
56-
Assert.Equal(1, summary.First(f => f.Name == "RazorTagHelper").Calls);
55+
Assert.Equal(2, summary.First(f => f.Name == "SdkRazorGenerate").Calls);
56+
Assert.Equal(1, summary.First(f => f.Name == "SdkRazorTagHelper").Calls);
5757

5858
// Incremental builds
5959
for (var i = 0; i < 2; i++)
@@ -63,8 +63,8 @@ public async Task BuildMvcAppWithComponents()
6363
Assert.BuildPassed(result);
6464
summary = ParseTaskPerformanceSummary(result.Output);
6565

66-
Assert.DoesNotContain(summary, item => item.Name == "RazorGenerate");
67-
Assert.DoesNotContain(summary, item => item.Name == "RazorTagHelper");
66+
Assert.DoesNotContain(summary, item => item.Name == "SdkRazorGenerate");
67+
Assert.DoesNotContain(summary, item => item.Name == "SdkRazorTagHelper");
6868
}
6969
}
7070

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System.IO;
5+
using System.Threading.Tasks;
6+
using Microsoft.AspNetCore.Testing;
7+
using Xunit;
8+
9+
namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
10+
{
11+
public class MvcBuildIntegrationTest21NetFx :
12+
MSBuildIntegrationTestBase,
13+
IClassFixture<LegacyBuildServerTestFixture>
14+
{
15+
private const string TestProjectName = "SimpleMvc21NetFx";
16+
17+
public MvcBuildIntegrationTest21NetFx(LegacyBuildServerTestFixture buildServer)
18+
: base(buildServer)
19+
{
20+
}
21+
22+
public string OutputFileName => $"{TestProjectName}.exe";
23+
24+
[ConditionalFact]
25+
[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)]
26+
[InitializeTestProject(TestProjectName)]
27+
public async Task BuildingProject_CopyToOutputDirectoryFiles()
28+
{
29+
Project.TargetFramework = "net461";
30+
31+
// Build
32+
var result = await DotnetMSBuild("Build");
33+
34+
Assert.BuildPassed(result);
35+
// No cshtml files should be in the build output directory
36+
Assert.FileCountEquals(result, 0, Path.Combine(OutputPath, "Views"), "*.cshtml");
37+
38+
// refs are required for runtime compilation in desktop targeting projects.
39+
Assert.FileCountEquals(result, 97, Path.Combine(OutputPath, "refs"), "*.dll");
40+
}
41+
42+
[ConditionalFact]
43+
[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)]
44+
[InitializeTestProject(TestProjectName)]
45+
public async Task PublishingProject_CopyToPublishDirectoryItems()
46+
{
47+
Project.TargetFramework = "net461";
48+
49+
// Build
50+
var result = await DotnetMSBuild("Publish");
51+
52+
Assert.BuildPassed(result);
53+
54+
// refs shouldn't be produced by default
55+
Assert.FileCountEquals(result, 0, Path.Combine(PublishOutputPath, "refs"), "*.dll");
56+
57+
// Views shouldn't be produced by default
58+
Assert.FileCountEquals(result, 0, Path.Combine(PublishOutputPath, "Views"), "*.cshtml");
59+
}
60+
61+
[ConditionalFact]
62+
[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)]
63+
[InitializeTestProject(TestProjectName)]
64+
public async Task Publish_IncludesRefAssemblies_WhenCopyRefAssembliesToPublishDirectoryIsSet()
65+
{
66+
Project.TargetFramework = "net461";
67+
68+
// Build
69+
var result = await DotnetMSBuild("Publish", "/p:CopyRefAssembliesToPublishDirectory=true");
70+
71+
Assert.BuildPassed(result);
72+
73+
// refs should be present if CopyRefAssembliesToPublishDirectory is set.
74+
Assert.FileExists(result, PublishOutputPath, "refs", "System.Threading.Tasks.Extensions.dll");
75+
}
76+
}
77+
}

src/Razor/Microsoft.NET.Sdk.Razor/src/RazorGenerate.cs renamed to src/Razor/Microsoft.NET.Sdk.Razor/src/SdkRazorGenerate.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
namespace Microsoft.AspNetCore.Razor.Tasks
99
{
10-
public class RazorGenerate : DotNetToolTask
10+
public class SdkRazorGenerate : DotNetToolTask
1111
{
1212
private static readonly string[] SourceRequiredMetadata = new string[]
1313
{
@@ -169,18 +169,18 @@ protected override string GenerateResponseFileCommands()
169169
builder.AppendLine(RootNamespace);
170170
}
171171

172-
if (!string.IsNullOrEmpty(CSharpLanguageVersion))
173-
{
174-
builder.AppendLine("--csharp-language-version");
175-
builder.AppendLine(CSharpLanguageVersion);
176-
}
177-
178172
if (GenerateDeclaration)
179173
{
180174
builder.AppendLine("--generate-declaration");
181175
}
182176
}
183177

178+
if (!string.IsNullOrEmpty(CSharpLanguageVersion))
179+
{
180+
builder.AppendLine("--csharp-language-version");
181+
builder.AppendLine(CSharpLanguageVersion);
182+
}
183+
184184
for (var i = 0; i < Extensions.Length; i++)
185185
{
186186
builder.AppendLine("-n");

src/Razor/Microsoft.NET.Sdk.Razor/src/RazorTagHelper.cs renamed to src/Razor/Microsoft.NET.Sdk.Razor/src/SdkRazorTagHelper.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
namespace Microsoft.AspNetCore.Razor.Tasks
1010
{
11-
public class RazorTagHelper : DotNetToolTask
11+
public class SdkRazorTagHelper : DotNetToolTask
1212
{
1313
private const string Identity = "Identity";
1414
private const string AssemblyName = "AssemblyName";

src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Microsoft.NET.Sdk.Razor.CodeGeneration.targets

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@ Copyright (c) .NET Foundation. All rights reserved.
1717
-->
1818

1919
<UsingTask
20-
TaskName="Microsoft.AspNetCore.Razor.Tasks.RazorGenerate"
20+
TaskName="Microsoft.AspNetCore.Razor.Tasks.SdkRazorGenerate"
2121
AssemblyFile="$(RazorSdkBuildTasksAssembly)"
2222
Condition="'$(RazorSdkBuildTasksAssembly)' != ''" />
2323

2424
<UsingTask
25-
TaskName="Microsoft.AspNetCore.Razor.Tasks.RazorTagHelper"
25+
TaskName="Microsoft.AspNetCore.Razor.Tasks.SdkRazorTagHelper"
2626
AssemblyFile="$(RazorSdkBuildTasksAssembly)"
2727
Condition="'$(RazorSdkBuildTasksAssembly)' != ''" />
2828

@@ -94,7 +94,7 @@ Copyright (c) .NET Foundation. All rights reserved.
9494
<FileWrites Include="$(_RazorTagHelperInputCache)" />
9595
</ItemGroup>
9696

97-
<RazorTagHelper
97+
<SdkRazorTagHelper
9898
Debug="$(_RazorDebugTagHelperTask)"
9999
DebugTool="$(_RazorDebugTagHelperTool)"
100100
ToolAssembly="$(_RazorSdkToolAssembly)"
@@ -112,7 +112,7 @@ Copyright (c) .NET Foundation. All rights reserved.
112112
<Output
113113
TaskParameter="TagHelperManifest"
114114
ItemName="FileWrites"/>
115-
</RazorTagHelper>
115+
</SdkRazorTagHelper>
116116
</Target>
117117

118118
<Target Name="_ResolveRazorGenerateOutputs" Condition="'@(RazorGenerateWithTargetPath)' != ''">
@@ -147,7 +147,7 @@ Copyright (c) .NET Foundation. All rights reserved.
147147
Directories="%(_RazorGenerateOutput.RelativeDir)"
148148
Condition="!Exists('%(_RazorGenerateOutput.RelativeDir)')" />
149149

150-
<RazorGenerate
150+
<SdkRazorGenerate
151151
Debug="$(_RazorDebugGenerateCodeTask)"
152152
DebugTool="$(_RazorDebugGenerateCodeTool)"
153153
ToolAssembly="$(_RazorSdkToolAssembly)"

src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Microsoft.NET.Sdk.Razor.Component.targets

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ Copyright (c) .NET Foundation. All rights reserved.
104104
<_RazorComponentDeclarationManifest>$(IntermediateOutputPath)$(MSBuildProjectName).RazorComponents.declaration.json</_RazorComponentDeclarationManifest>
105105
</PropertyGroup>
106106

107-
<RazorGenerate
107+
<SdkRazorGenerate
108108
Debug="$(_RazorDebugGenerateCodeTask)"
109109
DebugTool="$(_RazorDebugGenerateCodeTool)"
110110
ToolExe="$(_RazorSdkDotNetHostFileName)"

src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Sdk.Razor.CurrentVersion.targets

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -346,15 +346,10 @@ Copyright (c) .NET Foundation. All rights reserved.
346346

347347
<!-- Determine what compiler and versions of the language to target. For 2.x targeting projects, these are carried by packages referenced by the project. Use this -->
348348

349-
<!-- Use the 2.x compiler if we're building an application that references Microsoft.AspNetCore.Razor.Design. -->
350-
<Import Project="$(RazorCodeGenerationTargetsPath)"
351-
Condition="'$(IsRazorCompilerReferenced)' == 'true' AND '$(RazorCodeGenerationTargetsPath)' != '' AND Exists('$(RazorCodeGenerationTargetsPath)')" />
352-
353349
<!-- When targeting 3.x and later projects, we have to infer configuration by inspecting the project. -->
354350
<Import Project="Microsoft.NET.Sdk.Razor.Configuration.targets" Condition="'$(_Targeting30OrNewerRazorLangVersion)' == 'true'" />
355351

356-
<!-- For projects targeting 3.x and later, use the compiler that ships in the SDK -->
357-
<Import Project="Microsoft.NET.Sdk.Razor.CodeGeneration.targets" Condition="'$(_Targeting30OrNewerRazorLangVersion)' == 'true'" />
352+
<Import Project="Microsoft.NET.Sdk.Razor.CodeGeneration.targets" />
358353

359354
<Import Project="Microsoft.NET.Sdk.Razor.Component.targets" Condition="'$(_Targeting30OrNewerRazorLangVersion)' == 'true'" />
360355

src/Razor/test/testassets/ClassLibraryMvc21/ClassLibraryMvc21.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
<Project Sdk="Microsoft.NET.Sdk.Razor">
22

33
<!--
4-
This project references a shipped version of MVC and should not reference local builds of
5-
the CodeGeneration targets, rzc, or any of the test shims.
4+
This project references a shipped version of MVC and should not reference local builds of the test shims.
65
-->
76

87
<PropertyGroup>
98
<TargetFramework>netstandard2.0</TargetFramework>
9+
<RazorSdkDirectoryRoot>$(RazorSdkArtifactsDirectory)$(Configuration)\sdk-output\</RazorSdkDirectoryRoot>
1010
</PropertyGroup>
1111

1212
<ItemGroup>

0 commit comments

Comments
 (0)