Merge remote-tracking branch 'Razor/rybrande/release21ToSrc' into rybrande/Mondo2.1

This commit is contained in:
Ryan Brandenburg 2018-11-27 10:57:43 -08:00
commit 137bf3dde7
2005 changed files with 226205 additions and 0 deletions

56
src/Razor/.editorconfig Normal file
View File

@ -0,0 +1,56 @@
# EditorConfig is awesome:http://EditorConfig.org
# top-most EditorConfig file
root = true
# Don't use tabs for indentation.
[*]
indent_style = space
# (Please don't specify an indent_size here; that has too many unintended consequences.)
# Code files
[*.{cs,csx,vb,vbx}]
indent_size = 4
# Xml project files
[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]
indent_size = 2
# Xml config files
[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}]
indent_size = 2
# JSON files
[*.json]
indent_size = 2
# Dotnet code style settings:
[*.cs]
# Sort using and Import directives with System.* appearing first
dotnet_sort_system_directives_first = true
# Don't use this. qualifier
dotnet_style_qualification_for_field = false:suggestion
dotnet_style_qualification_for_property = false:suggestion
# use int x = .. over Int32
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
# use int.MaxValue over Int32.MaxValue
dotnet_style_predefined_type_for_member_access = true:suggestion
# Require var all the time.
csharp_style_var_for_built_in_types = true:suggestion
csharp_style_var_when_type_is_apparent = true:suggestion
csharp_style_var_elsewhere = true:suggestion
# Disallow throw expressions.
csharp_style_throw_expression = false:suggestion
# Newline settings
csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true
csharp_new_line_before_catch = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true

40
src/Razor/.gitignore vendored Normal file
View File

