diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Legacy/CSharpCodeParser.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Legacy/CSharpCodeParser.cs index fd94358c157e..48a6bd768faa 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Legacy/CSharpCodeParser.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Legacy/CSharpCodeParser.cs @@ -959,10 +959,18 @@ private void EnsureDirectiveIsAtStartOfLine() } } - protected void MapDirectives(Action, CSharpTransitionSyntax> handler, params string[] directives) + // Internal for unit testing + internal void MapDirectives(Action, CSharpTransitionSyntax> handler, params string[] directives) { foreach (var directive in directives) { + if (_directiveParserMap.ContainsKey(directive)) + { + // It is possible for the list to contain duplicates in cases when the project is misconfigured. + // In those cases, we shouldn't register multiple handlers per keyword. + continue; + } + _directiveParserMap.Add(directive, (builder, transition) => { handler(builder, transition); diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/Legacy/CSharpCodeParserTest.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/Legacy/CSharpCodeParserTest.cs index 250eff4f4076..8e75f90998db 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/Legacy/CSharpCodeParserTest.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/Legacy/CSharpCodeParserTest.cs @@ -211,5 +211,19 @@ public void TagHelperPrefixDirective_DuplicatesCauseError() var diagnostic = Assert.Single(chunkGenerator.Diagnostics); Assert.Equal(expectedDiagnostic, diagnostic); } + + [Fact] + public void MapDirectives_HandlesDuplicates() + { + // Arrange + var source = TestRazorSourceDocument.Create(); + var options = RazorParserOptions.CreateDefault(); + var context = new ParserContext(source, options); + var parser = new CSharpCodeParser(context); + + // Act & Assert (Does not throw) + parser.MapDirectives((b, t) => { }, "test"); + parser.MapDirectives((b, t) => { }, "test"); + } } } diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/BuildPerformanceTest.cs b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/BuildPerformanceTest.cs index 08d2bef5aea8..b8c97f0aa4a2 100644 --- a/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/BuildPerformanceTest.cs +++ b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/BuildPerformanceTest.cs @@ -26,8 +26,8 @@ public async Task BuildMvcApp() Assert.BuildPassed(result); var summary = ParseTaskPerformanceSummary(result.Output); - Assert.Equal(1, summary.First(f => f.Name == "RazorGenerate").Calls); - Assert.Equal(1, summary.First(f => f.Name == "RazorTagHelper").Calls); + Assert.Equal(1, summary.First(f => f.Name == "SdkRazorGenerate").Calls); + Assert.Equal(1, summary.First(f => f.Name == "SdkRazorTagHelper").Calls); // Incremental builds for (var i = 0; i < 2; i++) @@ -37,8 +37,8 @@ public async Task BuildMvcApp() Assert.BuildPassed(result); summary = ParseTaskPerformanceSummary(result.Output); - Assert.DoesNotContain(summary, item => item.Name == "RazorGenerate"); - Assert.DoesNotContain(summary, item => item.Name == "RazorTagHelper"); + Assert.DoesNotContain(summary, item => item.Name == "SdkRazorGenerate"); + Assert.DoesNotContain(summary, item => item.Name == "SdkRazorTagHelper"); } } @@ -52,8 +52,8 @@ public async Task BuildMvcAppWithComponents() var summary = ParseTaskPerformanceSummary(result.Output); // One for declaration build, one for the "real" code gen - Assert.Equal(2, summary.First(f => f.Name == "RazorGenerate").Calls); - Assert.Equal(1, summary.First(f => f.Name == "RazorTagHelper").Calls); + Assert.Equal(2, summary.First(f => f.Name == "SdkRazorGenerate").Calls); + Assert.Equal(1, summary.First(f => f.Name == "SdkRazorTagHelper").Calls); // Incremental builds for (var i = 0; i < 2; i++) @@ -63,8 +63,8 @@ public async Task BuildMvcAppWithComponents() Assert.BuildPassed(result); summary = ParseTaskPerformanceSummary(result.Output); - Assert.DoesNotContain(summary, item => item.Name == "RazorGenerate"); - Assert.DoesNotContain(summary, item => item.Name == "RazorTagHelper"); + Assert.DoesNotContain(summary, item => item.Name == "SdkRazorGenerate"); + Assert.DoesNotContain(summary, item => item.Name == "SdkRazorTagHelper"); } } diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/MvcBuildIntegrationTest21NetFx.cs b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/MvcBuildIntegrationTest21NetFx.cs new file mode 100644 index 000000000000..854cf0ca0654 --- /dev/null +++ b/src/Razor/Microsoft.NET.Sdk.Razor/integrationtests/MvcBuildIntegrationTest21NetFx.cs @@ -0,0 +1,77 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.IO; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Testing; +using Xunit; + +namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests +{ + public class MvcBuildIntegrationTest21NetFx : + MSBuildIntegrationTestBase, + IClassFixture + { + private const string TestProjectName = "SimpleMvc21NetFx"; + + public MvcBuildIntegrationTest21NetFx(LegacyBuildServerTestFixture buildServer) + : base(buildServer) + { + } + + public string OutputFileName => $"{TestProjectName}.exe"; + + [ConditionalFact] + [OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)] + [InitializeTestProject(TestProjectName)] + public async Task BuildingProject_CopyToOutputDirectoryFiles() + { + Project.TargetFramework = "net461"; + + // Build + var result = await DotnetMSBuild("Build"); + + Assert.BuildPassed(result); + // No cshtml files should be in the build output directory + Assert.FileCountEquals(result, 0, Path.Combine(OutputPath, "Views"), "*.cshtml"); + + // refs are required for runtime compilation in desktop targeting projects. + Assert.FileCountEquals(result, 97, Path.Combine(OutputPath, "refs"), "*.dll"); + } + + [ConditionalFact] + [OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)] + [InitializeTestProject(TestProjectName)] + public async Task PublishingProject_CopyToPublishDirectoryItems() + { + Project.TargetFramework = "net461"; + + // Build + var result = await DotnetMSBuild("Publish"); + + Assert.BuildPassed(result); + + // refs shouldn't be produced by default + Assert.FileCountEquals(result, 0, Path.Combine(PublishOutputPath, "refs"), "*.dll"); + + // Views shouldn't be produced by default + Assert.FileCountEquals(result, 0, Path.Combine(PublishOutputPath, "Views"), "*.cshtml"); + } + + [ConditionalFact] + [OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)] + [InitializeTestProject(TestProjectName)] + public async Task Publish_IncludesRefAssemblies_WhenCopyRefAssembliesToPublishDirectoryIsSet() + { + Project.TargetFramework = "net461"; + + // Build + var result = await DotnetMSBuild("Publish", "/p:CopyRefAssembliesToPublishDirectory=true"); + + Assert.BuildPassed(result); + + // refs should be present if CopyRefAssembliesToPublishDirectory is set. + Assert.FileExists(result, PublishOutputPath, "refs", "System.Threading.Tasks.Extensions.dll"); + } + } +} diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/src/RazorGenerate.cs b/src/Razor/Microsoft.NET.Sdk.Razor/src/SdkRazorGenerate.cs similarity index 96% rename from src/Razor/Microsoft.NET.Sdk.Razor/src/RazorGenerate.cs rename to src/Razor/Microsoft.NET.Sdk.Razor/src/SdkRazorGenerate.cs index 36875942b07c..8ccad6d98849 100644 --- a/src/Razor/Microsoft.NET.Sdk.Razor/src/RazorGenerate.cs +++ b/src/Razor/Microsoft.NET.Sdk.Razor/src/SdkRazorGenerate.cs @@ -7,7 +7,7 @@ namespace Microsoft.AspNetCore.Razor.Tasks { - public class RazorGenerate : DotNetToolTask + public class SdkRazorGenerate : DotNetToolTask { private static readonly string[] SourceRequiredMetadata = new string[] { @@ -169,18 +169,18 @@ protected override string GenerateResponseFileCommands() builder.AppendLine(RootNamespace); } - if (!string.IsNullOrEmpty(CSharpLanguageVersion)) - { - builder.AppendLine("--csharp-language-version"); - builder.AppendLine(CSharpLanguageVersion); - } - if (GenerateDeclaration) { builder.AppendLine("--generate-declaration"); } } + if (!string.IsNullOrEmpty(CSharpLanguageVersion)) + { + builder.AppendLine("--csharp-language-version"); + builder.AppendLine(CSharpLanguageVersion); + } + for (var i = 0; i < Extensions.Length; i++) { builder.AppendLine("-n"); diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/src/RazorTagHelper.cs b/src/Razor/Microsoft.NET.Sdk.Razor/src/SdkRazorTagHelper.cs similarity index 98% rename from src/Razor/Microsoft.NET.Sdk.Razor/src/RazorTagHelper.cs rename to src/Razor/Microsoft.NET.Sdk.Razor/src/SdkRazorTagHelper.cs index 9d764761b167..d4b6ac7df4ee 100644 --- a/src/Razor/Microsoft.NET.Sdk.Razor/src/RazorTagHelper.cs +++ b/src/Razor/Microsoft.NET.Sdk.Razor/src/SdkRazorTagHelper.cs @@ -8,7 +8,7 @@ namespace Microsoft.AspNetCore.Razor.Tasks { - public class RazorTagHelper : DotNetToolTask + public class SdkRazorTagHelper : DotNetToolTask { private const string Identity = "Identity"; private const string AssemblyName = "AssemblyName"; diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Microsoft.NET.Sdk.Razor.CodeGeneration.targets b/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Microsoft.NET.Sdk.Razor.CodeGeneration.targets index 76c4bba7c972..9cce3fa7a03b 100644 --- a/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Microsoft.NET.Sdk.Razor.CodeGeneration.targets +++ b/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Microsoft.NET.Sdk.Razor.CodeGeneration.targets @@ -17,12 +17,12 @@ Copyright (c) .NET Foundation. All rights reserved. --> @@ -94,7 +94,7 @@ Copyright (c) .NET Foundation. All rights reserved. - - + @@ -147,7 +147,7 @@ Copyright (c) .NET Foundation. All rights reserved. Directories="%(_RazorGenerateOutput.RelativeDir)" Condition="!Exists('%(_RazorGenerateOutput.RelativeDir)')" /> - $(IntermediateOutputPath)$(MSBuildProjectName).RazorComponents.declaration.json - - - - - - + diff --git a/src/Razor/test/testassets/ClassLibraryMvc21/ClassLibraryMvc21.csproj b/src/Razor/test/testassets/ClassLibraryMvc21/ClassLibraryMvc21.csproj index a554aab0ffe5..73d0df5c2579 100644 --- a/src/Razor/test/testassets/ClassLibraryMvc21/ClassLibraryMvc21.csproj +++ b/src/Razor/test/testassets/ClassLibraryMvc21/ClassLibraryMvc21.csproj @@ -1,12 +1,12 @@ netstandard2.0 + $(RazorSdkArtifactsDirectory)$(Configuration)\sdk-output\ diff --git a/src/Razor/test/testassets/RestoreTestProjects/RestoreTestProjects.csproj b/src/Razor/test/testassets/RestoreTestProjects/RestoreTestProjects.csproj index 741109414c27..c6e0565e712e 100644 --- a/src/Razor/test/testassets/RestoreTestProjects/RestoreTestProjects.csproj +++ b/src/Razor/test/testassets/RestoreTestProjects/RestoreTestProjects.csproj @@ -5,6 +5,7 @@ + diff --git a/src/Razor/test/testassets/SimpleMvc21/SimpleMvc21.csproj b/src/Razor/test/testassets/SimpleMvc21/SimpleMvc21.csproj index 292a0a83dfcd..a4530549f2c9 100644 --- a/src/Razor/test/testassets/SimpleMvc21/SimpleMvc21.csproj +++ b/src/Razor/test/testassets/SimpleMvc21/SimpleMvc21.csproj @@ -1,8 +1,7 @@ diff --git a/src/Razor/test/testassets/SimpleMvc21NetFx/Models/ErrorViewModel.cs b/src/Razor/test/testassets/SimpleMvc21NetFx/Models/ErrorViewModel.cs new file mode 100644 index 000000000000..b4aa0449146e --- /dev/null +++ b/src/Razor/test/testassets/SimpleMvc21NetFx/Models/ErrorViewModel.cs @@ -0,0 +1,11 @@ +using System; + +namespace SimpleMvc.Models +{ + public class ErrorViewModel + { + public string RequestId { get; set; } + + public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); + } +} \ No newline at end of file diff --git a/src/Razor/test/testassets/SimpleMvc21NetFx/Program.cs b/src/Razor/test/testassets/SimpleMvc21NetFx/Program.cs new file mode 100644 index 000000000000..25883d6b8bb4 --- /dev/null +++ b/src/Razor/test/testassets/SimpleMvc21NetFx/Program.cs @@ -0,0 +1,13 @@ + +namespace SimpleMvc +{ + public class Program + { + public static void Main(string[] args) + { + // Just make sure we have a reference to the MVC 2.2 + var t = typeof(Microsoft.AspNetCore.Mvc.IActionResult); + System.Console.WriteLine(t.FullName); + } + } +} diff --git a/src/Razor/test/testassets/SimpleMvc21NetFx/SimpleMvc21NetFx.csproj b/src/Razor/test/testassets/SimpleMvc21NetFx/SimpleMvc21NetFx.csproj new file mode 100644 index 000000000000..5b8d8133ae4e --- /dev/null +++ b/src/Razor/test/testassets/SimpleMvc21NetFx/SimpleMvc21NetFx.csproj @@ -0,0 +1,26 @@ + + + + + $(RazorSdkArtifactsDirectory)$(Configuration)\sdk-output\ + + + + net461 + full + + + + + + + + + + + false + + + diff --git a/src/Razor/test/testassets/SimpleMvc21NetFx/SimpleTagHelper.cs b/src/Razor/test/testassets/SimpleMvc21NetFx/SimpleTagHelper.cs new file mode 100644 index 000000000000..7cc52922d99a --- /dev/null +++ b/src/Razor/test/testassets/SimpleMvc21NetFx/SimpleTagHelper.cs @@ -0,0 +1,8 @@ +using Microsoft.AspNetCore.Razor.TagHelpers; + +namespace SimpleMvc +{ + public class SimpleTagHelper : TagHelper + { + } +} diff --git a/src/Razor/test/testassets/SimpleMvc21NetFx/Views/Home/Index.cshtml b/src/Razor/test/testassets/SimpleMvc21NetFx/Views/Home/Index.cshtml new file mode 100644 index 000000000000..00afab6a0cb7 --- /dev/null +++ b/src/Razor/test/testassets/SimpleMvc21NetFx/Views/Home/Index.cshtml @@ -0,0 +1,108 @@ +@{ + ViewData["Title"] = "Home Page"; +} + + + + diff --git a/src/Razor/test/testassets/SimpleMvc21NetFx/Views/Shared/_Layout.cshtml b/src/Razor/test/testassets/SimpleMvc21NetFx/Views/Shared/_Layout.cshtml new file mode 100644 index 000000000000..1a9473e4643b --- /dev/null +++ b/src/Razor/test/testassets/SimpleMvc21NetFx/Views/Shared/_Layout.cshtml @@ -0,0 +1,71 @@ + + + + + + @ViewData["Title"] - SimpleMvc + + + + + + + + + + + + +
+ @RenderBody() +
+
+

