Merge remote-tracking branch 'Mvc/rybrande/release22ToSrc' into rybrande/Mondo2.2

This commit is contained in:
Ryan Brandenburg 2018-11-27 12:26:05 -08:00
commit 4d9b60d0ad
1262 changed files with 57029 additions and 13089 deletions

1
src/Mvc/.gitignore vendored
View File

@ -37,7 +37,6 @@ node_modules
*launchSettings.json
*.orig
.vscode/
global.json
BenchmarkDotNet.Artifacts/
.idea/
msbuild.binlog

View File

@ -14,8 +14,8 @@
<RepositoryRoot>$(MSBuildThisFileDirectory)</RepositoryRoot>
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)build\Key.snk</AssemblyOriginatorKeyFile>
<SignAssembly>true</SignAssembly>
<PublicSign Condition="'$(OS)' != 'Windows_NT'">true</PublicSign>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<UseRoutingFromFeatureBranch>true</UseRoutingFromFeatureBranch>
</PropertyGroup>
</Project>

View File

@ -1,6 +1,9 @@
<Project>
<Project>
<PropertyGroup>
<RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp2.1' ">$(MicrosoftNETCoreApp21PackageVersion)</RuntimeFrameworkVersion>
<RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp2.2' ">$(MicrosoftNETCoreApp22PackageVersion)</RuntimeFrameworkVersion>
<NETStandardImplicitPackageVersion Condition=" '$(TargetFramework)' == 'netstandard2.0' ">$(NETStandardLibrary20PackageVersion)</NETStandardImplicitPackageVersion>
<!-- aspnet/BuildTools#662 Don't police what version of NetCoreApp we use -->
<NETCoreAppMaximumVersion>99.9</NETCoreAppMaximumVersion>
</PropertyGroup>
</Project>

View File

