From 84d2e027f514064a2d4e39d6ae674ba0c1dd5254 Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Fri, 27 Jan 2017 11:10:05 -0800 Subject: [PATCH] Use new Razor in MVC --- Mvc.sln | 30 + samples/MvcSandbox/project.json | 7 +- .../GeneratedTagHelperAttributeContext.cs | 2 +- .../GeneratedViewComponentTagHelperContext.cs | 2 +- .../Directives/ChunkHelper.cs | 93 --- .../Directives/ChunkInheritanceUtility.cs | 193 ------ .../Directives/ChunkTreeResult.cs | 46 -- .../Directives/DefaultChunkTreeCache.cs | 82 --- .../Directives/IChunkMerger.cs | 27 - .../Directives/IChunkTreeCache.cs | 27 - .../Directives/InjectChunkMerger.cs | 87 --- .../Directives/SetBaseTypeChunkMerger.cs | 85 --- .../Directives/UsingChunkMerger.cs | 56 -- .../IMvcRazorHost.cs | 29 - .../InjectChunk.cs | 33 -- .../InjectChunkVisitor.cs | 78 --- .../InjectDirective.cs | 93 +++ .../InjectParameterGenerator.cs | 48 -- .../Internal/TagHelperChunkDecorator.cs | 73 --- .../ViewComponentTagHelperChunkVisitor.cs | 208 ------- .../ModelChunk.cs | 27 - .../ModelChunkGenerator.cs | 40 -- .../ModelDirective.cs | 71 +++ .../ModelExpressionPass.cs | 78 +++ .../MvcCSharpChunkVisitor.cs | 42 -- .../MvcCSharpCodeGenerator.cs | 144 ----- .../MvcCSharpCodeVistor.cs | 31 - .../MvcCSharpDesignTimeCodeVisitor.cs | 70 --- .../MvcRazorCodeParser.cs | 172 ------ .../MvcRazorHost.cs | 355 ----------- .../MvcRazorParser.cs | 205 ------- .../MvcTagHelperAttributeValueCodeRenderer.cs | 94 --- .../MvcViewDocumentClassifierPass.cs | 262 +++++++++ ...ComponentTagHelperDescriptorConventions.cs | 2 +- .../ViewComponentTagHelperPass.cs | 282 +++++++++ .../exceptions.net45.json | 94 +++ .../exceptions.netcore.json | 94 +++ .../project.json | 2 +- .../Compilation/ICompilationService.cs | 14 +- .../MvcRazorMvcCoreBuilderExtensions.cs | 36 +- .../Internal/DefaultRazorProject.cs | 2 +- .../Internal/DefaultRazorProjectItem.cs | 2 +- .../DefaultRoslynCompilationService.cs | 58 +- .../Internal/RazorCompilationService.cs | 99 +++- .../Properties/Resources.Designer.cs | 16 + .../RazorPage.cs | 3 +- .../RenderAsyncDelegate.cs | 3 +- .../Resources.resx | 57 +- .../exceptions.net45.json | 29 + .../exceptions.netcore.json | 29 + .../project.json | 2 + .../Properties/Resources.Designer.cs | 16 - .../Resources.resx | 3 - .../project.json | 1 + .../ErrorPageTests.cs | 10 +- .../RazorPageExecutionInstrumentationTest.cs | 2 +- .../Directives/ChunkInheritanceUtilityTest.cs | 183 ------ .../Directives/DefaultCodeTreeCacheTest.cs | 180 ------ .../Directives/InjectChunkMergerTest.cs | 2 + .../Directives/SetBaseTypeChunkMergerTest.cs | 2 + .../Directives/UsingChunkMergerTest.cs | 2 + .../InjectChunkVisitorTest.cs | 2 + .../Internal/TagHelperChunkDecoratorTest.cs | 2 + .../ViewComponentTagHelperChunkVisitorTest.cs | 2 + .../MvcCSharpRazorCodeParserTest.cs | 554 ------------------ .../MvcRazorHostTest.cs | 165 +----- .../MvcRazorParserTest.cs | 253 -------- ...TagHelperAttributeValueCodeRendererTest.cs | 2 + ...onentTagHelperDescriptorConventionsTest.cs | 4 +- .../DefaultRoslynCompilationServiceTest.cs | 2 + .../Internal/RazorCompilationServiceTest.cs | 5 +- .../MvcRazorCodeParserTest.cs | 323 ---------- .../RazorPageTest.cs | 18 +- .../RazorViewTest.cs | 70 +-- .../PageActionDescriptorProviderTest.cs | 3 +- .../Components/PassThrough/Default.cshtml | 1 - .../Components/CheckViewData/Default.cshtml | 1 - .../DisplayTemplates/Int32.cshtml | 1 - .../DisplayTemplates/Int64.cshtml | 1 - .../DisplayTemplates/TemplateModel.cshtml | 1 - .../DisplayTemplates/ViewModel.cshtml | 1 - .../CheckViewData/PartialForViewModel.cshtml | 1 - .../EditorTemplates/Employee.cshtml | 1 - .../ItemUsingSharedEditorTemplate.cshtml | 1 - .../_ProductPartial.cshtml | 1 - .../Shared/DisplayTemplates/DayOfWeek.cshtml | 1 - .../TestRazorCompilationService.cs | 12 +- .../PageWithPartialsAndViewComponents.cshtml | 1 - ...SectionInvokedViaRenderSectionAsync.cshtml | 1 - ...lHelperOptionsDefaultsInPartialView.cshtml | 1 - .../HtmlHelperOptionsDefaultsInView.cshtml | 1 - .../Views/Employee/Create.cshtml | 1 - .../Views/Employee/Details.cshtml | 1 - .../TagHelpersWebSite/Views/Home/Index.cshtml | 97 ++- .../Shared/Components/Generic/Default.cshtml | 1 - 95 files changed, 1395 insertions(+), 4252 deletions(-) rename src/Microsoft.AspNetCore.Mvc.Razor.Host/{ => ApiSets}/GeneratedTagHelperAttributeContext.cs (90%) rename src/Microsoft.AspNetCore.Mvc.Razor.Host/{Internal => ApiSets}/GeneratedViewComponentTagHelperContext.cs (93%) delete mode 100644 src/Microsoft.AspNetCore.Mvc.Razor.Host/Directives/ChunkHelper.cs delete mode 100644 src/Microsoft.AspNetCore.Mvc.Razor.Host/Directives/ChunkInheritanceUtility.cs delete mode 100644 src/Microsoft.AspNetCore.Mvc.Razor.Host/Directives/ChunkTreeResult.cs delete mode 100644 src/Microsoft.AspNetCore.Mvc.Razor.Host/Directives/DefaultChunkTreeCache.cs delete mode 100644 src/Microsoft.AspNetCore.Mvc.Razor.Host/Directives/IChunkMerger.cs delete mode 100644 src/Microsoft.AspNetCore.Mvc.Razor.Host/Directives/IChunkTreeCache.cs delete mode 100644 src/Microsoft.AspNetCore.Mvc.Razor.Host/Directives/InjectChunkMerger.cs delete mode 100644 src/Microsoft.AspNetCore.Mvc.Razor.Host/Directives/SetBaseTypeChunkMerger.cs delete mode 100644 src/Microsoft.AspNetCore.Mvc.Razor.Host/Directives/UsingChunkMerger.cs delete mode 100644 src/Microsoft.AspNetCore.Mvc.Razor.Host/IMvcRazorHost.cs delete mode 100644 src/Microsoft.AspNetCore.Mvc.Razor.Host/InjectChunk.cs delete mode 100644 src/Microsoft.AspNetCore.Mvc.Razor.Host/InjectChunkVisitor.cs create mode 100644 src/Microsoft.AspNetCore.Mvc.Razor.Host/InjectDirective.cs delete mode 100644 src/Microsoft.AspNetCore.Mvc.Razor.Host/InjectParameterGenerator.cs delete mode 100644 src/Microsoft.AspNetCore.Mvc.Razor.Host/Internal/TagHelperChunkDecorator.cs delete mode 100644 src/Microsoft.AspNetCore.Mvc.Razor.Host/Internal/ViewComponentTagHelperChunkVisitor.cs delete mode 100644 src/Microsoft.AspNetCore.Mvc.Razor.Host/ModelChunk.cs delete mode 100644 src/Microsoft.AspNetCore.Mvc.Razor.Host/ModelChunkGenerator.cs create mode 100644 src/Microsoft.AspNetCore.Mvc.Razor.Host/ModelDirective.cs create mode 100644 src/Microsoft.AspNetCore.Mvc.Razor.Host/ModelExpressionPass.cs delete mode 100644 src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcCSharpChunkVisitor.cs delete mode 100644 src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcCSharpCodeGenerator.cs delete mode 100644 src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcCSharpCodeVistor.cs delete mode 100644 src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcCSharpDesignTimeCodeVisitor.cs delete mode 100644 src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcRazorCodeParser.cs delete mode 100644 src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcRazorHost.cs delete mode 100644 src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcRazorParser.cs delete mode 100644 src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcTagHelperAttributeValueCodeRenderer.cs create mode 100644 src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcViewDocumentClassifierPass.cs create mode 100644 src/Microsoft.AspNetCore.Mvc.Razor.Host/ViewComponentTagHelperPass.cs create mode 100644 src/Microsoft.AspNetCore.Mvc.Razor.Host/exceptions.net45.json create mode 100644 src/Microsoft.AspNetCore.Mvc.Razor.Host/exceptions.netcore.json rename src/{Microsoft.AspNetCore.Mvc.RazorPages => Microsoft.AspNetCore.Mvc.Razor}/Internal/DefaultRazorProject.cs (97%) rename src/{Microsoft.AspNetCore.Mvc.RazorPages => Microsoft.AspNetCore.Mvc.Razor}/Internal/DefaultRazorProjectItem.cs (94%) create mode 100644 src/Microsoft.AspNetCore.Mvc.Razor/exceptions.net45.json create mode 100644 src/Microsoft.AspNetCore.Mvc.Razor/exceptions.netcore.json delete mode 100644 test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/Directives/ChunkInheritanceUtilityTest.cs delete mode 100644 test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/Directives/DefaultCodeTreeCacheTest.cs delete mode 100644 test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/MvcCSharpRazorCodeParserTest.cs delete mode 100644 test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/MvcRazorParserTest.cs delete mode 100644 test/Microsoft.AspNetCore.Mvc.Razor.Test/MvcRazorCodeParserTest.cs diff --git a/Mvc.sln b/Mvc.sln index 24156e20b1..6105495fb1 100644 --- a/Mvc.sln +++ b/Mvc.sln @@ -125,6 +125,10 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "SimpleWebSite", "test\WebSi EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "SecurityWebSite", "test\WebSites\SecurityWebSite\SecurityWebSite.xproj", "{D28CAC79-7004-4B69-993B-EDEB4653BFA8}" EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Mvc.RazorPages", "src\Microsoft.AspNetCore.Mvc.RazorPages\Microsoft.AspNetCore.Mvc.RazorPages.xproj", "{CF322BE1-E1FE-4CFD-8FCA-16A14B905D53}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Mvc.RazorPages.Test", "test\Microsoft.AspNetCore.Mvc.RazorPages.Test\Microsoft.AspNetCore.Mvc.RazorPages.Test.xproj", "{0AB46520-F441-4E01-B444-08F4D23F8B1B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -741,6 +745,30 @@ Global {D28CAC79-7004-4B69-993B-EDEB4653BFA8}.Release|Mixed Platforms.Build.0 = Release|Any CPU {D28CAC79-7004-4B69-993B-EDEB4653BFA8}.Release|x86.ActiveCfg = Release|Any CPU {D28CAC79-7004-4B69-993B-EDEB4653BFA8}.Release|x86.Build.0 = Release|Any CPU + {CF322BE1-E1FE-4CFD-8FCA-16A14B905D53}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CF322BE1-E1FE-4CFD-8FCA-16A14B905D53}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CF322BE1-E1FE-4CFD-8FCA-16A14B905D53}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {CF322BE1-E1FE-4CFD-8FCA-16A14B905D53}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {CF322BE1-E1FE-4CFD-8FCA-16A14B905D53}.Debug|x86.ActiveCfg = Debug|Any CPU + {CF322BE1-E1FE-4CFD-8FCA-16A14B905D53}.Debug|x86.Build.0 = Debug|Any CPU + {CF322BE1-E1FE-4CFD-8FCA-16A14B905D53}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CF322BE1-E1FE-4CFD-8FCA-16A14B905D53}.Release|Any CPU.Build.0 = Release|Any CPU + {CF322BE1-E1FE-4CFD-8FCA-16A14B905D53}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {CF322BE1-E1FE-4CFD-8FCA-16A14B905D53}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {CF322BE1-E1FE-4CFD-8FCA-16A14B905D53}.Release|x86.ActiveCfg = Release|Any CPU + {CF322BE1-E1FE-4CFD-8FCA-16A14B905D53}.Release|x86.Build.0 = Release|Any CPU + {0AB46520-F441-4E01-B444-08F4D23F8B1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0AB46520-F441-4E01-B444-08F4D23F8B1B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0AB46520-F441-4E01-B444-08F4D23F8B1B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {0AB46520-F441-4E01-B444-08F4D23F8B1B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {0AB46520-F441-4E01-B444-08F4D23F8B1B}.Debug|x86.ActiveCfg = Debug|Any CPU + {0AB46520-F441-4E01-B444-08F4D23F8B1B}.Debug|x86.Build.0 = Debug|Any CPU + {0AB46520-F441-4E01-B444-08F4D23F8B1B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0AB46520-F441-4E01-B444-08F4D23F8B1B}.Release|Any CPU.Build.0 = Release|Any CPU + {0AB46520-F441-4E01-B444-08F4D23F8B1B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {0AB46520-F441-4E01-B444-08F4D23F8B1B}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {0AB46520-F441-4E01-B444-08F4D23F8B1B}.Release|x86.ActiveCfg = Release|Any CPU + {0AB46520-F441-4E01-B444-08F4D23F8B1B}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -802,5 +830,7 @@ Global {14ED4476-9F24-4776-8417-EA6927F6C9C9} = {DAAE4C74-D06F-4874-A166-33305D2643CE} {396B40D7-AC70-49A7-B33C-ED42129FEBE3} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C} {D28CAC79-7004-4B69-993B-EDEB4653BFA8} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C} + {CF322BE1-E1FE-4CFD-8FCA-16A14B905D53} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E} + {0AB46520-F441-4E01-B444-08F4D23F8B1B} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1} EndGlobalSection EndGlobal diff --git a/samples/MvcSandbox/project.json b/samples/MvcSandbox/project.json index 3e85d9b9f6..177a45fea7 100644 --- a/samples/MvcSandbox/project.json +++ b/samples/MvcSandbox/project.json @@ -7,10 +7,8 @@ "dependencies": { "Microsoft.AspNetCore.Diagnostics": "1.2.0-*", "Microsoft.AspNetCore.Mvc": "1.2.0-*", - "Microsoft.AspNetCore.Razor.Tools": { - "type": "build", - "version": "1.1.0-preview4-final" - }, + "Microsoft.AspNetCore.Razor": "1.2.0-*", + "Microsoft.AspNetCore.Razor.Runtime": "1.2.0-*", "Microsoft.AspNetCore.Server.IISIntegration": "1.2.0-*", "Microsoft.AspNetCore.Server.Kestrel": "1.2.0-*", "Microsoft.AspNetCore.StaticFiles": "1.2.0-*", @@ -26,7 +24,6 @@ ] }, "tools": { - "Microsoft.AspNetCore.Razor.Tools": "1.1.0-preview4-final", "Microsoft.DotNet.Watcher.Tools": "1.1.0-preview4-final" }, "frameworks": { diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Host/GeneratedTagHelperAttributeContext.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Host/ApiSets/GeneratedTagHelperAttributeContext.cs similarity index 90% rename from src/Microsoft.AspNetCore.Mvc.Razor.Host/GeneratedTagHelperAttributeContext.cs rename to src/Microsoft.AspNetCore.Mvc.Razor.Host/ApiSets/GeneratedTagHelperAttributeContext.cs index 15eae0b247..f21f1511ed 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Host/GeneratedTagHelperAttributeContext.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor.Host/ApiSets/GeneratedTagHelperAttributeContext.cs @@ -4,7 +4,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor { /// - /// Contains information for the attribute code + /// Contains information for the tag helper attribute code /// generation process. /// public class GeneratedTagHelperAttributeContext diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Host/Internal/GeneratedViewComponentTagHelperContext.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Host/ApiSets/GeneratedViewComponentTagHelperContext.cs similarity index 93% rename from src/Microsoft.AspNetCore.Mvc.Razor.Host/Internal/GeneratedViewComponentTagHelperContext.cs rename to src/Microsoft.AspNetCore.Mvc.Razor.Host/ApiSets/GeneratedViewComponentTagHelperContext.cs index 4102811a29..06ef983176 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Host/Internal/GeneratedViewComponentTagHelperContext.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor.Host/ApiSets/GeneratedViewComponentTagHelperContext.cs @@ -4,7 +4,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Host.Internal { /// - /// Contains necessary information for the view component code generation process. + /// Contains necessary information for the view component tag helper code generation process. /// public class GeneratedViewComponentTagHelperContext { diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Host/Directives/ChunkHelper.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Host/Directives/ChunkHelper.cs deleted file mode 100644 index 0d5be57be1..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Host/Directives/ChunkHelper.cs +++ /dev/null @@ -1,93 +0,0 @@ -// 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; -using System.Linq; -using Microsoft.AspNetCore.Razor.Chunks; - -namespace Microsoft.AspNetCore.Mvc.Razor.Directives -{ - /// - /// Contains helper methods for dealing with Chunks - /// - public static class ChunkHelper - { - /// - /// Token that is replaced by the model name in @inherits and @inject - /// chunks as part of . - /// - public static readonly string TModelToken = "TModel"; - private static readonly string TModelReplaceToken = $"<{TModelToken}>"; - - /// - /// Returns the used to determine the model name for the page generated - /// using the specified - /// - /// The to scan for s in. - /// The last in the if found, null otherwise. - /// - public static ModelChunk GetModelChunk(ChunkTree chunkTree) - { - if (chunkTree == null) - { - throw new ArgumentNullException(nameof(chunkTree)); - } - - // If there's more than 1 model chunk there will be a Razor error BUT we want intellisense to show up on - // the current model chunk that the user is typing. - return chunkTree - .Children - .OfType() - .LastOrDefault(); - } - - /// - /// Returns the type name of the Model specified via a in the - /// if specified or the default model type. - /// - /// The to scan for s in. - /// The name of the default model. - /// The model type name for the generated page. - public static string GetModelTypeName( - ChunkTree chunkTree, - string defaultModelName) - { - if (chunkTree == null) - { - throw new ArgumentNullException(nameof(chunkTree)); - } - - if (defaultModelName == null) - { - throw new ArgumentNullException(nameof(defaultModelName)); - } - - var modelChunk = GetModelChunk(chunkTree); - return modelChunk != null ? modelChunk.ModelType : defaultModelName; - } - - /// - /// Returns a string with the <TModel> token replaced with the value specified in - /// . - /// - /// The string to replace the token in. - /// The model name to replace with. - /// A string with the token replaced. - public static string ReplaceTModel( - string value, - string modelName) - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - if (modelName == null) - { - throw new ArgumentNullException(nameof(modelName)); - } - - return value.Replace(TModelReplaceToken, modelName); - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Host/Directives/ChunkInheritanceUtility.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Host/Directives/ChunkInheritanceUtility.cs deleted file mode 100644 index 7a3fc2bf43..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Host/Directives/ChunkInheritanceUtility.cs +++ /dev/null @@ -1,193 +0,0 @@ -// 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; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using Microsoft.AspNetCore.Razor; -using Microsoft.AspNetCore.Razor.Chunks; -using Microsoft.AspNetCore.Razor.Parser; -using Microsoft.Extensions.FileProviders; - -namespace Microsoft.AspNetCore.Mvc.Razor.Directives -{ - /// - /// A utility type for supporting inheritance of directives into a page from applicable _ViewImports pages. - /// - public class ChunkInheritanceUtility - { - private readonly MvcRazorHost _razorHost; - private readonly IReadOnlyList _defaultInheritedChunks; - private readonly IChunkTreeCache _chunkTreeCache; - - /// - /// Initializes a new instance of . - /// - /// The used to parse _ViewImports pages. - /// that caches instances. - /// - /// Sequence of s inherited by default. - public ChunkInheritanceUtility( - MvcRazorHost razorHost, - IChunkTreeCache chunkTreeCache, - IReadOnlyList defaultInheritedChunks) - { - if (razorHost == null) - { - throw new ArgumentNullException(nameof(razorHost)); - } - - if (chunkTreeCache == null) - { - throw new ArgumentNullException(nameof(chunkTreeCache)); - } - - if (defaultInheritedChunks == null) - { - throw new ArgumentNullException(nameof(defaultInheritedChunks)); - } - - _razorHost = razorHost; - _defaultInheritedChunks = defaultInheritedChunks; - _chunkTreeCache = chunkTreeCache; - } - - /// - /// Gets an ordered of parsed s and - /// file paths for each _ViewImports that is applicable to the page located at - /// . The list is ordered so that the 's - /// for the _ViewImports closest to the - /// in the file system appears first. - /// - /// The path of the page to locate inherited chunks for. - /// A of parsed _ViewImports - /// s and their file paths. - /// - /// The resulting is ordered so that the result - /// for a _ViewImport closest to the application root appears first and the _ViewImport - /// closest to the page appears last i.e. - /// [ /_ViewImport, /Views/_ViewImport, /Views/Home/_ViewImport ] - /// - public virtual IReadOnlyList GetInheritedChunkTreeResults(string pagePath) - { - if (pagePath == null) - { - throw new ArgumentNullException(nameof(pagePath)); - } - - var inheritedChunkTreeResults = new List(); - var templateEngine = new RazorTemplateEngine(_razorHost); - foreach (var viewImportsPath in ViewHierarchyUtility.GetViewImportsLocations(pagePath)) - { - // viewImportsPath contains the app-relative path of the _ViewImports. - // Since the parsing of a _ViewImports would cause parent _ViewImports to be parsed - // we need to ensure the paths are app-relative to allow the GetGlobalFileLocations - // for the current _ViewImports to succeed. - var chunkTree = _chunkTreeCache.GetOrAdd( - viewImportsPath, - fileInfo => ParseViewFile( - templateEngine, - fileInfo, - viewImportsPath)); - - if (chunkTree != null) - { - var result = new ChunkTreeResult(chunkTree, viewImportsPath); - inheritedChunkTreeResults.Insert(0, result); - } - } - - return inheritedChunkTreeResults; - } - - /// - /// Merges inherited by default and instances produced by parsing - /// _ViewImports files into the specified . - /// - /// The to merge in to. - /// inherited from _ViewImports - /// files. - /// The default model name. - public void MergeInheritedChunkTrees( - ChunkTree chunkTree, - IReadOnlyList inheritedChunkTrees, - string defaultModel) - { - if (chunkTree == null) - { - throw new ArgumentNullException(nameof(chunkTree)); - } - - if (inheritedChunkTrees == null) - { - throw new ArgumentNullException(nameof(inheritedChunkTrees)); - } - - var chunkMergers = GetChunkMergers(chunkTree, defaultModel); - // We merge chunks into the ChunkTree in two passes. In the first pass, we traverse the ChunkTree visiting - // a mapped IChunkMerger for types that are registered. - foreach (var chunk in chunkTree.Children) - { - foreach (var merger in chunkMergers) - { - merger.VisitChunk(chunk); - } - } - - var inheritedChunks = _defaultInheritedChunks.Concat( - inheritedChunkTrees.SelectMany(tree => tree.Children)).ToArray(); - - foreach (var merger in chunkMergers) - { - merger.MergeInheritedChunks(chunkTree, inheritedChunks); - } - } - - private static IChunkMerger[] GetChunkMergers(ChunkTree chunkTree, string defaultModel) - { - var modelType = ChunkHelper.GetModelTypeName(chunkTree, defaultModel); - return new IChunkMerger[] - { - new UsingChunkMerger(), - new InjectChunkMerger(modelType), - new SetBaseTypeChunkMerger(modelType) - }; - } - - private static ChunkTree ParseViewFile( - RazorTemplateEngine engine, - IFileInfo fileInfo, - string viewImportsPath) - { - using (var stream = fileInfo.CreateReadStream()) - { - using (var streamReader = new StreamReader(stream)) - { - var parseResults = engine.ParseTemplate(streamReader, viewImportsPath); - var className = ParserHelpers.SanitizeClassName(fileInfo.Name); - var language = engine.Host.CodeLanguage; - var chunkGenerator = language.CreateChunkGenerator( - className, - engine.Host.DefaultNamespace, - viewImportsPath, - engine.Host); - chunkGenerator.Visit(parseResults); - - // Rewrite the location of inherited chunks so they point to the global import file. - var chunkTree = chunkGenerator.Context.ChunkTreeBuilder.Root; - foreach (var chunk in chunkTree.Children) - { - chunk.Start = new SourceLocation( - viewImportsPath, - chunk.Start.AbsoluteIndex, - chunk.Start.LineIndex, - chunk.Start.CharacterIndex); - } - - return chunkTree; - } - } - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Host/Directives/ChunkTreeResult.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Host/Directives/ChunkTreeResult.cs deleted file mode 100644 index 62a2605afd..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Host/Directives/ChunkTreeResult.cs +++ /dev/null @@ -1,46 +0,0 @@ -// 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; -using Microsoft.AspNetCore.Razor.Chunks; - -namespace Microsoft.AspNetCore.Mvc.Razor.Directives -{ - /// - /// Contains information. - /// - public class ChunkTreeResult - { - /// - /// Initializes a new instance of . - /// - /// The generated from the file at the - /// given . - /// The path to the file that generated the given . - public ChunkTreeResult(ChunkTree chunkTree, string filePath) - { - if (chunkTree == null) - { - throw new ArgumentNullException(nameof(chunkTree)); - } - - if (filePath == null) - { - throw new ArgumentNullException(nameof(filePath)); - } - - ChunkTree = chunkTree; - FilePath = filePath; - } - - /// - /// The generated from the file at . - /// - public ChunkTree ChunkTree { get; } - - /// - /// The path to the file that generated the . - /// - public string FilePath { get; } - } -} diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Host/Directives/DefaultChunkTreeCache.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Host/Directives/DefaultChunkTreeCache.cs deleted file mode 100644 index 4f8eaa54c0..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Host/Directives/DefaultChunkTreeCache.cs +++ /dev/null @@ -1,82 +0,0 @@ -// 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; -using Microsoft.AspNetCore.Razor.Chunks; -using Microsoft.Extensions.Caching.Memory; -using Microsoft.Extensions.FileProviders; - -namespace Microsoft.AspNetCore.Mvc.Razor.Directives -{ - /// - /// Default implementation of . - /// - public class DefaultChunkTreeCache : IChunkTreeCache - { - private static readonly MemoryCacheOptions MemoryCacheOptions = new MemoryCacheOptions - { - CompactOnMemoryPressure = false - }; - private static readonly TimeSpan SlidingExpirationDuration = TimeSpan.FromMinutes(1); - private readonly IFileProvider _fileProvider; - private readonly IMemoryCache _chunkTreeCache; - - /// - /// Initializes a new instance of . - /// - /// The application's . - public DefaultChunkTreeCache(IFileProvider fileProvider) - : this(fileProvider, MemoryCacheOptions) - { - } - - // Internal for unit testing - internal DefaultChunkTreeCache( - IFileProvider fileProvider, - MemoryCacheOptions options) - { - _fileProvider = fileProvider; - _chunkTreeCache = new MemoryCache(options); - } - - /// - public ChunkTree GetOrAdd( - string pagePath, - Func getChunkTree) - { - if (pagePath == null) - { - throw new ArgumentNullException(nameof(pagePath)); - } - - if (getChunkTree == null) - { - throw new ArgumentNullException(nameof(getChunkTree)); - } - - ChunkTree chunkTree; - if (!_chunkTreeCache.TryGetValue(pagePath, out chunkTree)) - { - // GetOrAdd is invoked for each _ViewImport that might potentially exist in the path. - // We can avoid performing file system lookups for files that do not exist by caching - // negative results and adding a Watch for that file. - - var options = new MemoryCacheEntryOptions() - .AddExpirationToken(_fileProvider.Watch(pagePath)) - .SetSlidingExpiration(SlidingExpirationDuration); - - var file = _fileProvider.GetFileInfo(pagePath); - chunkTree = file.Exists ? getChunkTree(file) : null; - - _chunkTreeCache.Set(pagePath, chunkTree, options); - } - - return chunkTree; - } - - public void Dispose() - { - _chunkTreeCache.Dispose(); - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Host/Directives/IChunkMerger.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Host/Directives/IChunkMerger.cs deleted file mode 100644 index d171efacf6..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Host/Directives/IChunkMerger.cs +++ /dev/null @@ -1,27 +0,0 @@ -// 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.Collections.Generic; -using Microsoft.AspNetCore.Razor.Chunks; - -namespace Microsoft.AspNetCore.Mvc.Razor.Directives -{ - /// - /// Defines the contract for merging instances from _ViewStart files. - /// - public interface IChunkMerger - { - /// - /// Visits a from the to merge into. - /// - /// A from the tree. - void VisitChunk(Chunk chunk); - - /// - /// Merges an inherited into the . - /// - /// The to merge into. - /// The s to merge. - void MergeInheritedChunks(ChunkTree chunkTree, IReadOnlyList inheritedChunks); - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Host/Directives/IChunkTreeCache.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Host/Directives/IChunkTreeCache.cs deleted file mode 100644 index f47e7efaba..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Host/Directives/IChunkTreeCache.cs +++ /dev/null @@ -1,27 +0,0 @@ -// 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; -using Microsoft.AspNetCore.Razor.Chunks; -using Microsoft.Extensions.FileProviders; - -namespace Microsoft.AspNetCore.Mvc.Razor.Directives -{ - /// - /// A cache for parsed s. - /// - public interface IChunkTreeCache : IDisposable - { - /// - /// Get an existing , or create and add a new one if it is - /// not available in the cache or is expired. - /// - /// The application relative path of the Razor page. - /// A delegate that creates a new . - /// The if a file exists at , - /// null otherwise. - /// The resulting does not contain inherited chunks from _ViewStart or - /// default inherited chunks. - ChunkTree GetOrAdd(string pagePath, Func getChunkTree); - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Host/Directives/InjectChunkMerger.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Host/Directives/InjectChunkMerger.cs deleted file mode 100644 index 07a18f9741..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Host/Directives/InjectChunkMerger.cs +++ /dev/null @@ -1,87 +0,0 @@ -// 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; -using System.Collections.Generic; -using System.Linq; -using Microsoft.AspNetCore.Razor.Chunks; - -namespace Microsoft.AspNetCore.Mvc.Razor.Directives -{ - /// - /// A that merges instances. - /// - public class InjectChunkMerger : IChunkMerger - { - private readonly HashSet _addedMemberNames = new HashSet(StringComparer.Ordinal); - private string _modelType; - - /// - /// Initializes a new instance of . - /// - /// The model type to be used to replace <TModel> tokens. - public InjectChunkMerger(string modelType) - { - if (modelType == null) - { - throw new ArgumentNullException(nameof(modelType)); - } - - _modelType = "<" + modelType + ">"; - } - - /// - public void VisitChunk(Chunk chunk) - { - if (chunk == null) - { - throw new ArgumentNullException(nameof(chunk)); - } - - var injectChunk = chunk as InjectChunk; - if (injectChunk != null) - { - injectChunk.TypeName = ChunkHelper.ReplaceTModel(injectChunk.TypeName, _modelType); - _addedMemberNames.Add(injectChunk.MemberName); - } - } - - /// - public void MergeInheritedChunks(ChunkTree chunkTree, IReadOnlyList inheritedChunks) - { - if (chunkTree == null) - { - throw new ArgumentNullException(nameof(chunkTree)); - } - - if (inheritedChunks == null) - { - throw new ArgumentNullException(nameof(inheritedChunks)); - } - - for (var i = inheritedChunks.Count - 1; i >= 0; i--) - { - var injectChunk = inheritedChunks[i] as InjectChunk; - if (injectChunk != null && - _addedMemberNames.Add(injectChunk.MemberName)) - { - chunkTree.Children.Add(TransformChunk(injectChunk)); - } - } - } - - private InjectChunk TransformChunk(InjectChunk injectChunk) - { - var typeName = ChunkHelper.ReplaceTModel(injectChunk.TypeName, _modelType); - if (typeName != injectChunk.TypeName) - { - return new InjectChunk(typeName, injectChunk.MemberName) - { - Start = injectChunk.Start, - Association = injectChunk.Association - }; - } - return injectChunk; - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Host/Directives/SetBaseTypeChunkMerger.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Host/Directives/SetBaseTypeChunkMerger.cs deleted file mode 100644 index 28d69a80db..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Host/Directives/SetBaseTypeChunkMerger.cs +++ /dev/null @@ -1,85 +0,0 @@ -// 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; -using System.Collections.Generic; -using Microsoft.AspNetCore.Razor.Chunks; - -namespace Microsoft.AspNetCore.Mvc.Razor.Directives -{ - /// - /// A that merges instances. - /// - public class SetBaseTypeChunkMerger : IChunkMerger - { - private readonly string _modelType; - private bool _isBaseTypeSet; - - /// - /// Initializes a new instance of . - /// - /// The type name of the model used by default. - public SetBaseTypeChunkMerger(string modelType) - { - _modelType = "<" + modelType + ">"; - } - - /// - public void VisitChunk(Chunk chunk) - { - if (chunk == null) - { - throw new ArgumentNullException(nameof(chunk)); - } - - var setBaseTypeChunk = chunk as SetBaseTypeChunk; - if (setBaseTypeChunk != null) - { - setBaseTypeChunk.TypeName = ChunkHelper.ReplaceTModel(setBaseTypeChunk.TypeName, _modelType); - _isBaseTypeSet = true; - } - } - - /// - public void MergeInheritedChunks(ChunkTree chunkTree, IReadOnlyList inheritedChunks) - { - if (chunkTree == null) - { - throw new ArgumentNullException(nameof(chunkTree)); - } - - if (inheritedChunks == null) - { - throw new ArgumentNullException(nameof(inheritedChunks)); - } - - if (!_isBaseTypeSet) - { - for (var i = inheritedChunks.Count - 1; i >= 0; i--) - { - var baseTypeChunk = inheritedChunks[i] as SetBaseTypeChunk; - if (baseTypeChunk != null) - { - chunkTree.Children.Add(TransformChunk(baseTypeChunk)); - break; - } - } - } - } - - private SetBaseTypeChunk TransformChunk(SetBaseTypeChunk setBaseTypeChunk) - { - var typeName = ChunkHelper.ReplaceTModel(setBaseTypeChunk.TypeName, _modelType); - if (typeName != setBaseTypeChunk.TypeName) - { - return new SetBaseTypeChunk - { - TypeName = typeName, - Start = setBaseTypeChunk.Start, - Association = setBaseTypeChunk.Association - }; - } - return setBaseTypeChunk; - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Host/Directives/UsingChunkMerger.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Host/Directives/UsingChunkMerger.cs deleted file mode 100644 index 8c60952462..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Host/Directives/UsingChunkMerger.cs +++ /dev/null @@ -1,56 +0,0 @@ -// 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; -using System.Collections.Generic; -using System.Linq; -using Microsoft.AspNetCore.Razor.Chunks; - -namespace Microsoft.AspNetCore.Mvc.Razor.Directives -{ - /// - /// A that merges instances. - /// - public class UsingChunkMerger : IChunkMerger - { - private readonly HashSet _currentUsings = new HashSet(StringComparer.Ordinal); - - /// - public void VisitChunk(Chunk chunk) - { - if (chunk == null) - { - throw new ArgumentNullException(nameof(chunk)); - } - - var namespaceChunk = chunk as UsingChunk; - if (namespaceChunk != null) - { - _currentUsings.Add(namespaceChunk.Namespace); - } - } - - /// - public void MergeInheritedChunks(ChunkTree chunkTree, IReadOnlyList inheritedChunks) - { - if (chunkTree == null) - { - throw new ArgumentNullException(nameof(chunkTree)); - } - - if (inheritedChunks == null) - { - throw new ArgumentNullException(nameof(inheritedChunks)); - } - - var namespaceChunks = inheritedChunks.OfType(); - foreach (var namespaceChunk in namespaceChunks) - { - if (_currentUsings.Add(namespaceChunk.Namespace)) - { - chunkTree.Children.Add(namespaceChunk); - } - } - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Host/IMvcRazorHost.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Host/IMvcRazorHost.cs deleted file mode 100644 index fa8b6f98a9..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Host/IMvcRazorHost.cs +++ /dev/null @@ -1,29 +0,0 @@ -// 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 Microsoft.AspNetCore.Razor.CodeGenerators; - -namespace Microsoft.AspNetCore.Mvc.Razor -{ - /// - /// Specifies the contracts for a Razor host that parses Razor files and generates C# code. - /// - public interface IMvcRazorHost - { - /// - /// Parses and generates the contents of a Razor file represented by . - /// - /// The path of the relative to the root of the application. - /// Used to generate line pragmas and calculate the class name of the generated type. - /// A that represents the Razor contents. - /// A instance that represents the results of code generation. - /// - GeneratorResults GenerateCode(string rootRelativePath, Stream inputStream); - - /// - /// Represent the namespace the main entry class in the view. - /// - string DefaultNamespace { get; } - } -} diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Host/InjectChunk.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Host/InjectChunk.cs deleted file mode 100644 index f9c8fb36e9..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Host/InjectChunk.cs +++ /dev/null @@ -1,33 +0,0 @@ -// 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 Microsoft.AspNetCore.Razor.Chunks; - -namespace Microsoft.AspNetCore.Mvc.Razor -{ - public class InjectChunk : Chunk - { - /// - /// Represents the chunk for an @inject statement. - /// - /// The type name of the property to be injected - /// The member name of the property to be injected. - public InjectChunk( - string typeName, - string propertyName) - { - TypeName = typeName; - MemberName = propertyName; - } - - /// - /// Gets or sets the type name of the property to be injected. - /// - public string TypeName { get; set; } - - /// - /// Gets or sets the name of the property to be injected. - /// - public string MemberName { get; set; } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Host/InjectChunkVisitor.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Host/InjectChunkVisitor.cs deleted file mode 100644 index 47ba9c61c0..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Host/InjectChunkVisitor.cs +++ /dev/null @@ -1,78 +0,0 @@ -// 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; -using System.Collections.Generic; -using Microsoft.AspNetCore.Razor.CodeGenerators; -using Microsoft.AspNetCore.Razor.CodeGenerators.Visitors; - -namespace Microsoft.AspNetCore.Mvc.Razor -{ - public class InjectChunkVisitor : MvcCSharpCodeVisitor - { - private readonly string _injectAttribute; - - public InjectChunkVisitor( - CSharpCodeWriter writer, - CodeGeneratorContext context, - string injectAttributeName) - : base(writer, context) - { - if (writer == null) - { - throw new ArgumentNullException(nameof(writer)); - } - - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } - - if (injectAttributeName == null) - { - throw new ArgumentNullException(nameof(injectAttributeName)); - } - - _injectAttribute = "[" + injectAttributeName + "]"; - } - - public IList InjectChunks { get; } = new List(); - - protected override void Visit(InjectChunk chunk) - { - if (chunk == null) - { - throw new ArgumentNullException(nameof(chunk)); - } - - Writer.WriteLine(_injectAttribute); - - // Some of the chunks that we visit are either InjectDescriptors that are added by default or - // are chunks from _ViewStart files and are not associated with any Spans. Invoking - // CreateExpressionMapping to produce line mappings on these chunks would fail. We'll skip - // generating code mappings for these chunks. This makes sense since the chunks do not map - // to any code in the current view. - if (Context.Host.DesignTimeMode && chunk.Association != null) - { - Writer.WriteLine("public"); - - var code = string.IsNullOrEmpty(chunk.MemberName) ? - chunk.TypeName : - chunk.TypeName + " " + chunk.MemberName; - var csharpVisitor = new CSharpCodeVisitor(Writer, Context); - csharpVisitor.CreateExpressionCodeMapping(code, chunk); - Writer.WriteLine("{ get; private set; }"); - } - else - { - Writer.Write("public ") - .Write(chunk.TypeName) - .Write(" ") - .Write(chunk.MemberName) - .WriteLine(" { get; private set; }"); - } - - InjectChunks.Add(chunk); - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Host/InjectDirective.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Host/InjectDirective.cs new file mode 100644 index 0000000000..6af43444c1 --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.Razor.Host/InjectDirective.cs @@ -0,0 +1,93 @@ +// 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; +using System.Collections.Generic; +using System.Linq; +using Microsoft.AspNetCore.Razor.Evolution; +using Microsoft.AspNetCore.Razor.Evolution.Intermediate; + +namespace Microsoft.AspNetCore.Mvc.Razor.Host +{ + public static class InjectDirective + { + public static readonly DirectiveDescriptor Directive = DirectiveDescriptorBuilder.Create("inject").AddType().AddMember().Build(); + + public static IRazorEngineBuilder Register(IRazorEngineBuilder builder) + { + builder.AddDirective(Directive); + builder.Features.Add(new Pass()); + return builder; + } + + private class Pass : IRazorIRPass + { + public RazorEngine Engine { get; set; } + + public int Order => RazorIRPass.DirectiveClassifierOrder; + + public DocumentIRNode Execute(RazorCodeDocument codeDocument, DocumentIRNode irDocument) + { + var visitor = new Visitor(); + visitor.Visit(irDocument); + + for (var i = 0; i < visitor.Directives.Count; i++) + { + var directive = visitor.Directives[i]; + var typeName = directive.Tokens.ElementAt(0).Content;; + var memberName = directive.Tokens.ElementAt(1).Content; + + var modelType = "dynamic"; + if (visitor.ModelType.Count > 0) + { + modelType = visitor.ModelType.Last().Tokens.First().Content; + } + + typeName = typeName.Replace("", "<" + modelType + ">"); + + var member = new CSharpStatementIRNode() + { + Source = directive.Source, + Content = $"[Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]{Environment.NewLine}public {typeName} {memberName} {{ get; private set; }}", + Parent = visitor.Class, + }; + + visitor.Class.Children.Add(member); + } + + return irDocument; + } + } + + private class Visitor : RazorIRNodeWalker + { + public ClassDeclarationIRNode Class { get; private set; } + + public IList Directives { get; } = new List(); + + public IList ModelType { get; } = new List(); + + public override void VisitClass(ClassDeclarationIRNode node) + { + if (Class == null) + { + Class = node; + } + + base.VisitClass(node); + } + + public override void VisitDirective(DirectiveIRNode node) + { + if (node.Descriptor == Directive) + { + Directives.Add(node); + } + else if (node.Descriptor == ModelDirective.Directive) + { + ModelType.Add(node); + } + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Host/InjectParameterGenerator.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Host/InjectParameterGenerator.cs deleted file mode 100644 index 913404c16f..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Host/InjectParameterGenerator.cs +++ /dev/null @@ -1,48 +0,0 @@ -// 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; -using System.Globalization; -using Microsoft.AspNetCore.Razor.Chunks.Generators; -using Microsoft.AspNetCore.Razor.Parser.SyntaxTree; - -namespace Microsoft.AspNetCore.Mvc.Razor -{ - public class InjectParameterGenerator : SpanChunkGenerator - { - public InjectParameterGenerator(string typeName, string propertyName) - { - TypeName = typeName; - PropertyName = propertyName; - } - - public string TypeName { get; private set; } - - public string PropertyName { get; private set; } - - public override void GenerateChunk(Span target, ChunkGeneratorContext context) - { - var injectChunk = new InjectChunk(TypeName, PropertyName); - context.ChunkTreeBuilder.AddChunk(injectChunk, target); - } - - public override string ToString() - { - return string.Format(CultureInfo.InvariantCulture, "@inject {0} {1}", TypeName, PropertyName); - } - - public override bool Equals(object obj) - { - var other = obj as InjectParameterGenerator; - return other != null && - string.Equals(TypeName, other.TypeName, StringComparison.Ordinal) && - string.Equals(PropertyName, other.PropertyName, StringComparison.Ordinal); - } - - public override int GetHashCode() - { - return TypeName.GetHashCode() + - (PropertyName.GetHashCode() * 13); - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Host/Internal/TagHelperChunkDecorator.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Host/Internal/TagHelperChunkDecorator.cs deleted file mode 100644 index 3c69cfc078..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Host/Internal/TagHelperChunkDecorator.cs +++ /dev/null @@ -1,73 +0,0 @@ -// 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; -using System.Collections.Generic; -using Microsoft.AspNetCore.Razor.Chunks; -using Microsoft.AspNetCore.Razor.CodeGenerators; -using Microsoft.AspNetCore.Razor.CodeGenerators.Visitors; -using Microsoft.AspNetCore.Razor.Compilation.TagHelpers; - -namespace Microsoft.AspNetCore.Mvc.Razor.Host.Internal -{ - public class TagHelperChunkDecorator : CodeVisitor - { - private readonly string _className; - private readonly string _namespaceName; - - public TagHelperChunkDecorator(CodeGeneratorContext context) - : base(new CSharpCodeWriter(), context) - { - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } - - _namespaceName = context.RootNamespace; - _className = context.ClassName; - } - - public override void Accept(Chunk chunk) - { - if (chunk == null) - { - throw new ArgumentNullException(nameof(chunk)); - } - - var tagHelperChunk = chunk as TagHelperChunk; - if (tagHelperChunk != null) - { - tagHelperChunk.Descriptors = Decorate(tagHelperChunk.Descriptors); - } - - var parentChunk = chunk as ParentChunk; - if (parentChunk != null) - { - Visit(parentChunk); - } - } - - protected override void Visit(ParentChunk parentChunk) - { - Accept(parentChunk.Children); - } - - private IEnumerable Decorate(IEnumerable descriptors) - { - foreach (var descriptor in descriptors) - { - if (ViewComponentTagHelperDescriptorConventions.IsViewComponentDescriptor(descriptor)) - { - var decoratedDescriptor = new TagHelperDescriptor(descriptor); - decoratedDescriptor.TypeName = $"{_namespaceName}.{_className}.{descriptor.TypeName}"; - - yield return decoratedDescriptor; - } - else - { - yield return descriptor; - } - } - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Host/Internal/ViewComponentTagHelperChunkVisitor.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Host/Internal/ViewComponentTagHelperChunkVisitor.cs deleted file mode 100644 index a85649481d..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Host/Internal/ViewComponentTagHelperChunkVisitor.cs +++ /dev/null @@ -1,208 +0,0 @@ -// 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; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Razor.Chunks; -using Microsoft.AspNetCore.Razor.CodeGenerators; -using Microsoft.AspNetCore.Razor.CodeGenerators.Visitors; -using Microsoft.AspNetCore.Razor.Compilation.TagHelpers; -using Microsoft.AspNetCore.Razor.TagHelpers; - -namespace Microsoft.AspNetCore.Mvc.Razor.Host.Internal -{ - public class ViewComponentTagHelperChunkVisitor : CodeVisitor - { - private readonly GeneratedViewComponentTagHelperContext _context; - private readonly HashSet _writtenViewComponents; - - private const string ViewComponentTagHelperVariable = "_viewComponentHelper"; - private const string ViewContextVariable = "ViewContext"; - - public ViewComponentTagHelperChunkVisitor(CSharpCodeWriter writer, CodeGeneratorContext context) - : base(writer, context) - { - _context = new GeneratedViewComponentTagHelperContext(); - _writtenViewComponents = new HashSet(StringComparer.Ordinal); - } - - public override void Accept(Chunk chunk) - { - if (chunk == null) - { - throw new ArgumentNullException(nameof(chunk)); - } - - var tagHelperChunk = chunk as TagHelperChunk; - if (tagHelperChunk != null) - { - Visit(tagHelperChunk); - } - - var parentChunk = chunk as ParentChunk; - if (parentChunk != null) - { - Visit(parentChunk); - } - } - - protected override void Visit(ParentChunk parentChunk) - { - Accept(parentChunk.Children); - } - - protected override void Visit(TagHelperChunk chunk) - { - foreach (var descriptor in chunk.Descriptors) - { - string shortName; - if (descriptor.PropertyBag.TryGetValue( - ViewComponentTagHelperDescriptorConventions.ViewComponentNameKey, - out shortName)) - { - var typeName = $"__Generated__{shortName}ViewComponentTagHelper"; - - if (_writtenViewComponents.Add(typeName)) - { - WriteClass(descriptor); - } - } - } - } - - private void WriteClass(TagHelperDescriptor descriptor) - { - // Add target element. - BuildTargetElementString(descriptor); - - // Initialize declaration. - var tagHelperTypeName = typeof(TagHelper).FullName; - - var shortName = descriptor.PropertyBag[ViewComponentTagHelperDescriptorConventions.ViewComponentNameKey]; - var className = $"__Generated__{shortName}ViewComponentTagHelper"; - - using (Writer.BuildClassDeclaration("public", className, new[] { tagHelperTypeName })) - { - // Add view component helper. - Writer.WriteVariableDeclaration( - $"private readonly global::{_context.IViewComponentHelperTypeName}", - ViewComponentTagHelperVariable, - value: null); - - // Add constructor. - BuildConstructorString(className); - - // Add attributes. - BuildAttributeDeclarations(descriptor); - - // Add process method. - BuildProcessMethodString(descriptor); - } - } - - private void BuildConstructorString(string className) - { - var viewComponentHelperVariable = "viewComponentHelper"; - - var helperPair = new KeyValuePair( - $"global::{_context.IViewComponentHelperTypeName}", - viewComponentHelperVariable); - - using (Writer.BuildConstructor( "public", className, new[] { helperPair })) - { - Writer.WriteStartAssignment(ViewComponentTagHelperVariable) - .Write(viewComponentHelperVariable) - .WriteLine(";"); - } - } - - private void BuildAttributeDeclarations(TagHelperDescriptor descriptor) - { - Writer.Write("[") - .Write(typeof(HtmlAttributeNotBoundAttribute).FullName) - .WriteParameterSeparator() - .Write($"global::{_context.ViewContextAttributeTypeName}") - .WriteLine("]"); - - Writer.WriteAutoPropertyDeclaration( - "public", - $"global::{_context.ViewContextTypeName}", - ViewContextVariable); - - var indexerAttributes = descriptor.Attributes.Where(a => a.IsIndexer); - - foreach (var attribute in descriptor.Attributes) - { - if (attribute.IsIndexer) - { - continue; - } - - Writer.WriteAutoPropertyDeclaration("public", attribute.TypeName, attribute.PropertyName); - - if (indexerAttributes.Any(a => string.Equals(a.PropertyName, attribute.PropertyName, StringComparison.Ordinal))) - { - Writer.Write(" = ") - .WriteStartNewObject(attribute.TypeName) - .WriteEndMethodInvocation(); - } - } - } - - private void BuildProcessMethodString(TagHelperDescriptor descriptor) - { - var contextVariable = "context"; - var outputVariable = "output"; - - using (Writer.BuildMethodDeclaration( - $"public override async", - $"global::{typeof(Task).FullName}", - nameof(ITagHelper.ProcessAsync), - new Dictionary() - { - { typeof(TagHelperContext).FullName, contextVariable }, - { typeof(TagHelperOutput).FullName, outputVariable } - })) - { - Writer.WriteInstanceMethodInvocation( - $"({ViewComponentTagHelperVariable} as global::{_context.IViewContextAwareTypeName})?", - _context.ContextualizeMethodName, - new [] { ViewContextVariable }); - - var methodParameters = GetMethodParameters(descriptor); - var viewContentVariable = "viewContent"; - Writer.Write("var ") - .WriteStartAssignment(viewContentVariable) - .WriteInstanceMethodInvocation($"await {ViewComponentTagHelperVariable}", _context.InvokeAsyncMethodName, methodParameters); - Writer.WriteStartAssignment($"{outputVariable}.{nameof(TagHelperOutput.TagName)}") - .WriteLine("null;"); - Writer.WriteInstanceMethodInvocation( - $"{outputVariable}.{nameof(TagHelperOutput.Content)}", - nameof(TagHelperContent.SetHtmlContent), - new [] { viewContentVariable }); - } - } - - private string[] GetMethodParameters(TagHelperDescriptor descriptor) - { - var propertyNames = descriptor.Attributes.Where(a => !a.IsIndexer).Select(attribute => attribute.PropertyName); - var joinedPropertyNames = string.Join(", ", propertyNames); - var parametersString = $" new {{ { joinedPropertyNames } }}"; - - var viewComponentName = descriptor.PropertyBag[ - ViewComponentTagHelperDescriptorConventions.ViewComponentNameKey]; - var methodParameters = new [] { $"\"{viewComponentName}\"", parametersString }; - return methodParameters; - } - - private void BuildTargetElementString(TagHelperDescriptor descriptor) - { - Writer.Write("[") - .WriteStartMethodInvocation(typeof(HtmlTargetElementAttribute).FullName) - .WriteStringLiteral(descriptor.FullTagName) - .WriteLine(")]"); - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Host/ModelChunk.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Host/ModelChunk.cs deleted file mode 100644 index e7ff54e42c..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Host/ModelChunk.cs +++ /dev/null @@ -1,27 +0,0 @@ -// 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 Microsoft.AspNetCore.Razor.Chunks; - -namespace Microsoft.AspNetCore.Mvc.Razor -{ - /// - /// for an @model directive. - /// - public class ModelChunk : Chunk - { - /// - /// Initializes a new instance of . - /// - /// The type of the view's model. - public ModelChunk(string modelType) - { - ModelType = modelType; - } - - /// - /// Gets the type of the view's model. - /// - public string ModelType { get; } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Host/ModelChunkGenerator.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Host/ModelChunkGenerator.cs deleted file mode 100644 index 701dde1e4a..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Host/ModelChunkGenerator.cs +++ /dev/null @@ -1,40 +0,0 @@ -// 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; -using Microsoft.AspNetCore.Mvc.Razor; -using Microsoft.AspNetCore.Razor.Chunks.Generators; -using Microsoft.AspNetCore.Razor.Parser.SyntaxTree; - -namespace Microsoft.AspNetCore.Razor.Generator -{ - public class ModelChunkGenerator : SpanChunkGenerator - { - public ModelChunkGenerator(string modelType) - { - ModelType = modelType; - } - - public string ModelType { get; } - - public override void GenerateChunk(Span target, ChunkGeneratorContext context) - { - var modelChunk = new ModelChunk(ModelType); - context.ChunkTreeBuilder.AddChunk(modelChunk, target, topLevel: true); - } - - public override string ToString() => ModelType; - - public override bool Equals(object obj) - { - var other = obj as ModelChunkGenerator; - return other != null && - string.Equals(ModelType, other.ModelType, StringComparison.Ordinal); - } - - public override int GetHashCode() - { - return StringComparer.Ordinal.GetHashCode(ModelType); - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Host/ModelDirective.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Host/ModelDirective.cs new file mode 100644 index 0000000000..7c9eced429 --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.Razor.Host/ModelDirective.cs @@ -0,0 +1,71 @@ +// 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.Collections.Generic; +using System.Linq; +using Microsoft.AspNetCore.Razor.Evolution; +using Microsoft.AspNetCore.Razor.Evolution.Intermediate; + +namespace Microsoft.AspNetCore.Mvc.Razor.Host +{ + public static class ModelDirective + { + public static readonly DirectiveDescriptor Directive = DirectiveDescriptorBuilder.Create("model").AddType().Build(); + + public static IRazorEngineBuilder Register(IRazorEngineBuilder builder) + { + builder.AddDirective(Directive); + builder.Features.Add(new Pass()); + return builder; + } + + private class Pass : IRazorIRPass + { + public RazorEngine Engine { get; set; } + + // Runs after the @inherits directive + public int Order => RazorIRPass.DefaultDirectiveClassifierOrder + 5; + + public DocumentIRNode Execute(RazorCodeDocument codeDocument, DocumentIRNode irDocument) + { + var visitor = new Visitor(); + visitor.Visit(irDocument); + + string modelType = "dynamic"; + if (visitor.Directives.Count == 1) + { + modelType = visitor.Directives.Last().Tokens.First().Content; + } + + visitor.Class.BaseType = visitor.Class.BaseType.Replace("", "<" + modelType + ">"); + + return irDocument; + } + } + + private class Visitor : RazorIRNodeWalker + { + public ClassDeclarationIRNode Class { get; private set; } + + public IList Directives { get; } = new List(); + + public override void VisitClass(ClassDeclarationIRNode node) + { + if (Class == null) + { + Class = node; + } + + base.VisitClass(node); + } + + public override void VisitDirective(DirectiveIRNode node) + { + if (node.Descriptor == Directive) + { + Directives.Add(node); + } + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Host/ModelExpressionPass.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Host/ModelExpressionPass.cs new file mode 100644 index 0000000000..54c77baa27 --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.Razor.Host/ModelExpressionPass.cs @@ -0,0 +1,78 @@ +// 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; +using System.Collections.Generic; +using Microsoft.AspNetCore.Razor.Evolution; +using Microsoft.AspNetCore.Razor.Evolution.Intermediate; + +namespace Microsoft.AspNetCore.Mvc.Razor.Host +{ + public class ModelExpressionPass : IRazorIRPass + { + public RazorEngine Engine { get; set; } + + public int Order => RazorIRPass.LoweringOrder; + + public DocumentIRNode Execute(RazorCodeDocument codeDocument, DocumentIRNode irDocument) + { + var visitor = new Visitor(); + visitor.Visit(irDocument); + + return irDocument; + } + + private class Visitor : RazorIRNodeWalker + { + public List TagHelpers { get; } = new List(); + + public override void VisitSetTagHelperProperty(SetTagHelperPropertyIRNode node) + { + if (string.Equals(node.Descriptor.TypeName, "Microsoft.AspNetCore.Mvc.ViewFeatures.ModelExpression", StringComparison.Ordinal)) + { + var expression = new CSharpExpressionIRNode(); + var builder = RazorIRBuilder.Create(expression); + + builder.Add(new CSharpTokenIRNode() + { + Content = "ModelExpressionProvider.CreateModelExpression(ViewData, __model => ", + }); + + + if (node.Children.Count == 1 && node.Children[0] is HtmlContentIRNode) + { + var original = ((HtmlContentIRNode)node.Children[0]); + + builder.Add(new CSharpTokenIRNode() + { + Content = "__model." + }); + + builder.Add(new CSharpTokenIRNode() + { + Content = original.Content, + Source = original.Source, + }); + } + else + { + for (var i = 0; i < node.Children.Count; i++) + { + builder.Add(node.Children[i]); + } + } + + builder.Add(new CSharpTokenIRNode() + { + Content = ")", + }); + + node.Children.Clear(); + + node.Children.Add(expression); + expression.Parent = node; + } + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcCSharpChunkVisitor.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcCSharpChunkVisitor.cs deleted file mode 100644 index a2bb52bd28..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcCSharpChunkVisitor.cs +++ /dev/null @@ -1,42 +0,0 @@ -// 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; -using Microsoft.AspNetCore.Razor.Chunks; -using Microsoft.AspNetCore.Razor.CodeGenerators; -using Microsoft.AspNetCore.Razor.CodeGenerators.Visitors; - -namespace Microsoft.AspNetCore.Mvc.Razor -{ - public abstract class MvcCSharpChunkVisitor : CodeVisitor - { - public MvcCSharpChunkVisitor( - CSharpCodeWriter writer, - CodeGeneratorContext context) - : base(writer, context) - { - if (writer == null) - { - throw new ArgumentNullException(nameof(writer)); - } - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } - } - - public override void Accept(Chunk chunk) - { - if (chunk is InjectChunk) - { - Visit((InjectChunk)chunk); - } - else - { - base.Accept(chunk); - } - } - - protected abstract void Visit(InjectChunk chunk); - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcCSharpCodeGenerator.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcCSharpCodeGenerator.cs deleted file mode 100644 index 966b409ff8..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcCSharpCodeGenerator.cs +++ /dev/null @@ -1,144 +0,0 @@ -// 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; -using System.Collections.Generic; -using System.IO; -using Microsoft.AspNetCore.Mvc.Razor.Directives; -using Microsoft.AspNetCore.Mvc.Razor.Host.Internal; -using Microsoft.AspNetCore.Razor.Chunks; -using Microsoft.AspNetCore.Razor.CodeGenerators; -using Microsoft.AspNetCore.Razor.CodeGenerators.Visitors; - -namespace Microsoft.AspNetCore.Mvc.Razor -{ - public class MvcCSharpCodeGenerator : CSharpCodeGenerator - { - private readonly GeneratedTagHelperAttributeContext _tagHelperAttributeContext; - private readonly TagHelperChunkDecorator _tagHelperChunkDecorator; - private readonly string _defaultModel; - private readonly string _injectAttribute; - - public MvcCSharpCodeGenerator( - CodeGeneratorContext context, - string defaultModel, - string injectAttribute, - GeneratedTagHelperAttributeContext tagHelperAttributeContext) - : base(context) - { - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } - - if (defaultModel == null) - { - throw new ArgumentNullException(nameof(defaultModel)); - } - - if (injectAttribute == null) - { - throw new ArgumentNullException(nameof(injectAttribute)); - } - - if (tagHelperAttributeContext == null) - { - throw new ArgumentNullException(nameof(tagHelperAttributeContext)); - } - - _tagHelperAttributeContext = tagHelperAttributeContext; - _defaultModel = defaultModel; - _injectAttribute = injectAttribute; - _tagHelperChunkDecorator = new TagHelperChunkDecorator(Context); - } - - public override CodeGeneratorResult Generate() - { - _tagHelperChunkDecorator.Accept(Context.ChunkTreeBuilder.Root.Children); - return base.Generate(); - } - - protected override CSharpCodeWritingScope BuildClassDeclaration(CSharpCodeWriter writer) - { - if (Context.Host.DesignTimeMode && - string.Equals( - Path.GetFileName(Context.SourceFile), - ViewHierarchyUtility.ViewImportsFileName, - StringComparison.OrdinalIgnoreCase)) - { - // Write a using TModel = System.Object; token during design time to make intellisense work - writer.WriteLine($"using {ChunkHelper.TModelToken} = {typeof(object).FullName};"); - } - - return base.BuildClassDeclaration(writer); - } - - protected override void BuildAfterExecuteContent(CSharpCodeWriter writer, IList chunks) - { - new ViewComponentTagHelperChunkVisitor(writer, Context).Accept(chunks); - } - - protected override CSharpCodeVisitor CreateCSharpCodeVisitor( - CSharpCodeWriter writer, - CodeGeneratorContext context) - { - if (writer == null) - { - throw new ArgumentNullException(nameof(writer)); - } - - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } - - var csharpCodeVisitor = base.CreateCSharpCodeVisitor(writer, context); - - csharpCodeVisitor.TagHelperRenderer.AttributeValueCodeRenderer = - new MvcTagHelperAttributeValueCodeRenderer(_tagHelperAttributeContext); - - return csharpCodeVisitor; - } - - protected override CSharpDesignTimeCodeVisitor CreateCSharpDesignTimeCodeVisitor( - CSharpCodeVisitor csharpCodeVisitor, - CSharpCodeWriter writer, - CodeGeneratorContext context) - { - if (csharpCodeVisitor == null) - { - throw new ArgumentNullException(nameof(csharpCodeVisitor)); - } - - if (writer == null) - { - throw new ArgumentNullException(nameof(writer)); - } - - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } - - return new MvcCSharpDesignTimeCodeVisitor(csharpCodeVisitor, writer, context); - } - - protected override void BuildConstructor(CSharpCodeWriter writer) - { - if (writer == null) - { - throw new ArgumentNullException(nameof(writer)); - } - - base.BuildConstructor(writer); - - writer.WriteLineHiddenDirective(); - - var injectVisitor = new InjectChunkVisitor(writer, Context, _injectAttribute); - injectVisitor.Accept(Context.ChunkTreeBuilder.Root.Children); - - writer.WriteLine(); - writer.WriteLineHiddenDirective(); - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcCSharpCodeVistor.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcCSharpCodeVistor.cs deleted file mode 100644 index ba652d81bc..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcCSharpCodeVistor.cs +++ /dev/null @@ -1,31 +0,0 @@ -// 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; -using Microsoft.AspNetCore.Razor.CodeGenerators; - -namespace Microsoft.AspNetCore.Mvc.Razor -{ - public abstract class MvcCSharpCodeVisitor : MvcCSharpChunkVisitor - { - public MvcCSharpCodeVisitor( - CSharpCodeWriter writer, - CodeGeneratorContext context) - : base(writer, context) - { - if (writer == null) - { - throw new ArgumentNullException(nameof(writer)); - } - - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } - } - - protected override void Visit(InjectChunk chunk) - { - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcCSharpDesignTimeCodeVisitor.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcCSharpDesignTimeCodeVisitor.cs deleted file mode 100644 index 87ae079445..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcCSharpDesignTimeCodeVisitor.cs +++ /dev/null @@ -1,70 +0,0 @@ -// 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.Diagnostics; -using Microsoft.AspNetCore.Razor.Chunks; -using Microsoft.AspNetCore.Razor.CodeGenerators; -using Microsoft.AspNetCore.Razor.CodeGenerators.Visitors; - -namespace Microsoft.AspNetCore.Mvc.Razor -{ - public class MvcCSharpDesignTimeCodeVisitor : CSharpDesignTimeCodeVisitor - { - private const string ModelVariable = "__modelHelper"; - private ModelChunk _modelChunk; - - public MvcCSharpDesignTimeCodeVisitor( - CSharpCodeVisitor csharpCodeVisitor, - CSharpCodeWriter writer, - CodeGeneratorContext context) - : base(csharpCodeVisitor, writer, context) - { - } - - protected override void AcceptTreeCore(ChunkTree tree) - { - base.AcceptTreeCore(tree); - - if (_modelChunk != null) - { - WriteModelChunkLineMapping(); - } - } - - public override void Accept(Chunk chunk) - { - if (chunk is ModelChunk) - { - Visit((ModelChunk)chunk); - } - - base.Accept(chunk); - } - - private void Visit(ModelChunk chunk) - { - Debug.Assert(chunk != null); - _modelChunk = chunk; - } - - private void WriteModelChunkLineMapping() - { - Debug.Assert(Context.Host.DesignTimeMode); - - using (var lineMappingWriter = - Writer.BuildLineMapping(_modelChunk.Start, _modelChunk.ModelType.Length, Context.SourceFile)) - { - // var __modelHelper = default(MyModel); - Writer.Write("var ") - .Write(ModelVariable) - .Write(" = default("); - - lineMappingWriter.MarkLineMappingStart(); - Writer.Write(_modelChunk.ModelType); - lineMappingWriter.MarkLineMappingEnd(); - - Writer.WriteLine(");"); - } - } - } -} diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcRazorCodeParser.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcRazorCodeParser.cs deleted file mode 100644 index 0c6272979a..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcRazorCodeParser.cs +++ /dev/null @@ -1,172 +0,0 @@ -// 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.Diagnostics; -using Microsoft.AspNetCore.Mvc.Razor.Host; -using Microsoft.AspNetCore.Razor; -using Microsoft.AspNetCore.Razor.Chunks.Generators; -using Microsoft.AspNetCore.Razor.Generator; -using Microsoft.AspNetCore.Razor.Parser; -using Microsoft.AspNetCore.Razor.Parser.SyntaxTree; -using Microsoft.AspNetCore.Razor.Tokenizer.Symbols; - -namespace Microsoft.AspNetCore.Mvc.Razor -{ - public class MvcRazorCodeParser : CSharpCodeParser - { - private const string ModelKeyword = "model"; - private const string InjectKeyword = "inject"; - private SourceLocation? _endInheritsLocation; - private bool _modelStatementFound; - - public MvcRazorCodeParser() - { - MapDirectives(ModelDirective, ModelKeyword); - MapDirectives(InjectDirective, InjectKeyword); - } - - protected override void InheritsDirective() - { - // Verify we're on the right keyword and accept - AssertDirective(SyntaxConstants.CSharp.InheritsKeyword); - AcceptAndMoveNext(); - _endInheritsLocation = CurrentLocation; - - InheritsDirectiveCore(); - CheckForInheritsAndModelStatements(); - } - - private void CheckForInheritsAndModelStatements() - { - if (_modelStatementFound && _endInheritsLocation.HasValue) - { - Context.OnError( - _endInheritsLocation.Value, - Resources.FormatMvcRazorCodeParser_CannotHaveModelAndInheritsKeyword(ModelKeyword), - SyntaxConstants.CSharp.InheritsKeyword.Length); - } - } - - protected virtual void ModelDirective() - { - // Verify we're on the right keyword and accept - AssertDirective(ModelKeyword); - var startModelLocation = CurrentLocation; - AcceptAndMoveNext(); - - - BaseTypeDirective(Resources.FormatMvcRazorCodeParser_KeywordMustBeFollowedByTypeName(ModelKeyword), - CreateModelChunkGenerator); - - if (_modelStatementFound) - { - Context.OnError( - startModelLocation, - Resources.FormatMvcRazorCodeParser_OnlyOneModelStatementIsAllowed(ModelKeyword), - ModelKeyword.Length); - } - - _modelStatementFound = true; - - CheckForInheritsAndModelStatements(); - } - - protected virtual void InjectDirective() - { - // @inject MyApp.MyService MyServicePropertyName - AssertDirective(InjectKeyword); - var startLocation = CurrentLocation; - AcceptAndMoveNext(); - - Context.CurrentBlock.Type = BlockType.Directive; - - // Accept whitespace - var remainingWhitespace = AcceptSingleWhiteSpaceCharacter(); - var keywordwithSingleWhitespaceLength = Span.GetContent().Value.Length; - if (Span.Symbols.Count > 1) - { - Span.EditHandler.AcceptedCharacters = AcceptedCharacters.None; - } - Output(SpanKind.MetaCode); - - if (remainingWhitespace != null) - { - Accept(remainingWhitespace); - } - var remainingWhitespaceLength = Span.GetContent().Value.Length; - - // Consume any other whitespace tokens. - AcceptWhile(IsSpacingToken(includeNewLines: false, includeComments: true)); - - var hasTypeError = !At(CSharpSymbolType.Identifier); - if (hasTypeError) - { - Context.OnError( - startLocation, - Resources.FormatMvcRazorCodeParser_KeywordMustBeFollowedByTypeName(InjectKeyword), - InjectKeyword.Length); - } - - // Accept 'MyApp.MyService' - NamespaceOrTypeName(); - - // typeName now contains the token 'MyApp.MyService' - var typeName = Span.GetContent().Value; - - AcceptWhile(IsSpacingToken(includeNewLines: false, includeComments: true)); - - if (!hasTypeError && (EndOfFile || At(CSharpSymbolType.NewLine))) - { - // Add an error for the property name only if we successfully read the type name - Context.OnError( - startLocation, - Resources.FormatMvcRazorCodeParser_InjectDirectivePropertyNameRequired(InjectKeyword), - keywordwithSingleWhitespaceLength + remainingWhitespaceLength + typeName.Length); - } - - // Read until end of line. Span now contains 'MyApp.MyService MyServiceName'. - AcceptUntil(CSharpSymbolType.NewLine); - if (!Context.DesignTimeMode) - { - // We want the newline to be treated as code, but it causes issues at design-time. - Optional(CSharpSymbolType.NewLine); - } - - // Parse out 'MyServicePropertyName' from the Span. - var propertyName = Span.GetContent() - .Value - .Substring(typeName.Length); - - // ';' is optional - propertyName = RemoveWhitespaceAndTrailingSemicolons(propertyName); - Span.ChunkGenerator = new InjectParameterGenerator(typeName.Trim(), propertyName); - - // Output the span and finish the block - CompleteBlock(); - Output(SpanKind.Code, AcceptedCharacters.AnyExceptNewline); - } - - private SpanChunkGenerator CreateModelChunkGenerator(string model) - { - return new ModelChunkGenerator(model); - } - - // Internal for unit testing - internal static string RemoveWhitespaceAndTrailingSemicolons(string value) - { - Debug.Assert(value != null); - value = value.TrimStart(); - - for (var index = value.Length - 1; index >= 0; index--) - { - var currentChar = value[index]; - if (!char.IsWhiteSpace(currentChar) && currentChar != ';') - { - return value.Substring(0, index + 1); - } - } - - return string.Empty; - } - } -} diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcRazorHost.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcRazorHost.cs deleted file mode 100644 index b897997138..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcRazorHost.cs +++ /dev/null @@ -1,355 +0,0 @@ -// 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; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using Microsoft.AspNetCore.Mvc.Razor.Directives; -using Microsoft.AspNetCore.Mvc.Razor.Internal; -using Microsoft.AspNetCore.Razor; -using Microsoft.AspNetCore.Razor.Chunks; -using Microsoft.AspNetCore.Razor.CodeGenerators; -using Microsoft.AspNetCore.Razor.Compilation.TagHelpers; -using Microsoft.AspNetCore.Razor.Parser; -using Microsoft.AspNetCore.Razor.Runtime.TagHelpers; -using Microsoft.AspNetCore.Razor.TagHelpers; -#if NET451 -using Microsoft.Extensions.FileProviders; -#endif - -namespace Microsoft.AspNetCore.Mvc.Razor -{ - public class MvcRazorHost : RazorEngineHost, IMvcRazorHost - { - private const string BaseType = "Microsoft.AspNetCore.Mvc.Razor.RazorPage"; - private const string HtmlHelperPropertyName = "Html"; - private const string ModelExpressionProviderProperty = "ModelExpressionProvider"; - private const string ViewDataProperty = "ViewData"; - - private static readonly string[] _defaultNamespaces = new[] - { - "System", - "System.Linq", - "System.Collections.Generic", - "Microsoft.AspNetCore.Mvc", - "Microsoft.AspNetCore.Mvc.Rendering", - "Microsoft.AspNetCore.Mvc.ViewFeatures", - }; - private static readonly Chunk[] _defaultInheritedChunks = new Chunk[] - { - new InjectChunk("Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper", HtmlHelperPropertyName), - new InjectChunk("Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper", "Json"), - new InjectChunk("Microsoft.AspNetCore.Mvc.IViewComponentHelper", "Component"), - new InjectChunk("Microsoft.AspNetCore.Mvc.IUrlHelper", "Url"), - new InjectChunk("Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider", ModelExpressionProviderProperty), - new AddTagHelperChunk - { - LookupText = "Microsoft.AspNetCore.Mvc.Razor.TagHelpers.UrlResolutionTagHelper, Microsoft.AspNetCore.Mvc.Razor" - }, - new SetBaseTypeChunk - { - // Microsoft.AspNetCore.Mvc.Razor.RazorPage - TypeName = $"{BaseType}<{ChunkHelper.TModelToken}>", - // Set the Start to Undefined to prevent Razor design time code generation from rendering a line mapping - // for this chunk. - Start = SourceLocation.Undefined - } - }; - - // CodeGenerationContext.DefaultBaseClass is set to MyBaseType. - private readonly IChunkTreeCache _chunkTreeCache; - private readonly RazorPathNormalizer _pathNormalizer; - private ChunkInheritanceUtility _chunkInheritanceUtility; - private ITagHelperDescriptorResolver _tagHelperDescriptorResolver; - - internal MvcRazorHost(IChunkTreeCache chunkTreeCache, RazorPathNormalizer pathNormalizer) - : base(new CSharpRazorCodeLanguage()) - { - _pathNormalizer = pathNormalizer; - _chunkTreeCache = chunkTreeCache; - - DefaultBaseClass = $"{BaseType}<{ChunkHelper.TModelToken}>"; - DefaultNamespace = "AspNetCore"; - // Enable instrumentation by default to allow precompiled views to work with BrowserLink. - EnableInstrumentation = true; - GeneratedClassContext = new GeneratedClassContext( - executeMethodName: "ExecuteAsync", - writeMethodName: "Write", - writeLiteralMethodName: "WriteLiteral", - writeToMethodName: "WriteTo", - writeLiteralToMethodName: "WriteLiteralTo", - templateTypeName: "Microsoft.AspNetCore.Mvc.Razor.HelperResult", - defineSectionMethodName: "DefineSection", - generatedTagHelperContext: new GeneratedTagHelperContext - { - ExecutionContextTypeName = typeof(TagHelperExecutionContext).FullName, - ExecutionContextAddMethodName = nameof(TagHelperExecutionContext.Add), - ExecutionContextAddTagHelperAttributeMethodName = - nameof(TagHelperExecutionContext.AddTagHelperAttribute), - ExecutionContextAddHtmlAttributeMethodName = nameof(TagHelperExecutionContext.AddHtmlAttribute), - ExecutionContextOutputPropertyName = nameof(TagHelperExecutionContext.Output), - - RunnerTypeName = typeof(TagHelperRunner).FullName, - RunnerRunAsyncMethodName = nameof(TagHelperRunner.RunAsync), - - ScopeManagerTypeName = typeof(TagHelperScopeManager).FullName, - ScopeManagerBeginMethodName = nameof(TagHelperScopeManager.Begin), - ScopeManagerEndMethodName = nameof(TagHelperScopeManager.End), - - TagHelperContentTypeName = typeof(TagHelperContent).FullName, - - // Can't use nameof because RazorPage is not accessible here. - CreateTagHelperMethodName = "CreateTagHelper", - FormatInvalidIndexerAssignmentMethodName = "InvalidTagHelperIndexerAssignment", - StartTagHelperWritingScopeMethodName = "StartTagHelperWritingScope", - EndTagHelperWritingScopeMethodName = "EndTagHelperWritingScope", - BeginWriteTagHelperAttributeMethodName = "BeginWriteTagHelperAttribute", - EndWriteTagHelperAttributeMethodName = "EndWriteTagHelperAttribute", - - // Can't use nameof because IHtmlHelper is (also) not accessible here. - MarkAsHtmlEncodedMethodName = HtmlHelperPropertyName + ".Raw", - BeginAddHtmlAttributeValuesMethodName = "BeginAddHtmlAttributeValues", - EndAddHtmlAttributeValuesMethodName = "EndAddHtmlAttributeValues", - AddHtmlAttributeValueMethodName = "AddHtmlAttributeValue", - HtmlEncoderPropertyName = "HtmlEncoder", - TagHelperContentGetContentMethodName = nameof(TagHelperContent.GetContent), - TagHelperOutputIsContentModifiedPropertyName = nameof(TagHelperOutput.IsContentModified), - TagHelperOutputContentPropertyName = nameof(TagHelperOutput.Content), - ExecutionContextSetOutputContentAsyncMethodName = nameof(TagHelperExecutionContext.SetOutputContentAsync), - TagHelperAttributeValuePropertyName = nameof(TagHelperAttribute.Value), - }) - { - BeginContextMethodName = "BeginContext", - EndContextMethodName = "EndContext" - }; - - foreach (var ns in _defaultNamespaces) - { - NamespaceImports.Add(ns); - } - } - -#if NET451 - /// - /// Initializes a new instance of with the specified . - /// - /// The path to the application base. - // Note: This constructor is used by tooling and is created once for each - // Razor page that is loaded. Consequently, each loaded page has its own copy of - // the ChunkTreeCache, but this ok - having a shared ChunkTreeCache per application in tooling - // is problematic to manage. - public MvcRazorHost(string root) - : this(new DefaultChunkTreeCache(new PhysicalFileProvider(root)), new DesignTimeRazorPathNormalizer(root)) - { - } -#endif - /// - /// Initializes a new instance of using the specified . - /// - /// An rooted at the application base path. - /// The used to resolve tag helpers on razor views. - public MvcRazorHost(IChunkTreeCache chunkTreeCache, ITagHelperDescriptorResolver resolver) - : this(chunkTreeCache, new RazorPathNormalizer()) - { - TagHelperDescriptorResolver = resolver; - } - - /// - public override ITagHelperDescriptorResolver TagHelperDescriptorResolver - { - get - { - // The initialization of the _tagHelperDescriptorResolver needs to be lazy to allow for the setting - // of DesignTimeMode. - if (_tagHelperDescriptorResolver == null) - { - _tagHelperDescriptorResolver = new TagHelperDescriptorResolver(DesignTimeMode); - } - - return _tagHelperDescriptorResolver; - } - set - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - _tagHelperDescriptorResolver = value; - } - } - - /// - /// Gets the model type used by default when no model is specified. - /// - /// This value is used as the generic type argument for the base type - public virtual string DefaultModel - { - get { return "dynamic"; } - } - - /// - /// Gets the list of chunks that are injected by default by this host. - /// - public virtual IReadOnlyList DefaultInheritedChunks - { - get { return _defaultInheritedChunks; } - } - - /// - /// Gets or sets the name attribute that is used to decorate properties that are injected and need to be - /// activated. - /// - public virtual string InjectAttribute - { - get { return "Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute"; } - } - - /// - /// Gets the type name used to represent model expression properties. - /// - public virtual string ModelExpressionType - { - get { return "Microsoft.AspNetCore.Mvc.ViewFeatures.ModelExpression"; } - } - - /// - /// Gets the method name used to create model expressions. - /// - public virtual string CreateModelExpressionMethod - { - get { return "CreateModelExpression"; } - } - - /// - /// Gets the property name for IModelExpressionProvider. - /// - public virtual string ModelExpressionProvider - { - get { return ModelExpressionProviderProperty; } - } - - /// - /// Gets the property name for ViewDataDictionary. - /// - public virtual string ViewDataPropertyName - { - get { return ViewDataProperty; } - } - - // Internal for testing - internal ChunkInheritanceUtility ChunkInheritanceUtility - { - get - { - if (_chunkInheritanceUtility == null) - { - // This needs to be lazily evaluated to support DefaultInheritedChunks being virtual. - _chunkInheritanceUtility = new ChunkInheritanceUtility(this, _chunkTreeCache, DefaultInheritedChunks); - } - - return _chunkInheritanceUtility; - } - set - { - _chunkInheritanceUtility = value; - } - } - - /// - /// Locates and parses _ViewImports.cshtml files applying to the given to - /// create s. - /// - /// The path to a Razor file to locate _ViewImports.cshtml for. - /// Inherited s. - public IReadOnlyList GetInheritedChunkTreeResults(string sourceFileName) - { - if (sourceFileName == null) - { - throw new ArgumentNullException(nameof(sourceFileName)); - } - - // Need the normalized path to resolve inherited chunks only. Full paths are needed for generated Razor - // files checksum and line pragmas to enable DesignTime debugging. - var normalizedPath = _pathNormalizer.NormalizePath(sourceFileName); - - return ChunkInheritanceUtility.GetInheritedChunkTreeResults(normalizedPath); - } - - /// - public GeneratorResults GenerateCode(string rootRelativePath, Stream inputStream) - { - var className = ParserHelpers.SanitizeClassName(rootRelativePath); - var engine = new RazorTemplateEngine(this); - return engine.GenerateCode(inputStream, className, DefaultNamespace, rootRelativePath); - } - - /// - public override RazorParser DecorateRazorParser(RazorParser razorParser, string sourceFileName) - { - if (razorParser == null) - { - throw new ArgumentNullException(nameof(razorParser)); - } - - var inheritedChunkTrees = GetInheritedChunkTrees(sourceFileName); - return new MvcRazorParser(razorParser, inheritedChunkTrees, DefaultInheritedChunks, ModelExpressionType); - } - - /// - public override ParserBase DecorateCodeParser(ParserBase incomingCodeParser) - { - if (incomingCodeParser == null) - { - throw new ArgumentNullException(nameof(incomingCodeParser)); - } - - return new MvcRazorCodeParser(); - } - - /// - public override CodeGenerator DecorateCodeGenerator( - CodeGenerator incomingGenerator, - CodeGeneratorContext context) - { - if (incomingGenerator == null) - { - throw new ArgumentNullException(nameof(incomingGenerator)); - } - - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } - - var inheritedChunkTrees = GetInheritedChunkTrees(context.SourceFile); - - ChunkInheritanceUtility.MergeInheritedChunkTrees( - context.ChunkTreeBuilder.Root, - inheritedChunkTrees, - DefaultModel); - - return new MvcCSharpCodeGenerator( - context, - DefaultModel, - InjectAttribute, - new GeneratedTagHelperAttributeContext - { - ModelExpressionTypeName = ModelExpressionType, - CreateModelExpressionMethodName = CreateModelExpressionMethod, - ModelExpressionProviderPropertyName = ModelExpressionProviderProperty, - ViewDataPropertyName = ViewDataProperty, - }); - } - - private IReadOnlyList GetInheritedChunkTrees(string sourceFileName) - { - var inheritedChunkTrees = GetInheritedChunkTreeResults(sourceFileName) - .Select(result => result.ChunkTree) - .ToList(); - - return inheritedChunkTrees; - } - } -} diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcRazorParser.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcRazorParser.cs deleted file mode 100644 index b0b0fa53b7..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcRazorParser.cs +++ /dev/null @@ -1,205 +0,0 @@ -// 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; -using System.Collections.Generic; -using System.Linq; -using Microsoft.AspNetCore.Mvc.Razor.Host; -using Microsoft.AspNetCore.Razor; -using Microsoft.AspNetCore.Razor.Chunks; -using Microsoft.AspNetCore.Razor.Compilation.TagHelpers; -using Microsoft.AspNetCore.Razor.Parser; -using Microsoft.AspNetCore.Razor.Parser.SyntaxTree; -using Microsoft.AspNetCore.Razor.Parser.TagHelpers; - -namespace Microsoft.AspNetCore.Mvc.Razor -{ - /// - /// A subtype of that uses to support inheritance of tag - /// helpers from _ViewImports files. - /// - public class MvcRazorParser : RazorParser - { - private readonly IEnumerable _viewImportsDirectiveDescriptors; - - /// - /// Initializes a new instance of . - /// - /// The to copy properties from. - /// The s that are inherited - /// from parsed pages from _ViewImports files. - /// The inherited by - /// default by all Razor pages in the application. - /// The full name of the model expression . - public MvcRazorParser( - RazorParser parser, - IReadOnlyList inheritedChunkTrees, - IReadOnlyList defaultInheritedChunks, - string modelExpressionTypeName) - : base(parser) - { - if (parser == null) - { - throw new ArgumentNullException(nameof(parser)); - } - - if (inheritedChunkTrees == null) - { - throw new ArgumentNullException(nameof(inheritedChunkTrees)); - } - - if (defaultInheritedChunks == null) - { - throw new ArgumentNullException(nameof(defaultInheritedChunks)); - } - - if (modelExpressionTypeName == null) - { - throw new ArgumentNullException(nameof(modelExpressionTypeName)); - } - - // Construct tag helper descriptors from @addTagHelper, @removeTagHelper and @tagHelperPrefix chunks - _viewImportsDirectiveDescriptors = GetTagHelperDirectiveDescriptors( - inheritedChunkTrees, - defaultInheritedChunks); - } - - /// - protected override IEnumerable GetTagHelperDescriptors( - Block documentRoot, - ErrorSink errorSink) - { - if (documentRoot == null) - { - throw new ArgumentNullException(nameof(documentRoot)); - } - - if (errorSink == null) - { - throw new ArgumentNullException(nameof(errorSink)); - } - - var visitor = new ViewImportsTagHelperDirectiveSpanVisitor( - TagHelperDescriptorResolver, - _viewImportsDirectiveDescriptors, - errorSink); - - return visitor.GetDescriptors(documentRoot); - } - - private static IEnumerable GetTagHelperDirectiveDescriptors( - IReadOnlyList inheritedChunkTrees, - IReadOnlyList defaultInheritedChunks) - { - var descriptors = new List(); - - var inheritedChunks = defaultInheritedChunks.Concat(inheritedChunkTrees.SelectMany(tree => tree.Children)); - foreach (var chunk in inheritedChunks) - { - // All TagHelperDirectiveDescriptors created here have undefined source locations because the source - // that created them is not in the same file. - var addTagHelperChunk = chunk as AddTagHelperChunk; - if (addTagHelperChunk != null) - { - var descriptor = new TagHelperDirectiveDescriptor - { - DirectiveText = addTagHelperChunk.LookupText, - Location = chunk.Start, - DirectiveType = TagHelperDirectiveType.AddTagHelper - }; - - descriptors.Add(descriptor); - - continue; - } - - var removeTagHelperChunk = chunk as RemoveTagHelperChunk; - if (removeTagHelperChunk != null) - { - var descriptor = new TagHelperDirectiveDescriptor - { - DirectiveText = removeTagHelperChunk.LookupText, - Location = chunk.Start, - DirectiveType = TagHelperDirectiveType.RemoveTagHelper - }; - - descriptors.Add(descriptor); - - continue; - } - - var tagHelperPrefixDirectiveChunk = chunk as TagHelperPrefixDirectiveChunk; - if (tagHelperPrefixDirectiveChunk != null) - { - var descriptor = new TagHelperDirectiveDescriptor - { - DirectiveText = tagHelperPrefixDirectiveChunk.Prefix, - Location = chunk.Start, - DirectiveType = TagHelperDirectiveType.TagHelperPrefix - }; - - descriptors.Add(descriptor); - } - } - - return descriptors; - } - - private class ViewImportsTagHelperDirectiveSpanVisitor : TagHelperDirectiveSpanVisitor - { - private readonly IEnumerable _viewImportsDirectiveDescriptors; - - public ViewImportsTagHelperDirectiveSpanVisitor( - ITagHelperDescriptorResolver descriptorResolver, - IEnumerable viewImportsDirectiveDescriptors, - ErrorSink errorSink) - : base(descriptorResolver, errorSink) - { - _viewImportsDirectiveDescriptors = viewImportsDirectiveDescriptors; - } - - protected override TagHelperDescriptorResolutionContext GetTagHelperDescriptorResolutionContext( - IEnumerable descriptors, - ErrorSink errorSink) - { - var directivesToImport = MergeDirectiveDescriptors(descriptors, _viewImportsDirectiveDescriptors); - - return base.GetTagHelperDescriptorResolutionContext(directivesToImport, errorSink); - } - - private static IEnumerable MergeDirectiveDescriptors( - IEnumerable descriptors, - IEnumerable inheritedDescriptors) - { - var mergedDescriptors = new List(); - TagHelperDirectiveDescriptor prefixDirectiveDescriptor = null; - - foreach (var descriptor in inheritedDescriptors) - { - if (descriptor.DirectiveType == TagHelperDirectiveType.TagHelperPrefix) - { - // Always take the latest @tagHelperPrefix descriptor. Can only have 1 per page. - prefixDirectiveDescriptor = descriptor; - } - else - { - mergedDescriptors.Add(descriptor); - } - } - - // We need to see if the provided descriptors contain a @tagHelperPrefix directive. If so, it - // takes precedence and overrides any provided by the inheritedDescriptors. If not we need to add the - // inherited @tagHelperPrefix directive back into the merged list. - if (prefixDirectiveDescriptor != null && - !descriptors.Any(descriptor => descriptor.DirectiveType == TagHelperDirectiveType.TagHelperPrefix)) - { - mergedDescriptors.Add(prefixDirectiveDescriptor); - } - - mergedDescriptors.AddRange(descriptors); - - return mergedDescriptors; - } - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcTagHelperAttributeValueCodeRenderer.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcTagHelperAttributeValueCodeRenderer.cs deleted file mode 100644 index b76f78a8d2..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcTagHelperAttributeValueCodeRenderer.cs +++ /dev/null @@ -1,94 +0,0 @@ -// 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; -using Microsoft.AspNetCore.Razor.CodeGenerators; -using Microsoft.AspNetCore.Razor.Compilation.TagHelpers; - -namespace Microsoft.AspNetCore.Mvc.Razor -{ - /// - public class MvcTagHelperAttributeValueCodeRenderer : TagHelperAttributeValueCodeRenderer - { - private const string ModelLambdaVariableName = "__model"; - - private readonly GeneratedTagHelperAttributeContext _context; - - /// - /// Instantiates a new instance of . - /// - /// Contains code generation information for rendering attribute values. - public MvcTagHelperAttributeValueCodeRenderer(GeneratedTagHelperAttributeContext context) - { - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } - - _context = context; - } - - /// - /// If the attribute being rendered is of the type - /// , then a model expression will be - /// created by calling into . - /// - public override void RenderAttributeValue( - TagHelperAttributeDescriptor attributeDescriptor, - CSharpCodeWriter writer, - CodeGeneratorContext codeGeneratorContext, - Action renderAttributeValue, - bool complexValue) - { - if (attributeDescriptor == null) - { - throw new ArgumentNullException(nameof(attributeDescriptor)); - } - - if (writer == null) - { - throw new ArgumentNullException(nameof(writer)); - } - - if (codeGeneratorContext == null) - { - throw new ArgumentNullException(nameof(codeGeneratorContext)); - } - - if (renderAttributeValue == null) - { - throw new ArgumentNullException(nameof(renderAttributeValue)); - } - - if (attributeDescriptor.TypeName.Equals(_context.ModelExpressionTypeName, StringComparison.Ordinal)) - { - writer - .WriteStartInstanceMethodInvocation(_context.ModelExpressionProviderPropertyName, _context.CreateModelExpressionMethodName) - .Write(_context.ViewDataPropertyName) - .WriteParameterSeparator() - .Write(ModelLambdaVariableName) - .Write(" => "); - if (!complexValue) - { - writer - .Write(ModelLambdaVariableName) - .Write("."); - - } - - renderAttributeValue(writer); - - writer.WriteEndMethodInvocation(endLine: false); - } - else - { - base.RenderAttributeValue( - attributeDescriptor, - writer, - codeGeneratorContext, - renderAttributeValue, - complexValue); - } - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcViewDocumentClassifierPass.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcViewDocumentClassifierPass.cs new file mode 100644 index 0000000000..f1fdfde546 --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcViewDocumentClassifierPass.cs @@ -0,0 +1,262 @@ +// 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; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using Microsoft.AspNetCore.Razor.Evolution; +using Microsoft.AspNetCore.Razor.Evolution.Intermediate; + +namespace Microsoft.AspNetCore.Mvc.Razor.Host +{ + public class MvcViewDocumentClassifierPass : IRazorIRPass + { + public static readonly string Kind = "mvc.1.0.view"; + + public RazorEngine Engine { get; set; } + + // We want to run before the default, but after others since this is the MVC default. + public virtual int Order => RazorIRPass.DefaultDocumentClassifierOrder - 1; + + public static string DocumentKind = "default"; + + public DocumentIRNode Execute(RazorCodeDocument codeDocument, DocumentIRNode irDocument) + { + if (irDocument.DocumentKind != null) + { + return irDocument; + } + + irDocument.DocumentKind = DocumentKind; + + // Rewrite a use default namespace and class declaration. + var children = new List(irDocument.Children); + irDocument.Children.Clear(); + + var @namespace = new NamespaceDeclarationIRNode() + { + Content = "AspNetCore", + }; + + var @class = new ClassDeclarationIRNode() + { + AccessModifier = "public", + Name = GetClassName(codeDocument.Source.Filename) ?? "GeneratedClass", + BaseType = "Microsoft.AspNetCore.Mvc.Razor.RazorPage" + }; + + var method = new RazorMethodDeclarationIRNode() + { + AccessModifier = "public", + Modifiers = new List() { "async", "override" }, + Name = "ExecuteAsync", + ReturnType = "Task", + }; + + var documentBuilder = RazorIRBuilder.Create(irDocument); + + var namespaceBuilder = RazorIRBuilder.Create(documentBuilder.Current); + namespaceBuilder.Push(@namespace); + + var classBuilder = RazorIRBuilder.Create(namespaceBuilder.Current); + classBuilder.Push(@class); + + var methodBuilder = RazorIRBuilder.Create(classBuilder.Current); + methodBuilder.Push(method); + + var visitor = new Visitor(documentBuilder, namespaceBuilder, classBuilder, methodBuilder); + + for (var i = 0; i < children.Count; i++) + { + visitor.Visit(children[i]); + } + + return irDocument; + } + + private static string GetClassName(string filename) + { + if (filename == null) + { + return null; + } + + return ParserHelpers.SanitizeClassName("Generated_" + Path.GetFileNameWithoutExtension(filename)); + } + + private static class ParserHelpers + { + public static bool IsNewLine(char value) + { + return value == '\r' // Carriage return + || value == '\n' // Linefeed + || value == '\u0085' // Next Line + || value == '\u2028' // Line separator + || value == '\u2029'; // Paragraph separator + } + + public static bool IsNewLine(string value) + { + return (value.Length == 1 && (IsNewLine(value[0]))) || + (string.Equals(value, Environment.NewLine, StringComparison.Ordinal)); + } + + // Returns true if the character is Whitespace and NOT a newline + public static bool IsWhitespace(char value) + { + return value == ' ' || + value == '\f' || + value == '\t' || + value == '\u000B' || // Vertical Tab + CharUnicodeInfo.GetUnicodeCategory(value) == UnicodeCategory.SpaceSeparator; + } + + public static bool IsWhitespaceOrNewLine(char value) + { + return IsWhitespace(value) || IsNewLine(value); + } + + public static bool IsIdentifier(string value) + { + return IsIdentifier(value, requireIdentifierStart: true); + } + + public static bool IsIdentifier(string value, bool requireIdentifierStart) + { + IEnumerable identifierPart = value; + if (requireIdentifierStart) + { + identifierPart = identifierPart.Skip(1); + } + return (!requireIdentifierStart || IsIdentifierStart(value[0])) && identifierPart.All(IsIdentifierPart); + } + + public static bool IsHexDigit(char value) + { + return (value >= '0' && value <= '9') || (value >= 'A' && value <= 'F') || (value >= 'a' && value <= 'f'); + } + + public static bool IsIdentifierStart(char value) + { + return value == '_' || IsLetter(value); + } + + public static bool IsIdentifierPart(char value) + { + return IsLetter(value) + || IsDecimalDigit(value) + || IsConnecting(value) + || IsCombining(value) + || IsFormatting(value); + } + + public static bool IsTerminatingCharToken(char value) + { + return IsNewLine(value) || value == '\''; + } + + public static bool IsTerminatingQuotedStringToken(char value) + { + return IsNewLine(value) || value == '"'; + } + + public static bool IsDecimalDigit(char value) + { + return CharUnicodeInfo.GetUnicodeCategory(value) == UnicodeCategory.DecimalDigitNumber; + } + + public static bool IsLetterOrDecimalDigit(char value) + { + return IsLetter(value) || IsDecimalDigit(value); + } + + public static bool IsLetter(char value) + { + var cat = CharUnicodeInfo.GetUnicodeCategory(value); + + return cat == UnicodeCategory.UppercaseLetter + || cat == UnicodeCategory.LowercaseLetter + || cat == UnicodeCategory.TitlecaseLetter + || cat == UnicodeCategory.ModifierLetter + || cat == UnicodeCategory.OtherLetter + || cat == UnicodeCategory.LetterNumber; + } + + public static bool IsFormatting(char value) + { + return CharUnicodeInfo.GetUnicodeCategory(value) == UnicodeCategory.Format; + } + + public static bool IsCombining(char value) + { + UnicodeCategory cat = CharUnicodeInfo.GetUnicodeCategory(value); + + return cat == UnicodeCategory.SpacingCombiningMark || cat == UnicodeCategory.NonSpacingMark; + + } + + public static bool IsConnecting(char value) + { + return CharUnicodeInfo.GetUnicodeCategory(value) == UnicodeCategory.ConnectorPunctuation; + } + + public static string SanitizeClassName(string inputName) + { + if (!IsIdentifierStart(inputName[0]) && IsIdentifierPart(inputName[0])) + { + inputName = "_" + inputName; + } + + return new String((from value in inputName + select IsIdentifierPart(value) ? value : '_') + .ToArray()); + } + + public static bool IsEmailPart(char character) + { + // Source: http://tools.ietf.org/html/rfc5322#section-3.4.1 + // We restrict the allowed characters to alpha-numerics and '_' in order to ensure we cover most of the cases where an + // email address is intended without restricting the usage of code within JavaScript, CSS, and other contexts. + return Char.IsLetter(character) || Char.IsDigit(character) || character == '_'; + } + } + + private class Visitor : RazorIRNodeVisitor + { + private readonly RazorIRBuilder _document; + private readonly RazorIRBuilder _namespace; + private readonly RazorIRBuilder _class; + private readonly RazorIRBuilder _method; + + public Visitor(RazorIRBuilder document, RazorIRBuilder @namespace, RazorIRBuilder @class, RazorIRBuilder method) + { + _document = document; + _namespace = @namespace; + _class = @class; + _method = method; + } + + public override void VisitChecksum(ChecksumIRNode node) + { + _document.Insert(0, node); + } + + public override void VisitUsingStatement(UsingStatementIRNode node) + { + _namespace.AddAfter(node); + } + + public override void VisitDeclareTagHelperFields(DeclareTagHelperFieldsIRNode node) + { + _class.Insert(0, node); + } + + public override void VisitDefault(RazorIRNode node) + { + _method.Add(node); + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Host/ViewComponentTagHelperDescriptorConventions.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Host/ViewComponentTagHelperDescriptorConventions.cs index 36f42c9e01..5e7c24ccf7 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Host/ViewComponentTagHelperDescriptorConventions.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor.Host/ViewComponentTagHelperDescriptorConventions.cs @@ -1,7 +1,7 @@ // 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 Microsoft.AspNetCore.Razor.Compilation.TagHelpers; +using Microsoft.AspNetCore.Razor.Evolution; namespace Microsoft.AspNetCore.Mvc.Razor.Host { diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Host/ViewComponentTagHelperPass.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Host/ViewComponentTagHelperPass.cs new file mode 100644 index 0000000000..5458ac086b --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.Razor.Host/ViewComponentTagHelperPass.cs @@ -0,0 +1,282 @@ +// 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; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.Evolution; +using Microsoft.AspNetCore.Razor.Evolution.Intermediate; +using Microsoft.AspNetCore.Razor.Evolution.Legacy; + +namespace Microsoft.AspNetCore.Mvc.Razor.Host +{ + public class ViewComponentTagHelperPass : IRazorIRPass + { + public RazorEngine Engine { get; set; } + + public int Order => RazorIRPass.LoweringOrder; + + public DocumentIRNode Execute(RazorCodeDocument codeDocument, DocumentIRNode irDocument) + { + var visitor = new Visitor(); + visitor.Visit(irDocument); + + if (visitor.Class == null || visitor.TagHelpers.Count == 0) + { + // Nothing to do, bail. + return irDocument; + } + + foreach (var tagHelper in visitor.TagHelpers) + { + GenerateVCTHClass(visitor.Class, tagHelper.Value); + + if (visitor.Fields.UsedTagHelperTypeNames.Remove(tagHelper.Value.TypeName)) + { + visitor.Fields.UsedTagHelperTypeNames.Add(GetVCTHFullName(visitor.Namespace, visitor.Class, tagHelper.Value)); + } + } + + foreach (var createNode in visitor.CreateTagHelpers) + { + RewriteCreateNode(visitor.Namespace, visitor.Class, createNode); + } + + return irDocument; + } + + private void GenerateVCTHClass(ClassDeclarationIRNode @class, TagHelperDescriptor tagHelper) + { + var writer = new CSharpCodeWriter(); + WriteClass(writer, tagHelper); + + @class.Children.Add(new CSharpStatementIRNode() + { + Content = writer.Builder.ToString(), + Parent = @class, + }); + } + + private void RewriteCreateNode( + NamespaceDeclarationIRNode @namespace, + ClassDeclarationIRNode @class, + CreateTagHelperIRNode node) + { + var originalTypeName = node.TagHelperTypeName; + + var newTypeName = GetVCTHFullName(@namespace, @class, node.Descriptor); + for (var i = 0; i < node.Parent.Children.Count; i++) + { + var setProperty = node.Parent.Children[i] as SetTagHelperPropertyIRNode; + if (setProperty != null) + { + setProperty.TagHelperTypeName = newTypeName; + } + } + + node.TagHelperTypeName = newTypeName; + } + + private static string GetVCTHFullName( + NamespaceDeclarationIRNode @namespace, + ClassDeclarationIRNode @class, + TagHelperDescriptor tagHelper) + { + var vcName = tagHelper.PropertyBag[ViewComponentTagHelperDescriptorConventions.ViewComponentNameKey]; + return $"{@namespace.Content}.{@class.Name}.__Generated__{vcName}ViewComponentTagHelper"; + } + + private static string GetVCTHClassName( + TagHelperDescriptor tagHelper) + { + var vcName = tagHelper.PropertyBag[ViewComponentTagHelperDescriptorConventions.ViewComponentNameKey]; + return $"__Generated__{vcName}ViewComponentTagHelper"; + } + + private void WriteClass(CSharpCodeWriter writer, TagHelperDescriptor descriptor) + { + // Add target element. + BuildTargetElementString(writer, descriptor); + + // Initialize declaration. + var tagHelperTypeName = "Microsoft.AspNetCore.Razor.TagHelpers.TagHelper"; + var className = GetVCTHClassName(descriptor); + + using (writer.BuildClassDeclaration("public", className, new[] { tagHelperTypeName })) + { + // Add view component helper. + writer.WriteVariableDeclaration( + $"private readonly global::Microsoft.AspNetCore.Mvc.IViewComponentHelper", + "_helper", + value: null); + + // Add constructor. + BuildConstructorString(writer, className); + + // Add attributes. + BuildAttributeDeclarations(writer, descriptor); + + // Add process method. + BuildProcessMethodString(writer, descriptor); + } + } + + private void BuildConstructorString(CSharpCodeWriter writer, string className) + { + var helperPair = new KeyValuePair( + $"global::Microsoft.AspNetCore.Mvc.IViewComponentHelper", + "helper"); + + using (writer.BuildConstructor("public", className, new[] { helperPair })) + { + writer.WriteStartAssignment("_helper") + .Write("helper") + .WriteLine(";"); + } + } + + private void BuildAttributeDeclarations(CSharpCodeWriter writer, TagHelperDescriptor descriptor) + { + writer.Write("[") + .Write("Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeNotBoundAttribute") + .WriteParameterSeparator() + .Write($"global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewContextAttribute") + .WriteLine("]"); + + writer.WriteAutoPropertyDeclaration( + "public", + $"global::Microsoft.AspNetCore.Mvc.Rendering.ViewContext", + "_context"); + + var indexerAttributes = descriptor.Attributes.Where(a => a.IsIndexer); + + foreach (var attribute in descriptor.Attributes) + { + if (attribute.IsIndexer) + { + continue; + } + + writer.WriteAutoPropertyDeclaration("public", attribute.TypeName, attribute.PropertyName); + + if (indexerAttributes.Any(a => string.Equals(a.PropertyName, attribute.PropertyName, StringComparison.Ordinal))) + { + writer.Write(" = ") + .WriteStartNewObject(attribute.TypeName) + .WriteEndMethodInvocation(); + } + } + } + + private void BuildProcessMethodString(CSharpCodeWriter writer, TagHelperDescriptor descriptor) + { + var contextVariable = "context"; + var outputVariable = "output"; + + using (writer.BuildMethodDeclaration( + $"public override async", + $"global::{typeof(Task).FullName}", + "ProcessAsync", + new Dictionary() + { + { "Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext", contextVariable }, + { "Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput", outputVariable } + })) + { + writer.WriteInstanceMethodInvocation( + $"(_helper as global::Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware)?", + "Contextualize", + new[] { "_context" }); + + var methodParameters = GetMethodParameters(descriptor); + var viewContentVariable = "viewContent"; + writer.Write("var ") + .WriteStartAssignment(viewContentVariable) + .WriteInstanceMethodInvocation($"await _helper", "InvokeAsync", methodParameters); + writer.WriteStartAssignment($"{outputVariable}.TagName") + .WriteLine("null;"); + writer.WriteInstanceMethodInvocation( + $"{outputVariable}.Content", + "SetHtmlContent", + new[] { viewContentVariable }); + } + } + + private string[] GetMethodParameters(TagHelperDescriptor descriptor) + { + var propertyNames = descriptor.Attributes.Where(a => !a.IsIndexer).Select(attribute => attribute.PropertyName); + var joinedPropertyNames = string.Join(", ", propertyNames); + var parametersString = $" new {{ { joinedPropertyNames } }}"; + + var viewComponentName = descriptor.PropertyBag[ + ViewComponentTagHelperDescriptorConventions.ViewComponentNameKey]; + var methodParameters = new[] { $"\"{viewComponentName}\"", parametersString }; + return methodParameters; + } + + private void BuildTargetElementString(CSharpCodeWriter writer, TagHelperDescriptor descriptor) + { + writer.Write("[") + .WriteStartMethodInvocation("Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute") + .WriteStringLiteral(descriptor.FullTagName) + .WriteLine(")]"); + } + + private class Visitor : RazorIRNodeWalker + { + public ClassDeclarationIRNode Class { get; private set; } + + public DeclareTagHelperFieldsIRNode Fields { get; private set; } + + public NamespaceDeclarationIRNode Namespace { get; private set; } + + public List CreateTagHelpers { get; } = new List(); + + public Dictionary TagHelpers { get; } = new Dictionary(); + + public override void VisitCreateTagHelper(CreateTagHelperIRNode node) + { + var tagHelper = node.Descriptor; + if (ViewComponentTagHelperDescriptorConventions.IsViewComponentDescriptor(tagHelper)) + { + // Capture all the VCTagHelpers (unique by type name) so we can generate a class for each one. + var vcName = tagHelper.PropertyBag[ViewComponentTagHelperDescriptorConventions.ViewComponentNameKey]; + TagHelpers[vcName] = tagHelper; + + CreateTagHelpers.Add(node); + } + } + + public override void VisitNamespace(NamespaceDeclarationIRNode node) + { + if (Namespace == null) + { + Namespace = node; + } + + base.VisitNamespace(node); + } + + public override void VisitClass(ClassDeclarationIRNode node) + { + if (Class == null) + { + Class = node; + } + + base.VisitClass(node); + } + + public override void VisitDeclareTagHelperFields(DeclareTagHelperFieldsIRNode node) + { + if (Fields == null) + { + Fields = node; + } + + base.VisitDeclareTagHelperFields(node); + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Host/exceptions.net45.json b/src/Microsoft.AspNetCore.Mvc.Razor.Host/exceptions.net45.json new file mode 100644 index 0000000000..ae2b509a14 --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.Razor.Host/exceptions.net45.json @@ -0,0 +1,94 @@ +[ + { + "OldTypeId": "public interface Microsoft.AspNetCore.Mvc.Razor.IMvcRazorHost", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Mvc.Razor.ModelChunk : Microsoft.AspNetCore.Razor.Chunks.Chunk", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Razor.Generator.ModelChunkGenerator : Microsoft.AspNetCore.Razor.Chunks.Generators.SpanChunkGenerator", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Mvc.Razor.InjectChunk : Microsoft.AspNetCore.Razor.Chunks.Chunk", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Mvc.Razor.InjectChunkVisitor : Microsoft.AspNetCore.Mvc.Razor.MvcCSharpCodeVisitor", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Mvc.Razor.InjectParameterGenerator : Microsoft.AspNetCore.Razor.Chunks.Generators.SpanChunkGenerator", + "Kind": "Removal" + }, + { + "OldTypeId": "public abstract class Microsoft.AspNetCore.Mvc.Razor.MvcCSharpChunkVisitor : Microsoft.AspNetCore.Razor.CodeGenerators.Visitors.CodeVisitor", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Mvc.Razor.MvcCSharpCodeGenerator : Microsoft.AspNetCore.Razor.CodeGenerators.CSharpCodeGenerator", + "Kind": "Removal" + }, + { + "OldTypeId": "public abstract class Microsoft.AspNetCore.Mvc.Razor.MvcCSharpCodeVisitor : Microsoft.AspNetCore.Mvc.Razor.MvcCSharpChunkVisitor", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Mvc.Razor.MvcCSharpDesignTimeCodeVisitor : Microsoft.AspNetCore.Razor.CodeGenerators.Visitors.CSharpDesignTimeCodeVisitor", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Mvc.Razor.MvcRazorCodeParser : Microsoft.AspNetCore.Razor.Parser.CSharpCodeParser", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Mvc.Razor.MvcRazorParser : Microsoft.AspNetCore.Razor.Parser.RazorParser", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Mvc.Razor.MvcRazorHost : Microsoft.AspNetCore.Razor.RazorEngineHost, Microsoft.AspNetCore.Mvc.Razor.IMvcRazorHost", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Mvc.Razor.MvcTagHelperAttributeValueCodeRenderer : Microsoft.AspNetCore.Razor.CodeGenerators.TagHelperAttributeValueCodeRenderer", + "Kind": "Removal" + }, + { + "OldTypeId": "public static class Microsoft.AspNetCore.Mvc.Razor.Directives.ChunkHelper", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Mvc.Razor.Directives.ChunkInheritanceUtility", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Mvc.Razor.Directives.ChunkTreeResult", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Mvc.Razor.Directives.DefaultChunkTreeCache : Microsoft.AspNetCore.Mvc.Razor.Directives.IChunkTreeCache", + "Kind": "Removal" + }, + { + "OldTypeId": "public interface Microsoft.AspNetCore.Mvc.Razor.Directives.IChunkMerger", + "Kind": "Removal" + }, + { + "OldTypeId": "public interface Microsoft.AspNetCore.Mvc.Razor.Directives.IChunkTreeCache : System.IDisposable", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Mvc.Razor.Directives.InjectChunkMerger : Microsoft.AspNetCore.Mvc.Razor.Directives.IChunkMerger", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Mvc.Razor.Directives.SetBaseTypeChunkMerger : Microsoft.AspNetCore.Mvc.Razor.Directives.IChunkMerger", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Mvc.Razor.Directives.UsingChunkMerger : Microsoft.AspNetCore.Mvc.Razor.Directives.IChunkMerger", + "Kind": "Removal" + } +] \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Host/exceptions.netcore.json b/src/Microsoft.AspNetCore.Mvc.Razor.Host/exceptions.netcore.json new file mode 100644 index 0000000000..ae2b509a14 --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.Razor.Host/exceptions.netcore.json @@ -0,0 +1,94 @@ +[ + { + "OldTypeId": "public interface Microsoft.AspNetCore.Mvc.Razor.IMvcRazorHost", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Mvc.Razor.ModelChunk : Microsoft.AspNetCore.Razor.Chunks.Chunk", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Razor.Generator.ModelChunkGenerator : Microsoft.AspNetCore.Razor.Chunks.Generators.SpanChunkGenerator", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Mvc.Razor.InjectChunk : Microsoft.AspNetCore.Razor.Chunks.Chunk", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Mvc.Razor.InjectChunkVisitor : Microsoft.AspNetCore.Mvc.Razor.MvcCSharpCodeVisitor", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Mvc.Razor.InjectParameterGenerator : Microsoft.AspNetCore.Razor.Chunks.Generators.SpanChunkGenerator", + "Kind": "Removal" + }, + { + "OldTypeId": "public abstract class Microsoft.AspNetCore.Mvc.Razor.MvcCSharpChunkVisitor : Microsoft.AspNetCore.Razor.CodeGenerators.Visitors.CodeVisitor", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Mvc.Razor.MvcCSharpCodeGenerator : Microsoft.AspNetCore.Razor.CodeGenerators.CSharpCodeGenerator", + "Kind": "Removal" + }, + { + "OldTypeId": "public abstract class Microsoft.AspNetCore.Mvc.Razor.MvcCSharpCodeVisitor : Microsoft.AspNetCore.Mvc.Razor.MvcCSharpChunkVisitor", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Mvc.Razor.MvcCSharpDesignTimeCodeVisitor : Microsoft.AspNetCore.Razor.CodeGenerators.Visitors.CSharpDesignTimeCodeVisitor", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Mvc.Razor.MvcRazorCodeParser : Microsoft.AspNetCore.Razor.Parser.CSharpCodeParser", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Mvc.Razor.MvcRazorParser : Microsoft.AspNetCore.Razor.Parser.RazorParser", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Mvc.Razor.MvcRazorHost : Microsoft.AspNetCore.Razor.RazorEngineHost, Microsoft.AspNetCore.Mvc.Razor.IMvcRazorHost", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Mvc.Razor.MvcTagHelperAttributeValueCodeRenderer : Microsoft.AspNetCore.Razor.CodeGenerators.TagHelperAttributeValueCodeRenderer", + "Kind": "Removal" + }, + { + "OldTypeId": "public static class Microsoft.AspNetCore.Mvc.Razor.Directives.ChunkHelper", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Mvc.Razor.Directives.ChunkInheritanceUtility", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Mvc.Razor.Directives.ChunkTreeResult", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Mvc.Razor.Directives.DefaultChunkTreeCache : Microsoft.AspNetCore.Mvc.Razor.Directives.IChunkTreeCache", + "Kind": "Removal" + }, + { + "OldTypeId": "public interface Microsoft.AspNetCore.Mvc.Razor.Directives.IChunkMerger", + "Kind": "Removal" + }, + { + "OldTypeId": "public interface Microsoft.AspNetCore.Mvc.Razor.Directives.IChunkTreeCache : System.IDisposable", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Mvc.Razor.Directives.InjectChunkMerger : Microsoft.AspNetCore.Mvc.Razor.Directives.IChunkMerger", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Mvc.Razor.Directives.SetBaseTypeChunkMerger : Microsoft.AspNetCore.Mvc.Razor.Directives.IChunkMerger", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Mvc.Razor.Directives.UsingChunkMerger : Microsoft.AspNetCore.Mvc.Razor.Directives.IChunkMerger", + "Kind": "Removal" + } +] \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Host/project.json b/src/Microsoft.AspNetCore.Mvc.Razor.Host/project.json index c95bc2a02d..002da1aa9d 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Host/project.json +++ b/src/Microsoft.AspNetCore.Mvc.Razor.Host/project.json @@ -22,7 +22,7 @@ "xmlDoc": true }, "dependencies": { - "Microsoft.AspNetCore.Razor.Runtime": "1.2.0-*", + "Microsoft.AspNetCore.Razor.Evolution": "1.2.0-*", "Microsoft.Extensions.Caching.Memory": "1.2.0-*", "Microsoft.Extensions.FileProviders.Physical": "1.2.0-*", "Microsoft.Extensions.PropertyHelper.Sources": { diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/Compilation/ICompilationService.cs b/src/Microsoft.AspNetCore.Mvc.Razor/Compilation/ICompilationService.cs index c0cf33dcca..62652ae7e4 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor/Compilation/ICompilationService.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor/Compilation/ICompilationService.cs @@ -1,6 +1,8 @@ // 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 Microsoft.AspNetCore.Razor.Evolution; + namespace Microsoft.AspNetCore.Mvc.Razor.Compilation { /// @@ -9,13 +11,17 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Compilation public interface ICompilationService { /// - /// Compiles content and returns the result of compilation. + /// Compiles a and returns the result of compilation. /// - /// The for the Razor file that was compiled. - /// The generated C# content to be compiled. + /// + /// The that contains the sources for the compilation. + /// + /// + /// The to compile. + /// /// /// A representing the result of compilation. /// - CompilationResult Compile(RelativeFileInfo fileInfo, string compilationContent); + CompilationResult Compile(RazorCodeDocument codeDocument, RazorCSharpDocument cSharpDocument); } } diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/DependencyInjection/MvcRazorMvcCoreBuilderExtensions.cs b/src/Microsoft.AspNetCore.Mvc.Razor/DependencyInjection/MvcRazorMvcCoreBuilderExtensions.cs index 2d171b4cf6..72d8b556f5 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor/DependencyInjection/MvcRazorMvcCoreBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor/DependencyInjection/MvcRazorMvcCoreBuilderExtensions.cs @@ -6,11 +6,12 @@ using System.Linq; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Razor; using Microsoft.AspNetCore.Mvc.Razor.Compilation; -using Microsoft.AspNetCore.Mvc.Razor.Directives; +using Microsoft.AspNetCore.Mvc.Razor.Host; using Microsoft.AspNetCore.Mvc.Razor.Internal; using Microsoft.AspNetCore.Mvc.Razor.TagHelpers; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Razor.Compilation.TagHelpers; +using Microsoft.AspNetCore.Razor.Evolution; using Microsoft.AspNetCore.Razor.Runtime.TagHelpers; using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.Extensions.Caching.Memory; @@ -157,12 +158,6 @@ namespace Microsoft.Extensions.DependencyInjection services.TryAddSingleton(); - services.TryAdd(ServiceDescriptor.Singleton(serviceProvider => - { - var accessor = serviceProvider.GetRequiredService(); - return new DefaultChunkTreeCache(accessor.FileProvider); - })); - services.TryAddSingleton(); services.TryAddSingleton(s => new TagHelperDescriptorFactory(designTime: false)); services.TryAddSingleton(); @@ -176,7 +171,32 @@ namespace Microsoft.Extensions.DependencyInjection // creating the singleton RazorViewEngine instance. services.TryAddTransient(); services.TryAddTransient(); - services.TryAddTransient(); + + services.TryAddSingleton(s => + { + return new DefaultRazorProject(s.GetRequiredService().FileProvider); + }); + + services.TryAddSingleton(s => + { + return RazorEngine.Create(b => + { + InjectDirective.Register(b); + ModelDirective.Register(b); + + b.Features.Add(new ModelExpressionPass()); + b.Features.Add(new ViewComponentTagHelperPass()); + b.Features.Add(new MvcViewDocumentClassifierPass()); + + b.Features.Add(new Microsoft.CodeAnalysis.Razor.DefaultTagHelperFeature()); + + var referenceManager = s.GetRequiredService(); + b.Features.Add(new Microsoft.CodeAnalysis.Razor.DefaultMetadataReferenceFeature() + { + References = referenceManager.CompilationReferences.ToArray(), + }); + }); + }); // This caches Razor page activation details that are valid for the lifetime of the application. services.TryAddSingleton(); diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/DefaultRazorProject.cs b/src/Microsoft.AspNetCore.Mvc.Razor/Internal/DefaultRazorProject.cs similarity index 97% rename from src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/DefaultRazorProject.cs rename to src/Microsoft.AspNetCore.Mvc.Razor/Internal/DefaultRazorProject.cs index 06c6347bf5..b8429759ca 100644 --- a/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/DefaultRazorProject.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor/Internal/DefaultRazorProject.cs @@ -7,7 +7,7 @@ using System.IO; using Microsoft.AspNetCore.Razor.Evolution; using Microsoft.Extensions.FileProviders; -namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal +namespace Microsoft.AspNetCore.Mvc.Razor.Internal { public class DefaultRazorProject : RazorProject { diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/DefaultRazorProjectItem.cs b/src/Microsoft.AspNetCore.Mvc.Razor/Internal/DefaultRazorProjectItem.cs similarity index 94% rename from src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/DefaultRazorProjectItem.cs rename to src/Microsoft.AspNetCore.Mvc.Razor/Internal/DefaultRazorProjectItem.cs index ff3451ea99..ff3a69f88d 100644 --- a/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/DefaultRazorProjectItem.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor/Internal/DefaultRazorProjectItem.cs @@ -5,7 +5,7 @@ using System.IO; using Microsoft.AspNetCore.Razor.Evolution; using Microsoft.Extensions.FileProviders; -namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal +namespace Microsoft.AspNetCore.Mvc.Razor.Internal { public class DefaultRazorProjectItem : RazorProjectItem { diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/Internal/DefaultRoslynCompilationService.cs b/src/Microsoft.AspNetCore.Mvc.Razor/Internal/DefaultRoslynCompilationService.cs index ec0cedfa27..bf3e941f0b 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor/Internal/DefaultRoslynCompilationService.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor/Internal/DefaultRoslynCompilationService.cs @@ -10,6 +10,7 @@ using System.Reflection; using System.Text; using Microsoft.AspNetCore.Diagnostics; using Microsoft.AspNetCore.Mvc.Razor.Compilation; +using Microsoft.AspNetCore.Razor.Evolution; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Text; @@ -56,23 +57,24 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal } /// - public CompilationResult Compile(RelativeFileInfo fileInfo, string compilationContent) + public CompilationResult Compile(RazorCodeDocument codeDocument, RazorCSharpDocument cSharpDocument) { - if (fileInfo == null) + if (codeDocument == null) { - throw new ArgumentNullException(nameof(fileInfo)); + throw new ArgumentNullException(nameof(codeDocument)); } - if (compilationContent == null) + if (cSharpDocument == null) { - throw new ArgumentNullException(nameof(compilationContent)); + throw new ArgumentNullException(nameof(codeDocument)); } - _logger.GeneratedCodeToAssemblyCompilationStart(fileInfo.RelativePath); + _logger.GeneratedCodeToAssemblyCompilationStart(codeDocument.Source.Filename); + var startTimestamp = _logger.IsEnabled(LogLevel.Debug) ? Stopwatch.GetTimestamp() : 0; var assemblyName = Path.GetRandomFileName(); - var compilation = CreateCompilation(compilationContent, assemblyName); + var compilation = CreateCompilation(cSharpDocument.GeneratedCode, assemblyName); using (var assemblyStream = new MemoryStream()) { @@ -86,8 +88,8 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal if (!result.Success) { return GetCompilationFailedResult( - fileInfo.RelativePath, - compilationContent, + codeDocument, + cSharpDocument.GeneratedCode, assemblyName, result.Diagnostics); } @@ -98,7 +100,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal var assembly = LoadAssembly(assemblyStream, pdbStream); var type = assembly.GetExportedTypes().FirstOrDefault(a => !a.IsNested); - _logger.GeneratedCodeToAssemblyCompilationEnd(fileInfo.RelativePath, startTimestamp); + _logger.GeneratedCodeToAssemblyCompilationEnd(codeDocument.Source.Filename, startTimestamp); return new CompilationResult(type); } @@ -122,14 +124,14 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal // Internal for unit testing internal CompilationResult GetCompilationFailedResult( - string relativePath, + RazorCodeDocument codeDocument, string compilationContent, string assemblyName, IEnumerable diagnostics) { var diagnosticGroups = diagnostics .Where(IsError) - .GroupBy(diagnostic => GetFilePath(relativePath, diagnostic), StringComparer.Ordinal); + .GroupBy(diagnostic => GetFilePath(codeDocument, diagnostic), StringComparer.Ordinal); var failures = new List(); foreach (var group in diagnosticGroups) @@ -144,7 +146,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal } else { - sourceFileContent = ReadFileContentsSafely(_fileProvider, sourceFilePath); + sourceFileContent = GetContent(codeDocument, sourceFilePath); } string additionalMessage = null; @@ -171,11 +173,11 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal return new CompilationResult(failures); } - private static string GetFilePath(string relativePath, Diagnostic diagnostic) + private static string GetFilePath(RazorCodeDocument codeDocument, Diagnostic diagnostic) { if (diagnostic.Location == Location.None) { - return relativePath; + return codeDocument.Source.Filename; } return diagnostic.Location.GetMappedLineSpan().Path; @@ -197,21 +199,23 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal return assembly; } - private static string ReadFileContentsSafely(IFileProvider fileProvider, string filePath) + private static string GetContent(RazorCodeDocument codeDocument, string filePath) { - var fileInfo = fileProvider.GetFileInfo(filePath); - if (fileInfo.Exists) + if (filePath == codeDocument.Source.Filename) { - try + var chars = new char[codeDocument.Source.Length]; + codeDocument.Source.CopyTo(0, chars, 0, chars.Length); + return new string(chars); + } + + for (var i = 0; i < codeDocument.Imports.Count; i++) + { + var import = codeDocument.Imports[i]; + if (filePath == import.Filename) { - using (var reader = new StreamReader(fileInfo.CreateReadStream())) - { - return reader.ReadToEnd(); - } - } - catch - { - // Ignore any failures + var chars = new char[codeDocument.Source.Length]; + codeDocument.Source.CopyTo(0, chars, 0, chars.Length); + return new string(chars); } } diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/Internal/RazorCompilationService.cs b/src/Microsoft.AspNetCore.Mvc.Razor/Internal/RazorCompilationService.cs index f30af08729..e9d3da7338 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor/Internal/RazorCompilationService.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor/Internal/RazorCompilationService.cs @@ -6,11 +6,12 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; +using System.Text; using Microsoft.AspNetCore.Diagnostics; using Microsoft.AspNetCore.Mvc.Razor.Compilation; -using Microsoft.AspNetCore.Mvc.Razor.Internal; using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.CodeGenerators; +using Microsoft.AspNetCore.Razor.Evolution; using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Logging; @@ -22,27 +23,52 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal public class RazorCompilationService : IRazorCompilationService { private readonly ICompilationService _compilationService; - private readonly IMvcRazorHost _razorHost; + private readonly RazorEngine _engine; + private readonly RazorProject _project; private readonly IFileProvider _fileProvider; private readonly ILogger _logger; + private readonly RazorSourceDocument _globalImports; /// /// Instantiates a new instance of the class. /// /// The to compile generated code. - /// The to generate code from Razor files. + /// The to generate code from Razor files. + /// The implementation for locating files. /// The . /// The . public RazorCompilationService( ICompilationService compilationService, - IMvcRazorHost razorHost, + RazorEngine engine, + RazorProject project, IRazorViewEngineFileProviderAccessor fileProviderAccessor, ILoggerFactory loggerFactory) { _compilationService = compilationService; - _razorHost = razorHost; + _engine = engine; _fileProvider = fileProviderAccessor.FileProvider; _logger = loggerFactory.CreateLogger(); + + _project = project; + + var stream = new MemoryStream(); + var writer = new StreamWriter(stream, Encoding.UTF8); + writer.WriteLine("@using System"); + writer.WriteLine("@using System.Linq"); + writer.WriteLine("@using System.Collections.Generic"); + writer.WriteLine("@using Microsoft.AspNetCore.Mvc"); + writer.WriteLine("@using Microsoft.AspNetCore.Mvc.Rendering"); + writer.WriteLine("@using Microsoft.AspNetCore.Mvc.ViewFeatures"); + writer.WriteLine("@inject Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper Html"); + writer.WriteLine("@inject Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json"); + writer.WriteLine("@inject Microsoft.AspNetCore.Mvc.IViewComponentHelper Component"); + writer.WriteLine("@inject Microsoft.AspNetCore.Mvc.IUrlHelper Url"); + writer.WriteLine("@inject Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider"); + writer.WriteLine("@addTagHelper Microsoft.AspNetCore.Mvc.Razor.TagHelpers.UrlResolutionTagHelper, Microsoft.AspNetCore.Mvc.Razor"); + writer.Flush(); + + stream.Seek(0L, SeekOrigin.Begin); + _globalImports = RazorSourceDocument.ReadFrom(stream, filename: null, encoding: Encoding.UTF8); } /// @@ -53,43 +79,66 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal throw new ArgumentNullException(nameof(file)); } - GeneratorResults results; + RazorCodeDocument codeDocument; + RazorCSharpDocument cSharpDocument; using (var inputStream = file.FileInfo.CreateReadStream()) { _logger.RazorFileToCodeCompilationStart(file.RelativePath); var startTimestamp = _logger.IsEnabled(LogLevel.Debug) ? Stopwatch.GetTimestamp() : 0; - results = GenerateCode(file.RelativePath, inputStream); + codeDocument = CreateCodeDocument(file.RelativePath, inputStream); + cSharpDocument = ProcessCodeDocument(codeDocument); _logger.RazorFileToCodeCompilationEnd(file.RelativePath, startTimestamp); } - if (!results.Success) + if (cSharpDocument.Diagnostics.Count > 0) { - return GetCompilationFailedResult(file, results.ParserErrors); + return GetCompilationFailedResult(file, cSharpDocument.Diagnostics); } - return _compilationService.Compile(file, results.GeneratedCode); + return _compilationService.Compile(codeDocument, cSharpDocument); } - /// - /// Generate code for the Razor file at with content - /// . - /// - /// - /// The path of the Razor file relative to the root of the application. Used to generate line pragmas and - /// calculate the class name of the generated type. - /// - /// A that contains the Razor content. - /// A instance containing results of code generation. - protected virtual GeneratorResults GenerateCode(string relativePath, Stream inputStream) + protected virtual RazorCodeDocument CreateCodeDocument(string relativePath, Stream inputStream) { - return _razorHost.GenerateCode(relativePath, inputStream); + var absolutePath = _fileProvider.GetFileInfo(relativePath)?.PhysicalPath ?? relativePath; + + var source = RazorSourceDocument.ReadFrom(inputStream, absolutePath); + + var imports = new List() + { + _globalImports, + }; + + var paths = ViewHierarchyUtility.GetViewImportsLocations(relativePath); + foreach (var path in paths.Reverse()) + { + var file = _fileProvider.GetFileInfo(path); + if (file.Exists) + { + using (var stream = file.CreateReadStream()) + { + imports.Add(RazorSourceDocument.ReadFrom(stream, file.PhysicalPath ?? path)); + } + } + } + + return RazorCodeDocument.Create(source, imports); + } + + protected virtual RazorCSharpDocument ProcessCodeDocument(RazorCodeDocument codeDocument) + { + _engine.Process(codeDocument); + + return codeDocument.GetCSharpDocument(); } // Internal for unit testing - internal CompilationResult GetCompilationFailedResult(RelativeFileInfo file, IEnumerable errors) + internal CompilationResult GetCompilationFailedResult( + RelativeFileInfo file, + IEnumerable errors) { // If a SourceLocation does not specify a file path, assume it is produced // from parsing the current file. @@ -114,7 +163,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal return new CompilationResult(failures); } - private DiagnosticMessage CreateDiagnosticMessage(RazorError error, string filePath) + private DiagnosticMessage CreateDiagnosticMessage( + Microsoft.AspNetCore.Razor.Evolution.Legacy.RazorError error, + string filePath) { var location = error.Location; return new DiagnosticMessage( diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Mvc.Razor/Properties/Resources.Designer.cs index f53ef11e26..b36da66649 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor/Properties/Resources.Designer.cs @@ -510,6 +510,22 @@ namespace Microsoft.AspNetCore.Mvc.Razor return string.Format(CultureInfo.CurrentCulture, GetString("FileProvidersAreRequired"), p0, p1, p2); } + /// + /// Path must begin with a forward slash '/'. + /// + internal static string RazorProject_PathMustStartWithForwardSlash + { + get { return GetString("RazorProject_PathMustStartWithForwardSlash"); } + } + + /// + /// Path must begin with a forward slash '/'. + /// + internal static string FormatRazorProject_PathMustStartWithForwardSlash() + { + return GetString("RazorProject_PathMustStartWithForwardSlash"); + } + private static string GetString(string name, params string[] formatterNames) { var value = _resourceManager.GetString(name); diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/RazorPage.cs b/src/Microsoft.AspNetCore.Mvc.Razor/RazorPage.cs index 141e4f55b9..7e26b659a5 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor/RazorPage.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor/RazorPage.cs @@ -856,7 +856,8 @@ namespace Microsoft.AspNetCore.Mvc.Razor if (PreviousSectionWriters.TryGetValue(sectionName, out renderDelegate)) { _renderedSections.Add(sectionName); - await renderDelegate(Output); + + await renderDelegate(); // Return a token value that allows the Write call that wraps the RenderSection \ RenderSectionAsync // to succeed. diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/RenderAsyncDelegate.cs b/src/Microsoft.AspNetCore.Mvc.Razor/RenderAsyncDelegate.cs index 783ada00cc..ecdce26f06 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor/RenderAsyncDelegate.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor/RenderAsyncDelegate.cs @@ -1,10 +1,9 @@ // 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; namespace Microsoft.AspNetCore.Mvc.Razor { - public delegate Task RenderAsyncDelegate(TextWriter writer); + public delegate Task RenderAsyncDelegate(); } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/Resources.resx b/src/Microsoft.AspNetCore.Mvc.Razor/Resources.resx index c0d7484574..b2b1306305 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor/Resources.resx +++ b/src/Microsoft.AspNetCore.Mvc.Razor/Resources.resx @@ -1,17 +1,17 @@  - @@ -212,4 +212,7 @@ '{0}.{1}' must not be empty. At least one '{2}' is required to locate a view for rendering. + + Path must begin with a forward slash '/'. + \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/exceptions.net45.json b/src/Microsoft.AspNetCore.Mvc.Razor/exceptions.net45.json new file mode 100644 index 0000000000..84a68f88d7 --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.Razor/exceptions.net45.json @@ -0,0 +1,29 @@ +[ + { + "OldTypeId": "public sealed class Microsoft.AspNetCore.Mvc.Razor.RenderAsyncDelegate : System.MulticastDelegate", + "OldMemberId": "public virtual System.Threading.Tasks.Task Invoke(System.IO.TextWriter writer)", + "NewTypeId": "public sealed class Microsoft.AspNetCore.Mvc.Razor.RenderAsyncDelegate : System.MulticastDelegate", + "NewMemberId": "public virtual System.Threading.Tasks.Task Invoke()", + "Kind": "Modification" + }, + { + "OldTypeId": "public sealed class Microsoft.AspNetCore.Mvc.Razor.RenderAsyncDelegate : System.MulticastDelegate", + "OldMemberId": "public virtual System.IAsyncResult BeginInvoke(System.IO.TextWriter writer, System.AsyncCallback callback, System.Object object)", + "NewTypeId": "public sealed class Microsoft.AspNetCore.Mvc.Razor.RenderAsyncDelegate : System.MulticastDelegate", + "NewMemberId": "public virtual System.IAsyncResult BeginInvoke(System.AsyncCallback callback, System.Object object)", + "Kind": "Modification" + }, + { + "OldTypeId": "public interface Microsoft.AspNetCore.Mvc.Razor.Compilation.ICompilationService", + "OldMemberId": "Microsoft.AspNetCore.Mvc.Razor.Compilation.CompilationResult Compile(Microsoft.AspNetCore.Mvc.Razor.Compilation.RelativeFileInfo fileInfo, System.String compilationContent)", + "NewTypeId": "public interface Microsoft.AspNetCore.Mvc.Razor.Compilation.ICompilationService", + "NewMemberId": "Microsoft.AspNetCore.Mvc.Razor.Compilation.CompilationResult Compile(Microsoft.AspNetCore.Razor.Evolution.RazorCodeDocument codeDocument, Microsoft.AspNetCore.Razor.Evolution.RazorCSharpDocument cSharpDocument)", + "Kind": "Modification" + }, + { + "OldTypeId": "public interface Microsoft.AspNetCore.Mvc.Razor.Compilation.ICompilationService", + "NewTypeId": "public interface Microsoft.AspNetCore.Mvc.Razor.Compilation.ICompilationService", + "NewMemberId": "Microsoft.AspNetCore.Mvc.Razor.Compilation.CompilationResult Compile(Microsoft.AspNetCore.Razor.Evolution.RazorCodeDocument codeDocument, Microsoft.AspNetCore.Razor.Evolution.RazorCSharpDocument cSharpDocument)", + "Kind": "Addition" + } +] \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/exceptions.netcore.json b/src/Microsoft.AspNetCore.Mvc.Razor/exceptions.netcore.json new file mode 100644 index 0000000000..f59dd85061 --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.Razor/exceptions.netcore.json @@ -0,0 +1,29 @@ +[ + { + "OldTypeId": "public sealed class Microsoft.AspNetCore.Mvc.Razor.RenderAsyncDelegate : System.MulticastDelegate", + "OldMemberId": "public virtual System.Threading.Tasks.Task Invoke(System.IO.TextWriter writer)", + "NewTypeId": "public sealed class Microsoft.AspNetCore.Mvc.Razor.RenderAsyncDelegate : System.MulticastDelegate", + "NewMemberId": "public virtual System.Threading.Tasks.Task Invoke()", + "Kind": "Modification" + }, + { + "OldTypeId": "public sealed class Microsoft.AspNetCore.Mvc.Razor.RenderAsyncDelegate : System.MulticastDelegate", + "OldMemberId": "public virtual System.IAsyncResult BeginInvoke(System.IO.TextWriter writer, System.AsyncCallback callback, System.Object object)", + "NewTypeId": "public sealed class Microsoft.AspNetCore.Mvc.Razor.RenderAsyncDelegate : System.MulticastDelegate", + "NewMemberId": "public virtual System.IAsyncResult BeginInvoke(System.AsyncCallback callback, System.Object object)", + "Kind": "Modification" + }, + { + "OldTypeId": "public interface Microsoft.AspNetCore.Mvc.Razor.Compilation.ICompilationService", + "OldMemberId": "Microsoft.AspNetCore.Mvc.Razor.Compilation.CompilationResult Compile(Microsoft.AspNetCore.Mvc.Razor.Compilation.RelativeFileInfo fileInfo, System.String compilationContent)", + "NewTypeId": "public interface Microsoft.AspNetCore.Mvc.Razor.Compilation.ICompilationService", + "NewMemberId": "Microsoft.AspNetCore.Mvc.Razor.Compilation.CompilationResult Compile(Microsoft.AspNetCore.Razor.Evolution.RazorCodeDocument codeDocument, Microsoft.AspNetCore.Razor.Evolution.RazorCSharpDocument cSharpDocument)", + "Kind": "Modification" + }, + { + "OldTypeId": "public interface Microsoft.AspNetCore.Mvc.Razor.Compilation.ICompilationService", + "NewTypeId": "public interface Microsoft.AspNetCore.Mvc.Razor.Compilation.ICompilationService", + "NewMemberId": "Microsoft.AspNetCore.Mvc.Razor.Compilation.CompilationResult Compile(Microsoft.AspNetCore.Razor.Evolution.RazorCodeDocument codeDocument, Microsoft.AspNetCore.Razor.Evolution.RazorCSharpDocument cSharpDocument)", + "Kind": "Addition" + } +] \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/project.json b/src/Microsoft.AspNetCore.Mvc.Razor/project.json index c4f9d6b035..3ba817f719 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor/project.json +++ b/src/Microsoft.AspNetCore.Mvc.Razor/project.json @@ -22,6 +22,8 @@ "xmlDoc": true }, "dependencies": { + "Microsoft.CodeAnalysis.Razor": "1.2.0-*", + "Microsoft.AspNetCore.Razor.Runtime": "1.2.0-*", "Microsoft.AspNetCore.Mvc.Razor.Host": { "target": "project" }, diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/Properties/Resources.Designer.cs index 1741a5572c..af7fffe698 100644 --- a/src/Microsoft.AspNetCore.Mvc.RazorPages/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/Properties/Resources.Designer.cs @@ -26,22 +26,6 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages return string.Format(CultureInfo.CurrentCulture, GetString("PageActionDescriptorProvider_RouteTemplateCannotBeOverrideable"), p0); } - /// - /// Path must begin with a forward slash '/'. - /// - internal static string RazorProject_PathMustStartWithForwardSlash - { - get { return GetString("RazorProject_PathMustStartWithForwardSlash"); } - } - - /// - /// Path must begin with a forward slash '/'. - /// - internal static string FormatRazorProject_PathMustStartWithForwardSlash() - { - return GetString("RazorProject_PathMustStartWithForwardSlash"); - } - /// /// The '{0}' property of '{1}' must not be null. /// diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/Resources.resx b/src/Microsoft.AspNetCore.Mvc.RazorPages/Resources.resx index 26db628257..1f025bfbb1 100644 --- a/src/Microsoft.AspNetCore.Mvc.RazorPages/Resources.resx +++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/Resources.resx @@ -120,9 +120,6 @@ The route for the page at '{0}' cannot start with / or ~/. Pages do not support overriding the file path of the page. - - Path must begin with a forward slash '/'. - The '{0}' property of '{1}' must not be null. diff --git a/src/Microsoft.AspNetCore.Mvc.TagHelpers/project.json b/src/Microsoft.AspNetCore.Mvc.TagHelpers/project.json index 3bbe606e90..a943a064ec 100644 --- a/src/Microsoft.AspNetCore.Mvc.TagHelpers/project.json +++ b/src/Microsoft.AspNetCore.Mvc.TagHelpers/project.json @@ -25,6 +25,7 @@ "Microsoft.AspNetCore.Mvc.Razor": { "target": "project" }, + "Microsoft.AspNetCore.Razor.Runtime": "1.2.0-*", "Microsoft.AspNetCore.Routing.Abstractions": "1.2.0-*", "Microsoft.Extensions.Caching.Memory": "1.2.0-*", "Microsoft.Extensions.FileSystemGlobbing": "1.2.0-*", diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/ErrorPageTests.cs b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/ErrorPageTests.cs index 313702b44e..85c1584a5f 100644 --- a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/ErrorPageTests.cs +++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/ErrorPageTests.cs @@ -41,7 +41,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); Assert.Equal(expectedMediaType, response.Content.Headers.ContentType); var content = await response.Content.ReadAsStringAsync(); - Assert.Contains($"/Views/ErrorPageMiddleware/{action}.cshtml", content); + Assert.Contains($"{action}.cshtml", content); Assert.Contains(expected, content); Assert.DoesNotContain(PreserveCompilationContextMessage, content); } @@ -64,11 +64,11 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); Assert.Equal(expectedMediaType, response.Content.Headers.ContentType); var content = await response.Content.ReadAsStringAsync(); - Assert.Contains($"/Views/ErrorPageMiddleware/{action}.cshtml", content); + Assert.Contains($"{action}.cshtml", content); Assert.Contains(expected, content); } - [Fact] + [Fact(Skip = "Razor #595")] public async Task CompilationFailuresFromViewImportsAreListed() { // Arrange @@ -85,7 +85,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); Assert.Equal(expectedMediaType, response.Content.Headers.ContentType); var content = await response.Content.ReadAsStringAsync(); - Assert.Contains("/Views/ErrorFromViewImports/_ViewImports.cshtml", content); + Assert.Contains("_ViewImports.cshtml", content); Assert.Contains(expectedMessage, content); Assert.Contains(PreserveCompilationContextMessage, content); Assert.Contains(expectedCompilationContent, content); @@ -115,7 +115,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); Assert.Equal(expectedMediaType, response.Content.Headers.ContentType); var content = await response.Content.ReadAsStringAsync(); - Assert.Contains("/Views/ErrorPageMiddleware/RuntimeError.cshtml", content); + Assert.Contains("RuntimeError.cshtml", content); Assert.Contains(expectedMessage, content); } diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorPageExecutionInstrumentationTest.cs b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorPageExecutionInstrumentationTest.cs index f943484df2..74bae6001a 100644 --- a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorPageExecutionInstrumentationTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorPageExecutionInstrumentationTest.cs @@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests public HttpClient Client { get; } - [Fact] + [Fact(Skip = "Razor #961")] public async Task InstrumentedViews_RenderAsExpected() { // Arrange diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/Directives/ChunkInheritanceUtilityTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/Directives/ChunkInheritanceUtilityTest.cs deleted file mode 100644 index 115a2612d6..0000000000 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/Directives/ChunkInheritanceUtilityTest.cs +++ /dev/null @@ -1,183 +0,0 @@ -// 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 Microsoft.AspNetCore.Razor.Chunks; -using Microsoft.AspNetCore.Razor.Runtime.TagHelpers; -using Xunit; - -namespace Microsoft.AspNetCore.Mvc.Razor.Directives -{ - public class ChunkInheritanceUtilityTest - { - [Fact] - public void GetInheritedChunks_ReadsChunksFromGlobalFilesInPath() - { - // Arrange - var fileProvider = new TestFileProvider(); - fileProvider.AddFile(@"/Views/accounts/_ViewImports.cshtml", "@using AccountModels"); - fileProvider.AddFile(@"/Views/Shared/_ViewImports.cshtml", "@inject SharedHelper Shared"); - fileProvider.AddFile(@"/Views/home/_ViewImports.cshtml", "@using MyNamespace"); - fileProvider.AddFile(@"/Views/_ViewImports.cshtml", -@"@inject MyHelper Helper -@inherits MyBaseType - -@{ - Layout = ""test.cshtml""; -} - -"); - var defaultChunks = new Chunk[] - { - new InjectChunk("MyTestHtmlHelper", "Html"), - new UsingChunk { Namespace = "AppNamespace.Model" }, - }; - var cache = new DefaultChunkTreeCache(fileProvider); - var host = new MvcRazorHost(cache, new TagHelperDescriptorResolver(designTime: false)); - var utility = new ChunkInheritanceUtility(host, cache, defaultChunks); - - // Act - var chunkTreeResults = utility.GetInheritedChunkTreeResults( - Path.Combine("Views", "home", "Index.cshtml")); - - // Assert - Assert.Collection(chunkTreeResults, - chunkTreeResult => - { - var viewImportsPath = @"/Views/_ViewImports.cshtml"; - Assert.Collection(chunkTreeResult.ChunkTree.Children, - chunk => - { - Assert.IsType(chunk); - Assert.Equal(viewImportsPath, chunk.Start.FilePath); - }, - chunk => - { - var injectChunk = Assert.IsType(chunk); - Assert.Equal("MyHelper", injectChunk.TypeName); - Assert.Equal("Helper", injectChunk.MemberName); - Assert.Equal(viewImportsPath, chunk.Start.FilePath); - }, - chunk => - { - Assert.IsType(chunk); - Assert.Equal(viewImportsPath, chunk.Start.FilePath); - }, - chunk => - { - var setBaseTypeChunk = Assert.IsType(chunk); - Assert.Equal("MyBaseType", setBaseTypeChunk.TypeName); - Assert.Equal(viewImportsPath, chunk.Start.FilePath); - }, - chunk => - { - Assert.IsType(chunk); - Assert.Equal(viewImportsPath, chunk.Start.FilePath); - }, - chunk => - { - Assert.IsType(chunk); - Assert.Equal(viewImportsPath, chunk.Start.FilePath); - }, - chunk => - { - Assert.IsType(chunk); - Assert.Equal(viewImportsPath, chunk.Start.FilePath); - }); - Assert.Equal(viewImportsPath, chunkTreeResult.FilePath); - }, - chunkTreeResult => - { - var viewImportsPath = "/Views/home/_ViewImports.cshtml"; - Assert.Collection(chunkTreeResult.ChunkTree.Children, - chunk => - { - Assert.IsType(chunk); - Assert.Equal(viewImportsPath, chunk.Start.FilePath); - }, - chunk => - { - var usingChunk = Assert.IsType(chunk); - Assert.Equal("MyNamespace", usingChunk.Namespace); - Assert.Equal(viewImportsPath, chunk.Start.FilePath); - }, - chunk => - { - Assert.IsType(chunk); - Assert.Equal(viewImportsPath, chunk.Start.FilePath); - }); - Assert.Equal(viewImportsPath, chunkTreeResult.FilePath); - }); - } - - [Fact] - public void GetInheritedChunks_ReturnsEmptySequenceIfNoGlobalsArePresent() - { - // Arrange - var fileProvider = new TestFileProvider(); - fileProvider.AddFile(@"/_ViewImports.cs", string.Empty); - fileProvider.AddFile(@"/Views/_Layout.cshtml", string.Empty); - fileProvider.AddFile(@"/Views/home/_not-viewimports.cshtml", string.Empty); - var cache = new DefaultChunkTreeCache(fileProvider); - var host = new MvcRazorHost(cache, new TagHelperDescriptorResolver(designTime: false)); - var defaultChunks = new Chunk[] - { - new InjectChunk("MyTestHtmlHelper", "Html"), - new UsingChunk { Namespace = "AppNamespace.Model" }, - }; - var utility = new ChunkInheritanceUtility(host, cache, defaultChunks); - - // Act - var chunkTrees = utility.GetInheritedChunkTreeResults(Path.Combine("Views", "home", "Index.cshtml")); - - // Assert - Assert.Empty(chunkTrees); - } - - [Fact] - public void MergeInheritedChunks_MergesDefaultInheritedChunks() - { - // Arrange - var fileProvider = new TestFileProvider(); - fileProvider.AddFile(@"/Views/_ViewImports.cshtml", - "@inject DifferentHelper Html"); - var cache = new DefaultChunkTreeCache(fileProvider); - var host = new MvcRazorHost(cache, new TagHelperDescriptorResolver(designTime: false)); - var defaultChunks = new Chunk[] - { - new InjectChunk("MyTestHtmlHelper", "Html"), - new UsingChunk { Namespace = "AppNamespace.Model" }, - }; - var inheritedChunkTrees = new ChunkTree[] - { - new ChunkTree - { - Children = new Chunk[] - { - new UsingChunk { Namespace = "InheritedNamespace" }, - new LiteralChunk { Text = "some text" } - } - }, - new ChunkTree - { - Children = new Chunk[] - { - new UsingChunk { Namespace = "AppNamespace.Model" }, - } - } - }; - - var utility = new ChunkInheritanceUtility(host, cache, defaultChunks); - var chunkTree = new ChunkTree(); - - // Act - utility.MergeInheritedChunkTrees(chunkTree, inheritedChunkTrees, "dynamic"); - - // Assert - Assert.Collection(chunkTree.Children, - chunk => Assert.Same(defaultChunks[1], chunk), - chunk => Assert.Same(inheritedChunkTrees[0].Children[0], chunk), - chunk => Assert.Same(defaultChunks[0], chunk)); - } - } -} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/Directives/DefaultCodeTreeCacheTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/Directives/DefaultCodeTreeCacheTest.cs deleted file mode 100644 index 9b48fcb6ef..0000000000 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/Directives/DefaultCodeTreeCacheTest.cs +++ /dev/null @@ -1,180 +0,0 @@ -// 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; -using Microsoft.AspNetCore.Mvc.Razor.Directives; -using Microsoft.AspNetCore.Razor.Chunks; -using Microsoft.Extensions.Caching.Memory; -using Microsoft.Extensions.Internal; -using Moq; -using Xunit; - -namespace Microsoft.AspNetCore.Mvc.Razor.Host.Directives -{ - public class ChunkTreeCacheTest - { - [Fact] - public void GetOrAdd_ReturnsCachedEntriesOnSubsequentCalls() - { - // Arrange - var path = @"Views\_ViewStart.cshtml"; - var mockFileProvider = new Mock { CallBase = true }; - var fileProvider = mockFileProvider.Object; - fileProvider.AddFile(path, "test content"); - using (var chunkTreeCache = new DefaultChunkTreeCache(fileProvider)) - { - var expected = new ChunkTree(); - - // Act - var result1 = chunkTreeCache.GetOrAdd(path, fileInfo => expected); - var result2 = chunkTreeCache.GetOrAdd(path, fileInfo => { throw new Exception("Shouldn't be called."); }); - - // Assert - Assert.Same(expected, result1); - Assert.Same(expected, result2); - mockFileProvider.Verify(f => f.GetFileInfo(It.IsAny()), Times.Once()); - } - } - - [Fact] - public void GetOrAdd_ReturnsNullValues_IfFileDoesNotExistInFileProvider() - { - // Arrange - var path = @"Views\_ViewStart.cshtml"; - var mockFileProvider = new Mock { CallBase = true }; - var fileProvider = mockFileProvider.Object; - using (var chunkTreeCache = new DefaultChunkTreeCache(fileProvider)) - { - var expected = new ChunkTree(); - - // Act - var result1 = chunkTreeCache.GetOrAdd(path, fileInfo => expected); - var result2 = chunkTreeCache.GetOrAdd(path, fileInfo => { throw new Exception("Shouldn't be called."); }); - - // Assert - Assert.Null(result1); - Assert.Null(result2); - mockFileProvider.Verify(f => f.GetFileInfo(It.IsAny()), Times.Once()); - } - } - - [Fact] - public void GetOrAdd_UpdatesCache_IfFileExpirationTriggerExpires() - { - // Arrange - var path = @"Views\Home\_ViewStart.cshtml"; - var fileProvider = new TestFileProvider(); - fileProvider.AddFile(path, "test content"); - using (var chunkTreeCache = new DefaultChunkTreeCache(fileProvider)) - { - var expected1 = new ChunkTree(); - var expected2 = new ChunkTree(); - - // Act 1 - var result1 = chunkTreeCache.GetOrAdd(path, fileInfo => expected1); - - // Assert 1 - Assert.Same(expected1, result1); - - // Act 2 - fileProvider.GetChangeToken(path).HasChanged = true; - var result2 = chunkTreeCache.GetOrAdd(path, fileInfo => expected2); - - // Assert 2 - Assert.Same(expected2, result2); - } - } - - [Fact] - public void GetOrAdd_UpdatesCacheWithNullValue_IfFileWasDeleted() - { - // Arrange - var path = @"Views\Home\_ViewStart.cshtml"; - var fileProvider = new TestFileProvider(); - fileProvider.AddFile(path, "test content"); - using (var chunkTreeCache = new DefaultChunkTreeCache(fileProvider)) - { - var expected1 = new ChunkTree(); - - // Act 1 - var result1 = chunkTreeCache.GetOrAdd(path, fileInfo => expected1); - - // Assert 1 - Assert.Same(expected1, result1); - - // Act 2 - fileProvider.DeleteFile(path); - fileProvider.GetChangeToken(path).HasChanged = true; - var result2 = chunkTreeCache.GetOrAdd(path, fileInfo => { throw new Exception("Shouldn't be called."); }); - - // Assert 2 - Assert.Null(result2); - } - } - - [Fact] - public void GetOrAdd_UpdatesCacheWithValue_IfFileWasAdded() - { - // Arrange - var path = @"Views\Home\_ViewStart.cshtml"; - var fileProvider = new TestFileProvider(); - using (var chunkTreeCache = new DefaultChunkTreeCache(fileProvider)) - { - var expected = new ChunkTree(); - - // Act 1 - var result1 = chunkTreeCache.GetOrAdd(path, fileInfo => { throw new Exception("Shouldn't be called."); }); - - // Assert 1 - Assert.Null(result1); - - // Act 2 - fileProvider.AddFile(path, "test content"); - fileProvider.GetChangeToken(path).HasChanged = true; - var result2 = chunkTreeCache.GetOrAdd(path, fileInfo => expected); - - // Assert 2 - Assert.Same(expected, result2); - } - } - - [Fact] - public void GetOrAdd_ExpiresEntriesAfterOneMinute() - { - // Arrange - var path = @"Views\Home\_ViewStart.cshtml"; - var fileProvider = new TestFileProvider(); - fileProvider.AddFile(path, "some content"); - var clock = new Mock(); - var utcNow = DateTimeOffset.UtcNow; - clock.SetupGet(c => c.UtcNow) - .Returns(() => utcNow); - var options = new MemoryCacheOptions { Clock = clock.Object }; - using (var chunkTreeCache = new DefaultChunkTreeCache(fileProvider, options)) - { - var chunkTree1 = new ChunkTree(); - var chunkTree2 = new ChunkTree(); - - // Act 1 - var result1 = chunkTreeCache.GetOrAdd(path, fileInfo => chunkTree1); - - // Assert 1 - Assert.Same(chunkTree1, result1); - - // Act 2 - utcNow = utcNow.AddSeconds(59); - var result2 = chunkTreeCache.GetOrAdd(path, fileInfo => { throw new Exception("Shouldn't be called."); }); - - // Assert 2 - Assert.Same(chunkTree1, result2); - - // Act 3 - utcNow = utcNow.AddSeconds(65); - var result3 = chunkTreeCache.GetOrAdd(path, fileInfo => chunkTree2); - - // Assert 3 - Assert.Same(chunkTree2, result3); - } - } - } -} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/Directives/InjectChunkMergerTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/Directives/InjectChunkMergerTest.cs index ce81a8e774..41022d1c0c 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/Directives/InjectChunkMergerTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/Directives/InjectChunkMergerTest.cs @@ -8,6 +8,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Directives { public class InjectChunkMergerTest { +#if OLD_RAZOR [Theory] [InlineData("MyApp.TestHelper", "MyApp.TestHelper")] [InlineData("TestBaseType", "TestBaseType")] @@ -168,5 +169,6 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Directives Assert.Equal("DifferentProperty", injectChunk.MemberName); }); } +#endif } } \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/Directives/SetBaseTypeChunkMergerTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/Directives/SetBaseTypeChunkMergerTest.cs index d8b18cf1ae..b0feff71f5 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/Directives/SetBaseTypeChunkMergerTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/Directives/SetBaseTypeChunkMergerTest.cs @@ -8,6 +8,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Directives { public class SetBaseTypeChunkMergerTest { + #if OLD_RAZOR [Theory] [InlineData("MyApp.BaseType", "MyApp.BaseType")] [InlineData("TestBaseType", "TestBaseType")] @@ -88,5 +89,6 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Directives var setBaseTypeChunk = Assert.IsType(chunk); Assert.Equal("MyBase1", setBaseTypeChunk.TypeName); } +#endif } } \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/Directives/UsingChunkMergerTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/Directives/UsingChunkMergerTest.cs index da21ed1e42..f4981ea09f 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/Directives/UsingChunkMergerTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/Directives/UsingChunkMergerTest.cs @@ -9,6 +9,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Directives { public class UsingChunkMergerTest { + #if OLD_RAZOR [Fact] public void Merge_AddsNamespacesThatHaveNotBeenVisitedInChunkTree() { @@ -98,5 +99,6 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Directives chunk = Assert.IsType(chunkTree.Children[1]); Assert.Equal("Microsoft.AspNetCore.mvc", chunk.Namespace); } +#endif } } \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/InjectChunkVisitorTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/InjectChunkVisitorTest.cs index 461000d75a..1063f4026f 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/InjectChunkVisitorTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/InjectChunkVisitorTest.cs @@ -15,6 +15,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor { public class InjectChunkVisitorTest { + #if OLD_RAZOR [Fact] public void Visit_IgnoresNonInjectChunks() { @@ -157,5 +158,6 @@ MyType1 shouldGenerateLinePragmas: true), new ErrorSink()); } +#endif } } \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/Internal/TagHelperChunkDecoratorTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/Internal/TagHelperChunkDecoratorTest.cs index 7d9f65f2c6..03bbea9b86 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/Internal/TagHelperChunkDecoratorTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/Internal/TagHelperChunkDecoratorTest.cs @@ -13,6 +13,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Host.Test { public class TagHelperChunkDecoratorTest { + #if OLD_RAZOR [Fact] public void Accept_CorrectlyDecoratesViewComponentChunks() { @@ -63,5 +64,6 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Host.Test resultTagHelperChunk.Descriptors.First().TypeName, StringComparer.Ordinal); } +#endif } } diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/Internal/ViewComponentTagHelperChunkVisitorTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/Internal/ViewComponentTagHelperChunkVisitorTest.cs index 39a13605e4..bf3257abd5 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/Internal/ViewComponentTagHelperChunkVisitorTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/Internal/ViewComponentTagHelperChunkVisitorTest.cs @@ -12,6 +12,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Host.Test.Internal { public class ViewComponentTagHelperChunkVisitorTest { + #if OLD_RAZOR public static TheoryData CodeGenerationData { get @@ -56,5 +57,6 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Host.Test.Internal #endif } +#endif } } diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/MvcCSharpRazorCodeParserTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/MvcCSharpRazorCodeParserTest.cs deleted file mode 100644 index 2a3d5f8298..0000000000 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/MvcCSharpRazorCodeParserTest.cs +++ /dev/null @@ -1,554 +0,0 @@ -// 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; -using System.Collections.Generic; -using System.Linq; -using Microsoft.AspNetCore.Razor; -using Microsoft.AspNetCore.Razor.Chunks.Generators; -using Microsoft.AspNetCore.Razor.CodeGenerators; -using Microsoft.AspNetCore.Razor.Generator; -using Microsoft.AspNetCore.Razor.Parser; -using Microsoft.AspNetCore.Razor.Parser.Internal; -using Microsoft.AspNetCore.Razor.Parser.SyntaxTree; -using Microsoft.AspNetCore.Razor.Text; -using Xunit; - -namespace Microsoft.AspNetCore.Mvc.Razor -{ - public class MvcCSharpRazorCodeParserTest - { - [Theory] - [InlineData("model")] - [InlineData("inject")] - public void Constructor_AddsMvcSpecificKeywords(string keyword) - { - // Arrange - var parser = new TestMvcCSharpRazorCodeParser(); - - // Act - var hasDirective = parser.HasDirective(keyword); - - // Assert - Assert.True(hasDirective); - } - - [Fact] - public void ParseModelKeyword_HandlesSingleInstance() - { - // Arrange - var document = "@model Foo"; - var factory = SpanFactory.CreateCsHtml(); - var errors = new List(); - var expectedSpans = new Span[] - { - factory.EmptyHtml(), - factory.CodeTransition(SyntaxConstants.TransitionString) - .Accepts(AcceptedCharacters.None), - factory.MetaCode("model ") - .Accepts(AcceptedCharacters.None), - factory.Code(" Foo") - .As(new ModelChunkGenerator("Foo")) - .Accepts(AcceptedCharacters.AnyExceptNewline), - factory.EmptyHtml() - }; - - // Act - var spans = ParseDocument(document, errors); - - // Assert - Assert.Equal(expectedSpans, spans); - Assert.Empty(errors); - } - - [Theory] - [InlineData("Foo?", "Foo?")] - [InlineData("Foo[[]][]", "Foo[[]][]")] - [InlineData("$rootnamespace$.MyModel", "$rootnamespace$.MyModel")] - public void ParseModelKeyword_InfersBaseType_FromModelName( - string modelName, - string expectedModel) - { - // Arrange - var documentContent = "@model " + modelName + Environment.NewLine + "Bar"; - var factory = SpanFactory.CreateCsHtml(); - var errors = new List(); - var expectedSpans = new Span[] - { - factory.EmptyHtml(), - factory.CodeTransition(SyntaxConstants.TransitionString) - .Accepts(AcceptedCharacters.None), - factory.MetaCode("model ") - .Accepts(AcceptedCharacters.None), - factory.Code(modelName + Environment.NewLine) - .As(new ModelChunkGenerator(expectedModel)) - .Accepts(AcceptedCharacters.AnyExceptNewline), - factory.Markup("Bar") - .With(new MarkupChunkGenerator()) - }; - - // Act - var spans = ParseDocument(documentContent, errors); - - // Assert - Assert.Equal(expectedSpans, spans); - Assert.Empty(errors); - } - - [Fact] - public void ParseModelKeyword_ErrorOnMissingModelType() - { - // Arrange + Act - var errors = new List(); - var document = "@model "; - var spans = ParseDocument(document, errors); - - // Assert - var factory = SpanFactory.CreateCsHtml(); - var expectedSpans = new Span[] - { - factory.EmptyHtml(), - factory.CodeTransition(SyntaxConstants.TransitionString) - .Accepts(AcceptedCharacters.None), - factory.MetaCode("model ") - .Accepts(AcceptedCharacters.None), - factory.Code(" ") - .As(new ModelChunkGenerator(string.Empty)) - .Accepts(AcceptedCharacters.AnyExceptNewline), - factory.EmptyHtml(), - }; - var expectedErrors = new[] - { - new RazorError("The 'model' keyword must be followed by a type name on the same line.", - new SourceLocation(1, 0, 1), 5) - }; - Assert.Equal(expectedSpans, spans); - Assert.Equal(expectedErrors, errors); - } - - [Fact] - public void ParseModelKeyword_ErrorOnMultipleModelStatements() - { - // Arrange + Act - var errors = new List(); - var document = - "@model Foo" + Environment.NewLine - + "@model Bar"; - - var factory = SpanFactory.CreateCsHtml(); - var expectedSpans = new Span[] - { - factory.EmptyHtml(), - factory.CodeTransition(SyntaxConstants.TransitionString) - .Accepts(AcceptedCharacters.None), - factory.MetaCode("model ") - .Accepts(AcceptedCharacters.None), - factory.Code("Foo" + Environment.NewLine) - .As(new ModelChunkGenerator("Foo")) - .Accepts(AcceptedCharacters.AnyExceptNewline), - factory.EmptyHtml(), - factory.CodeTransition(SyntaxConstants.TransitionString) - .Accepts(AcceptedCharacters.None), - factory.MetaCode("model ") - .Accepts(AcceptedCharacters.None), - factory.Code("Bar") - .As(new ModelChunkGenerator("Bar")) - .Accepts(AcceptedCharacters.AnyExceptNewline), - factory.EmptyHtml() - }; - - var expectedErrors = new[] - { - new RazorError( - "Only one 'model' statement is allowed in a file.", - PlatformNormalizer.NormalizedSourceLocation(13, 1, 1), - 5) - }; - - // Act - var spans = ParseDocument(document, errors); - - // Assert - Assert.Equal(expectedSpans, spans); - Assert.Equal(expectedErrors, errors); - } - - [Fact] - public void ParseModelKeyword_ErrorOnModelFollowedByInherits() - { - // Arrange - var errors = new List(); - var document = - "@model Foo" + Environment.NewLine - + "@inherits Bar"; - - var factory = SpanFactory.CreateCsHtml(); - var expectedSpans = new Span[] - { - factory.EmptyHtml(), - factory.CodeTransition(SyntaxConstants.TransitionString) - .Accepts(AcceptedCharacters.None), - factory.MetaCode("model ") - .Accepts(AcceptedCharacters.None), - factory.Code("Foo" + Environment.NewLine) - .As(new ModelChunkGenerator("Foo")) - .Accepts(AcceptedCharacters.AnyExceptNewline), - factory.EmptyHtml(), - factory.CodeTransition(SyntaxConstants.TransitionString) - .Accepts(AcceptedCharacters.None), - factory.MetaCode("inherits ") - .Accepts(AcceptedCharacters.None), - factory.Code("Bar") - .As(new SetBaseTypeChunkGenerator("Bar")) - .Accepts(AcceptedCharacters.AnyExceptNewline), - factory.EmptyHtml() - }; - - var expectedErrors = new[] - { - new RazorError( - "The 'inherits' keyword is not allowed when a 'model' keyword is used.", - PlatformNormalizer.NormalizedSourceLocation(21, 1, 9), - length: 8) - }; - - // Act - var spans = ParseDocument(document, errors); - - // Assert - Assert.Equal(expectedSpans, spans); - Assert.Equal(expectedErrors, errors); - } - - [Fact] - public void ParseModelKeyword_ErrorOnInheritsFollowedByModel() - { - // Arrange - var errors = new List(); - var document = - "@inherits Bar" + Environment.NewLine - + "@model Foo"; - - var factory = SpanFactory.CreateCsHtml(); - var expectedSpans = new Span[] - { - factory.EmptyHtml(), - factory.CodeTransition(SyntaxConstants.TransitionString) - .Accepts(AcceptedCharacters.None), - factory.MetaCode("inherits ") - .Accepts(AcceptedCharacters.None), - factory.Code("Bar" + Environment.NewLine) - .As(new SetBaseTypeChunkGenerator("Bar")) - .Accepts(AcceptedCharacters.AnyExceptNewline), - factory.EmptyHtml(), - factory.CodeTransition(SyntaxConstants.TransitionString) - .Accepts(AcceptedCharacters.None), - factory.MetaCode("model ") - .Accepts(AcceptedCharacters.None), - factory.Code("Foo") - .As(new ModelChunkGenerator("Foo")) - .Accepts(AcceptedCharacters.AnyExceptNewline), - factory.EmptyHtml() - }; - - var expectedErrors = new[] - { - new RazorError( - "The 'inherits' keyword is not allowed when a 'model' keyword is used.", - new SourceLocation(9, 0, 9), - length: 8) - }; - - // Act - var spans = ParseDocument(document, errors); - - // Assert - Assert.Equal(expectedSpans, spans.ToArray()); - Assert.Equal(expectedErrors, errors.ToArray()); - } - - [Theory] - [InlineData("IMyService Service", "IMyService", "Service")] - [InlineData(" Microsoft.AspNetCore.Mvc.IHtmlHelper MyHelper ", - "Microsoft.AspNetCore.Mvc.IHtmlHelper", "MyHelper")] - [InlineData(" TestService @class ", "TestService", "@class")] - public void ParseInjectKeyword_InfersTypeAndPropertyName( - string injectStatement, - string expectedService, - string expectedPropertyName) - { - // Arrange - var documentContent = "@inject " + injectStatement; - var factory = SpanFactory.CreateCsHtml(); - var errors = new List(); - var expectedSpans = new Span[] - { - factory.EmptyHtml(), - factory.CodeTransition(SyntaxConstants.TransitionString) - .Accepts(AcceptedCharacters.None), - factory.MetaCode("inject ") - .Accepts(AcceptedCharacters.None), - factory.Code(injectStatement) - .As(new InjectParameterGenerator(expectedService, expectedPropertyName)) - .Accepts(AcceptedCharacters.AnyExceptNewline), - factory.EmptyHtml() - }; - - // Act - var spans = ParseDocument(documentContent, errors); - - // Assert - Assert.Equal(expectedSpans, spans); - Assert.Empty(errors); - } - - [Theory] - [InlineData("IMyService Service;", "IMyService", "Service")] - [InlineData("IMyService Service;;", "IMyService", "Service")] - [InlineData(" Microsoft.AspNetCore.Mvc.IHtmlHelper MyHelper; ", - "Microsoft.AspNetCore.Mvc.IHtmlHelper", "MyHelper")] - [InlineData(" Microsoft.AspNetCore.Mvc.IHtmlHelper MyHelper; ; ", - "Microsoft.AspNetCore.Mvc.IHtmlHelper", "MyHelper")] - [InlineData(" TestService @class; ; ", "TestService", "@class")] - [InlineData("IMyService Service ;", "IMyService", "Service")] - [InlineData("IMyService Service ; ;", "IMyService", "Service")] - [InlineData(" Microsoft.AspNetCore.Mvc.IHtmlHelper MyHelper ; ", - "Microsoft.AspNetCore.Mvc.IHtmlHelper", "MyHelper")] - [InlineData(" Microsoft.AspNetCore.Mvc.IHtmlHelper MyHelper ; ; ", - "Microsoft.AspNetCore.Mvc.IHtmlHelper", "MyHelper")] - [InlineData(" TestService @class ; ", "TestService", "@class")] - [InlineData(" TestService @class ; ; ", "TestService", "@class")] - public void ParseInjectKeyword_AllowsOptionalTrailingSemicolon( - string injectStatement, - string expectedService, - string expectedPropertyName) - { - // Arrange - var documentContent = "@inject " + injectStatement; - var factory = SpanFactory.CreateCsHtml(); - var errors = new List(); - var expectedSpans = new Span[] - { - factory.EmptyHtml(), - factory.CodeTransition(SyntaxConstants.TransitionString) - .Accepts(AcceptedCharacters.None), - factory.MetaCode("inject ") - .Accepts(AcceptedCharacters.None), - factory.Code(injectStatement) - .As(new InjectParameterGenerator(expectedService, expectedPropertyName)) - .Accepts(AcceptedCharacters.AnyExceptNewline), - factory.EmptyHtml() - }; - - // Act - var spans = ParseDocument(documentContent, errors); - - // Assert - Assert.Equal(expectedSpans, spans); - Assert.Empty(errors); - } - - [Theory] - [InlineData("IMyService Service ", "IMyService", "Service")] - [InlineData(" TestService @namespace ", "TestService", "@namespace")] - public void ParseInjectKeyword_ParsesUpToNewLine( - string injectStatement, - string expectedService, - string expectedPropertyName) - { - // Arrange - var documentContent = "@inject " + injectStatement + Environment.NewLine + "Bar"; - var factory = SpanFactory.CreateCsHtml(); - var errors = new List(); - var expectedSpans = new Span[] - { - factory.EmptyHtml(), - factory.CodeTransition(SyntaxConstants.TransitionString) - .Accepts(AcceptedCharacters.None), - factory.MetaCode("inject ") - .Accepts(AcceptedCharacters.None), - factory.Code(injectStatement + Environment.NewLine) - .As(new InjectParameterGenerator(expectedService, expectedPropertyName)) - .Accepts(AcceptedCharacters.AnyExceptNewline), - factory.Markup("Bar") - .With(new MarkupChunkGenerator()) - }; - - // Act - var spans = ParseDocument(documentContent, errors); - - // Assert - Assert.Equal(expectedSpans, spans); - Assert.Empty(errors); - } - - [Fact] - public void ParseInjectKeyword_ErrorOnMissingTypeName() - { - // Arrange - var errors = new List(); - var documentContent = $"@inject {Environment.NewLine}Bar"; - var factory = SpanFactory.CreateCsHtml(); - var expectedSpans = new Span[] - { - factory.EmptyHtml(), - factory.CodeTransition(SyntaxConstants.TransitionString) - .Accepts(AcceptedCharacters.None), - factory.MetaCode("inject ") - .Accepts(AcceptedCharacters.None), - factory.Code(" " + Environment.NewLine) - .As(new InjectParameterGenerator(string.Empty, string.Empty)) - .Accepts(AcceptedCharacters.AnyExceptNewline), - factory.Markup("Bar") - .With(new MarkupChunkGenerator()) - }; - var expectedErrors = new[] - { - new RazorError("The 'inject' keyword must be followed by a type name on the same line.", - new SourceLocation(1, 0, 1), 6) - }; - - // Act - var spans = ParseDocument(documentContent, errors); - - // Assert - Assert.Equal(expectedSpans, spans); - Assert.Equal(expectedErrors, errors); - } - - [Fact] - public void ParseInjectKeyword_ErrorOnMissingTypeName_WhenTypeNameEndsWithEOF() - { - // Arrange - var errors = new List(); - var documentContent = "@inject "; - var factory = SpanFactory.CreateCsHtml(); - var expectedSpans = new Span[] - { - factory.EmptyHtml(), - factory.CodeTransition(SyntaxConstants.TransitionString) - .Accepts(AcceptedCharacters.None), - factory.MetaCode("inject ") - .Accepts(AcceptedCharacters.None), - factory.Code(" ") - .As(new InjectParameterGenerator(string.Empty, string.Empty)) - .Accepts(AcceptedCharacters.AnyExceptNewline), - factory.EmptyHtml() - }; - var expectedErrors = new[] - { - new RazorError("The 'inject' keyword must be followed by a type name on the same line.", - new SourceLocation(1, 0, 1), 6) - }; - - // Act - var spans = ParseDocument(documentContent, errors); - - // Assert - Assert.Equal(expectedSpans, spans); - Assert.Equal(expectedErrors, errors); - } - - [Fact] - public void ParseInjectKeyword_ErrorOnMissingPropertyName() - { - // Arrange - var errors = new List(); - var documentContent = $"@inject IMyService {Environment.NewLine}Bar"; - var factory = SpanFactory.CreateCsHtml(); - var expectedSpans = new Span[] - { - factory.EmptyHtml(), - factory.CodeTransition(SyntaxConstants.TransitionString) - .Accepts(AcceptedCharacters.None), - factory.MetaCode("inject ") - .Accepts(AcceptedCharacters.None), - factory.Code(" IMyService " + Environment.NewLine) - .As(new InjectParameterGenerator("IMyService", string.Empty)) - .Accepts(AcceptedCharacters.AnyExceptNewline), - factory.Markup("Bar") - .With(new MarkupChunkGenerator()) - }; - var expectedErrors = new[] - { - new RazorError("A property name must be specified when using the 'inject' statement. " + - "Format for a 'inject' statement is '@inject '.", - new SourceLocation(1, 0, 1), 21) - }; - - // Act - var spans = ParseDocument(documentContent, errors); - - // Assert - Assert.Equal(expectedSpans, spans); - Assert.Equal(expectedErrors, errors); - } - - [Fact] - public void ParseInjectKeyword_ErrorOnMissingPropertyName_WhenTypeNameEndsWithEOF() - { - // Arrange - var errors = new List(); - var documentContent = "@inject IMyServi"; - var factory = SpanFactory.CreateCsHtml(); - var expectedSpans = new Span[] - { - factory.EmptyHtml(), - factory.CodeTransition(SyntaxConstants.TransitionString) - .Accepts(AcceptedCharacters.None), - factory.MetaCode("inject ") - .Accepts(AcceptedCharacters.None), - factory.Code(" IMyServi") - .As(new InjectParameterGenerator("IMyServi", string.Empty)) - .Accepts(AcceptedCharacters.AnyExceptNewline), - factory.EmptyHtml() - }; - var expectedErrors = new[] - { - new RazorError("A property name must be specified when using the 'inject' statement. " + - "Format for a 'inject' statement is '@inject '.", - new SourceLocation(1, 0, 1), 21) - }; - - // Act - var spans = ParseDocument(documentContent, errors); - - // Assert - Assert.Equal(expectedSpans, spans); - Assert.Equal(expectedErrors, errors); - } - - private static List ParseDocument( - string documentContents, - List errors = null, - List lineMappings = null) - { - errors = errors ?? new List(); - var markupParser = new HtmlMarkupParser(); - var codeParser = new TestMvcCSharpRazorCodeParser(); - var reader = new SeekableTextReader(documentContents); - var context = new ParserContext( - reader, - codeParser, - markupParser, - markupParser, - new ErrorSink()); - codeParser.Context = context; - markupParser.Context = context; - markupParser.ParseDocument(); - - var results = context.CompleteParse(); - errors.AddRange(results.ParserErrors); - return results.Document.Flatten().ToList(); - } - - private sealed class TestMvcCSharpRazorCodeParser : MvcRazorCodeParser - { - public bool HasDirective(string directive) - { - Action handler; - return TryGetDirectiveHandler(directive, out handler); - } - } - } -} diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/MvcRazorHostTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/MvcRazorHostTest.cs index 7749ebe427..baaeef4314 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/MvcRazorHostTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/MvcRazorHostTest.cs @@ -11,13 +11,10 @@ using System.Reflection; #if GENERATE_BASELINES using System.Text; #endif -using Microsoft.AspNetCore.Mvc.Razor.Directives; using Microsoft.AspNetCore.Mvc.Razor.Internal; using Microsoft.AspNetCore.Razor; -using Microsoft.AspNetCore.Razor.Chunks; using Microsoft.AspNetCore.Razor.Chunks.Generators; using Microsoft.AspNetCore.Razor.CodeGenerators; -using Microsoft.AspNetCore.Razor.CodeGenerators.Visitors; using Microsoft.AspNetCore.Razor.Parser; using Microsoft.AspNetCore.Razor.Runtime.TagHelpers; using Microsoft.AspNetCore.Testing; @@ -27,6 +24,8 @@ namespace Microsoft.AspNetCore.Mvc.Razor { public class MvcRazorHostTest { + +#if OLD_RAZOR private static Assembly _assembly = typeof(MvcRazorHostTest).GetTypeInfo().Assembly; public static TheoryData NormalizeChunkInheritanceUtilityPaths_Data @@ -106,22 +105,6 @@ namespace Microsoft.AspNetCore.Mvc.Razor Assert.Equal("src/file.cshtml", chunkInheritanceUtility.InheritedChunkTreePagePath, StringComparer.Ordinal); } - [Fact] - public void MvcRazorHost_EnablesInstrumentationByDefault() - { - // Arrange - var fileProvider = new TestFileProvider(); - var host = new MvcRazorHost( - new DefaultChunkTreeCache(fileProvider), - new TagHelperDescriptorResolver(designTime: false)); - - // Act - var instrumented = host.EnableInstrumentation; - - // Assert - Assert.True(instrumented); - } - [Fact] public void MvcRazorHost_GeneratesTagHelperModelExpressionCode_DesignTime() { @@ -595,148 +578,6 @@ namespace Microsoft.AspNetCore.Mvc.Razor documentLocation: new MappingLocation(documentLocation, contentLength), generatedLocation: new MappingLocation(generatedLocation, contentLength)); } - - private class PathValidatingChunkInheritanceUtility : ChunkInheritanceUtility - { - public PathValidatingChunkInheritanceUtility(MvcRazorHost razorHost, IChunkTreeCache chunkTreeCache) - : base(razorHost, chunkTreeCache, defaultInheritedChunks: new Chunk[0]) - { - } - - public string InheritedChunkTreePagePath { get; private set; } - - public override IReadOnlyList GetInheritedChunkTreeResults(string pagePath) - { - InheritedChunkTreePagePath = pagePath; - - return new ChunkTreeResult[0]; - } - } - - // Normalizes the newlines in different OS platforms. - private class MvcRazorHostWithNormalizedNewLine : MvcRazorHost - { - public MvcRazorHostWithNormalizedNewLine(IChunkTreeCache codeTreeCache) - : base(codeTreeCache, new TagHelperDescriptorResolver(designTime: false)) - { } - - public override CodeGenerator DecorateCodeGenerator( - CodeGenerator incomingBuilder, - CodeGeneratorContext context) - { - base.DecorateCodeGenerator(incomingBuilder, context); - - return new TestCSharpCodeGenerator( - context, - DefaultModel, - "Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute", - new GeneratedTagHelperAttributeContext - { - ModelExpressionTypeName = ModelExpressionType, - CreateModelExpressionMethodName = CreateModelExpressionMethod, - ModelExpressionProviderPropertyName = ModelExpressionProvider, - ViewDataPropertyName = ViewDataPropertyName - }); - } - - protected class TestCSharpCodeGenerator : MvcCSharpCodeGenerator - { - private readonly GeneratedTagHelperAttributeContext _tagHelperAttributeContext; - - public TestCSharpCodeGenerator( - CodeGeneratorContext context, - string defaultModel, - string activateAttribute, - GeneratedTagHelperAttributeContext tagHelperAttributeContext) - : base(context, defaultModel, activateAttribute, tagHelperAttributeContext) - { - _tagHelperAttributeContext = tagHelperAttributeContext; - } - - protected override CSharpCodeWriter CreateCodeWriter() - { - // We normalize newlines so no matter what platform we're on - // they're consistent (for code generation tests). - var codeWriter = base.CreateCodeWriter(); - codeWriter.NewLine = "\r\n"; - - return codeWriter; - } - } - } - - /// - /// Used when testing Tag Helpers, it disables the unique ID generation feature. - /// - private class TestMvcRazorHost : MvcRazorHost - { - public TestMvcRazorHost(IChunkTreeCache ChunkTreeCache) - : base(ChunkTreeCache, new TagHelperDescriptorResolver(designTime: false)) - { - } - - public override CodeGenerator DecorateCodeGenerator( - CodeGenerator incomingBuilder, - CodeGeneratorContext context) - { - base.DecorateCodeGenerator(incomingBuilder, context); - - return new TestCSharpCodeGenerator( - context, - DefaultModel, - "Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute", - new GeneratedTagHelperAttributeContext - { - ModelExpressionTypeName = ModelExpressionType, - CreateModelExpressionMethodName = CreateModelExpressionMethod, - ModelExpressionProviderPropertyName = ModelExpressionProvider, - ViewDataPropertyName = ViewDataPropertyName - }); - } - - protected class TestCSharpCodeGenerator : MvcCSharpCodeGenerator - { - private readonly GeneratedTagHelperAttributeContext _tagHelperAttributeContext; - - public TestCSharpCodeGenerator( - CodeGeneratorContext context, - string defaultModel, - string activateAttribute, - GeneratedTagHelperAttributeContext tagHelperAttributeContext) - : base(context, defaultModel, activateAttribute, tagHelperAttributeContext) - { - _tagHelperAttributeContext = tagHelperAttributeContext; - } - - protected override CSharpCodeVisitor CreateCSharpCodeVisitor( - CSharpCodeWriter writer, - CodeGeneratorContext context) - { - var visitor = base.CreateCSharpCodeVisitor(writer, context); - visitor.TagHelperRenderer = new NoUniqueIdsTagHelperCodeRenderer(visitor, writer, context) - { - AttributeValueCodeRenderer = - new MvcTagHelperAttributeValueCodeRenderer(_tagHelperAttributeContext) - }; - return visitor; - } - - private class NoUniqueIdsTagHelperCodeRenderer : CSharpTagHelperCodeRenderer - { - public NoUniqueIdsTagHelperCodeRenderer( - IChunkVisitor bodyVisitor, - CSharpCodeWriter writer, - CodeGeneratorContext context) - : base(bodyVisitor, writer, context) - { - } - - protected override string GenerateUniqueId() - { - return "test"; - } - } - } - } +#endif } } \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/MvcRazorParserTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/MvcRazorParserTest.cs deleted file mode 100644 index 06d31837a0..0000000000 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/MvcRazorParserTest.cs +++ /dev/null @@ -1,253 +0,0 @@ -// 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; -using System.Collections.Generic; -using System.Linq; -using Microsoft.AspNetCore.Mvc.ViewFeatures; -using Microsoft.AspNetCore.Razor; -using Microsoft.AspNetCore.Razor.Chunks; -using Microsoft.AspNetCore.Razor.Compilation.TagHelpers; -using Microsoft.AspNetCore.Razor.Parser; -using Microsoft.AspNetCore.Razor.Parser.Internal; -using Microsoft.AspNetCore.Razor.Parser.SyntaxTree; -using Moq; -using Xunit; - -namespace Microsoft.AspNetCore.Mvc.Razor -{ - public class MvcRazorCodeParserTest - { - public static TheoryData ViewImportsData - { - get - { - // chunkTrees, expectedDirectiveDescriptors - return new TheoryData - { - { - new[] { CreateChunkTree(new TagHelperPrefixDirectiveChunk { Prefix = "THP" }) }, - new[] { CreateDirectiveDescriptor("THP", TagHelperDirectiveType.TagHelperPrefix) } - }, - { - new[] { CreateChunkTree(new AddTagHelperChunk { LookupText = "ATH" }) }, - new[] { CreateDirectiveDescriptor("ATH", TagHelperDirectiveType.AddTagHelper) } - }, - { - new[] - { - CreateChunkTree( - new AddTagHelperChunk { LookupText = "ATH1" }, - new AddTagHelperChunk { LookupText = "ATH2" }) - }, - new[] - { - CreateDirectiveDescriptor("ATH1", TagHelperDirectiveType.AddTagHelper), - CreateDirectiveDescriptor("ATH2", TagHelperDirectiveType.AddTagHelper) - } - }, - { - new[] { CreateChunkTree(new RemoveTagHelperChunk { LookupText = "RTH" }) }, - new[] { CreateDirectiveDescriptor("RTH", TagHelperDirectiveType.RemoveTagHelper) } - }, - { - new[] - { - CreateChunkTree( - new RemoveTagHelperChunk { LookupText = "RTH1" }, - new RemoveTagHelperChunk { LookupText = "RTH2" }) - }, - new[] - { - CreateDirectiveDescriptor("RTH1", TagHelperDirectiveType.RemoveTagHelper), - CreateDirectiveDescriptor("RTH2", TagHelperDirectiveType.RemoveTagHelper) - } - }, - { - new[] - { - CreateChunkTree(new TagHelperPrefixDirectiveChunk { Prefix = "THP2" }), - CreateChunkTree(new TagHelperPrefixDirectiveChunk { Prefix = "THP1" }), - }, - new[] { CreateDirectiveDescriptor("THP1", TagHelperDirectiveType.TagHelperPrefix) } - }, - { - new[] - { - CreateChunkTree( - new TagHelperPrefixDirectiveChunk { Prefix = "THP" }, - new RemoveTagHelperChunk { LookupText = "RTH" }, - new AddTagHelperChunk { LookupText = "ATH" }) - }, - new[] - { - CreateDirectiveDescriptor("RTH", TagHelperDirectiveType.RemoveTagHelper), - CreateDirectiveDescriptor("ATH", TagHelperDirectiveType.AddTagHelper), - CreateDirectiveDescriptor("THP", TagHelperDirectiveType.TagHelperPrefix), - } - }, - { - new[] - { - CreateChunkTree(new RemoveTagHelperChunk { LookupText = "RTH" }), - CreateChunkTree( - new LiteralChunk { Text = "Hello world" }, - new AddTagHelperChunk { LookupText = "ATH" }), - }, - new[] - { - CreateDirectiveDescriptor("RTH", TagHelperDirectiveType.RemoveTagHelper), - CreateDirectiveDescriptor("ATH", TagHelperDirectiveType.AddTagHelper), - } - }, - { - new[] - { - CreateChunkTree(new RemoveTagHelperChunk { LookupText = "RTH" }), - CreateChunkTree( - new LiteralChunk { Text = "Hello world" }, - new AddTagHelperChunk { LookupText = "ATH" }), - CreateChunkTree(new TagHelperPrefixDirectiveChunk { Prefix = "THP" }), - }, - new[] - { - CreateDirectiveDescriptor("RTH", TagHelperDirectiveType.RemoveTagHelper), - CreateDirectiveDescriptor("ATH", TagHelperDirectiveType.AddTagHelper), - CreateDirectiveDescriptor("THP", TagHelperDirectiveType.TagHelperPrefix), - } - }, - { - new[] - { - CreateChunkTree(new TagHelperPrefixDirectiveChunk { Prefix = "THP2" }), - CreateChunkTree(new RemoveTagHelperChunk { LookupText = "RTH" }), - CreateChunkTree(new AddTagHelperChunk { LookupText = "ATH" }), - CreateChunkTree(new TagHelperPrefixDirectiveChunk { Prefix = "THP1" }), - }, - new[] - { - CreateDirectiveDescriptor("RTH", TagHelperDirectiveType.RemoveTagHelper), - CreateDirectiveDescriptor("ATH", TagHelperDirectiveType.AddTagHelper), - CreateDirectiveDescriptor("THP1", TagHelperDirectiveType.TagHelperPrefix), - } - }, - }; - } - } - - [Theory] - [MemberData(nameof(ViewImportsData))] - public void GetTagHelperDescriptors_ReturnsExpectedDirectiveDescriptors( - ChunkTree[] chunkTrees, - TagHelperDirectiveDescriptor[] expectedDirectiveDescriptors) - { - // Arrange - var builder = new BlockBuilder { Type = BlockType.Comment }; - var block = new Block(builder); - - IList descriptors = null; - var resolver = new Mock(); - resolver.Setup(r => r.Resolve(It.IsAny())) - .Callback((TagHelperDescriptorResolutionContext context) => - { - descriptors = context.DirectiveDescriptors; - }) - .Returns(Enumerable.Empty()) - .Verifiable(); - - var baseParser = new RazorParser( - new CSharpCodeParser(), - new HtmlMarkupParser(), - tagHelperDescriptorResolver: resolver.Object); - var parser = new TestableMvcRazorParser(baseParser, chunkTrees, defaultInheritedChunks: new Chunk[0]); - - // Act - parser.GetTagHelperDescriptorsPublic(block, errorSink: new ErrorSink()).ToArray(); - - // Assert - Assert.NotNull(descriptors); - Assert.Equal(expectedDirectiveDescriptors.Length, descriptors.Count); - - for (var i = 0; i < expectedDirectiveDescriptors.Length; i++) - { - var expected = expectedDirectiveDescriptors[i]; - var actual = descriptors[i]; - - Assert.Equal(expected.DirectiveText, actual.DirectiveText, StringComparer.Ordinal); - Assert.Equal(SourceLocation.Zero, actual.Location); - Assert.Equal(expected.DirectiveType, actual.DirectiveType); - } - } - - [Theory] - [InlineData("", "")] - [InlineData(" ; ", "")] - [InlineData(" ", "")] - [InlineData(";;", "")] - [InlineData("a", "a")] - [InlineData("a;", "a")] - [InlineData("abcd", "abcd")] - [InlineData("abc;d", "abc;d")] - [InlineData("a bc d", "a bc d")] - [InlineData("a\t\tbc\td\t", "a\t\tbc\td")] - [InlineData("abc;", "abc")] - [InlineData(" abc;", "abc")] - [InlineData("\tabc;", "abc")] - [InlineData(";; abc;", ";; abc")] - [InlineData(";;\tabc;", ";;\tabc")] - [InlineData("\t;;abc;", ";;abc")] - [InlineData("abc;; ;", "abc")] - [InlineData("abc;;\t;", "abc")] - [InlineData("\tabc \t;", "abc")] - [InlineData("abc;;\r\n;", "abc")] - [InlineData("abcd \n", "abcd")] - [InlineData("\r\n\r \n\t abcd \t \t \n \r\n", "abcd")] - [InlineData("pqrs\r", "pqrs")] - public void RemoveWhitespaceAndTrailingSemicolons_ReturnsExpectedValues(string input, string expectedOutput) - { - // Arrange and Act - var output = MvcRazorCodeParser.RemoveWhitespaceAndTrailingSemicolons(input); - - // Assert - Assert.Equal(expectedOutput, output, StringComparer.Ordinal); - } - - private static ChunkTree CreateChunkTree(params Chunk[] chunks) - { - return new ChunkTree - { - Children = chunks - }; - } - - private static TagHelperDirectiveDescriptor CreateDirectiveDescriptor( - string directiveText, - TagHelperDirectiveType directiveType) - { - return new TagHelperDirectiveDescriptor - { - DirectiveText = directiveText, - Location = SourceLocation.Undefined, - DirectiveType = directiveType - }; - } - - private class TestableMvcRazorParser : MvcRazorParser - { - public TestableMvcRazorParser( - RazorParser parser, - IReadOnlyList chunkTrees, - IReadOnlyList defaultInheritedChunks) - : base(parser, chunkTrees, defaultInheritedChunks, typeof(ModelExpression).FullName) - { - } - - public IEnumerable GetTagHelperDescriptorsPublic( - Block documentRoot, - ErrorSink errorSink) - { - return GetTagHelperDescriptors(documentRoot, errorSink); - } - } - } -} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/MvcTagHelperAttributeValueCodeRendererTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/MvcTagHelperAttributeValueCodeRendererTest.cs index d501bf60c7..7d873eba3e 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/MvcTagHelperAttributeValueCodeRendererTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/MvcTagHelperAttributeValueCodeRendererTest.cs @@ -11,6 +11,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor { public class MvcTagHelperAttributeValueCodeRendererTest { + #if OLD_RAZOR [Theory] [InlineData("SomeType", "SomeType", "Provider.SomeMethod(ViewData, __model => __model.MyValue)")] [InlineData("SomeType", "SomeType2", "MyValue")] @@ -55,5 +56,6 @@ namespace Microsoft.AspNetCore.Mvc.Razor // Assert Assert.Equal(expectedValue, writer.GenerateCode()); } +#endif } } \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/ViewComponentTagHelperDescriptorConventionsTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/ViewComponentTagHelperDescriptorConventionsTest.cs index 5f399fafe0..9eb24f8437 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/ViewComponentTagHelperDescriptorConventionsTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/ViewComponentTagHelperDescriptorConventionsTest.cs @@ -1,9 +1,7 @@ // 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; -using Microsoft.AspNetCore.Mvc.ViewComponents; -using Microsoft.AspNetCore.Razor.Compilation.TagHelpers; +using Microsoft.AspNetCore.Razor.Evolution; using Xunit; namespace Microsoft.AspNetCore.Mvc.Razor.Host.Test diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Test/Internal/DefaultRoslynCompilationServiceTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Test/Internal/DefaultRoslynCompilationServiceTest.cs index ed47de593e..30cf4c92ad 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Test/Internal/DefaultRoslynCompilationServiceTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Test/Internal/DefaultRoslynCompilationServiceTest.cs @@ -17,6 +17,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal { public class DefaultRoslynCompilationServiceTest { +#if OLD_RAZOR [Fact] public void Compile_ReturnsCompilationResult() { @@ -357,5 +358,6 @@ public class MyNonCustomDefinedClass {} optionsAccessor, NullLoggerFactory.Instance); } +#endif } } diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Test/Internal/RazorCompilationServiceTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Test/Internal/RazorCompilationServiceTest.cs index 0eaa04556a..957c3c8dd5 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Test/Internal/RazorCompilationServiceTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Test/Internal/RazorCompilationServiceTest.cs @@ -19,13 +19,14 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal { public class RazorCompilationServiceTest { +#if OLD_RAZOR [Theory] [InlineData(@"src\work\myapp", @"src\work\myapp\Views\index\home.cshtml")] [InlineData(@"src\work\myapp\", @"src\work\myapp\Views\index\home.cshtml")] public void CompileCalculatesRootRelativePath(string appPath, string viewPath) { // Arrange - var host = new Mock(); + var host = new Mock(); host.Setup(h => h.GenerateCode(@"Views\index\home.cshtml", It.IsAny())) .Returns(GetGeneratorResult()) .Verifiable(); @@ -222,5 +223,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal return options.Object; } + +#endif } } diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Test/MvcRazorCodeParserTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Test/MvcRazorCodeParserTest.cs deleted file mode 100644 index ccb33d75e0..0000000000 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Test/MvcRazorCodeParserTest.cs +++ /dev/null @@ -1,323 +0,0 @@ -// 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; -using System.Collections.Generic; -using System.Linq; -using Microsoft.AspNetCore.Razor; -using Microsoft.AspNetCore.Razor.Chunks.Generators; -using Microsoft.AspNetCore.Razor.Generator; -using Microsoft.AspNetCore.Razor.Parser; -using Microsoft.AspNetCore.Razor.Parser.Internal; -using Microsoft.AspNetCore.Razor.Parser.SyntaxTree; -using Microsoft.AspNetCore.Razor.Text; -using Xunit; - -namespace Microsoft.AspNetCore.Mvc.Razor.Host.Test -{ - public class MvcRazorCodeParserTest - { - [Fact] - public void Constructor_AddsModelKeyword() - { - var parser = new TestMvcCSharpRazorCodeParser(); - - Assert.True(parser.HasDirective("model")); - } - - [Fact] - public void ParseModelKeyword_HandlesSingleInstance() - { - // Arrange + Act - var document = "@model Foo"; - var spans = ParseDocument(document); - - // Assert - var factory = SpanFactory.CreateCsHtml(); - var expectedSpans = new Span[] - { - factory.EmptyHtml(), - factory.CodeTransition(SyntaxConstants.TransitionString) - .Accepts(AcceptedCharacters.None), - factory.MetaCode("model ") - .Accepts(AcceptedCharacters.None), - factory.Code(" Foo") - .As(new ModelChunkGenerator("Foo")) - .Accepts(AcceptedCharacters.AnyExceptNewline), - factory.EmptyHtml() - }; - Assert.Equal(expectedSpans, spans.ToArray()); - } - - [Fact] - public void ParseModelKeyword_HandlesNullableTypes() - { - // Arrange + Act - var document = $"@model Foo?{Environment.NewLine}Bar"; - var spans = ParseDocument(document); - - // Assert - var factory = SpanFactory.CreateCsHtml(); - var expectedSpans = new Span[] - { - factory.EmptyHtml(), - factory.CodeTransition(SyntaxConstants.TransitionString) - .Accepts(AcceptedCharacters.None), - factory.MetaCode("model ") - .Accepts(AcceptedCharacters.None), - factory.Code("Foo?" + Environment.NewLine) - .As(new ModelChunkGenerator("Foo?")) - .Accepts(AcceptedCharacters.AnyExceptNewline), - factory.Markup("Bar") - .With(new MarkupChunkGenerator()) - }; - Assert.Equal(expectedSpans, spans.ToArray()); - } - - [Fact] - public void ParseModelKeyword_HandlesArrays() - { - // Arrange + Act - var document = $"@model Foo[[]][]{Environment.NewLine}Bar"; - var spans = ParseDocument(document); - - // Assert - var factory = SpanFactory.CreateCsHtml(); - var expectedSpans = new Span[] - { - factory.EmptyHtml(), - factory.CodeTransition(SyntaxConstants.TransitionString) - .Accepts(AcceptedCharacters.None), - factory.MetaCode("model ") - .Accepts(AcceptedCharacters.None), - factory.Code("Foo[[]][]" + Environment.NewLine) - .As(new ModelChunkGenerator("Foo[[]][]")) - .Accepts(AcceptedCharacters.AnyExceptNewline), - factory.Markup("Bar") - .With(new MarkupChunkGenerator()) - }; - Assert.Equal(expectedSpans, spans.ToArray()); - } - - [Fact] - public void ParseModelKeyword_HandlesVSTemplateSyntax() - { - // Arrange + Act - var document = "@model $rootnamespace$.MyModel"; - var spans = ParseDocument(document); - - // Assert - var factory = SpanFactory.CreateCsHtml(); - var expectedSpans = new Span[] - { - factory.EmptyHtml(), - factory.CodeTransition(SyntaxConstants.TransitionString) - .Accepts(AcceptedCharacters.None), - factory.MetaCode("model ") - .Accepts(AcceptedCharacters.None), - factory.Code("$rootnamespace$.MyModel") - .As(new ModelChunkGenerator("$rootnamespace$.MyModel")) - .Accepts(AcceptedCharacters.AnyExceptNewline), - factory.EmptyHtml() - }; - Assert.Equal(expectedSpans, spans.ToArray()); - } - - [Fact] - public void ParseModelKeyword_ErrorOnMissingModelType() - { - // Arrange + Act - List errors = new List(); - var document = "@model "; - var spans = ParseDocument(document, errors); - - // Assert - var factory = SpanFactory.CreateCsHtml(); - var expectedSpans = new Span[] - { - factory.EmptyHtml(), - factory.CodeTransition(SyntaxConstants.TransitionString) - .Accepts(AcceptedCharacters.None), - factory.MetaCode("model ") - .Accepts(AcceptedCharacters.None), - factory.Code(" ") - .As(new ModelChunkGenerator(string.Empty)) - .Accepts(AcceptedCharacters.AnyExceptNewline), - factory.EmptyHtml() - }; - var expectedErrors = new[] - { - new RazorError("The 'model' keyword must be followed by a type name on the same line.", new SourceLocation(1, 0, 1), 5) - }; - Assert.Equal(expectedSpans, spans.ToArray()); - Assert.Equal(expectedErrors, errors.ToArray()); - } - - [Fact] - public void ParseModelKeyword_ErrorOnMultipleModelStatements() - { - // Arrange + Act - List errors = new List(); - var document = - "@model Foo" + Environment.NewLine - + "@model Bar"; - var spans = ParseDocument(document, errors); - - // Assert - var factory = SpanFactory.CreateCsHtml(); - var expectedSpans = new Span[] - { - factory.EmptyHtml(), - factory.CodeTransition(SyntaxConstants.TransitionString) - .Accepts(AcceptedCharacters.None), - factory.MetaCode("model ") - .Accepts(AcceptedCharacters.None), - factory.Code("Foo" + Environment.NewLine) - .As(new ModelChunkGenerator("Foo")) - .Accepts(AcceptedCharacters.AnyExceptNewline), - factory.EmptyHtml(), - factory.CodeTransition(SyntaxConstants.TransitionString) - .Accepts(AcceptedCharacters.None), - factory.MetaCode("model ") - .Accepts(AcceptedCharacters.None), - factory.Code("Bar") - .As(new ModelChunkGenerator("Bar")) - .Accepts(AcceptedCharacters.AnyExceptNewline), - factory.EmptyHtml() - }; - - var expectedErrors = new[] - { - new RazorError( - "Only one 'model' statement is allowed in a file.", - PlatformNormalizer.NormalizedSourceLocation(13, 1, 1), - 5) - }; - expectedSpans.Zip(spans, (exp, span) => new { expected = exp, span = span }).ToList().ForEach(i => Assert.Equal(i.expected, i.span)); - Assert.Equal(expectedSpans, spans.ToArray()); - Assert.Equal(expectedErrors, errors.ToArray()); - } - - [Fact] - public void ParseModelKeyword_ErrorOnModelFollowedByInherits() - { - // Arrange + Act - List errors = new List(); - var document = - "@model Foo" + Environment.NewLine - + "@inherits Bar"; - var spans = ParseDocument(document, errors); - - // Assert - var factory = SpanFactory.CreateCsHtml(); - var expectedSpans = new Span[] - { - factory.EmptyHtml(), - factory.CodeTransition(SyntaxConstants.TransitionString) - .Accepts(AcceptedCharacters.None), - factory.MetaCode("model ") - .Accepts(AcceptedCharacters.None), - factory.Code("Foo" + Environment.NewLine) - .As(new ModelChunkGenerator("Foo")) - .Accepts(AcceptedCharacters.AnyExceptNewline), - factory.EmptyHtml(), - factory.CodeTransition(SyntaxConstants.TransitionString) - .Accepts(AcceptedCharacters.None), - factory.MetaCode("inherits ") - .Accepts(AcceptedCharacters.None), - factory.Code("Bar") - .As(new SetBaseTypeChunkGenerator("Bar")) - .Accepts(AcceptedCharacters.AnyExceptNewline), - factory.EmptyHtml() - }; - - var expectedErrors = new[] - { - new RazorError( - "The 'inherits' keyword is not allowed when a 'model' keyword is used.", - PlatformNormalizer.NormalizedSourceLocation(21, 1, 9), - length: 8) - }; - expectedSpans.Zip(spans, (exp, span) => new { expected = exp, span = span }).ToList().ForEach(i => Assert.Equal(i.expected, i.span)); - Assert.Equal(expectedSpans, spans.ToArray()); - Assert.Equal(expectedErrors, errors.ToArray()); - } - - [Fact] - public void ParseModelKeyword_ErrorOnInheritsFollowedByModel() - { - // Arrange + Act - List errors = new List(); - var document = - "@inherits Bar" + Environment.NewLine - + "@model Foo"; - var spans = ParseDocument(document, errors); - - // Assert - var factory = SpanFactory.CreateCsHtml(); - var expectedSpans = new Span[] - { - factory.EmptyHtml(), - factory.CodeTransition(SyntaxConstants.TransitionString) - .Accepts(AcceptedCharacters.None), - factory.MetaCode("inherits ") - .Accepts(AcceptedCharacters.None), - factory.Code("Bar" + Environment.NewLine) - .As(new SetBaseTypeChunkGenerator("Bar")) - .Accepts(AcceptedCharacters.AnyExceptNewline), - factory.EmptyHtml(), - factory.CodeTransition(SyntaxConstants.TransitionString) - .Accepts(AcceptedCharacters.None), - factory.MetaCode("model ") - .Accepts(AcceptedCharacters.None), - factory.Code("Foo") - .As(new ModelChunkGenerator("Foo")) - .Accepts(AcceptedCharacters.AnyExceptNewline), - factory.EmptyHtml() - }; - - var expectedErrors = new[] - { - new RazorError( - "The 'inherits' keyword is not allowed when a 'model' keyword is used.", - new SourceLocation(9, 0, 9), - length: 8) - }; - expectedSpans.Zip(spans, (exp, span) => new { expected = exp, span = span }).ToList().ForEach(i => Assert.Equal(i.expected, i.span)); - Assert.Equal(expectedSpans, spans.ToArray()); - Assert.Equal(expectedErrors, errors.ToArray()); - } - - private static List ParseDocument(string documentContents, IList errors = null) - { - errors = errors ?? new List(); - var markupParser = new HtmlMarkupParser(); - var codeParser = new TestMvcCSharpRazorCodeParser(); - var context = new ParserContext( - new SeekableTextReader(documentContents), - codeParser, - markupParser, - markupParser, - new ErrorSink()); - codeParser.Context = context; - markupParser.Context = context; - markupParser.ParseDocument(); - - ParserResults results = context.CompleteParse(); - foreach (RazorError error in results.ParserErrors) - { - errors.Add(error); - } - return results.Document.Flatten().ToList(); - } - - private sealed class TestMvcCSharpRazorCodeParser : MvcRazorCodeParser - { - public bool HasDirective(string directive) - { - Action handler; - return TryGetDirectiveHandler(directive, out handler); - } - } - } -} diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Test/RazorPageTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Test/RazorPageTest.cs index 56cba25a0d..cb076afc5c 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Test/RazorPageTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Test/RazorPageTest.cs @@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor { public class RazorPageTest { - private readonly RenderAsyncDelegate _nullRenderAsyncDelegate = writer => Task.FromResult(0); + private readonly RenderAsyncDelegate _nullRenderAsyncDelegate = () => Task.FromResult(0); private readonly Func NullAsyncWrite = writer => writer.WriteAsync(string.Empty); [Fact] @@ -443,7 +443,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor }); page.PreviousSectionWriters = new Dictionary { - { "bar", writer => writer.WriteAsync(expected) } + { "bar", () => page.Output.WriteAsync(expected) } }; // Act @@ -767,7 +767,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor page.PreviousSectionWriters = new Dictionary { { "ignored", _nullRenderAsyncDelegate }, - { "not-ignored-section", writer => writer.WriteAsync("not-ignored-section-content") } + { "not-ignored-section", () => page.Output.WriteAsync("not-ignored-section-content") } }; // Act @@ -826,16 +826,16 @@ namespace Microsoft.AspNetCore.Mvc.Razor page.PreviousSectionWriters = new Dictionary { { - "footer", writer => writer.WriteLineAsync("Footer section") + "footer", () => page.Output.WriteLineAsync("Footer section") }, { - "header", writer => writer.WriteLineAsync("Header section") + "header", () => page.Output.WriteLineAsync("Header section") }, { - "async-header", writer => writer.WriteLineAsync("Async Header section") + "async-header", () => page.Output.WriteLineAsync("Async Header section") }, { - "async-footer", writer => writer.WriteLineAsync("Async Footer section") + "async-footer", () => page.Output.WriteLineAsync("Async Footer section") }, }; @@ -928,7 +928,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor var page = CreatePage(p => { p.Layout = "bar"; - p.DefineSection("test-section", async _ => + p.DefineSection("test-section", async () => { await p.FlushAsync(); }); @@ -940,7 +940,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor // Assert (does not throw) var renderAsyncDelegate = page.SectionWriters["test-section"]; - await renderAsyncDelegate(TextWriter.Null); + await renderAsyncDelegate(); } [Fact] diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Test/RazorViewTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Test/RazorViewTest.cs index 068727a67e..ce5dc500da 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Test/RazorViewTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Test/RazorViewTest.cs @@ -26,7 +26,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor private const string LayoutPath = "~/Shared/_Layout.cshtml"; #pragma warning disable 1998 - private readonly RenderAsyncDelegate _nullRenderAsyncDelegate = async writer => { }; + private readonly RenderAsyncDelegate _nullRenderAsyncDelegate = async () => { }; #pragma warning restore 1998 [Fact] @@ -601,13 +601,13 @@ namespace Microsoft.AspNetCore.Mvc.Razor v.HtmlEncoder = htmlEncoder; v.WriteLiteral("body-content"); v.Layout = LayoutPath; - v.DefineSection("head", async writer => + v.DefineSection("head", async () => { - await writer.WriteAsync("head-content"); + await v.Output.WriteAsync("head-content"); }); - v.DefineSection("foot", async writer => + v.DefineSection("foot", async () => { - await writer.WriteAsync("foot-content"); + await v.Output.WriteAsync("foot-content"); }); }); var layout = new TestableRazorPage(v => @@ -702,9 +702,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor { v.HtmlEncoder = htmlEncoder; v.Layout = "~/Shared/Layout1.cshtml"; - v.DefineSection("foo", async writer => + v.DefineSection("foo", async () => { - await writer.WriteAsync("page-section-content"); + await v.Output.WriteAsync("page-section-content"); }); }); var nestedLayout = new TestableRazorPage(v => @@ -712,9 +712,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor v.HtmlEncoder = htmlEncoder; v.Layout = "~/Shared/Layout2.cshtml"; v.RenderBodyPublic(); - v.DefineSection("foo", async writer => + v.DefineSection("foo", async () => { - await writer.WriteLineAsync("layout-section-content"); + await v.Output.WriteLineAsync("layout-section-content"); await v.RenderSectionAsync("foo"); }); }) @@ -769,9 +769,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor v.HtmlEncoder = htmlEncoder; v.Layout = "NestedLayout"; v.WriteLiteral("Page body content that will not be written"); - v.DefineSection("sectionA", async writer => + v.DefineSection("sectionA", async () => { - await writer.WriteAsync("page-section-content"); + await v.Output.WriteAsync("page-section-content"); }); }); var nestedLayout = new TestableRazorPage(v => @@ -779,9 +779,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor v.HtmlEncoder = htmlEncoder; v.Layout = "Layout"; v.WriteLiteral("Nested layout content that will not be written"); - v.DefineSection("sectionB", async writer => + v.DefineSection("sectionB", async () => { - await writer.WriteLineAsync("layout-section-content"); + await v.Output.WriteLineAsync("layout-section-content"); await v.RenderSectionAsync("sectionA"); }); }); @@ -832,9 +832,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor v.HtmlEncoder = htmlEncoder; v.Layout = "~/Shared/Layout1.cshtml"; v.WriteLiteral("BodyContent"); - v.DefineSection("foo", async writer => + v.DefineSection("foo", async () => { - await writer.WriteLineAsync("foo-content"); + await v.Output.WriteLineAsync("foo-content"); }); }); var nestedLayout = new TestableRazorPage(v => @@ -843,7 +843,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor v.Layout = "~/Shared/Layout2.cshtml"; v.Write("NestedLayout" + Environment.NewLine); v.RenderBodyPublic(); - v.DefineSection("foo", async _ => + v.DefineSection("foo", async () => { await v.RenderSectionAsync("foo"); }); @@ -894,9 +894,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor v.HtmlEncoder = htmlEncoder; v.Layout = "~/Shared/Layout1.cshtml"; v.WriteLiteral("BodyContent"); - v.DefineSection("foo", async writer => + v.DefineSection("foo", async () => { - await writer.WriteLineAsync("foo-content"); + await v.Output.WriteLineAsync("foo-content"); }); }) { @@ -909,9 +909,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor v.Layout = "~/Shared/Layout2.cshtml"; v.Write("NestedLayout" + Environment.NewLine); v.RenderBodyPublic(); - v.DefineSection("foo", async writer => + v.DefineSection("foo", async () => { - await writer.WriteLineAsync("dont-render-inner-foo"); + await v.Output.WriteLineAsync("dont-render-inner-foo"); }); }) { @@ -1003,9 +1003,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor var page = new TestableRazorPage(v => { v.HtmlEncoder = htmlEncoder; - v.DefineSection("foo", async writer => + v.DefineSection("foo", async () => { - await writer.WriteLineAsync("foo-content"); + await v.Output.WriteLineAsync("foo-content"); }); v.Layout = "~/Shared/Layout1.cshtml"; v.WriteLiteral("body-content"); @@ -1015,7 +1015,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor v.HtmlEncoder = htmlEncoder; v.Write("layout-1" + Environment.NewLine); v.Write(v.RenderSection("foo")); - v.DefineSection("bar", writer => writer.WriteLineAsync("bar-content")); + v.DefineSection("bar", () => v.Output.WriteLineAsync("bar-content")); v.RenderBodyPublic(); v.Layout = "~/Shared/Layout2.cshtml"; }); @@ -1068,9 +1068,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor var page = new TestableRazorPage(v => { v.HtmlEncoder = htmlEncoder; - v.DefineSection("foo", async writer => + v.DefineSection("foo", async () => { - await writer.WriteLineAsync("foo-content"); + await v.Output.WriteLineAsync("foo-content"); }); v.Layout = "Layout1.cshtml"; v.WriteLiteral("body-content"); @@ -1084,7 +1084,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor v.HtmlEncoder = htmlEncoder; v.Write("layout-1" + Environment.NewLine); v.Write(v.RenderSection("foo")); - v.DefineSection("bar", writer => writer.WriteLineAsync("bar-content")); + v.DefineSection("bar", () => v.Output.WriteLineAsync("bar-content")); v.RenderBodyPublic(); v.Layout = "Layout2.cshtml"; }) @@ -1238,9 +1238,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor v.HtmlEncoder = htmlEncoder; v.Layout = "~/Shared/Layout1.cshtml"; v.WriteLiteral("BodyContent"); - v.DefineSection("foo", async writer => + v.DefineSection("foo", async () => { - await writer.WriteLineAsync("foo-content"); + await v.Output.WriteLineAsync("foo-content"); }); }); var nestedLayout = new TestableRazorPage(v => @@ -1249,9 +1249,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor v.Layout = "~/Shared/Layout2.cshtml"; v.Write("NestedLayout" + Environment.NewLine); v.RenderBodyPublic(); - v.DefineSection("foo", async writer => + v.DefineSection("foo", async () => { - await writer.WriteLineAsync(htmlEncoder.Encode(v.RenderSection("foo").ToString())); + await v.Output.WriteLineAsync(htmlEncoder.Encode(v.RenderSection("foo").ToString())); }); }); nestedLayout.Path = "~/Shared/Layout1.cshtml"; @@ -1306,7 +1306,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor v.HtmlEncoder = htmlEncoder; v.Layout = "layout-1"; v.WriteLiteral("body content" + Environment.NewLine); - v.DefineSection("foo", async _ => + v.DefineSection("foo", async () => { v.WriteLiteral("section-content-1" + Environment.NewLine); await v.FlushAsync(); @@ -1360,7 +1360,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor { v.HtmlEncoder = htmlEncoder; v.Layout = "layout-1"; - v.DefineSection("foo", async _ => + v.DefineSection("foo", async () => { v.WriteLiteral("section-content-1" + Environment.NewLine); await v.FlushAsync(); @@ -1437,9 +1437,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor { v.Path = "/Views/TestPath/Test.cshtml"; v.HtmlEncoder = new HtmlTestEncoder(); - v.DefineSection("foo", async writer => + v.DefineSection("foo", async () => { - writer.WriteLine("foo-content"); + v.Output.WriteLine("foo-content"); await v.FlushAsync(); }); v.Layout = "~/Shared/Layout1.cshtml"; @@ -1450,7 +1450,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor v.HtmlEncoder = new HtmlTestEncoder(); v.Write("layout-1" + Environment.NewLine); v.Write(v.RenderSection("foo")); - v.DefineSection("bar", writer => writer.WriteLineAsync("bar-content")); + v.DefineSection("bar", () => v.Output.WriteLineAsync("bar-content")); v.RenderBodyPublic(); v.Layout = "~/Shared/Layout2.cshtml"; }); diff --git a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Infrastructure/PageActionDescriptorProviderTest.cs b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Infrastructure/PageActionDescriptorProviderTest.cs index b1040ac812..7b6362903e 100644 --- a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Infrastructure/PageActionDescriptorProviderTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Infrastructure/PageActionDescriptorProviderTest.cs @@ -11,6 +11,7 @@ using Microsoft.Extensions.Options; using Moq; using Xunit; using Microsoft.AspNetCore.Razor.Evolution; +using Microsoft.AspNetCore.Mvc.Razor.Internal; namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure { @@ -298,7 +299,5 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure return new DefaultRazorProjectItem(testFileInfo, basePath, path); } - - } } diff --git a/test/WebSites/BasicWebSite/Views/Shared/Components/PassThrough/Default.cshtml b/test/WebSites/BasicWebSite/Views/Shared/Components/PassThrough/Default.cshtml index 87248ac689..e471138939 100644 --- a/test/WebSites/BasicWebSite/Views/Shared/Components/PassThrough/Default.cshtml +++ b/test/WebSites/BasicWebSite/Views/Shared/Components/PassThrough/Default.cshtml @@ -1,3 +1,2 @@ @model long -

The passed through value was: @Model

\ No newline at end of file diff --git a/test/WebSites/HtmlGenerationWebSite/Views/CheckViewData/Components/CheckViewData/Default.cshtml b/test/WebSites/HtmlGenerationWebSite/Views/CheckViewData/Components/CheckViewData/Default.cshtml index 44c2026cc1..a9aa5a7824 100644 --- a/test/WebSites/HtmlGenerationWebSite/Views/CheckViewData/Components/CheckViewData/Default.cshtml +++ b/test/WebSites/HtmlGenerationWebSite/Views/CheckViewData/Components/CheckViewData/Default.cshtml @@ -1,7 +1,6 @@ @using HtmlGenerationWebSite.Models @using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata @model ViewModel - @{ var metadata = ViewData.ModelMetadata; } diff --git a/test/WebSites/HtmlGenerationWebSite/Views/CheckViewData/DisplayTemplates/Int32.cshtml b/test/WebSites/HtmlGenerationWebSite/Views/CheckViewData/DisplayTemplates/Int32.cshtml index 1ffc68323b..f3b7fea4fd 100644 --- a/test/WebSites/HtmlGenerationWebSite/Views/CheckViewData/DisplayTemplates/Int32.cshtml +++ b/test/WebSites/HtmlGenerationWebSite/Views/CheckViewData/DisplayTemplates/Int32.cshtml @@ -1,7 +1,6 @@ @using HtmlGenerationWebSite.Models @using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata @model int? - @{ var metadata = ViewData.ModelMetadata; } diff --git a/test/WebSites/HtmlGenerationWebSite/Views/CheckViewData/DisplayTemplates/Int64.cshtml b/test/WebSites/HtmlGenerationWebSite/Views/CheckViewData/DisplayTemplates/Int64.cshtml index f436e067af..63eaa7c01e 100644 --- a/test/WebSites/HtmlGenerationWebSite/Views/CheckViewData/DisplayTemplates/Int64.cshtml +++ b/test/WebSites/HtmlGenerationWebSite/Views/CheckViewData/DisplayTemplates/Int64.cshtml @@ -1,7 +1,6 @@ @using HtmlGenerationWebSite.Models @using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata @model long? - @{ var metadata = ViewData.ModelMetadata; } diff --git a/test/WebSites/HtmlGenerationWebSite/Views/CheckViewData/DisplayTemplates/TemplateModel.cshtml b/test/WebSites/HtmlGenerationWebSite/Views/CheckViewData/DisplayTemplates/TemplateModel.cshtml index 12ea51887c..2c932190ac 100644 --- a/test/WebSites/HtmlGenerationWebSite/Views/CheckViewData/DisplayTemplates/TemplateModel.cshtml +++ b/test/WebSites/HtmlGenerationWebSite/Views/CheckViewData/DisplayTemplates/TemplateModel.cshtml @@ -1,7 +1,6 @@ @using HtmlGenerationWebSite.Models @using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata @model TemplateModel - @{ var metadata = ViewData.ModelMetadata; } diff --git a/test/WebSites/HtmlGenerationWebSite/Views/CheckViewData/DisplayTemplates/ViewModel.cshtml b/test/WebSites/HtmlGenerationWebSite/Views/CheckViewData/DisplayTemplates/ViewModel.cshtml index 01bac15c3b..65ef29ba72 100644 --- a/test/WebSites/HtmlGenerationWebSite/Views/CheckViewData/DisplayTemplates/ViewModel.cshtml +++ b/test/WebSites/HtmlGenerationWebSite/Views/CheckViewData/DisplayTemplates/ViewModel.cshtml @@ -1,7 +1,6 @@ @using HtmlGenerationWebSite.Models @using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata @model ViewModel - @{ var metadata = ViewData.ModelMetadata; } diff --git a/test/WebSites/HtmlGenerationWebSite/Views/CheckViewData/PartialForViewModel.cshtml b/test/WebSites/HtmlGenerationWebSite/Views/CheckViewData/PartialForViewModel.cshtml index 5e19e180f6..36f206127a 100644 --- a/test/WebSites/HtmlGenerationWebSite/Views/CheckViewData/PartialForViewModel.cshtml +++ b/test/WebSites/HtmlGenerationWebSite/Views/CheckViewData/PartialForViewModel.cshtml @@ -1,7 +1,6 @@ @using HtmlGenerationWebSite.Models @using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata @model ViewModel - @{ var metadata = ViewData.ModelMetadata; } diff --git a/test/WebSites/HtmlGenerationWebSite/Views/HtmlGeneration_Home/EditorTemplates/Employee.cshtml b/test/WebSites/HtmlGenerationWebSite/Views/HtmlGeneration_Home/EditorTemplates/Employee.cshtml index e8a4681706..c052f7a9eb 100644 --- a/test/WebSites/HtmlGenerationWebSite/Views/HtmlGeneration_Home/EditorTemplates/Employee.cshtml +++ b/test/WebSites/HtmlGenerationWebSite/Views/HtmlGeneration_Home/EditorTemplates/Employee.cshtml @@ -1,5 +1,4 @@ @model HtmlGenerationWebSite.Models.Employee - @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
diff --git a/test/WebSites/HtmlGenerationWebSite/Views/HtmlGeneration_Home/ItemUsingSharedEditorTemplate.cshtml b/test/WebSites/HtmlGenerationWebSite/Views/HtmlGeneration_Home/ItemUsingSharedEditorTemplate.cshtml index 85de35fa58..2e49de9d5a 100644 --- a/test/WebSites/HtmlGenerationWebSite/Views/HtmlGeneration_Home/ItemUsingSharedEditorTemplate.cshtml +++ b/test/WebSites/HtmlGenerationWebSite/Views/HtmlGeneration_Home/ItemUsingSharedEditorTemplate.cshtml @@ -1,5 +1,4 @@ @using HtmlGenerationWebSite.Models @model Item - @Html.EditorFor(model => model.Name) @Html.Editor("Id") diff --git a/test/WebSites/HtmlGenerationWebSite/Views/HtmlGeneration_Home/_ProductPartial.cshtml b/test/WebSites/HtmlGenerationWebSite/Views/HtmlGeneration_Home/_ProductPartial.cshtml index 166fc4cb87..a71025b7c1 100644 --- a/test/WebSites/HtmlGenerationWebSite/Views/HtmlGeneration_Home/_ProductPartial.cshtml +++ b/test/WebSites/HtmlGenerationWebSite/Views/HtmlGeneration_Home/_ProductPartial.cshtml @@ -1,5 +1,4 @@ @model HtmlGenerationWebSite.Models.Product - @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
diff --git a/test/WebSites/HtmlGenerationWebSite/Views/Shared/DisplayTemplates/DayOfWeek.cshtml b/test/WebSites/HtmlGenerationWebSite/Views/Shared/DisplayTemplates/DayOfWeek.cshtml index cfe576c195..ec91752e11 100644 --- a/test/WebSites/HtmlGenerationWebSite/Views/Shared/DisplayTemplates/DayOfWeek.cshtml +++ b/test/WebSites/HtmlGenerationWebSite/Views/Shared/DisplayTemplates/DayOfWeek.cshtml @@ -1,5 +1,4 @@ @model HtmlGenerationWebSite.Models.DayOfWeek - @switch (Model) { case HtmlGenerationWebSite.Models.DayOfWeek.Monday: diff --git a/test/WebSites/RazorPageExecutionInstrumentationWebSite/TestRazorCompilationService.cs b/test/WebSites/RazorPageExecutionInstrumentationWebSite/TestRazorCompilationService.cs index d9b8410710..729ce64d7f 100644 --- a/test/WebSites/RazorPageExecutionInstrumentationWebSite/TestRazorCompilationService.cs +++ b/test/WebSites/RazorPageExecutionInstrumentationWebSite/TestRazorCompilationService.cs @@ -3,10 +3,9 @@ using System.IO; using System.Text; -using Microsoft.AspNetCore.Mvc.Razor; using Microsoft.AspNetCore.Mvc.Razor.Compilation; using Microsoft.AspNetCore.Mvc.Razor.Internal; -using Microsoft.AspNetCore.Razor.CodeGenerators; +using Microsoft.AspNetCore.Razor.Evolution; using Microsoft.Extensions.Logging; namespace RazorPageExecutionInstrumentationWebSite @@ -15,14 +14,15 @@ namespace RazorPageExecutionInstrumentationWebSite { public TestRazorCompilationService( ICompilationService compilationService, - IMvcRazorHost razorHost, + RazorEngine engine, + RazorProject project, IRazorViewEngineFileProviderAccessor fileProviderAccessor, ILoggerFactory loggerFactory) - : base(compilationService, razorHost, fileProviderAccessor, loggerFactory) + : base(compilationService, engine, project, fileProviderAccessor, loggerFactory) { } - protected override GeneratorResults GenerateCode(string relativePath, Stream inputStream) + protected override RazorCodeDocument CreateCodeDocument(string relativePath, Stream inputStream) { // Normalize line endings to '\r\n' (CRLF). This removes core.autocrlf, core.eol, core.safecrlf, and // .gitattributes from the equation and treats "\r\n" and "\n" as equivalent. Does not handle @@ -36,7 +36,7 @@ namespace RazorPageExecutionInstrumentationWebSite var bytes = Encoding.UTF8.GetBytes(text); inputStream = new MemoryStream(bytes); - return base.GenerateCode(relativePath, inputStream); + return base.CreateCodeDocument(relativePath, inputStream); } } } \ No newline at end of file diff --git a/test/WebSites/RazorWebSite/Views/FlushPoint/PageWithPartialsAndViewComponents.cshtml b/test/WebSites/RazorWebSite/Views/FlushPoint/PageWithPartialsAndViewComponents.cshtml index 3c728f2ef0..7d31bd9218 100644 --- a/test/WebSites/RazorWebSite/Views/FlushPoint/PageWithPartialsAndViewComponents.cshtml +++ b/test/WebSites/RazorWebSite/Views/FlushPoint/PageWithPartialsAndViewComponents.cshtml @@ -1,5 +1,4 @@ @inject TaskReturningService TaskReturningService - @{ Layout = "/Views/Shared/_LayoutWithPartialAndFlush.cshtml"; ViewBag.Title = "FlushAsync invoked inside RenderSection"; diff --git a/test/WebSites/RazorWebSite/Views/FlushPoint/PageWithSectionInvokedViaRenderSectionAsync.cshtml b/test/WebSites/RazorWebSite/Views/FlushPoint/PageWithSectionInvokedViaRenderSectionAsync.cshtml index a386653b73..f500cbf493 100644 --- a/test/WebSites/RazorWebSite/Views/FlushPoint/PageWithSectionInvokedViaRenderSectionAsync.cshtml +++ b/test/WebSites/RazorWebSite/Views/FlushPoint/PageWithSectionInvokedViaRenderSectionAsync.cshtml @@ -1,5 +1,4 @@ @inject TaskReturningService TaskReturningService - @{ Layout = "/Views/Shared/_LayoutWithRenderSectionAsync.cshtml"; ViewBag.Title = "FlushAsync invoked inside RenderSectionAsync"; diff --git a/test/WebSites/RazorWebSite/Views/HtmlHelperOptions/HtmlHelperOptionsDefaultsInPartialView.cshtml b/test/WebSites/RazorWebSite/Views/HtmlHelperOptions/HtmlHelperOptionsDefaultsInPartialView.cshtml index fdf768fe8d..4cfc57f63a 100644 --- a/test/WebSites/RazorWebSite/Views/HtmlHelperOptions/HtmlHelperOptionsDefaultsInPartialView.cshtml +++ b/test/WebSites/RazorWebSite/Views/HtmlHelperOptions/HtmlHelperOptionsDefaultsInPartialView.cshtml @@ -1,5 +1,4 @@ @model RazorWebSite.Controllers.DateModel - @Html.ValidationSummary(true, "MySummary") @Html.ValidationMessage("Error") @Html.TextBox("Prefix.Property1") diff --git a/test/WebSites/RazorWebSite/Views/HtmlHelperOptions/HtmlHelperOptionsDefaultsInView.cshtml b/test/WebSites/RazorWebSite/Views/HtmlHelperOptions/HtmlHelperOptionsDefaultsInView.cshtml index 969a2187fb..88477de19c 100644 --- a/test/WebSites/RazorWebSite/Views/HtmlHelperOptions/HtmlHelperOptionsDefaultsInView.cshtml +++ b/test/WebSites/RazorWebSite/Views/HtmlHelperOptions/HtmlHelperOptionsDefaultsInView.cshtml @@ -1,5 +1,4 @@ @model RazorWebSite.Controllers.DateModel - @Html.ValidationSummary(true, "MySummary") @Html.ValidationMessage("Error") @Html.TextBox("Prefix.Property1") diff --git a/test/WebSites/TagHelpersWebSite/Views/Employee/Create.cshtml b/test/WebSites/TagHelpersWebSite/Views/Employee/Create.cshtml index f8e5476d99..21aaa01baa 100644 --- a/test/WebSites/TagHelpersWebSite/Views/Employee/Create.cshtml +++ b/test/WebSites/TagHelpersWebSite/Views/Employee/Create.cshtml @@ -1,5 +1,4 @@ @model TagHelpersWebSite.Models.Employee - @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers @{ diff --git a/test/WebSites/TagHelpersWebSite/Views/Employee/Details.cshtml b/test/WebSites/TagHelpersWebSite/Views/Employee/Details.cshtml index 34420f35c4..2393a00652 100644 --- a/test/WebSites/TagHelpersWebSite/Views/Employee/Details.cshtml +++ b/test/WebSites/TagHelpersWebSite/Views/Employee/Details.cshtml @@ -1,5 +1,4 @@ @model TagHelpersWebSite.Models.Employee - @{ Layout = null; } diff --git a/test/WebSites/TagHelpersWebSite/Views/Home/Index.cshtml b/test/WebSites/TagHelpersWebSite/Views/Home/Index.cshtml index 2af1cd0a61..77699bd939 100644 --- a/test/WebSites/TagHelpersWebSite/Views/Home/Index.cshtml +++ b/test/WebSites/TagHelpersWebSite/Views/Home/Index.cshtml @@ -1,53 +1,52 @@ -@using TagHelpersWebSite.Models -@using Microsoft.AspNetCore.Mvc.Razor - -@model WebsiteContext - -@{ - ViewBag.Title = "Home Page"; -} - -@addTagHelper *, TagHelpersWebSite - -@section css { - -} - -@functions { - public void RenderTemplate(string title, Func template) - { - Output.WriteLine("

Rendering Template:

"); - var helperResult = template(title); - helperResult.WriteTo(Output, HtmlEncoder); - } -} - -
-

This website has not been approved yet. Visit www.contoso.com for more information.

-
- -
-

Current Tag Cloud from Tag Helper

- -

Current Tag Cloud from ViewComponentHelper:

-
@await Component.InvokeAsync("Tags", new { count = 15 })
- @{ - RenderTemplate( - "Tag Cloud from Template: ", - @

@item

); - } -
- +@using TagHelpersWebSite.Models +@using Microsoft.AspNetCore.Mvc.Razor + +@model WebsiteContext +@{ + ViewBag.Title = "Home Page"; +} + +@addTagHelper *, TagHelpersWebSite + +@section css { + +} + +@functions { + public void RenderTemplate(string title, Func template) + { + Output.WriteLine("

Rendering Template:

"); + var helperResult = template(title); + helperResult.WriteTo(Output, HtmlEncoder); + } +} + +
+

This website has not been approved yet. Visit www.contoso.com for more information.

+
+ +
+

Current Tag Cloud from Tag Helper

+ +

Current Tag Cloud from ViewComponentHelper:

+
@await Component.InvokeAsync("Tags", new { count = 15 })
+ @{ + RenderTemplate( + "Tag Cloud from Template: ", + @

@item

); + } +
+

Dictionary Valued Model Expression

-
- -@section footerContent { -

© @Model.CopyrightYear - My ASP.NET Application

+
+ +@section footerContent { +

© @Model.CopyrightYear - My ASP.NET Application

} \ No newline at end of file diff --git a/test/WebSites/TagHelpersWebSite/Views/Shared/Components/Generic/Default.cshtml b/test/WebSites/TagHelpersWebSite/Views/Shared/Components/Generic/Default.cshtml index 2a81b86c2a..da3df2e9a5 100644 --- a/test/WebSites/TagHelpersWebSite/Views/Shared/Components/Generic/Default.cshtml +++ b/test/WebSites/TagHelpersWebSite/Views/Shared/Components/Generic/Default.cshtml @@ -1,5 +1,4 @@ @model Dictionary> -
Items:
@foreach (var item in Model)