@ -0,0 +1,40 @@
[Oo]bj/
[Bb]in/
TestResults/
.nuget/
.build/
.testPublish/
*.sln.ide/
_ReSharper.*/
packages/
artifacts/
.build/
PublishProfiles/
*.user
*.suo
*.cache
*.docstates
_ReSharper.*
nuget.exe
project.lock.json
*net45.csproj
*net451.csproj
*k10.csproj
*.psess
*.vsp
*.pidb
*.userprefs
*DS_Store
*.ncrunchsolution
*.*sdf
*.ipch
.build/
.vs/
launchSettings.json
global.json
.vscode/*
BenchmarkDotNet.Artifacts/
Microsoft.VisualStudio.RazorExtension.nuget.props
Microsoft.VisualStudio.RazorExtension.nuget.targets
msbuild.binlog
msbuild.log

View File

@ -0,0 +1,26 @@
<Project>
<Import
Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), AspNetCoreSettings.props))\AspNetCoreSettings.props"
Condition=" '$(CI)' != 'true' AND '$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), AspNetCoreSettings.props))' != '' " />
<Import Project="version.props" />
<Import Project="build\dependencies.props" />
<Import Project="build\sources.props" />
<PropertyGroup>
<Product>Microsoft ASP.NET Core</Product>
<RepositoryUrl>https://github.com/aspnet/Razor</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<RepositoryRoot>$(MSBuildThisFileDirectory)</RepositoryRoot>
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)build\Key.snk</AssemblyOriginatorKeyFile>
<SignAssembly>true</SignAssembly>
<PublicSign Condition="'$(OS)' != 'Windows_NT'">true</PublicSign>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<AssemblySigningCertName>Microsoft</AssemblySigningCertName>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Internal.AspNetCore.Sdk" PrivateAssets="All" Version="$(InternalAspNetCoreSdkPackageVersion)" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,7 @@
<Project>
<PropertyGroup>
<RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp2.0' ">$(MicrosoftNETCoreApp20PackageVersion)</RuntimeFrameworkVersion>
<RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp2.1' ">$(MicrosoftNETCoreApp21PackageVersion)</RuntimeFrameworkVersion>
<NETStandardImplicitPackageVersion Condition=" '$(TargetFramework)' == 'netstandard2.0' ">$(NETStandardLibrary20PackageVersion)</NETStandardImplicitPackageVersion>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,73 @@
{
"adx-nonshipping": { // Packages written by the ADX team but that don't ship on NuGet.org (thus, no need to scan anything in them)
"rules": [
// Don't run any rules for packages the ADX team creates but doesn't ship.
],
"packages": {
"Microsoft.AspNetCore.Razor.TagHelpers.Testing.Sources": {},
"RazorPageGenerator": {},
"Microsoft.CodeAnalysis.Remote.Razor": {},
"Microsoft.VisualStudio.Editor.Razor": {},
"Microsoft.VisualStudio.LanguageServices.Razor": {},
"Microsoft.VisualStudio.Mac.LanguageServices.Razor": {}
}
},
"Default": { // Rules to run for packages not listed in any other set.
"rules": [
"DefaultCompositeRule"
],
"packages": {
"Microsoft.AspNetCore.Razor.Design": {
"exclusions": {
"ASSEMBLY_DESCRIPTION": {
"tools/Microsoft.CodeAnalysis.CSharp.dll": "This assembly is not owned by us and does not follow our conventions.",
"tools/Microsoft.CodeAnalysis.dll": "This assembly is not owned by us and does not follow our conventions."
},
"NEUTRAL_RESOURCES_LANGUAGE": {
"tools/Microsoft.CodeAnalysis.CSharp.dll": "This assembly is not owned by us and does not follow our conventions.",
"tools/Microsoft.CodeAnalysis.dll": "This assembly is not owned by us and does not follow our conventions.",
"tools/Newtonsoft.Json.dll": "This assembly is not owned by us and does not follow our conventions."
},
"ASSEMBLY_PRODUCT": {
"tools/Microsoft.CodeAnalysis.CSharp.dll": "This assembly is not owned by us and does not follow our conventions.",
"tools/Microsoft.CodeAnalysis.dll": "This assembly is not owned by us and does not follow our conventions."
},
"SERVICING_ATTRIBUTE": {
"tools/Newtonsoft.Json.dll": "This assembly is not owned by us and does not follow our conventions."
},
"VERSION_INFORMATIONALVERSION": {
"tools/Newtonsoft.Json.dll": "This assembly is not owned by us and does not follow our conventions."
},
"WRONG_PUBLICKEYTOKEN": {
"tools/Microsoft.CodeAnalysis.CSharp.dll": "This assembly is not owned by us and does not follow our conventions.",
"tools/Microsoft.CodeAnalysis.dll": "This assembly is not owned by us and does not follow our conventions.",
"tools/Newtonsoft.Json.dll": "This assembly is not owned by us and does not follow our conventions.",
"tools/runtimes/unix/lib/netstandard1.3/System.Text.Encoding.CodePages.dll": "This assembly is not owned by us and does not follow our conventions.",
"tools/runtimes/win/lib/netstandard1.3/System.Text.Encoding.CodePages.dll": "This assembly is not owned by us and does not follow our conventions."
},
"ASSEMBLY_INFORMATIONAL_VERSION_MISMATCH": {
"tools/Microsoft.CodeAnalysis.CSharp.dll": "This assembly is not owned by us and does not follow our conventions.",
"tools/Microsoft.CodeAnalysis.dll": "This assembly is not owned by us and does not follow our conventions.",
"tools/Newtonsoft.Json.dll": "This assembly is not owned by us and does not follow our conventions.",
"tools/runtimes/unix/lib/netstandard1.3/System.Text.Encoding.CodePages.dll": "This assembly is not owned by us and does not follow our conventions.",
"tools/runtimes/win/lib/netstandard1.3/System.Text.Encoding.CodePages.dll": "This assembly is not owned by us and does not follow our conventions."
},
"ASSEMBLY_FILE_VERSION_MISMATCH": {
"tools/Microsoft.CodeAnalysis.CSharp.dll": "This assembly is not owned by us and does not follow our conventions.",
"tools/Microsoft.CodeAnalysis.dll": "This assembly is not owned by us and does not follow our conventions.",
"tools/Newtonsoft.Json.dll": "This assembly is not owned by us and does not follow our conventions.",
"tools/runtimes/unix/lib/netstandard1.3/System.Text.Encoding.CodePages.dll": "This assembly is not owned by us and does not follow our conventions.",
"tools/runtimes/win/lib/netstandard1.3/System.Text.Encoding.CodePages.dll": "This assembly is not owned by us and does not follow our conventions."
},
"ASSEMBLY_VERSION_MISMATCH": {
"tools/Microsoft.CodeAnalysis.CSharp.dll": "This assembly is not owned by us and does not follow our conventions.",
"tools/Microsoft.CodeAnalysis.dll": "This assembly is not owned by us and does not follow our conventions.",
"tools/Newtonsoft.Json.dll": "This assembly is not owned by us and does not follow our conventions.",
"tools/runtimes/unix/lib/netstandard1.3/System.Text.Encoding.CodePages.dll": "This assembly is not owned by us and does not follow our conventions.",
"tools/runtimes/win/lib/netstandard1.3/System.Text.Encoding.CodePages.dll": "This assembly is not owned by us and does not follow our conventions."
}
}
}
}
}
}

12
src/Razor/README.md Normal file
View File

@ -0,0 +1,12 @@
Razor
=====
Travis: [![Travis](https://travis-ci.org/aspnet/Razor.svg?branch=dev)](https://travis-ci.org/aspnet/Razor)
The Razor syntax provides a fast, terse, clean and lightweight way to combine server code with HTML to create dynamic web content. This repo contains the parser and the C# code generator for the Razor syntax.
This project is part of ASP.NET Core. You can find samples, documentation and getting started instructions for ASP.NET Core at the [Home](https://www.github.com/aspnet/home) repo.
## Building from source
To run a complete build on command line only, execute `build.cmd` or `build.sh` without arguments. See [developer documentation](https://github.com/aspnet/Home/wiki) for more details.

459
src/Razor/Razor.sln Normal file
View File

@ -0,0 +1,459 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27130.2036
MinimumVisualStudioVersion = 15.0.26730.03
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{3C0D6505-79B3-49D0-B4C3-176F0F1836ED}"
ProjectSection(SolutionItems) = preProject
src\Directory.Build.props = src\Directory.Build.props
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{92463391-81BE-462B-AC3C-78C6C760741F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor", "src\Microsoft.AspNetCore.Razor\Microsoft.AspNetCore.Razor.csproj", "{EDA30434-C567-44DC-B8B6-2566A7F77163}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.Runtime", "src\Microsoft.AspNetCore.Razor.Runtime\Microsoft.AspNetCore.Razor.Runtime.csproj", "{D0196096-1B01-4133-AACE-1A10A0F7247C}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F8C12DD6-659D-405A-AA27-FB22AD92A010}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
build\dependencies.props = build\dependencies.props
Directory.Build.props = Directory.Build.props
Directory.Build.targets = Directory.Build.targets
build\sources.props = build\sources.props
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RazorPageGenerator", "src\RazorPageGenerator\RazorPageGenerator.csproj", "{7BE58880-36AD-4CD5-9E16-2A5AFEA790EF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.Language", "src\Microsoft.AspNetCore.Razor.Language\Microsoft.AspNetCore.Razor.Language.csproj", "{932F3C9C-A6C0-40D3-BA50-9309886242FC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.Language.Test", "test\Microsoft.AspNetCore.Razor.Language.Test\Microsoft.AspNetCore.Razor.Language.Test.csproj", "{969357A4-CCF1-46D9-B002-9AA072AFC75C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.Runtime.Test", "test\Microsoft.AspNetCore.Razor.Runtime.Test\Microsoft.AspNetCore.Razor.Runtime.Test.csproj", "{277AB67E-9C8D-4799-A18C-C628E70A8664}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Razor.Workspaces", "src\Microsoft.CodeAnalysis.Razor.Workspaces\Microsoft.CodeAnalysis.Razor.Workspaces.csproj", "{0F265874-C592-448B-BC4F-3430AB03E0DC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Remote.Razor", "src\Microsoft.CodeAnalysis.Remote.Razor\Microsoft.CodeAnalysis.Remote.Razor.csproj", "{4EAD959D-73B2-4FB2-B46F-16CEB1EF49D4}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tooling", "tooling", "{C0CC1E1F-1559-44DE-93A8-63259CEA2AAB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.VisualStudio.RazorExtension", "tooling\Microsoft.VisualStudio.RazorExtension\Microsoft.VisualStudio.RazorExtension.csproj", "{D66B45B5-CBFD-4947-81F1-F30AB80EA992}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Razor", "src\Microsoft.CodeAnalysis.Razor\Microsoft.CodeAnalysis.Razor.csproj", "{42403DAF-F0BC-4F3A-B7F2-46D7013345D8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Razor.Test", "test\Microsoft.CodeAnalysis.Razor.Test\Microsoft.CodeAnalysis.Razor.Test.csproj", "{7A8A1664-37CE-4376-81CA-1862CF5F91D9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.LanguageServices.Razor", "src\Microsoft.VisualStudio.LanguageServices.Razor\Microsoft.VisualStudio.LanguageServices.Razor.csproj", "{E5D92DB7-5CBF-410A-9685-FF76F71EC96F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RazorPageGenerator.Test", "test\RazorPageGenerator.Test\RazorPageGenerator.Test.csproj", "{96EB1BD4-B8E0-4F52-A068-BBCACA7E3F63}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.LanguageServices.Razor.Test", "test\Microsoft.VisualStudio.LanguageServices.Razor.Test\Microsoft.VisualStudio.LanguageServices.Razor.Test.csproj", "{37E61BDB-658E-4F44-A499-D64CC6D35485}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Razor.Extensions", "src\Microsoft.AspNetCore.Mvc.Razor.Extensions\Microsoft.AspNetCore.Mvc.Razor.Extensions.csproj", "{995F2FEB-65FA-4399-B1C0-16E0B3FBDB15}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Razor.Extensions.Test", "test\Microsoft.AspNetCore.Mvc.Razor.Extensions.Test\Microsoft.AspNetCore.Mvc.Razor.Extensions.Test.csproj", "{7CFD5646-A757-4498-9E01-9C8528ED60AE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.Test.Common", "test\Microsoft.AspNetCore.Razor.Test.Common\Microsoft.AspNetCore.Razor.Test.Common.csproj", "{078AEF36-F319-4CE2-BAA2-5B58A6536B46}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.Test.MvcShim", "test\Microsoft.AspNetCore.Razor.Test.MvcShim\Microsoft.AspNetCore.Razor.Test.MvcShim.csproj", "{8F165A3F-A18C-4649-AA08-C0E1BA5F5C90}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Razor.Workspaces.Test", "test\Microsoft.CodeAnalysis.Razor.Workspaces.Test\Microsoft.CodeAnalysis.Razor.Workspaces.Test.csproj", "{C61AAE12-5007-4205-A220-68F354A7F235}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X", "src\Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X\Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X.csproj", "{F1538809-7347-45D2-A7AC-C1D89CF0BBD4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X.Test", "test\Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X.Test\Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X.Test.csproj", "{296D4516-0323-4D28-955D-B0324E4F10BE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.Test.MvcShim.Version1_X", "test\Microsoft.AspNetCore.Razor.Test.MvcShim.Version1_X\Microsoft.AspNetCore.Razor.Test.MvcShim.Version1_X.csproj", "{AC5CA24B-B81E-4B20-B193-2E3983B1896C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.Editor.Razor", "src\Microsoft.VisualStudio.Editor.Razor\Microsoft.VisualStudio.Editor.Razor.csproj", "{0BCDE75A-A438-46C7-95E9-391F029D07C5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.Editor.Razor.Test", "test\Microsoft.VisualStudio.Editor.Razor.Test\Microsoft.VisualStudio.Editor.Razor.Test.csproj", "{AA888DB9-340E-4E06-A2A4-25BFEE1AC2B7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.Editor.Razor.Test.Common", "test\Microsoft.VisualStudio.Editor.Razor.Test.Common\Microsoft.VisualStudio.Editor.Razor.Test.Common.csproj", "{FC684D4F-D23C-407C-9C68-E10EF3B38560}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.Mac.RazorAddin", "tooling\Microsoft.VisualStudio.Mac.RazorAddin\Microsoft.VisualStudio.Mac.RazorAddin.csproj", "{FAF9986F-E086-4513-9D52-F7BF5FFCF31D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.Mac.LanguageServices.Razor", "src\Microsoft.VisualStudio.Mac.LanguageServices.Razor\Microsoft.VisualStudio.Mac.LanguageServices.Razor.csproj", "{95B18DEE-8B45-4CF0-B9F8-CCBAF3B5251A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.Mac.LanguageServices.Razor.Test", "test\Microsoft.VisualStudio.Mac.LanguageServices.Razor.Test\Microsoft.VisualStudio.Mac.LanguageServices.Razor.Test.csproj", "{B8A3E4CA-D54A-441F-A3BF-E00F060CA042}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.Design", "src\Microsoft.AspNetCore.Razor.Design\Microsoft.AspNetCore.Razor.Design.csproj", "{5257B25D-330A-4DCF-ACED-B4709CFBF916}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.Design.Test", "test\Microsoft.AspNetCore.Razor.Design.Test\Microsoft.AspNetCore.Razor.Design.Test.csproj", "{1D90F276-E1CA-4FDF-A173-EB889E7D3150}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.Tasks", "src\Microsoft.AspNetCore.Razor.Tasks\Microsoft.AspNetCore.Razor.Tasks.csproj", "{043B9497-C0BA-4770-9210-4456D2F81CE0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.Test", "test\Microsoft.AspNetCore.Razor.Test\Microsoft.AspNetCore.Razor.Test.csproj", "{323553F0-14AB-4FBD-9CF0-1CC0BE8056F8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.Performance", "benchmarks\Microsoft.AspNetCore.Razor.Performance\Microsoft.AspNetCore.Razor.Performance.csproj", "{6205467F-E381-4C42-AEEC-763BD62B3D5E}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmarks", "benchmarks", "{C2C98051-0F39-47F2-80B6-E72B29159F2C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Razor.Workspaces.Test.Common", "test\Microsoft.CodeAnalysis.Razor.Workspaces.Test.Common\Microsoft.CodeAnalysis.Razor.Workspaces.Test.Common.csproj", "{933101DA-C4CC-401A-AA01-2784E1025B7F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.Tools", "src\Microsoft.AspNetCore.Razor.Tools\Microsoft.AspNetCore.Razor.Tools.csproj", "{3E7F2D49-3B45-45A8-9893-F73EC1EEBAAB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.NET.Sdk.Razor", "src\Microsoft.NET.Sdk.Razor\Microsoft.NET.Sdk.Razor.csproj", "{7D9ECCEE-71D1-4A42-ABEE-876AFA1B4FC9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.Tools.Test", "test\Microsoft.AspNetCore.Razor.Tools.Test\Microsoft.AspNetCore.Razor.Tools.Test.csproj", "{6EA56B2B-89EC-4C38-A384-97D203375B06}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.Test.MvcShim.ClassLib", "test\Microsoft.AspNetCore.Razor.Test.MvcShim.ClassLib\Microsoft.AspNetCore.Razor.Test.MvcShim.ClassLib.csproj", "{72E89155-86C7-454E-BDD9-39F497F2F61B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
DebugNoVSIX|Any CPU = DebugNoVSIX|Any CPU
Release|Any CPU = Release|Any CPU
ReleaseNoVSIX|Any CPU = ReleaseNoVSIX|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{EDA30434-C567-44DC-B8B6-2566A7F77163}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EDA30434-C567-44DC-B8B6-2566A7F77163}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EDA30434-C567-44DC-B8B6-2566A7F77163}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{EDA30434-C567-44DC-B8B6-2566A7F77163}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{EDA30434-C567-44DC-B8B6-2566A7F77163}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EDA30434-C567-44DC-B8B6-2566A7F77163}.Release|Any CPU.Build.0 = Release|Any CPU
{EDA30434-C567-44DC-B8B6-2566A7F77163}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{EDA30434-C567-44DC-B8B6-2566A7F77163}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{D0196096-1B01-4133-AACE-1A10A0F7247C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D0196096-1B01-4133-AACE-1A10A0F7247C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D0196096-1B01-4133-AACE-1A10A0F7247C}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{D0196096-1B01-4133-AACE-1A10A0F7247C}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{D0196096-1B01-4133-AACE-1A10A0F7247C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D0196096-1B01-4133-AACE-1A10A0F7247C}.Release|Any CPU.Build.0 = Release|Any CPU
{D0196096-1B01-4133-AACE-1A10A0F7247C}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{D0196096-1B01-4133-AACE-1A10A0F7247C}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{7BE58880-36AD-4CD5-9E16-2A5AFEA790EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7BE58880-36AD-4CD5-9E16-2A5AFEA790EF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7BE58880-36AD-4CD5-9E16-2A5AFEA790EF}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{7BE58880-36AD-4CD5-9E16-2A5AFEA790EF}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{7BE58880-36AD-4CD5-9E16-2A5AFEA790EF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7BE58880-36AD-4CD5-9E16-2A5AFEA790EF}.Release|Any CPU.Build.0 = Release|Any CPU
{7BE58880-36AD-4CD5-9E16-2A5AFEA790EF}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{7BE58880-36AD-4CD5-9E16-2A5AFEA790EF}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{932F3C9C-A6C0-40D3-BA50-9309886242FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{932F3C9C-A6C0-40D3-BA50-9309886242FC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{932F3C9C-A6C0-40D3-BA50-9309886242FC}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{932F3C9C-A6C0-40D3-BA50-9309886242FC}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{932F3C9C-A6C0-40D3-BA50-9309886242FC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{932F3C9C-A6C0-40D3-BA50-9309886242FC}.Release|Any CPU.Build.0 = Release|Any CPU
{932F3C9C-A6C0-40D3-BA50-9309886242FC}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{932F3C9C-A6C0-40D3-BA50-9309886242FC}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{969357A4-CCF1-46D9-B002-9AA072AFC75C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{969357A4-CCF1-46D9-B002-9AA072AFC75C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{969357A4-CCF1-46D9-B002-9AA072AFC75C}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{969357A4-CCF1-46D9-B002-9AA072AFC75C}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{969357A4-CCF1-46D9-B002-9AA072AFC75C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{969357A4-CCF1-46D9-B002-9AA072AFC75C}.Release|Any CPU.Build.0 = Release|Any CPU
{969357A4-CCF1-46D9-B002-9AA072AFC75C}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{969357A4-CCF1-46D9-B002-9AA072AFC75C}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{277AB67E-9C8D-4799-A18C-C628E70A8664}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{277AB67E-9C8D-4799-A18C-C628E70A8664}.Debug|Any CPU.Build.0 = Debug|Any CPU
{277AB67E-9C8D-4799-A18C-C628E70A8664}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{277AB67E-9C8D-4799-A18C-C628E70A8664}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{277AB67E-9C8D-4799-A18C-C628E70A8664}.Release|Any CPU.ActiveCfg = Release|Any CPU
{277AB67E-9C8D-4799-A18C-C628E70A8664}.Release|Any CPU.Build.0 = Release|Any CPU
{277AB67E-9C8D-4799-A18C-C628E70A8664}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{277AB67E-9C8D-4799-A18C-C628E70A8664}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{0F265874-C592-448B-BC4F-3430AB03E0DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0F265874-C592-448B-BC4F-3430AB03E0DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0F265874-C592-448B-BC4F-3430AB03E0DC}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{0F265874-C592-448B-BC4F-3430AB03E0DC}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{0F265874-C592-448B-BC4F-3430AB03E0DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0F265874-C592-448B-BC4F-3430AB03E0DC}.Release|Any CPU.Build.0 = Release|Any CPU
{0F265874-C592-448B-BC4F-3430AB03E0DC}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{0F265874-C592-448B-BC4F-3430AB03E0DC}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{4EAD959D-73B2-4FB2-B46F-16CEB1EF49D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4EAD959D-73B2-4FB2-B46F-16CEB1EF49D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4EAD959D-73B2-4FB2-B46F-16CEB1EF49D4}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{4EAD959D-73B2-4FB2-B46F-16CEB1EF49D4}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{4EAD959D-73B2-4FB2-B46F-16CEB1EF49D4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4EAD959D-73B2-4FB2-B46F-16CEB1EF49D4}.Release|Any CPU.Build.0 = Release|Any CPU
{4EAD959D-73B2-4FB2-B46F-16CEB1EF49D4}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{4EAD959D-73B2-4FB2-B46F-16CEB1EF49D4}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{D66B45B5-CBFD-4947-81F1-F30AB80EA992}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D66B45B5-CBFD-4947-81F1-F30AB80EA992}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D66B45B5-CBFD-4947-81F1-F30AB80EA992}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{D66B45B5-CBFD-4947-81F1-F30AB80EA992}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D66B45B5-CBFD-4947-81F1-F30AB80EA992}.Release|Any CPU.Build.0 = Release|Any CPU
{D66B45B5-CBFD-4947-81F1-F30AB80EA992}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{42403DAF-F0BC-4F3A-B7F2-46D7013345D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{42403DAF-F0BC-4F3A-B7F2-46D7013345D8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{42403DAF-F0BC-4F3A-B7F2-46D7013345D8}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{42403DAF-F0BC-4F3A-B7F2-46D7013345D8}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{42403DAF-F0BC-4F3A-B7F2-46D7013345D8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{42403DAF-F0BC-4F3A-B7F2-46D7013345D8}.Release|Any CPU.Build.0 = Release|Any CPU
{42403DAF-F0BC-4F3A-B7F2-46D7013345D8}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{42403DAF-F0BC-4F3A-B7F2-46D7013345D8}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{7A8A1664-37CE-4376-81CA-1862CF5F91D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7A8A1664-37CE-4376-81CA-1862CF5F91D9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7A8A1664-37CE-4376-81CA-1862CF5F91D9}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{7A8A1664-37CE-4376-81CA-1862CF5F91D9}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{7A8A1664-37CE-4376-81CA-1862CF5F91D9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7A8A1664-37CE-4376-81CA-1862CF5F91D9}.Release|Any CPU.Build.0 = Release|Any CPU
{7A8A1664-37CE-4376-81CA-1862CF5F91D9}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{7A8A1664-37CE-4376-81CA-1862CF5F91D9}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{E5D92DB7-5CBF-410A-9685-FF76F71EC96F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E5D92DB7-5CBF-410A-9685-FF76F71EC96F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E5D92DB7-5CBF-410A-9685-FF76F71EC96F}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{E5D92DB7-5CBF-410A-9685-FF76F71EC96F}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{E5D92DB7-5CBF-410A-9685-FF76F71EC96F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E5D92DB7-5CBF-410A-9685-FF76F71EC96F}.Release|Any CPU.Build.0 = Release|Any CPU
{E5D92DB7-5CBF-410A-9685-FF76F71EC96F}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{E5D92DB7-5CBF-410A-9685-FF76F71EC96F}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{96EB1BD4-B8E0-4F52-A068-BBCACA7E3F63}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{96EB1BD4-B8E0-4F52-A068-BBCACA7E3F63}.Debug|Any CPU.Build.0 = Debug|Any CPU
{96EB1BD4-B8E0-4F52-A068-BBCACA7E3F63}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{96EB1BD4-B8E0-4F52-A068-BBCACA7E3F63}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{96EB1BD4-B8E0-4F52-A068-BBCACA7E3F63}.Release|Any CPU.ActiveCfg = Release|Any CPU
{96EB1BD4-B8E0-4F52-A068-BBCACA7E3F63}.Release|Any CPU.Build.0 = Release|Any CPU
{96EB1BD4-B8E0-4F52-A068-BBCACA7E3F63}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{96EB1BD4-B8E0-4F52-A068-BBCACA7E3F63}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{37E61BDB-658E-4F44-A499-D64CC6D35485}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{37E61BDB-658E-4F44-A499-D64CC6D35485}.Debug|Any CPU.Build.0 = Debug|Any CPU
{37E61BDB-658E-4F44-A499-D64CC6D35485}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{37E61BDB-658E-4F44-A499-D64CC6D35485}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{37E61BDB-658E-4F44-A499-D64CC6D35485}.Release|Any CPU.ActiveCfg = Release|Any CPU
{37E61BDB-658E-4F44-A499-D64CC6D35485}.Release|Any CPU.Build.0 = Release|Any CPU
{37E61BDB-658E-4F44-A499-D64CC6D35485}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{37E61BDB-658E-4F44-A499-D64CC6D35485}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{995F2FEB-65FA-4399-B1C0-16E0B3FBDB15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{995F2FEB-65FA-4399-B1C0-16E0B3FBDB15}.Debug|Any CPU.Build.0 = Debug|Any CPU
{995F2FEB-65FA-4399-B1C0-16E0B3FBDB15}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{995F2FEB-65FA-4399-B1C0-16E0B3FBDB15}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{995F2FEB-65FA-4399-B1C0-16E0B3FBDB15}.Release|Any CPU.ActiveCfg = Release|Any CPU
{995F2FEB-65FA-4399-B1C0-16E0B3FBDB15}.Release|Any CPU.Build.0 = Release|Any CPU
{995F2FEB-65FA-4399-B1C0-16E0B3FBDB15}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{995F2FEB-65FA-4399-B1C0-16E0B3FBDB15}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{7CFD5646-A757-4498-9E01-9C8528ED60AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7CFD5646-A757-4498-9E01-9C8528ED60AE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7CFD5646-A757-4498-9E01-9C8528ED60AE}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{7CFD5646-A757-4498-9E01-9C8528ED60AE}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{7CFD5646-A757-4498-9E01-9C8528ED60AE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7CFD5646-A757-4498-9E01-9C8528ED60AE}.Release|Any CPU.Build.0 = Release|Any CPU
{7CFD5646-A757-4498-9E01-9C8528ED60AE}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{7CFD5646-A757-4498-9E01-9C8528ED60AE}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{078AEF36-F319-4CE2-BAA2-5B58A6536B46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{078AEF36-F319-4CE2-BAA2-5B58A6536B46}.Debug|Any CPU.Build.0 = Debug|Any CPU
{078AEF36-F319-4CE2-BAA2-5B58A6536B46}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{078AEF36-F319-4CE2-BAA2-5B58A6536B46}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{078AEF36-F319-4CE2-BAA2-5B58A6536B46}.Release|Any CPU.ActiveCfg = Release|Any CPU
{078AEF36-F319-4CE2-BAA2-5B58A6536B46}.Release|Any CPU.Build.0 = Release|Any CPU
{078AEF36-F319-4CE2-BAA2-5B58A6536B46}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{078AEF36-F319-4CE2-BAA2-5B58A6536B46}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{8F165A3F-A18C-4649-AA08-C0E1BA5F5C90}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8F165A3F-A18C-4649-AA08-C0E1BA5F5C90}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8F165A3F-A18C-4649-AA08-C0E1BA5F5C90}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{8F165A3F-A18C-4649-AA08-C0E1BA5F5C90}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{8F165A3F-A18C-4649-AA08-C0E1BA5F5C90}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8F165A3F-A18C-4649-AA08-C0E1BA5F5C90}.Release|Any CPU.Build.0 = Release|Any CPU
{8F165A3F-A18C-4649-AA08-C0E1BA5F5C90}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{8F165A3F-A18C-4649-AA08-C0E1BA5F5C90}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{C61AAE12-5007-4205-A220-68F354A7F235}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C61AAE12-5007-4205-A220-68F354A7F235}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C61AAE12-5007-4205-A220-68F354A7F235}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{C61AAE12-5007-4205-A220-68F354A7F235}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{C61AAE12-5007-4205-A220-68F354A7F235}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C61AAE12-5007-4205-A220-68F354A7F235}.Release|Any CPU.Build.0 = Release|Any CPU
{C61AAE12-5007-4205-A220-68F354A7F235}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{C61AAE12-5007-4205-A220-68F354A7F235}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{F1538809-7347-45D2-A7AC-C1D89CF0BBD4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F1538809-7347-45D2-A7AC-C1D89CF0BBD4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F1538809-7347-45D2-A7AC-C1D89CF0BBD4}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{F1538809-7347-45D2-A7AC-C1D89CF0BBD4}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{F1538809-7347-45D2-A7AC-C1D89CF0BBD4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F1538809-7347-45D2-A7AC-C1D89CF0BBD4}.Release|Any CPU.Build.0 = Release|Any CPU
{F1538809-7347-45D2-A7AC-C1D89CF0BBD4}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{F1538809-7347-45D2-A7AC-C1D89CF0BBD4}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{296D4516-0323-4D28-955D-B0324E4F10BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{296D4516-0323-4D28-955D-B0324E4F10BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{296D4516-0323-4D28-955D-B0324E4F10BE}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{296D4516-0323-4D28-955D-B0324E4F10BE}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{296D4516-0323-4D28-955D-B0324E4F10BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{296D4516-0323-4D28-955D-B0324E4F10BE}.Release|Any CPU.Build.0 = Release|Any CPU
{296D4516-0323-4D28-955D-B0324E4F10BE}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{296D4516-0323-4D28-955D-B0324E4F10BE}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{AC5CA24B-B81E-4B20-B193-2E3983B1896C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AC5CA24B-B81E-4B20-B193-2E3983B1896C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AC5CA24B-B81E-4B20-B193-2E3983B1896C}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{AC5CA24B-B81E-4B20-B193-2E3983B1896C}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{AC5CA24B-B81E-4B20-B193-2E3983B1896C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AC5CA24B-B81E-4B20-B193-2E3983B1896C}.Release|Any CPU.Build.0 = Release|Any CPU
{AC5CA24B-B81E-4B20-B193-2E3983B1896C}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{AC5CA24B-B81E-4B20-B193-2E3983B1896C}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{0BCDE75A-A438-46C7-95E9-391F029D07C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0BCDE75A-A438-46C7-95E9-391F029D07C5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0BCDE75A-A438-46C7-95E9-391F029D07C5}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{0BCDE75A-A438-46C7-95E9-391F029D07C5}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{0BCDE75A-A438-46C7-95E9-391F029D07C5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0BCDE75A-A438-46C7-95E9-391F029D07C5}.Release|Any CPU.Build.0 = Release|Any CPU
{0BCDE75A-A438-46C7-95E9-391F029D07C5}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{0BCDE75A-A438-46C7-95E9-391F029D07C5}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{AA888DB9-340E-4E06-A2A4-25BFEE1AC2B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AA888DB9-340E-4E06-A2A4-25BFEE1AC2B7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AA888DB9-340E-4E06-A2A4-25BFEE1AC2B7}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{AA888DB9-340E-4E06-A2A4-25BFEE1AC2B7}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{AA888DB9-340E-4E06-A2A4-25BFEE1AC2B7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AA888DB9-340E-4E06-A2A4-25BFEE1AC2B7}.Release|Any CPU.Build.0 = Release|Any CPU
{AA888DB9-340E-4E06-A2A4-25BFEE1AC2B7}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{AA888DB9-340E-4E06-A2A4-25BFEE1AC2B7}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{FC684D4F-D23C-407C-9C68-E10EF3B38560}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FC684D4F-D23C-407C-9C68-E10EF3B38560}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FC684D4F-D23C-407C-9C68-E10EF3B38560}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{FC684D4F-D23C-407C-9C68-E10EF3B38560}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{FC684D4F-D23C-407C-9C68-E10EF3B38560}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FC684D4F-D23C-407C-9C68-E10EF3B38560}.Release|Any CPU.Build.0 = Release|Any CPU
{FC684D4F-D23C-407C-9C68-E10EF3B38560}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{FC684D4F-D23C-407C-9C68-E10EF3B38560}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{FAF9986F-E086-4513-9D52-F7BF5FFCF31D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FAF9986F-E086-4513-9D52-F7BF5FFCF31D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FAF9986F-E086-4513-9D52-F7BF5FFCF31D}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{FAF9986F-E086-4513-9D52-F7BF5FFCF31D}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{FAF9986F-E086-4513-9D52-F7BF5FFCF31D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FAF9986F-E086-4513-9D52-F7BF5FFCF31D}.Release|Any CPU.Build.0 = Release|Any CPU
{FAF9986F-E086-4513-9D52-F7BF5FFCF31D}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{FAF9986F-E086-4513-9D52-F7BF5FFCF31D}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{95B18DEE-8B45-4CF0-B9F8-CCBAF3B5251A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{95B18DEE-8B45-4CF0-B9F8-CCBAF3B5251A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{95B18DEE-8B45-4CF0-B9F8-CCBAF3B5251A}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{95B18DEE-8B45-4CF0-B9F8-CCBAF3B5251A}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{95B18DEE-8B45-4CF0-B9F8-CCBAF3B5251A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{95B18DEE-8B45-4CF0-B9F8-CCBAF3B5251A}.Release|Any CPU.Build.0 = Release|Any CPU
{95B18DEE-8B45-4CF0-B9F8-CCBAF3B5251A}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{95B18DEE-8B45-4CF0-B9F8-CCBAF3B5251A}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{B8A3E4CA-D54A-441F-A3BF-E00F060CA042}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B8A3E4CA-D54A-441F-A3BF-E00F060CA042}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B8A3E4CA-D54A-441F-A3BF-E00F060CA042}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{B8A3E4CA-D54A-441F-A3BF-E00F060CA042}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{B8A3E4CA-D54A-441F-A3BF-E00F060CA042}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B8A3E4CA-D54A-441F-A3BF-E00F060CA042}.Release|Any CPU.Build.0 = Release|Any CPU
{B8A3E4CA-D54A-441F-A3BF-E00F060CA042}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{B8A3E4CA-D54A-441F-A3BF-E00F060CA042}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{5257B25D-330A-4DCF-ACED-B4709CFBF916}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5257B25D-330A-4DCF-ACED-B4709CFBF916}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5257B25D-330A-4DCF-ACED-B4709CFBF916}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{5257B25D-330A-4DCF-ACED-B4709CFBF916}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{5257B25D-330A-4DCF-ACED-B4709CFBF916}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5257B25D-330A-4DCF-ACED-B4709CFBF916}.Release|Any CPU.Build.0 = Release|Any CPU
{5257B25D-330A-4DCF-ACED-B4709CFBF916}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{5257B25D-330A-4DCF-ACED-B4709CFBF916}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{1D90F276-E1CA-4FDF-A173-EB889E7D3150}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1D90F276-E1CA-4FDF-A173-EB889E7D3150}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1D90F276-E1CA-4FDF-A173-EB889E7D3150}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{1D90F276-E1CA-4FDF-A173-EB889E7D3150}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{1D90F276-E1CA-4FDF-A173-EB889E7D3150}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1D90F276-E1CA-4FDF-A173-EB889E7D3150}.Release|Any CPU.Build.0 = Release|Any CPU
{1D90F276-E1CA-4FDF-A173-EB889E7D3150}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{1D90F276-E1CA-4FDF-A173-EB889E7D3150}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{043B9497-C0BA-4770-9210-4456D2F81CE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{043B9497-C0BA-4770-9210-4456D2F81CE0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{043B9497-C0BA-4770-9210-4456D2F81CE0}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{043B9497-C0BA-4770-9210-4456D2F81CE0}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{043B9497-C0BA-4770-9210-4456D2F81CE0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{043B9497-C0BA-4770-9210-4456D2F81CE0}.Release|Any CPU.Build.0 = Release|Any CPU
{043B9497-C0BA-4770-9210-4456D2F81CE0}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{043B9497-C0BA-4770-9210-4456D2F81CE0}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{323553F0-14AB-4FBD-9CF0-1CC0BE8056F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{323553F0-14AB-4FBD-9CF0-1CC0BE8056F8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{323553F0-14AB-4FBD-9CF0-1CC0BE8056F8}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{323553F0-14AB-4FBD-9CF0-1CC0BE8056F8}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{323553F0-14AB-4FBD-9CF0-1CC0BE8056F8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{323553F0-14AB-4FBD-9CF0-1CC0BE8056F8}.Release|Any CPU.Build.0 = Release|Any CPU
{323553F0-14AB-4FBD-9CF0-1CC0BE8056F8}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{323553F0-14AB-4FBD-9CF0-1CC0BE8056F8}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{6205467F-E381-4C42-AEEC-763BD62B3D5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6205467F-E381-4C42-AEEC-763BD62B3D5E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6205467F-E381-4C42-AEEC-763BD62B3D5E}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{6205467F-E381-4C42-AEEC-763BD62B3D5E}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{6205467F-E381-4C42-AEEC-763BD62B3D5E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6205467F-E381-4C42-AEEC-763BD62B3D5E}.Release|Any CPU.Build.0 = Release|Any CPU
{6205467F-E381-4C42-AEEC-763BD62B3D5E}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{6205467F-E381-4C42-AEEC-763BD62B3D5E}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{933101DA-C4CC-401A-AA01-2784E1025B7F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{933101DA-C4CC-401A-AA01-2784E1025B7F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{933101DA-C4CC-401A-AA01-2784E1025B7F}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{933101DA-C4CC-401A-AA01-2784E1025B7F}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{933101DA-C4CC-401A-AA01-2784E1025B7F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{933101DA-C4CC-401A-AA01-2784E1025B7F}.Release|Any CPU.Build.0 = Release|Any CPU
{933101DA-C4CC-401A-AA01-2784E1025B7F}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{933101DA-C4CC-401A-AA01-2784E1025B7F}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{3E7F2D49-3B45-45A8-9893-F73EC1EEBAAB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3E7F2D49-3B45-45A8-9893-F73EC1EEBAAB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3E7F2D49-3B45-45A8-9893-F73EC1EEBAAB}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{3E7F2D49-3B45-45A8-9893-F73EC1EEBAAB}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{3E7F2D49-3B45-45A8-9893-F73EC1EEBAAB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3E7F2D49-3B45-45A8-9893-F73EC1EEBAAB}.Release|Any CPU.Build.0 = Release|Any CPU
{3E7F2D49-3B45-45A8-9893-F73EC1EEBAAB}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{3E7F2D49-3B45-45A8-9893-F73EC1EEBAAB}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{7D9ECCEE-71D1-4A42-ABEE-876AFA1B4FC9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7D9ECCEE-71D1-4A42-ABEE-876AFA1B4FC9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7D9ECCEE-71D1-4A42-ABEE-876AFA1B4FC9}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{7D9ECCEE-71D1-4A42-ABEE-876AFA1B4FC9}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{7D9ECCEE-71D1-4A42-ABEE-876AFA1B4FC9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7D9ECCEE-71D1-4A42-ABEE-876AFA1B4FC9}.Release|Any CPU.Build.0 = Release|Any CPU
{7D9ECCEE-71D1-4A42-ABEE-876AFA1B4FC9}.ReleaseNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{7D9ECCEE-71D1-4A42-ABEE-876AFA1B4FC9}.ReleaseNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{6EA56B2B-89EC-4C38-A384-97D203375B06}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6EA56B2B-89EC-4C38-A384-97D203375B06}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6EA56B2B-89EC-4C38-A384-97D203375B06}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{6EA56B2B-89EC-4C38-A384-97D203375B06}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{6EA56B2B-89EC-4C38-A384-97D203375B06}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6EA56B2B-89EC-4C38-A384-97D203375B06}.Release|Any CPU.Build.0 = Release|Any CPU
{6EA56B2B-89EC-4C38-A384-97D203375B06}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{6EA56B2B-89EC-4C38-A384-97D203375B06}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{72E89155-86C7-454E-BDD9-39F497F2F61B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{72E89155-86C7-454E-BDD9-39F497F2F61B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{72E89155-86C7-454E-BDD9-39F497F2F61B}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{72E89155-86C7-454E-BDD9-39F497F2F61B}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{72E89155-86C7-454E-BDD9-39F497F2F61B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{72E89155-86C7-454E-BDD9-39F497F2F61B}.Release|Any CPU.Build.0 = Release|Any CPU
{72E89155-86C7-454E-BDD9-39F497F2F61B}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{72E89155-86C7-454E-BDD9-39F497F2F61B}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{EDA30434-C567-44DC-B8B6-2566A7F77163} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
{D0196096-1B01-4133-AACE-1A10A0F7247C} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
{7BE58880-36AD-4CD5-9E16-2A5AFEA790EF} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
{932F3C9C-A6C0-40D3-BA50-9309886242FC} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
{969357A4-CCF1-46D9-B002-9AA072AFC75C} = {92463391-81BE-462B-AC3C-78C6C760741F}
{277AB67E-9C8D-4799-A18C-C628E70A8664} = {92463391-81BE-462B-AC3C-78C6C760741F}
{0F265874-C592-448B-BC4F-3430AB03E0DC} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
{4EAD959D-73B2-4FB2-B46F-16CEB1EF49D4} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
{D66B45B5-CBFD-4947-81F1-F30AB80EA992} = {C0CC1E1F-1559-44DE-93A8-63259CEA2AAB}
{42403DAF-F0BC-4F3A-B7F2-46D7013345D8} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
{7A8A1664-37CE-4376-81CA-1862CF5F91D9} = {92463391-81BE-462B-AC3C-78C6C760741F}
{E5D92DB7-5CBF-410A-9685-FF76F71EC96F} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
{96EB1BD4-B8E0-4F52-A068-BBCACA7E3F63} = {92463391-81BE-462B-AC3C-78C6C760741F}
{37E61BDB-658E-4F44-A499-D64CC6D35485} = {92463391-81BE-462B-AC3C-78C6C760741F}
{995F2FEB-65FA-4399-B1C0-16E0B3FBDB15} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
{7CFD5646-A757-4498-9E01-9C8528ED60AE} = {92463391-81BE-462B-AC3C-78C6C760741F}
{078AEF36-F319-4CE2-BAA2-5B58A6536B46} = {92463391-81BE-462B-AC3C-78C6C760741F}
{8F165A3F-A18C-4649-AA08-C0E1BA5F5C90} = {92463391-81BE-462B-AC3C-78C6C760741F}
{C61AAE12-5007-4205-A220-68F354A7F235} = {92463391-81BE-462B-AC3C-78C6C760741F}
{F1538809-7347-45D2-A7AC-C1D89CF0BBD4} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
{296D4516-0323-4D28-955D-B0324E4F10BE} = {92463391-81BE-462B-AC3C-78C6C760741F}
{AC5CA24B-B81E-4B20-B193-2E3983B1896C} = {92463391-81BE-462B-AC3C-78C6C760741F}
{0BCDE75A-A438-46C7-95E9-391F029D07C5} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
{AA888DB9-340E-4E06-A2A4-25BFEE1AC2B7} = {92463391-81BE-462B-AC3C-78C6C760741F}
{FC684D4F-D23C-407C-9C68-E10EF3B38560} = {92463391-81BE-462B-AC3C-78C6C760741F}
{FAF9986F-E086-4513-9D52-F7BF5FFCF31D} = {C0CC1E1F-1559-44DE-93A8-63259CEA2AAB}
{95B18DEE-8B45-4CF0-B9F8-CCBAF3B5251A} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
{B8A3E4CA-D54A-441F-A3BF-E00F060CA042} = {92463391-81BE-462B-AC3C-78C6C760741F}
{5257B25D-330A-4DCF-ACED-B4709CFBF916} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
{1D90F276-E1CA-4FDF-A173-EB889E7D3150} = {92463391-81BE-462B-AC3C-78C6C760741F}
{043B9497-C0BA-4770-9210-4456D2F81CE0} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
{323553F0-14AB-4FBD-9CF0-1CC0BE8056F8} = {92463391-81BE-462B-AC3C-78C6C760741F}
{6205467F-E381-4C42-AEEC-763BD62B3D5E} = {C2C98051-0F39-47F2-80B6-E72B29159F2C}
{933101DA-C4CC-401A-AA01-2784E1025B7F} = {92463391-81BE-462B-AC3C-78C6C760741F}
{3E7F2D49-3B45-45A8-9893-F73EC1EEBAAB} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
{7D9ECCEE-71D1-4A42-ABEE-876AFA1B4FC9} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
{6EA56B2B-89EC-4C38-A384-97D203375B06} = {92463391-81BE-462B-AC3C-78C6C760741F}
{72E89155-86C7-454E-BDD9-39F497F2F61B} = {92463391-81BE-462B-AC3C-78C6C760741F}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0035341D-175A-4D05-95E6-F1C2785A1E26}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1 @@
[assembly: BenchmarkDotNet.Attributes.AspNetCoreBenchmark]

View File

@ -0,0 +1,58 @@
// 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.IO;
using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Mvc.Razor.Extensions;
using Microsoft.AspNetCore.Razor.Language;
namespace Microsoft.AspNetCore.Razor.Performance
{
public class CodeGenerationBenchmark
{
public CodeGenerationBenchmark()
{
var current = new DirectoryInfo(AppContext.BaseDirectory);
while (current != null && !File.Exists(Path.Combine(current.FullName, "MSN.cshtml")))
{
current = current.Parent;
}
var root = current;
var fileSystem = RazorProjectFileSystem.Create(root.FullName);
ProjectEngine = RazorProjectEngine.Create(RazorConfiguration.Default, fileSystem, b => RazorExtensions.Register(b)); ;
MSN = fileSystem.GetItem(Path.Combine(root.FullName, "MSN.cshtml"));
}
public RazorProjectEngine ProjectEngine { get; }
public RazorProjectItem MSN { get; }
[Benchmark(Description = "Razor Design Time Code Generation of MSN.com")]
public void CodeGeneration_DesignTime_LargeStaticFile()
{
var codeDocument = ProjectEngine.ProcessDesignTime(MSN);
var generated = codeDocument.GetCSharpDocument();
if (generated.Diagnostics.Count != 0)
{
throw new Exception("Error!" + Environment.NewLine + string.Join(Environment.NewLine, generated.Diagnostics));
}
}
[Benchmark(Description = "Razor Runtime Code Generation of MSN.com")]
public void CodeGeneration_Runtime_LargeStaticFile()
{
var codeDocument = ProjectEngine.Process(MSN);
var generated = codeDocument.GetCSharpDocument();
if (generated.Diagnostics.Count != 0)
{
throw new Exception("Error!" + Environment.NewLine + string.Join(Environment.NewLine, generated.Diagnostics));
}
}
}
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<OutputType>Exe</OutputType>
<ServerGarbageCollection>true</ServerGarbageCollection>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Mvc.Razor.Extensions\Microsoft.AspNetCore.Mvc.Razor.Extensions.csproj" />
<ProjectReference Include="..\..\src\Microsoft.CodeAnalysis.Razor.Workspaces\Microsoft.CodeAnalysis.Razor.Workspaces.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\src\Microsoft.VisualStudio.LanguageServices.Razor\Serialization\*.cs">
<Link>Serialization\%(FileName)%(Extension)</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="$(BenchmarkDotNetPackageVersion)" />
<PackageReference Include="Newtonsoft.Json" Version="$(NewtonsoftJsonPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.BenchmarkRunner.Sources" Version="$(MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion)" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,54 @@
// 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.Text;
using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.VisualStudio.LanguageServices.Razor.Serialization;
using Newtonsoft.Json;
namespace Microsoft.AspNetCore.Razor.Performance
{
public class TagHelperSerializationBenchmark
{
private readonly byte[] _tagHelperBuffer;
public TagHelperSerializationBenchmark()
{
var current = new DirectoryInfo(AppContext.BaseDirectory);
while (current != null && !File.Exists(Path.Combine(current.FullName, "taghelpers.json")))
{
current = current.Parent;
}
var tagHelperFilePath = Path.Combine(current.FullName, "taghelpers.json");
_tagHelperBuffer = File.ReadAllBytes(tagHelperFilePath);
}
[Benchmark(Description = "Razor TagHelper Serialization")]
public void TagHelper_Serialization_RoundTrip()
{
var serializer = new JsonSerializer();
serializer.Converters.Add(new RazorDiagnosticJsonConverter());
serializer.Converters.Add(new TagHelperDescriptorJsonConverter());
// Deserialize from json file.
IReadOnlyList<TagHelperDescriptor> tagHelpers;
using (var stream = new MemoryStream(_tagHelperBuffer))
using (var reader = new JsonTextReader(new StreamReader(stream)))
{
tagHelpers = serializer.Deserialize<IReadOnlyList<TagHelperDescriptor>>(reader);
}
// Serialize back to json.
using (var stream = new MemoryStream())
using (var writer = new StreamWriter(stream, Encoding.UTF8, bufferSize: 4096))
{
serializer.Serialize(writer, tagHelpers);
}
}
}
}

View File

@ -0,0 +1,11 @@
Compile the solution in Release mode (so binaries are available in release)
To run a specific benchmark add it as parameter.
```
dotnet run -c Release <benchmark_name>
```
If you run without any parameters, you'll be offered the list of all benchmarks and get to choose.
```
dotnet run -c Release
```

File diff suppressed because one or more lines are too long

BIN
src/Razor/build/Key.snk Normal file

Binary file not shown.

View File

@ -0,0 +1,97 @@
<Project>
<PropertyGroup>
<PackageDependsOn>$(PackageDependsOn);GenerateMPack</PackageDependsOn>
<GetArtifactInfoDependsOn>$(GetArtifactInfoDependsOn);GetMPackArtifactInfo</GetArtifactInfoDependsOn>
<AddinName>Microsoft.VisualStudio.Mac.RazorAddin</AddinName>
<AddinDirectory>$(RepositoryRoot)tooling\$(AddinName)\</AddinDirectory>
<MPackArtifactCategory>shipoob</MPackArtifactCategory>
<MPackIntermediateOutputPath>$(IntermediateDir)mpack\</MPackIntermediateOutputPath>
<AddinOutputPath>$(AddinDirectory)bin\$(Configuration)\net461\</AddinOutputPath>
<LanguageServiceName>Microsoft.VisualStudio.Mac.LanguageServices.Razor</LanguageServiceName>
<LanguageServiceOutputPath>$(RepositoryRoot)src\$(LanguageServiceName)\bin\$(Configuration)\net461\</LanguageServiceOutputPath>
<MPackName>$(AddinName)_$(AddinVersion)</MPackName>
<MPackFileName>$(MPackName).mpack</MPackFileName>
<MPackOutputPath>$(BuildDir)$(MPackFileName)</MPackOutputPath>
<MPackZipFile>$(BuildDir)$(MPackName).zip</MPackZipFile>
<MPackManifest>$(AddinDirectory)Properties\_Manifest.addin.xml</MPackManifest>
<AddinInfoFilePath>$(MPackIntermediateOutputPath)addin.info</AddinInfoFilePath>
</PropertyGroup>
<Import Project="$(AddinDirectory)AddinMetadata.props" />
<!-- This target is required so KoreBuild can generate a bill of materials with relevant information about the .mpack files. -->
<Target Name="GetMPackArtifactInfo">
<ItemGroup>
<ArtifactInfo Include="$(MPackOutputPath)">
<ArtifactType>MPackFile</ArtifactType>
<PackageId>$(AddinName)</PackageId>
<Version>$(AddinVersion)</Version>
<Category>$(MPackArtifactCategory)</Category>
</ArtifactInfo>
<FilesToExcludeFromSigning Include="$(MPackOutputPath)" />
</ItemGroup>
</Target>
<Target Name="GenerateMPack">
<!--
In our case the mpack archive requires the following:
1. An addin.info
2. An addin binary (Microsoft.VisualStudio.Mac.RazorAddin.dll)
a. _Manifest.addin.xml embedded
b. Addin assembly attributes for metadata
3. All language service binaries
-->
<MakeDir Directories="$(MPackIntermediateOutputPath)" Condition="!Exists('$(MPackIntermediateOutputPath)')" />
<Delete Files="$(MPackOutputPath)" Condition="Exists('$(MPackOutputPath)')" />
<!-- We need to resolve the language service assemblies to generate an addin.info for the mpack -->
<XmlPeek XmlInputPath="$(MPackManifest)" Query="/ExtensionModel/Runtime/Import/@assembly">
<Output TaskParameter="Result" ItemName="LanguageServiceAssemblyNames" />
</XmlPeek>
<!-- We need to resolve the addin dependencies to generate an addin.info for the mpack -->
<XmlPeek XmlInputPath="$(MPackManifest)" Query="/ExtensionModel/Dependencies/Addin">
<Output TaskParameter="Result" ItemName="AddinDependencies" />
</XmlPeek>
<ItemGroup>
<AddinInfoLine Include="&lt;Addin id=&quot;$(AddinId)&quot; namespace=&quot;$(AddinNamespace)&quot; version=&quot;$(AddinVersion)&quot; name=&quot;$(AddinDetailedName)&quot; author=&quot;$(Authors)&quot; description=&quot;$(Description)&quot; category=&quot;$(AddinCategory)&quot;&gt;" />
<AddinInfoLine Include=" &lt;Runtime&gt;" />
<AddinInfoLine Include=" &lt;Import assembly=&quot;%(LanguageServiceAssemblyNames.Identity)&quot; /&gt;" />
<AddinInfoLine Include=" &lt;Import assembly=&quot;$(AddinName).dll&quot; /&gt;" />
<AddinInfoLine Include=" &lt;/Runtime&gt;" />
<AddinInfoLine Include=" &lt;Dependencies&gt;" />
<AddinInfoLine Include=" %(AddinDependencies.Identity)" />
<AddinInfoLine Include=" &lt;/Dependencies&gt;" />
<AddinInfoLine Include="&lt;/Addin&gt;" />
</ItemGroup>
<ItemGroup>
<LanguageServiceExtensionAssembly Include="$(RepositoryRoot)src\Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X\bin\$(Configuration)\net46\Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X.dll" />
<LanguageServiceExtensionAssembly Include="$(RepositoryRoot)src\Microsoft.AspNetCore.Mvc.Razor.Extensions\bin\$(Configuration)\net46\Microsoft.AspNetCore.Mvc.Razor.Extensions.dll" />
<LanguageServiceAssembly Include="$(LanguageServiceOutputPath)%(LanguageServiceAssemblyNames.Identity)" Condition="Exists('$(LanguageServiceOutputPath)%(LanguageServiceAssemblyNames.Identity)')" />
<LanguageServiceAssembly Include="%(LanguageServiceExtensionAssembly.Identity)" />
<LanguageServicePDB Include="%(LanguageServiceAssembly.RootDir)%(Directory)%(FileName).pdb" Condition="Exists('%(LanguageServiceAssembly.RootDir)%(Directory)%(FileName).pdb')" />
</ItemGroup>
<!-- Generate the addin.info and gather sources for mpack zipping-->
<WriteLinesToFile File="$(AddinInfoFilePath)" Lines="@(AddinInfoLine)" Overwrite="true" />
<Copy SourceFiles="%(LanguageServiceAssembly.Identity)" DestinationFolder="$(MPackIntermediateOutputPath)" />
<Copy SourceFiles="%(LanguageServicePDB.Identity)" DestinationFolder="$(MPackIntermediateOutputPath)" />
<Copy SourceFiles="$(AddinOutputPath)$(AddinName).dll" DestinationFolder="$(MPackIntermediateOutputPath)" />
<Copy SourceFiles="$(AddinOutputPath)$(AddinName).pdb" DestinationFolder="$(MPackIntermediateOutputPath)" />
<ItemGroup>
<MPackFile Include="$(MPackIntermediateOutputPath)\*" />
</ItemGroup>
<ZipArchive
File="$(MPackOutputPath)"
SourceFiles="@(MPackFile)"
WorkingDirectory="$(MPackIntermediateOutputPath)" />
</Target>
</Project>

View File

@ -0,0 +1,121 @@
<Project>
<PropertyGroup>
<BuildVSIX Condition="'$(BuildVSIX)' ==''">true</BuildVSIX>
<RestoreDependsOn Condition="'$(OS)'=='Windows_NT' AND '$(BuildVSIX)' == 'true'">$(RestoreDependsOn);RestoreVSIX</RestoreDependsOn>
<PackageDependsOn Condition="'$(OS)'=='Windows_NT' AND '$(BuildVSIX)' == 'true'">$(PackageDependsOn);PackageVSIX</PackageDependsOn>
<GetArtifactInfoDependsOn Condition="'$(OS)'=='Windows_NT' AND '$(BuildVSIX)' == 'true'">$(GetArtifactInfoDependsOn);GetVSIXArtifactInfo</GetArtifactInfoDependsOn>
<VSIXName>Microsoft.VisualStudio.RazorExtension</VSIXName>
<VSIXOutputPath>$(BuildDir)$(VSIXName).vsix</VSIXOutputPath>
<VSIXManifestOutputPath>$(BuildDir)$(VSIXName).json</VSIXManifestOutputPath>
<VSIXProject>$(RepositoryRoot)tooling\$(VSIXName)\$(VSIXName).csproj</VSIXProject>
<VSIXSymbolsOutputPath>$(BuildDir)$(VSIXName).pdb</VSIXSymbolsOutputPath>
<VSIXArtifactCategory>shipoob</VSIXArtifactCategory>
</PropertyGroup>
<Target
Name="GenerateVSIX"
DependsOnTargets="RestoreVSIX;PackageVSIX"
Condition="'$(OS)'=='Windows_NT'" />
<!-- This target is required so KoreBuild can generate a bill of materials with relevant information about the VSIX. -->
<Target Name="GetVSIXArtifactInfo">
<ItemGroup>
<ArtifactInfo Include="$(VSIXOutputPath)">
<ArtifactType>VsixPackage</ArtifactType>
<Version>$(PackageVersion)</Version>
<Category>$(VSIXArtifactCategory)</Category>
<PackageId>$(VSIXName)</PackageId>
</ArtifactInfo>
<ArtifactInfo Include="$(VSIXSymbolsOutputPath)">
<ArtifactType>SymbolsFile</ArtifactType>
<Category>$(VSIXArtifactCategory)</Category>
<Dependencies>$(VSIXName).vsix</Dependencies>
<DebugType>full</DebugType>
</ArtifactInfo>
<ArtifactInfo Include="$(VSIXManifestOutputPath)">
<ArtifactType>VsixPackageManifestFile</ArtifactType>
<Category>$(VSIXArtifactCategory)</Category>
<Dependencies>$(VSIXName).vsix</Dependencies>
<PackageId>$(VSIXName)</PackageId>
</ArtifactInfo>
<FilesToSign Include="$(VSIXOutputPath)" Certificate="Vsix" />
<FilesToExcludeFromSigning Include="$(VSIXManifestOutputPath)" />
<FilesToExcludeFromSigning Include="$(VSIXSymbolsOutputPath)" />
</ItemGroup>
</Target>
<!--
VisualStudioMSBuildx86Path is set by the GetToolsets target in KoreBuild if a version of VS matching the requirements in korebuild.json is found.
-->
<Target Name="RestoreVSIX" DependsOnTargets="GetToolsets">
<PropertyGroup>
<VSIXResponseFilePath>$(LogOutputDir)vsix-restore.rsp</VSIXResponseFilePath>
</PropertyGroup>
<ItemGroup>
<MSBuildArguments Remove="@(MSBuildArguments)" />
<MSBuildArguments Include="
$(VSIXProject);
/t:Restore;
/m;
/v:m;
/p:Configuration=$(Configuration);
/p:BuildNumber=$(BuildNumber);" />
<MSBuildArguments Include="/p:DotNetPackageVersionPropsPath=$(DotNetPackageVersionPropsPath)" Condition="'$(DotNetPackageVersionPropsPath)' != ''" />
<MSBuildArguments Include="/p:DotNetRestoreSourcePropsPath=$(DotNetRestoreSourcePropsPath)" Condition="'$(DotNetRestoreSourcePropsPath)' != ''" />
</ItemGroup>
<MakeDir Directories="$(LogOutputDir)" />
<WriteLinesToFile
File="$(VSIXResponseFilePath)"
Lines="@(MSBuildArguments)"
Overwrite="true" />
<Exec Command="&quot;$(VisualStudioMSBuildx86Path)&quot; @&quot;$(VSIXResponseFilePath)&quot;"
Condition="'$(VisualStudioMSBuildx86Path)' != ''" />
</Target>
<Target Name="PackageVSIX" DependsOnTargets="GetToolsets">
<Warning Text="Could not find a version of Visual Studio that has the Visual Studio SDK installed. This is required to build the Razor VSIX. Skipping."
Condition="'$(VisualStudioMSBuildx86Path)' == ''" />
<PropertyGroup>
<VSIXLogFilePath>$(LogOutputDir)vsix.log</VSIXLogFilePath>
<VSIXResponseFilePath>$(LogOutputDir)vsix-build.rsp</VSIXResponseFilePath>
</PropertyGroup>
<ItemGroup>
<MSBuildArguments Remove="@(MSBuildArguments)" />
<MSBuildArguments Include="
$(VSIXProject);
/m;
/v:M;
/fl;
/flp:LogFile=$(VSIXLogFilePath);
/p:DeployExtension=false;
/p:TargetVSIXContainer=$(VSIXOutputPath);
/p:SymbolsPublishDir=$(BuildDir);
/p:Configuration=$(Configuration);
/p:LangVersion=7.1" />
</ItemGroup>
<MakeDir Directories="$(LogOutputDir)" />
<WriteLinesToFile
File="$(VSIXResponseFilePath)"
Lines="@(MSBuildArguments)"
Overwrite="true" />
<Exec Command="&quot;$(VisualStudioMSBuildx86Path)&quot; @&quot;$(VSIXResponseFilePath)&quot;"
Condition="'$(VisualStudioMSBuildx86Path)' != ''" />
</Target>
</Project>

View File

@ -0,0 +1,10 @@
@Library('dotnet-ci') _
simpleNode('Ubuntu16.04', 'latest-or-auto-docker') {
stage ('Checking out source') {
checkout scm
}
stage ('Build') {
sh './build.sh --ci'
}
}

View File

@ -0,0 +1,10 @@
@Library('dotnet-ci') _
simpleNode('OSX10.12','latest') {
stage ('Checking out source') {
checkout scm
}
stage ('Build') {
sh './build.sh --ci'
}
}

View File

@ -0,0 +1,18 @@
import org.dotnet.ci.pipelines.Pipeline
def windowsPipeline = Pipeline.createPipeline(this, 'build/buildpipeline/windows.groovy')
def linuxPipeline = Pipeline.createPipeline(this, 'build/buildpipeline/linux.groovy')
def osxPipeline = Pipeline.createPipeline(this, 'build/buildpipeline/osx.groovy')
String configuration = 'Release'
def parameters = [
'Configuration': configuration
]
windowsPipeline.triggerPipelineOnEveryGithubPR("Windows ${configuration} x64 Build", parameters)
windowsPipeline.triggerPipelineOnGithubPush(parameters)
linuxPipeline.triggerPipelineOnEveryGithubPR("Ubuntu 16.04 ${configuration} Build", parameters)
linuxPipeline.triggerPipelineOnGithubPush(parameters)
osxPipeline.triggerPipelineOnEveryGithubPR("OSX 10.12 ${configuration} Build", parameters)
osxPipeline.triggerPipelineOnGithubPush(parameters)

View File

@ -0,0 +1,12 @@
@Library('dotnet-ci') _
// 'node' indicates to Jenkins that the enclosed block runs on a node that matches
// the label 'windows-with-vs'
simpleNode('Windows.10.Amd64.EnterpriseRS3.ASPNET.Open') {
stage ('Checking out source') {
checkout scm
}
stage ('Build') {
bat '.\\run.cmd -CI default-build'
}
}

View File

@ -0,0 +1,72 @@
<Project>
<PropertyGroup>
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
</PropertyGroup>
<!-- These package versions may be overridden or updated by automation. -->
<PropertyGroup Label="Package Versions: Auto">
<BenchmarkDotNetPackageVersion>0.10.13</BenchmarkDotNetPackageVersion>
<InternalAspNetCoreSdkPackageVersion>2.1.3-rtm-15802</InternalAspNetCoreSdkPackageVersion>
<MicrosoftBuildFrameworkPackageVersion>15.6.82</MicrosoftBuildFrameworkPackageVersion>
<MicrosoftBuildPackageVersion>15.6.82</MicrosoftBuildPackageVersion>
<MicrosoftBuildUtilitiesCorePackageVersion>15.6.82</MicrosoftBuildUtilitiesCorePackageVersion>
<MicrosoftCodeAnalysisCommonPackageVersion>2.8.0</MicrosoftCodeAnalysisCommonPackageVersion>
<MicrosoftCodeAnalysisCSharpPackageVersion>2.8.0</MicrosoftCodeAnalysisCSharpPackageVersion>
<MicrosoftExtensionsDependencyModelPackageVersion>2.1.0</MicrosoftExtensionsDependencyModelPackageVersion>
<MicrosoftNETCoreApp20PackageVersion>2.0.0</MicrosoftNETCoreApp20PackageVersion>
<MicrosoftNETCoreApp21PackageVersion>2.1.2</MicrosoftNETCoreApp21PackageVersion>
<MicrosoftNETTestSdkPackageVersion>15.6.1</MicrosoftNETTestSdkPackageVersion>
<MicrosoftVisualStudioComponentModelHostPackageVersion>15.0.26606</MicrosoftVisualStudioComponentModelHostPackageVersion>
<MicrosoftVisualStudioEditorPackageVersion>15.6.161-preview</MicrosoftVisualStudioEditorPackageVersion>
<MicrosoftVisualStudioLanguageIntellisensePackageVersion>15.6.161-preview</MicrosoftVisualStudioLanguageIntellisensePackageVersion>
<MicrosoftVisualStudioOLEInteropPackageVersion>7.10.6070</MicrosoftVisualStudioOLEInteropPackageVersion>
<MicrosoftVisualStudioProjectSystemAnalyzersPackageVersion>15.3.224</MicrosoftVisualStudioProjectSystemAnalyzersPackageVersion>
<MicrosoftVisualStudioProjectSystemManagedVSPackageVersion>2.0.6142705</MicrosoftVisualStudioProjectSystemManagedVSPackageVersion>
<MicrosoftVisualStudioProjectSystemSDKPackageVersion>15.3.224</MicrosoftVisualStudioProjectSystemSDKPackageVersion>
<MicrosoftVisualStudioShell150PackageVersion>15.0.26606</MicrosoftVisualStudioShell150PackageVersion>
<MicrosoftVisualStudioShellInterop100PackageVersion>10.0.30319</MicrosoftVisualStudioShellInterop100PackageVersion>
<MicrosoftVisualStudioShellInterop110PackageVersion>11.0.61030</MicrosoftVisualStudioShellInterop110PackageVersion>
<MicrosoftVisualStudioShellInterop120PackageVersion>12.0.30110</MicrosoftVisualStudioShellInterop120PackageVersion>
<MicrosoftVisualStudioShellInterop80PackageVersion>8.0.50727</MicrosoftVisualStudioShellInterop80PackageVersion>
<MicrosoftVisualStudioShellInterop90PackageVersion>9.0.30729</MicrosoftVisualStudioShellInterop90PackageVersion>
<MicrosoftVisualStudioShellInteropPackageVersion>7.10.6071</MicrosoftVisualStudioShellInteropPackageVersion>
<MicrosoftVisualStudioTextUIPackageVersion>15.6.161-preview</MicrosoftVisualStudioTextUIPackageVersion>
<MonoAddinsPackageVersion>1.3.8</MonoAddinsPackageVersion>
<MonoDevelopSdkPackageVersion>1.0.1</MonoDevelopSdkPackageVersion>
<MoqPackageVersion>4.7.49</MoqPackageVersion>
<NETStandardLibrary20PackageVersion>2.0.3</NETStandardLibrary20PackageVersion>
<NewtonsoftJsonPackageVersion>11.0.2</NewtonsoftJsonPackageVersion>
<StreamJsonRpcPackageVersion>1.1.92</StreamJsonRpcPackageVersion>
<SystemDiagnosticsDiagnosticSourcePackageVersion>4.5.0</SystemDiagnosticsDiagnosticSourcePackageVersion>
<SystemRuntimeInteropServicesRuntimeInformationPackageVersion>4.3.0</SystemRuntimeInteropServicesRuntimeInformationPackageVersion>
<SystemValueTuplePackageVersion>4.5.0</SystemValueTuplePackageVersion>
<VisualStudio_NewtonsoftJsonPackageVersion>9.0.1</VisualStudio_NewtonsoftJsonPackageVersion>
<VSIX_MicrosoftCodeAnalysisCommonPackageVersion>2.8.0</VSIX_MicrosoftCodeAnalysisCommonPackageVersion>
<VSIX_MicrosoftCodeAnalysisCSharpFeaturesPackageVersion>2.8.0</VSIX_MicrosoftCodeAnalysisCSharpFeaturesPackageVersion>
<VSIX_MicrosoftCodeAnalysisCSharpPackageVersion>2.8.0</VSIX_MicrosoftCodeAnalysisCSharpPackageVersion>
<VSIX_MicrosoftCodeAnalysisCSharpWorkspacesPackageVersion>2.8.0</VSIX_MicrosoftCodeAnalysisCSharpWorkspacesPackageVersion>
<VSIX_MicrosoftCodeAnalysisEditorFeaturesTextPackageVersion>2.8.0</VSIX_MicrosoftCodeAnalysisEditorFeaturesTextPackageVersion>
<VSIX_MicrosoftCodeAnalysisRemoteRazorServiceHubPackageVersion>2.8.0-beta2-62721-09</VSIX_MicrosoftCodeAnalysisRemoteRazorServiceHubPackageVersion>
<VSIX_MicrosoftCodeAnalysisVisualBasicWorkspacesPackageVersion>2.8.0</VSIX_MicrosoftCodeAnalysisVisualBasicWorkspacesPackageVersion>
<VSIX_MicrosoftCodeAnalysisWorkspacesCommonPackageVersion>2.8.0</VSIX_MicrosoftCodeAnalysisWorkspacesCommonPackageVersion>
<VSIX_MicrosoftVisualStudioLanguageServicesPackageVersion>2.8.0</VSIX_MicrosoftVisualStudioLanguageServicesPackageVersion>
<VSIX_MicrosoftVisualStudioLanguageServicesRazorRemoteClientPackageVersion>2.8.0-beta2-62721-09</VSIX_MicrosoftVisualStudioLanguageServicesRazorRemoteClientPackageVersion>
<XunitAnalyzersPackageVersion>0.8.0</XunitAnalyzersPackageVersion>
<XunitPackageVersion>2.3.1</XunitPackageVersion>
<XunitRunnerVisualStudioPackageVersion>2.4.0-beta.1.build3945</XunitRunnerVisualStudioPackageVersion>
</PropertyGroup>
<!-- This may import a generated file which may override the variables above. -->
<Import Project="$(DotNetPackageVersionPropsPath)" Condition=" '$(DotNetPackageVersionPropsPath)' != '' " />
<!-- These are package versions that should not be overridden or updated by automation. -->
<PropertyGroup Label="Package Versions: Pinned">
<MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>2.1.1</MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>
<MicrosoftAspNetCoreHtmlAbstractionsPackageVersion>2.1.1</MicrosoftAspNetCoreHtmlAbstractionsPackageVersion>
<MicrosoftAspNetCoreTestingPackageVersion>2.1.0</MicrosoftAspNetCoreTestingPackageVersion>
<MicrosoftExtensionsCommandLineUtilsSourcesPackageVersion>2.1.1</MicrosoftExtensionsCommandLineUtilsSourcesPackageVersion>
<MicrosoftExtensionsCopyOnWriteDictionarySourcesPackageVersion>2.1.1</MicrosoftExtensionsCopyOnWriteDictionarySourcesPackageVersion>
<MicrosoftExtensionsHashCodeCombinerSourcesPackageVersion>2.1.1</MicrosoftExtensionsHashCodeCombinerSourcesPackageVersion>
<MicrosoftExtensionsWebEncodersPackageVersion>2.1.1</MicrosoftExtensionsWebEncodersPackageVersion>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,32 @@
<Project>
<Import Project="dependencies.props" />
<PropertyGroup>
<EnableBenchmarkValidation>true</EnableBenchmarkValidation>
</PropertyGroup>
<ItemGroup>
<ExcludeFromTest Include="$(RepositoryRoot)test\Microsoft.VisualStudio.Mac.LanguageServices.Razor.Test\Microsoft.VisualStudio.Mac.LanguageServices.Razor.Test.csproj" Condition="'$(OS)'!='Windows_NT'" />
<ExcludeFromTest Include="$(RepositoryRoot)test\Microsoft.VisualStudio.LanguageServices.Razor.Test\Microsoft.VisualStudio.LanguageServices.Razor.Test.csproj" Condition="'$(OS)'!='Windows_NT'" />
<ExcludeFromTest Include="$(RepositoryRoot)test\Microsoft.AspNetCore.Razor.Test.Common\Microsoft.AspNetCore.Razor.Test.Common.csproj" />
<ExcludeFromTest Include="$(RepositoryRoot)test\Microsoft.VisualStudio.Editor.Razor.Test\Microsoft.VisualStudio.Editor.Razor.Test.csproj" Condition="'$(OS)'!='Windows_NT'" />
<ExcludeFromTest Include="$(RepositoryRoot)test\Microsoft.CodeAnalysis.Razor.Workspaces.Test.Common\Microsoft.CodeAnalysis.Razor.Workspaces.Test.Common.csproj" />
<ExcludeFromTest Include="$(RepositoryRoot)test\Microsoft.VisualStudio.Editor.Razor.Test.Common\Microsoft.VisualStudio.Editor.Razor.Test.Common.csproj" />
<ExcludeFromTest Include="$(RepositoryRoot)test\Microsoft.AspNetCore.Razor.Performance\Microsoft.AspNetCore.Razor.Performance.csproj" />
<ExcludeFromTest Include="$(RepositoryRoot)test\Microsoft.AspNetCore.Razor.Test.MvcShim\Microsoft.AspNetCore.Razor.Test.MvcShim.csproj" />
<ExcludeFromTest Include="$(RepositoryRoot)test\Microsoft.AspNetCore.Razor.Test.MvcShim.Version1_X\Microsoft.AspNetCore.Razor.Test.MvcShim.Version1_X.csproj" />
<ExcludeSolutions Include="$(RepositoryRoot)Razor.Slim.sln" />
</ItemGroup>
<PropertyGroup>
<!-- These properties are use by the automation that updates dependencies.props -->
<LineupPackageId>Internal.AspNetCore.Universe.Lineup</LineupPackageId>
<LineupPackageVersion>2.1.0-rc1-*</LineupPackageVersion>
<LineupPackageRestoreSource>https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json</LineupPackageRestoreSource>
</PropertyGroup>
<ItemGroup>
<DotNetCoreRuntime Include="$(MicrosoftNETCoreApp20PackageVersion)" />
<DotNetCoreRuntime Include="$(MicrosoftNETCoreApp21PackageVersion)" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,33 @@
<Project>
<Import Project="VSIX.targets" />
<Import Project="MPack.targets" />
<ItemGroup>
<Solutions Update="$(RepositoryRoot)Razor.sln">
<!-- the 'DebugNoVSIX' and 'ReleaseNoVSIX' configurations exclude the VSIX project, which doesn't build with Microsoft.NET.Sdk yet. -->
<AdditionalProperties>Configuration=$(Configuration)NoVSIX</AdditionalProperties>
</Solutions>
</ItemGroup>
<PropertyGroup>
<PrepareDependsOn>$(PrepareDependsOn);GenerateMSBuildLocationFile</PrepareDependsOn>
<RazorDesignTestProject>$(RepositoryRoot)test\Microsoft.AspNetCore.Razor.Design.Test\</RazorDesignTestProject>
<MSBuildLocationFileTemplate>$(RazorDesignTestProject)BuildVariables.cs.template</MSBuildLocationFileTemplate>
<MSBuildLocationFileOutput>$(RazorDesignTestProject)obj\BuildVariables.generated.cs</MSBuildLocationFileOutput>
</PropertyGroup>
<Target Name="GenerateMSBuildLocationFile"
DependsOnTargets="GetToolsets"
Inputs="$(MSBuildLocationFileTemplate);$(VisualStudioMSBuildx86Path)"
Outputs="$(MSBuildLocationFileOutput)">
<PropertyGroup>
<TemplateProperties>MSBuildLocation=$(VisualStudioMSBuildx86Path)</TemplateProperties>
</PropertyGroup>
<GenerateFileFromTemplate
TemplateFile="$(MSBuildLocationFileTemplate)"
Properties="$(TemplateProperties)"
OutputPath="$(MSBuildLocationFileOutput)" />
</Target>
</Project>

View File

@ -0,0 +1,21 @@
<Project>
<Import Project="$(DotNetRestoreSourcePropsPath)" Condition="'$(DotNetRestoreSourcePropsPath)' != ''"/>
<PropertyGroup Label="RestoreSources">
<RestoreSources>$(DotNetRestoreSources)</RestoreSources>
<RestoreSources Condition="'$(DotNetBuildOffline)' != 'true' AND '$(AspNetUniverseBuildOffline)' != 'true' ">
$(RestoreSources);
https://dotnet.myget.org/F/dotnet-core/api/v3/index.json;
https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json;
https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json;
https://dotnet.myget.org/F/msbuild/api/v3/index.json;
https://dotnet.myget.org/F/roslyn/api/v3/index.json;
https://vside.myget.org/F/vssdk/api/v3/index.json;
https://vside.myget.org/F/vsmac/api/v3/index.json
</RestoreSources>
<RestoreSources Condition="'$(DotNetBuildOffline)' != 'true'">
$(RestoreSources);
https://api.nuget.org/v3/index.json;
</RestoreSources>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,55 @@
// 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.Html;
namespace Microsoft.AspNetCore.Razor.TagHelpers.Testing
{
internal class CaseSensitiveTagHelperAttributeComparer : IEqualityComparer<TagHelperAttribute>
{
public readonly static CaseSensitiveTagHelperAttributeComparer Default =
new CaseSensitiveTagHelperAttributeComparer();
private CaseSensitiveTagHelperAttributeComparer()
{
}
public bool Equals(TagHelperAttribute attributeX, TagHelperAttribute attributeY)
{
if (attributeX == attributeY)
{
return true;
}
// Normal comparer (TagHelperAttribute.Equals()) doesn't care about the Name case, in tests we do.
return attributeX != null &&
string.Equals(attributeX.Name, attributeY.Name, StringComparison.Ordinal) &&
attributeX.ValueStyle == attributeY.ValueStyle &&
(attributeX.ValueStyle == HtmlAttributeValueStyle.Minimized ||
string.Equals(GetString(attributeX.Value), GetString(attributeY.Value)));
}
public int GetHashCode(TagHelperAttribute attribute)
{
return attribute.GetHashCode();
}
private string GetString(object value)
{
var htmlContent = value as IHtmlContent;
if (htmlContent != null)
{
using (var writer = new StringWriter())
{
htmlContent.WriteTo(writer, NullHtmlEncoder.Default);
return writer.ToString();
}
}
return value?.ToString() ?? string.Empty;
}
}
}

View File

@ -0,0 +1,10 @@
<Project>
<Import Project="..\Directory.Build.props" />
<PropertyGroup>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore;cshtml;razor</PackageTags>
</PropertyGroup>
</Project>

View File

@ -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;
using System.Globalization;
using System.Text;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
{
internal static class CSharpIdentifier
{
private const string CshtmlExtension = ".cshtml";
public static string GetClassNameFromPath(string path)
{
if (string.IsNullOrEmpty(path))
{
return path;
}
if (path.EndsWith(CshtmlExtension, StringComparison.OrdinalIgnoreCase))
{
path = path.Substring(0, path.Length - CshtmlExtension.Length);
}
return SanitizeClassName(path);
}
// CSharp Spec §2.4.2
private static bool IsIdentifierStart(char character)
{
return char.IsLetter(character) ||
character == '_' ||
CharUnicodeInfo.GetUnicodeCategory(character) == UnicodeCategory.LetterNumber;
}
public static bool IsIdentifierPart(char character)
{
return char.IsDigit(character) ||
IsIdentifierStart(character) ||
IsIdentifierPartByUnicodeCategory(character);
}
private static bool IsIdentifierPartByUnicodeCategory(char character)
{
var category = CharUnicodeInfo.GetUnicodeCategory(character);
return category == UnicodeCategory.NonSpacingMark || // Mn
category == UnicodeCategory.SpacingCombiningMark || // Mc
category == UnicodeCategory.ConnectorPunctuation || // Pc
category == UnicodeCategory.Format; // Cf
}
public static string SanitizeClassName(string inputName)
{
if (!IsIdentifierStart(inputName[0]) && IsIdentifierPart(inputName[0]))
{
inputName = "_" + inputName;
}
var builder = new StringBuilder(inputName.Length);
for (var i = 0; i < inputName.Length; i++)
{
var ch = inputName[i];
builder.Append(IsIdentifierPart(ch) ? ch : '_');
}
return builder.ToString();
}
}
}

View File

@ -0,0 +1,29 @@
// 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.Language;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
{
internal class ExtensionInitializer : RazorExtensionInitializer
{
public override void Initialize(RazorProjectEngineBuilder builder)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
if (builder.Configuration.ConfigurationName == "MVC-1.0")
{
RazorExtensions.Register(builder);
}
else if (builder.Configuration.ConfigurationName == "MVC-1.1")
{
RazorExtensions.Register(builder);
RazorExtensions.RegisterViewComponentTagHelpers(builder);
}
}
}
}

View File

@ -0,0 +1,12 @@
// 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.Language.CodeGeneration;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
{
public interface IInjectTargetExtension : ICodeTargetExtension
{
void WriteInjectProperty(CodeRenderingContext context, InjectIntermediateNode node);
}
}

View File

@ -0,0 +1,12 @@
// 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.Language.CodeGeneration;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
{
public interface IViewComponentTagHelperTargetExtension : ICodeTargetExtension
{
void WriteViewComponentTagHelper(CodeRenderingContext context, ViewComponentTagHelperIntermediateNode node);
}
}

View File

@ -0,0 +1,124 @@
// 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.Language;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
{
public static class InjectDirective
{
public static readonly DirectiveDescriptor Directive = DirectiveDescriptor.CreateDirective(
"inject",
DirectiveKind.SingleLine,
builder =>
{
builder
.AddTypeToken(Resources.InjectDirective_TypeToken_Name, Resources.InjectDirective_TypeToken_Description)
.AddMemberToken(Resources.InjectDirective_MemberToken_Name, Resources.InjectDirective_MemberToken_Description);
builder.Usage = DirectiveUsage.FileScopedMultipleOccurring;
builder.Description = Resources.InjectDirective_Description;
});
public static RazorProjectEngineBuilder Register(RazorProjectEngineBuilder builder)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
builder.AddDirective(Directive);
builder.Features.Add(new Pass());
builder.AddTargetExtension(new InjectTargetExtension());
return builder;
}
internal class Pass : IntermediateNodePassBase, IRazorDirectiveClassifierPass
{
// Runs after the @model and @namespace directives
public override int Order => 10;
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
{
var visitor = new Visitor();
visitor.Visit(documentNode);
var modelType = ModelDirective.GetModelType(documentNode);
var properties = new HashSet<string>(StringComparer.Ordinal);
for (var i = visitor.Directives.Count - 1; i >= 0; i--)
{
var directive = visitor.Directives[i];
var tokens = directive.Tokens.ToArray();
if (tokens.Length < 2)
{
continue;
}
var typeName = tokens[0].Content;
var memberName = tokens[1].Content;
if (!properties.Add(memberName))
{
continue;
}
typeName = typeName.Replace("<TModel>", "<" + modelType + ">");
var injectNode = new InjectIntermediateNode()
{
TypeName = typeName,
MemberName = memberName,
};
visitor.Class.Children.Add(injectNode);
}
}
}
private class Visitor : IntermediateNodeWalker
{
public ClassDeclarationIntermediateNode Class { get; private set; }
public IList<DirectiveIntermediateNode> Directives { get; } = new List<DirectiveIntermediateNode>();
public override void VisitClassDeclaration(ClassDeclarationIntermediateNode node)
{
if (Class == null)
{
Class = node;
}
base.VisitClassDeclaration(node);
}
public override void VisitDirective(DirectiveIntermediateNode node)
{
if (node.Directive == Directive)
{
Directives.Add(node);
}
}
}
#region Obsolete
[Obsolete("This method is obsolete and will be removed in a future version.")]
public static IRazorEngineBuilder Register(IRazorEngineBuilder builder)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
builder.AddDirective(Directive);
builder.Features.Add(new Pass());
builder.AddTargetExtension(new InjectTargetExtension());
return builder;
}
#endregion
}
}

View File

@ -0,0 +1,51 @@
// 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.Language;
using Microsoft.AspNetCore.Razor.Language.CodeGeneration;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
{
public class InjectIntermediateNode : ExtensionIntermediateNode
{
public string TypeName { get; set; }
public string MemberName { get; set; }
public override IntermediateNodeCollection Children => IntermediateNodeCollection.ReadOnly;
public override void Accept(IntermediateNodeVisitor visitor)
{
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
AcceptExtensionNode<InjectIntermediateNode>(this, visitor);
}
public override void WriteNode(CodeTarget target, CodeRenderingContext context)
{
if (target == null)
{
throw new ArgumentNullException(nameof(target));
}
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var extension = target.GetExtension<IInjectTargetExtension>();
if (extension == null)
{
ReportMissingCodeTargetExtension<IInjectTargetExtension>(context);
return;
}
extension.WriteInjectProperty(context, this);
}
}
}

View File

@ -0,0 +1,44 @@
// 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.Language.CodeGeneration;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
{
public class InjectTargetExtension : IInjectTargetExtension
{
private const string RazorInjectAttribute = "[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]";
public void WriteInjectProperty(CodeRenderingContext context, InjectIntermediateNode node)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (node == null)
{
throw new ArgumentNullException(nameof(node));
}
var property = $"public {node.TypeName} {node.MemberName} {{ get; private set; }}";
if (node.Source.HasValue)
{
using (context.CodeWriter.BuildLinePragma(node.Source.Value))
{
context.CodeWriter
.WriteLine(RazorInjectAttribute)
.WriteLine(property);
}
}
else
{
context.CodeWriter
.WriteLine(RazorInjectAttribute)
.WriteLine(property);
}
}
}
}

View File

@ -0,0 +1,32 @@
// 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.Language.CodeGeneration;
namespace Microsoft.AspNetCore.Razor.Language.Extensions
{
internal class LegacySectionTargetExtension : ISectionTargetExtension
{
private static readonly string DefaultWriterName = "__razor_section_writer";
public static readonly string DefaultSectionMethodName = "DefineSection";
public string SectionMethodName { get; set; } = DefaultSectionMethodName;
public void WriteSection(CodeRenderingContext context, SectionIntermediateNode node)
{
context.CodeWriter
.WriteStartMethodInvocation(SectionMethodName)
.Write("\"")
.Write(node.SectionName)
.Write("\", ");
using (context.CodeWriter.BuildAsyncLambda(DefaultWriterName))
{
context.RenderChildren(node);
}
context.CodeWriter.WriteEndMethodInvocation(endLine: true);
}
}
}

View File

@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>ASP.NET Core design time hosting infrastructure for the Razor view engine.</Description>
<TargetFrameworks>net46;netstandard2.0</TargetFrameworks>
<PackageTags>$(PackageTags);aspnetcoremvc</PackageTags>
<EnableApiCheck>false</EnableApiCheck>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\Microsoft.AspNetCore.Razor.Language\CodeGeneration\CodeWriterExtensions.cs">
<Link>Shared\CodeWriterExtensions.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../Microsoft.AspNetCore.Razor.Language/Microsoft.AspNetCore.Razor.Language.csproj" />
<ProjectReference Include="../Microsoft.CodeAnalysis.Razor/Microsoft.CodeAnalysis.Razor.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,145 @@
// 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.Language;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
{
public static class ModelDirective
{
public static readonly DirectiveDescriptor Directive = DirectiveDescriptor.CreateDirective(
"model",
DirectiveKind.SingleLine,
builder =>
{
builder.AddTypeToken(Resources.ModelDirective_TypeToken_Name, Resources.ModelDirective_TypeToken_Description);
builder.Usage = DirectiveUsage.FileScopedSinglyOccurring;
builder.Description = Resources.ModelDirective_Description;
});
public static RazorProjectEngineBuilder Register(RazorProjectEngineBuilder builder)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
builder.AddDirective(Directive);
builder.Features.Add(new Pass());
return builder;
}
public static string GetModelType(DocumentIntermediateNode document)
{
if (document == null)
{
throw new ArgumentNullException(nameof(document));
}
var visitor = new Visitor();
return GetModelType(document, visitor);
}
private static string GetModelType(DocumentIntermediateNode document, Visitor visitor)
{
visitor.Visit(document);
for (var i = visitor.ModelDirectives.Count - 1; i >= 0; i--)
{
var directive = visitor.ModelDirectives[i];
var tokens = directive.Tokens.ToArray();
if (tokens.Length >= 1)
{
return tokens[0].Content;
}
}
return "dynamic";
}
internal class Pass : IntermediateNodePassBase, IRazorDirectiveClassifierPass
{
// Runs after the @inherits directive
public override int Order => 5;
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
{
var visitor = new Visitor();
var modelType = GetModelType(documentNode, visitor);
if (documentNode.Options.DesignTime)
{
// Alias the TModel token to a known type.
// This allows design time compilation to succeed for Razor files where the token isn't replaced.
var typeName = $"global::{typeof(object).FullName}";
var usingNode = new UsingDirectiveIntermediateNode()
{
Content = $"TModel = {typeName}"
};
visitor.Namespace?.Children.Insert(0, usingNode);
}
var baseType = visitor.Class?.BaseType?.Replace("<TModel>", "<" + modelType + ">");
visitor.Class.BaseType = baseType;
}
}
private class Visitor : IntermediateNodeWalker
{
public NamespaceDeclarationIntermediateNode Namespace { get; private set; }
public ClassDeclarationIntermediateNode Class { get; private set; }
public IList<DirectiveIntermediateNode> ModelDirectives { get; } = new List<DirectiveIntermediateNode>();
public override void VisitNamespaceDeclaration(NamespaceDeclarationIntermediateNode node)
{
if (Namespace == null)
{
Namespace = node;
}
base.VisitNamespaceDeclaration(node);
}
public override void VisitClassDeclaration(ClassDeclarationIntermediateNode node)
{
if (Class == null)
{
Class = node;
}
base.VisitClassDeclaration(node);
}
public override void VisitDirective(DirectiveIntermediateNode node)
{
if (node.Directive == Directive)
{
ModelDirectives.Add(node);
}
}
}
#region Obsolete
[Obsolete("This method is obsolete and will be removed in a future version.")]
public static IRazorEngineBuilder Register(IRazorEngineBuilder builder)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
builder.AddDirective(Directive);
builder.Features.Add(new Pass());
return builder;
}
#endregion
}
}

View File

@ -0,0 +1,85 @@
// 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.Text;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
{
public class ModelExpressionPass : IntermediateNodePassBase, IRazorOptimizationPass
{
private const string ModelExpressionTypeName = "Microsoft.AspNetCore.Mvc.ViewFeatures.ModelExpression";
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
{
var visitor = new Visitor();
visitor.Visit(documentNode);
}
private class Visitor : IntermediateNodeWalker
{
public List<TagHelperIntermediateNode> TagHelpers { get; } = new List<TagHelperIntermediateNode>();
public override void VisitTagHelperProperty(TagHelperPropertyIntermediateNode node)
{
if (string.Equals(node.BoundAttribute.TypeName, ModelExpressionTypeName, StringComparison.Ordinal) ||
(node.IsIndexerNameMatch &&
string.Equals(node.BoundAttribute.IndexerTypeName, ModelExpressionTypeName, StringComparison.Ordinal)))
{
var expression = new CSharpExpressionIntermediateNode();
expression.Children.Add(new IntermediateToken()
{
Kind = TokenKind.CSharp,
Content = "ModelExpressionProvider.CreateModelExpression(ViewData, __model => ",
});
if (node.Children.Count == 1 && node.Children[0] is IntermediateToken token && token.IsCSharp)
{
// A 'simple' expression will look like __model => __model.Foo
expression.Children.Add(new IntermediateToken()
{
Kind = TokenKind.CSharp,
Content = "__model."
});
expression.Children.Add(token);
}
else
{
for (var i = 0; i < node.Children.Count; i++)
{
if (node.Children[i] is CSharpExpressionIntermediateNode nestedExpression)
{
for (var j = 0; j < nestedExpression.Children.Count; j++)
{
if (nestedExpression.Children[j] is IntermediateToken cSharpToken &&
cSharpToken.IsCSharp)
{
expression.Children.Add(cSharpToken);
}
}
continue;
}
}
}
expression.Children.Add(new IntermediateToken()
{
Kind = TokenKind.CSharp,
Content = ")",
});
node.Children.Clear();
node.Children.Add(expression);
}
}
}
}
}

View File

@ -0,0 +1,89 @@
// 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 System.Text;
using Microsoft.AspNetCore.Razor.Language;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
{
internal class MvcImportProjectFeature : RazorProjectEngineFeatureBase, IImportProjectFeature
{
private const string ImportsFileName = "_ViewImports.cshtml";
public IReadOnlyList<RazorProjectItem> GetImports(RazorProjectItem projectItem)
{
if (projectItem == null)
{
throw new ArgumentNullException(nameof(projectItem));
}
var imports = new List<RazorProjectItem>();
AddDefaultDirectivesImport(imports);
// We add hierarchical imports second so any default directive imports can be overridden.
AddHierarchicalImports(projectItem, imports);
return imports;
}
// Internal for testing
internal static void AddDefaultDirectivesImport(List<RazorProjectItem> imports)
{
imports.Add(DefaultDirectivesProjectItem.Instance);
}
// Internal for testing
internal void AddHierarchicalImports(RazorProjectItem projectItem, List<RazorProjectItem> imports)
{
// We want items in descending order. FindHierarchicalItems returns items in ascending order.
var importProjectItems = ProjectEngine.FileSystem.FindHierarchicalItems(projectItem.FilePath, ImportsFileName).Reverse();
imports.AddRange(importProjectItems);
}
private class DefaultDirectivesProjectItem : RazorProjectItem
{
private readonly byte[] _defaultImportBytes;
private DefaultDirectivesProjectItem()
{
var preamble = Encoding.UTF8.GetPreamble();
var content = @"
@using System
@using System.Collections.Generic
@using System.Linq
@using System.Threading.Tasks
@using Microsoft.AspNetCore.Mvc
@using Microsoft.AspNetCore.Mvc.Rendering
@using Microsoft.AspNetCore.Mvc.ViewFeatures
@inject global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<TModel> Html
@inject global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json
@inject global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component
@inject global::Microsoft.AspNetCore.Mvc.IUrlHelper Url
@inject global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider
@addTagHelper Microsoft.AspNetCore.Mvc.Razor.TagHelpers.UrlResolutionTagHelper, Microsoft.AspNetCore.Mvc.Razor
";
var contentBytes = Encoding.UTF8.GetBytes(content);
_defaultImportBytes = new byte[preamble.Length + contentBytes.Length];
preamble.CopyTo(_defaultImportBytes, 0);
contentBytes.CopyTo(_defaultImportBytes, preamble.Length);
}
public override string BasePath => null;
public override string FilePath => null;
public override string PhysicalPath => null;
public override bool Exists => true;
public static DefaultDirectivesProjectItem Instance { get; } = new DefaultDirectivesProjectItem();
public override Stream Read() => new MemoryStream(_defaultImportBytes);
}
}
}

View File

@ -0,0 +1,60 @@
// 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.Text;
using Microsoft.AspNetCore.Razor.Language;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
{
/// <summary>
/// A <see cref="RazorTemplateEngine"/> for Mvc Razor views.
/// </summary>
public class MvcRazorTemplateEngine : RazorTemplateEngine
{
/// <summary>
/// Initializes a new instance of <see cref="MvcRazorTemplateEngine"/>.
/// </summary>
/// <param name="engine">The <see cref="RazorEngine"/>.</param>
/// <param name="project">The <see cref="RazorProject"/>.</param>
public MvcRazorTemplateEngine(
RazorEngine engine,
RazorProject project)
: base(engine, project)
{
Options.ImportsFileName = "_ViewImports.cshtml";
Options.DefaultImports = GetDefaultImports();
}
public override RazorCodeDocument CreateCodeDocument(RazorProjectItem projectItem)
{
return base.CreateCodeDocument(projectItem);
}
// Internal for testing.
internal static RazorSourceDocument GetDefaultImports()
{
using (var stream = new MemoryStream())
using (var writer = new StreamWriter(stream, Encoding.UTF8))
{
writer.WriteLine("@using System");
writer.WriteLine("@using System.Collections.Generic");
writer.WriteLine("@using System.Linq");
writer.WriteLine("@using System.Threading.Tasks");
writer.WriteLine("@using Microsoft.AspNetCore.Mvc");
writer.WriteLine("@using Microsoft.AspNetCore.Mvc.Rendering");
writer.WriteLine("@using Microsoft.AspNetCore.Mvc.ViewFeatures");
writer.WriteLine("@inject global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<TModel> Html");
writer.WriteLine("@inject global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json");
writer.WriteLine("@inject global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component");
writer.WriteLine("@inject global::Microsoft.AspNetCore.Mvc.IUrlHelper Url");
writer.WriteLine("@inject global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider");
writer.WriteLine("@addTagHelper Microsoft.AspNetCore.Mvc.Razor.TagHelpers.UrlResolutionTagHelper, Microsoft.AspNetCore.Mvc.Razor");
writer.Flush();
stream.Position = 0;
return RazorSourceDocument.ReadFrom(stream, fileName: null, encoding: Encoding.UTF8);
}
}
}
}

View File

@ -0,0 +1,41 @@
// 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.Language;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
{
public class MvcViewDocumentClassifierPass : DocumentClassifierPassBase
{
public static readonly string MvcViewDocumentKind = "mvc.1.0.view";
protected override string DocumentKind => MvcViewDocumentKind;
protected override bool IsMatch(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode) => true;
protected override void OnDocumentStructureCreated(
RazorCodeDocument codeDocument,
NamespaceDeclarationIntermediateNode @namespace,
ClassDeclarationIntermediateNode @class,
MethodDeclarationIntermediateNode method)
{
base.OnDocumentStructureCreated(codeDocument, @namespace, @class, method);
@namespace.Content = "AspNetCore";
var filePath = codeDocument.Source.RelativePath ?? codeDocument.Source.FilePath;
@class.ClassName = CSharpIdentifier.GetClassNameFromPath(filePath);
@class.BaseType = "global::Microsoft.AspNetCore.Mvc.Razor.RazorPage<TModel>";
@class.Modifiers.Clear();
@class.Modifiers.Add("public");
method.MethodName = "ExecuteAsync";
method.Modifiers.Clear();
method.Modifiers.Add("public");
method.Modifiers.Add("async");
method.Modifiers.Add("override");
method.ReturnType = $"global::{typeof(System.Threading.Tasks.Task).FullName}";
}
}
}

View File

@ -0,0 +1,11 @@
// 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.Runtime.CompilerServices;
using Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X;
using Microsoft.AspNetCore.Razor.Language;
[assembly: ProvideRazorExtensionInitializer("MVC-1.0", typeof(ExtensionInitializer))]
[assembly: ProvideRazorExtensionInitializer("MVC-1.1", typeof(ExtensionInitializer))]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]

View File

@ -0,0 +1,254 @@
// <auto-generated />
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
{
using System.Globalization;
using System.Reflection;
using System.Resources;
internal static class Resources
{
private static readonly ResourceManager _resourceManager
= new ResourceManager("Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X.Resources", typeof(Resources).GetTypeInfo().Assembly);
/// <summary>
/// Value cannot be null or empty.
/// </summary>
internal static string ArgumentCannotBeNullOrEmpy
{
get => GetString("ArgumentCannotBeNullOrEmpy");
}
/// <summary>
/// Value cannot be null or empty.
/// </summary>
internal static string FormatArgumentCannotBeNullOrEmpy()
=> GetString("ArgumentCannotBeNullOrEmpy");
/// <summary>
/// Inject a service from the application's service container into a property.
/// </summary>
internal static string InjectDirective_Description
{
get => GetString("InjectDirective_Description");
}
/// <summary>
/// Inject a service from the application's service container into a property.
/// </summary>
internal static string FormatInjectDirective_Description()
=> GetString("InjectDirective_Description");
/// <summary>
/// The name of the property.
/// </summary>
internal static string InjectDirective_MemberToken_Description
{
get => GetString("InjectDirective_MemberToken_Description");
}
/// <summary>
/// The name of the property.
/// </summary>
internal static string FormatInjectDirective_MemberToken_Description()
=> GetString("InjectDirective_MemberToken_Description");
/// <summary>
/// PropertyName
/// </summary>
internal static string InjectDirective_MemberToken_Name
{
get => GetString("InjectDirective_MemberToken_Name");
}
/// <summary>
/// PropertyName
/// </summary>
internal static string FormatInjectDirective_MemberToken_Name()
=> GetString("InjectDirective_MemberToken_Name");
/// <summary>
/// The type of the service to inject.
/// </summary>
internal static string InjectDirective_TypeToken_Description
{
get => GetString("InjectDirective_TypeToken_Description");
}
/// <summary>
/// The type of the service to inject.
/// </summary>
internal static string FormatInjectDirective_TypeToken_Description()
=> GetString("InjectDirective_TypeToken_Description");
/// <summary>
/// TypeName
/// </summary>
internal static string InjectDirective_TypeToken_Name
{
get => GetString("InjectDirective_TypeToken_Name");
}
/// <summary>
/// TypeName
/// </summary>
internal static string FormatInjectDirective_TypeToken_Name()
=> GetString("InjectDirective_TypeToken_Name");
/// <summary>
/// Specify the view or page model for the page.
/// </summary>
internal static string ModelDirective_Description
{
get => GetString("ModelDirective_Description");
}
/// <summary>
/// Specify the view or page model for the page.
/// </summary>
internal static string FormatModelDirective_Description()
=> GetString("ModelDirective_Description");
/// <summary>
/// The model type.
/// </summary>
internal static string ModelDirective_TypeToken_Description
{
get => GetString("ModelDirective_TypeToken_Description");
}
/// <summary>
/// The model type.
/// </summary>
internal static string FormatModelDirective_TypeToken_Description()
=> GetString("ModelDirective_TypeToken_Description");
/// <summary>
/// TypeName
/// </summary>
internal static string ModelDirective_TypeToken_Name
{
get => GetString("ModelDirective_TypeToken_Name");
}
/// <summary>
/// TypeName
/// </summary>
internal static string FormatModelDirective_TypeToken_Name()
=> GetString("ModelDirective_TypeToken_Name");
/// <summary>
/// The 'inherits' keyword is not allowed when a '{0}' keyword is used.
/// </summary>
internal static string MvcRazorCodeParser_CannotHaveModelAndInheritsKeyword
{
get => GetString("MvcRazorCodeParser_CannotHaveModelAndInheritsKeyword");
}
/// <summary>
/// The 'inherits' keyword is not allowed when a '{0}' keyword is used.
/// </summary>
internal static string FormatMvcRazorCodeParser_CannotHaveModelAndInheritsKeyword(object p0)
=> string.Format(CultureInfo.CurrentCulture, GetString("MvcRazorCodeParser_CannotHaveModelAndInheritsKeyword"), p0);
/// <summary>
/// A property name must be specified when using the '{0}' statement. Format for a '{0}' statement is '@{0} &lt;Type Name&gt; &lt;Property Name&gt;'.
/// </summary>
internal static string MvcRazorCodeParser_InjectDirectivePropertyNameRequired
{
get => GetString("MvcRazorCodeParser_InjectDirectivePropertyNameRequired");
}
/// <summary>
/// A property name must be specified when using the '{0}' statement. Format for a '{0}' statement is '@{0} &lt;Type Name&gt; &lt;Property Name&gt;'.
/// </summary>
internal static string FormatMvcRazorCodeParser_InjectDirectivePropertyNameRequired(object p0)
=> string.Format(CultureInfo.CurrentCulture, GetString("MvcRazorCodeParser_InjectDirectivePropertyNameRequired"), p0);
/// <summary>
/// The '{0}' keyword must be followed by a type name on the same line.
/// </summary>
internal static string MvcRazorCodeParser_KeywordMustBeFollowedByTypeName
{
get => GetString("MvcRazorCodeParser_KeywordMustBeFollowedByTypeName");
}
/// <summary>
/// The '{0}' keyword must be followed by a type name on the same line.
/// </summary>
internal static string FormatMvcRazorCodeParser_KeywordMustBeFollowedByTypeName(object p0)
=> string.Format(CultureInfo.CurrentCulture, GetString("MvcRazorCodeParser_KeywordMustBeFollowedByTypeName"), p0);
/// <summary>
/// Only one '{0}' statement is allowed in a file.
/// </summary>
internal static string MvcRazorCodeParser_OnlyOneModelStatementIsAllowed
{
get => GetString("MvcRazorCodeParser_OnlyOneModelStatementIsAllowed");
}
/// <summary>
/// Only one '{0}' statement is allowed in a file.
/// </summary>
internal static string FormatMvcRazorCodeParser_OnlyOneModelStatementIsAllowed(object p0)
=> string.Format(CultureInfo.CurrentCulture, GetString("MvcRazorCodeParser_OnlyOneModelStatementIsAllowed"), p0);
/// <summary>
/// Invalid tag helper property '{0}.{1}'. Dictionary values must not be of type '{2}'.
/// </summary>
internal static string MvcRazorParser_InvalidPropertyType
{
get => GetString("MvcRazorParser_InvalidPropertyType");
}
/// <summary>
/// Invalid tag helper property '{0}.{1}'. Dictionary values must not be of type '{2}'.
/// </summary>
internal static string FormatMvcRazorParser_InvalidPropertyType(object p0, object p1, object p2)
=> string.Format(CultureInfo.CurrentCulture, GetString("MvcRazorParser_InvalidPropertyType"), p0, p1, p2);
/// <summary>
/// The '@{0}' directive specified in {1} file will not be imported. The directive must appear at the top of each Razor cshtml file.
/// </summary>
internal static string PageDirectiveCannotBeImported
{
get => GetString("PageDirectiveCannotBeImported");
}
/// <summary>
/// The '@{0}' directive specified in {1} file will not be imported. The directive must appear at the top of each Razor cshtml file.
/// </summary>
internal static string FormatPageDirectiveCannotBeImported(object p0, object p1)
=> string.Format(CultureInfo.CurrentCulture, GetString("PageDirectiveCannotBeImported"), p0, p1);
/// <summary>
/// Runtime code generation for Mvc 1.x is not supported.
/// </summary>
internal static string RuntimeCodeGenerationNotSupported
{
get => GetString("RuntimeCodeGenerationNotSupported");
}
/// <summary>
/// Runtime code generation for Mvc 1.x is not supported.
/// </summary>
internal static string FormatRuntimeCodeGenerationNotSupported()
=> GetString("RuntimeCodeGenerationNotSupported");
private static string GetString(string name, params string[] formatterNames)
{
var value = _resourceManager.GetString(name);
System.Diagnostics.Debug.Assert(value != null);
if (formatterNames != null)
{
for (var i = 0; i < formatterNames.Length; i++)
{
value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}");
}
}
return value;
}
}
}

View File

@ -0,0 +1,100 @@
// <auto-generated />
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
{
using System.Globalization;
using System.Reflection;
using System.Resources;
internal static class ViewComponentResources
{
private static readonly ResourceManager _resourceManager
= new ResourceManager("Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X.ViewComponentResources", typeof(ViewComponentResources).GetTypeInfo().Assembly);
/// <summary>
/// View component '{0}' must have exactly one public method named '{1}' or '{2}'.
/// </summary>
internal static string ViewComponent_AmbiguousMethods
{
get => GetString("ViewComponent_AmbiguousMethods");
}
/// <summary>
/// View component '{0}' must have exactly one public method named '{1}' or '{2}'.
/// </summary>
internal static string FormatViewComponent_AmbiguousMethods(object p0, object p1, object p2)
=> string.Format(CultureInfo.CurrentCulture, GetString("ViewComponent_AmbiguousMethods"), p0, p1, p2);
/// <summary>
/// Method '{0}' of view component '{1}' should be declared to return {2}&amp;lt;T&amp;gt;.
/// </summary>
internal static string ViewComponent_AsyncMethod_ShouldReturnTask
{
get => GetString("ViewComponent_AsyncMethod_ShouldReturnTask");
}
/// <summary>
/// Method '{0}' of view component '{1}' should be declared to return {2}&amp;lt;T&amp;gt;.
/// </summary>
internal static string FormatViewComponent_AsyncMethod_ShouldReturnTask(object p0, object p1, object p2)
=> string.Format(CultureInfo.CurrentCulture, GetString("ViewComponent_AsyncMethod_ShouldReturnTask"), p0, p1, p2);
/// <summary>
/// Could not find an '{0}' or '{1}' method for the view component '{2}'.
/// </summary>
internal static string ViewComponent_CannotFindMethod
{
get => GetString("ViewComponent_CannotFindMethod");
}
/// <summary>
/// Could not find an '{0}' or '{1}' method for the view component '{2}'.
/// </summary>
internal static string FormatViewComponent_CannotFindMethod(object p0, object p1, object p2)
=> string.Format(CultureInfo.CurrentCulture, GetString("ViewComponent_CannotFindMethod"), p0, p1, p2);
/// <summary>
/// Method '{0}' of view component '{1}' cannot return a {2}.
/// </summary>
internal static string ViewComponent_SyncMethod_CannotReturnTask
{
get => GetString("ViewComponent_SyncMethod_CannotReturnTask");
}
/// <summary>
/// Method '{0}' of view component '{1}' cannot return a {2}.
/// </summary>
internal static string FormatViewComponent_SyncMethod_CannotReturnTask(object p0, object p1, object p2)
=> string.Format(CultureInfo.CurrentCulture, GetString("ViewComponent_SyncMethod_CannotReturnTask"), p0, p1, p2);
/// <summary>
/// Method '{0}' of view component '{1}' should be declared to return a value.
/// </summary>
internal static string ViewComponent_SyncMethod_ShouldReturnValue
{
get => GetString("ViewComponent_SyncMethod_ShouldReturnValue");
}
/// <summary>
/// Method '{0}' of view component '{1}' should be declared to return a value.
/// </summary>
internal static string FormatViewComponent_SyncMethod_ShouldReturnValue(object p0, object p1)
=> string.Format(CultureInfo.CurrentCulture, GetString("ViewComponent_SyncMethod_ShouldReturnValue"), p0, p1);
private static string GetString(string name, params string[] formatterNames)
{
var value = _resourceManager.GetString(name);
System.Diagnostics.Debug.Assert(value != null);
if (formatterNames != null)
{
for (var i = 0; i < formatterNames.Length; i++)
{
value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}");
}
}
return value;
}
}
}

View File

@ -0,0 +1,118 @@
// 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.Language;
using Microsoft.AspNetCore.Razor.Language.Extensions;
using Microsoft.CodeAnalysis.Razor;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
{
public static class RazorExtensions
{
public static void Register(RazorProjectEngineBuilder builder)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
InjectDirective.Register(builder);
ModelDirective.Register(builder);
FunctionsDirective.Register(builder);
InheritsDirective.Register(builder);
builder.Features.Add(new DefaultTagHelperDescriptorProvider());
// Register section directive with the 1.x compatible target extension.
builder.AddDirective(SectionDirective.Directive);
builder.Features.Add(new SectionDirectivePass());
builder.AddTargetExtension(new LegacySectionTargetExtension());
builder.AddTargetExtension(new TemplateTargetExtension()
{
TemplateTypeName = "global::Microsoft.AspNetCore.Mvc.Razor.HelperResult",
});
builder.Features.Add(new ModelExpressionPass());
builder.Features.Add(new MvcViewDocumentClassifierPass());
builder.SetImportFeature(new MvcImportProjectFeature());
}
public static void RegisterViewComponentTagHelpers(RazorProjectEngineBuilder builder)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
builder.Features.Add(new ViewComponentTagHelperDescriptorProvider());
builder.Features.Add(new ViewComponentTagHelperPass());
builder.AddTargetExtension(new ViewComponentTagHelperTargetExtension());
}
#region Obsolete
[Obsolete("This method is obsolete and will be removed in a future version.")]
public static void Register(IRazorEngineBuilder builder)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
EnsureDesignTime(builder);
InjectDirective.Register(builder);
ModelDirective.Register(builder);
FunctionsDirective.Register(builder);
InheritsDirective.Register(builder);
builder.Features.Add(new DefaultTagHelperDescriptorProvider());
// Register section directive with the 1.x compatible target extension.
builder.AddDirective(SectionDirective.Directive);
builder.Features.Add(new SectionDirectivePass());
builder.AddTargetExtension(new LegacySectionTargetExtension());
builder.AddTargetExtension(new TemplateTargetExtension()
{
TemplateTypeName = "global::Microsoft.AspNetCore.Mvc.Razor.HelperResult",
});
builder.Features.Add(new ModelExpressionPass());
builder.Features.Add(new MvcViewDocumentClassifierPass());
}
[Obsolete("This method is obsolete and will be removed in a future version.")]
public static void RegisterViewComponentTagHelpers(IRazorEngineBuilder builder)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
EnsureDesignTime(builder);
builder.Features.Add(new ViewComponentTagHelperDescriptorProvider());
builder.Features.Add(new ViewComponentTagHelperPass());
builder.AddTargetExtension(new ViewComponentTagHelperTargetExtension());
}
#pragma warning disable CS0618 // Type or member is obsolete
private static void EnsureDesignTime(IRazorEngineBuilder builder)
#pragma warning restore CS0618 // Type or member is obsolete
{
if (builder.DesignTime)
{
return;
}
throw new NotSupportedException(Resources.RuntimeCodeGenerationNotSupported);
}
#endregion
}
}

View File

@ -0,0 +1,103 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
{
internal class RazorExtensionsDiagnosticFactory
{
private const string DiagnosticPrefix = "RZ";
internal static readonly RazorDiagnosticDescriptor ViewComponent_CannotFindMethod =
new RazorDiagnosticDescriptor(
$"{DiagnosticPrefix}3900",
() => ViewComponentResources.ViewComponent_CannotFindMethod,
RazorDiagnosticSeverity.Error);
public static RazorDiagnostic CreateViewComponent_CannotFindMethod(string tagHelperType)
{
var diagnostic = RazorDiagnostic.Create(
ViewComponent_CannotFindMethod,
new SourceSpan(SourceLocation.Undefined, contentLength: 0),
ViewComponentTypes.SyncMethodName,
ViewComponentTypes.AsyncMethodName,
tagHelperType);
return diagnostic;
}
internal static readonly RazorDiagnosticDescriptor ViewComponent_AmbiguousMethods =
new RazorDiagnosticDescriptor(
$"{DiagnosticPrefix}3901",
() => ViewComponentResources.ViewComponent_AmbiguousMethods,
RazorDiagnosticSeverity.Error);
public static RazorDiagnostic CreateViewComponent_AmbiguousMethods(string tagHelperType)
{
var diagnostic = RazorDiagnostic.Create(
ViewComponent_AmbiguousMethods,
new SourceSpan(SourceLocation.Undefined, contentLength: 0),
tagHelperType,
ViewComponentTypes.SyncMethodName,
ViewComponentTypes.AsyncMethodName);
return diagnostic;
}
internal static readonly RazorDiagnosticDescriptor ViewComponent_AsyncMethod_ShouldReturnTask =
new RazorDiagnosticDescriptor(
$"{DiagnosticPrefix}3902",
() => ViewComponentResources.ViewComponent_AsyncMethod_ShouldReturnTask,
RazorDiagnosticSeverity.Error);
public static RazorDiagnostic CreateViewComponent_AsyncMethod_ShouldReturnTask(string tagHelperType)
{
var diagnostic = RazorDiagnostic.Create(
ViewComponent_AsyncMethod_ShouldReturnTask,
new SourceSpan(SourceLocation.Undefined, contentLength: 0),
ViewComponentTypes.AsyncMethodName,
tagHelperType,
nameof(Task));
return diagnostic;
}
internal static readonly RazorDiagnosticDescriptor ViewComponent_SyncMethod_ShouldReturnValue =
new RazorDiagnosticDescriptor(
$"{DiagnosticPrefix}3903",
() => ViewComponentResources.ViewComponent_SyncMethod_ShouldReturnValue,
RazorDiagnosticSeverity.Error);
public static RazorDiagnostic CreateViewComponent_SyncMethod_ShouldReturnValue(string tagHelperType)
{
var diagnostic = RazorDiagnostic.Create(
ViewComponent_SyncMethod_ShouldReturnValue,
new SourceSpan(SourceLocation.Undefined, contentLength: 0),
ViewComponentTypes.SyncMethodName,
tagHelperType);
return diagnostic;
}
internal static readonly RazorDiagnosticDescriptor ViewComponent_SyncMethod_CannotReturnTask =
new RazorDiagnosticDescriptor(
$"{DiagnosticPrefix}3904",
() => ViewComponentResources.ViewComponent_SyncMethod_CannotReturnTask,
RazorDiagnosticSeverity.Error);
public static RazorDiagnostic CreateViewComponent_SyncMethod_CannotReturnTask(string tagHelperType)
{
var diagnostic = RazorDiagnostic.Create(
ViewComponent_SyncMethod_CannotReturnTask,
new SourceSpan(SourceLocation.Undefined, contentLength: 0),
ViewComponentTypes.SyncMethodName,
tagHelperType,
nameof(Task));
return diagnostic;
}
}
}

View File

@ -0,0 +1,168 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="ArgumentCannotBeNullOrEmpy" xml:space="preserve">
<value>Value cannot be null or empty.</value>
</data>
<data name="InjectDirective_Description" xml:space="preserve">
<value>Inject a service from the application's service container into a property.</value>
</data>
<data name="InjectDirective_MemberToken_Description" xml:space="preserve">
<value>The name of the property.</value>
</data>
<data name="InjectDirective_MemberToken_Name" xml:space="preserve">
<value>PropertyName</value>
</data>
<data name="InjectDirective_TypeToken_Description" xml:space="preserve">
<value>The type of the service to inject.</value>
</data>
<data name="InjectDirective_TypeToken_Name" xml:space="preserve">
<value>TypeName</value>
</data>
<data name="ModelDirective_Description" xml:space="preserve">
<value>Specify the view or page model for the page.</value>
</data>
<data name="ModelDirective_TypeToken_Description" xml:space="preserve">
<value>The model type.</value>
</data>
<data name="ModelDirective_TypeToken_Name" xml:space="preserve">
<value>TypeName</value>
</data>
<data name="MvcRazorCodeParser_CannotHaveModelAndInheritsKeyword" xml:space="preserve">
<value>The 'inherits' keyword is not allowed when a '{0}' keyword is used.</value>
</data>
<data name="MvcRazorCodeParser_InjectDirectivePropertyNameRequired" xml:space="preserve">
<value>A property name must be specified when using the '{0}' statement. Format for a '{0}' statement is '@{0} &lt;Type Name&gt; &lt;Property Name&gt;'.</value>
</data>
<data name="MvcRazorCodeParser_KeywordMustBeFollowedByTypeName" xml:space="preserve">
<value>The '{0}' keyword must be followed by a type name on the same line.</value>
</data>
<data name="MvcRazorCodeParser_OnlyOneModelStatementIsAllowed" xml:space="preserve">
<value>Only one '{0}' statement is allowed in a file.</value>
</data>
<data name="MvcRazorParser_InvalidPropertyType" xml:space="preserve">
<value>Invalid tag helper property '{0}.{1}'. Dictionary values must not be of type '{2}'.</value>
</data>
<data name="PageDirectiveCannotBeImported" xml:space="preserve">
<value>The '@{0}' directive specified in {1} file will not be imported. The directive must appear at the top of each Razor cshtml file.</value>
</data>
<data name="RuntimeCodeGenerationNotSupported" xml:space="preserve">
<value>Runtime code generation for Mvc 1.x is not supported.</value>
</data>
</root>

View File

@ -0,0 +1,37 @@
// 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.Language;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
{
public static class TagHelperDescriptorExtensions
{
/// <summary>
/// Indicates whether a <see cref="TagHelperDescriptor"/> represents a view component.
/// </summary>
/// <param name="tagHelper">The <see cref="TagHelperDescriptor"/> to check.</param>
/// <returns>Whether a <see cref="TagHelperDescriptor"/> represents a view component.</returns>
public static bool IsViewComponentKind(this TagHelperDescriptor tagHelper)
{
if (tagHelper == null)
{
throw new ArgumentNullException(nameof(tagHelper));
}
return string.Equals(ViewComponentTagHelperConventions.Kind, tagHelper.Kind, StringComparison.Ordinal);
}
public static string GetViewComponentName(this TagHelperDescriptor tagHelper)
{
if (tagHelper == null)
{
throw new ArgumentNullException(nameof(tagHelper));
}
tagHelper.Metadata.TryGetValue(ViewComponentTagHelperMetadata.Name, out var result);
return result;
}
}
}

View File

@ -0,0 +1,135 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="ViewComponent_AmbiguousMethods" xml:space="preserve">
<value>View component '{0}' must have exactly one public method named '{1}' or '{2}'.</value>
</data>
<data name="ViewComponent_AsyncMethod_ShouldReturnTask" xml:space="preserve">
<value>Method '{0}' of view component '{1}' should be declared to return {2}&amp;lt;T&amp;gt;.</value>
</data>
<data name="ViewComponent_CannotFindMethod" xml:space="preserve">
<value>Could not find an '{0}' or '{1}' method for the view component '{2}'.</value>
</data>
<data name="ViewComponent_SyncMethod_CannotReturnTask" xml:space="preserve">
<value>Method '{0}' of view component '{1}' cannot return a {2}.</value>
</data>
<data name="ViewComponent_SyncMethod_ShouldReturnValue" xml:space="preserve">
<value>Method '{0}' of view component '{1}' should be declared to return a value.</value>
</data>
</root>

View File

@ -0,0 +1,10 @@
// 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.
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
{
public static class ViewComponentTagHelperConventions
{
public static readonly string Kind = "MVC.ViewComponent";
}
}

View File

@ -0,0 +1,269 @@
// 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.Collections.Immutable;
using System.Linq;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
{
internal class ViewComponentTagHelperDescriptorFactory
{
private readonly INamedTypeSymbol _viewComponentAttributeSymbol;
private readonly INamedTypeSymbol _genericTaskSymbol;
private readonly INamedTypeSymbol _taskSymbol;
private readonly INamedTypeSymbol _iDictionarySymbol;
private static readonly SymbolDisplayFormat FullNameTypeDisplayFormat =
SymbolDisplayFormat.FullyQualifiedFormat
.WithGlobalNamespaceStyle(SymbolDisplayGlobalNamespaceStyle.Omitted)
.WithMiscellaneousOptions(SymbolDisplayFormat.FullyQualifiedFormat.MiscellaneousOptions & (~SymbolDisplayMiscellaneousOptions.UseSpecialTypes));
private static readonly IReadOnlyDictionary<string, string> PrimitiveDisplayTypeNameLookups = new Dictionary<string, string>(StringComparer.Ordinal)
{
[typeof(byte).FullName] = "byte",
[typeof(sbyte).FullName] = "sbyte",
[typeof(int).FullName] = "int",
[typeof(uint).FullName] = "uint",
[typeof(short).FullName] = "short",
[typeof(ushort).FullName] = "ushort",
[typeof(long).FullName] = "long",
[typeof(ulong).FullName] = "ulong",
[typeof(float).FullName] = "float",
[typeof(double).FullName] = "double",
[typeof(char).FullName] = "char",
[typeof(bool).FullName] = "bool",
[typeof(object).FullName] = "object",
[typeof(string).FullName] = "string",
[typeof(decimal).FullName] = "decimal",
};
public ViewComponentTagHelperDescriptorFactory(Compilation compilation)
{
_viewComponentAttributeSymbol = compilation.GetTypeByMetadataName(ViewComponentTypes.ViewComponentAttribute);
_genericTaskSymbol = compilation.GetTypeByMetadataName(ViewComponentTypes.GenericTask);
_taskSymbol = compilation.GetTypeByMetadataName(ViewComponentTypes.Task);
_iDictionarySymbol = compilation.GetTypeByMetadataName(ViewComponentTypes.IDictionary);
}
public virtual TagHelperDescriptor CreateDescriptor(INamedTypeSymbol type)
{
var assemblyName = type.ContainingAssembly.Name;
var shortName = GetShortName(type);
var tagName = $"vc:{HtmlConventions.ToHtmlCase(shortName)}";
var typeName = $"__Generated__{shortName}ViewComponentTagHelper";
var displayName = shortName + "ViewComponentTagHelper";
var descriptorBuilder = TagHelperDescriptorBuilder.Create(ViewComponentTagHelperConventions.Kind, typeName, assemblyName);
descriptorBuilder.SetTypeName(typeName);
descriptorBuilder.DisplayName = displayName;
if (TryFindInvokeMethod(type, out var method, out var diagnostic))
{
var methodParameters = method.Parameters;
descriptorBuilder.TagMatchingRule(ruleBuilder =>
{
ruleBuilder.TagName = tagName;
AddRequiredAttributes(methodParameters, ruleBuilder);
});
AddBoundAttributes(methodParameters, displayName, descriptorBuilder);
}
else
{
descriptorBuilder.Diagnostics.Add(diagnostic);
}
descriptorBuilder.Metadata[ViewComponentTagHelperMetadata.Name] = shortName;
var descriptor = descriptorBuilder.Build();
return descriptor;
}
private bool TryFindInvokeMethod(INamedTypeSymbol type, out IMethodSymbol method, out RazorDiagnostic diagnostic)
{
var methods = type.GetMembers()
.OfType<IMethodSymbol>()
.Where(m =>
m.DeclaredAccessibility == Accessibility.Public &&
(string.Equals(m.Name, ViewComponentTypes.AsyncMethodName, StringComparison.Ordinal) ||
string.Equals(m.Name, ViewComponentTypes.SyncMethodName, StringComparison.Ordinal)))
.ToArray();
if (methods.Length == 0)
{
diagnostic = RazorExtensionsDiagnosticFactory.CreateViewComponent_CannotFindMethod(type.ToDisplayString(FullNameTypeDisplayFormat));
method = null;
return false;
}
else if (methods.Length > 1)
{
diagnostic = RazorExtensionsDiagnosticFactory.CreateViewComponent_AmbiguousMethods(type.ToDisplayString(FullNameTypeDisplayFormat));
method = null;
return false;
}
var selectedMethod = methods[0];
var returnType = selectedMethod.ReturnType as INamedTypeSymbol;
if (string.Equals(selectedMethod.Name, ViewComponentTypes.AsyncMethodName, StringComparison.Ordinal))
{
// Will invoke asynchronously. Method must not return Task or Task<T>.
if (returnType == _taskSymbol)
{
// This is ok.
}
else if (returnType.IsGenericType && returnType.ConstructedFrom == _genericTaskSymbol)
{
// This is ok.
}
else
{
diagnostic = RazorExtensionsDiagnosticFactory.CreateViewComponent_AsyncMethod_ShouldReturnTask(type.ToDisplayString(FullNameTypeDisplayFormat));
method = null;
return false;
}
}
else
{
// Will invoke synchronously. Method must not return void, Task or Task<T>.
if (returnType.SpecialType == SpecialType.System_Void)
{
diagnostic = RazorExtensionsDiagnosticFactory.CreateViewComponent_SyncMethod_ShouldReturnValue(type.ToDisplayString(FullNameTypeDisplayFormat));
method = null;
return false;
}
else if (returnType == _taskSymbol)
{
diagnostic = RazorExtensionsDiagnosticFactory.CreateViewComponent_SyncMethod_CannotReturnTask(type.ToDisplayString(FullNameTypeDisplayFormat));
method = null;
return false;
}
else if (returnType.IsGenericType && returnType.ConstructedFrom == _genericTaskSymbol)
{
diagnostic = RazorExtensionsDiagnosticFactory.CreateViewComponent_SyncMethod_CannotReturnTask(type.ToDisplayString(FullNameTypeDisplayFormat));
method = null;
return false;
}
}
method = selectedMethod;
diagnostic = null;
return true;
}
private void AddRequiredAttributes(ImmutableArray<IParameterSymbol> methodParameters, TagMatchingRuleDescriptorBuilder builder)
{
foreach (var parameter in methodParameters)
{
if (GetIndexerValueTypeName(parameter) == null)
{
// Set required attributes only for non-indexer attributes. Indexer attributes can't be required attributes
// because there are two ways of setting values for the attribute.
builder.Attribute(attributeBuilder =>
{
var lowerKebabName = HtmlConventions.ToHtmlCase(parameter.Name);
attributeBuilder.Name =lowerKebabName;
});
}
}
}
private void AddBoundAttributes(ImmutableArray<IParameterSymbol> methodParameters, string containingDisplayName, TagHelperDescriptorBuilder builder)
{
foreach (var parameter in methodParameters)
{
var lowerKebabName = HtmlConventions.ToHtmlCase(parameter.Name);
var typeName = parameter.Type.ToDisplayString(FullNameTypeDisplayFormat);
if (!PrimitiveDisplayTypeNameLookups.TryGetValue(typeName, out var simpleName))
{
simpleName = typeName;
}
builder.BindAttribute(attributeBuilder =>
{
attributeBuilder.Name = lowerKebabName;
attributeBuilder.TypeName = typeName;
attributeBuilder.DisplayName = $"{simpleName} {containingDisplayName}.{parameter.Name}";
attributeBuilder.SetPropertyName(parameter.Name);
if (parameter.Type.TypeKind == TypeKind.Enum)
{
attributeBuilder.IsEnum = true;
}
else
{
var dictionaryValueType = GetIndexerValueTypeName(parameter);
if (dictionaryValueType != null)
{
attributeBuilder.AsDictionary(lowerKebabName + "-", dictionaryValueType);
}
}
});
}
}
private string GetIndexerValueTypeName(IParameterSymbol parameter)
{
INamedTypeSymbol dictionaryType;
if ((parameter.Type as INamedTypeSymbol)?.ConstructedFrom == _iDictionarySymbol)
{
dictionaryType = (INamedTypeSymbol)parameter.Type;
}
else if (parameter.Type.AllInterfaces.Any(s => s.ConstructedFrom == _iDictionarySymbol))
{
dictionaryType = parameter.Type.AllInterfaces.First(s => s.ConstructedFrom == _iDictionarySymbol);
}
else
{
dictionaryType = null;
}
if (dictionaryType == null || dictionaryType.TypeArguments[0].SpecialType != SpecialType.System_String)
{
return null;
}
var type = dictionaryType.TypeArguments[1];
var typeName = type.ToDisplayString(FullNameTypeDisplayFormat);
return typeName;
}
private string GetShortName(INamedTypeSymbol componentType)
{
var viewComponentAttribute = componentType.GetAttributes().Where(a => a.AttributeClass == _viewComponentAttributeSymbol).FirstOrDefault();
var name = viewComponentAttribute
?.NamedArguments
.Where(namedArgument => string.Equals(namedArgument.Key, ViewComponentTypes.ViewComponent.Name, StringComparison.Ordinal))
.FirstOrDefault()
.Value
.Value as string;
if (!string.IsNullOrEmpty(name))
{
var separatorIndex = name.LastIndexOf('.');
if (separatorIndex >= 0)
{
return name.Substring(separatorIndex + 1);
}
else
{
return name;
}
}
// Get name by convention
if (componentType.Name.EndsWith(ViewComponentTypes.ViewComponentSuffix, StringComparison.OrdinalIgnoreCase))
{
return componentType.Name.Substring(0, componentType.Name.Length - ViewComponentTypes.ViewComponentSuffix.Length);
}
else
{
return componentType.Name;
}
}
}
}

View File

@ -0,0 +1,64 @@
// 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.Language;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
{
public sealed class ViewComponentTagHelperDescriptorProvider : RazorEngineFeatureBase, ITagHelperDescriptorProvider
{
public int Order { get; set; }
public void Execute(TagHelperDescriptorProviderContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var compilation = context.GetCompilation();
if (compilation == null)
{
// No compilation, nothing to do.
return;
}
var types = new List<INamedTypeSymbol>();
var visitor = ViewComponentTypeVisitor.Create(compilation, types);
// We always visit the global namespace.
visitor.Visit(compilation.Assembly.GlobalNamespace);
foreach (var reference in compilation.References)
{
if (compilation.GetAssemblyOrModuleSymbol(reference) is IAssemblySymbol assembly)
{
if (IsTagHelperAssembly(assembly))
{
visitor.Visit(assembly.GlobalNamespace);
}
}
}
var factory = new ViewComponentTagHelperDescriptorFactory(compilation);
for (var i = 0; i < types.Count; i++)
{
var descriptor = factory.CreateDescriptor(types[i]);
if (descriptor != null)
{
context.Results.Add(descriptor);
}
}
}
private bool IsTagHelperAssembly(IAssemblySymbol assembly)
{
return assembly.Name != null && !assembly.Name.StartsWith("System.", StringComparison.Ordinal);
}
}
}

View File

@ -0,0 +1,51 @@
// 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.Language;
using Microsoft.AspNetCore.Razor.Language.CodeGeneration;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
{
public sealed class ViewComponentTagHelperIntermediateNode : ExtensionIntermediateNode
{
public override IntermediateNodeCollection Children { get; } = IntermediateNodeCollection.ReadOnly;
public string ClassName { get; set; }
public TagHelperDescriptor TagHelper { get; set; }
public override void Accept(IntermediateNodeVisitor visitor)
{
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
AcceptExtensionNode<ViewComponentTagHelperIntermediateNode>(this, visitor);
}
public override void WriteNode(CodeTarget target, CodeRenderingContext context)
{
if (target == null)
{
throw new ArgumentNullException(nameof(target));
}
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var extension = target.GetExtension<IViewComponentTagHelperTargetExtension>();
if (extension == null)
{
ReportMissingCodeTargetExtension<IViewComponentTagHelperTargetExtension>(context);
return;
}
extension.WriteViewComponentTagHelper(context, this);
}
}
}

View File

@ -0,0 +1,14 @@
// 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.
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
{
public static class ViewComponentTagHelperMetadata
{
/// <summary>
/// The key in a <see cref="Microsoft.AspNetCore.Razor.Language.TagHelperDescriptor.Metadata"/> containing
/// the short name of a view component.
/// </summary>
public static readonly string Name = "MVC.ViewComponent.Name";
}
}

View File

@ -0,0 +1,203 @@
// 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.Language;
using Microsoft.AspNetCore.Razor.Language.Extensions;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
{
public class ViewComponentTagHelperPass : IntermediateNodePassBase, IRazorOptimizationPass
{
// Run after the default taghelper pass
public override int Order => IntermediateNodePassBase.DefaultFeatureOrder + 2000;
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
{
var @namespace = documentNode.FindPrimaryNamespace();
var @class = documentNode.FindPrimaryClass();
if (@namespace == null || @class == null)
{
// Nothing to do, bail. We can't function without the standard structure.
return;
}
var context = new Context(@namespace, @class);
// For each VCTH *usage* we need to rewrite the tag helper node to use the tag helper runtime to construct
// and set properties on the the correct field, and using the name of the type we will generate.
var nodes = documentNode.FindDescendantNodes<TagHelperIntermediateNode>();
for (var i = 0; i < nodes.Count; i++)
{
var node = nodes[i];
foreach (var tagHelper in node.TagHelpers)
{
RewriteUsage(context, node, tagHelper);
}
}
// Then for each VCTH *definition* that we've seen we need to generate the class that implements
// ITagHelper and the field that will hold it.
foreach (var tagHelper in context.TagHelpers)
{
AddField(context, tagHelper);
AddTagHelperClass(context, tagHelper);
}
}
private void RewriteUsage(Context context, TagHelperIntermediateNode node, TagHelperDescriptor tagHelper)
{
if (!tagHelper.IsViewComponentKind())
{
return;
}
context.Add(tagHelper);
// Now we need to insert a create node using the default tag helper runtime. This is similar to
// code in DefaultTagHelperOptimizationPass.
//
// Find the body node.
var i = 0;
while (i < node.Children.Count && node.Children[i] is TagHelperBodyIntermediateNode)
{
i++;
}
while (i < node.Children.Count && node.Children[i] is DefaultTagHelperBodyIntermediateNode)
{
i++;
}
// Now find the last create node.
while (i < node.Children.Count && node.Children[i] is DefaultTagHelperCreateIntermediateNode)
{
i++;
}
// Now i has the right insertion point.
node.Children.Insert(i, new DefaultTagHelperCreateIntermediateNode()
{
FieldName = context.GetFieldName(tagHelper),
TagHelper = tagHelper,
TypeName = context.GetFullyQualifiedName(tagHelper),
});
// Now we need to rewrite any set property nodes to use the default runtime.
for (i = 0; i < node.Children.Count; i++)
{
if (node.Children[i] is TagHelperPropertyIntermediateNode propertyNode &&
propertyNode.TagHelper == tagHelper)
{
// This is a set property for this VCTH - we need to replace it with a node
// that will use our field and property name.
node.Children[i] = new DefaultTagHelperPropertyIntermediateNode(propertyNode)
{
FieldName = context.GetFieldName(tagHelper),
PropertyName = propertyNode.BoundAttribute.GetPropertyName(),
};
}
}
}
private void AddField(Context context, TagHelperDescriptor tagHelper)
{
// We need to insert a node for the field that will hold the tag helper. We've already generated a field name
// at this time and use it for all uses of the same tag helper type.
//
// We also want to preserve the ordering of the nodes for testability. So insert at the end of any existing
// field nodes.
var i = 0;
while (i < context.Class.Children.Count && context.Class.Children[i] is DefaultTagHelperRuntimeIntermediateNode)
{
i++;
}
while (i < context.Class.Children.Count && context.Class.Children[i] is FieldDeclarationIntermediateNode)
{
i++;
}
context.Class.Children.Insert(i, new FieldDeclarationIntermediateNode()
{
Annotations =
{
{ CommonAnnotations.DefaultTagHelperExtension.TagHelperField, bool.TrueString },
},
Modifiers =
{
"private",
},
FieldName = context.GetFieldName(tagHelper),
FieldType = "global::" + context.GetFullyQualifiedName(tagHelper),
});
}
private void AddTagHelperClass(Context context, TagHelperDescriptor tagHelper)
{
var node = new ViewComponentTagHelperIntermediateNode()
{
ClassName = context.GetClassName(tagHelper),
TagHelper = tagHelper
};
context.Class.Children.Add(node);
}
private struct Context
{
private Dictionary<TagHelperDescriptor, (string className, string fullyQualifiedName, string fieldName)> _tagHelpers;
public Context(NamespaceDeclarationIntermediateNode @namespace, ClassDeclarationIntermediateNode @class)
{
Namespace = @namespace;
Class = @class;
_tagHelpers = new Dictionary<TagHelperDescriptor, (string, string, string)>();
}
public ClassDeclarationIntermediateNode Class { get; }
public NamespaceDeclarationIntermediateNode Namespace { get; }
public IEnumerable<TagHelperDescriptor> TagHelpers => _tagHelpers.Keys;
public bool Add(TagHelperDescriptor tagHelper)
{
if (_tagHelpers.ContainsKey(tagHelper))
{
return false;
}
var className = $"__Generated__{tagHelper.GetViewComponentName()}ViewComponentTagHelper";
var fullyQualifiedName = $"{Namespace.Content}.{Class.ClassName}.{className}";
var fieldName = GenerateFieldName(tagHelper);
_tagHelpers.Add(tagHelper, (className, fullyQualifiedName, fieldName));
return true;
}
public string GetClassName(TagHelperDescriptor taghelper)
{
return _tagHelpers[taghelper].className;
}
public string GetFullyQualifiedName(TagHelperDescriptor taghelper)
{
return _tagHelpers[taghelper].fullyQualifiedName;
}
public string GetFieldName(TagHelperDescriptor taghelper)
{
return _tagHelpers[taghelper].fieldName;
}
private static string GenerateFieldName(TagHelperDescriptor tagHelper)
{
return $"__{tagHelper.GetViewComponentName()}ViewComponentTagHelper";
}
}
}
}

View File

@ -0,0 +1,183 @@
// 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.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.CodeGeneration;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
{
internal class ViewComponentTagHelperTargetExtension : IViewComponentTagHelperTargetExtension
{
private static readonly string[] PublicModifiers = new[] { "public" };
public string TagHelperTypeName { get; set; } = "Microsoft.AspNetCore.Razor.TagHelpers.TagHelper";
public string ViewComponentHelperTypeName { get; set; } = "global::Microsoft.AspNetCore.Mvc.IViewComponentHelper";
public string ViewComponentHelperVariableName { get; set; } = "_helper";
public string ViewComponentInvokeMethodName { get; set; } = "InvokeAsync";
public string HtmlAttributeNotBoundAttributeTypeName { get; set; } = "Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeNotBoundAttribute";
public string ViewContextAttributeTypeName { get; set; } = "global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewContextAttribute";
public string ViewContextTypeName { get; set; } = "global::Microsoft.AspNetCore.Mvc.Rendering.ViewContext";
public string ViewContextPropertyName { get; set; } = "ViewContext";
public string HtmlTargetElementAttributeTypeName { get; set; } = "Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute";
public string TagHelperProcessMethodName { get; set; } = "ProcessAsync";
public string TagHelperContextTypeName { get; set; } = "Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext";
public string TagHelperContextVariableName { get; set; } = "context";
public string TagHelperOutputTypeName { get; set; } = "Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput";
public string TagHelperOutputVariableName { get; set; } = "output";
public string TagHelperOutputTagNamePropertyName { get; set; } = "TagName";
public string TagHelperOutputContentPropertyName { get; set; } = "Content";
public string TagHelperContentSetMethodName { get; set; } = "SetHtmlContent";
public string TagHelperContentVariableName { get; set; } = "content";
public string IViewContextAwareTypeName { get; set; } = "global::Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware";
public string IViewContextAwareContextualizeMethodName { get; set; } = "Contextualize";
public void WriteViewComponentTagHelper(CodeRenderingContext context, ViewComponentTagHelperIntermediateNode node)
{
// Add target element.
WriteTargetElementString(context.CodeWriter, node.TagHelper);
// Initialize declaration.
using (context.CodeWriter.BuildClassDeclaration(
PublicModifiers,
node.ClassName,
TagHelperTypeName,
interfaces: null,
typeParameters: null))
{
// Add view component helper.
context.CodeWriter.WriteVariableDeclaration(
$"private readonly {ViewComponentHelperTypeName}",
ViewComponentHelperVariableName,
value: null);
// Add constructor.
WriteConstructorString(context.CodeWriter, node.ClassName);
// Add attributes.
WriteAttributeDeclarations(context.CodeWriter, node.TagHelper);
// Add process method.
WriteProcessMethodString(context.CodeWriter, node.TagHelper);
}
}
private void WriteConstructorString(CodeWriter writer, string className)
{
writer.Write("public ")
.Write(className)
.Write("(")
.Write($"{ViewComponentHelperTypeName} helper")
.WriteLine(")");
using (writer.BuildScope())
{
writer.WriteStartAssignment(ViewComponentHelperVariableName)
.Write("helper")
.WriteLine(";");
}
}
private void WriteAttributeDeclarations(CodeWriter writer, TagHelperDescriptor tagHelper)
{
writer.Write("[")
.Write(HtmlAttributeNotBoundAttributeTypeName)
.WriteParameterSeparator()
.Write(ViewContextAttributeTypeName)
.WriteLine("]");
writer.WriteAutoPropertyDeclaration(
PublicModifiers,
ViewContextTypeName,
ViewContextPropertyName);
foreach (var attribute in tagHelper.BoundAttributes)
{
writer.WriteAutoPropertyDeclaration(
PublicModifiers,
attribute.TypeName,
attribute.GetPropertyName());
if (attribute.IndexerTypeName != null)
{
writer.Write(" = ")
.WriteStartNewObject(attribute.TypeName)
.WriteEndMethodInvocation();
}
}
}
private void WriteProcessMethodString(CodeWriter writer, TagHelperDescriptor tagHelper)
{
using (writer.BuildMethodDeclaration(
$"public override async",
$"global::{typeof(Task).FullName}",
TagHelperProcessMethodName,
new Dictionary<string, string>()
{
{ TagHelperContextTypeName, TagHelperContextVariableName },
{ TagHelperOutputTypeName, TagHelperOutputVariableName }
}))
{
writer.WriteInstanceMethodInvocation(
$"({ViewComponentHelperVariableName} as {IViewContextAwareTypeName})?",
IViewContextAwareContextualizeMethodName,
new[] { ViewContextPropertyName });
var methodParameters = GetMethodParameters(tagHelper);
writer.Write("var ")
.WriteStartAssignment(TagHelperContentVariableName)
.WriteInstanceMethodInvocation($"await {ViewComponentHelperVariableName}", ViewComponentInvokeMethodName, methodParameters);
writer.WriteStartAssignment($"{TagHelperOutputVariableName}.{TagHelperOutputTagNamePropertyName}")
.WriteLine("null;");
writer.WriteInstanceMethodInvocation(
$"{TagHelperOutputVariableName}.{TagHelperOutputContentPropertyName}",
TagHelperContentSetMethodName,
new[] { TagHelperContentVariableName });
}
}
private string[] GetMethodParameters(TagHelperDescriptor tagHelper)
{
var propertyNames = tagHelper.BoundAttributes.Select(attribute => attribute.GetPropertyName());
var joinedPropertyNames = string.Join(", ", propertyNames);
var parametersString = $"new {{ { joinedPropertyNames } }}";
var viewComponentName = tagHelper.GetViewComponentName();
var methodParameters = new[] { $"\"{viewComponentName}\"", parametersString };
return methodParameters;
}
private void WriteTargetElementString(CodeWriter writer, TagHelperDescriptor tagHelper)
{
Debug.Assert(tagHelper.TagMatchingRules.Count() == 1);
var rule = tagHelper.TagMatchingRules.First();
writer.Write("[")
.WriteStartMethodInvocation(HtmlTargetElementAttributeTypeName)
.WriteStringLiteral(rule.TagName)
.WriteLine(")]");
}
}
}

View File

@ -0,0 +1,102 @@
// 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.CodeAnalysis;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
{
internal class ViewComponentTypeVisitor : SymbolVisitor
{
private static readonly Version SupportedVCTHMvcVersion = new Version(1, 1);
private readonly INamedTypeSymbol _viewComponentAttribute;
private readonly INamedTypeSymbol _nonViewComponentAttribute;
private readonly List<INamedTypeSymbol> _results;
public static ViewComponentTypeVisitor Create(Compilation compilation, List<INamedTypeSymbol> results)
{
var vcAttribute = compilation.GetTypeByMetadataName(ViewComponentTypes.ViewComponentAttribute);
var nonVCAttribute = compilation.GetTypeByMetadataName(ViewComponentTypes.NonViewComponentAttribute);
return new ViewComponentTypeVisitor(vcAttribute, nonVCAttribute, results);
}
public ViewComponentTypeVisitor(
INamedTypeSymbol viewComponentAttribute,
INamedTypeSymbol nonViewComponentAttribute,
List<INamedTypeSymbol> results)
{
_viewComponentAttribute = viewComponentAttribute;
_nonViewComponentAttribute = nonViewComponentAttribute;
_results = results;
Enabled = _viewComponentAttribute != null;
}
public bool Enabled { get; set; }
public override void VisitNamedType(INamedTypeSymbol symbol)
{
if (IsViewComponent(symbol))
{
_results.Add(symbol);
}
if (symbol.DeclaredAccessibility != Accessibility.Public)
{
return;
}
foreach (var member in symbol.GetTypeMembers())
{
Visit(member);
}
}
public override void VisitNamespace(INamespaceSymbol symbol)
{
foreach (var member in symbol.GetMembers())
{
Visit(member);
}
}
internal bool IsViewComponent(INamedTypeSymbol symbol)
{
if (!Enabled)
{
return false;
}
if (symbol.DeclaredAccessibility != Accessibility.Public ||
symbol.IsAbstract ||
symbol.IsGenericType ||
AttributeIsDefined(symbol, _nonViewComponentAttribute))
{
return false;
}
return symbol.Name.EndsWith(ViewComponentTypes.ViewComponentSuffix) ||
AttributeIsDefined(symbol, _viewComponentAttribute);
}
private static bool AttributeIsDefined(INamedTypeSymbol type, INamedTypeSymbol queryAttribute)
{
if (type == null || queryAttribute == null)
{
return false;
}
var attribute = type.GetAttributes().Where(a => a.AttributeClass == queryAttribute).FirstOrDefault();
if (attribute != null)
{
return true;
}
return AttributeIsDefined(type.BaseType, queryAttribute);
}
}
}

View File

@ -0,0 +1,35 @@
// 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;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
{
internal static class ViewComponentTypes
{
public const string Assembly = "Microsoft.AspNetCore.Mvc.ViewFeatures";
public static readonly Version AssemblyVersion = new Version(1, 1, 0, 0);
public const string ViewComponentSuffix = "ViewComponent";
public const string ViewComponentAttribute = "Microsoft.AspNetCore.Mvc.ViewComponentAttribute";
public const string NonViewComponentAttribute = "Microsoft.AspNetCore.Mvc.NonViewComponentAttribute";
public const string GenericTask = "System.Threading.Tasks.Task`1";
public const string Task = "System.Threading.Tasks.Task";
public const string IDictionary = "System.Collections.Generic.IDictionary`2";
public const string AsyncMethodName = "InvokeAsync";
public const string SyncMethodName = "Invoke";
public static class ViewComponent
{
public const string Name = "Name";
}
}
}

View File

@ -0,0 +1,102 @@
// 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.Language;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public class AssemblyAttributeInjectionPass : IntermediateNodePassBase, IRazorOptimizationPass
{
private const string RazorViewAttribute = "global::Microsoft.AspNetCore.Mvc.Razor.Compilation.RazorViewAttribute";
private const string RazorPageAttribute = "global::Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.RazorPageAttribute";
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
{
if (documentNode.Options.DesignTime)
{
return;
}
var @namespace = documentNode.FindPrimaryNamespace();
if (@namespace == null || string.IsNullOrEmpty(@namespace.Content))
{
// No namespace node or it's incomplete. Skip.
return;
}
var @class = documentNode.FindPrimaryClass();
if (@class == null || string.IsNullOrEmpty(@class.ClassName))
{
// No class node or it's incomplete. Skip.
return;
}
var generatedTypeName = $"{@namespace.Content}.{@class.ClassName}";
// The MVC attributes require a relative path to be specified so that we can make a view engine path.
// We can't use a rooted path because we don't know what the project root is.
//
// If we can't sanitize the path, we'll just set it to null and let is blow up at runtime - we don't
// want to create noise if this code has to run in some unanticipated scenario.
var escapedPath = MakeVerbatimStringLiteral(ConvertToViewEnginePath(codeDocument.Source.RelativePath));
string attribute;
if (documentNode.DocumentKind == MvcViewDocumentClassifierPass.MvcViewDocumentKind)
{
attribute = $"[assembly:{RazorViewAttribute}({escapedPath}, typeof({generatedTypeName}))]";
}
else if (documentNode.DocumentKind == RazorPageDocumentClassifierPass.RazorPageDocumentKind &&
PageDirective.TryGetPageDirective(documentNode, out var pageDirective))
{
var escapedRoutePrefix = MakeVerbatimStringLiteral(pageDirective.RouteTemplate);
attribute = $"[assembly:{RazorPageAttribute}({escapedPath}, typeof({generatedTypeName}), {escapedRoutePrefix})]";
}
else
{
return;
}
var index = documentNode.Children.IndexOf(@namespace);
Debug.Assert(index >= 0);
var pageAttribute = new CSharpCodeIntermediateNode();
pageAttribute.Children.Add(new IntermediateToken()
{
Kind = TokenKind.CSharp,
Content = attribute,
});
documentNode.Children.Insert(index, pageAttribute);
}
private static string MakeVerbatimStringLiteral(string value)
{
if (value == null)
{
return "null";
}
value = value.Replace("\"", "\"\"");
return $"@\"{value}\"";
}
private static string ConvertToViewEnginePath(string relativePath)
{
if (string.IsNullOrEmpty(relativePath))
{
return null;
}
// Checking for both / and \ because a \ will become a /.
if (!relativePath.StartsWith("/") && !relativePath.StartsWith("\\"))
{
relativePath = "/" + relativePath;
}
relativePath = relativePath.Replace('\\', '/');
return relativePath;
}
}
}

View File

@ -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;
using System.Globalization;
using System.Text;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
internal static class CSharpIdentifier
{
private const string CshtmlExtension = ".cshtml";
public static string GetClassNameFromPath(string path)
{
if (string.IsNullOrEmpty(path))
{
return path;
}
if (path.EndsWith(CshtmlExtension, StringComparison.OrdinalIgnoreCase))
{
path = path.Substring(0, path.Length - CshtmlExtension.Length);
}
return SanitizeClassName(path);
}
// CSharp Spec §2.4.2
private static bool IsIdentifierStart(char character)
{
return char.IsLetter(character) ||
character == '_' ||
CharUnicodeInfo.GetUnicodeCategory(character) == UnicodeCategory.LetterNumber;
}
public static bool IsIdentifierPart(char character)
{
return char.IsDigit(character) ||
IsIdentifierStart(character) ||
IsIdentifierPartByUnicodeCategory(character);
}
private static bool IsIdentifierPartByUnicodeCategory(char character)
{
var category = CharUnicodeInfo.GetUnicodeCategory(character);
return category == UnicodeCategory.NonSpacingMark || // Mn
category == UnicodeCategory.SpacingCombiningMark || // Mc
category == UnicodeCategory.ConnectorPunctuation || // Pc
category == UnicodeCategory.Format; // Cf
}
public static string SanitizeClassName(string inputName)
{
if (!IsIdentifierStart(inputName[0]) && IsIdentifierPart(inputName[0]))
{
inputName = "_" + inputName;
}
var builder = new StringBuilder(inputName.Length);
for (var i = 0; i < inputName.Length; i++)
{
var ch = inputName[i];
builder.Append(IsIdentifierPart(ch) ? ch : '_');
}
return builder.ToString();
}
}
}

View File

@ -0,0 +1,15 @@
// 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.Language;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
internal class ExtensionInitializer : RazorExtensionInitializer
{
public override void Initialize(RazorProjectEngineBuilder builder)
{
RazorExtensions.Register(builder);
}
}
}

View File

@ -0,0 +1,12 @@
// 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.Language.CodeGeneration;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public interface IInjectTargetExtension : ICodeTargetExtension
{
void WriteInjectProperty(CodeRenderingContext context, InjectIntermediateNode node);
}
}

View File

@ -0,0 +1,12 @@
// 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.Language.CodeGeneration;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public interface IViewComponentTagHelperTargetExtension : ICodeTargetExtension
{
void WriteViewComponentTagHelper(CodeRenderingContext context, ViewComponentTagHelperIntermediateNode node);
}
}

View File

@ -0,0 +1,124 @@
// 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.Language;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public static class InjectDirective
{
public static readonly DirectiveDescriptor Directive = DirectiveDescriptor.CreateDirective(
"inject",
DirectiveKind.SingleLine,
builder =>
{
builder
.AddTypeToken(Resources.InjectDirective_TypeToken_Name, Resources.InjectDirective_TypeToken_Description)
.AddMemberToken(Resources.InjectDirective_MemberToken_Name, Resources.InjectDirective_MemberToken_Description);
builder.Usage = DirectiveUsage.FileScopedMultipleOccurring;
builder.Description = Resources.InjectDirective_Description;
});
public static RazorProjectEngineBuilder Register(RazorProjectEngineBuilder builder)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
builder.AddDirective(Directive);
builder.Features.Add(new Pass());
builder.AddTargetExtension(new InjectTargetExtension());
return builder;
}
internal class Pass : IntermediateNodePassBase, IRazorDirectiveClassifierPass
{
// Runs after the @model and @namespace directives
public override int Order => 10;
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
{
var visitor = new Visitor();
visitor.Visit(documentNode);
var modelType = ModelDirective.GetModelType(documentNode);
var properties = new HashSet<string>(StringComparer.Ordinal);
for (var i = visitor.Directives.Count - 1; i >= 0; i--)
{
var directive = visitor.Directives[i];
var tokens = directive.Tokens.ToArray();
if (tokens.Length < 2)
{
continue;
}
var typeName = tokens[0].Content;
var memberName = tokens[1].Content;
if (!properties.Add(memberName))
{
continue;
}
typeName = typeName.Replace("<TModel>", "<" + modelType + ">");
var injectNode = new InjectIntermediateNode()
{
TypeName = typeName,
MemberName = memberName,
};
visitor.Class.Children.Add(injectNode);
}
}
}
private class Visitor : IntermediateNodeWalker
{
public ClassDeclarationIntermediateNode Class { get; private set; }
public IList<DirectiveIntermediateNode> Directives { get; } = new List<DirectiveIntermediateNode>();
public override void VisitClassDeclaration(ClassDeclarationIntermediateNode node)
{
if (Class == null)
{
Class = node;
}
base.VisitClassDeclaration(node);
}
public override void VisitDirective(DirectiveIntermediateNode node)
{
if (node.Directive == Directive)
{
Directives.Add(node);
}
}
}
#region Obsolete
[Obsolete("This method is obsolete and will be removed in a future version.")]
public static IRazorEngineBuilder Register(IRazorEngineBuilder builder)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
builder.AddDirective(Directive);
builder.Features.Add(new Pass());
builder.AddTargetExtension(new InjectTargetExtension());
return builder;
}
#endregion
}
}

View File

@ -0,0 +1,51 @@
// 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.Language;
using Microsoft.AspNetCore.Razor.Language.CodeGeneration;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public class InjectIntermediateNode : ExtensionIntermediateNode
{
public string TypeName { get; set; }
public string MemberName { get; set; }
public override IntermediateNodeCollection Children => IntermediateNodeCollection.ReadOnly;
public override void Accept(IntermediateNodeVisitor visitor)
{
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
AcceptExtensionNode<InjectIntermediateNode>(this, visitor);
}
public override void WriteNode(CodeTarget target, CodeRenderingContext context)
{
if (target == null)
{
throw new ArgumentNullException(nameof(target));
}
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var extension = target.GetExtension<IInjectTargetExtension>();
if (extension == null)
{
ReportMissingCodeTargetExtension<IInjectTargetExtension>(context);
return;
}
extension.WriteInjectProperty(context, this);
}
}
}

View File

@ -0,0 +1,44 @@
// 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.Language.CodeGeneration;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public class InjectTargetExtension : IInjectTargetExtension
{
private const string RazorInjectAttribute = "[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]";
public void WriteInjectProperty(CodeRenderingContext context, InjectIntermediateNode node)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (node == null)
{
throw new ArgumentNullException(nameof(node));
}
var property = $"public {node.TypeName} {node.MemberName} {{ get; private set; }}";
if (node.Source.HasValue)
{
using (context.CodeWriter.BuildLinePragma(node.Source.Value))
{
context.CodeWriter
.WriteLine(RazorInjectAttribute)
.WriteLine(property);
}
}
else
{
context.CodeWriter
.WriteLine(RazorInjectAttribute)
.WriteLine(property);
}
}
}
}

View File

@ -0,0 +1,125 @@
// 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.Globalization;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Extensions;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public class InstrumentationPass : IntermediateNodePassBase, IRazorOptimizationPass
{
public override int Order => DefaultFeatureOrder;
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
{
if (documentNode.Options.DesignTime)
{
return;
}
var walker = new Visitor();
walker.VisitDocument(documentNode);
for (var i = 0; i < walker.Items.Count; i++)
{
var node = walker.Items[i];
AddInstrumentation(node);
}
}
private static void AddInstrumentation(InstrumentationItem item)
{
var beginContextMethodName = "BeginContext"; /* ORIGINAL: BeginContextMethodName */
var endContextMethodName = "EndContext"; /* ORIGINAL: EndContextMethodName */
var beginNode = new CSharpCodeIntermediateNode();
beginNode.Children.Add(new IntermediateToken()
{
Kind = TokenKind.CSharp,
Content = string.Format("{0}({1}, {2}, {3});",
beginContextMethodName,
item.Source.AbsoluteIndex.ToString(CultureInfo.InvariantCulture),
item.Source.Length.ToString(CultureInfo.InvariantCulture),
item.IsLiteral ? "true" : "false")
});
var endNode = new CSharpCodeIntermediateNode();
endNode.Children.Add(new IntermediateToken()
{
Kind = TokenKind.CSharp,
Content = string.Format("{0}();", endContextMethodName)
});
var nodeIndex = item.Parent.Children.IndexOf(item.Node);
item.Parent.Children.Insert(nodeIndex, beginNode);
item.Parent.Children.Insert(nodeIndex + 2, endNode);
}
private struct InstrumentationItem
{
public InstrumentationItem(IntermediateNode node, IntermediateNode parent, bool isLiteral, SourceSpan source)
{
Node = node;
Parent = parent;
IsLiteral = isLiteral;
Source = source;
}
public IntermediateNode Node { get; }
public IntermediateNode Parent { get; }
public bool IsLiteral { get; }
public SourceSpan Source { get; }
}
private class Visitor : IntermediateNodeWalker
{
public List<InstrumentationItem> Items { get; } = new List<InstrumentationItem>();
public override void VisitHtml(HtmlContentIntermediateNode node)
{
if (node.Source != null)
{
Items.Add(new InstrumentationItem(node, Parent, isLiteral: true, source: node.Source.Value));
}
VisitDefault(node);
}
public override void VisitCSharpExpression(CSharpExpressionIntermediateNode node)
{
if (node.Source != null)
{
Items.Add(new InstrumentationItem(node, Parent, isLiteral: false, source: node.Source.Value));
}
VisitDefault(node);
}
public override void VisitTagHelper(TagHelperIntermediateNode node)
{
if (node.Source != null)
{
Items.Add(new InstrumentationItem(node, Parent, isLiteral: false, source: node.Source.Value));
}
// Inside a tag helper we only want to visit inside of the body (skip all of the attributes and properties).
for (var i = 0; i < node.Children.Count; i++)
{
var child = node.Children[i];
if (child is TagHelperBodyIntermediateNode ||
child is DefaultTagHelperBodyIntermediateNode)
{
VisitDefault(child);
}
}
}
}
}
}