@ -1,3 +1,4 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27130.2036
@ -35,7 +36,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Ta
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.TagHelpers.Test", "test\Microsoft.AspNetCore.Mvc.TagHelpers.Test\Microsoft.AspNetCore.Mvc.TagHelpers.Test.csproj", "{860119ED-3DB1-424D-8D0A-30132A8A7D96}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.TestCommon", "test\Microsoft.AspNetCore.Mvc.TestCommon\Microsoft.AspNetCore.Mvc.TestCommon.csproj", "{F504357E-C2E1-4818-BA5C-9A2EAC25FEE5}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Core.TestCommon", "test\Microsoft.AspNetCore.Mvc.Core.TestCommon\Microsoft.AspNetCore.Mvc.Core.TestCommon.csproj", "{F504357E-C2E1-4818-BA5C-9A2EAC25FEE5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.IntegrationTests", "test\Microsoft.AspNetCore.Mvc.IntegrationTests\Microsoft.AspNetCore.Mvc.IntegrationTests.csproj", "{864FA09D-1E48-403A-A6C8-4F079D2A30F0}"
EndProject
@ -104,13 +105,23 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmarks", "benchmarks", "{44546170-35BF-448F-88F5-4331AE67AEAE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test", "test\Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test\Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test.csproj", "{2E6CDE10-8F96-4B75-B0D9-808F6A01B8BD}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Analyzers", "src\Microsoft.AspNetCore.Mvc.Analyzers\Microsoft.AspNetCore.Mvc.Analyzers.csproj", "{30862895-C1FA-49F5-B69A-B0F9F2ECD0F3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Analyzers.Experimental", "src\Microsoft.AspNetCore.Mvc.Analyzers.Experimental\Microsoft.AspNetCore.Mvc.Analyzers.Experimental.csproj", "{F8FD2D6A-DCD1-4A7B-B599-B728A12A1754}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mvc.Analyzers.Test", "test\Mvc.Analyzers.Test\Mvc.Analyzers.Test.csproj", "{829D9A67-2D07-4CE6-86C0-59F2549B0CFA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Analyzers.Test", "test\Microsoft.AspNetCore.Mvc.Analyzers.Test\Microsoft.AspNetCore.Mvc.Analyzers.Test.csproj", "{829D9A67-2D07-4CE6-86C0-59F2549B0CFA}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Views.TestCommon", "test\Microsoft.AspNetCore.Mvc.Views.TestCommon\Microsoft.AspNetCore.Mvc.Views.TestCommon.csproj", "{0772E545-A674-4165-9469-E3D79D88A4A8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Testing", "src\Microsoft.AspNetCore.Mvc.Testing\Microsoft.AspNetCore.Mvc.Testing.csproj", "{92D959F2-66B8-490A-BA33-DA4421EBC948}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Api.Analyzers", "src\Microsoft.AspNetCore.Mvc.Api.Analyzers\Microsoft.AspNetCore.Mvc.Api.Analyzers.csproj", "{1B398182-9EAE-400B-A2BD-EFFAC0168A36}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mvc.Api.Analyzers.Test", "test\Mvc.Api.Analyzers.Test\Mvc.Api.Analyzers.Test.csproj", "{71C626FC-6408-494B-A127-38CB64F71324}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-getdocument", "src\dotnet-getdocument\dotnet-getdocument.csproj", "{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GetDocumentInsider", "src\GetDocumentInsider\GetDocumentInsider.csproj", "{2F683CF8-B055-46AE-BF83-9D1307F8D45F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.ApiDescription.Design", "src\Microsoft.Extensions.ApiDescription.Design\Microsoft.Extensions.ApiDescription.Design.csproj", "{34E3C302-B767-40C8-B538-3EE2BD4000C4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -498,18 +509,6 @@ Global
{28D4DA20-6E13-47F9-80AE-D6AA7699CC35}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{28D4DA20-6E13-47F9-80AE-D6AA7699CC35}.Release|x86.ActiveCfg = Release|Any CPU
{28D4DA20-6E13-47F9-80AE-D6AA7699CC35}.Release|x86.Build.0 = Release|Any CPU
{2E6CDE10-8F96-4B75-B0D9-808F6A01B8BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2E6CDE10-8F96-4B75-B0D9-808F6A01B8BD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2E6CDE10-8F96-4B75-B0D9-808F6A01B8BD}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{2E6CDE10-8F96-4B75-B0D9-808F6A01B8BD}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{2E6CDE10-8F96-4B75-B0D9-808F6A01B8BD}.Debug|x86.ActiveCfg = Debug|Any CPU
{2E6CDE10-8F96-4B75-B0D9-808F6A01B8BD}.Debug|x86.Build.0 = Debug|Any CPU
{2E6CDE10-8F96-4B75-B0D9-808F6A01B8BD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2E6CDE10-8F96-4B75-B0D9-808F6A01B8BD}.Release|Any CPU.Build.0 = Release|Any CPU
{2E6CDE10-8F96-4B75-B0D9-808F6A01B8BD}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{2E6CDE10-8F96-4B75-B0D9-808F6A01B8BD}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{2E6CDE10-8F96-4B75-B0D9-808F6A01B8BD}.Release|x86.ActiveCfg = Release|Any CPU
{2E6CDE10-8F96-4B75-B0D9-808F6A01B8BD}.Release|x86.Build.0 = Release|Any CPU
{30862895-C1FA-49F5-B69A-B0F9F2ECD0F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{30862895-C1FA-49F5-B69A-B0F9F2ECD0F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{30862895-C1FA-49F5-B69A-B0F9F2ECD0F3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
@ -522,18 +521,6 @@ Global
{30862895-C1FA-49F5-B69A-B0F9F2ECD0F3}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{30862895-C1FA-49F5-B69A-B0F9F2ECD0F3}.Release|x86.ActiveCfg = Release|Any CPU
{30862895-C1FA-49F5-B69A-B0F9F2ECD0F3}.Release|x86.Build.0 = Release|Any CPU
{F8FD2D6A-DCD1-4A7B-B599-B728A12A1754}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F8FD2D6A-DCD1-4A7B-B599-B728A12A1754}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F8FD2D6A-DCD1-4A7B-B599-B728A12A1754}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{F8FD2D6A-DCD1-4A7B-B599-B728A12A1754}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{F8FD2D6A-DCD1-4A7B-B599-B728A12A1754}.Debug|x86.ActiveCfg = Debug|Any CPU
{F8FD2D6A-DCD1-4A7B-B599-B728A12A1754}.Debug|x86.Build.0 = Debug|Any CPU
{F8FD2D6A-DCD1-4A7B-B599-B728A12A1754}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F8FD2D6A-DCD1-4A7B-B599-B728A12A1754}.Release|Any CPU.Build.0 = Release|Any CPU
{F8FD2D6A-DCD1-4A7B-B599-B728A12A1754}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{F8FD2D6A-DCD1-4A7B-B599-B728A12A1754}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{F8FD2D6A-DCD1-4A7B-B599-B728A12A1754}.Release|x86.ActiveCfg = Release|Any CPU
{F8FD2D6A-DCD1-4A7B-B599-B728A12A1754}.Release|x86.Build.0 = Release|Any CPU
{829D9A67-2D07-4CE6-86C0-59F2549B0CFA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{829D9A67-2D07-4CE6-86C0-59F2549B0CFA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{829D9A67-2D07-4CE6-86C0-59F2549B0CFA}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
@ -546,6 +533,90 @@ Global
{829D9A67-2D07-4CE6-86C0-59F2549B0CFA}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{829D9A67-2D07-4CE6-86C0-59F2549B0CFA}.Release|x86.ActiveCfg = Release|Any CPU
{829D9A67-2D07-4CE6-86C0-59F2549B0CFA}.Release|x86.Build.0 = Release|Any CPU
{0772E545-A674-4165-9469-E3D79D88A4A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0772E545-A674-4165-9469-E3D79D88A4A8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0772E545-A674-4165-9469-E3D79D88A4A8}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{0772E545-A674-4165-9469-E3D79D88A4A8}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{0772E545-A674-4165-9469-E3D79D88A4A8}.Debug|x86.ActiveCfg = Debug|Any CPU
{0772E545-A674-4165-9469-E3D79D88A4A8}.Debug|x86.Build.0 = Debug|Any CPU
{0772E545-A674-4165-9469-E3D79D88A4A8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0772E545-A674-4165-9469-E3D79D88A4A8}.Release|Any CPU.Build.0 = Release|Any CPU
{0772E545-A674-4165-9469-E3D79D88A4A8}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{0772E545-A674-4165-9469-E3D79D88A4A8}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{0772E545-A674-4165-9469-E3D79D88A4A8}.Release|x86.ActiveCfg = Release|Any CPU
{0772E545-A674-4165-9469-E3D79D88A4A8}.Release|x86.Build.0 = Release|Any CPU
{92D959F2-66B8-490A-BA33-DA4421EBC948}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{92D959F2-66B8-490A-BA33-DA4421EBC948}.Debug|Any CPU.Build.0 = Debug|Any CPU
{92D959F2-66B8-490A-BA33-DA4421EBC948}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{92D959F2-66B8-490A-BA33-DA4421EBC948}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{92D959F2-66B8-490A-BA33-DA4421EBC948}.Debug|x86.ActiveCfg = Debug|Any CPU
{92D959F2-66B8-490A-BA33-DA4421EBC948}.Debug|x86.Build.0 = Debug|Any CPU
{92D959F2-66B8-490A-BA33-DA4421EBC948}.Release|Any CPU.ActiveCfg = Release|Any CPU
{92D959F2-66B8-490A-BA33-DA4421EBC948}.Release|Any CPU.Build.0 = Release|Any CPU
{92D959F2-66B8-490A-BA33-DA4421EBC948}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{92D959F2-66B8-490A-BA33-DA4421EBC948}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{92D959F2-66B8-490A-BA33-DA4421EBC948}.Release|x86.ActiveCfg = Release|Any CPU
{92D959F2-66B8-490A-BA33-DA4421EBC948}.Release|x86.Build.0 = Release|Any CPU
{1B398182-9EAE-400B-A2BD-EFFAC0168A36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1B398182-9EAE-400B-A2BD-EFFAC0168A36}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1B398182-9EAE-400B-A2BD-EFFAC0168A36}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{1B398182-9EAE-400B-A2BD-EFFAC0168A36}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{1B398182-9EAE-400B-A2BD-EFFAC0168A36}.Debug|x86.ActiveCfg = Debug|Any CPU
{1B398182-9EAE-400B-A2BD-EFFAC0168A36}.Debug|x86.Build.0 = Debug|Any CPU
{1B398182-9EAE-400B-A2BD-EFFAC0168A36}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1B398182-9EAE-400B-A2BD-EFFAC0168A36}.Release|Any CPU.Build.0 = Release|Any CPU
{1B398182-9EAE-400B-A2BD-EFFAC0168A36}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{1B398182-9EAE-400B-A2BD-EFFAC0168A36}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{1B398182-9EAE-400B-A2BD-EFFAC0168A36}.Release|x86.ActiveCfg = Release|Any CPU
{1B398182-9EAE-400B-A2BD-EFFAC0168A36}.Release|x86.Build.0 = Release|Any CPU
{71C626FC-6408-494B-A127-38CB64F71324}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{71C626FC-6408-494B-A127-38CB64F71324}.Debug|Any CPU.Build.0 = Debug|Any CPU
{71C626FC-6408-494B-A127-38CB64F71324}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{71C626FC-6408-494B-A127-38CB64F71324}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{71C626FC-6408-494B-A127-38CB64F71324}.Debug|x86.ActiveCfg = Debug|Any CPU
{71C626FC-6408-494B-A127-38CB64F71324}.Debug|x86.Build.0 = Debug|Any CPU
{71C626FC-6408-494B-A127-38CB64F71324}.Release|Any CPU.ActiveCfg = Release|Any CPU
{71C626FC-6408-494B-A127-38CB64F71324}.Release|Any CPU.Build.0 = Release|Any CPU
{71C626FC-6408-494B-A127-38CB64F71324}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{71C626FC-6408-494B-A127-38CB64F71324}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{71C626FC-6408-494B-A127-38CB64F71324}.Release|x86.ActiveCfg = Release|Any CPU
{71C626FC-6408-494B-A127-38CB64F71324}.Release|x86.Build.0 = Release|Any CPU
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Debug|x86.ActiveCfg = Debug|Any CPU
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Debug|x86.Build.0 = Debug|Any CPU
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Release|Any CPU.Build.0 = Release|Any CPU
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Release|x86.ActiveCfg = Release|Any CPU
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Release|x86.Build.0 = Release|Any CPU
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Debug|x86.ActiveCfg = Debug|Any CPU
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Debug|x86.Build.0 = Debug|Any CPU
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Release|Any CPU.Build.0 = Release|Any CPU
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Release|x86.ActiveCfg = Release|Any CPU
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Release|x86.Build.0 = Release|Any CPU
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Debug|x86.ActiveCfg = Debug|Any CPU
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Debug|x86.Build.0 = Debug|Any CPU
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Release|Any CPU.Build.0 = Release|Any CPU
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Release|x86.ActiveCfg = Release|Any CPU
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -584,10 +655,15 @@ Global
{CF322BE1-E1FE-4CFD-8FCA-16A14B905D53} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
{0AB46520-F441-4E01-B444-08F4D23F8B1B} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
{28D4DA20-6E13-47F9-80AE-D6AA7699CC35} = {44546170-35BF-448F-88F5-4331AE67AEAE}
{2E6CDE10-8F96-4B75-B0D9-808F6A01B8BD} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
{30862895-C1FA-49F5-B69A-B0F9F2ECD0F3} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
{F8FD2D6A-DCD1-4A7B-B599-B728A12A1754} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
{829D9A67-2D07-4CE6-86C0-59F2549B0CFA} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
{0772E545-A674-4165-9469-E3D79D88A4A8} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
{92D959F2-66B8-490A-BA33-DA4421EBC948} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
{1B398182-9EAE-400B-A2BD-EFFAC0168A36} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
{71C626FC-6408-494B-A127-38CB64F71324} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
{2F683CF8-B055-46AE-BF83-9D1307F8D45F} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
{34E3C302-B767-40C8-B538-3EE2BD4000C4} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D003597F-372F-4068-A2F0-353BE3C3B39A}

View File

@ -51,8 +51,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TagHelpersWebSite", "test\W
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FilesWebSite", "test\WebSites\FilesWebSite\FilesWebSite.csproj", "{0EF9860B-10D7-452F-B0F4-A405B88BEBB3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RazorPageExecutionInstrumentationWebSite", "test\WebSites\RazorPageExecutionInstrumentationWebSite\RazorPageExecutionInstrumentationWebSite.csproj", "{2B2B9876-903C-4065-8D62-2EE832BBA106}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApplicationModelWebSite", "test\WebSites\ApplicationModelWebSite\ApplicationModelWebSite.csproj", "{CAE52CB7-0FAC-4B5B-8251-B0FF837DB657}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.WebApiCompatShim", "src\Microsoft.AspNetCore.Mvc.WebApiCompatShim\Microsoft.AspNetCore.Mvc.WebApiCompatShim.csproj", "{23D30B8C-04B1-4577-A604-ED27EA1E4A0E}"
@ -75,7 +73,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControllersFromServicesWebS
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControllersFromServicesClassLibrary", "test\WebSites\ControllersFromServicesClassLibrary\ControllersFromServicesClassLibrary.csproj", "{551DC89E-2A13-4CF2-83D7-1ADD802443D5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.TestCommon", "test\Microsoft.AspNetCore.Mvc.TestCommon\Microsoft.AspNetCore.Mvc.TestCommon.csproj", "{F504357E-C2E1-4818-BA5C-9A2EAC25FEE5}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Core.TestCommon", "test\Microsoft.AspNetCore.Mvc.Core.TestCommon\Microsoft.AspNetCore.Mvc.Core.TestCommon.csproj", "{F504357E-C2E1-4818-BA5C-9A2EAC25FEE5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CorsWebSite", "test\WebSites\CorsWebSite\CorsWebSite.csproj", "{94BA134D-04B3-48AA-BA55-5A4DB8640F2D}"
EndProject
@ -162,14 +160,30 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RazorBuildWebSite.Views", "
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Analyzers", "src\Microsoft.AspNetCore.Mvc.Analyzers\Microsoft.AspNetCore.Mvc.Analyzers.csproj", "{87A3E227-C45E-4141-A59F-402908E651FD}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Analyzers.Test", "test\Microsoft.AspNetCore.Mvc.Analyzers.Test\Microsoft.AspNetCore.Mvc.Analyzers.Test.csproj", "{E3E09D2F-1FCF-4396-9B09-5A62CA8CC831}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Analyzers.Experimental", "src\Microsoft.AspNetCore.Mvc.Analyzers.Experimental\Microsoft.AspNetCore.Mvc.Analyzers.Experimental.csproj", "{CBF23034-2249-4FE5-BD48-5F3CEAC0DF61}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test", "test\Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test\Microsoft.AspNetCore.Mvc.Analyzers.Experimental.Test.csproj", "{E83D3745-9BCF-40E8-8D34-AFBA604C2439}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mvc.Analyzers.Test", "test\Mvc.Analyzers.Test\Mvc.Analyzers.Test.csproj", "{E3E09D2F-1FCF-4396-9B09-5A62CA8CC831}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RazorPagesClassLibrary", "test\WebSites\RazorPagesClassLibrary\RazorPagesClassLibrary.csproj", "{17122147-ADFD-41C8-87D9-CCC582CCA8F9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Views.TestCommon", "test\Microsoft.AspNetCore.Mvc.Views.TestCommon\Microsoft.AspNetCore.Mvc.Views.TestCommon.csproj", "{51E3E785-A9D1-4196-BAFE-A17FF4304B89}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmarkapps", "benchmarkapps", "{2859F266-673A-45A2-9E3C-7B39C6DDD38E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BasicApi", "benchmarkapps\BasicApi\BasicApi.csproj", "{910F023A-88E3-4CB4-8793-AC4005C7B421}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BasicViews", "benchmarkapps\BasicViews\BasicViews.csproj", "{E89EB74D-C1CE-456F-B42D-CCF1575E0CFB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mvc.Api.Analyzers.Test", "test\Mvc.Api.Analyzers.Test\Mvc.Api.Analyzers.Test.csproj", "{DD7B9F20-354C-4D9E-8C8A-8AE6E7595A87}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Api.Analyzers", "src\Microsoft.AspNetCore.Mvc.Api.Analyzers\Microsoft.AspNetCore.Mvc.Api.Analyzers.csproj", "{3B550487-10E4-4E6D-9CEF-B1B4CA1253DA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RazorRendering", "benchmarkapps\RazorRendering\RazorRendering.csproj", "{D7C6A696-F232-4288-BCCD-367407E4A934}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-getdocument", "src\dotnet-getdocument\dotnet-getdocument.csproj", "{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GetDocumentInsider", "src\GetDocumentInsider\GetDocumentInsider.csproj", "{2F683CF8-B055-46AE-BF83-9D1307F8D45F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.ApiDescription.Design", "src\Microsoft.Extensions.ApiDescription.Design\Microsoft.Extensions.ApiDescription.Design.csproj", "{34E3C302-B767-40C8-B538-3EE2BD4000C4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -330,16 +344,6 @@ Global
{0EF9860B-10D7-452F-B0F4-A405B88BEBB3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{0EF9860B-10D7-452F-B0F4-A405B88BEBB3}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{0EF9860B-10D7-452F-B0F4-A405B88BEBB3}.Release|x86.ActiveCfg = Release|Any CPU
{2B2B9876-903C-4065-8D62-2EE832BBA106}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2B2B9876-903C-4065-8D62-2EE832BBA106}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2B2B9876-903C-4065-8D62-2EE832BBA106}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{2B2B9876-903C-4065-8D62-2EE832BBA106}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{2B2B9876-903C-4065-8D62-2EE832BBA106}.Debug|x86.ActiveCfg = Debug|Any CPU
{2B2B9876-903C-4065-8D62-2EE832BBA106}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2B2B9876-903C-4065-8D62-2EE832BBA106}.Release|Any CPU.Build.0 = Release|Any CPU
{2B2B9876-903C-4065-8D62-2EE832BBA106}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{2B2B9876-903C-4065-8D62-2EE832BBA106}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{2B2B9876-903C-4065-8D62-2EE832BBA106}.Release|x86.ActiveCfg = Release|Any CPU
{CAE52CB7-0FAC-4B5B-8251-B0FF837DB657}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CAE52CB7-0FAC-4B5B-8251-B0FF837DB657}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CAE52CB7-0FAC-4B5B-8251-B0FF837DB657}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
@ -856,30 +860,6 @@ Global
{E3E09D2F-1FCF-4396-9B09-5A62CA8CC831}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{E3E09D2F-1FCF-4396-9B09-5A62CA8CC831}.Release|x86.ActiveCfg = Release|Any CPU
{E3E09D2F-1FCF-4396-9B09-5A62CA8CC831}.Release|x86.Build.0 = Release|Any CPU
{CBF23034-2249-4FE5-BD48-5F3CEAC0DF61}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CBF23034-2249-4FE5-BD48-5F3CEAC0DF61}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CBF23034-2249-4FE5-BD48-5F3CEAC0DF61}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{CBF23034-2249-4FE5-BD48-5F3CEAC0DF61}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{CBF23034-2249-4FE5-BD48-5F3CEAC0DF61}.Debug|x86.ActiveCfg = Debug|Any CPU
{CBF23034-2249-4FE5-BD48-5F3CEAC0DF61}.Debug|x86.Build.0 = Debug|Any CPU
{CBF23034-2249-4FE5-BD48-5F3CEAC0DF61}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CBF23034-2249-4FE5-BD48-5F3CEAC0DF61}.Release|Any CPU.Build.0 = Release|Any CPU
{CBF23034-2249-4FE5-BD48-5F3CEAC0DF61}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{CBF23034-2249-4FE5-BD48-5F3CEAC0DF61}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{CBF23034-2249-4FE5-BD48-5F3CEAC0DF61}.Release|x86.ActiveCfg = Release|Any CPU
{CBF23034-2249-4FE5-BD48-5F3CEAC0DF61}.Release|x86.Build.0 = Release|Any CPU
{E83D3745-9BCF-40E8-8D34-AFBA604C2439}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E83D3745-9BCF-40E8-8D34-AFBA604C2439}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E83D3745-9BCF-40E8-8D34-AFBA604C2439}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{E83D3745-9BCF-40E8-8D34-AFBA604C2439}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{E83D3745-9BCF-40E8-8D34-AFBA604C2439}.Debug|x86.ActiveCfg = Debug|Any CPU
{E83D3745-9BCF-40E8-8D34-AFBA604C2439}.Debug|x86.Build.0 = Debug|Any CPU
{E83D3745-9BCF-40E8-8D34-AFBA604C2439}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E83D3745-9BCF-40E8-8D34-AFBA604C2439}.Release|Any CPU.Build.0 = Release|Any CPU
{E83D3745-9BCF-40E8-8D34-AFBA604C2439}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{E83D3745-9BCF-40E8-8D34-AFBA604C2439}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{E83D3745-9BCF-40E8-8D34-AFBA604C2439}.Release|x86.ActiveCfg = Release|Any CPU
{E83D3745-9BCF-40E8-8D34-AFBA604C2439}.Release|x86.Build.0 = Release|Any CPU
{17122147-ADFD-41C8-87D9-CCC582CCA8F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{17122147-ADFD-41C8-87D9-CCC582CCA8F9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{17122147-ADFD-41C8-87D9-CCC582CCA8F9}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
@ -892,6 +872,114 @@ Global
{17122147-ADFD-41C8-87D9-CCC582CCA8F9}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{17122147-ADFD-41C8-87D9-CCC582CCA8F9}.Release|x86.ActiveCfg = Release|Any CPU
{17122147-ADFD-41C8-87D9-CCC582CCA8F9}.Release|x86.Build.0 = Release|Any CPU
{51E3E785-A9D1-4196-BAFE-A17FF4304B89}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{51E3E785-A9D1-4196-BAFE-A17FF4304B89}.Debug|Any CPU.Build.0 = Debug|Any CPU
{51E3E785-A9D1-4196-BAFE-A17FF4304B89}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{51E3E785-A9D1-4196-BAFE-A17FF4304B89}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{51E3E785-A9D1-4196-BAFE-A17FF4304B89}.Debug|x86.ActiveCfg = Debug|Any CPU
{51E3E785-A9D1-4196-BAFE-A17FF4304B89}.Debug|x86.Build.0 = Debug|Any CPU
{51E3E785-A9D1-4196-BAFE-A17FF4304B89}.Release|Any CPU.ActiveCfg = Release|Any CPU
{51E3E785-A9D1-4196-BAFE-A17FF4304B89}.Release|Any CPU.Build.0 = Release|Any CPU
{51E3E785-A9D1-4196-BAFE-A17FF4304B89}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{51E3E785-A9D1-4196-BAFE-A17FF4304B89}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{51E3E785-A9D1-4196-BAFE-A17FF4304B89}.Release|x86.ActiveCfg = Release|Any CPU
{51E3E785-A9D1-4196-BAFE-A17FF4304B89}.Release|x86.Build.0 = Release|Any CPU
{910F023A-88E3-4CB4-8793-AC4005C7B421}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{910F023A-88E3-4CB4-8793-AC4005C7B421}.Debug|Any CPU.Build.0 = Debug|Any CPU
{910F023A-88E3-4CB4-8793-AC4005C7B421}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{910F023A-88E3-4CB4-8793-AC4005C7B421}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{910F023A-88E3-4CB4-8793-AC4005C7B421}.Debug|x86.ActiveCfg = Debug|Any CPU
{910F023A-88E3-4CB4-8793-AC4005C7B421}.Debug|x86.Build.0 = Debug|Any CPU
{910F023A-88E3-4CB4-8793-AC4005C7B421}.Release|Any CPU.ActiveCfg = Release|Any CPU
{910F023A-88E3-4CB4-8793-AC4005C7B421}.Release|Any CPU.Build.0 = Release|Any CPU
{910F023A-88E3-4CB4-8793-AC4005C7B421}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{910F023A-88E3-4CB4-8793-AC4005C7B421}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{910F023A-88E3-4CB4-8793-AC4005C7B421}.Release|x86.ActiveCfg = Release|Any CPU
{910F023A-88E3-4CB4-8793-AC4005C7B421}.Release|x86.Build.0 = Release|Any CPU
{E89EB74D-C1CE-456F-B42D-CCF1575E0CFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E89EB74D-C1CE-456F-B42D-CCF1575E0CFB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E89EB74D-C1CE-456F-B42D-CCF1575E0CFB}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{E89EB74D-C1CE-456F-B42D-CCF1575E0CFB}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{E89EB74D-C1CE-456F-B42D-CCF1575E0CFB}.Debug|x86.ActiveCfg = Debug|Any CPU
{E89EB74D-C1CE-456F-B42D-CCF1575E0CFB}.Debug|x86.Build.0 = Debug|Any CPU
{E89EB74D-C1CE-456F-B42D-CCF1575E0CFB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E89EB74D-C1CE-456F-B42D-CCF1575E0CFB}.Release|Any CPU.Build.0 = Release|Any CPU
{E89EB74D-C1CE-456F-B42D-CCF1575E0CFB}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{E89EB74D-C1CE-456F-B42D-CCF1575E0CFB}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{E89EB74D-C1CE-456F-B42D-CCF1575E0CFB}.Release|x86.ActiveCfg = Release|Any CPU
{E89EB74D-C1CE-456F-B42D-CCF1575E0CFB}.Release|x86.Build.0 = Release|Any CPU
{DD7B9F20-354C-4D9E-8C8A-8AE6E7595A87}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DD7B9F20-354C-4D9E-8C8A-8AE6E7595A87}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DD7B9F20-354C-4D9E-8C8A-8AE6E7595A87}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{DD7B9F20-354C-4D9E-8C8A-8AE6E7595A87}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{DD7B9F20-354C-4D9E-8C8A-8AE6E7595A87}.Debug|x86.ActiveCfg = Debug|Any CPU
{DD7B9F20-354C-4D9E-8C8A-8AE6E7595A87}.Debug|x86.Build.0 = Debug|Any CPU
{DD7B9F20-354C-4D9E-8C8A-8AE6E7595A87}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DD7B9F20-354C-4D9E-8C8A-8AE6E7595A87}.Release|Any CPU.Build.0 = Release|Any CPU
{DD7B9F20-354C-4D9E-8C8A-8AE6E7595A87}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{DD7B9F20-354C-4D9E-8C8A-8AE6E7595A87}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{DD7B9F20-354C-4D9E-8C8A-8AE6E7595A87}.Release|x86.ActiveCfg = Release|Any CPU
{DD7B9F20-354C-4D9E-8C8A-8AE6E7595A87}.Release|x86.Build.0 = Release|Any CPU
{3B550487-10E4-4E6D-9CEF-B1B4CA1253DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3B550487-10E4-4E6D-9CEF-B1B4CA1253DA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3B550487-10E4-4E6D-9CEF-B1B4CA1253DA}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{3B550487-10E4-4E6D-9CEF-B1B4CA1253DA}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{3B550487-10E4-4E6D-9CEF-B1B4CA1253DA}.Debug|x86.ActiveCfg = Debug|Any CPU
{3B550487-10E4-4E6D-9CEF-B1B4CA1253DA}.Debug|x86.Build.0 = Debug|Any CPU
{3B550487-10E4-4E6D-9CEF-B1B4CA1253DA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3B550487-10E4-4E6D-9CEF-B1B4CA1253DA}.Release|Any CPU.Build.0 = Release|Any CPU
{3B550487-10E4-4E6D-9CEF-B1B4CA1253DA}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{3B550487-10E4-4E6D-9CEF-B1B4CA1253DA}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{3B550487-10E4-4E6D-9CEF-B1B4CA1253DA}.Release|x86.ActiveCfg = Release|Any CPU
{3B550487-10E4-4E6D-9CEF-B1B4CA1253DA}.Release|x86.Build.0 = Release|Any CPU
{D7C6A696-F232-4288-BCCD-367407E4A934}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D7C6A696-F232-4288-BCCD-367407E4A934}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D7C6A696-F232-4288-BCCD-367407E4A934}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{D7C6A696-F232-4288-BCCD-367407E4A934}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{D7C6A696-F232-4288-BCCD-367407E4A934}.Debug|x86.ActiveCfg = Debug|Any CPU
{D7C6A696-F232-4288-BCCD-367407E4A934}.Debug|x86.Build.0 = Debug|Any CPU
{D7C6A696-F232-4288-BCCD-367407E4A934}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D7C6A696-F232-4288-BCCD-367407E4A934}.Release|Any CPU.Build.0 = Release|Any CPU
{D7C6A696-F232-4288-BCCD-367407E4A934}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{D7C6A696-F232-4288-BCCD-367407E4A934}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{D7C6A696-F232-4288-BCCD-367407E4A934}.Release|x86.ActiveCfg = Release|Any CPU
{D7C6A696-F232-4288-BCCD-367407E4A934}.Release|x86.Build.0 = Release|Any CPU
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Debug|x86.ActiveCfg = Debug|Any CPU
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Debug|x86.Build.0 = Debug|Any CPU
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Release|Any CPU.Build.0 = Release|Any CPU
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Release|x86.ActiveCfg = Release|Any CPU
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Release|x86.Build.0 = Release|Any CPU
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Debug|x86.ActiveCfg = Debug|Any CPU
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Debug|x86.Build.0 = Debug|Any CPU
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Release|Any CPU.Build.0 = Release|Any CPU
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Release|x86.ActiveCfg = Release|Any CPU
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Release|x86.Build.0 = Release|Any CPU
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Debug|x86.ActiveCfg = Debug|Any CPU
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Debug|x86.Build.0 = Debug|Any CPU
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Release|Any CPU.Build.0 = Release|Any CPU
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Release|x86.ActiveCfg = Release|Any CPU
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -913,7 +1001,6 @@ Global
{C6304029-78C8-4604-99BE-2078DCA1DD36} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{6DB9B8D0-80F7-4E70-BBB0-0B4C04D79A47} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{0EF9860B-10D7-452F-B0F4-A405B88BEBB3} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{2B2B9876-903C-4065-8D62-2EE832BBA106} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{CAE52CB7-0FAC-4B5B-8251-B0FF837DB657} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{23D30B8C-04B1-4577-A604-ED27EA1E4A0E} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
{B2B7BC91-688E-4C1E-A71F-CE948D958DDF} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
@ -958,9 +1045,16 @@ Global
{8916DDCA-EC2A-4193-B9F3-78CAA1A96D5A} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{87A3E227-C45E-4141-A59F-402908E651FD} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
{E3E09D2F-1FCF-4396-9B09-5A62CA8CC831} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
{CBF23034-2249-4FE5-BD48-5F3CEAC0DF61} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
{E83D3745-9BCF-40E8-8D34-AFBA604C2439} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
{17122147-ADFD-41C8-87D9-CCC582CCA8F9} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{51E3E785-A9D1-4196-BAFE-A17FF4304B89} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
{910F023A-88E3-4CB4-8793-AC4005C7B421} = {2859F266-673A-45A2-9E3C-7B39C6DDD38E}
{E89EB74D-C1CE-456F-B42D-CCF1575E0CFB} = {2859F266-673A-45A2-9E3C-7B39C6DDD38E}
{DD7B9F20-354C-4D9E-8C8A-8AE6E7595A87} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
{3B550487-10E4-4E6D-9CEF-B1B4CA1253DA} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
{D7C6A696-F232-4288-BCCD-367407E4A934} = {2859F266-673A-45A2-9E3C-7B39C6DDD38E}
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
{2F683CF8-B055-46AE-BF83-9D1307F8D45F} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
{34E3C302-B767-40C8-B538-3EE2BD4000C4} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {63D344F6-F86D-40E6-85B9-0AABBE338C4A}

View File

@ -1,7 +1,31 @@
{
"Default": {
"rules": [
"DefaultCompositeRule"
]
"Default": {
"rules": [
"DefaultCompositeRule"
],
"packages": {
"Microsoft.Extensions.ApiDescription.Design": {
"Exclusions": {
"BUILD_ITEMS_FRAMEWORK": {
"*": "Package includes tool with different target frameworks."
},
"SERVICING_ATTRIBUTE": {
"tools/Newtonsoft.Json.dll": "External assembly, not built as part of this process"
},
"WRONG_PUBLICKEYTOKEN": {
"tools/Newtonsoft.Json.dll": "External assembly, not built as part of this process"
},
"ASSEMBLY_INFORMATIONAL_VERSION_MISMATCH": {
"tools/Newtonsoft.Json.dll": "External assembly, not built as part of this process"
},
"ASSEMBLY_FILE_VERSION_MISMATCH": {
"tools/Newtonsoft.Json.dll": "External assembly, not built as part of this process"
},
"ASSEMBLY_VERSION_MISMATCH": {
"tools/Newtonsoft.Json.dll": "External assembly, not built as part of this process"
}
}
}
}
}
}
}

View File

@ -3,9 +3,7 @@ ASP.NET Core MVC
**Note: For ASP.NET MVC 5.x, Web API 2.x, and Web Pages 3.x (not ASP.NET Core), see https://github.com/aspnet/AspNetWebStack**
AppVeyor: [![AppVeyor](https://ci.appveyor.com/api/projects/status/969jbosi0qwc1awg/branch/dev?svg=true)](https://ci.appveyor.com/project/aspnetci/mvc/branch/dev)
Travis: [![Travis](https://travis-ci.org/aspnet/Mvc.svg?branch=dev)](https://travis-ci.org/aspnet/Mvc)
Travis: [![Travis](https://travis-ci.org/aspnet/Mvc.svg?branch=release/2.2)](https://travis-ci.org/aspnet/Mvc)
ASP.NET Core MVC gives you a powerful, patterns-based way to build dynamic websites that enables a clean separation of concerns and gives you full control over markup for enjoyable, agile development. ASP.NET Core MVC includes many features that enable fast, TDD-friendly development for creating sophisticated applications that use the latest web standards.

View File

@ -0,0 +1,43 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFrameworks>netcoreapp2.2</TargetFrameworks>
<TargetFrameworks Condition=" '$(DeveloperBuild)' != 'true' AND '$(OS)' == 'Windows_NT' ">$(TargetFrameworks);net461</TargetFrameworks>
<TargetFrameworks Condition="'$(BenchmarksTargetFramework)' != ''">$(BenchmarksTargetFramework)</TargetFrameworks>
<DefineConstants Condition=" '$(GenerateSqlScripts)'=='true' ">$(DefineConstants);GENERATE_SQL_SCRIPTS</DefineConstants>
<DefineConstants>$(DefineConstants);__RemoveThisBitTo__GENERATE_SQL_SCRIPTS</DefineConstants>
<WarningsNotAsErrors>CS8002;$(WarningsNotAsErrors)</WarningsNotAsErrors>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="$(BenchmarksOnlyNpgsqlEntityFrameworkCorePostgreSQLPackageVersion)" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' != 'net461'">
<PackageReference Include="MySqlConnector" Version="$(BenchmarksOnlyMySqlConnectorPackageVersion)" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="$(BenchmarksOnlyPomeloEntityFrameworkCoreMySqlPackageVersion)" />
</ItemGroup>
<!-- These references are used when running locally -->
<ItemGroup Condition="'$(BenchmarksTargetFramework)' == ''">
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="$(MicrosoftAspNetCoreAuthenticationJwtBearerPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="$(MicrosoftAspNetCoreServerKestrelPackageVersion)" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="$(BenchmarksOnlyMicrosoftEntityFrameworkCoreDesignPackageVersion)" PrivateAssets="All" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="$(BenchmarksOnlyMicrosoftEntityFrameworkCoreSqlitePackageVersion)" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="$(BenchmarksOnlyMicrosoftEntityFrameworkCoreSqlServerPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="$(MicrosoftExtensionsConfigurationCommandLinePackageVersion)" />
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Mvc.Core\Microsoft.AspNetCore.Mvc.Core.csproj" />
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Mvc.DataAnnotations\Microsoft.AspNetCore.Mvc.DataAnnotations.csproj" />
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Mvc.Formatters.Json\Microsoft.AspNetCore.Mvc.Formatters.Json.csproj" />
</ItemGroup>
<!--
These references are used when running on the Benchmarks Server.
Use All meta-package and not App to include Microsoft.EntityFrameworkCore.Sqlite.
-->
<ItemGroup Condition="'$(BenchmarksTargetFramework)' != ''">
<PackageReference Include="Microsoft.AspNetCore.All" Version="$(MicrosoftAspNetCoreAllPackageVersion)" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,163 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Linq;
using System.Threading.Tasks;
using BasicApi.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace BasicApi.Controllers
{
[ApiController]
[Authorize("pet-store-reader")]
[Route("/pet")]
public class PetController : ControllerBase
{
public PetController(BasicApiContext dbContext)
{
DbContext = dbContext;
}
public BasicApiContext DbContext { get; }
[HttpGet("{id}", Name = "FindPetById")]
[ProducesResponseType(typeof(Pet), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<Pet>> FindById(int id)
{
var pet = await DbContext.Pets
.Include(p => p.Category)
.Include(p => p.Images)
.Include(p => p.Tags)
.FirstOrDefaultAsync(p => p.Id == id);
if (pet == null)
{
return new NotFoundResult();
}
return pet;
}
[AllowAnonymous]
[HttpGet("anonymous/{id}")]
[ProducesResponseType(typeof(Pet), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<Pet>> FindByIdWithoutToken(int id)
{
var pet = await DbContext.Pets
.Include(p => p.Category)
.Include(p => p.Images)
.Include(p => p.Tags)
.FirstOrDefaultAsync(p => p.Id == id);
if (pet == null)
{
return new NotFoundResult();
}
return pet;
}
[HttpGet("findByCategory/{categoryId}")]
[ProducesResponseType(typeof(Pet), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<Pet>> FindByCategory(int categoryId)
{
var pet = await DbContext.Pets
.Include(p => p.Category)
.Include(p => p.Images)
.Include(p => p.Tags)
.FirstOrDefaultAsync(p => p.Category != null && p.Category.Id == categoryId);
if (pet == null)
{
return new NotFoundResult();
}
return pet;
}
[HttpGet("findByStatus")]
[ProducesResponseType(typeof(Pet), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<Pet>> FindByStatus(string status)
{
var pet = await DbContext.Pets
.Include(p => p.Category)
.Include(p => p.Images)
.Include(p => p.Tags)
.FirstOrDefaultAsync(p => p.Status == status);
if (pet == null)
{
return new NotFoundResult();
}
return pet;
}
[HttpGet("findByTags")]
[ProducesResponseType(typeof(Pet), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<Pet>> FindByTags(string[] tags)
{
var pet = await DbContext.Pets
.Include(p => p.Category)
.Include(p => p.Images)
.Include(p => p.Tags)
.FirstOrDefaultAsync(p => p.Tags.Any(t => tags.Contains(t.Name)));
if (pet == null)
{
return new NotFoundResult();
}
return pet;
}
[Authorize("pet-store-writer")]
[HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
public async Task<IActionResult> AddPet([FromBody] Pet pet)
{
DbContext.Pets.Add(pet);
await DbContext.SaveChangesAsync();
return new CreatedAtRouteResult("FindPetById", new { id = pet.Id }, pet);
}
[Authorize("pet-store-writer")]
[HttpPost("add-pet")]
public ActionResult<Pet> AddPetWithoutDb(Pet pet)
{
return pet;
}
[Authorize("pet-store-writer")]
[HttpPut]
public IActionResult EditPet(Pet pet)
{
throw new NotImplementedException();
}
[Authorize("pet-store-writer")]
[HttpPost("{id}/uploadImage")]
public IActionResult UploadImage(int id, IFormFile file)
{
throw new NotImplementedException();
}
[Authorize("pet-store-writer")]
[HttpDelete("{id}")]
public IActionResult DeletePet(int id)
{
throw new NotImplementedException();
}
}
}

View File

@ -0,0 +1,77 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
namespace BasicApi.Controllers
{
public class TokenController : ControllerBase
{
private static readonly Dictionary<string, ClaimsIdentity> _identities;
static TokenController()
{
_identities = new Dictionary<string, ClaimsIdentity>(StringComparer.Ordinal);
var reader = new ClaimsIdentity();
reader.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, "reader@example.com"));
reader.AddClaim(new Claim("scope", "pet-store-reader"));
_identities.Add("reader@example.com", reader);
var writer = new ClaimsIdentity();
writer.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, "writer@example.com"));
writer.AddClaim(new Claim("scope", "pet-store-reader"));
writer.AddClaim(new Claim("scope", "pet-store-writer"));
_identities.Add("writer@example.com", writer);
}
private readonly SigningCredentials _credentials;
private readonly JwtBearerOptions _options;
public TokenController(
IOptionsSnapshot<JwtBearerOptions> options,
SigningCredentials credentials)
{
_options = options.Get(JwtBearerDefaults.AuthenticationScheme);
_credentials = credentials;
}
[HttpGet("/token")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
public IActionResult GetToken(string username)
{
if (username == null || !_identities.TryGetValue(username, out var identity))
{
return new StatusCodeResult(StatusCodes.Status403Forbidden);
}
var handler = _options.SecurityTokenValidators.OfType<JwtSecurityTokenHandler>().First();
var tokenDescriptor = new SecurityTokenDescriptor()
{
Issuer = _options.TokenValidationParameters.ValidIssuer,
Audience = _options.TokenValidationParameters.ValidAudience,
SigningCredentials = _credentials,
Subject = identity
};
var securityToken = handler.CreateJwtSecurityToken(
issuer: _options.TokenValidationParameters.ValidIssuer,
audience: _options.TokenValidationParameters.ValidAudience,
signingCredentials: _credentials,
subject: identity);
var token = handler.WriteToken(securityToken);
return Content(token);
}
}
}

View File

@ -0,0 +1,172 @@
// <auto-generated />
using BasicApi.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace BasicApi.Migrations
{
[DbContext(typeof(BasicApiContext))]
[Migration("20180609000420_InitialCreate")]
partial class InitialCreate
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn)
.HasAnnotation("ProductVersion", "2.1.0-rtm-30799")
.HasAnnotation("Relational:MaxIdentifierLength", 63)
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("BasicApi.Models.Category", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<string>("Name");
b.HasKey("Id");
b.ToTable("Categories");
b.HasData(
new { Id = -1, Name = "Dogs" },
new { Id = -2, Name = "Cats" },
new { Id = -3, Name = "Rabbits" },
new { Id = -4, Name = "Lions" }
);
});
modelBuilder.Entity("BasicApi.Models.Image", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int?>("PetId");
b.Property<string>("Url");
b.HasKey("Id");
b.HasIndex("PetId");
b.ToTable("Images");
b.HasData(
new { Id = -1, PetId = -1, Url = "http://example.com/pets/-1_1.png" },
new { Id = -2, PetId = -2, Url = "http://example.com/pets/-2_1.png" },
new { Id = -3, PetId = -3, Url = "http://example.com/pets/-3_1.png" },
new { Id = -4, PetId = -4, Url = "http://example.com/pets/-4_1.png" },
new { Id = -5, PetId = -5, Url = "http://example.com/pets/-5_1.png" },
new { Id = -6, PetId = -6, Url = "http://example.com/pets/-6_1.png" },
new { Id = -7, PetId = -7, Url = "http://example.com/pets/-7_1.png" },
new { Id = -8, PetId = -8, Url = "http://example.com/pets/-8_1.png" },
new { Id = -9, PetId = -9, Url = "http://example.com/pets/-9_1.png" },
new { Id = -10, PetId = -10, Url = "http://example.com/pets/-10_1.png" },
new { Id = -11, PetId = -11, Url = "http://example.com/pets/-11_1.png" },
new { Id = -12, PetId = -12, Url = "http://example.com/pets/-12_1.png" }
);
});
modelBuilder.Entity("BasicApi.Models.Pet", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("Age");
b.Property<int?>("CategoryId");
b.Property<bool>("HasVaccinations");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(50);
b.Property<string>("Status")
.IsRequired();
b.HasKey("Id");
b.HasIndex("CategoryId");
b.ToTable("Pets");
b.HasData(
new { Id = -1, Age = 1, CategoryId = -1, HasVaccinations = true, Name = "Dogs1", Status = "available" },
new { Id = -2, Age = 1, CategoryId = -1, HasVaccinations = true, Name = "Dogs2", Status = "available" },
new { Id = -3, Age = 1, CategoryId = -1, HasVaccinations = true, Name = "Dogs3", Status = "available" },
new { Id = -4, Age = 1, CategoryId = -2, HasVaccinations = true, Name = "Cats1", Status = "available" },
new { Id = -5, Age = 1, CategoryId = -2, HasVaccinations = true, Name = "Cats2", Status = "available" },
new { Id = -6, Age = 1, CategoryId = -2, HasVaccinations = true, Name = "Cats3", Status = "available" },
new { Id = -7, Age = 1, CategoryId = -3, HasVaccinations = true, Name = "Rabbits1", Status = "available" },
new { Id = -8, Age = 1, CategoryId = -3, HasVaccinations = true, Name = "Rabbits2", Status = "available" },
new { Id = -9, Age = 1, CategoryId = -3, HasVaccinations = true, Name = "Rabbits3", Status = "available" },
new { Id = -10, Age = 1, CategoryId = -4, HasVaccinations = true, Name = "Lions1", Status = "available" },
new { Id = -11, Age = 1, CategoryId = -4, HasVaccinations = true, Name = "Lions2", Status = "available" },
new { Id = -12, Age = 1, CategoryId = -4, HasVaccinations = true, Name = "Lions3", Status = "available" }
);
});
modelBuilder.Entity("BasicApi.Models.Tag", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<string>("Name");
b.Property<int?>("PetId");
b.HasKey("Id");
b.HasIndex("PetId");
b.ToTable("Tags");
b.HasData(
new { Id = -1, Name = "Tag1", PetId = -1 },
new { Id = -2, Name = "Tag1", PetId = -2 },
new { Id = -3, Name = "Tag1", PetId = -3 },
new { Id = -4, Name = "Tag1", PetId = -4 },
new { Id = -5, Name = "Tag1", PetId = -5 },
new { Id = -6, Name = "Tag1", PetId = -6 },
new { Id = -7, Name = "Tag1", PetId = -7 },
new { Id = -8, Name = "Tag1", PetId = -8 },
new { Id = -9, Name = "Tag1", PetId = -9 },
new { Id = -10, Name = "Tag1", PetId = -10 },
new { Id = -11, Name = "Tag1", PetId = -11 },
new { Id = -12, Name = "Tag1", PetId = -12 }
);
});
modelBuilder.Entity("BasicApi.Models.Image", b =>
{
b.HasOne("BasicApi.Models.Pet")
.WithMany("Images")
.HasForeignKey("PetId");
});
modelBuilder.Entity("BasicApi.Models.Pet", b =>
{
b.HasOne("BasicApi.Models.Category", "Category")
.WithMany()
.HasForeignKey("CategoryId");
});
modelBuilder.Entity("BasicApi.Models.Tag", b =>
{
b.HasOne("BasicApi.Models.Pet")
.WithMany("Tags")
.HasForeignKey("PetId");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,218 @@
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace BasicApi.Migrations
{
public partial class InitialCreate : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Categories",
columns: table => new
{
Id = table.Column<int>(nullable: false)
#if !NET461
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn)
#endif
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn)
.Annotation("Sqlite:Autoincrement", true)
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
Name = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Categories", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Pets",
columns: table => new
{
Id = table.Column<int>(nullable: false)
#if !NET461
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn)
#endif
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn)
.Annotation("Sqlite:Autoincrement", true)
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
Age = table.Column<int>(nullable: false),
CategoryId = table.Column<int>(nullable: true),
HasVaccinations = table.Column<bool>(nullable: false),
Name = table.Column<string>(maxLength: 50, nullable: false),
Status = table.Column<string>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Pets", x => x.Id);
table.ForeignKey(
name: "FK_Pets_Categories_CategoryId",
column: x => x.CategoryId,
principalTable: "Categories",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "Images",
columns: table => new
{
Id = table.Column<int>(nullable: false)
#if !NET461
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn)
#endif
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn)
.Annotation("Sqlite:Autoincrement", true)
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
Url = table.Column<string>(nullable: true),
PetId = table.Column<int>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Images", x => x.Id);
table.ForeignKey(
name: "FK_Images_Pets_PetId",
column: x => x.PetId,
principalTable: "Pets",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "Tags",
columns: table => new
{
Id = table.Column<int>(nullable: false)
#if !NET461
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn)
#endif
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn)
.Annotation("Sqlite:Autoincrement", true)
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
Name = table.Column<string>(nullable: true),
PetId = table.Column<int>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Tags", x => x.Id);
table.ForeignKey(
name: "FK_Tags_Pets_PetId",
column: x => x.PetId,
principalTable: "Pets",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.InsertData(
table: "Categories",
columns: new[] { "Id", "Name" },
values: new object[,]
{
{ -1, "Dogs" },
{ -2, "Cats" },
{ -3, "Rabbits" },
{ -4, "Lions" }
});
migrationBuilder.InsertData(
table: "Pets",
columns: new[] { "Id", "Age", "CategoryId", "HasVaccinations", "Name", "Status" },
values: new object[,]
{
{ -1, 1, -1, true, "Dogs1", "available" },
{ -2, 1, -1, true, "Dogs2", "available" },
{ -3, 1, -1, true, "Dogs3", "available" },
{ -4, 1, -2, true, "Cats1", "available" },
{ -5, 1, -2, true, "Cats2", "available" },
{ -6, 1, -2, true, "Cats3", "available" },
{ -7, 1, -3, true, "Rabbits1", "available" },
{ -8, 1, -3, true, "Rabbits2", "available" },
{ -9, 1, -3, true, "Rabbits3", "available" },
{ -10, 1, -4, true, "Lions1", "available" },
{ -11, 1, -4, true, "Lions2", "available" },
{ -12, 1, -4, true, "Lions3", "available" }
});
migrationBuilder.InsertData(
table: "Images",
columns: new[] { "Id", "PetId", "Url" },
values: new object[,]
{
{ -1, -1, "http://example.com/pets/-1_1.png" },
{ -2, -2, "http://example.com/pets/-2_1.png" },
{ -11, -11, "http://example.com/pets/-11_1.png" },
{ -3, -3, "http://example.com/pets/-3_1.png" },
{ -4, -4, "http://example.com/pets/-4_1.png" },
{ -10, -10, "http://example.com/pets/-10_1.png" },
{ -5, -5, "http://example.com/pets/-5_1.png" },
{ -6, -6, "http://example.com/pets/-6_1.png" },
{ -12, -12, "http://example.com/pets/-12_1.png" },
{ -7, -7, "http://example.com/pets/-7_1.png" },
{ -9, -9, "http://example.com/pets/-9_1.png" },
{ -8, -8, "http://example.com/pets/-8_1.png" }
});
migrationBuilder.InsertData(
table: "Tags",
columns: new[] { "Id", "Name", "PetId" },
values: new object[,]
{
{ -11, "Tag1", -11 },
{ -10, "Tag1", -10 },
{ -9, "Tag1", -9 },
{ -6, "Tag1", -6 },
{ -7, "Tag1", -7 },
{ -5, "Tag1", -5 },
{ -4, "Tag1", -4 },
{ -3, "Tag1", -3 },
{ -2, "Tag1", -2 },
{ -1, "Tag1", -1 },
{ -8, "Tag1", -8 },
{ -12, "Tag1", -12 }
});
migrationBuilder.CreateIndex(
name: "IX_Images_PetId",
table: "Images",
column: "PetId");
migrationBuilder.CreateIndex(
name: "IX_Pets_CategoryId",
table: "Pets",
column: "CategoryId");
migrationBuilder.CreateIndex(
name: "IX_Tags_PetId",
table: "Tags",
column: "PetId");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Images");
migrationBuilder.DropTable(
name: "Tags");
migrationBuilder.DropTable(
name: "Pets");
migrationBuilder.DropTable(
name: "Categories");
}
}
}

View File

@ -0,0 +1,170 @@
// <auto-generated />
using BasicApi.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace BasicApi.Migrations
{
[DbContext(typeof(BasicApiContext))]
partial class BasicApiContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn)
.HasAnnotation("ProductVersion", "2.1.0-rtm-30799")
.HasAnnotation("Relational:MaxIdentifierLength", 63)
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("BasicApi.Models.Category", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<string>("Name");
b.HasKey("Id");
b.ToTable("Categories");
b.HasData(
new { Id = -1, Name = "Dogs" },
new { Id = -2, Name = "Cats" },
new { Id = -3, Name = "Rabbits" },
new { Id = -4, Name = "Lions" }
);
});
modelBuilder.Entity("BasicApi.Models.Image", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int?>("PetId");
b.Property<string>("Url");
b.HasKey("Id");
b.HasIndex("PetId");
b.ToTable("Images");
b.HasData(
new { Id = -1, PetId = -1, Url = "http://example.com/pets/-1_1.png" },
new { Id = -2, PetId = -2, Url = "http://example.com/pets/-2_1.png" },
new { Id = -3, PetId = -3, Url = "http://example.com/pets/-3_1.png" },
new { Id = -4, PetId = -4, Url = "http://example.com/pets/-4_1.png" },
new { Id = -5, PetId = -5, Url = "http://example.com/pets/-5_1.png" },
new { Id = -6, PetId = -6, Url = "http://example.com/pets/-6_1.png" },
new { Id = -7, PetId = -7, Url = "http://example.com/pets/-7_1.png" },
new { Id = -8, PetId = -8, Url = "http://example.com/pets/-8_1.png" },
new { Id = -9, PetId = -9, Url = "http://example.com/pets/-9_1.png" },
new { Id = -10, PetId = -10, Url = "http://example.com/pets/-10_1.png" },
new { Id = -11, PetId = -11, Url = "http://example.com/pets/-11_1.png" },
new { Id = -12, PetId = -12, Url = "http://example.com/pets/-12_1.png" }
);
});
modelBuilder.Entity("BasicApi.Models.Pet", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("Age");
b.Property<int?>("CategoryId");
b.Property<bool>("HasVaccinations");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(50);
b.Property<string>("Status")
.IsRequired();
b.HasKey("Id");
b.HasIndex("CategoryId");
b.ToTable("Pets");
b.HasData(
new { Id = -1, Age = 1, CategoryId = -1, HasVaccinations = true, Name = "Dogs1", Status = "available" },
new { Id = -2, Age = 1, CategoryId = -1, HasVaccinations = true, Name = "Dogs2", Status = "available" },
new { Id = -3, Age = 1, CategoryId = -1, HasVaccinations = true, Name = "Dogs3", Status = "available" },
new { Id = -4, Age = 1, CategoryId = -2, HasVaccinations = true, Name = "Cats1", Status = "available" },
new { Id = -5, Age = 1, CategoryId = -2, HasVaccinations = true, Name = "Cats2", Status = "available" },
new { Id = -6, Age = 1, CategoryId = -2, HasVaccinations = true, Name = "Cats3", Status = "available" },
new { Id = -7, Age = 1, CategoryId = -3, HasVaccinations = true, Name = "Rabbits1", Status = "available" },
new { Id = -8, Age = 1, CategoryId = -3, HasVaccinations = true, Name = "Rabbits2", Status = "available" },
new { Id = -9, Age = 1, CategoryId = -3, HasVaccinations = true, Name = "Rabbits3", Status = "available" },
new { Id = -10, Age = 1, CategoryId = -4, HasVaccinations = true, Name = "Lions1", Status = "available" },
new { Id = -11, Age = 1, CategoryId = -4, HasVaccinations = true, Name = "Lions2", Status = "available" },
new { Id = -12, Age = 1, CategoryId = -4, HasVaccinations = true, Name = "Lions3", Status = "available" }
);
});
modelBuilder.Entity("BasicApi.Models.Tag", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<string>("Name");
b.Property<int?>("PetId");
b.HasKey("Id");
b.HasIndex("PetId");
b.ToTable("Tags");
b.HasData(
new { Id = -1, Name = "Tag1", PetId = -1 },
new { Id = -2, Name = "Tag1", PetId = -2 },
new { Id = -3, Name = "Tag1", PetId = -3 },
new { Id = -4, Name = "Tag1", PetId = -4 },
new { Id = -5, Name = "Tag1", PetId = -5 },
new { Id = -6, Name = "Tag1", PetId = -6 },
new { Id = -7, Name = "Tag1", PetId = -7 },
new { Id = -8, Name = "Tag1", PetId = -8 },
new { Id = -9, Name = "Tag1", PetId = -9 },
new { Id = -10, Name = "Tag1", PetId = -10 },
new { Id = -11, Name = "Tag1", PetId = -11 },
new { Id = -12, Name = "Tag1", PetId = -12 }
);
});
modelBuilder.Entity("BasicApi.Models.Image", b =>
{
b.HasOne("BasicApi.Models.Pet")
.WithMany("Images")
.HasForeignKey("PetId");
});
modelBuilder.Entity("BasicApi.Models.Pet", b =>
{
b.HasOne("BasicApi.Models.Category", "Category")
.WithMany()
.HasForeignKey("CategoryId");
});
modelBuilder.Entity("BasicApi.Models.Tag", b =>
{
b.HasOne("BasicApi.Models.Pet")
.WithMany("Tags")
.HasForeignKey("PetId");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,190 @@
// 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.EntityFrameworkCore;
namespace BasicApi.Models
{
public class BasicApiContext : DbContext
{
public BasicApiContext(DbContextOptions options)
: base(options)
{
}
public DbSet<Category> Categories { get; set; }
public DbSet<Image> Images { get; set; }
public DbSet<Pet> Pets { get; set; }
public DbSet<Tag> Tags { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
var id = -1;
var categories = new[]
{
new Category { Id = id--, Name = "Dogs" },
new Category { Id = id--, Name = "Cats" },
new Category { Id = id--, Name = "Rabbits" },
new Category { Id = id, Name = "Lions" },
};
id = -1;
var categoryId = -1;
var pets = new[]
{
new
{
Age = 1,
CategoryId = categoryId,
HasVaccinations = true,
Id = id--,
Name = "Dogs1",
Status = "available",
},
new
{
Age = 1,
CategoryId = categoryId,
HasVaccinations = true,
Id = id--,
Name = "Dogs2",
Status = "available",
},
new
{
Age = 1,
CategoryId = categoryId--,
HasVaccinations = true,
Id = id--,
Name = "Dogs3",
Status = "available",
},
new
{
Age = 1,
CategoryId = categoryId,
HasVaccinations = true,
Id = id--,
Name = "Cats1",
Status = "available",
},
new
{
Age = 1,
CategoryId = categoryId,
HasVaccinations = true,
Id = id--,
Name = "Cats2",
Status = "available",
},
new
{
Age = 1,
CategoryId = categoryId--,
HasVaccinations = true,
Id = id--,
Name = "Cats3",
Status = "available",
},
new
{
Age = 1,
CategoryId = categoryId,
HasVaccinations = true,
Id = id--,
Name = "Rabbits1",
Status = "available",
},
new
{
Age = 1,
CategoryId = categoryId,
HasVaccinations = true,
Id = id--,
Name = "Rabbits2",
Status = "available",
},
new
{
Age = 1,
CategoryId = categoryId--,
HasVaccinations = true,
Id = id--,
Name = "Rabbits3",
Status = "available",
},
new
{
Age = 1,
CategoryId = categoryId,
HasVaccinations = true,
Id = id--,
Name = "Lions1",
Status = "available",
},
new
{
Age = 1,
CategoryId = categoryId,
HasVaccinations = true,
Id = id--,
Name = "Lions2",
Status = "available",
},
new
{
Age = 1,
CategoryId = categoryId,
HasVaccinations = true,
Id = id,
Name = "Lions3",
Status = "available",
},
};
id = -1;
var images = new[]
{
new { Id = id, PetId = id, Url = $"http://example.com/pets/{id--}_1.png" },
new { Id = id, PetId = id, Url = $"http://example.com/pets/{id--}_1.png" },
new { Id = id, PetId = id, Url = $"http://example.com/pets/{id--}_1.png" },
new { Id = id, PetId = id, Url = $"http://example.com/pets/{id--}_1.png" },
new { Id = id, PetId = id, Url = $"http://example.com/pets/{id--}_1.png" },
new { Id = id, PetId = id, Url = $"http://example.com/pets/{id--}_1.png" },
new { Id = id, PetId = id, Url = $"http://example.com/pets/{id--}_1.png" },
new { Id = id, PetId = id, Url = $"http://example.com/pets/{id--}_1.png" },
new { Id = id, PetId = id, Url = $"http://example.com/pets/{id--}_1.png" },
new { Id = id, PetId = id, Url = $"http://example.com/pets/{id--}_1.png" },
new { Id = id, PetId = id, Url = $"http://example.com/pets/{id--}_1.png" },
new { Id = id, PetId = id, Url = $"http://example.com/pets/{id}_1.png" },
};
id = -1;
var tags = new[]
{
new { Id = id, PetId = id--, Name = "Tag1" },
new { Id = id, PetId = id--, Name = "Tag1" },
new { Id = id, PetId = id--, Name = "Tag1" },
new { Id = id, PetId = id--, Name = "Tag1" },
new { Id = id, PetId = id--, Name = "Tag1" },
new { Id = id, PetId = id--, Name = "Tag1" },
new { Id = id, PetId = id--, Name = "Tag1" },
new { Id = id, PetId = id--, Name = "Tag1" },
new { Id = id, PetId = id--, Name = "Tag1" },
new { Id = id, PetId = id--, Name = "Tag1" },
new { Id = id, PetId = id--, Name = "Tag1" },
new { Id = id, PetId = id, Name = "Tag1" },
};
modelBuilder.Entity<Category>().HasData(categories);
modelBuilder.Entity<Pet>().HasData(pets);
modelBuilder.Entity<Image>().HasData(images);
modelBuilder.Entity<Tag>().HasData(tags);
}
}
}

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.
namespace BasicApi.Models
{
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
}
}

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.
namespace BasicApi.Models
{
public class Image
{
public int Id { get; set; }
public string Url { get; set; }
}
}

View File

@ -0,0 +1,31 @@
// 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.ComponentModel.DataAnnotations;
namespace BasicApi.Models
{
public class Pet
{
public int Id { get; set; }
[Range(0, 150)]
public int Age { get; set; }
public Category Category { get; set; }
public bool HasVaccinations { get; set; }
[Required]
[StringLength(50, MinimumLength = 2)]
public string Name { get; set; }
public List<Image> Images { get; set; }
public List<Tag> Tags { get; set; }
[Required]
public string Status { get; set; }
}
}

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.
namespace BasicApi.Models
{
public class Tag
{
public int Id { get; set; }
public string Name { get; set; }
}
}

View File

@ -0,0 +1,246 @@
// 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;
#if GENERATE_SQL_SCRIPTS
using System.Linq;
#endif
using System.Security.Cryptography;
using BasicApi.Models;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json.Serialization;
using Npgsql;
namespace BasicApi
{
public class Startup
{
private bool _isSQLite;
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
var rsa = new RSACryptoServiceProvider(2048);
var key = new RsaSecurityKey(rsa.ExportParameters(true));
services.AddSingleton(new SigningCredentials(
key,
SecurityAlgorithms.RsaSha256Signature));
services.AddAuthentication().AddJwtBearer(options =>
{
options.TokenValidationParameters.IssuerSigningKey = key;
options.TokenValidationParameters.ValidAudience = "Myself";
options.TokenValidationParameters.ValidIssuer = "BasicApi";
});
var connectionString = Configuration["ConnectionString"];
var databaseType = Configuration["Database"];
if (string.IsNullOrEmpty(databaseType))
{
// Use SQLite when running outside a benchmark test or if benchmarks user specified "None".
// ("None" is not passed to the web application.)
databaseType = "SQLite";
}
else if (string.IsNullOrEmpty(connectionString))
{
throw new ArgumentException("Connection string must be specified for {databaseType}.");
}
switch (databaseType.ToUpper())
{
#if !NET461
case "MYSQL":
services
.AddEntityFrameworkMySql()
.AddDbContextPool<BasicApiContext>(options => options.UseMySql(connectionString));
break;
#endif
case "POSTGRESQL":
var settings = new NpgsqlConnectionStringBuilder(connectionString);
if (!settings.NoResetOnClose)
{
throw new ArgumentException("No Reset On Close=true must be specified for Npgsql.");
}
if (settings.Enlist)
{
throw new ArgumentException("Enlist=false must be specified for Npgsql.");
}
services
.AddEntityFrameworkNpgsql()
.AddDbContextPool<BasicApiContext>(options => options.UseNpgsql(connectionString));
break;
case "SQLITE":
_isSQLite = true;
services
.AddEntityFrameworkSqlite()
.AddDbContextPool<BasicApiContext>(options => options.UseSqlite("Data Source=BasicApi.db"));
break;
case "SQLSERVER":
services
.AddEntityFrameworkSqlServer()
.AddDbContextPool<BasicApiContext>(options => options.UseSqlServer(connectionString));
break;
default:
throw new ArgumentException($"Application does not support database type {databaseType}.");
}
services.AddAuthorization(options =>
{
options.AddPolicy(
"pet-store-reader",
builder => builder
.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
.RequireAuthenticatedUser()
.RequireClaim("scope", "pet-store-reader"));
options.AddPolicy(
"pet-store-writer",
builder => builder
.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
.RequireAuthenticatedUser()
.RequireClaim("scope", "pet-store-writer"));
});
services
.AddMvcCore()
.AddAuthorization()
.AddJsonFormatters(json => json.ContractResolver = new CamelCasePropertyNamesContractResolver())
.AddDataAnnotations();
}
public void Configure(IApplicationBuilder app, IApplicationLifetime lifetime)
{
var services = app.ApplicationServices;
CreateDatabaseTables(services);
if (_isSQLite)
{
lifetime.ApplicationStopping.Register(() => DropDatabase(services));
}
else
{
lifetime.ApplicationStopping.Register(() => DropDatabaseTables(services));
}
app.Use(next => async context =>
{
try
{
await next(context);
}
catch (Exception ex)
{
Console.WriteLine(ex);
throw;
}
});
app.UseAuthentication();
app.UseMvc();
}
private void CreateDatabaseTables(IServiceProvider services)
{
using (var serviceScope = services.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
using (var dbContext = serviceScope.ServiceProvider.GetRequiredService<BasicApiContext>())
{
#if GENERATE_SQL_SCRIPTS
var migrator = dbContext.GetService<IMigrator>();
var script = migrator.GenerateScript(
fromMigration: Migration.InitialDatabase,
toMigration: dbContext.Database.GetMigrations().LastOrDefault());
Console.WriteLine("Create script:");
Console.WriteLine(script);
#endif
dbContext.Database.Migrate();
}
}
}
// Don't leave SQLite's .db file behind.
public static void DropDatabase(IServiceProvider services)
{
using (var serviceScope = services.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
using (var dbContext = serviceScope.ServiceProvider.GetRequiredService<BasicApiContext>())
{
#if GENERATE_SQL_SCRIPTS
var migrator = dbContext.GetService<IMigrator>();
var script = migrator.GenerateScript(
fromMigration: dbContext.Database.GetAppliedMigrations().LastOrDefault(),
toMigration: Migration.InitialDatabase);
Console.WriteLine("Delete script:");
Console.WriteLine(script);
#endif
dbContext.Database.EnsureDeleted();
}
}
}
private void DropDatabaseTables(IServiceProvider services)
{
using (var serviceScope = services.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
using (var dbContext = serviceScope.ServiceProvider.GetRequiredService<BasicApiContext>())
{
var migrator = dbContext.GetService<IMigrator>();
#if GENERATE_SQL_SCRIPTS
var script = migrator.GenerateScript(
fromMigration: dbContext.Database.GetAppliedMigrations().LastOrDefault(),
toMigration: Migration.InitialDatabase);
Console.WriteLine("Delete script:");
Console.WriteLine(script);
#endif
migrator.Migrate(Migration.InitialDatabase);
}
}
}
public static void Main(string[] args)
{
var host = CreateWebHostBuilder(args)
.Build();
host.Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
var configuration = new ConfigurationBuilder()
.AddEnvironmentVariables()
.AddCommandLine(args)
.Build();
return new WebHostBuilder()
.UseKestrel()
.UseUrls("http://+:5000")
.UseConfiguration(configuration)
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>();
}
}
}

View File

@ -0,0 +1,54 @@
{
"Default": {
"Client": "Wrk",
"Headers": {
"Cache-Control": "no-cache"
},
"PresetHeaders": "Json",
"ReadyStateText": "Application started.",
"Source": {
"BranchOrCommit": "release/2.2",
"Project": "benchmarkapps/BasicApi/BasicApi.csproj",
"Repository": "https://github.com/aspnet/mvc.git"
}
},
"BasicApi.GetToken": {
"Path": "/token",
"PresetHeaders": "Plaintext",
"Query": "?username=reader@example.com"
},
"BasicApi.GetUsingQueryString": {
"ClientProperties": {
"Scripts": "https://raw.githubusercontent.com/aspnet/Mvc/release/2.2/benchmarkapps/BasicApi/getWithToken.lua"
},
"Path": "/pet/findByStatus",
"Query": "?status=available"
},
"BasicApi.GetUsingRouteValue": {
"ClientProperties": {
"Scripts": "https://raw.githubusercontent.com/aspnet/Mvc/release/2.2/benchmarkapps/BasicApi/getWithToken.lua"
},
"Path": "/pet/-1"
},
"BasicApi.GetUsingRouteValueWithoutAuthorization": {
"ClientProperties": {
"Scripts": "https://raw.githubusercontent.com/aspnet/Mvc/release/2.2/benchmarkapps/BasicApi/getWithToken.lua"
},
"Path": "/pet/anonymous/-1"
},
"BasicApi.GetUsingRouteValueWithoutToken": {
"Path": "/pet/anonymous/-1"
},
"BasicApi.Post": {
"ClientProperties": {
"Scripts": "https://raw.githubusercontent.com/aspnet/Mvc/release/2.2/benchmarkapps/BasicApi/postJsonWithToken.lua"
},
"Path": "/pet"
},
"BasicApi.PostWithoutDb": {
"Path": "/pet/add-pet",
"ClientProperties": {
"Scripts": "https://raw.githubusercontent.com/aspnet/Mvc/release/2.2/benchmarkapps/BasicApi/postJsonWithToken.lua"
}
}
}

View File

@ -0,0 +1,51 @@
-- script that retrieves an authentication token to send in all future requests
-- keep this file and postJsonWithToken.lua in sync with respect to token handling
-- use token for at most maxRequests, default throughout test
local counter = 0
local maxRequests = -1
-- request access necessary for both reading and writing by default
local username = "writer@example.com"
-- marker that we have completed the first request
local token = nil
function init(args)
if args[1] ~= nil then
maxRequests = args[1]
print("Max requests: " .. maxRequests)
end
if args[2] ~= nil then
username = args[2]
end
local path = "/token?username=" .. username
-- initialize first (empty) request
req = wrk.format("GET", path, nil, "")
end
function request()
return req
end
function response(status, headers, body)
if not token and status == 200 then
token = body
wrk.headers["Authorization"] = "Bearer " .. token
req = wrk.format()
return
end
if not token then
print("Failed initial request! status: " .. status)
wrk.thread:stop()
end
if counter == maxRequests then
wrk.thread:stop()
end
counter = counter + 1
end

View File

@ -0,0 +1,83 @@
-- script that retrieves an authentication token to send in all future requests and adds a body for those requests
-- keep this file and getWithToken.lua in sync with respect to token handling
-- do not use wrk's default request
local req = nil
-- use token for at most maxRequests, default throughout test
local counter = 0
local maxRequests = -1
-- request access necessary for both reading and writing by default
local username = "writer@example.com"
-- marker that we have completed the first request
local token = nil
function init(args)
if args[1] ~= nil then
maxRequests = args[1]
print("Max requests: " .. maxRequests)
end
if args[2] ~= nil then
username = args[2]
end
local path = "/token?username=" .. username
-- initialize first (empty) request
req = wrk.format("GET", path, nil, "")
end
function request()
return req
end
function response(status, headers, body)
if not token and status == 200 then
token = body
wrk.headers["Authorization"] = "Bearer " .. token
wrk.headers["Content-Type"] = "application/json"
wrk.method = "POST"
wrk.body = [[
{
"category": {
"name": "Cats"
},
"images": [
{
"url": "http://example.com/images/fluffy1.png"
},
{
"url": "http://example.com/images/fluffy2.png"
},
],
"tags": [
{
"name": "orange"
},
{
"name": "kitty"
}
],
"age": 2,
"hasVaccinations": "true",
"name": "fluffy",
"status": "available"
}]]
req = wrk.format()
return
end
if not token then
print("Failed initial request! status: " .. status)
wrk.thread:stop()
end
if counter == maxRequests then
wrk.thread:stop()
end
counter = counter + 1
end

View File

@ -0,0 +1,5 @@
{
"configProperties": {
"System.GC.Server": true
}
}

View File

@ -0,0 +1,44 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFrameworks>netcoreapp2.2</TargetFrameworks>
<TargetFrameworks Condition=" '$(DeveloperBuild)' != 'true' AND '$(OS)' == 'Windows_NT' ">$(TargetFrameworks);net461</TargetFrameworks>
<TargetFrameworks Condition="'$(BenchmarksTargetFramework)' != ''">$(BenchmarksTargetFramework)</TargetFrameworks>
<DefineConstants Condition=" '$(GenerateSqlScripts)'=='true' ">$(DefineConstants);GENERATE_SQL_SCRIPTS</DefineConstants>
<DefineConstants>$(DefineConstants);__RemoveThisBitTo__GENERATE_SQL_SCRIPTS</DefineConstants>
<WarningsNotAsErrors>CS8002;$(WarningsNotAsErrors)</WarningsNotAsErrors>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="$(BenchmarksOnlyNpgsqlEntityFrameworkCorePostgreSQLPackageVersion)" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' != 'net461'">
<PackageReference Include="MySqlConnector" Version="$(BenchmarksOnlyMySqlConnectorPackageVersion)" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="$(BenchmarksOnlyPomeloEntityFrameworkCoreMySqlPackageVersion)" />
</ItemGroup>
<!-- These references are used when running locally -->
<ItemGroup Condition="'$(BenchmarksTargetFramework)' == ''">
<PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="$(MicrosoftAspNetCoreServerIISIntegrationPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="$(MicrosoftAspNetCoreServerKestrelPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="$(MicrosoftAspNetCoreStaticFilesPackageVersion)" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="$(BenchmarksOnlyMicrosoftEntityFrameworkCoreDesignPackageVersion)" PrivateAssets="All" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="$(BenchmarksOnlyMicrosoftEntityFrameworkCoreSqlitePackageVersion)" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="$(BenchmarksOnlyMicrosoftEntityFrameworkCoreSqlServerPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="$(MicrosoftExtensionsConfigurationCommandLinePackageVersion)" />
<PackageReference Include="Microsoft.NET.Sdk.Razor" Version="$(MicrosoftNETSdkRazorPackageVersion)" PrivateAssets="All" />
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Mvc\Microsoft.AspNetCore.Mvc.csproj" />
</ItemGroup>
<!--
These references are used when running on the Benchmarks Server.
Use All meta-package and not App to include Microsoft.EntityFrameworkCore.Sqlite.
-->
<ItemGroup Condition="'$(BenchmarksTargetFramework)' != ''">
<PackageReference Include="Microsoft.AspNetCore.All" Version="$(MicrosoftAspNetCoreAllPackageVersion)" />
<PackageReference Include="Microsoft.NET.Sdk.Razor" Version="$(MicrosoftAspNetCoreAllPackageVersion)" PrivateAssets="All" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,17 @@
// 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.EntityFrameworkCore;
namespace BasicViews
{
public class BasicViewsContext : DbContext
{
public BasicViewsContext(DbContextOptions options)
: base(options)
{
}
public virtual DbSet<Person> People { get; set; }
}
}

View File

@ -0,0 +1,19 @@
// 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.Mvc;
namespace BasicViews.Components
{
public class CurrentUser : ViewComponent
{
private static readonly string[] Names = { "Curly", "Curly Joe", "Joe", "Larry", "Moe", "Shemp" };
private static int index = 0;
public string Invoke()
{
index = index++ / Names.Length;
return Names[index];
}
}
}

View File

@ -0,0 +1,75 @@
// 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.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
namespace BasicViews.Controllers
{
public class HomeController : Controller
{
private readonly BasicViewsContext _context;
public HomeController(BasicViewsContext context)
{
_context = context;
}
[HttpGet]
public IActionResult Index()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Index(Person person)
{
if (ModelState.IsValid)
{
_context.Add(person);
await _context.SaveChangesAsync();
}
return View(person);
}
[HttpGet]
public IActionResult IndexWithoutToken()
{
return View(viewName: nameof(Index));
}
[HttpPost]
[IgnoreAntiforgeryToken]
public async Task<IActionResult> IndexWithoutToken(Person person)
{
if (ModelState.IsValid)
{
_context.Add(person);
await _context.SaveChangesAsync();
}
return View(viewName: nameof(Index), model: person);
}
[HttpGet]
public IActionResult HtmlHelpers()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> HtmlHelpers(Person person)
{
if (ModelState.IsValid)
{
_context.Add(person);
await _context.SaveChangesAsync();
}
return View(person);
}
}
}

View File

@ -0,0 +1,44 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace BasicViews.Migrations
{
[DbContext(typeof(BasicViewsContext))]
[Migration("20180609000611_InitialCreate")]
partial class InitialCreate
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn)
.HasAnnotation("ProductVersion", "2.1.0-rtm-30799")
.HasAnnotation("Relational:MaxIdentifierLength", 63)
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("BasicViews.Person", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("Age");
b.Property<DateTimeOffset>("BirthDate");
b.Property<string>("Name")
.HasMaxLength(27);
b.HasKey("Id");
b.ToTable("People");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,39 @@
using System;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace BasicViews.Migrations
{
public partial class InitialCreate : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "People",
columns: table => new
{
Id = table.Column<int>(nullable: false)
#if !NET461
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn)
#endif
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn)
.Annotation("Sqlite:Autoincrement", true)
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
Name = table.Column<string>(maxLength: 27, nullable: true),
Age = table.Column<int>(nullable: false),
BirthDate = table.Column<DateTimeOffset>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_People", x => x.Id);
});
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "People");
}
}
}

View File

@ -0,0 +1,42 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace BasicViews.Migrations
{
[DbContext(typeof(BasicViewsContext))]
partial class BasicViewsContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn)
.HasAnnotation("ProductVersion", "2.1.0-rtm-30799")
.HasAnnotation("Relational:MaxIdentifierLength", 63)
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("BasicViews.Person", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<int>("Age");
b.Property<DateTimeOffset>("BirthDate");
b.Property<string>("Name")
.HasMaxLength(27);
b.HasKey("Id");
b.ToTable("People");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,21 @@
// 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.ComponentModel.DataAnnotations;
namespace BasicViews
{
public class Person
{
public int Id { get; set; }
[StringLength(27, MinimumLength = 2)]
public string Name { get; set; }
[Range(10, 54)]
public int Age { get; set; }
public DateTimeOffset BirthDate { get; set; }
}
}

View File

@ -0,0 +1,207 @@
// 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;
#if GENERATE_SQL_SCRIPTS
using System.Linq;
#endif
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Npgsql;
namespace BasicViews
{
public class Startup
{
private bool _isSQLite;
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
var connectionString = Configuration["ConnectionString"];
var databaseType = Configuration["Database"];
if (string.IsNullOrEmpty(databaseType))
{
// Use SQLite when running outside a benchmark test or if benchmarks user specified "None".
// ("None" is not passed to the web application.)
databaseType = "SQLite";
}
else if (string.IsNullOrEmpty(connectionString))
{
throw new ArgumentException("Connection string must be specified for {databaseType}.");
}
switch (databaseType.ToUpper())
{
#if !NET461
case "MYSQL":
services
.AddEntityFrameworkMySql()
.AddDbContextPool<BasicViewsContext>(options => options.UseMySql(connectionString));
break;
#endif
case "POSTGRESQL":
var settings = new NpgsqlConnectionStringBuilder(connectionString);
if (!settings.NoResetOnClose)
{
throw new ArgumentException("No Reset On Close=true must be specified for Npgsql.");
}
if (settings.Enlist)
{
throw new ArgumentException("Enlist=false must be specified for Npgsql.");
}
services
.AddEntityFrameworkNpgsql()
.AddDbContextPool<BasicViewsContext>(options => options.UseNpgsql(connectionString));
break;
case "SQLITE":
_isSQLite = true;
services
.AddEntityFrameworkSqlite()
.AddDbContextPool<BasicViewsContext>(options => options.UseSqlite("Data Source=BasicViews.db"));
break;
case "SQLSERVER":
services
.AddEntityFrameworkSqlServer()
.AddDbContextPool<BasicViewsContext>(options => options.UseSqlServer(connectionString));
break;
default:
throw new ArgumentException($"Application does not support database type {databaseType}.");
}
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IApplicationLifetime lifetime)
{
var services = app.ApplicationServices;
CreateDatabaseTables(services);
if (_isSQLite)
{
lifetime.ApplicationStopping.Register(() => DropDatabase(services));
}
else
{
lifetime.ApplicationStopping.Register(() => DropDatabaseTables(services));
}
app.Use(next => async context =>
{
try
{
await next(context);
}
catch (Exception ex)
{
Console.WriteLine(ex);
throw;
}
});
app.UseStaticFiles();
app.UseMvcWithDefaultRoute();
}
private void CreateDatabaseTables(IServiceProvider services)
{
using (var serviceScope = services.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
using (var dbContext = serviceScope.ServiceProvider.GetRequiredService<BasicViewsContext>())
{
#if GENERATE_SQL_SCRIPTS
var migrator = dbContext.GetService<IMigrator>();
var script = migrator.GenerateScript(
fromMigration: Migration.InitialDatabase,
toMigration: dbContext.Database.GetMigrations().LastOrDefault());
Console.WriteLine("Create script:");
Console.WriteLine(script);
#endif
dbContext.Database.Migrate();
}
}
}
// Don't leave SQLite's .db file behind.
public static void DropDatabase(IServiceProvider services)
{
using (var serviceScope = services.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
using (var dbContext = serviceScope.ServiceProvider.GetRequiredService<BasicViewsContext>())
{
#if GENERATE_SQL_SCRIPTS
var migrator = dbContext.GetService<IMigrator>();
var script = migrator.GenerateScript(
fromMigration: dbContext.Database.GetAppliedMigrations().LastOrDefault(),
toMigration: Migration.InitialDatabase);
Console.WriteLine("Delete script:");
Console.WriteLine(script);
#endif
dbContext.Database.EnsureDeleted();
}
}
}
private void DropDatabaseTables(IServiceProvider services)
{
using (var serviceScope = services.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
using (var dbContext = serviceScope.ServiceProvider.GetRequiredService<BasicViewsContext>())
{
var migrator = dbContext.GetService<IMigrator>();
#if GENERATE_SQL_SCRIPTS
var script = migrator.GenerateScript(
fromMigration: dbContext.Database.GetAppliedMigrations().LastOrDefault(),
toMigration: Migration.InitialDatabase);
Console.WriteLine("Delete script:");
Console.WriteLine(script);
#endif
migrator.Migrate(Migration.InitialDatabase);
}
}
}
public static void Main(string[] args)
{
var host = CreateWebHostBuilder(args)
.Build();
host.Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
var configuration = new ConfigurationBuilder()
.AddEnvironmentVariables()
.AddCommandLine(args)
.Build();
return new WebHostBuilder()
.UseKestrel()
.UseUrls("http://+:5000")
.UseConfiguration(configuration)
.UseIISIntegration()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>();
}
}
}

View File

@ -0,0 +1,23 @@
@using BasicViews
@model Person
@Html.ValidationSummary()
@using (Html.BeginForm())
{
<div>
@Html.LabelFor(p => p.Name)
@Html.EditorFor(p => p.Name)
</div>
<div>
@Html.LabelFor(p => p.Age)
@Html.EditorFor(p => p.Age)
</div>
<div>
@Html.LabelFor(p => p.BirthDate)
@Html.EditorFor(p => p.BirthDate)
</div>
<input type="submit" />
@Html.AntiForgeryToken()
}

View File

@ -0,0 +1,21 @@
@using BasicViews
@model Person
<div asp-validation-summary="All">
</div>
<form asp-action="Index" asp-controller="Home">
<div>
<label asp-for="Name"></label>
<input asp-for="Name" />
</div>
<div>
<label asp-for="Age"></label>
<input asp-for="Age" />
</div>
<div>
<label asp-for="BirthDate"></label>
<input asp-for="BirthDate" />
</div>
<input type="submit" />
</form>

View File

@ -0,0 +1,55 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>MVC with views</title>
<environment names="Development">
<link rel="stylesheet" href="~/css/site.css" />
</environment>
<environment names="Staging,Production">
<link rel="stylesheet" href="~/css/site.min.css" asp-fallback-href="~/css/site.css"
asp-fallback-test-class="test-it" asp-fallback-test-property="float"
asp-fallback-test-value="right" asp-append-version="true" />
</environment>
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a asp-controller="Home" asp-action="Index" class="navbar-brand">BasicViews</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a asp-controller="Home" asp-action="Index">TagHelpers</a></li>
<li><a asp-controller="Home" asp-action="HtmlHelpers">HtmlHelpers</a></li>
</ul>
</div>
</div>
</div>
<div class="container body-content">
<p>Hello @await Component.InvokeAsync("CurrentUser")!</p>
<div>
@RenderBody()
</div>
</div>
<environment names="Development">
<script src="~/js/site.js" asp-append-version="true"></script>
</environment>
<environment names="Staging,Production">
<script src="~/js/site.min.js" asp-fallback-src="~/js/site.js"
asp-fallback-test="test" asp-append-version="true"></script>
</environment>
@RenderSection("scripts", required: false)
</body>
</html>

View File

@ -0,0 +1 @@
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

View File

@ -0,0 +1,3 @@
@{
Layout = "_Layout";
}

View File

@ -0,0 +1,39 @@
{
"Default": {
"Client": "Wrk",
"Headers": {
"Cache-Control": "no-cache"
},
"PresetHeaders": "Html",
"ReadyStateText": "Application started.",
"Source": {
"BranchOrCommit": "release/2.2",
"Project": "benchmarkapps/BasicViews/BasicViews.csproj",
"Repository": "https://github.com/aspnet/mvc.git"
}
},
"BasicViews.GetHtmlHelpers": {
"Path": "/Home/HtmlHelpers"
},
"BasicViews.GetTagHelpers": {
"Path": "/Home/Index"
},
"BasicViews.Post": {
"ClientProperties": {
"Scripts": "https://raw.githubusercontent.com/aspnet/Mvc/release/2.2/benchmarkapps/BasicViews/postWithToken.lua"
},
"Path": "/Home/Index"
},
"BasicViews.PostIgnoringToken": {
"ClientProperties": {
"Scripts": "https://raw.githubusercontent.com/aspnet/Mvc/release/2.2/benchmarkapps/BasicViews/postWithToken.lua"
},
"Path": "/Home/IndexWithoutToken"
},
"BasicViews.PostWithoutToken": {
"ClientProperties": {
"Scripts": "https://raw.githubusercontent.com/aspnet/Mvc/release/2.2/benchmarkapps/BasicViews/post.lua"
},
"Path": "/Home/IndexWithoutToken"
}
}

View File

@ -0,0 +1,7 @@
-- script that POSTs body for requests
function init(args)
wrk.body = "Age=12&BirthDate=2006-03-01T09%3A51%3A43.041-07%3A00&Name=George"
wrk.headers["Content-Type"] = "application/x-www-form-urlencoded"
wrk.method = "POST"
end

View File

@ -0,0 +1,55 @@
-- script that retrieves an antiforgery token to send in all future requests and adds a body for those requests
-- do not use wrk's default request
local req = nil
-- use token for at most maxRequests, default throughout test
local counter = 0
local maxRequests = -1
-- marker that we have completed the first request
local token = nil
function init(args)
-- initialize first (empty) request
req = wrk.format("GET")
end
function request()
return req
end
function response(status, headers, body)
if not token and status == 200 then
local cookie = string.gsub(headers["Set-Cookie"], "^([^;]*)(;.*)?$", "%1")
if not cookie or cookie == "" then
print("Unable to find antiforgery cookie in initial response!")
wrk.thread:stop()
end
token = string.gsub(body, '^.* name="__RequestVerificationToken".* value="([^"]*)"[ >].*$', "%1")
if not token or token == "" then
print("Unable to find antiforgery token in initial response!")
wrk.thread:stop()
end
wrk.body = "Age=12&BirthDate=2006-03-01T09%3A51%3A43.041-07%3A00&Name=George&__RequestVerificationToken=" .. token
wrk.headers["Content-Type"] = "application/x-www-form-urlencoded"
wrk.headers["Cookie"] = cookie
wrk.method = "POST"
req = wrk.format()
return
end
if not token then
print("Failed initial request! status: " .. status)
wrk.thread:stop()
end
if counter == maxRequests then
wrk.thread:stop()
end
counter = counter + 1
end

View File

@ -0,0 +1,5 @@
{
"configProperties": {
"System.GC.Server": true
}
}

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
</handlers>
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" forwardWindowsAuthToken="false" stdoutLogEnabled="false" />
</system.webServer>
</configuration>

View File

@ -0,0 +1,6 @@
label {
font-size: 1.2em;
}
.test-it {
float: right;
}

View File

@ -0,0 +1,6 @@
label {
font-size: 1.3em;
}
.test-it {
float: right;
}

View File

@ -0,0 +1,3 @@
console.log("Hello World");
function test() {
}

View File

@ -0,0 +1,3 @@
console.log("Hello Minified World");
function test() {
}

View File

@ -0,0 +1,15 @@
## Purpose
These projects assist in Benchmarking MVC.
They makes it easier to test local changes than having the App in the Benchmarks repo by letting us make changes in MVC branches and use the example commandline below to run the benchmarks against our branches.
## Usage
1. Push changes you would like to test to a branch on GitHub
2. Clone aspnet/benchmarks repo to your machine or install the global BenchmarksDriver tool https://www.nuget.org/packages/BenchmarksDriver/
3. If cloned go to the BenchmarksDriver project
4. Use the following command as a guideline for running a test using your changes
`benchmarks --server <server-endpoint> --client <client-endpoint> -j https://raw.githubusercontent.com/aspnet/MVC/{your branch}/benchmarkaps/BasicApi/BasicApi.json`
5. For more info/commands see https://github.com/aspnet/benchmarks/blob/master/src/BenchmarksDriver/README.md

View File

@ -0,0 +1,26 @@
using Microsoft.AspNetCore.Html;
namespace Data
{
public class DataA
{
public DataA(int id, HtmlString icon, HtmlString html, string name, int seconds, int max, float perHour)
{
Id = id;
Icon = icon;
Html = html;
Name = name;
Seconds = seconds;
Max = max;
PerHour = perHour;
}
public int Id { get; }
public HtmlString Icon { get; }
public HtmlString Html { get; }
public string Name { get; }
public int Seconds { get; }
public int Max { get; }
public float PerHour { get; }
}
}

View File

@ -0,0 +1,25 @@
using System;
using Microsoft.AspNetCore.Html;
namespace Data
{
public class DataB
{
public DataB(int id, HtmlString icon, string name, int value, DateTimeOffset startDate, DateTimeOffset completeDate)
{
Id = id;
Icon = icon;
Name = name;
Value = value;
StartDate = startDate;
CompleteDate = completeDate;
}
public int Id { get; }
public HtmlString Icon { get; }
public string Name { get; }
public int Value { get; }
public DateTimeOffset StartDate { get; }
public DateTimeOffset CompleteDate { get; }
}
}

View File

@ -0,0 +1,138 @@
@page
@model Pages.PageA
@using static System.Convert
@section Subcategories {
<partial name="_Subcategories" />
}
@section Tabs {
<span class="dialog-tab@(Model.Condition ? " selected" : "")"><span class="link" data-url="/Category/PageA">Sub cat A</span></span>
<span class="dialog-tab"><span class="link" data-url="/Category/PageB/@Model.Value1/@Model.Value2">Sub cat B</span></span>
<span class="dialog-tab"><span class="link" data-url="/Category/PageC/@((int)Model.Value3)">Sub cat C</span></span>
<span class="dialog-tab@(!Model.Condition ? " selected" : "")"><span class="link" data-url="/Category/PageD/@((int)Model.Value3)">Sub cat D</span></span>
}
@switch (Model.Value)
{
case 0:
<h1>@Model.Name Type A</h1>
break;
case 1:
<h1>@Model.Name Type B</h1>
break;
case 2:
<h1>@Model.Name Type C</h1>
break;
}
<h3 style="clear:both;">Something Something</h3>
<div>
<table class="generic small oddeven middle center">
<tr>
<th style="width: 24px;"></th>
<th>Something</th>
<th style="width: 270px;">Something Something</th>
@if (Model.Value3 != 0)
{
<th style="width: 70px;" class="dull right">Something</th>
}
<th style="width: 130px;"></th>
</tr>
@{
foreach (var data in Model.Data1)
{
<tr>
<td class="left">@data.Icon</td>
<td class="left">@data.Name</td>
<td style="text-align:center">@data.Html</td>
@if (Model.Value3 != 0)
{
<td class="dull right">
@(new TimeSpan(0, 0, (int)data.Seconds)) <br />
(@data.PerHour.ToString("N2") p/h)
</td>
}
<td>
<form asp-page-handler="Make">
<input type="hidden" name="Id" value="@((int)Model.Value3)" />
<input type="hidden" name="ResType" value="@data.Id" />
<input type="text" name="Quantity" style="width: 35px; font-size: 11px; text-align: left;" placeholder="@data.Max.ToString(System.Globalization.NumberFormatInfo.InvariantInfo)" />
<a href="#" class="max">max</a>
<button class="small">Make</button>
</form>
</td>
</tr>
}
}
</table>
</div>
<h3 style="clear:both;">Something something something</h3>
<div>
@{
if (Model.Data2.Count > 0)
{
<table class="oddeven" style="font-size: 11px;">
<tr>
<th style="width:20px"></th>
<th class="left">SomethingA</th>
<th style="width: 80px;">SomethingB</th>
<th style="width: 60px">SomethingC</th>
<th>SomethingD</th>
<th style="width: 60px">SomethingE</th>
<th style="width: 90px;">SomethingF</th>
<th style="width: 56px;"></th>
</tr>
@foreach (var data in Model.Data2)
{
var StartDate = data.StartDate;
var CompleteDate = data.CompleteDate;
<tr>
<td>@data.Icon</td>
<td class="left">@data.Name</td>
<td>@data.Value</td>
<td class="center">@StartDate.ToString("dd MMM HH:mm:ss")</td>
@{
float percentage = 100f;
var totalTime = CompleteDate.Subtract(StartDate).TotalMilliseconds;
if (totalTime > 1000)
{
percentage = 100f * (float)DateTimeOffset.UtcNow.Subtract(StartDate).TotalMilliseconds / (float)totalTime;
}
percentage = MathF.Min(100f, MathF.Max(0f, percentage));
var startDate = ToInt64(StartDate.Subtract(DateTime.UnixEpoch).Ticks / (double)10000);
var endDate = ToInt64(CompleteDate.Subtract(DateTime.UnixEpoch).Ticks / (double)10000);
}
<td>
<div class="progBar">
<div class="progProgress" data-start="@startDate" data-end="@endDate" style="width: @(percentage.ToString("N0"))%;"></div>
</div>
</td>
<td class="center">@CompleteDate.ToString("dd MMM HH:mm:ss")</td>
<td>
<span class="progTime" data-start="@startDate" data-end="@endDate">@(CompleteDate.Subtract(DateTime.UtcNow).ToString())</span>
</td>
<td>
<form method="post" asp-page-handler="Cancel">
<input type="hidden" name="id" value="@data.Id" />
<button class="small">Cancel</button>
</form>
</td>
</tr>
}
</table>
}
else
{
<span>Something @Model.Name something something something something.</span>
}
}
</div>

View File

@ -0,0 +1,35 @@
using Data;
using Microsoft.Extensions.Logging;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Pages
{
public class PageA : Page
{
public int Value { get; } = 0;
public int Value1 { get; } = 0;
public int Value2 { get; } = 0;
public int Value3 { get; } = 1;
public bool Condition { get; } = true;
public string Name { get; } = "A Name";
public List<DataA> Data1 { get; }
public List<DataB> Data2 { get; }
public PageA(List<DataA> dataA, List<DataB> dataB, ILogger<PageA> logger) : base(logger)
{
Data1 = dataA;
Data2 = dataB;
}
public async Task OnGetAsync()
{
PageTitle = "PageA Title";
PageIcon = "sicon dialogue_pagea";
await Task.Delay(0);
}
}
}

View File

@ -0,0 +1,12 @@
@model Pages.Page
<div class="dialog-subcat">
<div data-url="/Category/PageA" title="PageA Title" class="sicon dialogue_pagea"></div>
<div data-url="/Category/PageB" title="PageB Title" class="sicon dialogue_pageb"></div>
<div data-url="/Category/PageC" title="PageC Title" class="sicon dialogue_pagec"></div>
<div data-url="/Category/PageD" title="PageD Title" class="sicon dialogue_paged"></div>
<div data-url="/Category/PageE" title="PageE Title" class="sicon dialogue_pagee"></div>
<div data-url="/Category/PageF" title="PageF Title" class="sicon dialogue_pagef"></div>
<div data-url="/Category/PageG" title="PageG Title" class="sicon dialogue_pageg"></div>
</div>
<div class="licon micon dialogue_category"></div>

View File

@ -0,0 +1,26 @@
using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
namespace Pages
{
public class Page : PageModel
{
public ILogger Logger { get; }
public string PageIcon { get; protected set; }
public string PageTitle { get; protected set; }
public string PageUrl { get; protected set; }
public Page(ILogger logger)
{
Logger = logger;
}
public void AddErrorMessage(string message)
{
Response.Headers.Add("X-Error-Message", UrlEncoder.Default.Encode(message));
}
}
}

View File

@ -0,0 +1,31 @@
@model Pages.Page
@RenderSection("Subcategories")
<div class="dialog-title-icon @Model.PageIcon"></div>
<div class="dialog-title">@Model.PageTitle</div>
@{
var hasTabs = IsSectionDefined("Tabs");
}
<div class="dialog-body@(hasTabs ? "-tabs" : "")">
@if (hasTabs)
{
<div class="dialog-tabs">
@RenderSection("Tabs", required: false)
</div>
}
<div class="dialog-parch-bottom@(hasTabs ? " tabs" : "")">
<div id="contentScroll" tabindex="20" class="dialog-parch-scroll@(hasTabs ? " tabs" : "")">
<div class="dialog-parch-left">
<div class="dialog-parch-right">
<div id="contentWindow" class="dialog-parch@(hasTabs ? " tabs" : "")">
@RenderBody()
</div>
</div>
</div>
</div>
<div class="dialog-parch-shadow@(hasTabs ? " tabs" : "")"></div>
</div>
</div>
<div class="dialog-close-icon icon_close"></div>
<div class="dialog-bottom-left-edge"></div>
<div class="dialog-bottom-edge"></div>

View File

@ -0,0 +1,2 @@
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

View File

@ -0,0 +1,3 @@
@{
Layout = "_Layout";
}

View File

@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFrameworks>netcoreapp2.2</TargetFrameworks>
</PropertyGroup>
<!-- These references are used when running locally -->
<ItemGroup Condition="'$(BenchmarksTargetFramework)' == ''">
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="$(MicrosoftAspNetCoreServerKestrelPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="$(MicrosoftExtensionsConfigurationCommandLinePackageVersion)" />
<PackageReference Include="Microsoft.NET.Sdk.Razor" Version="$(MicrosoftNETSdkRazorPackageVersion)" PrivateAssets="All" />
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Mvc\Microsoft.AspNetCore.Mvc.csproj" />
</ItemGroup>
<!--
These references are used when running on the Benchmarks Server.
-->
<ItemGroup Condition="'$(BenchmarksTargetFramework)' != ''">
<PackageReference Include="Microsoft.AspNetCore.App" Version="$(MicrosoftNETCoreApp22PackageVersion)" />
<PackageReference Include="Microsoft.NET.Sdk.Razor" Version="$(MicrosoftNETCoreApp22PackageVersion)" PrivateAssets="All" />
</ItemGroup>
<ItemGroup>
<Folder Include="Properties\" />
</ItemGroup>
</Project>

View File

@ -0,0 +1 @@
Url: /Category/PageA

View File

@ -0,0 +1,78 @@
using System;
using System.Linq;
using System.Collections.Generic;
using Data;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Html;
using Microsoft.Extensions.Configuration;
using System.IO;
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<List<DataA>>(_ => DataA);
services.AddScoped<List<DataB>>(_ => DataB);
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Latest);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseMvc();
}
private static List<DataA> DataA = GenerateDataA();
private static List<DataA> GenerateDataA()
{
var dataA = new List<DataA>();
foreach (var i in Enumerable.Range(0, 100))
{
dataA.Add(new DataA(i, new HtmlString(i.ToString()), new HtmlString(i.ToString()), i.ToString(), i, i, 60f / i));
}
return dataA;
}
private static List<DataB> DataB = GenerateDataB();
private static List<DataB> GenerateDataB()
{
var utc = DateTimeOffset.UtcNow;
var dataB = new List<DataB>();
foreach (var i in Enumerable.Range(0, 100))
{
dataB.Add(new DataB(i, new HtmlString(i.ToString()), i.ToString(), i, utc, utc));
}
return dataB;
}
public static void Main(string[] args)
{
var host = CreateWebHostBuilder(args)
.Build();
host.Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
var configuration = new ConfigurationBuilder()
.AddEnvironmentVariables()
.AddCommandLine(args)
.Build();
return new WebHostBuilder()
.UseKestrel()
.UseUrls("http://+:5000")
.UseConfiguration(configuration)
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>();
}
}

View File

@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;
@ -105,7 +106,7 @@ namespace Microsoft.AspNetCore.Mvc.Performance
var state = routeContext.RouteData.PushState(MockRouter.Instance, routeValues, null);
var actual = NaiveSelectCandiates(_actions, routeContext.RouteData.Values);
var actual = NaiveSelectCandidates(_actions, routeContext.RouteData.Values);
Verify(expected, actual);
state.Restore();
@ -113,7 +114,7 @@ namespace Microsoft.AspNetCore.Mvc.Performance
}
// A naive implementation we can use to generate match data for inputs, and for a baseline.
private static IReadOnlyList<ActionDescriptor> NaiveSelectCandiates(ActionDescriptor[] actions, RouteValueDictionary routeValues)
private static IReadOnlyList<ActionDescriptor> NaiveSelectCandidates(ActionDescriptor[] actions, RouteValueDictionary routeValues)
{
var results = new List<ActionDescriptor>();
for (var i = 0; i < actions.Length; i++)
@ -123,8 +124,8 @@ namespace Microsoft.AspNetCore.Mvc.Performance
var isMatch = true;
foreach (var kvp in action.RouteValues)
{
var routeValue = Convert.ToString(routeValues[kvp.Key]) ?? string.Empty;
var routeValue = Convert.ToString(routeValues[kvp.Key], CultureInfo.InvariantCulture) ??
string.Empty;
if (string.IsNullOrEmpty(kvp.Value) && string.IsNullOrEmpty(routeValue))
{
// Match
@ -156,7 +157,7 @@ namespace Microsoft.AspNetCore.Mvc.Performance
var routeValues = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
foreach (var kvp in new RouteValueDictionary(obj))
{
routeValues.Add(kvp.Key, Convert.ToString(kvp.Value) ?? string.Empty);
routeValues.Add(kvp.Key, Convert.ToString(kvp.Value, CultureInfo.InvariantCulture) ?? string.Empty);
}
return new ActionDescriptor()
@ -175,7 +176,7 @@ namespace Microsoft.AspNetCore.Mvc.Performance
{
var action = actions[i];
var routeValues = new RouteValueDictionary(action.RouteValues);
var matches = NaiveSelectCandiates(actions, routeValues);
var matches = NaiveSelectCandidates(actions, routeValues);
if (matches.Count == 0)
{
throw new InvalidOperationException("This should have at least one match.");
@ -193,7 +194,7 @@ namespace Microsoft.AspNetCore.Mvc.Performance
// Make one of the route values not match.
routeValues[routeValues.First().Key] = ((string)routeValues.First().Value) + "fkdkfdkkf";
var matches = NaiveSelectCandiates(actions, routeValues);
var matches = NaiveSelectCandidates(actions, routeValues);
if (matches.Count != 0)
{
throw new InvalidOperationException("This should have 0 matches.");

View File

@ -0,0 +1,142 @@
// 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 BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Routing.Patterns;
namespace Microsoft.AspNetCore.Mvc.Performance
{
public class MvcEndpointDataSourceBenchmark
{
private const string DefaultRoute = "{Controller=Home}/{Action=Index}/{id?}";
// Attribute routes can't have controller and action as parameters, so we edit the
// route template in the test to make it more realistic.
private const string ControllerReplacementToken = "{Controller=Home}";
private const string ActionReplacementToken = "{Action=Index}";
private MockActionDescriptorCollectionProvider _conventionalActionProvider;
private MockActionDescriptorCollectionProvider _attributeActionProvider;
private List<MvcEndpointInfo> _conventionalEndpointInfos;
[Params(1, 100, 1000)]
public int ActionCount;
[GlobalSetup]
public void Setup()
{
_conventionalActionProvider = new MockActionDescriptorCollectionProvider(
Enumerable.Range(0, ActionCount).Select(i => CreateConventionalRoutedAction(i)).ToList()
);
_attributeActionProvider = new MockActionDescriptorCollectionProvider(
Enumerable.Range(0, ActionCount).Select(i => CreateAttributeRoutedAction(i)).ToList()
);
_conventionalEndpointInfos = new List<MvcEndpointInfo>
{
new MvcEndpointInfo(
"Default",
DefaultRoute,
new RouteValueDictionary(),
new Dictionary<string, object>(),
new RouteValueDictionary(),
new MockParameterPolicyFactory())
};
}
[Benchmark]
public void AttributeRouteEndpoints()
{
var endpointDataSource = CreateMvcEndpointDataSource(_attributeActionProvider);
var endpoints = endpointDataSource.Endpoints;
}
[Benchmark]
public void ConventionalEndpoints()
{
var endpointDataSource = CreateMvcEndpointDataSource(_conventionalActionProvider);
endpointDataSource.ConventionalEndpointInfos.AddRange(_conventionalEndpointInfos);
var endpoints = endpointDataSource.Endpoints;
}
private ActionDescriptor CreateAttributeRoutedAction(int id)
{
var routeValues = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
["Controller"] = "Controller" + id,
["Action"] = "Index"
};
var template = DefaultRoute
.Replace(ControllerReplacementToken, routeValues["Controller"])
.Replace(ActionReplacementToken, routeValues["Action"]);
return new ActionDescriptor
{
RouteValues = routeValues,
DisplayName = "Action " + id,
AttributeRouteInfo = new AttributeRouteInfo()
{
Template = template,
}
};
}
private ActionDescriptor CreateConventionalRoutedAction(int id)
{
return new ActionDescriptor
{
RouteValues = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
["Controller"] = "Controller" + id,
["Action"] = "Index"
},
DisplayName = "Action " + id
};
}
private MvcEndpointDataSource CreateMvcEndpointDataSource(
IActionDescriptorCollectionProvider actionDescriptorCollectionProvider)
{
var dataSource = new MvcEndpointDataSource(
actionDescriptorCollectionProvider,
new MvcEndpointInvokerFactory(new ActionInvokerFactory(Array.Empty<IActionInvokerProvider>())),
new MockParameterPolicyFactory());
return dataSource;
}
private class MockActionDescriptorCollectionProvider : IActionDescriptorCollectionProvider
{
public MockActionDescriptorCollectionProvider(List<ActionDescriptor> actionDescriptors)
{
ActionDescriptors = new ActionDescriptorCollection(actionDescriptors, 0);
}
public ActionDescriptorCollection ActionDescriptors { get; }
}
private class MockParameterPolicyFactory : ParameterPolicyFactory
{
public override IParameterPolicy Create(RoutePatternParameterPart parameter, string inlineText)
{
throw new NotImplementedException();
}
public override IParameterPolicy Create(RoutePatternParameterPart parameter, IParameterPolicy parameterPolicy)
{
throw new NotImplementedException();
}
}
}
}

View File

@ -0,0 +1,75 @@
// 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 BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.DataAnnotations;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Mvc.Performance
{
public abstract class ValidationVisitorBenchmarkBase
{
protected const int Iterations = 4;
protected static readonly IModelValidatorProvider[] ValidatorProviders = new IModelValidatorProvider[]
{
new DefaultModelValidatorProvider(),
new DataAnnotationsModelValidatorProvider(
new ValidationAttributeAdapterProvider(),
Options.Create(new MvcDataAnnotationsLocalizationOptions()),
null),
};
protected static readonly CompositeModelValidatorProvider CompositeModelValidatorProvider = new CompositeModelValidatorProvider(ValidatorProviders);
public abstract object Model { get; }
public ModelMetadataProvider BaselineModelMetadataProvider { get; private set; }
public ModelMetadataProvider ModelMetadataProvider { get; private set; }
public ModelMetadata BaselineModelMetadata { get; private set; }
public ModelMetadata ModelMetadata { get; private set; }
public ActionContext ActionContext { get; private set; }
public ValidatorCache ValidatorCache { get; private set; }
[GlobalSetup]
public void Setup()
{
BaselineModelMetadataProvider = CreateModelMetadataProvider(addHasValidatorsProvider: false);
ModelMetadataProvider = CreateModelMetadataProvider(addHasValidatorsProvider: true);
BaselineModelMetadata = BaselineModelMetadataProvider.GetMetadataForType(Model.GetType());
ModelMetadata = ModelMetadataProvider.GetMetadataForType(Model.GetType());
ActionContext = GetActionContext();
ValidatorCache = new ValidatorCache();
}
protected static ModelMetadataProvider CreateModelMetadataProvider(bool addHasValidatorsProvider)
{
var detailsProviders = new List<IMetadataDetailsProvider>
{
new DefaultValidationMetadataProvider(),
};
if (addHasValidatorsProvider)
{
detailsProviders.Add(new HasValidatorsValidationMetadataProvider(ValidatorProviders));
}
var compositeDetailsProvider = new DefaultCompositeMetadataDetailsProvider(detailsProviders);
return new DefaultModelMetadataProvider(compositeDetailsProvider, Options.Create(new MvcOptions()));
}
protected static ActionContext GetActionContext()
{
return new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor());
}
}
}

View File

@ -0,0 +1,42 @@
// 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 BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
namespace Microsoft.AspNetCore.Mvc.Performance
{
public class ValidationVisitorByteArrayBenchmark : ValidationVisitorBenchmarkBase
{
public override object Model { get; } = new byte[30];
[Benchmark(Baseline = true, Description = "validation for byte arrays baseline", OperationsPerInvoke = Iterations)]
public void Baseline()
{
// Baseline for validating a byte array of size 30, without the ModelMetadata.HasValidators optimization.
// This is the behavior as of 2.1.
var validationVisitor = new ValidationVisitor(
ActionContext,
CompositeModelValidatorProvider,
ValidatorCache,
BaselineModelMetadataProvider,
new ValidationStateDictionary());
validationVisitor.Validate(BaselineModelMetadata, "key", Model);
}
[Benchmark(Description = "validation for byte arrays", OperationsPerInvoke = Iterations)]
public void HasValidators()
{
// Validating a byte array of size 30, with the ModelMetadata.HasValidators optimization.
var validationVisitor = new ValidationVisitor(
ActionContext,
CompositeModelValidatorProvider,
ValidatorCache,
ModelMetadataProvider,
new ValidationStateDictionary());
validationVisitor.Validate(ModelMetadata, "key", Model);
}
}
}

View File

@ -0,0 +1,92 @@
// 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.ComponentModel.DataAnnotations;
using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
namespace Microsoft.AspNetCore.Mvc.Performance
{
public class ValidationVisitorModelWithValidatedProperties : ValidationVisitorBenchmarkBase
{
public class Person
{
[Required]
public int Id { get; set; }
[Required]
[StringLength(20)]
public string Name { get; set; }
public string Description { get; set; }
public IList<Address> Address { get; set; }
}
public class Address
{
[Required]
public string Street { get; set; }
public string Street2 { get; set; }
public string Type { get; set; }
[Required]
public string Zip { get; set; }
}
public override object Model { get; } = new Person
{
Id = 10,
Name = "Test",
Address = new List<Address>
{
new Address
{
Street = "1 Microsoft Way",
Type = "Work",
Zip = "98056",
},
new Address
{
Street = "15701 NE 39th St",
Type = "Home",
Zip = "98052",
}
},
};
[Benchmark(Baseline = true, Description = "validation for a model with some validated properties - baseline", OperationsPerInvoke = Iterations)]
public void Visit_TypeWithSomeValidatedProperties_Baseline()
{
// Baseline for validating a typical model with some properties that require validation.
// This executes without the ModelMetadata.HasValidators optimization.
var validationVisitor = new ValidationVisitor(
ActionContext,
CompositeModelValidatorProvider,
ValidatorCache,
BaselineModelMetadataProvider,
new ValidationStateDictionary());
validationVisitor.Validate(BaselineModelMetadata, "key", Model);
}
[Benchmark(Description = "validation for a model with some validated properties", OperationsPerInvoke = Iterations)]
public void Visit_TypeWithSomeValidatedProperties()
{
// Validating a typical model with some properties that require validation.
// This executes with the ModelMetadata.HasValidators optimization.
var validationVisitor = new ValidationVisitor(
ActionContext,
CompositeModelValidatorProvider,
ValidatorCache,
ModelMetadataProvider,
new ValidationStateDictionary());
validationVisitor.Validate(ModelMetadata, "key", Model);
}
}
}

View File

@ -2,102 +2,115 @@
<PropertyGroup>
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
</PropertyGroup>
<!-- These package versions may be overridden or updated by automation. -->
<PropertyGroup Label="Package Versions: Auto">
<PropertyGroup Label="Package Versions"><!--
BenchmarksOnly* package versions come from NuGet.org and are intended only for use in benchmarks apps where EF
is not otherwise referenced. They avoid unnecessary changes to the Universe build graph or to product
dependencies. Do not use these properties elsewhere.
-->
<AngleSharpPackageVersion>0.9.9</AngleSharpPackageVersion>
<BenchmarkDotNetPackageVersion>0.10.13</BenchmarkDotNetPackageVersion>
<InternalAspNetCoreSdkPackageVersion>2.1.3-rtm-15802</InternalAspNetCoreSdkPackageVersion>
<BenchmarksOnlyMicrosoftEntityFrameworkCoreDesignPackageVersion>2.1.1</BenchmarksOnlyMicrosoftEntityFrameworkCoreDesignPackageVersion>
<BenchmarksOnlyMicrosoftEntityFrameworkCoreSqlitePackageVersion>2.1.1</BenchmarksOnlyMicrosoftEntityFrameworkCoreSqlitePackageVersion>
<BenchmarksOnlyMicrosoftEntityFrameworkCoreSqlServerPackageVersion>2.1.1</BenchmarksOnlyMicrosoftEntityFrameworkCoreSqlServerPackageVersion>
<BenchmarksOnlyMySqlConnectorPackageVersion>0.43.0</BenchmarksOnlyMySqlConnectorPackageVersion>
<BenchmarksOnlyNpgsqlEntityFrameworkCorePostgreSQLPackageVersion>2.1.1.1</BenchmarksOnlyNpgsqlEntityFrameworkCorePostgreSQLPackageVersion>
<BenchmarksOnlyPomeloEntityFrameworkCoreMySqlPackageVersion>2.1.1</BenchmarksOnlyPomeloEntityFrameworkCoreMySqlPackageVersion>
<InternalAspNetCoreAnalyzersPackageVersion>2.2.0-rtm-35519</InternalAspNetCoreAnalyzersPackageVersion>
<MicrosoftAspNetCoreAllPackageVersion>2.2.0-rtm-35519</MicrosoftAspNetCoreAllPackageVersion>
<MicrosoftAspNetCoreAnalyzerTestingPackageVersion>2.2.0-rtm-35519</MicrosoftAspNetCoreAnalyzerTestingPackageVersion>
<MicrosoftAspNetCoreAntiforgeryPackageVersion>2.2.0-rtm-35519</MicrosoftAspNetCoreAntiforgeryPackageVersion>
<MicrosoftAspNetCoreAuthenticationCookiesPackageVersion>2.2.0-rtm-35519</MicrosoftAspNetCoreAuthenticationCookiesPackageVersion>
<MicrosoftAspNetCoreAuthenticationCorePackageVersion>2.2.0-rtm-35519</MicrosoftAspNetCoreAuthenticationCorePackageVersion>
<MicrosoftAspNetCoreAuthenticationJwtBearerPackageVersion>2.2.0-rtm-35519</MicrosoftAspNetCoreAuthenticationJwtBearerPackageVersion>
<MicrosoftAspNetCoreAuthenticationPackageVersion>2.2.0-rtm-35519</MicrosoftAspNetCoreAuthenticationPackageVersion>
<MicrosoftAspNetCoreAuthorizationPolicyPackageVersion>2.2.0-rtm-35519</MicrosoftAspNetCoreAuthorizationPolicyPackageVersion>
<MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>2.2.0-rtm-35519</MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>
<MicrosoftAspNetCoreChunkingCookieManagerSourcesPackageVersion>2.2.0-rtm-35519</MicrosoftAspNetCoreChunkingCookieManagerSourcesPackageVersion>
<MicrosoftAspNetCoreCookiePolicyPackageVersion>2.2.0-rtm-35519</MicrosoftAspNetCoreCookiePolicyPackageVersion>
<MicrosoftAspNetCoreCorsPackageVersion>2.2.0-a-rtm-fix-wildcard-16567</MicrosoftAspNetCoreCorsPackageVersion>
<MicrosoftAspNetCoreDiagnosticsAbstractionsPackageVersion>2.2.0-rtm-35519</MicrosoftAspNetCoreDiagnosticsAbstractionsPackageVersion>
<MicrosoftAspNetCoreDiagnosticsPackageVersion>2.2.0-rtm-35519</MicrosoftAspNetCoreDiagnosticsPackageVersion>
<MicrosoftAspNetCoreHostingAbstractions20PackageVersion>2.0.0</MicrosoftAspNetCoreHostingAbstractions20PackageVersion>
<MicrosoftAspNetCoreHostingAbstractionsPackageVersion>2.2.0-rtm-35519</MicrosoftAspNetCoreHostingAbstractionsPackageVersion>
<MicrosoftAspNetCoreHostingPackageVersion>2.2.0-rtm-35519</MicrosoftAspNetCoreHostingPackageVersion>
<MicrosoftAspNetCoreHtmlAbstractionsPackageVersion>2.2.0-rtm-35519</MicrosoftAspNetCoreHtmlAbstractionsPackageVersion>
<MicrosoftAspNetCoreHttpExtensionsPackageVersion>2.2.0-rtm-35519</MicrosoftAspNetCoreHttpExtensionsPackageVersion>
<MicrosoftAspNetCoreHttpPackageVersion>2.2.0-rtm-35519</MicrosoftAspNetCoreHttpPackageVersion>
<MicrosoftAspNetCoreJsonPatchPackageVersion>2.2.0-rtm-35519</MicrosoftAspNetCoreJsonPatchPackageVersion>
<MicrosoftAspNetCoreLocalizationPackageVersion>2.2.0-rtm-35519</MicrosoftAspNetCoreLocalizationPackageVersion>
<MicrosoftAspNetCoreLocalizationRoutingPackageVersion>2.2.0-rtm-35519</MicrosoftAspNetCoreLocalizationRoutingPackageVersion>
<MicrosoftAspNetCoreMvcRazorExtensionsPackageVersion>2.2.0-rtm-35519</MicrosoftAspNetCoreMvcRazorExtensionsPackageVersion>
<MicrosoftAspNetCoreRangeHelperSourcesPackageVersion>2.2.0-rtm-35519</MicrosoftAspNetCoreRangeHelperSourcesPackageVersion>
<MicrosoftAspNetCoreRazorDesignPackageVersion>2.2.0-rtm-35519</MicrosoftAspNetCoreRazorDesignPackageVersion>
<MicrosoftAspNetCoreRazorLanguagePackageVersion>2.2.0-rtm-35519</MicrosoftAspNetCoreRazorLanguagePackageVersion>
<MicrosoftAspNetCoreRazorRuntimePackageVersion>2.2.0-rtm-35519</MicrosoftAspNetCoreRazorRuntimePackageVersion>
<MicrosoftAspNetCoreRazorTagHelpersTestingSourcesPackageVersion>2.2.0-rtm-35519</MicrosoftAspNetCoreRazorTagHelpersTestingSourcesPackageVersion>
<MicrosoftAspNetCoreResponseCachingAbstractionsPackageVersion>2.2.0-rtm-35519</MicrosoftAspNetCoreResponseCachingAbstractionsPackageVersion>
<MicrosoftAspNetCoreResponseCachingPackageVersion>2.2.0-rtm-35519</MicrosoftAspNetCoreResponseCachingPackageVersion>
<MicrosoftAspNetCoreRoutingAbstractionsPackageVersion>2.2.0-a-rtm-allow-required-parameters-17081</MicrosoftAspNetCoreRoutingAbstractionsPackageVersion>
<MicrosoftAspNetCoreRoutingPackageVersion>2.2.0-a-rtm-allow-required-parameters-17081</MicrosoftAspNetCoreRoutingPackageVersion>
<MicrosoftAspNetCoreServerIISIntegrationPackageVersion>2.2.0-rtm-35519</MicrosoftAspNetCoreServerIISIntegrationPackageVersion>
<MicrosoftAspNetCoreServerKestrelPackageVersion>2.2.0-rtm-35519</MicrosoftAspNetCoreServerKestrelPackageVersion>
<MicrosoftAspNetCoreSessionPackageVersion>2.2.0-rtm-35519</MicrosoftAspNetCoreSessionPackageVersion>
<MicrosoftAspNetCoreStaticFilesPackageVersion>2.2.0-rtm-35519</MicrosoftAspNetCoreStaticFilesPackageVersion>
<MicrosoftAspNetCoreTestHostPackageVersion>2.2.0-rtm-35519</MicrosoftAspNetCoreTestHostPackageVersion>
<MicrosoftAspNetCoreTestingPackageVersion>2.2.0-rtm-35519</MicrosoftAspNetCoreTestingPackageVersion>
<MicrosoftAspNetCoreWebUtilitiesPackageVersion>2.2.0-rtm-35519</MicrosoftAspNetCoreWebUtilitiesPackageVersion>
<MicrosoftAspNetWebApiClientPackageVersion>5.2.6</MicrosoftAspNetWebApiClientPackageVersion>
<MicrosoftBuildUtilitiesCorePackageVersion>15.6.82</MicrosoftBuildUtilitiesCorePackageVersion>
<MicrosoftCodeAnalysisCSharpPackageVersion>2.8.0</MicrosoftCodeAnalysisCSharpPackageVersion>
<MicrosoftCodeAnalysisCSharpWorkspacesPackageVersion>2.8.0</MicrosoftCodeAnalysisCSharpWorkspacesPackageVersion>
<MicrosoftCodeAnalysisRazorPackageVersion>2.2.0-rtm-35519</MicrosoftCodeAnalysisRazorPackageVersion>
<MicrosoftDiaSymReaderNativePackageVersion>1.7.0</MicrosoftDiaSymReaderNativePackageVersion>
<MicrosoftExtensionsCachingMemoryPackageVersion>2.2.0-rtm-35519</MicrosoftExtensionsCachingMemoryPackageVersion>
<MicrosoftExtensionsClosedGenericMatcherSourcesPackageVersion>2.2.0-rtm-35519</MicrosoftExtensionsClosedGenericMatcherSourcesPackageVersion>
<MicrosoftExtensionsConfigurationCommandLinePackageVersion>2.2.0-rtm-35519</MicrosoftExtensionsConfigurationCommandLinePackageVersion>
<MicrosoftExtensionsConfigurationJsonPackageVersion>2.2.0-rtm-35519</MicrosoftExtensionsConfigurationJsonPackageVersion>
<MicrosoftExtensionsConfigurationPackageVersion>2.2.0-rtm-35519</MicrosoftExtensionsConfigurationPackageVersion>
<MicrosoftExtensionsCopyOnWriteDictionarySourcesPackageVersion>2.2.0-rtm-35519</MicrosoftExtensionsCopyOnWriteDictionarySourcesPackageVersion>
<MicrosoftExtensionsDependencyInjectionPackageVersion>2.2.0-rtm-35519</MicrosoftExtensionsDependencyInjectionPackageVersion>
<MicrosoftExtensionsDependencyModelPackageVersion>2.1.0</MicrosoftExtensionsDependencyModelPackageVersion>
<MicrosoftNETCoreApp20PackageVersion>2.0.0</MicrosoftNETCoreApp20PackageVersion>
<MicrosoftNETCoreApp21PackageVersion>2.1.2</MicrosoftNETCoreApp21PackageVersion>
<MicrosoftNETSdkRazorPackageVersion>2.1.1</MicrosoftNETSdkRazorPackageVersion>
<MicrosoftExtensionsDiagnosticAdapterPackageVersion>2.2.0-rtm-35519</MicrosoftExtensionsDiagnosticAdapterPackageVersion>
<MicrosoftExtensionsFileProvidersAbstractionsPackageVersion>2.2.0-rtm-35519</MicrosoftExtensionsFileProvidersAbstractionsPackageVersion>
<MicrosoftExtensionsFileProvidersCompositePackageVersion>2.2.0-rtm-35519</MicrosoftExtensionsFileProvidersCompositePackageVersion>
<MicrosoftExtensionsFileProvidersEmbeddedPackageVersion>2.2.0-rtm-35519</MicrosoftExtensionsFileProvidersEmbeddedPackageVersion>
<MicrosoftExtensionsFileSystemGlobbingPackageVersion>2.2.0-rtm-35519</MicrosoftExtensionsFileSystemGlobbingPackageVersion>
<MicrosoftExtensionsHashCodeCombinerSourcesPackageVersion>2.2.0-rtm-35519</MicrosoftExtensionsHashCodeCombinerSourcesPackageVersion>
<MicrosoftExtensionsLocalizationPackageVersion>2.2.0-rtm-35519</MicrosoftExtensionsLocalizationPackageVersion>
<MicrosoftExtensionsLoggingAbstractionsPackageVersion>2.2.0-rtm-35519</MicrosoftExtensionsLoggingAbstractionsPackageVersion>
<MicrosoftExtensionsLoggingConsolePackageVersion>2.2.0-rtm-35519</MicrosoftExtensionsLoggingConsolePackageVersion>
<MicrosoftExtensionsLoggingDebugPackageVersion>2.2.0-rtm-35519</MicrosoftExtensionsLoggingDebugPackageVersion>
<MicrosoftExtensionsLoggingPackageVersion>2.2.0-rtm-35519</MicrosoftExtensionsLoggingPackageVersion>
<MicrosoftExtensionsLoggingTestingPackageVersion>2.2.0-rtm-35519</MicrosoftExtensionsLoggingTestingPackageVersion>
<MicrosoftExtensionsObjectMethodExecutorSourcesPackageVersion>2.2.0-rtm-35519</MicrosoftExtensionsObjectMethodExecutorSourcesPackageVersion>
<MicrosoftExtensionsOptionsPackageVersion>2.2.0-rtm-35519</MicrosoftExtensionsOptionsPackageVersion>
<MicrosoftExtensionsParameterDefaultValueSourcesPackageVersion>2.2.0-rtm-35519</MicrosoftExtensionsParameterDefaultValueSourcesPackageVersion>
<MicrosoftExtensionsPrimitivesPackageVersion>2.2.0-rtm-35519</MicrosoftExtensionsPrimitivesPackageVersion>
<MicrosoftExtensionsPropertyActivatorSourcesPackageVersion>2.2.0-rtm-35519</MicrosoftExtensionsPropertyActivatorSourcesPackageVersion>
<MicrosoftExtensionsPropertyHelperSourcesPackageVersion>2.2.0-rtm-35519</MicrosoftExtensionsPropertyHelperSourcesPackageVersion>
<MicrosoftExtensionsSecurityHelperSourcesPackageVersion>2.2.0-rtm-35519</MicrosoftExtensionsSecurityHelperSourcesPackageVersion>
<MicrosoftExtensionsTypeNameHelperSourcesPackageVersion>2.2.0-rtm-35519</MicrosoftExtensionsTypeNameHelperSourcesPackageVersion>
<MicrosoftExtensionsValueStopwatchSourcesPackageVersion>2.2.0-rtm-35519</MicrosoftExtensionsValueStopwatchSourcesPackageVersion>
<MicrosoftExtensionsWebEncodersPackageVersion>2.2.0-rtm-35519</MicrosoftExtensionsWebEncodersPackageVersion>
<MicrosoftNETCoreApp20PackageVersion>2.0.9</MicrosoftNETCoreApp20PackageVersion>
<MicrosoftNETCoreApp21PackageVersion>2.1.3</MicrosoftNETCoreApp21PackageVersion>
<MicrosoftNETCoreApp22PackageVersion>2.2.0-preview3-27014-02</MicrosoftNETCoreApp22PackageVersion>
<MicrosoftNetHttpHeadersPackageVersion>2.2.0-rtm-35519</MicrosoftNetHttpHeadersPackageVersion>
<MicrosoftNETSdkRazorPackageVersion>2.2.0-rtm-35519</MicrosoftNETSdkRazorPackageVersion>
<MicrosoftNETTestSdkPackageVersion>15.6.1</MicrosoftNETTestSdkPackageVersion>
<MoqPackageVersion>4.7.49</MoqPackageVersion>
<MoqPackageVersion>4.10.0</MoqPackageVersion>
<NETStandardLibrary20PackageVersion>2.0.3</NETStandardLibrary20PackageVersion>
<NewtonsoftJsonBsonPackageVersion>1.0.1</NewtonsoftJsonBsonPackageVersion>
<NewtonsoftJsonPackageVersion>11.0.2</NewtonsoftJsonPackageVersion>
<SystemComponentModelAnnotationsPackageVersion>4.5.0</SystemComponentModelAnnotationsPackageVersion>
<SystemDiagnosticsDiagnosticSourcePackageVersion>4.5.0</SystemDiagnosticsDiagnosticSourcePackageVersion>
<SystemNetHttpPackageVersion>4.3.2</SystemNetHttpPackageVersion>
<SystemThreadingTasksExtensionsPackageVersion>4.5.1</SystemThreadingTasksExtensionsPackageVersion>
<XunitAnalyzersPackageVersion>0.8.0</XunitAnalyzersPackageVersion>
<XunitAnalyzersPackageVersion>0.10.0</XunitAnalyzersPackageVersion>
<XunitPackageVersion>2.3.1</XunitPackageVersion>
<XunitRunnerVisualStudioPackageVersion>2.4.0-beta.1.build3945</XunitRunnerVisualStudioPackageVersion>
<XunitRunnerVisualStudioPackageVersion>2.4.0</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">
<MicrosoftAspNetCoreAntiforgeryPackageVersion>2.1.1</MicrosoftAspNetCoreAntiforgeryPackageVersion>
<MicrosoftAspNetCoreAuthenticationCookiesPackageVersion>2.1.1</MicrosoftAspNetCoreAuthenticationCookiesPackageVersion>
<MicrosoftAspNetCoreAuthenticationCorePackageVersion>2.1.1</MicrosoftAspNetCoreAuthenticationCorePackageVersion>
<MicrosoftAspNetCoreAuthenticationPackageVersion>2.1.1</MicrosoftAspNetCoreAuthenticationPackageVersion>
<MicrosoftAspNetCoreAuthorizationPolicyPackageVersion>2.1.1</MicrosoftAspNetCoreAuthorizationPolicyPackageVersion>
<MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>2.1.1</MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>
<MicrosoftAspNetCoreChunkingCookieManagerSourcesPackageVersion>2.1.1</MicrosoftAspNetCoreChunkingCookieManagerSourcesPackageVersion>
<MicrosoftAspNetCoreCookiePolicyPackageVersion>2.1.1</MicrosoftAspNetCoreCookiePolicyPackageVersion>
<MicrosoftAspNetCoreCorsPackageVersion>2.1.1</MicrosoftAspNetCoreCorsPackageVersion>
<MicrosoftAspNetCoreDiagnosticsAbstractionsPackageVersion>2.1.1</MicrosoftAspNetCoreDiagnosticsAbstractionsPackageVersion>
<MicrosoftAspNetCoreDiagnosticsPackageVersion>2.1.1</MicrosoftAspNetCoreDiagnosticsPackageVersion>
<MicrosoftAspNetCoreHostingAbstractionsPackageVersion>2.1.1</MicrosoftAspNetCoreHostingAbstractionsPackageVersion>
<MicrosoftAspNetCoreHostingPackageVersion>2.1.1</MicrosoftAspNetCoreHostingPackageVersion>
<MicrosoftAspNetCoreHtmlAbstractionsPackageVersion>2.1.1</MicrosoftAspNetCoreHtmlAbstractionsPackageVersion>
<MicrosoftAspNetCoreHttpExtensionsPackageVersion>2.1.1</MicrosoftAspNetCoreHttpExtensionsPackageVersion>
<MicrosoftAspNetCoreHttpPackageVersion>2.1.1</MicrosoftAspNetCoreHttpPackageVersion>
<MicrosoftAspNetCoreJsonPatchPackageVersion>2.1.1</MicrosoftAspNetCoreJsonPatchPackageVersion>
<MicrosoftAspNetCoreLocalizationPackageVersion>2.1.1</MicrosoftAspNetCoreLocalizationPackageVersion>
<MicrosoftAspNetCoreLocalizationRoutingPackageVersion>2.1.1</MicrosoftAspNetCoreLocalizationRoutingPackageVersion>
<MicrosoftAspNetCoreMvcRazorExtensionsPackageVersion>2.1.1</MicrosoftAspNetCoreMvcRazorExtensionsPackageVersion>
<MicrosoftAspNetCoreRangeHelperSourcesPackageVersion>2.1.1</MicrosoftAspNetCoreRangeHelperSourcesPackageVersion>
<MicrosoftAspNetCoreRazorDesignPackageVersion>2.1.1</MicrosoftAspNetCoreRazorDesignPackageVersion>
<MicrosoftAspNetCoreRazorLanguagePackageVersion>2.1.1</MicrosoftAspNetCoreRazorLanguagePackageVersion>
<MicrosoftAspNetCoreRazorRuntimePackageVersion>2.1.1</MicrosoftAspNetCoreRazorRuntimePackageVersion>
<MicrosoftAspNetCoreRazorTagHelpersTestingSourcesPackageVersion>2.1.1</MicrosoftAspNetCoreRazorTagHelpersTestingSourcesPackageVersion>
<MicrosoftAspNetCoreResponseCachingAbstractionsPackageVersion>2.1.1</MicrosoftAspNetCoreResponseCachingAbstractionsPackageVersion>
<MicrosoftAspNetCoreResponseCachingPackageVersion>2.1.1</MicrosoftAspNetCoreResponseCachingPackageVersion>
<MicrosoftAspNetCoreRoutingAbstractionsPackageVersion>2.1.1</MicrosoftAspNetCoreRoutingAbstractionsPackageVersion>
<MicrosoftAspNetCoreRoutingPackageVersion>2.1.1</MicrosoftAspNetCoreRoutingPackageVersion>
<MicrosoftAspNetCoreServerIISIntegrationPackageVersion>2.1.1</MicrosoftAspNetCoreServerIISIntegrationPackageVersion>
<MicrosoftAspNetCoreServerKestrelPackageVersion>2.1.2</MicrosoftAspNetCoreServerKestrelPackageVersion>
<MicrosoftAspNetCoreSessionPackageVersion>2.1.1</MicrosoftAspNetCoreSessionPackageVersion>
<MicrosoftAspNetCoreStaticFilesPackageVersion>2.1.1</MicrosoftAspNetCoreStaticFilesPackageVersion>
<MicrosoftAspNetCoreTestHostPackageVersion>2.1.1</MicrosoftAspNetCoreTestHostPackageVersion>
<MicrosoftAspNetCoreTestingPackageVersion>2.1.0</MicrosoftAspNetCoreTestingPackageVersion>
<MicrosoftAspNetCoreWebUtilitiesPackageVersion>2.1.1</MicrosoftAspNetCoreWebUtilitiesPackageVersion>
<MicrosoftCodeAnalysisRazorPackageVersion>2.1.1</MicrosoftCodeAnalysisRazorPackageVersion>
<MicrosoftExtensionsCachingMemoryPackageVersion>2.1.1</MicrosoftExtensionsCachingMemoryPackageVersion>
<MicrosoftExtensionsClosedGenericMatcherSourcesPackageVersion>2.1.1</MicrosoftExtensionsClosedGenericMatcherSourcesPackageVersion>
<MicrosoftExtensionsConfigurationJsonPackageVersion>2.1.1</MicrosoftExtensionsConfigurationJsonPackageVersion>
<MicrosoftExtensionsConfigurationPackageVersion>2.1.1</MicrosoftExtensionsConfigurationPackageVersion>
<MicrosoftExtensionsCopyOnWriteDictionarySourcesPackageVersion>2.1.1</MicrosoftExtensionsCopyOnWriteDictionarySourcesPackageVersion>
<MicrosoftExtensionsDependencyInjectionPackageVersion>2.1.1</MicrosoftExtensionsDependencyInjectionPackageVersion>
<MicrosoftExtensionsDiagnosticAdapterPackageVersion>2.1.0</MicrosoftExtensionsDiagnosticAdapterPackageVersion>
<MicrosoftExtensionsFileProvidersAbstractionsPackageVersion>2.1.1</MicrosoftExtensionsFileProvidersAbstractionsPackageVersion>
<MicrosoftExtensionsFileProvidersCompositePackageVersion>2.1.1</MicrosoftExtensionsFileProvidersCompositePackageVersion>
<MicrosoftExtensionsFileProvidersEmbeddedPackageVersion>2.1.1</MicrosoftExtensionsFileProvidersEmbeddedPackageVersion>
<MicrosoftExtensionsFileSystemGlobbingPackageVersion>2.1.1</MicrosoftExtensionsFileSystemGlobbingPackageVersion>
<MicrosoftExtensionsHashCodeCombinerSourcesPackageVersion>2.1.1</MicrosoftExtensionsHashCodeCombinerSourcesPackageVersion>
<MicrosoftExtensionsLocalizationPackageVersion>2.1.1</MicrosoftExtensionsLocalizationPackageVersion>
<MicrosoftExtensionsLoggingAbstractionsPackageVersion>2.1.1</MicrosoftExtensionsLoggingAbstractionsPackageVersion>
<MicrosoftExtensionsLoggingConsolePackageVersion>2.1.1</MicrosoftExtensionsLoggingConsolePackageVersion>
<MicrosoftExtensionsLoggingDebugPackageVersion>2.1.1</MicrosoftExtensionsLoggingDebugPackageVersion>
<MicrosoftExtensionsLoggingPackageVersion>2.1.1</MicrosoftExtensionsLoggingPackageVersion>
<MicrosoftExtensionsLoggingTestingPackageVersion>2.1.1</MicrosoftExtensionsLoggingTestingPackageVersion>
<MicrosoftExtensionsObjectMethodExecutorSourcesPackageVersion>2.1.1</MicrosoftExtensionsObjectMethodExecutorSourcesPackageVersion>
<MicrosoftExtensionsOptionsPackageVersion>2.1.1</MicrosoftExtensionsOptionsPackageVersion>
<MicrosoftExtensionsParameterDefaultValueSourcesPackageVersion>2.1.1</MicrosoftExtensionsParameterDefaultValueSourcesPackageVersion>
<MicrosoftExtensionsPrimitivesPackageVersion>2.1.1</MicrosoftExtensionsPrimitivesPackageVersion>
<MicrosoftExtensionsPropertyActivatorSourcesPackageVersion>2.1.1</MicrosoftExtensionsPropertyActivatorSourcesPackageVersion>
<MicrosoftExtensionsPropertyHelperSourcesPackageVersion>2.1.1</MicrosoftExtensionsPropertyHelperSourcesPackageVersion>
<MicrosoftExtensionsSecurityHelperSourcesPackageVersion>2.1.1</MicrosoftExtensionsSecurityHelperSourcesPackageVersion>
<MicrosoftExtensionsTypeNameHelperSourcesPackageVersion>2.1.1</MicrosoftExtensionsTypeNameHelperSourcesPackageVersion>
<MicrosoftExtensionsValueStopwatchSourcesPackageVersion>2.1.1</MicrosoftExtensionsValueStopwatchSourcesPackageVersion>
<MicrosoftExtensionsWebEncodersPackageVersion>2.1.1</MicrosoftExtensionsWebEncodersPackageVersion>
<MicrosoftNetHttpHeadersPackageVersion>2.1.1</MicrosoftNetHttpHeadersPackageVersion>
</PropertyGroup>
<PropertyGroup Label="Package Versions: Pinned" />
</Project>

View File

@ -6,18 +6,20 @@
</PropertyGroup>
<ItemGroup>
<ExcludeFromTest Include="$(RepositoryRoot)test\Microsoft.AspNetCore.Mvc.TestCommon\*.csproj" />
<ExcludeFromTest Include="$(RepositoryRoot)test\Microsoft.AspNetCore.Mvc.Core.TestCommon\*.csproj" />
<ExcludeFromTest Include="$(RepositoryRoot)test\Microsoft.AspNetCore.Mvc.Views.TestCommon\*.csproj" />
<ExcludeFromTest Include="$(RepositoryRoot)test\Microsoft.AspNetCore.Mvc.TestDiagnosticListener\*.csproj" />
<ExcludeSolutions Include="$(RepositoryRoot)Mvc.*Fun.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>
<LineupPackageVersion>2.2.0-*</LineupPackageVersion>
<LineupPackageRestoreSource>https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json</LineupPackageRestoreSource>
</PropertyGroup>
<ItemGroup>
<DotNetCoreRuntime Include="$(MicrosoftNETCoreApp21PackageVersion)" />
<DotNetCoreRuntime Include="$(MicrosoftNETCoreApp22PackageVersion)" />
</ItemGroup>
</Project>

8
src/Mvc/global.json Normal file
View File

@ -0,0 +1,8 @@
{
"sdk": {
"version": "2.2.100-preview2-009404"
},
"msbuild-sdks": {
"Internal.AspNetCore.Sdk": "2.2.0-preview2-20181003.2"
}
}

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFrameworks>netcoreapp2.1</TargetFrameworks>
<TargetFrameworks>netcoreapp2.2</TargetFrameworks>
<TargetFrameworks Condition=" '$(DeveloperBuild)' != 'true' AND '$(OS)' == 'Windows_NT' ">$(TargetFrameworks);net461</TargetFrameworks>
</PropertyGroup>

View File

@ -14,7 +14,7 @@ namespace MvcSandbox
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(Microsoft.AspNetCore.Mvc.CompatibilityVersion.Version_2_1);
services.AddMvc().SetCompatibilityVersion(Microsoft.AspNetCore.Mvc.CompatibilityVersion.Latest);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.

View File

@ -2,6 +2,6 @@
<Import Project="..\Directory.Build.props" />
<ItemGroup>
<PackageReference Include="Internal.AspNetCore.Sdk" PrivateAssets="All" Version="$(InternalAspNetCoreSdkPackageVersion)" />
<PackageReference Include="Internal.AspNetCore.Analyzers" PrivateAssets="All" Version="$(InternalAspNetCoreAnalyzersPackageVersion)" />
</ItemGroup>
</Project>

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 System;
namespace Microsoft.Extensions.ApiDescription.Tool
{
internal class AnsiConsole
{
public static readonly AnsiTextWriter _out = new AnsiTextWriter(Console.Out);
public static void WriteLine(string text)
=> _out.WriteLine(text);
}
}

View File

@ -0,0 +1,20 @@
// 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.Extensions.ApiDescription.Tool
{
internal static class AnsiConstants
{
public const string Reset = "\x1b[22m\x1b[39m";
public const string Bold = "\x1b[1m";
public const string Dark = "\x1b[22m";
public const string Black = "\x1b[30m";
public const string Red = "\x1b[31m";
public const string Green = "\x1b[32m";
public const string Yellow = "\x1b[33m";
public const string Blue = "\x1b[34m";
public const string Magenta = "\x1b[35m";
public const string Cyan = "\x1b[36m";
public const string Gray = "\x1b[37m";
}
}

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;
using System.Diagnostics;
using System.IO;
using System.Text.RegularExpressions;
namespace Microsoft.Extensions.ApiDescription.Tool
{
internal class AnsiTextWriter
{
private readonly TextWriter _writer;
public AnsiTextWriter(TextWriter writer) => _writer = writer;
public void WriteLine(string text)
{
Interpret(text);
_writer.Write(Environment.NewLine);
}
private void Interpret(string value)
{
var matches = Regex.Matches(value, "\x1b\\[([0-9]+)?m");
var start = 0;
foreach (Match match in matches)
{
var length = match.Index - start;
if (length != 0)
{
_writer.Write(value.Substring(start, length));
}
Apply(match.Groups[1].Value);
start = match.Index + match.Length;
}
if (start != value.Length)
{
_writer.Write(value.Substring(start));
}
}
private static void Apply(string parameter)
{
switch (parameter)
{
case "1":
ApplyBold();
break;
case "22":
ResetBold();
break;
case "30":
ApplyColor(ConsoleColor.Black);
break;
case "31":
ApplyColor(ConsoleColor.DarkRed);
break;
case "32":
ApplyColor(ConsoleColor.DarkGreen);
break;
case "33":
ApplyColor(ConsoleColor.DarkYellow);
break;
case "34":
ApplyColor(ConsoleColor.DarkBlue);
break;
case "35":
ApplyColor(ConsoleColor.DarkMagenta);
break;
case "36":
ApplyColor(ConsoleColor.DarkCyan);
break;
case "37":
ApplyColor(ConsoleColor.Gray);
break;
case "39":
ResetColor();
break;
default:
Debug.Fail("Unsupported parameter: " + parameter);
break;
}
}
private static void ApplyBold()
=> Console.ForegroundColor = (ConsoleColor)((int)Console.ForegroundColor | 8);
private static void ResetBold()
=> Console.ForegroundColor = (ConsoleColor)((int)Console.ForegroundColor & 7);
private static void ApplyColor(ConsoleColor color)
{
var wasBold = ((int)Console.ForegroundColor & 8) != 0;
Console.ForegroundColor = color;
if (wasBold)
{
ApplyBold();
}
}
private static void ResetColor()
{
var wasBold = ((int)Console.ForegroundColor & 8) != 0;
Console.ResetColor();
if (wasBold)
{
ApplyBold();
}
}
}
}

View File

@ -0,0 +1,20 @@
// 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.Extensions.ApiDescription.Tool
{
internal class CommandException : Exception
{
public CommandException(string message)
: base(message)
{
}
public CommandException(string message, Exception innerException)
: base(message, innerException)
{
}
}
}

View File

@ -0,0 +1,19 @@
// 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;
namespace Microsoft.DotNet.Cli.CommandLine
{
internal class CommandArgument
{
public CommandArgument() => Values = new List<string>();
public string Name { get; set; }
public string Description { get; set; }
public List<string> Values { get; private set; }
public bool MultipleValues { get; set; }
public string Value => Values.FirstOrDefault();
}
}

View File

@ -0,0 +1,604 @@
// 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;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.DotNet.Cli.CommandLine
{
internal class CommandLineApplication
{
private enum ParseOptionResult
{
Succeeded,
ShowHelp,
ShowVersion,
UnexpectedArgs,
}
// Indicates whether the parser should throw an exception when it runs into an unexpected argument.
// If this field is set to false, the parser will stop parsing when it sees an unexpected argument, and all
// remaining arguments, including the first unexpected argument, will be stored in RemainingArguments property.
private readonly bool _throwOnUnexpectedArg;
public CommandLineApplication(bool throwOnUnexpectedArg = true)
{
_throwOnUnexpectedArg = throwOnUnexpectedArg;
Options = new List<CommandOption>();
Arguments = new List<CommandArgument>();
Commands = new List<CommandLineApplication>();
RemainingArguments = new List<string>();
Invoke = () => 0;
}
public CommandLineApplication Parent { get; set; }
public string Name { get; set; }
public string FullName { get; set; }
public string Syntax { get; set; }
public string Description { get; set; }
public List<CommandOption> Options { get; private set; }
public CommandOption OptionHelp { get; private set; }
public CommandOption OptionVersion { get; private set; }
public List<CommandArgument> Arguments { get; private set; }
public List<string> RemainingArguments { get; private set; }
public bool IsShowingInformation { get; protected set; } // Is showing help or version?
public Func<int> Invoke { get; set; }
public Func<string> LongVersionGetter { get; set; }
public Func<string> ShortVersionGetter { get; set; }
public List<CommandLineApplication> Commands { get; private set; }
public bool HandleResponseFiles { get; set; }
public bool AllowArgumentSeparator { get; set; }
public bool HandleRemainingArguments { get; set; }
public string ArgumentSeparatorHelpText { get; set; }
public CommandLineApplication Command(string name, bool throwOnUnexpectedArg = true)
=> Command(name, _ => { }, throwOnUnexpectedArg);
public CommandLineApplication Command(string name, Action<CommandLineApplication> configuration,
bool throwOnUnexpectedArg = true)
{
var command = new CommandLineApplication(throwOnUnexpectedArg) { Name = name, Parent = this };
Commands.Add(command);
configuration(command);
return command;
}
public CommandOption Option(string template, string description, CommandOptionType optionType)
=> Option(template, description, optionType, _ => { });
public CommandOption Option(string template, string description, CommandOptionType optionType, Action<CommandOption> configuration)
{
var option = new CommandOption(template, optionType) { Description = description };
Options.Add(option);
configuration(option);
return option;
}
public CommandArgument Argument(string name, string description, bool multipleValues = false)
=> Argument(name, description, _ => { }, multipleValues);
public CommandArgument Argument(string name, string description, Action<CommandArgument> configuration, bool multipleValues = false)
{
var lastArg = Arguments.LastOrDefault();
if (lastArg != null && lastArg.MultipleValues)
{
var message = string.Format("The last argument '{0}' accepts multiple values. No more argument can be added.",
lastArg.Name);
throw new InvalidOperationException(message);
}
var argument = new CommandArgument { Name = name, Description = description, MultipleValues = multipleValues };
Arguments.Add(argument);
configuration(argument);
return argument;
}
public void OnExecute(Func<int> invoke) => Invoke = invoke;
public void OnExecute(Func<Task<int>> invoke) => Invoke = () => invoke().Result;
public int Execute(params string[] args)
{
var command = this;
IEnumerator<CommandArgument> arguments = null;
if (HandleResponseFiles)
{
args = ExpandResponseFiles(args).ToArray();
}
for (var index = 0; index < args.Length; index++)
{
var arg = args[index];
var isLongOption = arg.StartsWith("--");
if (isLongOption || arg.StartsWith("-"))
{
var result = ParseOption(isLongOption, command, args, ref index, out var option);
if (result == ParseOptionResult.ShowHelp)
{
command.ShowHelp();
return 0;
}
else if (result == ParseOptionResult.ShowVersion)
{
command.ShowVersion();
return 0;
}
}
else
{
var subcommand = ParseSubCommand(arg, command);
if (subcommand != null)
{
command = subcommand;
}
else
{
if (arguments == null)
{
arguments = new CommandArgumentEnumerator(command.Arguments.GetEnumerator());
}
if (arguments.MoveNext())
{
arguments.Current.Values.Add(arg);
}
else
{
HandleUnexpectedArg(command, args, index, argTypeName: "command or argument");
}
}
}
}
return command.Invoke();
}
private ParseOptionResult ParseOption(
bool isLongOption,
CommandLineApplication command,
string[] args,
ref int index,
out CommandOption option)
{
option = null;
var result = ParseOptionResult.Succeeded;
var arg = args[index];
var optionPrefixLength = isLongOption ? 2 : 1;
var optionComponents = arg.Substring(optionPrefixLength).Split(new[] { ':', '=' }, 2);
var optionName = optionComponents[0];
if (isLongOption)
{
option = command.Options.SingleOrDefault(
opt => string.Equals(opt.LongName, optionName, StringComparison.Ordinal));
}
else
{
option = command.Options.SingleOrDefault(
opt => string.Equals(opt.ShortName, optionName, StringComparison.Ordinal));
if (option == null)
{
option = command.Options.SingleOrDefault(
opt => string.Equals(opt.SymbolName, optionName, StringComparison.Ordinal));
}
}
if (option == null)
{
if (isLongOption && string.IsNullOrEmpty(optionName) &&
!command._throwOnUnexpectedArg && AllowArgumentSeparator)
{
// a stand-alone "--" is the argument separator, so skip it and
// handle the rest of the args as unexpected args
index++;
}
HandleUnexpectedArg(command, args, index, argTypeName: "option");
result = ParseOptionResult.UnexpectedArgs;
}
else if (command.OptionHelp == option)
{
result = ParseOptionResult.ShowHelp;
}
else if (command.OptionVersion == option)
{
result = ParseOptionResult.ShowVersion;
}
else
{
if (optionComponents.Length == 2)
{
if (!option.TryParse(optionComponents[1]))
{
command.ShowHint();
throw new CommandParsingException(command,
$"Unexpected value '{optionComponents[1]}' for option '{optionName}'");
}
}
else
{
if (option.OptionType == CommandOptionType.NoValue ||
option.OptionType == CommandOptionType.BoolValue)
{
// No value is needed for this option
option.TryParse(null);
}
else
{
index++;
arg = args[index];
if (!option.TryParse(arg))
{
command.ShowHint();
throw new CommandParsingException(command, $"Unexpected value '{arg}' for option '{optionName}'");
}
}
}
}
return result;
}
private static CommandLineApplication ParseSubCommand(string arg, CommandLineApplication command)
{
foreach (var subcommand in command.Commands)
{
if (string.Equals(subcommand.Name, arg, StringComparison.OrdinalIgnoreCase))
{
return subcommand;
}
}
return null;
}
// Helper method that adds a help option
public CommandOption HelpOption(string template)
{
// Help option is special because we stop parsing once we see it
// So we store it separately for further use
OptionHelp = Option(template, "Show help information", CommandOptionType.NoValue);
return OptionHelp;
}
public CommandOption VersionOption(string template,
string shortFormVersion,
string longFormVersion = null)
{
if (longFormVersion == null)
{
return VersionOption(template, () => shortFormVersion);
}
else
{
return VersionOption(template, () => shortFormVersion, () => longFormVersion);
}
}
// Helper method that adds a version option
public CommandOption VersionOption(string template,
Func<string> shortFormVersionGetter,
Func<string> longFormVersionGetter = null)
{
// Version option is special because we stop parsing once we see it
// So we store it separately for further use
OptionVersion = Option(template, "Show version information", CommandOptionType.NoValue);
ShortVersionGetter = shortFormVersionGetter;
LongVersionGetter = longFormVersionGetter ?? shortFormVersionGetter;
return OptionVersion;
}
// Show short hint that reminds users to use help option
public void ShowHint()
{
if (OptionHelp != null)
{
Console.WriteLine(string.Format("Specify --{0} for a list of available options and commands.", OptionHelp.LongName));
}
}
// Show full help
public void ShowHelp(string commandName = null)
{
var headerBuilder = new StringBuilder("Usage:");
var usagePrefixLength = headerBuilder.Length;
for (var cmd = this; cmd != null; cmd = cmd.Parent)
{
cmd.IsShowingInformation = true;
if (cmd != this && cmd.Arguments.Any())
{
var args = string.Join(" ", cmd.Arguments.Select(arg => arg.Name));
headerBuilder.Insert(usagePrefixLength, string.Format(" {0} {1}", cmd.Name, args));
}
else
{
headerBuilder.Insert(usagePrefixLength, string.Format(" {0}", cmd.Name));
}
}
CommandLineApplication target;
if (commandName == null || string.Equals(Name, commandName, StringComparison.OrdinalIgnoreCase))
{
target = this;
}
else
{
target = Commands.SingleOrDefault(cmd => string.Equals(cmd.Name, commandName, StringComparison.OrdinalIgnoreCase));
if (target != null)
{
headerBuilder.AppendFormat(" {0}", commandName);
}
else
{
// The command name is invalid so don't try to show help for something that doesn't exist
target = this;
}
}
var optionsBuilder = new StringBuilder();
var commandsBuilder = new StringBuilder();
var argumentsBuilder = new StringBuilder();
var argumentSeparatorBuilder = new StringBuilder();
var maxArgLen = 0;
for (var cmd = target; cmd != null; cmd = cmd.Parent)
{
if (cmd.Arguments.Any())
{
if (cmd == target)
{
headerBuilder.Append(" [arguments]");
}
if (argumentsBuilder.Length == 0)
{
argumentsBuilder.AppendLine();
argumentsBuilder.AppendLine("Arguments:");
}
maxArgLen = Math.Max(maxArgLen, MaxArgumentLength(cmd.Arguments));
}
}
for (var cmd = target; cmd != null; cmd = cmd.Parent)
{
if (cmd.Arguments.Any())
{
var outputFormat = " {0}{1}";
foreach (var arg in cmd.Arguments)
{
argumentsBuilder.AppendFormat(
outputFormat,
arg.Name.PadRight(maxArgLen + 2),
arg.Description);
argumentsBuilder.AppendLine();
}
}
}
if (target.Options.Any())
{
headerBuilder.Append(" [options]");
optionsBuilder.AppendLine();
optionsBuilder.AppendLine("Options:");
var maxOptLen = MaxOptionTemplateLength(target.Options);
var outputFormat = string.Format(" {{0, -{0}}}{{1}}", maxOptLen + 2);
foreach (var opt in target.Options)
{
optionsBuilder.AppendFormat(outputFormat, opt.Template, opt.Description);
optionsBuilder.AppendLine();
}
}
if (target.Commands.Any())
{
headerBuilder.Append(" [command]");
commandsBuilder.AppendLine();
commandsBuilder.AppendLine("Commands:");
var maxCmdLen = MaxCommandLength(target.Commands);
var outputFormat = string.Format(" {{0, -{0}}}{{1}}", maxCmdLen + 2);
foreach (var cmd in target.Commands.OrderBy(c => c.Name))
{
commandsBuilder.AppendFormat(outputFormat, cmd.Name, cmd.Description);
commandsBuilder.AppendLine();
}
if (OptionHelp != null)
{
commandsBuilder.AppendLine();
commandsBuilder.AppendFormat("Use \"{0} [command] --help\" for more information about a command.", Name);
commandsBuilder.AppendLine();
}
}
if (target.AllowArgumentSeparator || target.HandleRemainingArguments)
{
if (target.AllowArgumentSeparator)
{
headerBuilder.Append(" [[--] <arg>...]]");
}
else
{
headerBuilder.Append(" [args]");
}
if (!string.IsNullOrEmpty(target.ArgumentSeparatorHelpText))
{
argumentSeparatorBuilder.AppendLine();
argumentSeparatorBuilder.AppendLine("Args:");
argumentSeparatorBuilder.AppendLine($" {target.ArgumentSeparatorHelpText}");
argumentSeparatorBuilder.AppendLine();
}
}
headerBuilder.AppendLine();
var nameAndVersion = new StringBuilder();
nameAndVersion.AppendLine(GetFullNameAndVersion());
nameAndVersion.AppendLine();
Console.Write("{0}{1}{2}{3}{4}{5}", nameAndVersion, headerBuilder, argumentsBuilder, optionsBuilder, commandsBuilder, argumentSeparatorBuilder);
}
public void ShowVersion()
{
for (var cmd = this; cmd != null; cmd = cmd.Parent)
{
cmd.IsShowingInformation = true;
}
Console.WriteLine(FullName);
Console.WriteLine(LongVersionGetter());
}
public string GetFullNameAndVersion()
=> ShortVersionGetter == null ? FullName : string.Format("{0} {1}", FullName, ShortVersionGetter());
public void ShowRootCommandFullNameAndVersion()
{
var rootCmd = this;
while (rootCmd.Parent != null)
{
rootCmd = rootCmd.Parent;
}
Console.WriteLine(rootCmd.GetFullNameAndVersion());
Console.WriteLine();
}
private static int MaxOptionTemplateLength(IEnumerable<CommandOption> options)
{
var maxLen = 0;
foreach (var opt in options)
{
maxLen = opt.Template.Length > maxLen ? opt.Template.Length : maxLen;
}
return maxLen;
}
private static int MaxCommandLength(IEnumerable<CommandLineApplication> commands)
{
var maxLen = 0;
foreach (var cmd in commands)
{
maxLen = cmd.Name.Length > maxLen ? cmd.Name.Length : maxLen;
}
return maxLen;
}
private static int MaxArgumentLength(IEnumerable<CommandArgument> arguments)
{
var maxLen = 0;
foreach (var arg in arguments)
{
maxLen = arg.Name.Length > maxLen ? arg.Name.Length : maxLen;
}
return maxLen;
}
private static void HandleUnexpectedArg(CommandLineApplication command, string[] args, int index, string argTypeName)
{
if (command._throwOnUnexpectedArg)
{
command.ShowHint();
throw new CommandParsingException(command, $"Unrecognized {argTypeName} '{args[index]}'");
}
else
{
command.RemainingArguments.Add(args[index]);
}
}
private IEnumerable<string> ExpandResponseFiles(IEnumerable<string> args)
{
foreach (var arg in args)
{
if (!arg.StartsWith("@", StringComparison.Ordinal))
{
yield return arg;
}
else
{
var fileName = arg.Substring(1);
var responseFileArguments = ParseResponseFile(fileName);
// ParseResponseFile can suppress expanding this response file by
// returning null. In that case, we'll treat the response
// file token as a regular argument.
if (responseFileArguments == null)
{
yield return arg;
}
else
{
foreach (var responseFileArgument in responseFileArguments)
{
yield return responseFileArgument.Trim();
}
}
}
}
}
private IEnumerable<string> ParseResponseFile(string fileName)
{
if (!HandleResponseFiles)
{
return null;
}
if (!File.Exists(fileName))
{
throw new InvalidOperationException($"Response file '{fileName}' doesn't exist.");
}
return File.ReadLines(fileName);
}
private class CommandArgumentEnumerator : IEnumerator<CommandArgument>
{
private readonly IEnumerator<CommandArgument> _enumerator;
public CommandArgumentEnumerator(IEnumerator<CommandArgument> enumerator) => _enumerator = enumerator;
public CommandArgument Current => _enumerator.Current;
object IEnumerator.Current => Current;
public void Dispose() => _enumerator.Dispose();
public bool MoveNext()
{
if (Current == null || !Current.MultipleValues)
{
return _enumerator.MoveNext();
}
// If current argument allows multiple values, we don't move forward and
// all later values will be added to current CommandArgument.Values
return true;
}
public void Reset() => _enumerator.Reset();
}
}
}

View File

@ -0,0 +1,18 @@
// 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.DotNet.Cli.CommandLine
{
internal static class CommandLineApplicationExtensions
{
public static CommandOption Option(this CommandLineApplication command, string template, string description)
=> command.Option(
template,
description,
template.IndexOf('<') != -1
? template.EndsWith(">...")
? CommandOptionType.MultipleValue
: CommandOptionType.SingleValue
: CommandOptionType.NoValue);
}
}

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;
using System.Collections.Generic;
using System.Linq;
namespace Microsoft.DotNet.Cli.CommandLine
{
internal class CommandOption
{
public CommandOption(string template, CommandOptionType optionType)
{
Template = template;
OptionType = optionType;
Values = new List<string>();
foreach (var part in Template.Split(new[] { ' ', '|' }, StringSplitOptions.RemoveEmptyEntries))
{
if (part.StartsWith("--"))
{
LongName = part.Substring(2);
}
else if (part.StartsWith("-"))
{
var optName = part.Substring(1);
// If there is only one char and it is not an English letter, it is a symbol option (e.g. "-?")
if (optName.Length == 1 && !IsEnglishLetter(optName[0]))
{
SymbolName = optName;
}
else
{
ShortName = optName;
}
}
else if (part.StartsWith("<") && part.EndsWith(">"))
{
ValueName = part.Substring(1, part.Length - 2);
}
else if (optionType == CommandOptionType.MultipleValue && part.StartsWith("<") && part.EndsWith(">..."))
{
ValueName = part.Substring(1, part.Length - 5);
}
else
{
throw new ArgumentException($"Invalid template pattern '{template}'", nameof(template));
}
}
if (string.IsNullOrEmpty(LongName) && string.IsNullOrEmpty(ShortName) && string.IsNullOrEmpty(SymbolName))
{
throw new ArgumentException($"Invalid template pattern '{template}'", nameof(template));
}
}
public string Template { get; set; }
public string ShortName { get; set; }
public string LongName { get; set; }
public string SymbolName { get; set; }
public string ValueName { get; set; }
public string Description { get; set; }
public List<string> Values { get; private set; }
public bool? BoolValue { get; private set; }
public CommandOptionType OptionType { get; private set; }
public bool TryParse(string value)
{
switch (OptionType)
{
case CommandOptionType.MultipleValue:
Values.Add(value);
break;
case CommandOptionType.SingleValue:
if (Values.Any())
{
return false;
}
Values.Add(value);
break;
case CommandOptionType.BoolValue:
if (Values.Any())
{
return false;
}
if (value == null)
{
// add null to indicate that the option was present, but had no value
Values.Add(null);
BoolValue = true;
}
else
{
if (!bool.TryParse(value, out var boolValue))
{
return false;
}
Values.Add(value);
BoolValue = boolValue;
}
break;
case CommandOptionType.NoValue:
if (value != null)
{
return false;
}
// Add a value to indicate that this option was specified
Values.Add("on");
break;
default:
break;
}
return true;
}
public bool HasValue() => Values.Any();
public string Value() => HasValue() ? Values[0] : null;
private static bool IsEnglishLetter(char c) => (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}
}

View File

@ -0,0 +1,13 @@
// 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.DotNet.Cli.CommandLine
{
internal enum CommandOptionType
{
MultipleValue,
SingleValue,
BoolValue,
NoValue
}
}

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 System;
namespace Microsoft.DotNet.Cli.CommandLine
{
internal class CommandParsingException : Exception
{
public CommandParsingException(CommandLineApplication command, string message)
: base(message) => Command = command;
public CommandLineApplication Command { get; }
}
}

View File

@ -0,0 +1,38 @@
// 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.DotNet.Cli.CommandLine;
namespace Microsoft.Extensions.ApiDescription.Tool.Commands
{
internal abstract class CommandBase
{
public virtual void Configure(CommandLineApplication command)
{
var verbose = command.Option("-v|--verbose", Resources.VerboseDescription);
var noColor = command.Option("--no-color", Resources.NoColorDescription);
var prefixOutput = command.Option("--prefix-output", Resources.PrefixDescription);
command.HandleResponseFiles = true;
command.OnExecute(
() =>
{
Reporter.IsVerbose = verbose.HasValue();
Reporter.NoColor = noColor.HasValue();
Reporter.PrefixOutput = prefixOutput.HasValue();
Validate();
return Execute();
});
}
protected virtual void Validate()
{
}
protected virtual int Execute()
=> 0;
}
}

View File

@ -0,0 +1,167 @@
// 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.Reflection;
#if NETCOREAPP2_0
using System.Runtime.Loader;
#endif
using Microsoft.DotNet.Cli.CommandLine;
namespace Microsoft.Extensions.ApiDescription.Tool.Commands
{
internal class GetDocumentCommand : ProjectCommandBase
{
internal const string FallbackDocumentName = "v1";
internal const string FallbackMethod = "GenerateAsync";
internal const string FallbackService = "Microsoft.Extensions.ApiDescription.IDocumentProvider";
private CommandOption _documentName;
private CommandOption _method;
private CommandOption _output;
private CommandOption _service;
public override void Configure(CommandLineApplication command)
{
base.Configure(command);
_documentName = command.Option(
"--documentName <Name>",
Resources.FormatDocumentDescription(FallbackDocumentName));
_method = command.Option("--method <Name>", Resources.FormatMethodDescription(FallbackMethod));
_output = command.Option("--output <Path>", Resources.OutputDescription);
_service = command.Option("--service <QualifiedName>", Resources.FormatServiceDescription(FallbackService));
}
protected override void Validate()
{
base.Validate();
if (!_output.HasValue())
{
throw new CommandException(Resources.FormatMissingOption(_output.LongName));
}
if (_method.HasValue() && !_service.HasValue())
{
throw new CommandException(Resources.FormatMissingOption(_service.LongName));
}
if (_service.HasValue() && !_method.HasValue())
{
throw new CommandException(Resources.FormatMissingOption(_method.LongName));
}
}
protected override int Execute()
{
var thisAssembly = typeof(GetDocumentCommand).Assembly;
var toolsDirectory = ToolsDirectory.Value();
var packagedAssemblies = Directory
.EnumerateFiles(toolsDirectory, "*.dll")
.Except(new[] { Path.GetFullPath(thisAssembly.Location) })
.ToDictionary(path => Path.GetFileNameWithoutExtension(path), path => new AssemblyInfo(path));
// Explicitly load all assemblies we need first to preserve target project as much as possible. This
// executable is always run in the target project's context (either through location or .deps.json file).
foreach (var keyValuePair in packagedAssemblies)
{
try
{
keyValuePair.Value.Assembly = Assembly.Load(new AssemblyName(keyValuePair.Key));
}
catch
{
// Ignore all failures because missing assemblies should be loadable from tools directory.
}
}
#if NETCOREAPP2_0
AssemblyLoadContext.Default.Resolving += (loadContext, assemblyName) =>
{
var name = assemblyName.Name;
if (!packagedAssemblies.TryGetValue(name, out var info))
{
return null;
}
var assemblyPath = info.Path;
if (!File.Exists(assemblyPath))
{
throw new InvalidOperationException(
$"Referenced assembly '{name}' was not found in '{toolsDirectory}'.");
}
return loadContext.LoadFromAssemblyPath(assemblyPath);
};
#elif NET461
AppDomain.CurrentDomain.AssemblyResolve += (source, eventArgs) =>
{
var assemblyName = new AssemblyName(eventArgs.Name);
var name = assemblyName.Name;
if (!packagedAssemblies.TryGetValue(name, out var info))
{
return null;
}
var assembly = info.Assembly;
if (assembly != null)
{
// Loaded already
return assembly;
}
var assemblyPath = info.Path;
if (!File.Exists(assemblyPath))
{
throw new InvalidOperationException(
$"Referenced assembly '{name}' was not found in '{toolsDirectory}'.");
}
return Assembly.LoadFile(assemblyPath);
};
#else
#error target frameworks need to be updated.
#endif
// Now safe to reference the application's code.
try
{
var assemblyPath = AssemblyPath.Value();
var context = new GetDocumentCommandContext
{
AssemblyPath = assemblyPath,
AssemblyDirectory = Path.GetDirectoryName(assemblyPath),
AssemblyName = Path.GetFileNameWithoutExtension(assemblyPath),
DocumentName = _documentName.Value(),
Method = _method.Value(),
OutputPath = _output.Value(),
Service = _service.Value(),
};
return GetDocumentCommandWorker.Process(context);
}
catch (Exception ex)
{
Console.Error.WriteLine(ex.ToString());
return 1;
}
}
private class AssemblyInfo
{
public AssemblyInfo(string path)
{
Path = path;
}
public string Path { get; }
public Assembly Assembly { get; set; }
}
}
}

View File

@ -0,0 +1,25 @@
// 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.Extensions.ApiDescription.Tool.Commands
{
[Serializable]
public class GetDocumentCommandContext
{
public string AssemblyDirectory { get; set; }
public string AssemblyName { get; set; }
public string AssemblyPath { get; set; }
public string DocumentName { get; set; }
public string Method { get; set; }
public string OutputPath { get; set; }
public string Service { get; set; }
}
}

View File

@ -0,0 +1,217 @@
// 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.Reflection;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
namespace Microsoft.Extensions.ApiDescription.Tool.Commands
{
internal class GetDocumentCommandWorker
{
public static int Process(GetDocumentCommandContext context)
{
var assemblyName = new AssemblyName(context.AssemblyName);
var assembly = Assembly.Load(assemblyName);
var entryPointType = assembly.EntryPoint?.DeclaringType;
if (entryPointType == null)
{
Reporter.WriteError(Resources.FormatMissingEntryPoint(context.AssemblyPath));
return 2;
}
var services = GetServices(entryPointType, context.AssemblyPath, context.AssemblyName);
if (services == null)
{
return 3;
}
var success = TryProcess(context, services);
if (!success)
{
// As part of the aspnet/Mvc#8425 fix, return 4 here.
return 0;
}
return 0;
}
public static bool TryProcess(GetDocumentCommandContext context, IServiceProvider services)
{
var documentName = string.IsNullOrEmpty(context.DocumentName) ?
GetDocumentCommand.FallbackDocumentName :
context.DocumentName;
var methodName = string.IsNullOrEmpty(context.Method) ?
GetDocumentCommand.FallbackMethod :
context.Method;
var serviceName = string.IsNullOrEmpty(context.Service) ?
GetDocumentCommand.FallbackService :
context.Service;
Reporter.WriteInformation(Resources.FormatUsingDocument(documentName));
Reporter.WriteInformation(Resources.FormatUsingMethod(methodName));
Reporter.WriteInformation(Resources.FormatUsingService(serviceName));
try
{
Type serviceType = null;
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
serviceType = assembly.GetType(serviceName, throwOnError: false);
if (serviceType != null)
{
break;
}
}
// As part of the aspnet/Mvc#8425 fix, make all warnings in this method errors unless the file already
// exists.
if (serviceType == null)
{
Reporter.WriteWarning(Resources.FormatServiceTypeNotFound(serviceName));
return false;
}
var method = serviceType.GetMethod(methodName, new[] { typeof(string), typeof(TextWriter) });
if (method == null)
{
Reporter.WriteWarning(Resources.FormatMethodNotFound(methodName, serviceName));
return false;
}
else if (!typeof(Task).IsAssignableFrom(method.ReturnType))
{
Reporter.WriteWarning(Resources.FormatMethodReturnTypeUnsupported(
methodName,
serviceName,
method.ReturnType,
typeof(Task)));
return false;
}
var service = services.GetService(serviceType);
if (service == null)
{
Reporter.WriteWarning(Resources.FormatServiceNotFound(serviceName));
return false;
}
// Create the output FileStream last to avoid corrupting an existing file or writing partial data.
var stream = new MemoryStream();
using (var writer = new StreamWriter(stream))
{
var resultTask = (Task)method.Invoke(service, new object[] { documentName, writer });
if (resultTask == null)
{
Reporter.WriteWarning(
Resources.FormatMethodReturnedNull(methodName, serviceName, nameof(Task)));
return false;
}
var finished = Task.WhenAny(resultTask, Task.Delay(TimeSpan.FromMinutes(1)));
if (!ReferenceEquals(resultTask, finished))
{
Reporter.WriteWarning(Resources.FormatMethodTimedOut(methodName, serviceName, 1));
return false;
}
writer.Flush();
stream.Position = 0L;
using (var outStream = File.Create(context.OutputPath))
{
stream.CopyTo(outStream);
}
}
return true;
}
catch (AggregateException ex) when (ex.InnerException != null)
{
foreach (var innerException in ex.Flatten().InnerExceptions)
{
Reporter.WriteWarning(FormatException(innerException));
}
}
catch (Exception ex)
{
Reporter.WriteWarning(FormatException(ex));
}
File.Delete(context.OutputPath);
return false;
}
// TODO: Use Microsoft.AspNetCore.Hosting.WebHostBuilderFactory.Sources once we have dev feed available.
private static IServiceProvider GetServices(Type entryPointType, string assemblyPath, string assemblyName)
{
var args = new[] { Array.Empty<string>() };
var methodInfo = entryPointType.GetMethod("BuildWebHost");
if (methodInfo != null)
{
// BuildWebHost (old style has highest priority)
var parameters = methodInfo.GetParameters();
if (!methodInfo.IsStatic ||
parameters.Length != 1 ||
typeof(string[]) != parameters[0].ParameterType ||
typeof(IWebHost) != methodInfo.ReturnType)
{
Reporter.WriteError(
"BuildWebHost method found in {assemblyPath} does not have expected signature.");
return null;
}
try
{
var webHost = (IWebHost)methodInfo.Invoke(obj: null, parameters: args);
return webHost.Services;
}
catch (Exception ex)
{
Reporter.WriteError($"BuildWebHost method threw: {FormatException(ex)}");
return null;
}
}
if ((methodInfo = entryPointType.GetMethod("CreateWebHostBuilder")) != null)
{
// CreateWebHostBuilder
var parameters = methodInfo.GetParameters();
if (!methodInfo.IsStatic ||
parameters.Length != 1 ||
typeof(string[]) != parameters[0].ParameterType ||
typeof(IWebHostBuilder) != methodInfo.ReturnType)
{
Reporter.WriteError(
"CreateWebHostBuilder method found in {assemblyPath} does not have expected signature.");
return null;
}
try
{
var builder = (IWebHostBuilder)methodInfo.Invoke(obj: null, parameters: args);
return builder.Build().Services;
}
catch (Exception ex)
{
Reporter.WriteError($"CreateWebHostBuilder method threw: {FormatException(ex)}");
return null;
}
}
return null;
}
private static string FormatException(Exception exception)
{
return $"{exception.GetType().FullName}: {exception.Message}";
}
}
}

View File

@ -0,0 +1,17 @@
// 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.DotNet.Cli.CommandLine;
namespace Microsoft.Extensions.ApiDescription.Tool.Commands
{
internal class HelpCommandBase : CommandBase
{
public override void Configure(CommandLineApplication command)
{
base.Configure(command);
command.HelpOption("-h|--help");
}
}
}

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 Microsoft.DotNet.Cli.CommandLine;
namespace Microsoft.Extensions.ApiDescription.Tool.Commands
{
internal abstract class ProjectCommandBase : HelpCommandBase
{
public CommandOption AssemblyPath { get; private set; }
public CommandOption ToolsDirectory { get; private set; }
public override void Configure(CommandLineApplication command)
{
base.Configure(command);
AssemblyPath = command.Option("-a|--assembly <PATH>", Resources.AssemblyDescription);
ToolsDirectory = command.Option("--tools-directory <PATH>", Resources.ToolsDirectoryDescription);
}
protected override void Validate()
{
base.Validate();
if (!AssemblyPath.HasValue())
{
throw new CommandException(Resources.FormatMissingOption(AssemblyPath.LongName));
}
if (!ToolsDirectory.HasValue())
{
throw new CommandException(Resources.FormatMissingOption(ToolsDirectory.LongName));
}
}
}
}

View File

@ -0,0 +1,22 @@
<Project Sdk="Internal.AspNetCore.Sdk">
<PropertyGroup>
<AssemblyName>GetDocument.Insider</AssemblyName>
<Description>GetDocument Command-line Tool inside man</Description>
<IsPackable>false</IsPackable>
<OutputType>Exe</OutputType>
<RootNamespace>Microsoft.Extensions.ApiDescription.Tool</RootNamespace>
<TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net461'">
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="$(MicrosoftAspNetCoreHostingAbstractions20PackageVersion)" />
</ItemGroup>
<Target Name="BuildX86" AfterTargets="Build" Condition=" '$(TargetFramework)' == 'net461' And '$(Platform)' != 'x86' ">
<MSBuild Projects="$(MSBuildProjectFullPath)" Properties="TargetFramework=$(TargetFramework);Platform=x86" Targets="Build" />
</Target>
</Project>

View File

@ -0,0 +1,16 @@
// 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.Reflection;
namespace Microsoft.Extensions.ApiDescription.Tool
{
internal static class ProductInfo
{
public static string GetVersion()
=> typeof(ProductInfo)
.Assembly
.GetCustomAttribute<AssemblyInformationalVersionAttribute>()
.InformationalVersion;
}
}

View File

@ -0,0 +1,48 @@
// 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.Text;
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.Extensions.ApiDescription.Tool.Commands;
namespace Microsoft.Extensions.ApiDescription.Tool
{
internal static class Program
{
private static int Main(string[] args)
{
if (Console.IsOutputRedirected)
{
Console.OutputEncoding = Encoding.UTF8;
}
var app = new CommandLineApplication(throwOnUnexpectedArg: false)
{
Name = "GetDocument.Insider"
};
new GetDocumentCommand().Configure(app);
try
{
return app.Execute(args);
}
catch (Exception ex)
{
if (ex is CommandException || ex is CommandParsingException)
{
Reporter.WriteVerbose(ex.ToString());
}
else
{
Reporter.WriteInformation(ex.ToString());
}
Reporter.WriteError(ex.Message);
return 1;
}
}
}
}

View File

@ -0,0 +1,324 @@
// <auto-generated />
namespace Microsoft.Extensions.ApiDescription.Tool
{
using System.Globalization;
using System.Reflection;
using System.Resources;
internal static class Resources
{
private static readonly ResourceManager _resourceManager
= new ResourceManager("Microsoft.Extensions.ApiDescription.Tool.Resources", typeof(Resources).GetTypeInfo().Assembly);
/// <summary>
/// The assembly to use.
/// </summary>
internal static string AssemblyDescription
{
get => GetString("AssemblyDescription");
}
/// <summary>
/// The assembly to use.
/// </summary>
internal static string FormatAssemblyDescription()
=> GetString("AssemblyDescription");
/// <summary>
/// Missing required option '--{0}'.
/// </summary>
internal static string MissingOption
{
get => GetString("MissingOption");
}
/// <summary>
/// Missing required option '--{0}'.
/// </summary>
internal static string FormatMissingOption(object p0)
=> string.Format(CultureInfo.CurrentCulture, GetString("MissingOption"), p0);
/// <summary>
/// Do not colorize output.
/// </summary>
internal static string NoColorDescription
{
get => GetString("NoColorDescription");
}
/// <summary>
/// Do not colorize output.
/// </summary>
internal static string FormatNoColorDescription()
=> GetString("NoColorDescription");
/// <summary>
/// The file to write the result to.
/// </summary>
internal static string OutputDescription
{
get => GetString("OutputDescription");
}
/// <summary>
/// The file to write the result to.
/// </summary>
internal static string FormatOutputDescription()
=> GetString("OutputDescription");
/// <summary>
/// Prefix console output with logging level.
/// </summary>
internal static string PrefixDescription
{
get => GetString("PrefixDescription");
}
/// <summary>
/// Prefix console output with logging level.
/// </summary>
internal static string FormatPrefixDescription()
=> GetString("PrefixDescription");
/// <summary>
/// Show verbose output.
/// </summary>
internal static string VerboseDescription
{
get => GetString("VerboseDescription");
}
/// <summary>
/// Show verbose output.
/// </summary>
internal static string FormatVerboseDescription()
=> GetString("VerboseDescription");
/// <summary>
/// Location from which inside man was copied (in the .NET Framework case) or loaded.
/// </summary>
internal static string ToolsDirectoryDescription
{
get => GetString("ToolsDirectoryDescription");
}
/// <summary>
/// Location from which inside man was copied (in the .NET Framework case) or loaded.
/// </summary>
internal static string FormatToolsDirectoryDescription()
=> GetString("ToolsDirectoryDescription");
/// <summary>
/// The name of the method to invoke on the '--service' instance. Default value '{0}'.
/// </summary>
internal static string MethodDescription
{
get => GetString("MethodDescription");
}
/// <summary>
/// The name of the method to invoke on the '--service' instance. Default value '{0}'.
/// </summary>
internal static string FormatMethodDescription(object p0)
=> string.Format(CultureInfo.CurrentCulture, GetString("MethodDescription"), p0);
/// <summary>
/// The qualified name of the service type to retrieve from dependency injection. Default value '{0}'.
/// </summary>
internal static string ServiceDescription
{
get => GetString("ServiceDescription");
}
/// <summary>
/// The qualified name of the service type to retrieve from dependency injection. Default value '{0}'.
/// </summary>
internal static string FormatServiceDescription(object p0)
=> string.Format(CultureInfo.CurrentCulture, GetString("ServiceDescription"), p0);
/// <summary>
/// The name of the document to pass to the '--method' method. Default value '{0}'.
/// </summary>
internal static string DocumentDescription
{
get => GetString("DocumentDescription");
}
/// <summary>
/// The name of the document to pass to the '--method' method. Default value '{0}'.
/// </summary>
internal static string FormatDocumentDescription(object p0)
=> string.Format(CultureInfo.CurrentCulture, GetString("DocumentDescription"), p0);
/// <summary>
/// Using document name '{0}'.
/// </summary>
internal static string UsingDocument
{
get => GetString("UsingDocument");
}
/// <summary>
/// Using document name '{0}'.
/// </summary>
internal static string FormatUsingDocument(object p0)
=> string.Format(CultureInfo.CurrentCulture, GetString("UsingDocument"), p0);
/// <summary>
/// Using method '{0}'.
/// </summary>
internal static string UsingMethod
{
get => GetString("UsingMethod");
}
/// <summary>
/// Using method '{0}'.
/// </summary>
internal static string FormatUsingMethod(object p0)
=> string.Format(CultureInfo.CurrentCulture, GetString("UsingMethod"), p0);
/// <summary>
/// Using service '{0}'.
/// </summary>
internal static string UsingService
{
get => GetString("UsingService");
}
/// <summary>
/// Using service '{0}'.
/// </summary>
internal static string FormatUsingService(object p0)
=> string.Format(CultureInfo.CurrentCulture, GetString("UsingService"), p0);
/// <summary>
/// Method '{0}' of service '{1}' failed to generate document '{2}'.
/// </summary>
internal static string MethodInvocationFailed
{
get => GetString("MethodInvocationFailed");
}
/// <summary>
/// Method '{0}' of service '{1}' failed to generate document '{2}'.
/// </summary>
internal static string FormatMethodInvocationFailed(object p0, object p1, object p2)
=> string.Format(CultureInfo.CurrentCulture, GetString("MethodInvocationFailed"), p0, p1, p2);
/// <summary>
/// Assembly '{0}' does not contain an entry point.
/// </summary>
internal static string MissingEntryPoint
{
get => GetString("MissingEntryPoint");
}
/// <summary>
/// Assembly '{0}' does not contain an entry point.
/// </summary>
internal static string FormatMissingEntryPoint(object p0)
=> string.Format(CultureInfo.CurrentCulture, GetString("MissingEntryPoint"), p0);
/// <summary>
/// Unable to find service type '{0}' in loaded assemblies.
/// </summary>
internal static string ServiceTypeNotFound
{
get => GetString("ServiceTypeNotFound");
}
/// <summary>
/// Unable to find service type '{0}' in loaded assemblies.
/// </summary>
internal static string FormatServiceTypeNotFound(object p0)
=> string.Format(CultureInfo.CurrentCulture, GetString("ServiceTypeNotFound"), p0);
/// <summary>
/// Unable to find method named '{0}' in '{1}' implementation.
/// </summary>
internal static string MethodNotFound
{
get => GetString("MethodNotFound");
}
/// <summary>
/// Unable to find method named '{0}' in '{1}' implementation.
/// </summary>
internal static string FormatMethodNotFound(object p0, object p1)
=> string.Format(CultureInfo.CurrentCulture, GetString("MethodNotFound"), p0, p1);
/// <summary>
/// Unable to find service of type '{0}' in dependency injection container.
/// </summary>
internal static string ServiceNotFound
{
get => GetString("ServiceNotFound");
}
/// <summary>
/// Unable to find service of type '{0}' in dependency injection container.
/// </summary>
internal static string FormatServiceNotFound(object p0)
=> string.Format(CultureInfo.CurrentCulture, GetString("ServiceNotFound"), p0);
/// <summary>
/// Method '{0}' of service '{1}' returned null. Must return a non-null '{2}'.
/// </summary>
internal static string MethodReturnedNull
{
get => GetString("MethodReturnedNull");
}
/// <summary>
/// Method '{0}' of service '{1}' returned null. Must return a non-null '{2}'.
/// </summary>
internal static string FormatMethodReturnedNull(object p0, object p1, object p2)
=> string.Format(CultureInfo.CurrentCulture, GetString("MethodReturnedNull"), p0, p1, p2);
/// <summary>
/// Method '{0}' of service '{1}' has unsupported return type '{2}'. Must return a '{3}'.
/// </summary>
internal static string MethodReturnTypeUnsupported
{
get => GetString("MethodReturnTypeUnsupported");
}
/// <summary>
/// Method '{0}' of service '{1}' has unsupported return type '{2}'. Must return a '{3}'.
/// </summary>
internal static string FormatMethodReturnTypeUnsupported(object p0, object p1, object p2, object p3)
=> string.Format(CultureInfo.CurrentCulture, GetString("MethodReturnTypeUnsupported"), p0, p1, p2, p3);
/// <summary>
/// Method '{0}' of service '{1}' timed out. Must complete execution within {2} minute.
/// </summary>
internal static string MethodTimedOut
{
get => GetString("MethodTimedOut");
}
/// <summary>
/// Method '{0}' of service '{1}' timed out. Must complete execution within {2} minute.
/// </summary>
internal static string FormatMethodTimedOut(object p0, object p1, object p2)
=> string.Format(CultureInfo.CurrentCulture, GetString("MethodTimedOut"), p0, p1, p2);
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,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.Linq;
using static Microsoft.Extensions.ApiDescription.Tool.AnsiConstants;
namespace Microsoft.Extensions.ApiDescription.Tool
{
internal static class Reporter
{
public static bool IsVerbose { get; set; }
public static bool NoColor { get; set; }
public static bool PrefixOutput { get; set; }
public static string Colorize(string value, Func<string, string> colorizeFunc)
=> NoColor ? value : colorizeFunc(value);
public static void WriteError(string message)
=> WriteLine(Prefix("error: ", Colorize(message, x => Bold + Red + x + Reset)));
public static void WriteWarning(string message)
=> WriteLine(Prefix("warn: ", Colorize(message, x => Bold + Yellow + x + Reset)));
public static void WriteInformation(string message)
=> WriteLine(Prefix("info: ", message));
public static void WriteData(string message)
=> WriteLine(Prefix("data: ", Colorize(message, x => Bold + Gray + x + Reset)));
public static void WriteVerbose(string message)
{
if (IsVerbose)
{
WriteLine(Prefix("verbose: ", Colorize(message, x => Bold + Black + x + Reset)));
}
}
private static string Prefix(string prefix, string value)
=> PrefixOutput
? string.Join(
Environment.NewLine,
value.Split(new[] { Environment.NewLine }, StringSplitOptions.None).Select(l => prefix + l))
: value;
private static void WriteLine(string value)
{
if (NoColor)
{
Console.WriteLine(value);
}
else
{
AnsiConsole.WriteLine(value);
}
}
}
}

View File

@ -0,0 +1,183 @@
<?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="AssemblyDescription" xml:space="preserve">
<value>The assembly to use.</value>
</data>
<data name="MissingOption" xml:space="preserve">
<value>Missing required option '--{0}'.</value>
</data>
<data name="NoColorDescription" xml:space="preserve">
<value>Do not colorize output.</value>
</data>
<data name="OutputDescription" xml:space="preserve">
<value>The file to write the result to.</value>
</data>
<data name="PrefixDescription" xml:space="preserve">
<value>Prefix console output with logging level.</value>
</data>
<data name="VerboseDescription" xml:space="preserve">
<value>Show verbose output.</value>
</data>
<data name="ToolsDirectoryDescription" xml:space="preserve">
<value>Location from which inside man was copied (in the .NET Framework case) or loaded.</value>
</data>
<data name="MethodDescription" xml:space="preserve">
<value>The name of the method to invoke on the '--service' instance. Default value '{0}'.</value>
</data>
<data name="ServiceDescription" xml:space="preserve">
<value>The qualified name of the service type to retrieve from dependency injection. Default value '{0}'.</value>
</data>
<data name="DocumentDescription" xml:space="preserve">
<value>The name of the document to pass to the '--method' method. Default value '{0}'.</value>
</data>
<data name="UsingDocument" xml:space="preserve">
<value>Using document name '{0}'.</value>
</data>
<data name="UsingMethod" xml:space="preserve">
<value>Using method '{0}'.</value>
</data>
<data name="UsingService" xml:space="preserve">
<value>Using service '{0}'.</value>
</data>
<data name="MethodInvocationFailed" xml:space="preserve">
<value>Method '{0}' of service '{1}' failed to generate document '{2}'.</value>
</data>
<data name="MissingEntryPoint" xml:space="preserve">
<value>Assembly '{0}' does not contain an entry point.</value>
</data>
<data name="ServiceTypeNotFound" xml:space="preserve">
<value>Unable to find service type '{0}' in loaded assemblies.</value>
</data>
<data name="MethodNotFound" xml:space="preserve">
<value>Unable to find method named '{0}' in '{1}' implementation.</value>
</data>
<data name="ServiceNotFound" xml:space="preserve">
<value>Unable to find service of type '{0}' in dependency injection container.</value>
</data>
<data name="MethodReturnedNull" xml:space="preserve">
<value>Method '{0}' of service '{1}' returned null. Must return a non-null '{2}'.</value>
</data>
<data name="MethodReturnTypeUnsupported" xml:space="preserve">
<value>Method '{0}' of service '{1}' has unsupported return type '{2}'. Must return a '{3}'.</value>
</data>
<data name="MethodTimedOut" xml:space="preserve">
<value>Method '{0}' of service '{1}' timed out. Must complete execution within {2} minute.</value>
</data>
</root>

View File

@ -36,6 +36,11 @@ namespace Microsoft.AspNetCore.Mvc.Abstractions
/// </summary>
public IList<IActionConstraintMetadata> ActionConstraints { get; set; }
/// <summary>
/// Gets or sets the endpoint metadata for this action.
/// </summary>
public IList<object> EndpointMetadata { get; set; }
/// <summary>
/// The set of parameters associated with this action.
/// </summary>

View File

@ -10,7 +10,7 @@ namespace Microsoft.AspNetCore.Mvc.ActionConstraints
/// <summary>
/// A candidate action for action selection.
/// </summary>
public struct ActionSelectorCandidate
public readonly struct ActionSelectorCandidate
{
/// <summary>
/// Creates a new <see cref="ActionSelectorCandidate"/>.

View File

@ -31,15 +31,11 @@ namespace Microsoft.AspNetCore.Mvc
/// <param name="actionContext">The <see cref="ActionContext"/> to copy.</param>
public ActionContext(ActionContext actionContext)
: this(
actionContext.HttpContext,
actionContext.RouteData,
actionContext.ActionDescriptor,
actionContext.ModelState)
actionContext?.HttpContext,
actionContext?.RouteData,
actionContext?.ActionDescriptor,
actionContext?.ModelState)
{
if (actionContext == null)
{
throw new ArgumentNullException(nameof(actionContext));
}
}
/// <summary>
@ -136,4 +132,4 @@ namespace Microsoft.AspNetCore.Mvc
get; set;
}
}
}
}

View File

@ -41,5 +41,23 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer
/// Gets or sets the parameter descriptor.
/// </summary>
public ParameterDescriptor ParameterDescriptor { get; set; }
/// <summary>
/// Gets or sets a value that determines if the parameter is required.
/// </summary>
/// <remarks>
/// A parameter is considered required if
/// <list type="bullet">
/// <item>it's bound from the request body (<see cref="BindingSource.Body"/>).</item>
/// <item>it's a required route value.</item>
/// <item>it has annotations (e.g. BindRequiredAttribute) that indicate it's required.</item>
/// </list>
/// </remarks>
public bool IsRequired { get; set; }
/// <summary>
/// Gets or sets the default value for a parameter.
/// </summary>
public object DefaultValue { get; set; }
}
}

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Routing;
namespace Microsoft.AspNetCore.Mvc
@ -19,14 +20,22 @@ namespace Microsoft.AspNetCore.Mvc
/// Generates a URL with an absolute path for an action method, which contains the action
/// name, controller name, route values, protocol to use, host name, and fragment specified by
/// <see cref="UrlActionContext"/>. Generates an absolute URL if <see cref="UrlActionContext.Protocol"/> and
/// <see cref="UrlActionContext.Host"/> are non-<c>null</c>.
/// <see cref="UrlActionContext.Host"/> are non-<c>null</c>. See the remarks section for important security information.
/// </summary>
/// <param name="actionContext">The context object for the generated URLs for an action method.</param>
/// <returns>The generated URL.</returns>
/// <remarks>
/// <para>
/// The value of <see cref="UrlActionContext.Host" /> should be a trusted value. Relying on the value of the current request
/// can allow untrusted input to influence the resulting URI unless the <c>Host</c> header has been validated.
/// See the deployment documentation for instructions on how to properly validate the <c>Host</c> header in
/// your deployment environment.
/// </para>
/// </remarks>
string Action(UrlActionContext actionContext);
/// <summary>
/// Converts a virtual (relative) path to an application absolute path.
/// Converts a virtual (relative, starting with ~/) path to an application absolute path.
/// </summary>
/// <remarks>
/// If the specified content path does not start with the tilde (~) character,
@ -65,19 +74,36 @@ namespace Microsoft.AspNetCore.Mvc
/// Generates a URL with an absolute path, which contains the route name, route values, protocol to use, host
/// name, and fragment specified by <see cref="UrlRouteContext"/>. Generates an absolute URL if
/// <see cref="UrlActionContext.Protocol"/> and <see cref="UrlActionContext.Host"/> are non-<c>null</c>.
/// See the remarks section for important security information.
/// </summary>
/// <param name="routeContext">The context object for the generated URLs for a route.</param>
/// <returns>The generated URL.</returns>
/// <remarks>
/// <para>
/// The value of <see cref="UrlRouteContext.Host" /> should be a trusted value. Relying on the value of the current request
/// can allow untrusted input to influence the resulting URI unless the <c>Host</c> header has been validated.
/// See the deployment documentation for instructions on how to properly validate the <c>Host</c> header in
/// your deployment environment.
/// </para>
/// </remarks>
string RouteUrl(UrlRouteContext routeContext);
/// <summary>
/// Generates an absolute URL for the specified <paramref name="routeName"/> and route
/// <paramref name="values"/>, which contains the protocol (such as "http" or "https") and host name from the
/// current request.
/// current request. See the remarks section for important security information.
/// </summary>
/// <param name="routeName">The name of the route that is used to generate URL.</param>
/// <param name="values">An object that contains route values.</param>
/// <returns>The generated absolute URL.</returns>
/// <remarks>
/// <para>
/// This method uses the value of <see cref="HttpRequest.Host"/> to populate the host section of the generated URI.
/// Relying on the value of the current request can allow untrusted input to influence the resulting URI unless
/// the <c>Host</c> header has been validated. See the deployment documentation for instructions on how to properly
/// validate the <c>Host</c> header in your deployment environment.
/// </para>
/// </remarks>
string Link(string routeName, object values);
}
}

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Internal.AspNetCore.Sdk">
<PropertyGroup>
<Description>ASP.NET Core MVC abstractions and interfaces for action invocation and dispatching, authorization, action filters, formatters, model binding, routing, validation, and more.
@ -12,11 +12,12 @@ Microsoft.AspNetCore.Mvc.IActionResult</Description>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Routing.Abstractions" Version="$(MicrosoftAspNetCoreRoutingAbstractionsPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.ClosedGenericMatcher.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsClosedGenericMatcherSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.CopyOnWriteDictionary.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsCopyOnWriteDictionarySourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.HashCodeCombiner.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsHashCodeCombinerSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.PropertyHelper.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsPropertyHelperSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Net.Http.Headers" Version="$(MicrosoftNetHttpHeadersPackageVersion)" />
</ItemGroup>
<ItemGroup Label="Sources packages">
<PackageReference Include="Microsoft.Extensions.ClosedGenericMatcher.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsClosedGenericMatcherSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.HashCodeCombiner.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsHashCodeCombinerSourcesPackageVersion)" />
</ItemGroup>
</Project>

View File

@ -8,7 +8,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
/// <summary>
/// An abstraction used when grouping enum values for <see cref="ModelMetadata.EnumGroupedDisplayNamesAndValues"/>.
/// </summary>
public struct EnumGroupAndName
public readonly struct EnumGroupAndName
{
private readonly Func<string> _name;

View File

@ -14,7 +14,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
/// Error message the model binding system adds when a property with an associated
/// <c>BindRequiredAttribute</c> is not bound.
/// </summary>
/// <value>Default <see cref="string"/> is "A value for the '{0}' property was not provided.".</value>
/// <value>
/// Default <see cref="string"/> is "A value for the '{0}' parameter or property was not provided.".
/// </value>
public virtual Func<string, string> MissingBindRequiredValueAccessor { get; }
/// <summary>

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