© 2017 - SimpleMvc

+
+
+ + + + + + + + + + + + + @RenderSection("Scripts", required: false) + + diff --git a/src/Razor/test/testassets/SimpleMvc21NetFx/Views/_ViewImports.cshtml b/src/Razor/test/testassets/SimpleMvc21NetFx/Views/_ViewImports.cshtml new file mode 100644 index 000000000000..477d4ba603e9 --- /dev/null +++ b/src/Razor/test/testassets/SimpleMvc21NetFx/Views/_ViewImports.cshtml @@ -0,0 +1,4 @@ +@using SimpleMvc +@using SimpleMvc.Models +@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers +@namespace SimpleMvc21 diff --git a/src/Razor/test/testassets/SimpleMvc21NetFx/Views/_ViewStart.cshtml b/src/Razor/test/testassets/SimpleMvc21NetFx/Views/_ViewStart.cshtml new file mode 100644 index 000000000000..a5f10045db97 --- /dev/null +++ b/src/Razor/test/testassets/SimpleMvc21NetFx/Views/_ViewStart.cshtml @@ -0,0 +1,3 @@ +@{ + Layout = "_Layout"; +} diff --git a/src/Razor/test/testassets/SimpleMvc22/SimpleMvc22.csproj b/src/Razor/test/testassets/SimpleMvc22/SimpleMvc22.csproj index e5f191fae7b3..6cd1820ff1e4 100644 --- a/src/Razor/test/testassets/SimpleMvc22/SimpleMvc22.csproj +++ b/src/Razor/test/testassets/SimpleMvc22/SimpleMvc22.csproj @@ -1,8 +1,7 @@