View File

@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>ASP.NET Core design time hosting infrastructure for the Razor view engine.</Description>
<TargetFrameworks>net46;netstandard2.0</TargetFrameworks>
<PackageTags>$(PackageTags);aspnetcoremvc</PackageTags>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\Microsoft.AspNetCore.Razor.Language\CodeGeneration\CodeWriterExtensions.cs">
<Link>Shared\CodeWriterExtensions.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<Content Include="build\**\*.props" PackagePath="build\" />
<Content Include="build\**\*.targets" PackagePath="build\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../Microsoft.AspNetCore.Razor.Language/Microsoft.AspNetCore.Razor.Language.csproj" />
<ProjectReference Include="../Microsoft.CodeAnalysis.Razor/Microsoft.CodeAnalysis.Razor.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,152 @@
// 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.Language;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public static class ModelDirective
{
public static readonly DirectiveDescriptor Directive = DirectiveDescriptor.CreateDirective(
"model",
DirectiveKind.SingleLine,
builder =>
{
builder.AddTypeToken(Resources.ModelDirective_TypeToken_Name, Resources.ModelDirective_TypeToken_Description);
builder.Usage = DirectiveUsage.FileScopedSinglyOccurring;
builder.Description = Resources.ModelDirective_Description;
});
public static RazorProjectEngineBuilder Register(RazorProjectEngineBuilder builder)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
builder.AddDirective(Directive);
builder.Features.Add(new Pass());
return builder;
}
public static string GetModelType(DocumentIntermediateNode document)
{
if (document == null)
{
throw new ArgumentNullException(nameof(document));
}
var visitor = new Visitor();
return GetModelType(document, visitor);
}
private static string GetModelType(DocumentIntermediateNode document, Visitor visitor)
{
visitor.Visit(document);
for (var i = visitor.ModelDirectives.Count - 1; i >= 0; i--)
{
var directive = visitor.ModelDirectives[i];
var tokens = directive.Tokens.ToArray();
if (tokens.Length >= 1)
{
return tokens[0].Content;
}
}
if (document.DocumentKind == RazorPageDocumentClassifierPass.RazorPageDocumentKind)
{
return visitor.Class.ClassName;
}
else
{
return "dynamic";
}
}
internal class Pass : IntermediateNodePassBase, IRazorDirectiveClassifierPass
{
// Runs after the @inherits directive
public override int Order => 5;
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
{
var visitor = new Visitor();
var modelType = GetModelType(documentNode, visitor);
if (documentNode.Options.DesignTime)
{
// Alias the TModel token to a known type.
// This allows design time compilation to succeed for Razor files where the token isn't replaced.
var typeName = $"global::{typeof(object).FullName}";
var usingNode = new UsingDirectiveIntermediateNode()
{
Content = $"TModel = {typeName}"
};
visitor.Namespace?.Children.Insert(0, usingNode);
}
var baseType = visitor.Class?.BaseType?.Replace("<TModel>", "<" + modelType + ">");
visitor.Class.BaseType = baseType;
}
}
private class Visitor : IntermediateNodeWalker
{
public NamespaceDeclarationIntermediateNode Namespace { get; private set; }
public ClassDeclarationIntermediateNode Class { get; private set; }
public IList<DirectiveIntermediateNode> ModelDirectives { get; } = new List<DirectiveIntermediateNode>();
public override void VisitNamespaceDeclaration(NamespaceDeclarationIntermediateNode node)
{
if (Namespace == null)
{
Namespace = node;
}
base.VisitNamespaceDeclaration(node);
}
public override void VisitClassDeclaration(ClassDeclarationIntermediateNode node)
{
if (Class == null)
{
Class = node;
}
base.VisitClassDeclaration(node);
}
public override void VisitDirective(DirectiveIntermediateNode node)
{
if (node.Directive == Directive)
{
ModelDirectives.Add(node);
}
}
}
#region Obsolete
[Obsolete("This method is obsolete and will be removed in a future version.")]
public static IRazorEngineBuilder Register(IRazorEngineBuilder builder)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
builder.AddDirective(Directive);
builder.Features.Add(new Pass());
return builder;
}
#endregion
}
}

View File

@ -0,0 +1,85 @@
// 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.Text;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public class ModelExpressionPass : IntermediateNodePassBase, IRazorOptimizationPass
{
private const string ModelExpressionTypeName = "Microsoft.AspNetCore.Mvc.ViewFeatures.ModelExpression";
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
{
var visitor = new Visitor();
visitor.Visit(documentNode);
}
private class Visitor : IntermediateNodeWalker
{
public List<TagHelperIntermediateNode> TagHelpers { get; } = new List<TagHelperIntermediateNode>();
public override void VisitTagHelperProperty(TagHelperPropertyIntermediateNode node)
{
if (string.Equals(node.BoundAttribute.TypeName, ModelExpressionTypeName, StringComparison.Ordinal) ||
(node.IsIndexerNameMatch &&
string.Equals(node.BoundAttribute.IndexerTypeName, ModelExpressionTypeName, StringComparison.Ordinal)))
{
var expression = new CSharpExpressionIntermediateNode();
expression.Children.Add(new IntermediateToken()
{
Kind = TokenKind.CSharp,
Content = "ModelExpressionProvider.CreateModelExpression(ViewData, __model => ",
});
if (node.Children.Count == 1 && node.Children[0] is IntermediateToken token && token.IsCSharp)
{
// A 'simple' expression will look like __model => __model.Foo
expression.Children.Add(new IntermediateToken()
{
Kind = TokenKind.CSharp,
Content = "__model."
});
expression.Children.Add(token);
}
else
{
for (var i = 0; i < node.Children.Count; i++)
{
if (node.Children[i] is CSharpExpressionIntermediateNode nestedExpression)
{
for (var j = 0; j < nestedExpression.Children.Count; j++)
{
if (nestedExpression.Children[j] is IntermediateToken cSharpToken &&
cSharpToken.IsCSharp)
{
expression.Children.Add(cSharpToken);
}
}
continue;
}
}
}
expression.Children.Add(new IntermediateToken()
{
Kind = TokenKind.CSharp,
Content = ")",
});
node.Children.Clear();
node.Children.Add(expression);
}
}
}
}
}

View File

@ -0,0 +1,91 @@
// 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 System.Text;
using Microsoft.AspNetCore.Razor.Language;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
internal class MvcImportProjectFeature : RazorProjectEngineFeatureBase, IImportProjectFeature
{
private const string ImportsFileName = "_ViewImports.cshtml";
public IReadOnlyList<RazorProjectItem> GetImports(RazorProjectItem projectItem)
{
if (projectItem == null)
{
throw new ArgumentNullException(nameof(projectItem));
}
var imports = new List<RazorProjectItem>();
AddDefaultDirectivesImport(imports);
// We add hierarchical imports second so any default directive imports can be overridden.
AddHierarchicalImports(projectItem, imports);
return imports;
}
// Internal for testing
internal static void AddDefaultDirectivesImport(List<RazorProjectItem> imports)
{
imports.Add(DefaultDirectivesProjectItem.Instance);
}
// Internal for testing
internal void AddHierarchicalImports(RazorProjectItem projectItem, List<RazorProjectItem> imports)
{
// We want items in descending order. FindHierarchicalItems returns items in ascending order.
var importProjectItems = ProjectEngine.FileSystem.FindHierarchicalItems(projectItem.FilePath, ImportsFileName).Reverse();
imports.AddRange(importProjectItems);
}
private class DefaultDirectivesProjectItem : RazorProjectItem
{
private readonly byte[] _defaultImportBytes;
private DefaultDirectivesProjectItem()
{
var preamble = Encoding.UTF8.GetPreamble();
var content = @"
@using System
@using System.Collections.Generic
@using System.Linq
@using System.Threading.Tasks
@using Microsoft.AspNetCore.Mvc
@using Microsoft.AspNetCore.Mvc.Rendering
@using Microsoft.AspNetCore.Mvc.ViewFeatures
@inject global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<TModel> Html
@inject global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json
@inject global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component
@inject global::Microsoft.AspNetCore.Mvc.IUrlHelper Url
@inject global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider
@addTagHelper Microsoft.AspNetCore.Mvc.Razor.TagHelpers.UrlResolutionTagHelper, Microsoft.AspNetCore.Mvc.Razor
@addTagHelper Microsoft.AspNetCore.Mvc.Razor.TagHelpers.HeadTagHelper, Microsoft.AspNetCore.Mvc.Razor
@addTagHelper Microsoft.AspNetCore.Mvc.Razor.TagHelpers.BodyTagHelper, Microsoft.AspNetCore.Mvc.Razor
";
var contentBytes = Encoding.UTF8.GetBytes(content);
_defaultImportBytes = new byte[preamble.Length + contentBytes.Length];
preamble.CopyTo(_defaultImportBytes, 0);
contentBytes.CopyTo(_defaultImportBytes, preamble.Length);
}
public override string BasePath => null;
public override string FilePath => null;
public override string PhysicalPath => null;
public override bool Exists => true;
public static DefaultDirectivesProjectItem Instance { get; } = new DefaultDirectivesProjectItem();
public override Stream Read() => new MemoryStream(_defaultImportBytes);
}
}
}

View File

@ -0,0 +1,62 @@
// 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.Text;
using Microsoft.AspNetCore.Razor.Language;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
/// <summary>
/// A <see cref="RazorTemplateEngine"/> for Mvc Razor views.
/// </summary>
public class MvcRazorTemplateEngine : RazorTemplateEngine
{
/// <summary>
/// Initializes a new instance of <see cref="MvcRazorTemplateEngine"/>.
/// </summary>
/// <param name="engine">The <see cref="RazorEngine"/>.</param>
/// <param name="project">The <see cref="RazorProject"/>.</param>
public MvcRazorTemplateEngine(
RazorEngine engine,
RazorProject project)
: base(engine, project)
{
Options.ImportsFileName = "_ViewImports.cshtml";
Options.DefaultImports = GetDefaultImports();
}
public override RazorCodeDocument CreateCodeDocument(RazorProjectItem projectItem)
{
return base.CreateCodeDocument(projectItem);
}
// Internal for testing.
internal static RazorSourceDocument GetDefaultImports()
{
using (var stream = new MemoryStream())
using (var writer = new StreamWriter(stream, Encoding.UTF8))
{
writer.WriteLine("@using System");
writer.WriteLine("@using System.Collections.Generic");
writer.WriteLine("@using System.Linq");
writer.WriteLine("@using System.Threading.Tasks");
writer.WriteLine("@using Microsoft.AspNetCore.Mvc");
writer.WriteLine("@using Microsoft.AspNetCore.Mvc.Rendering");
writer.WriteLine("@using Microsoft.AspNetCore.Mvc.ViewFeatures");
writer.WriteLine("@inject global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<TModel> Html");
writer.WriteLine("@inject global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json");
writer.WriteLine("@inject global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component");
writer.WriteLine("@inject global::Microsoft.AspNetCore.Mvc.IUrlHelper Url");
writer.WriteLine("@inject global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider");
writer.WriteLine("@addTagHelper Microsoft.AspNetCore.Mvc.Razor.TagHelpers.UrlResolutionTagHelper, Microsoft.AspNetCore.Mvc.Razor");
writer.WriteLine("@addTagHelper Microsoft.AspNetCore.Mvc.Razor.TagHelpers.HeadTagHelper, Microsoft.AspNetCore.Mvc.Razor");
writer.WriteLine("@addTagHelper Microsoft.AspNetCore.Mvc.Razor.TagHelpers.BodyTagHelper, Microsoft.AspNetCore.Mvc.Razor");
writer.Flush();
stream.Position = 0;
return RazorSourceDocument.ReadFrom(stream, fileName: null, encoding: Encoding.UTF8);
}
}
}
}

View File

@ -0,0 +1,41 @@
// 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.Language;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public class MvcViewDocumentClassifierPass : DocumentClassifierPassBase
{
public static readonly string MvcViewDocumentKind = "mvc.1.0.view";
protected override string DocumentKind => MvcViewDocumentKind;
protected override bool IsMatch(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode) => true;
protected override void OnDocumentStructureCreated(
RazorCodeDocument codeDocument,
NamespaceDeclarationIntermediateNode @namespace,
ClassDeclarationIntermediateNode @class,
MethodDeclarationIntermediateNode method)
{
base.OnDocumentStructureCreated(codeDocument, @namespace, @class, method);
@namespace.Content = "AspNetCore";
var filePath = codeDocument.Source.RelativePath ?? codeDocument.Source.FilePath;
@class.ClassName = CSharpIdentifier.GetClassNameFromPath(filePath);
@class.BaseType = "global::Microsoft.AspNetCore.Mvc.Razor.RazorPage<TModel>";
@class.Modifiers.Clear();
@class.Modifiers.Add("public");
method.MethodName = "ExecuteAsync";
method.Modifiers.Clear();
method.Modifiers.Add("public");
method.Modifiers.Add("async");
method.Modifiers.Add("override");
method.ReturnType = $"global::{typeof(System.Threading.Tasks.Task).FullName}";
}
}
}

View File

@ -0,0 +1,204 @@
// 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.IO;
using System.Linq;
using System.Text;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public static class NamespaceDirective
{
private static readonly char[] Separators = new char[] { '\\', '/' };
public static readonly DirectiveDescriptor Directive = DirectiveDescriptor.CreateDirective(
"namespace",
DirectiveKind.SingleLine,
builder =>
{
builder.AddNamespaceToken(
Resources.NamespaceDirective_NamespaceToken_Name,
Resources.NamespaceDirective_NamespaceToken_Description);
builder.Usage = DirectiveUsage.FileScopedSinglyOccurring;
builder.Description = Resources.NamespaceDirective_Description;
});
public static void Register(RazorProjectEngineBuilder builder)
{
if (builder == null)
{
throw new ArgumentNullException();
}
builder.AddDirective(Directive);
builder.Features.Add(new Pass());
}
// internal for testing
internal class Pass : IntermediateNodePassBase, IRazorDirectiveClassifierPass
{
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
{
if (documentNode.DocumentKind != RazorPageDocumentClassifierPass.RazorPageDocumentKind &&
documentNode.DocumentKind != MvcViewDocumentClassifierPass.MvcViewDocumentKind)
{
// Not a page. Skip.
return;
}
var visitor = new Visitor();
visitor.Visit(documentNode);
var directive = visitor.LastNamespaceDirective;
if (directive == null)
{
// No namespace set. Skip.
return;
}
var @namespace = visitor.FirstNamespace;
if (@namespace == null)
{
// No namespace node. Skip.
return;
}
@namespace.Content = GetNamespace(codeDocument.Source.FilePath, directive);
}
}
// internal for testing.
//
// This code does a best-effort attempt to compute a namespace 'suffix' - the path difference between
// where the @namespace directive appears and where the current document is on disk.
//
// In the event that these two source either don't have FileNames set or don't follow a coherent hierarchy,
// we will just use the namespace verbatim.
internal static string GetNamespace(string source, DirectiveIntermediateNode directive)
{
var directiveSource = NormalizeDirectory(directive.Source?.FilePath);
var baseNamespace = directive.Tokens.FirstOrDefault()?.Content;
if (string.IsNullOrEmpty(baseNamespace))
{
// The namespace directive was incomplete.
return string.Empty;
}
if (string.IsNullOrEmpty(source) || directiveSource == null)
{
// No sources, can't compute a suffix.
return baseNamespace;
}
// We're specifically using OrdinalIgnoreCase here because Razor treats all paths as case-insensitive.
if (!source.StartsWith(directiveSource, StringComparison.OrdinalIgnoreCase) ||
source.Length <= directiveSource.Length)
{
// The imports are not from the directory hierarchy, can't compute a suffix.
return baseNamespace;
}
// OK so that this point we know that the 'imports' file containing this directive is in the directory
// hierarchy of this soure file. This is the case where we can append a suffix to the baseNamespace.
//
// Everything so far has just been defensiveness on our part.
var builder = new StringBuilder(baseNamespace);
var segments = source.Substring(directiveSource.Length).Split(Separators);
// Skip the last segment because it's the FileName.
for (var i = 0; i < segments.Length - 1; i++)
{
builder.Append('.');
builder.Append(CSharpIdentifier.SanitizeClassName(segments[i]));
}
return builder.ToString();
}
// We want to normalize the path of the file containing the '@namespace' directive to just the containing
// directory with a trailing separator.
//
// Not using Path.GetDirectoryName here because it doesn't meet these requirements, and we want to handle
// both 'view engine' style paths and absolute paths.
//
// We also don't normalize the separators here. We expect that all documents are using a consistent style of path.
//
// If we can't normalize the path, we just return null so it will be ignored.
private static string NormalizeDirectory(string path)
{
if (string.IsNullOrEmpty(path))
{
return null;
}
var lastSeparator = path.LastIndexOfAny(Separators);
if (lastSeparator == -1)
{
return null;
}
// Includes the separator
return path.Substring(0, lastSeparator + 1);
}
private class Visitor : IntermediateNodeWalker
{
public ClassDeclarationIntermediateNode FirstClass { get; private set; }
public NamespaceDeclarationIntermediateNode FirstNamespace { get; private set; }
// We want the last one, so get them all and then .
public DirectiveIntermediateNode LastNamespaceDirective { get; private set; }
public override void VisitNamespaceDeclaration(NamespaceDeclarationIntermediateNode node)
{
if (FirstNamespace == null)
{
FirstNamespace = node;
}
base.VisitNamespaceDeclaration(node);
}
public override void VisitClassDeclaration(ClassDeclarationIntermediateNode node)
{
if (FirstClass == null)
{
FirstClass = node;
}
base.VisitClassDeclaration(node);
}
public override void VisitDirective(DirectiveIntermediateNode node)
{
if (node.Directive == Directive)
{
LastNamespaceDirective = node;
}
base.VisitDirective(node);
}
}
#region Obsolete
[Obsolete("This method is obsolete and will be removed in a future version.")]
public static void Register(IRazorEngineBuilder builder)
{
if (builder == null)
{
throw new ArgumentNullException();
}
builder.AddDirective(Directive);
builder.Features.Add(new Pass());
}
#endregion
}
}

View File

@ -0,0 +1,121 @@
// 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.Diagnostics;
using System.Linq;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public class PageDirective
{
public static readonly DirectiveDescriptor Directive = DirectiveDescriptor.CreateDirective(
"page",
DirectiveKind.SingleLine,
builder =>
{
builder.AddOptionalStringToken(Resources.PageDirective_RouteToken_Name, Resources.PageDirective_RouteToken_Description);
builder.Usage = DirectiveUsage.FileScopedSinglyOccurring;
builder.Description = Resources.PageDirective_Description;
});
private PageDirective(string routeTemplate, IntermediateNode directiveNode)
{
RouteTemplate = routeTemplate;
DirectiveNode = directiveNode;
}
public string RouteTemplate { get; }
public IntermediateNode DirectiveNode { get; }
public static RazorProjectEngineBuilder Register(RazorProjectEngineBuilder builder)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
builder.AddDirective(Directive);
return builder;
}
public static bool TryGetPageDirective(DocumentIntermediateNode documentNode, out PageDirective pageDirective)
{
var visitor = new Visitor();
for (var i = 0; i < documentNode.Children.Count; i++)
{
visitor.Visit(documentNode.Children[i]);
}
if (visitor.DirectiveTokens == null)
{
pageDirective = null;
return false;
}
var tokens = visitor.DirectiveTokens.ToList();
string routeTemplate = null;
if (tokens.Count > 0)
{
routeTemplate = TrimQuotes(tokens[0].Content);
}
pageDirective = new PageDirective(routeTemplate, visitor.DirectiveNode);
return true;
}
private static string TrimQuotes(string content)
{
// Tokens aren't captured if they're malformed. Therefore, this method will
// always be called with a valid token content.
Debug.Assert(content.Length >= 2);
Debug.Assert(content.StartsWith("\"", StringComparison.Ordinal));
Debug.Assert(content.EndsWith("\"", StringComparison.Ordinal));
return content.Substring(1, content.Length - 2);
}
private class Visitor : IntermediateNodeWalker
{
public IntermediateNode DirectiveNode { get; private set; }
public IEnumerable<DirectiveTokenIntermediateNode> DirectiveTokens { get; private set; }
public override void VisitDirective(DirectiveIntermediateNode node)
{
if (node.Directive == Directive)
{
DirectiveNode = node;
DirectiveTokens = node.Tokens;
}
}
public override void VisitMalformedDirective(MalformedDirectiveIntermediateNode node)
{
if (DirectiveTokens == null && node.Directive == Directive)
{
DirectiveNode = node;
DirectiveTokens = node.Tokens;
}
}
}
#region Obsolete
[Obsolete("This method is obsolete and will be removed in a future version.")]
public static IRazorEngineBuilder Register(IRazorEngineBuilder builder)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
builder.AddDirective(Directive);
return builder;
}
#endregion
}
}

View File

@ -0,0 +1,57 @@
// 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.Language;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public class PagesPropertyInjectionPass : IntermediateNodePassBase, IRazorOptimizationPass
{
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
{
if (documentNode.DocumentKind != RazorPageDocumentClassifierPass.RazorPageDocumentKind)
{
return;
}
var modelType = ModelDirective.GetModelType(documentNode);
var visitor = new Visitor();
visitor.Visit(documentNode);
var @class = visitor.Class;
var viewDataType = $"global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary<{modelType}>";
var vddProperty = new CSharpCodeIntermediateNode();
vddProperty.Children.Add(new IntermediateToken()
{
Kind = TokenKind.CSharp,
Content = $"public {viewDataType} ViewData => ({viewDataType})PageContext?.ViewData;",
});
@class.Children.Add(vddProperty);
var modelProperty = new CSharpCodeIntermediateNode();
modelProperty.Children.Add(new IntermediateToken()
{
Kind = TokenKind.CSharp,
Content = $"public {modelType} Model => ViewData.Model;",
});
@class.Children.Add(modelProperty);
}
private class Visitor : IntermediateNodeWalker
{
public ClassDeclarationIntermediateNode Class { get; private set; }
public override void VisitClassDeclaration(ClassDeclarationIntermediateNode node)
{
if (Class == null)
{
Class = node;
}
base.VisitClassDeclaration(node);
}
}
}
}

View File

@ -0,0 +1,12 @@
// 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.Runtime.CompilerServices;
using Microsoft.AspNetCore.Mvc.Razor.Extensions;
using Microsoft.AspNetCore.Razor.Language;
[assembly: ProvideRazorExtensionInitializer("MVC-2.0", typeof(ExtensionInitializer))]
[assembly: ProvideRazorExtensionInitializer("MVC-2.1", typeof(ExtensionInitializer))]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Razor.Extensions.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.VisualStudio.Editor.Razor, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]

View File

@ -0,0 +1,338 @@
// <auto-generated />
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
using System.Globalization;
using System.Reflection;
using System.Resources;
internal static class Resources
{
private static readonly ResourceManager _resourceManager
= new ResourceManager("Microsoft.AspNetCore.Mvc.Razor.Extensions.Resources", typeof(Resources).GetTypeInfo().Assembly);
/// <summary>
/// Value cannot be null or empty.
/// </summary>
internal static string ArgumentCannotBeNullOrEmpty
{
get => GetString("ArgumentCannotBeNullOrEmpty");
}
/// <summary>
/// Value cannot be null or empty.
/// </summary>
internal static string FormatArgumentCannotBeNullOrEmpty()
=> GetString("ArgumentCannotBeNullOrEmpty");
/// <summary>
/// Inject a service from the application's service container into a property.
/// </summary>
internal static string InjectDirective_Description
{
get => GetString("InjectDirective_Description");
}
/// <summary>
/// Inject a service from the application's service container into a property.
/// </summary>
internal static string FormatInjectDirective_Description()
=> GetString("InjectDirective_Description");
/// <summary>
/// The name of the property.
/// </summary>
internal static string InjectDirective_MemberToken_Description
{
get => GetString("InjectDirective_MemberToken_Description");
}
/// <summary>
/// The name of the property.
/// </summary>
internal static string FormatInjectDirective_MemberToken_Description()
=> GetString("InjectDirective_MemberToken_Description");
/// <summary>
/// PropertyName
/// </summary>
internal static string InjectDirective_MemberToken_Name
{
get => GetString("InjectDirective_MemberToken_Name");
}
/// <summary>
/// PropertyName
/// </summary>
internal static string FormatInjectDirective_MemberToken_Name()
=> GetString("InjectDirective_MemberToken_Name");
/// <summary>
/// The type of the service to inject.
/// </summary>
internal static string InjectDirective_TypeToken_Description
{
get => GetString("InjectDirective_TypeToken_Description");
}
/// <summary>
/// The type of the service to inject.
/// </summary>
internal static string FormatInjectDirective_TypeToken_Description()
=> GetString("InjectDirective_TypeToken_Description");
/// <summary>
/// TypeName
/// </summary>
internal static string InjectDirective_TypeToken_Name
{
get => GetString("InjectDirective_TypeToken_Name");
}
/// <summary>
/// TypeName
/// </summary>
internal static string FormatInjectDirective_TypeToken_Name()
=> GetString("InjectDirective_TypeToken_Name");
/// <summary>
/// Specify the view or page model for the page.
/// </summary>
internal static string ModelDirective_Description
{
get => GetString("ModelDirective_Description");
}
/// <summary>
/// Specify the view or page model for the page.
/// </summary>
internal static string FormatModelDirective_Description()
=> GetString("ModelDirective_Description");
/// <summary>
/// The model type.
/// </summary>
internal static string ModelDirective_TypeToken_Description
{
get => GetString("ModelDirective_TypeToken_Description");
}
/// <summary>
/// The model type.
/// </summary>
internal static string FormatModelDirective_TypeToken_Description()
=> GetString("ModelDirective_TypeToken_Description");
/// <summary>
/// TypeName
/// </summary>
internal static string ModelDirective_TypeToken_Name
{
get => GetString("ModelDirective_TypeToken_Name");
}
/// <summary>
/// TypeName
/// </summary>
internal static string FormatModelDirective_TypeToken_Name()
=> GetString("ModelDirective_TypeToken_Name");
/// <summary>
/// The 'inherits' keyword is not allowed when a '{0}' keyword is used.
/// </summary>
internal static string MvcRazorCodeParser_CannotHaveModelAndInheritsKeyword
{
get => GetString("MvcRazorCodeParser_CannotHaveModelAndInheritsKeyword");
}
/// <summary>
/// The 'inherits' keyword is not allowed when a '{0}' keyword is used.
/// </summary>
internal static string FormatMvcRazorCodeParser_CannotHaveModelAndInheritsKeyword(object p0)
=> string.Format(CultureInfo.CurrentCulture, GetString("MvcRazorCodeParser_CannotHaveModelAndInheritsKeyword"), p0);
/// <summary>
/// A property name must be specified when using the '{0}' statement. Format for a '{0}' statement is '@{0} &lt;Type Name&gt; &lt;Property Name&gt;'.
/// </summary>
internal static string MvcRazorCodeParser_InjectDirectivePropertyNameRequired
{
get => GetString("MvcRazorCodeParser_InjectDirectivePropertyNameRequired");
}
/// <summary>
/// A property name must be specified when using the '{0}' statement. Format for a '{0}' statement is '@{0} &lt;Type Name&gt; &lt;Property Name&gt;'.
/// </summary>
internal static string FormatMvcRazorCodeParser_InjectDirectivePropertyNameRequired(object p0)
=> string.Format(CultureInfo.CurrentCulture, GetString("MvcRazorCodeParser_InjectDirectivePropertyNameRequired"), p0);
/// <summary>
/// The '{0}' keyword must be followed by a type name on the same line.
/// </summary>
internal static string MvcRazorCodeParser_KeywordMustBeFollowedByTypeName
{
get => GetString("MvcRazorCodeParser_KeywordMustBeFollowedByTypeName");
}
/// <summary>
/// The '{0}' keyword must be followed by a type name on the same line.
/// </summary>
internal static string FormatMvcRazorCodeParser_KeywordMustBeFollowedByTypeName(object p0)
=> string.Format(CultureInfo.CurrentCulture, GetString("MvcRazorCodeParser_KeywordMustBeFollowedByTypeName"), p0);
/// <summary>
/// Only one '{0}' statement is allowed in a file.
/// </summary>
internal static string MvcRazorCodeParser_OnlyOneModelStatementIsAllowed
{
get => GetString("MvcRazorCodeParser_OnlyOneModelStatementIsAllowed");
}
/// <summary>
/// Only one '{0}' statement is allowed in a file.
/// </summary>
internal static string FormatMvcRazorCodeParser_OnlyOneModelStatementIsAllowed(object p0)
=> string.Format(CultureInfo.CurrentCulture, GetString("MvcRazorCodeParser_OnlyOneModelStatementIsAllowed"), p0);
/// <summary>
/// Invalid tag helper property '{0}.{1}'. Dictionary values must not be of type '{2}'.
/// </summary>
internal static string MvcRazorParser_InvalidPropertyType
{
get => GetString("MvcRazorParser_InvalidPropertyType");
}
/// <summary>
/// Invalid tag helper property '{0}.{1}'. Dictionary values must not be of type '{2}'.
/// </summary>
internal static string FormatMvcRazorParser_InvalidPropertyType(object p0, object p1, object p2)
=> string.Format(CultureInfo.CurrentCulture, GetString("MvcRazorParser_InvalidPropertyType"), p0, p1, p2);
/// <summary>
/// Specify the base namespace for the page.
/// </summary>
internal static string NamespaceDirective_Description
{
get => GetString("NamespaceDirective_Description");
}
/// <summary>
/// Specify the base namespace for the page.
/// </summary>
internal static string FormatNamespaceDirective_Description()
=> GetString("NamespaceDirective_Description");
/// <summary>
/// The namespace for the page.
/// </summary>
internal static string NamespaceDirective_NamespaceToken_Description
{
get => GetString("NamespaceDirective_NamespaceToken_Description");
}
/// <summary>
/// The namespace for the page.
/// </summary>
internal static string FormatNamespaceDirective_NamespaceToken_Description()
=> GetString("NamespaceDirective_NamespaceToken_Description");
/// <summary>
/// Namespace
/// </summary>
internal static string NamespaceDirective_NamespaceToken_Name
{
get => GetString("NamespaceDirective_NamespaceToken_Name");
}
/// <summary>
/// Namespace
/// </summary>
internal static string FormatNamespaceDirective_NamespaceToken_Name()
=> GetString("NamespaceDirective_NamespaceToken_Name");
/// <summary>
/// The '@{0}' directive specified in {1} file will not be imported. The directive must appear at the top of each Razor cshtml file.
/// </summary>
internal static string PageDirectiveCannotBeImported
{
get => GetString("PageDirectiveCannotBeImported");
}
/// <summary>
/// The '@{0}' directive specified in {1} file will not be imported. The directive must appear at the top of each Razor cshtml file.
/// </summary>
internal static string FormatPageDirectiveCannotBeImported(object p0, object p1)
=> string.Format(CultureInfo.CurrentCulture, GetString("PageDirectiveCannotBeImported"), p0, p1);
/// <summary>
/// The '@{0}' directive must exist at the top of the file. Only comments and whitespace are allowed before the '@{0}' directive.
/// </summary>
internal static string PageDirectiveMustExistAtTheTopOfFile
{
get => GetString("PageDirectiveMustExistAtTheTopOfFile");
}
/// <summary>
/// The '@{0}' directive must exist at the top of the file. Only comments and whitespace are allowed before the '@{0}' directive.
/// </summary>
internal static string FormatPageDirectiveMustExistAtTheTopOfFile(object p0)
=> string.Format(CultureInfo.CurrentCulture, GetString("PageDirectiveMustExistAtTheTopOfFile"), p0);
/// <summary>
/// Mark the page as a Razor Page.
/// </summary>
internal static string PageDirective_Description
{
get => GetString("PageDirective_Description");
}
/// <summary>
/// Mark the page as a Razor Page.
/// </summary>
internal static string FormatPageDirective_Description()
=> GetString("PageDirective_Description");
/// <summary>
/// An optional route template for the page.
/// </summary>
internal static string PageDirective_RouteToken_Description
{
get => GetString("PageDirective_RouteToken_Description");
}
/// <summary>
/// An optional route template for the page.
/// </summary>
internal static string FormatPageDirective_RouteToken_Description()
=> GetString("PageDirective_RouteToken_Description");
/// <summary>
/// RouteTemplate
/// </summary>
internal static string PageDirective_RouteToken_Name
{
get => GetString("PageDirective_RouteToken_Name");
}
/// <summary>
/// RouteTemplate
/// </summary>
internal static string FormatPageDirective_RouteToken_Name()
=> GetString("PageDirective_RouteToken_Name");
private static string GetString(string name, params string[] formatterNames)
{
var value = _resourceManager.GetString(name);
System.Diagnostics.Debug.Assert(value != null);
if (formatterNames != null)
{
for (var i = 0; i < formatterNames.Length; i++)
{
value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}");
}
}
return value;
}
}
}

View File

@ -0,0 +1,100 @@
// <auto-generated />
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
using System.Globalization;
using System.Reflection;
using System.Resources;
internal static class ViewComponentResources
{
private static readonly ResourceManager _resourceManager
= new ResourceManager("Microsoft.AspNetCore.Mvc.Razor.Extensions.ViewComponentResources", typeof(ViewComponentResources).GetTypeInfo().Assembly);
/// <summary>
/// View component '{0}' must have exactly one public method named '{1}' or '{2}'.
/// </summary>
internal static string ViewComponent_AmbiguousMethods
{
get => GetString("ViewComponent_AmbiguousMethods");
}
/// <summary>
/// View component '{0}' must have exactly one public method named '{1}' or '{2}'.
/// </summary>
internal static string FormatViewComponent_AmbiguousMethods(object p0, object p1, object p2)
=> string.Format(CultureInfo.CurrentCulture, GetString("ViewComponent_AmbiguousMethods"), p0, p1, p2);
/// <summary>
/// Method '{0}' of view component '{1}' should be declared to return {2}&amp;lt;T&amp;gt;.
/// </summary>
internal static string ViewComponent_AsyncMethod_ShouldReturnTask
{
get => GetString("ViewComponent_AsyncMethod_ShouldReturnTask");
}
/// <summary>
/// Method '{0}' of view component '{1}' should be declared to return {2}&amp;lt;T&amp;gt;.
/// </summary>
internal static string FormatViewComponent_AsyncMethod_ShouldReturnTask(object p0, object p1, object p2)
=> string.Format(CultureInfo.CurrentCulture, GetString("ViewComponent_AsyncMethod_ShouldReturnTask"), p0, p1, p2);
/// <summary>
/// Could not find an '{0}' or '{1}' method for the view component '{2}'.
/// </summary>
internal static string ViewComponent_CannotFindMethod
{
get => GetString("ViewComponent_CannotFindMethod");
}
/// <summary>
/// Could not find an '{0}' or '{1}' method for the view component '{2}'.
/// </summary>
internal static string FormatViewComponent_CannotFindMethod(object p0, object p1, object p2)
=> string.Format(CultureInfo.CurrentCulture, GetString("ViewComponent_CannotFindMethod"), p0, p1, p2);
/// <summary>
/// Method '{0}' of view component '{1}' cannot return a {2}.
/// </summary>
internal static string ViewComponent_SyncMethod_CannotReturnTask
{
get => GetString("ViewComponent_SyncMethod_CannotReturnTask");
}
/// <summary>
/// Method '{0}' of view component '{1}' cannot return a {2}.
/// </summary>
internal static string FormatViewComponent_SyncMethod_CannotReturnTask(object p0, object p1, object p2)
=> string.Format(CultureInfo.CurrentCulture, GetString("ViewComponent_SyncMethod_CannotReturnTask"), p0, p1, p2);
/// <summary>
/// Method '{0}' of view component '{1}' should be declared to return a value.
/// </summary>
internal static string ViewComponent_SyncMethod_ShouldReturnValue
{
get => GetString("ViewComponent_SyncMethod_ShouldReturnValue");
}
/// <summary>
/// Method '{0}' of view component '{1}' should be declared to return a value.
/// </summary>
internal static string FormatViewComponent_SyncMethod_ShouldReturnValue(object p0, object p1)
=> string.Format(CultureInfo.CurrentCulture, GetString("ViewComponent_SyncMethod_ShouldReturnValue"), p0, p1);
private static string GetString(string name, params string[] formatterNames)
{
var value = _resourceManager.GetString(name);
System.Diagnostics.Debug.Assert(value != null);
if (formatterNames != null)
{
for (var i = 0; i < formatterNames.Length; i++)
{
value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}");
}
}
return value;
}
}
}

View File

@ -0,0 +1,90 @@
// 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.Language;
using Microsoft.AspNetCore.Razor.Language.Extensions;
using Microsoft.CodeAnalysis.Razor;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public static class RazorExtensions
{
public static void Register(RazorProjectEngineBuilder builder)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
InjectDirective.Register(builder);
ModelDirective.Register(builder);
NamespaceDirective.Register(builder);
PageDirective.Register(builder);
FunctionsDirective.Register(builder);
InheritsDirective.Register(builder);
SectionDirective.Register(builder);
builder.Features.Add(new DefaultTagHelperDescriptorProvider());
builder.Features.Add(new ViewComponentTagHelperDescriptorProvider());
builder.AddTargetExtension(new ViewComponentTagHelperTargetExtension());
builder.AddTargetExtension(new TemplateTargetExtension()
{
TemplateTypeName = "global::Microsoft.AspNetCore.Mvc.Razor.HelperResult",
});
builder.Features.Add(new ModelExpressionPass());
builder.Features.Add(new PagesPropertyInjectionPass());
builder.Features.Add(new ViewComponentTagHelperPass());
builder.Features.Add(new RazorPageDocumentClassifierPass());
builder.Features.Add(new MvcViewDocumentClassifierPass());
builder.Features.Add(new AssemblyAttributeInjectionPass());
builder.Features.Add(new InstrumentationPass());
builder.SetImportFeature(new MvcImportProjectFeature());
}
#region Obsolete
[Obsolete("This method is obsolete and will be removed in a future version.")]
public static void Register(IRazorEngineBuilder builder)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
InjectDirective.Register(builder);
ModelDirective.Register(builder);
NamespaceDirective.Register(builder);
PageDirective.Register(builder);
FunctionsDirective.Register(builder);
InheritsDirective.Register(builder);
SectionDirective.Register(builder);
builder.Features.Add(new DefaultTagHelperDescriptorProvider());
builder.Features.Add(new ViewComponentTagHelperDescriptorProvider());
builder.AddTargetExtension(new ViewComponentTagHelperTargetExtension());
builder.AddTargetExtension(new TemplateTargetExtension()
{
TemplateTypeName = "global::Microsoft.AspNetCore.Mvc.Razor.HelperResult",
});
builder.Features.Add(new ModelExpressionPass());
builder.Features.Add(new PagesPropertyInjectionPass());
builder.Features.Add(new ViewComponentTagHelperPass());
builder.Features.Add(new RazorPageDocumentClassifierPass());
builder.Features.Add(new MvcViewDocumentClassifierPass());
if (!builder.DesignTime)
{
builder.Features.Add(new AssemblyAttributeInjectionPass());
builder.Features.Add(new InstrumentationPass());
}
}
#endregion
}
}

View File

@ -0,0 +1,131 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
internal class RazorExtensionsDiagnosticFactory
{
private const string DiagnosticPrefix = "RZ";
internal static readonly RazorDiagnosticDescriptor ViewComponent_CannotFindMethod =
new RazorDiagnosticDescriptor(
$"{DiagnosticPrefix}3900",
() => ViewComponentResources.ViewComponent_CannotFindMethod,
RazorDiagnosticSeverity.Error);
public static RazorDiagnostic CreateViewComponent_CannotFindMethod(string tagHelperType)
{
var diagnostic = RazorDiagnostic.Create(
ViewComponent_CannotFindMethod,
new SourceSpan(SourceLocation.Undefined, contentLength: 0),
ViewComponentTypes.SyncMethodName,
ViewComponentTypes.AsyncMethodName,
tagHelperType);
return diagnostic;
}
internal static readonly RazorDiagnosticDescriptor ViewComponent_AmbiguousMethods =
new RazorDiagnosticDescriptor(
$"{DiagnosticPrefix}3901",
() => ViewComponentResources.ViewComponent_AmbiguousMethods,
RazorDiagnosticSeverity.Error);
public static RazorDiagnostic CreateViewComponent_AmbiguousMethods(string tagHelperType)
{
var diagnostic = RazorDiagnostic.Create(
ViewComponent_AmbiguousMethods,
new SourceSpan(SourceLocation.Undefined, contentLength: 0),
tagHelperType,
ViewComponentTypes.SyncMethodName,
ViewComponentTypes.AsyncMethodName);
return diagnostic;
}
internal static readonly RazorDiagnosticDescriptor ViewComponent_AsyncMethod_ShouldReturnTask =
new RazorDiagnosticDescriptor(
$"{DiagnosticPrefix}3902",
() => ViewComponentResources.ViewComponent_AsyncMethod_ShouldReturnTask,
RazorDiagnosticSeverity.Error);
public static RazorDiagnostic CreateViewComponent_AsyncMethod_ShouldReturnTask(string tagHelperType)
{
var diagnostic = RazorDiagnostic.Create(
ViewComponent_AsyncMethod_ShouldReturnTask,
new SourceSpan(SourceLocation.Undefined, contentLength: 0),
ViewComponentTypes.AsyncMethodName,
tagHelperType,
nameof(Task));
return diagnostic;
}
internal static readonly RazorDiagnosticDescriptor ViewComponent_SyncMethod_ShouldReturnValue =
new RazorDiagnosticDescriptor(
$"{DiagnosticPrefix}3903",
() => ViewComponentResources.ViewComponent_SyncMethod_ShouldReturnValue,
RazorDiagnosticSeverity.Error);
public static RazorDiagnostic CreateViewComponent_SyncMethod_ShouldReturnValue(string tagHelperType)
{
var diagnostic = RazorDiagnostic.Create(
ViewComponent_SyncMethod_ShouldReturnValue,
new SourceSpan(SourceLocation.Undefined, contentLength: 0),
ViewComponentTypes.SyncMethodName,
tagHelperType);
return diagnostic;
}
internal static readonly RazorDiagnosticDescriptor ViewComponent_SyncMethod_CannotReturnTask =
new RazorDiagnosticDescriptor(
$"{DiagnosticPrefix}3904",
() => ViewComponentResources.ViewComponent_SyncMethod_CannotReturnTask,
RazorDiagnosticSeverity.Error);
public static RazorDiagnostic CreateViewComponent_SyncMethod_CannotReturnTask(string tagHelperType)
{
var diagnostic = RazorDiagnostic.Create(
ViewComponent_SyncMethod_CannotReturnTask,
new SourceSpan(SourceLocation.Undefined, contentLength: 0),
ViewComponentTypes.SyncMethodName,
tagHelperType,
nameof(Task));
return diagnostic;
}
internal static readonly RazorDiagnosticDescriptor PageDirective_CannotBeImported =
new RazorDiagnosticDescriptor(
$"{DiagnosticPrefix}3905",
() => Resources.PageDirectiveCannotBeImported,
RazorDiagnosticSeverity.Error);
public static RazorDiagnostic CreatePageDirective_CannotBeImported(SourceSpan source)
{
var fileName = Path.GetFileName(source.FilePath);
var diagnostic = RazorDiagnostic.Create(PageDirective_CannotBeImported, source, PageDirective.Directive.Directive, fileName);
return diagnostic;
}
internal static readonly RazorDiagnosticDescriptor PageDirective_MustExistAtTheTopOfFile =
new RazorDiagnosticDescriptor(
$"{DiagnosticPrefix}3906",
() => Resources.PageDirectiveMustExistAtTheTopOfFile,
RazorDiagnosticSeverity.Error);
public static RazorDiagnostic CreatePageDirective_MustExistAtTheTopOfFile(SourceSpan source)
{
var fileName = Path.GetFileName(source.FilePath);
var diagnostic = RazorDiagnostic.Create(PageDirective_MustExistAtTheTopOfFile, source, PageDirective.Directive.Directive);
return diagnostic;
}
}
}

View File

@ -0,0 +1,135 @@
// 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.Language;
using Microsoft.AspNetCore.Razor.Language.Extensions;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public class RazorPageDocumentClassifierPass : DocumentClassifierPassBase
{
public static readonly string RazorPageDocumentKind = "mvc.1.0.razor-page";
public static readonly string RouteTemplateKey = "RouteTemplate";
private static readonly RazorProjectEngine LeadingDirectiveParsingEngine = RazorProjectEngine.Create(
RazorConfiguration.Default,
RazorProjectFileSystem.Create("/"),
builder =>
{
for (var i = builder.Phases.Count - 1; i >= 0; i--)
{
var phase = builder.Phases[i];
builder.Phases.RemoveAt(i);
if (phase is IRazorDocumentClassifierPhase)
{
break;
}
}
RazorExtensions.Register(builder);
builder.Features.Add(new LeadingDirectiveParserOptionsFeature());
});
protected override string DocumentKind => RazorPageDocumentKind;
protected override bool IsMatch(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
{
return PageDirective.TryGetPageDirective(documentNode, out var pageDirective);
}
protected override void OnDocumentStructureCreated(
RazorCodeDocument codeDocument,
NamespaceDeclarationIntermediateNode @namespace,
ClassDeclarationIntermediateNode @class,
MethodDeclarationIntermediateNode method)
{
base.OnDocumentStructureCreated(codeDocument, @namespace, @class, method);
@namespace.Content = "AspNetCore";
@class.BaseType = "global::Microsoft.AspNetCore.Mvc.RazorPages.Page";
var filePath = codeDocument.Source.RelativePath ?? codeDocument.Source.FilePath;
@class.ClassName = CSharpIdentifier.GetClassNameFromPath(filePath);
@class.Modifiers.Clear();
@class.Modifiers.Add("public");
method.MethodName = "ExecuteAsync";
method.Modifiers.Clear();
method.Modifiers.Add("public");
method.Modifiers.Add("async");
method.Modifiers.Add("override");
method.ReturnType = $"global::{typeof(System.Threading.Tasks.Task).FullName}";
var document = codeDocument.GetDocumentIntermediateNode();
PageDirective.TryGetPageDirective(document, out var pageDirective);
EnsureValidPageDirective(codeDocument, pageDirective);
AddRouteTemplateMetadataAttribute(@namespace, @class, pageDirective);
}
private static void AddRouteTemplateMetadataAttribute(NamespaceDeclarationIntermediateNode @namespace, ClassDeclarationIntermediateNode @class, PageDirective pageDirective)
{
if (string.IsNullOrEmpty(pageDirective.RouteTemplate))
{
return;
}
var classIndex = @namespace.Children.IndexOf(@class);
if (classIndex == -1)
{
return;
}
var metadataAttributeNode = new RazorCompiledItemMetadataAttributeIntermediateNode
{
Key = RouteTemplateKey,
Value = pageDirective.RouteTemplate,
};
// Metadata attributes need to be inserted right before the class declaration.
@namespace.Children.Insert(classIndex, metadataAttributeNode);
}
private void EnsureValidPageDirective(RazorCodeDocument codeDocument, PageDirective pageDirective)
{
Debug.Assert(pageDirective != null);
if (pageDirective.DirectiveNode.IsImported())
{
pageDirective.DirectiveNode.Diagnostics.Add(
RazorExtensionsDiagnosticFactory.CreatePageDirective_CannotBeImported(pageDirective.DirectiveNode.Source.Value));
}
else
{
// The document contains a page directive and it is not imported.
// We now want to make sure this page directive exists at the top of the file.
// We are going to do that by re-parsing the document until the very first line that is not Razor comment
// or whitespace. We then make sure the page directive still exists in the re-parsed IR tree.
var leadingDirectiveCodeDocument = RazorCodeDocument.Create(codeDocument.Source);
LeadingDirectiveParsingEngine.Engine.Process(leadingDirectiveCodeDocument);
var leadingDirectiveDocumentNode = leadingDirectiveCodeDocument.GetDocumentIntermediateNode();
if (!PageDirective.TryGetPageDirective(leadingDirectiveDocumentNode, out var _))
{
// The page directive is not the leading directive. Add an error.
pageDirective.DirectiveNode.Diagnostics.Add(
RazorExtensionsDiagnosticFactory.CreatePageDirective_MustExistAtTheTopOfFile(pageDirective.DirectiveNode.Source.Value));
}
}
}
private class LeadingDirectiveParserOptionsFeature : RazorEngineFeatureBase, IConfigureRazorParserOptionsFeature
{
public int Order { get; }
public void Configure(RazorParserOptionsBuilder options)
{
options.ParseLeadingDirectives = true;
}
}
}
}

View File

@ -0,0 +1,186 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="ArgumentCannotBeNullOrEmpty" xml:space="preserve">
<value>Value cannot be null or empty.</value>
</data>
<data name="InjectDirective_Description" xml:space="preserve">
<value>Inject a service from the application's service container into a property.</value>
</data>
<data name="InjectDirective_MemberToken_Description" xml:space="preserve">
<value>The name of the property.</value>
</data>
<data name="InjectDirective_MemberToken_Name" xml:space="preserve">
<value>PropertyName</value>
</data>
<data name="InjectDirective_TypeToken_Description" xml:space="preserve">
<value>The type of the service to inject.</value>
</data>
<data name="InjectDirective_TypeToken_Name" xml:space="preserve">
<value>TypeName</value>
</data>
<data name="ModelDirective_Description" xml:space="preserve">
<value>Specify the view or page model for the page.</value>
</data>
<data name="ModelDirective_TypeToken_Description" xml:space="preserve">
<value>The model type.</value>
</data>
<data name="ModelDirective_TypeToken_Name" xml:space="preserve">
<value>TypeName</value>
</data>
<data name="MvcRazorCodeParser_CannotHaveModelAndInheritsKeyword" xml:space="preserve">
<value>The 'inherits' keyword is not allowed when a '{0}' keyword is used.</value>
</data>
<data name="MvcRazorCodeParser_InjectDirectivePropertyNameRequired" xml:space="preserve">
<value>A property name must be specified when using the '{0}' statement. Format for a '{0}' statement is '@{0} &lt;Type Name&gt; &lt;Property Name&gt;'.</value>
</data>
<data name="MvcRazorCodeParser_KeywordMustBeFollowedByTypeName" xml:space="preserve">
<value>The '{0}' keyword must be followed by a type name on the same line.</value>
</data>
<data name="MvcRazorCodeParser_OnlyOneModelStatementIsAllowed" xml:space="preserve">
<value>Only one '{0}' statement is allowed in a file.</value>
</data>
<data name="MvcRazorParser_InvalidPropertyType" xml:space="preserve">
<value>Invalid tag helper property '{0}.{1}'. Dictionary values must not be of type '{2}'.</value>
</data>
<data name="NamespaceDirective_Description" xml:space="preserve">
<value>Specify the base namespace for the page.</value>
</data>
<data name="NamespaceDirective_NamespaceToken_Description" xml:space="preserve">
<value>The namespace for the page.</value>
</data>
<data name="NamespaceDirective_NamespaceToken_Name" xml:space="preserve">
<value>Namespace</value>
</data>
<data name="PageDirectiveCannotBeImported" xml:space="preserve">
<value>The '@{0}' directive specified in {1} file will not be imported. The directive must appear at the top of each Razor cshtml file.</value>
</data>
<data name="PageDirectiveMustExistAtTheTopOfFile" xml:space="preserve">
<value>The '@{0}' directive must precede all other elements defined in a Razor file.</value>
</data>
<data name="PageDirective_Description" xml:space="preserve">
<value>Mark the page as a Razor Page.</value>
</data>
<data name="PageDirective_RouteToken_Description" xml:space="preserve">
<value>An optional route template for the page.</value>
</data>
<data name="PageDirective_RouteToken_Name" xml:space="preserve">
<value>RouteTemplate</value>
</data>
</root>

View File

@ -0,0 +1,37 @@
// 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.Language;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public static class TagHelperDescriptorExtensions
{
/// <summary>
/// Indicates whether a <see cref="TagHelperDescriptor"/> represents a view component.
/// </summary>
/// <param name="tagHelper">The <see cref="TagHelperDescriptor"/> to check.</param>
/// <returns>Whether a <see cref="TagHelperDescriptor"/> represents a view component.</returns>
public static bool IsViewComponentKind(this TagHelperDescriptor tagHelper)
{
if (tagHelper == null)
{
throw new ArgumentNullException(nameof(tagHelper));
}
return string.Equals(ViewComponentTagHelperConventions.Kind, tagHelper.Kind, StringComparison.Ordinal);
}
public static string GetViewComponentName(this TagHelperDescriptor tagHelper)
{
if (tagHelper == null)
{
throw new ArgumentNullException(nameof(tagHelper));
}
tagHelper.Metadata.TryGetValue(ViewComponentTagHelperMetadata.Name, out var result);
return result;
}
}
}

View File

@ -0,0 +1,135 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="ViewComponent_AmbiguousMethods" xml:space="preserve">
<value>View component '{0}' must have exactly one public method named '{1}' or '{2}'.</value>
</data>
<data name="ViewComponent_AsyncMethod_ShouldReturnTask" xml:space="preserve">
<value>Method '{0}' of view component '{1}' should be declared to return {2}&amp;lt;T&amp;gt;.</value>
</data>
<data name="ViewComponent_CannotFindMethod" xml:space="preserve">
<value>Could not find an '{0}' or '{1}' method for the view component '{2}'.</value>
</data>
<data name="ViewComponent_SyncMethod_CannotReturnTask" xml:space="preserve">
<value>Method '{0}' of view component '{1}' cannot return a {2}.</value>
</data>
<data name="ViewComponent_SyncMethod_ShouldReturnValue" xml:space="preserve">
<value>Method '{0}' of view component '{1}' should be declared to return a value.</value>
</data>
</root>

View File

@ -0,0 +1,10 @@
// 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.
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public static class ViewComponentTagHelperConventions
{
public static readonly string Kind = "MVC.ViewComponent";
}
}

View File

@ -0,0 +1,269 @@
// 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.Collections.Immutable;
using System.Linq;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
internal class ViewComponentTagHelperDescriptorFactory
{
private readonly INamedTypeSymbol _viewComponentAttributeSymbol;
private readonly INamedTypeSymbol _genericTaskSymbol;
private readonly INamedTypeSymbol _taskSymbol;
private readonly INamedTypeSymbol _iDictionarySymbol;
private static readonly SymbolDisplayFormat FullNameTypeDisplayFormat =
SymbolDisplayFormat.FullyQualifiedFormat
.WithGlobalNamespaceStyle(SymbolDisplayGlobalNamespaceStyle.Omitted)
.WithMiscellaneousOptions(SymbolDisplayFormat.FullyQualifiedFormat.MiscellaneousOptions & (~SymbolDisplayMiscellaneousOptions.UseSpecialTypes));
private static readonly IReadOnlyDictionary<string, string> PrimitiveDisplayTypeNameLookups = new Dictionary<string, string>(StringComparer.Ordinal)
{
[typeof(byte).FullName] = "byte",
[typeof(sbyte).FullName] = "sbyte",
[typeof(int).FullName] = "int",
[typeof(uint).FullName] = "uint",
[typeof(short).FullName] = "short",
[typeof(ushort).FullName] = "ushort",
[typeof(long).FullName] = "long",
[typeof(ulong).FullName] = "ulong",
[typeof(float).FullName] = "float",
[typeof(double).FullName] = "double",
[typeof(char).FullName] = "char",
[typeof(bool).FullName] = "bool",
[typeof(object).FullName] = "object",
[typeof(string).FullName] = "string",
[typeof(decimal).FullName] = "decimal",
};
public ViewComponentTagHelperDescriptorFactory(Compilation compilation)
{
_viewComponentAttributeSymbol = compilation.GetTypeByMetadataName(ViewComponentTypes.ViewComponentAttribute);
_genericTaskSymbol = compilation.GetTypeByMetadataName(ViewComponentTypes.GenericTask);
_taskSymbol = compilation.GetTypeByMetadataName(ViewComponentTypes.Task);
_iDictionarySymbol = compilation.GetTypeByMetadataName(ViewComponentTypes.IDictionary);
}
public virtual TagHelperDescriptor CreateDescriptor(INamedTypeSymbol type)
{
var assemblyName = type.ContainingAssembly.Name;
var shortName = GetShortName(type);
var tagName = $"vc:{HtmlConventions.ToHtmlCase(shortName)}";
var typeName = $"__Generated__{shortName}ViewComponentTagHelper";
var displayName = shortName + "ViewComponentTagHelper";
var descriptorBuilder = TagHelperDescriptorBuilder.Create(ViewComponentTagHelperConventions.Kind, typeName, assemblyName);
descriptorBuilder.SetTypeName(typeName);
descriptorBuilder.DisplayName = displayName;
if (TryFindInvokeMethod(type, out var method, out var diagnostic))
{
var methodParameters = method.Parameters;
descriptorBuilder.TagMatchingRule(ruleBuilder =>
{
ruleBuilder.TagName = tagName;
AddRequiredAttributes(methodParameters, ruleBuilder);
});
AddBoundAttributes(methodParameters, displayName, descriptorBuilder);
}
else
{
descriptorBuilder.Diagnostics.Add(diagnostic);
}
descriptorBuilder.Metadata[ViewComponentTagHelperMetadata.Name] = shortName;
var descriptor = descriptorBuilder.Build();
return descriptor;
}
private bool TryFindInvokeMethod(INamedTypeSymbol type, out IMethodSymbol method, out RazorDiagnostic diagnostic)
{
var methods = type.GetMembers()
.OfType<IMethodSymbol>()
.Where(m =>
m.DeclaredAccessibility == Accessibility.Public &&
(string.Equals(m.Name, ViewComponentTypes.AsyncMethodName, StringComparison.Ordinal) ||
string.Equals(m.Name, ViewComponentTypes.SyncMethodName, StringComparison.Ordinal)))
.ToArray();
if (methods.Length == 0)
{
diagnostic = RazorExtensionsDiagnosticFactory.CreateViewComponent_CannotFindMethod(type.ToDisplayString(FullNameTypeDisplayFormat));
method = null;
return false;
}
else if (methods.Length > 1)
{
diagnostic = RazorExtensionsDiagnosticFactory.CreateViewComponent_AmbiguousMethods(type.ToDisplayString(FullNameTypeDisplayFormat));
method = null;
return false;
}
var selectedMethod = methods[0];
var returnType = selectedMethod.ReturnType as INamedTypeSymbol;
if (string.Equals(selectedMethod.Name, ViewComponentTypes.AsyncMethodName, StringComparison.Ordinal))
{
// Will invoke asynchronously. Method must not return Task or Task<T>.
if (returnType == _taskSymbol)
{
// This is ok.
}
else if (returnType.IsGenericType && returnType.ConstructedFrom == _genericTaskSymbol)
{
// This is ok.
}
else
{
diagnostic = RazorExtensionsDiagnosticFactory.CreateViewComponent_AsyncMethod_ShouldReturnTask(type.ToDisplayString(FullNameTypeDisplayFormat));
method = null;
return false;
}
}
else
{
// Will invoke synchronously. Method must not return void, Task or Task<T>.
if (returnType.SpecialType == SpecialType.System_Void)
{
diagnostic = RazorExtensionsDiagnosticFactory.CreateViewComponent_SyncMethod_ShouldReturnValue(type.ToDisplayString(FullNameTypeDisplayFormat));
method = null;
return false;
}
else if (returnType == _taskSymbol)
{
diagnostic = RazorExtensionsDiagnosticFactory.CreateViewComponent_SyncMethod_CannotReturnTask(type.ToDisplayString(FullNameTypeDisplayFormat));
method = null;
return false;
}
else if (returnType.IsGenericType && returnType.ConstructedFrom == _genericTaskSymbol)
{
diagnostic = RazorExtensionsDiagnosticFactory.CreateViewComponent_SyncMethod_CannotReturnTask(type.ToDisplayString(FullNameTypeDisplayFormat));
method = null;
return false;
}
}
method = selectedMethod;
diagnostic = null;
return true;
}
private void AddRequiredAttributes(ImmutableArray<IParameterSymbol> methodParameters, TagMatchingRuleDescriptorBuilder builder)
{
foreach (var parameter in methodParameters)
{
if (GetIndexerValueTypeName(parameter) == null)
{
// Set required attributes only for non-indexer attributes. Indexer attributes can't be required attributes
// because there are two ways of setting values for the attribute.
builder.Attribute(attributeBuilder =>
{
var lowerKebabName = HtmlConventions.ToHtmlCase(parameter.Name);
attributeBuilder.Name =lowerKebabName;
});
}
}
}
private void AddBoundAttributes(ImmutableArray<IParameterSymbol> methodParameters, string containingDisplayName, TagHelperDescriptorBuilder builder)
{
foreach (var parameter in methodParameters)
{
var lowerKebabName = HtmlConventions.ToHtmlCase(parameter.Name);
var typeName = parameter.Type.ToDisplayString(FullNameTypeDisplayFormat);
if (!PrimitiveDisplayTypeNameLookups.TryGetValue(typeName, out var simpleName))
{
simpleName = typeName;
}
builder.BindAttribute(attributeBuilder =>
{
attributeBuilder.Name = lowerKebabName;
attributeBuilder.TypeName = typeName;
attributeBuilder.DisplayName = $"{simpleName} {containingDisplayName}.{parameter.Name}";
attributeBuilder.SetPropertyName(parameter.Name);
if (parameter.Type.TypeKind == TypeKind.Enum)
{
attributeBuilder.IsEnum = true;
}
else
{
var dictionaryValueType = GetIndexerValueTypeName(parameter);
if (dictionaryValueType != null)
{
attributeBuilder.AsDictionary(lowerKebabName + "-", dictionaryValueType);
}
}
});
}
}
private string GetIndexerValueTypeName(IParameterSymbol parameter)
{
INamedTypeSymbol dictionaryType;
if ((parameter.Type as INamedTypeSymbol)?.ConstructedFrom == _iDictionarySymbol)
{
dictionaryType = (INamedTypeSymbol)parameter.Type;
}
else if (parameter.Type.AllInterfaces.Any(s => s.ConstructedFrom == _iDictionarySymbol))
{
dictionaryType = parameter.Type.AllInterfaces.First(s => s.ConstructedFrom == _iDictionarySymbol);
}
else
{
dictionaryType = null;
}
if (dictionaryType == null || dictionaryType.TypeArguments[0].SpecialType != SpecialType.System_String)
{
return null;
}
var type = dictionaryType.TypeArguments[1];
var typeName = type.ToDisplayString(FullNameTypeDisplayFormat);
return typeName;
}
private string GetShortName(INamedTypeSymbol componentType)
{
var viewComponentAttribute = componentType.GetAttributes().Where(a => a.AttributeClass == _viewComponentAttributeSymbol).FirstOrDefault();
var name = viewComponentAttribute
?.NamedArguments
.Where(namedArgument => string.Equals(namedArgument.Key, ViewComponentTypes.ViewComponent.Name, StringComparison.Ordinal))
.FirstOrDefault()
.Value
.Value as string;
if (!string.IsNullOrEmpty(name))
{
var separatorIndex = name.LastIndexOf('.');
if (separatorIndex >= 0)
{
return name.Substring(separatorIndex + 1);
}
else
{
return name;
}
}
// Get name by convention
if (componentType.Name.EndsWith(ViewComponentTypes.ViewComponentSuffix, StringComparison.OrdinalIgnoreCase))
{
return componentType.Name.Substring(0, componentType.Name.Length - ViewComponentTypes.ViewComponentSuffix.Length);
}
else
{
return componentType.Name;
}
}
}
}

View File

@ -0,0 +1,64 @@
// 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.Language;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public sealed class ViewComponentTagHelperDescriptorProvider : RazorEngineFeatureBase, ITagHelperDescriptorProvider
{
public int Order { get; set; }
public void Execute(TagHelperDescriptorProviderContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var compilation = context.GetCompilation();
if (compilation == null)
{
// No compilation, nothing to do.
return;
}
var types = new List<INamedTypeSymbol>();
var visitor = ViewComponentTypeVisitor.Create(compilation, types);
// We always visit the global namespace.
visitor.Visit(compilation.Assembly.GlobalNamespace);
foreach (var reference in compilation.References)
{
if (compilation.GetAssemblyOrModuleSymbol(reference) is IAssemblySymbol assembly)
{
if (IsTagHelperAssembly(assembly))
{
visitor.Visit(assembly.GlobalNamespace);
}
}
}
var factory = new ViewComponentTagHelperDescriptorFactory(compilation);
for (var i = 0; i < types.Count; i++)
{
var descriptor = factory.CreateDescriptor(types[i]);
if (descriptor != null)
{
context.Results.Add(descriptor);
}
}
}
private bool IsTagHelperAssembly(IAssemblySymbol assembly)
{
return assembly.Name != null && !assembly.Name.StartsWith("System.", StringComparison.Ordinal);
}
}
}

View File

@ -0,0 +1,51 @@
// 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.Language;
using Microsoft.AspNetCore.Razor.Language.CodeGeneration;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public sealed class ViewComponentTagHelperIntermediateNode : ExtensionIntermediateNode
{
public override IntermediateNodeCollection Children { get; } = IntermediateNodeCollection.ReadOnly;
public string ClassName { get; set; }
public TagHelperDescriptor TagHelper { get; set; }
public override void Accept(IntermediateNodeVisitor visitor)
{
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
AcceptExtensionNode<ViewComponentTagHelperIntermediateNode>(this, visitor);
}
public override void WriteNode(CodeTarget target, CodeRenderingContext context)
{
if (target == null)
{
throw new ArgumentNullException(nameof(target));
}
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var extension = target.GetExtension<IViewComponentTagHelperTargetExtension>();
if (extension == null)
{
ReportMissingCodeTargetExtension<IViewComponentTagHelperTargetExtension>(context);
return;
}
extension.WriteViewComponentTagHelper(context, this);
}
}
}

View File

@ -0,0 +1,14 @@
// 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.
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public static class ViewComponentTagHelperMetadata
{
/// <summary>
/// The key in a <see cref="Microsoft.AspNetCore.Razor.Language.TagHelperDescriptor.Metadata"/> containing
/// the short name of a view component.
/// </summary>
public static readonly string Name = "MVC.ViewComponent.Name";
}
}

View File

@ -0,0 +1,203 @@
// 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.Language;
using Microsoft.AspNetCore.Razor.Language.Extensions;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public class ViewComponentTagHelperPass : IntermediateNodePassBase, IRazorOptimizationPass
{
// Run after the default taghelper pass
public override int Order => IntermediateNodePassBase.DefaultFeatureOrder + 2000;
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
{
var @namespace = documentNode.FindPrimaryNamespace();
var @class = documentNode.FindPrimaryClass();
if (@namespace == null || @class == null)
{
// Nothing to do, bail. We can't function without the standard structure.
return;
}
var context = new Context(@namespace, @class);
// For each VCTH *usage* we need to rewrite the tag helper node to use the tag helper runtime to construct
// and set properties on the the correct field, and using the name of the type we will generate.
var nodes = documentNode.FindDescendantNodes<TagHelperIntermediateNode>();
for (var i = 0; i < nodes.Count; i++)
{
var node = nodes[i];
foreach (var tagHelper in node.TagHelpers)
{
RewriteUsage(context, node, tagHelper);
}
}
// Then for each VCTH *definition* that we've seen we need to generate the class that implements
// ITagHelper and the field that will hold it.
foreach (var tagHelper in context.TagHelpers)
{
AddField(context, tagHelper);
AddTagHelperClass(context, tagHelper);
}
}
private void RewriteUsage(Context context, TagHelperIntermediateNode node, TagHelperDescriptor tagHelper)
{
if (!tagHelper.IsViewComponentKind())
{
return;
}
context.Add(tagHelper);
// Now we need to insert a create node using the default tag helper runtime. This is similar to
// code in DefaultTagHelperOptimizationPass.
//
// Find the body node.
var i = 0;
while (i < node.Children.Count && node.Children[i] is TagHelperBodyIntermediateNode)
{
i++;
}
while (i < node.Children.Count && node.Children[i] is DefaultTagHelperBodyIntermediateNode)
{
i++;
}
// Now find the last create node.
while (i < node.Children.Count && node.Children[i] is DefaultTagHelperCreateIntermediateNode)
{
i++;
}
// Now i has the right insertion point.
node.Children.Insert(i, new DefaultTagHelperCreateIntermediateNode()
{
FieldName = context.GetFieldName(tagHelper),
TagHelper = tagHelper,
TypeName = context.GetFullyQualifiedName(tagHelper),
});
// Now we need to rewrite any set property nodes to use the default runtime.
for (i = 0; i < node.Children.Count; i++)
{
if (node.Children[i] is TagHelperPropertyIntermediateNode propertyNode &&
propertyNode.TagHelper == tagHelper)
{
// This is a set property for this VCTH - we need to replace it with a node
// that will use our field and property name.
node.Children[i] = new DefaultTagHelperPropertyIntermediateNode(propertyNode)
{
FieldName = context.GetFieldName(tagHelper),
PropertyName = propertyNode.BoundAttribute.GetPropertyName(),
};
}
}
}
private void AddField(Context context, TagHelperDescriptor tagHelper)
{
// We need to insert a node for the field that will hold the tag helper. We've already generated a field name
// at this time and use it for all uses of the same tag helper type.
//
// We also want to preserve the ordering of the nodes for testability. So insert at the end of any existing
// field nodes.
var i = 0;
while (i < context.Class.Children.Count && context.Class.Children[i] is DefaultTagHelperRuntimeIntermediateNode)
{
i++;
}
while (i < context.Class.Children.Count && context.Class.Children[i] is FieldDeclarationIntermediateNode)
{
i++;
}
context.Class.Children.Insert(i, new FieldDeclarationIntermediateNode()
{
Annotations =
{
{ CommonAnnotations.DefaultTagHelperExtension.TagHelperField, bool.TrueString },
},
Modifiers =
{
"private",
},
FieldName = context.GetFieldName(tagHelper),
FieldType = "global::" + context.GetFullyQualifiedName(tagHelper),
});
}
private void AddTagHelperClass(Context context, TagHelperDescriptor tagHelper)
{
var node = new ViewComponentTagHelperIntermediateNode()
{
ClassName = context.GetClassName(tagHelper),
TagHelper = tagHelper
};
context.Class.Children.Add(node);
}
private struct Context
{
private Dictionary<TagHelperDescriptor, (string className, string fullyQualifiedName, string fieldName)> _tagHelpers;
public Context(NamespaceDeclarationIntermediateNode @namespace, ClassDeclarationIntermediateNode @class)
{
Namespace = @namespace;
Class = @class;
_tagHelpers = new Dictionary<TagHelperDescriptor, (string, string, string)>();
}
public ClassDeclarationIntermediateNode Class { get; }
public NamespaceDeclarationIntermediateNode Namespace { get; }
public IEnumerable<TagHelperDescriptor> TagHelpers => _tagHelpers.Keys;
public bool Add(TagHelperDescriptor tagHelper)
{
if (_tagHelpers.ContainsKey(tagHelper))
{
return false;
}
var className = $"__Generated__{tagHelper.GetViewComponentName()}ViewComponentTagHelper";
var fullyQualifiedName = $"{Namespace.Content}.{Class.ClassName}.{className}";
var fieldName = GenerateFieldName(tagHelper);
_tagHelpers.Add(tagHelper, (className, fullyQualifiedName, fieldName));
return true;
}
public string GetClassName(TagHelperDescriptor taghelper)
{
return _tagHelpers[taghelper].className;
}
public string GetFullyQualifiedName(TagHelperDescriptor taghelper)
{
return _tagHelpers[taghelper].fullyQualifiedName;
}
public string GetFieldName(TagHelperDescriptor taghelper)
{
return _tagHelpers[taghelper].fieldName;
}
private static string GenerateFieldName(TagHelperDescriptor tagHelper)
{
return $"__{tagHelper.GetViewComponentName()}ViewComponentTagHelper";
}
}
}
}

View File

@ -0,0 +1,183 @@
// 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.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.CodeGeneration;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
internal class ViewComponentTagHelperTargetExtension : IViewComponentTagHelperTargetExtension
{
private static readonly string[] PublicModifiers = new[] { "public" };
public string TagHelperTypeName { get; set; } = "Microsoft.AspNetCore.Razor.TagHelpers.TagHelper";
public string ViewComponentHelperTypeName { get; set; } = "global::Microsoft.AspNetCore.Mvc.IViewComponentHelper";
public string ViewComponentHelperVariableName { get; set; } = "_helper";
public string ViewComponentInvokeMethodName { get; set; } = "InvokeAsync";
public string HtmlAttributeNotBoundAttributeTypeName { get; set; } = "Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeNotBoundAttribute";
public string ViewContextAttributeTypeName { get; set; } = "global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewContextAttribute";
public string ViewContextTypeName { get; set; } = "global::Microsoft.AspNetCore.Mvc.Rendering.ViewContext";
public string ViewContextPropertyName { get; set; } = "ViewContext";
public string HtmlTargetElementAttributeTypeName { get; set; } = "Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute";
public string TagHelperProcessMethodName { get; set; } = "ProcessAsync";
public string TagHelperContextTypeName { get; set; } = "Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext";
public string TagHelperContextVariableName { get; set; } = "context";
public string TagHelperOutputTypeName { get; set; } = "Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput";
public string TagHelperOutputVariableName { get; set; } = "output";
public string TagHelperOutputTagNamePropertyName { get; set; } = "TagName";
public string TagHelperOutputContentPropertyName { get; set; } = "Content";
public string TagHelperContentSetMethodName { get; set; } = "SetHtmlContent";
public string TagHelperContentVariableName { get; set; } = "content";
public string IViewContextAwareTypeName { get; set; } = "global::Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware";
public string IViewContextAwareContextualizeMethodName { get; set; } = "Contextualize";
public void WriteViewComponentTagHelper(CodeRenderingContext context, ViewComponentTagHelperIntermediateNode node)
{
// Add target element.
WriteTargetElementString(context.CodeWriter, node.TagHelper);
// Initialize declaration.
using (context.CodeWriter.BuildClassDeclaration(
PublicModifiers,
node.ClassName,
TagHelperTypeName,
interfaces: null,
typeParameters: null))
{
// Add view component helper.
context.CodeWriter.WriteVariableDeclaration(
$"private readonly {ViewComponentHelperTypeName}",
ViewComponentHelperVariableName,
value: null);
// Add constructor.
WriteConstructorString(context.CodeWriter, node.ClassName);
// Add attributes.
WriteAttributeDeclarations(context.CodeWriter, node.TagHelper);
// Add process method.
WriteProcessMethodString(context.CodeWriter, node.TagHelper);
}
}
private void WriteConstructorString(CodeWriter writer, string className)
{
writer.Write("public ")
.Write(className)
.Write("(")
.Write($"{ViewComponentHelperTypeName} helper")
.WriteLine(")");
using (writer.BuildScope())
{
writer.WriteStartAssignment(ViewComponentHelperVariableName)
.Write("helper")
.WriteLine(";");
}
}
private void WriteAttributeDeclarations(CodeWriter writer, TagHelperDescriptor tagHelper)
{
writer.Write("[")
.Write(HtmlAttributeNotBoundAttributeTypeName)
.WriteParameterSeparator()
.Write(ViewContextAttributeTypeName)
.WriteLine("]");
writer.WriteAutoPropertyDeclaration(
PublicModifiers,
ViewContextTypeName,
ViewContextPropertyName);
foreach (var attribute in tagHelper.BoundAttributes)
{
writer.WriteAutoPropertyDeclaration(
PublicModifiers,
attribute.TypeName,
attribute.GetPropertyName());
if (attribute.IndexerTypeName != null)
{
writer.Write(" = ")
.WriteStartNewObject(attribute.TypeName)
.WriteEndMethodInvocation();
}
}
}
private void WriteProcessMethodString(CodeWriter writer, TagHelperDescriptor tagHelper)
{
using (writer.BuildMethodDeclaration(
$"public override async",
$"global::{typeof(Task).FullName}",
TagHelperProcessMethodName,
new Dictionary<string, string>()
{
{ TagHelperContextTypeName, TagHelperContextVariableName },
{ TagHelperOutputTypeName, TagHelperOutputVariableName }
}))
{
writer.WriteInstanceMethodInvocation(
$"({ViewComponentHelperVariableName} as {IViewContextAwareTypeName})?",
IViewContextAwareContextualizeMethodName,
new[] { ViewContextPropertyName });
var methodParameters = GetMethodParameters(tagHelper);
writer.Write("var ")
.WriteStartAssignment(TagHelperContentVariableName)
.WriteInstanceMethodInvocation($"await {ViewComponentHelperVariableName}", ViewComponentInvokeMethodName, methodParameters);
writer.WriteStartAssignment($"{TagHelperOutputVariableName}.{TagHelperOutputTagNamePropertyName}")
.WriteLine("null;");
writer.WriteInstanceMethodInvocation(
$"{TagHelperOutputVariableName}.{TagHelperOutputContentPropertyName}",
TagHelperContentSetMethodName,
new[] { TagHelperContentVariableName });
}
}
private string[] GetMethodParameters(TagHelperDescriptor tagHelper)
{
var propertyNames = tagHelper.BoundAttributes.Select(attribute => attribute.GetPropertyName());
var joinedPropertyNames = string.Join(", ", propertyNames);
var parametersString = $"new {{ { joinedPropertyNames } }}";
var viewComponentName = tagHelper.GetViewComponentName();
var methodParameters = new[] { $"\"{viewComponentName}\"", parametersString };
return methodParameters;
}
private void WriteTargetElementString(CodeWriter writer, TagHelperDescriptor tagHelper)
{
Debug.Assert(tagHelper.TagMatchingRules.Count() == 1);
var rule = tagHelper.TagMatchingRules.First();
writer.Write("[")
.WriteStartMethodInvocation(HtmlTargetElementAttributeTypeName)
.WriteStringLiteral(rule.TagName)
.WriteLine(")]");
}
}
}

View File

@ -0,0 +1,95 @@
// 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.CodeAnalysis;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
internal class ViewComponentTypeVisitor : SymbolVisitor
{
private readonly INamedTypeSymbol _viewComponentAttribute;
private readonly INamedTypeSymbol _nonViewComponentAttribute;
private readonly List<INamedTypeSymbol> _results;
public static ViewComponentTypeVisitor Create(Compilation compilation, List<INamedTypeSymbol> results)
{
var vcAttribute = compilation.GetTypeByMetadataName(ViewComponentTypes.ViewComponentAttribute);
var nonVCAttribute = compilation.GetTypeByMetadataName(ViewComponentTypes.NonViewComponentAttribute);
return new ViewComponentTypeVisitor(vcAttribute, nonVCAttribute, results);
}
public ViewComponentTypeVisitor(
INamedTypeSymbol viewComponentAttribute,
INamedTypeSymbol nonViewComponentAttribute,
List<INamedTypeSymbol> results)
{
_viewComponentAttribute = viewComponentAttribute;
_nonViewComponentAttribute = nonViewComponentAttribute;
_results = results;
}
public override void VisitNamedType(INamedTypeSymbol symbol)
{
if (IsViewComponent(symbol))
{
_results.Add(symbol);
}
if (symbol.DeclaredAccessibility != Accessibility.Public)
{
return;
}
foreach (var member in symbol.GetTypeMembers())
{
Visit(member);
}
}
public override void VisitNamespace(INamespaceSymbol symbol)
{
foreach (var member in symbol.GetMembers())
{
Visit(member);
}
}
internal bool IsViewComponent(INamedTypeSymbol symbol)
{
if (_viewComponentAttribute == null)
{
return false;
}
if (symbol.DeclaredAccessibility != Accessibility.Public ||
symbol.IsAbstract ||
symbol.IsGenericType ||
AttributeIsDefined(symbol, _nonViewComponentAttribute))
{
return false;
}
return symbol.Name.EndsWith(ViewComponentTypes.ViewComponentSuffix) ||
AttributeIsDefined(symbol, _viewComponentAttribute);
}
private static bool AttributeIsDefined(INamedTypeSymbol type, INamedTypeSymbol queryAttribute)
{
if (type == null || queryAttribute == null)
{
return false;
}
var attribute = type.GetAttributes().Where(a => a.AttributeClass == queryAttribute).FirstOrDefault();
if (attribute != null)
{
return true;
}
return AttributeIsDefined(type.BaseType, queryAttribute);
}
}
}

View File

@ -0,0 +1,35 @@
// 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;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
internal static class ViewComponentTypes
{
public const string Assembly = "Microsoft.AspNetCore.Mvc.ViewFeatures";
public static readonly Version AssemblyVersion = new Version(1, 1, 0, 0);
public const string ViewComponentSuffix = "ViewComponent";
public const string ViewComponentAttribute = "Microsoft.AspNetCore.Mvc.ViewComponentAttribute";
public const string NonViewComponentAttribute = "Microsoft.AspNetCore.Mvc.NonViewComponentAttribute";
public const string GenericTask = "System.Threading.Tasks.Task`1";
public const string Task = "System.Threading.Tasks.Task";
public const string IDictionary = "System.Collections.Generic.IDictionary`2";
public const string AsyncMethodName = "InvokeAsync";
public const string SyncMethodName = "Invoke";
public static class ViewComponent
{
public const string Name = "Name";
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,40 @@
<Project>
<!--
MSBuild support for Razor code generation that targets ASP.NET Core MVC 2.X
The properties and items here are designed to be read by CPS so they should be just simple evaluation-time values
and should not require targets to initialize.
-->
<PropertyGroup>
<!--
Set the primary configuration supported by this pacakge as the default configuration for Razor.
-->
<RazorDefaultConfiguration Condition="'$(RazorDefaultConfiguration)'==''">MVC-2.1</RazorDefaultConfiguration>
<!--
MVC uses a ProvideApplicationPartFactoryAttribute on the generated assembly to load compiled views from assembly. Set this to false, to prevent generating this attribute.
-->
<GenerateProvideApplicationPartFactoryAttribute>true</GenerateProvideApplicationPartFactoryAttribute>
<!-- Override for testing. This path is only correct inside a nuget package. -->
<_MvcExtensionAssemblyPath Condition="'$(_MvcExtensionAssemblyPath)'==''">$(MSBuildThisFileDirectory)..\..\lib\netstandard2.0\Microsoft.AspNetCore.Mvc.Razor.Extensions.dll</_MvcExtensionAssemblyPath>
</PropertyGroup>
<ItemGroup>
<!--
While technically the assembly in this package can provide support for the MVC-2.0 configuration, don't declare
it here. The IDE is hardcoded to inject 2.0 support when needed. The settings flowing through MSBuild should reflect
the project's runtime.
-->
<RazorConfiguration Include="MVC-2.1">
<Extensions>MVC-2.1;$(CustomRazorExtension)</Extensions>
</RazorConfiguration>
</ItemGroup>
<ItemGroup>
<RazorExtension Include="MVC-2.1">
<AssemblyName>Microsoft.AspNetCore.Mvc.Razor.Extensions</AssemblyName>
<AssemblyFilePath>$(_MvcExtensionAssemblyPath)</AssemblyFilePath>
</RazorExtension>
</ItemGroup>
</Project>

View File

@ -0,0 +1,36 @@
<Project>
<PropertyGroup>
<!--
Determines if the Sdk is allowed to add additional attributes to the project assembly.
For instance, MVC will generally want to add attributes to support view discovery and runtime compilation.
-->
<GenerateRazorAssemblyInfo Condition="'$(GenerateRazorAssemblyInfo)'==''">true</GenerateRazorAssemblyInfo>
<!--
MVC will generally want to add support for runtime compilation, but only for applications.
-->
<GenerateRazorHostingAssemblyInfo Condition="'$(GenerateRazorHostingAssemblyInfo)'=='' AND '$(OutputType)'=='exe'">$(GenerateRazorAssemblyInfo)</GenerateRazorHostingAssemblyInfo>
<!--
Use the suffix .Views when producing compiled view assemblies. This matches the requirements for Mvc's ViewsFeatureProvider.
-->
<RazorTargetNameSuffix Condition="'$(RazorTargetNameSuffix)'==''">.Views</RazorTargetNameSuffix>
<!--
The type name of the ApplicationPartFactory applied to the generated Razor file.
-->
<ProvideApplicationPartFactoryAttributeTypeName Condition="'$(ProvideApplicationPartFactoryAttributeTypeName)' == ''">Microsoft.AspNetCore.Mvc.ApplicationParts.CompiledRazorAssemblyApplicationPartFactory, Microsoft.AspNetCore.Mvc.Razor</ProvideApplicationPartFactoryAttributeTypeName>
</PropertyGroup>
<ItemGroup Condition="'$(GenerateRazorAssemblyInfo)'=='true' AND '$(ResolvedRazorCompileToolset)'=='RazorSdk' AND ('$(RazorCompileOnBuild)' == 'true' OR '$(RazorCompileOnPublish)' == 'true')">
<_RazorAssemblyAttribute Include="Microsoft.AspNetCore.Mvc.ApplicationParts.RelatedAssemblyAttribute">
<_Parameter1>$(RazorTargetName)</_Parameter1>
</_RazorAssemblyAttribute>
</ItemGroup>
<ItemGroup Condition="'$(GenerateProvideApplicationPartFactoryAttribute)' == 'true' AND '$(ProvideApplicationPartFactoryAttributeTypeName)'!=''">
<RazorTargetAssemblyAttribute Include="Microsoft.AspNetCore.Mvc.ApplicationParts.ProvideApplicationPartFactoryAttribute">
<_Parameter1>$(ProvideApplicationPartFactoryAttributeTypeName)</_Parameter1>
</RazorTargetAssemblyAttribute>
</ItemGroup>
</Project>

View File

@ -0,0 +1,125 @@
<Project>
<!-- Using explicit SDK imports here because the default way conflicts with the AfterBuild target -->
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
<PropertyGroup>
<Description>Razor is a markup syntax for adding server-side logic to web pages. This package contains MSBuild support for Razor.</Description>
<TargetFramework>netstandard2.0</TargetFramework>
<!-- This project doesn't have any code, so don't include it in the .nupkg -->
<IncludeBuildOutput>false</IncludeBuildOutput>
<NuspecFile>$(MSBuildProjectName).nuspec</NuspecFile>
</PropertyGroup>
<!--
Building this package is somewhat complicated because we need to Build or Publish some other projects
that have different TFM's including one with multiple TFMs.
We then need to include the output of those projects in our output directory (where it will be used
by tests) and in the nukpg.
-->
<!-- This is the tasks project that needs to be included in the package. -->
<ItemGroup>
<TaskProject Include="..\Microsoft.AspNetCore.Razor.Tasks\Microsoft.AspNetCore.Razor.Tasks.csproj" />
</ItemGroup>
<!-- These are tools that need to be included in the package. -->
<ItemGroup>
<ToolProject Include="..\Microsoft.AspNetCore.Razor.Tools\Microsoft.AspNetCore.Razor.Tools.csproj" />
</ItemGroup>
<!-- Using explicit SDK imports here because the default way conflicts with the AfterBuild target -->
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
<PropertyGroup>
<GenerateNuspecDependsOn>_BuildDependencyProjects;$(GenerateNuspecDependsOn)</GenerateNuspecDependsOn>
<BuildDependsOn>_BuildDependencyProjects;$(BuildDependsOn)</BuildDependsOn>
</PropertyGroup>
<Target Name="_BuildDependencyProjects">
<!--
The Microsoft.AspNetCore.Razor.Tasks package needs to support both net46 and netstandard2.0 for desktop vs
coreclr MSBuild - so we have to build it twice.
We're careful here to avoid setting properties when building the other projects. This can create problems
with concurrency.
First, build the project, then copy it to the ouput directory, then add it as packable content.
-->
<MSBuild Projects="@(TaskProject)" />
<MSBuild Projects="@(TaskProject)" Properties="TargetFramework=net46" Targets="BuiltProjectOutputGroup">
<Output TaskParameter="TargetOutputs" ItemName="TaskAssemblyNet46" />
</MSBuild>
<MSBuild Projects="@(TaskProject)" Properties="TargetFramework=net46" Targets="DebugSymbolsProjectOutputGroup">
<Output TaskParameter="TargetOutputs" ItemName="TaskSymbolNet46" />
</MSBuild>
<MSBuild Projects="@(TaskProject)" Properties="TargetFramework=netstandard2.0" Targets="BuiltProjectOutputGroup">
<Output TaskParameter="TargetOutputs" ItemName="TaskAssemblyNetStandard" />
</MSBuild>
<MSBuild Projects="@(TaskProject)" Properties="TargetFramework=netstandard2.0" Targets="DebugSymbolsProjectOutputGroup">
<Output TaskParameter="TargetOutputs" ItemName="TaskSymbolNetStandard" />
</MSBuild>
<Copy SourceFiles="@(TaskAssemblyNet46)" DestinationFolder="$(OutputPath)\tasks\net46\">
<Output TaskParameter="CopiedFiles" ItemName="FileWrites" />
</Copy>
<Copy SourceFiles="@(TaskAssemblyNetStandard)" DestinationFolder="$(OutputPath)\tasks\netstandard2.0\">
<Output TaskParameter="CopiedFiles" ItemName="FileWrites" />
</Copy>
<Error Text="TaskAssemblyNet46 is empty. This is a bug" Condition="'@(TaskAssemblyNet46)'==''" />
<Error Text="TaskAssemblyNetStandard is empty. This is a bug" Condition="'@(TaskAssemblyNetStandard)'==''" />
<!--
Next we need to build the netcoreapp2.0 tools. In this case we need to do a publish, because we need
all of the output to put in the package.
-->
<RemoveDir Directories="tools\" />
<MSBuild Projects="@(ToolProject)" />
<MSBuild Projects="@(ToolProject)" Properties="PublishDir=$(MSBuildProjectDirectory)\$(OutputPath)tools\" Targets="Publish" />
<ItemGroup>
<_RazorTool Include="$(OutputPath)tools\**\*" />
</ItemGroup>
<Error Text="_RazorTool is empty. This is a bug" Condition="'@(_RazorTool)'==''" />
</Target>
<Target Name="PopulateNuspec" BeforeTargets="GenerateNuspec" DependsOnTargets="BuiltProjectOutputGroup;DebugSymbolsProjectOutputGroup;_BuildDependencyProjects">
<PropertyGroup>
<!-- Make sure we create a symbols.nupkg. -->
<IncludeSymbols>true</IncludeSymbols>
<NuspecProperties>
id=$(PackageId);
version=$(PackageVersion);
authors=$(Authors);
description=$(Description);
tags=$(PackageTags.Replace(';', ' '));
licenseUrl=$(PackageLicenseUrl);
projectUrl=$(PackageProjectUrl);
iconUrl=$(PackageIconUrl);
repositoryUrl=$(RepositoryUrl);
repositoryCommit=$(RepositoryCommit);
copyright=$(Copyright);
<!-- Include the assembly and symbols from the tasks project -->
TaskAssemblyNet46=@(TaskAssemblyNet46);
TaskSymbolNet46=@(TaskSymbolNet46);
TaskAssemblyNetStandard=@(TaskAssemblyNetStandard);
TaskSymbolNetStandard=@(TaskSymbolNetStandard);
<!-- Include the assembly and symbols from the tools project -->
ToolAssembly=$(OutputPath)tools\**\*;
</NuspecProperties>
</PropertyGroup>
</Target>
</Project>

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
<id>$id$</id>
<version>$version$</version>
<authors>$authors$</authors>
<description>$description$</description>
<requireLicenseAcceptance>true</requireLicenseAcceptance>
<tags>$tags$</tags>
<licenseUrl>$licenseUrl$</licenseUrl>
<projectUrl>$projectUrl$</projectUrl>
<iconUrl>$iconUrl$</iconUrl>
<repository type="git" url="$repositoryUrl$" commit="$repositoryCommit$" />
<copyright>$copyright$</copyright>
<dependencies>
<group targetFramework=".NETStandard2.0" />
</dependencies>
</metadata>
<files>
<file src="build\**\*.props" target="build\" />
<file src="build\**\*.targets" target="build\" />
<file src="buildMultiTargeting\**\*.props" target="buildMultiTargeting\" />
<file src="buildMultiTargeting\**\*.targets" target="buildMultiTargeting\" />
<file src="$TaskAssemblyNet46$" target="tasks\net46\" />
<file src="$TaskSymbolNet46$" target="tasks\net46\" />
<file src="$TaskAssemblyNetStandard$" target="tasks\netstandard2.0\" />
<file src="$TaskSymbolNetStandard$" target="tasks\netstandard2.0\" />
<file src="$ToolAssembly$" target="tools\" exclude="**\*.xml" />
</files>
</package>

Some files were not shown because too many files have changed in this diff Show More