diff --git a/.azure/pipelines/fast-pr-validation.yml b/.azure/pipelines/fast-pr-validation.yml index fe8f93b205..d0045c031e 100644 --- a/.azure/pipelines/fast-pr-validation.yml +++ b/.azure/pipelines/fast-pr-validation.yml @@ -1,3 +1,4 @@ + trigger: - master - release/* @@ -5,31 +6,18 @@ trigger: jobs: - template: jobs/default-build.yml parameters: + jobName: PR_FastCheck + jobDisplayName: Fast Check agentOs: Windows - jobName: Windows_FastCheck - jobDisplayName: Windows - Fast Check buildArgs: "/t:FastCheck" - artifacts: - publish: false -- job: RepoBuilds - pool: - vmImage: vs2017-win2016 - strategy: - maxParallel: 3 - matrix: - DataProtection: - _FolderName: DataProtection - WebSockets: - _FolderName: WebSockets - steps: - - script: src/$(_FolderName)/build.cmd -ci - displayName: Run src/$(_FolderName)/build.cmd - - task: PublishTestResults@2 - displayName: Publish test results - condition: always() - inputs: - testRunner: vstest - testResultsFiles: 'src/$(_FolderName)/artifacts/logs/**/*.trx' +- template: jobs/default-build.yml + parameters: + jobName: Windows_Build + jobDisplayName: "Build: Windows" + agentOs: Windows + beforeBuild: + - powershell: "& ./src/IISIntegration/tools/UpdateIISExpressCertificate.ps1" + displayName: Setup IISExpress test certificates - template: jobs/iisintegration-job.yml parameters: TestGroupName: IIS diff --git a/.azure/pipelines/jobs/default-build.yml b/.azure/pipelines/jobs/default-build.yml index df7f08f57d..87873f95d8 100644 --- a/.azure/pipelines/jobs/default-build.yml +++ b/.azure/pipelines/jobs/default-build.yml @@ -63,6 +63,7 @@ jobs: - job: ${{ coalesce(parameters.jobName, parameters.agentOs) }} displayName: ${{ coalesce(parameters.jobDisplayName, parameters.agentOs) }} dependsOn: ${{ parameters.dependsOn }} + timeoutInMinutes: 90 workspace: clean: all strategy: diff --git a/.gitmodules b/.gitmodules index 50e0b0d516..2e4ed7971c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -26,18 +26,10 @@ path = modules/Diagnostics url = https://github.com/aspnet/Diagnostics.git branch = master -[submodule "modules/DotNetTools"] - path = modules/DotNetTools - url = https://github.com/aspnet/DotNetTools.git - branch = master [submodule "modules/Hosting"] path = modules/Hosting url = https://github.com/aspnet/Hosting.git branch = master -[submodule "modules/HtmlAbstractions"] - path = modules/HtmlAbstractions - url = https://github.com/aspnet/HtmlAbstractions.git - branch = master [submodule "modules/HttpAbstractions"] path = modules/HttpAbstractions url = https://github.com/aspnet/HttpAbstractions.git @@ -58,10 +50,6 @@ path = modules/JavaScriptServices url = https://github.com/aspnet/JavaScriptServices.git branch = master -[submodule "modules/JsonPatch"] - path = modules/JsonPatch - url = https://github.com/aspnet/JsonPatch.git - branch = master [submodule "modules/KestrelHttpServer"] path = modules/KestrelHttpServer url = https://github.com/aspnet/KestrelHttpServer.git diff --git a/Directory.Build.props b/Directory.Build.props index 7968a8b8ad..b121675096 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -17,6 +17,8 @@ replace PackageLicenseUrl with PackageLicenseExpression. --> $(NoWarn);NU5125 + + $(NoWarn);NU5105 nugetaspnet@microsoft.com @@ -49,6 +51,16 @@ false + + + Microsoft400 + 3PartySHA2 + Microsoft400 + NuGet + VsixSHA2 + MicrosoftJAR + + @@ -75,8 +87,16 @@ true + + netcoreapp2.2;net461 + + + + + + diff --git a/Directory.Build.targets b/Directory.Build.targets index 1013afefeb..a7ad514960 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -1,9 +1,46 @@ + + $(AssemblyName) + false + + + + + + + true + $(PackagesInPatch.Contains(' $(PackageId);')) + + + + + true + + false + + + + + $(BaselinePackageVersion).0 + + $(BaselinePackageVersion) + $(BaselinePackageVersion) + + true + + false + $(IsImplementationProject) true false @@ -16,6 +53,7 @@ + diff --git a/build/CodeSign.props b/build/CodeSign.props index d7d412b073..8b3a235030 100644 --- a/build/CodeSign.props +++ b/build/CodeSign.props @@ -43,6 +43,7 @@ + diff --git a/build/CodeSign.targets b/build/CodeSign.targets index 032fbd1c84..13d89fc64f 100644 --- a/build/CodeSign.targets +++ b/build/CodeSign.targets @@ -4,7 +4,7 @@ $(CodeSignDependsOn);CollectFileSignInfo - + <_RepositoryProject Remove="@(_RepositoryProject)" /> @@ -12,6 +12,10 @@ RepositoryRoot=%(Repository.RootPath) %(Repository.Build) + <_ShippedRepositoryProject Include="$(MSBuildProjectFullPath)" Condition="'%(ShippedRepository.Identity)' != ''"> + RepositoryRoot=%(ShippedRepository.RootPath) + false + @@ -28,21 +32,37 @@ + + + <_FilesToSign Include="@(_RepoFileSignInfo)" Condition="'%(_RepoFileSignInfo.IsFileToSign)' == 'true' AND ('$(_ReposWereBuilt)' == 'true' OR '%(_RepoFileSignInfo.Container)' != '' ) " /> + <_FilesToSign Include="@(_ShippedRepoFileSignInfo)" Condition="'%(_ShippedRepoFileSignInfo.IsFileToSign)' == 'true' AND '%(_ShippedRepoFileSignInfo.Container)' != '' " /> + + <_Temp Remove="@(_Temp)" /> + <_Temp Include="@(FilesToExcludeFromSigning)" /> + + + <_Temp Remove="@(_Temp)" /> + + - diff --git a/build/PackageArchive.targets b/build/PackageArchive.targets index 5ba1cadcf8..0eea5b6c15 100644 --- a/build/PackageArchive.targets +++ b/build/PackageArchive.targets @@ -8,9 +8,7 @@ - - - + DotNetRestoreSourcePropsPath=$(GeneratedRestoreSourcesPropsPath); diff --git a/build/SharedFx.targets b/build/SharedFx.targets index 0ccf8b7a4e..f172eb9350 100644 --- a/build/SharedFx.targets +++ b/build/SharedFx.targets @@ -2,21 +2,22 @@ $(RepositoryRoot)src\Framework\Framework.UnitTests\Framework.UnitTests.csproj $([MSBuild]::NormalizePath($(UnitTestFxProject))) - $(CodeSignDependsOn);GetSharedFxFilesToSign + $(CodeSignDependsOn);GetSharedFxFilesToSign _BuildSharedFxProjects;TestSharedFx $(BuildSharedFxDependsOn);CodeSign $(IntermediateDir)ar\$(SharedFxRid)\ + $(GetArtifactInfo);GetFxProjectArtifactInfo true - - - - - - - + + + + + + + @@ -43,7 +44,7 @@ - <_RestoreGraphProjectInput>@(ProjectToBuild) + <_RestoreGraphProjectInput>@(FxProjectToBuild) $(BuildProperties); SharedFxRid=$(SharedFxRid); @@ -58,11 +59,11 @@ Targets="Restore" Properties="$(SharedFxBuildProperties);RestoreGraphProjectInput=$(_RestoreGraphProjectInput);_DummyTarget=Restore" /> - - + + + <_InspectionTargetsFile>$(MSBuildProjectDirectory)\Project.Inspection.targets + + + + <_Temp Remove="@(_Temp)" /> + + + + + + + + + + + + + + + + + + + diff --git a/build/artifacts.props b/build/artifacts.props index 8700fdf2ca..fbea00052b 100644 --- a/build/artifacts.props +++ b/build/artifacts.props @@ -175,7 +175,6 @@ - diff --git a/build/buildorder.props b/build/buildorder.props index 3ee7ccff69..5a2e14559f 100644 --- a/build/buildorder.props +++ b/build/buildorder.props @@ -7,16 +7,12 @@ - - - - @@ -28,7 +24,6 @@ - diff --git a/build/dependencies.folderbuilds.props b/build/dependencies.folderbuilds.props index b4940f76b6..ef8e16b829 100644 --- a/build/dependencies.folderbuilds.props +++ b/build/dependencies.folderbuilds.props @@ -1,7 +1,7 @@  - 3.0.0-alpha1-20181108.8 + 3.0.0-build-20181114.5 3.0.0-alpha1-10717 3.0.0-alpha1-10717 3.0.0-alpha1-10717 diff --git a/build/dependencies.props b/build/dependencies.props index 985728b25c..73f5d2a0c7 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -31,67 +31,68 @@ 4.6.0-preview1-26907-04 4.6.0-preview1-26829-04 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 - 3.0.0-preview-181108-06 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 3.0.0-preview-181109-02 3.0.0-preview-181109-02 @@ -116,10 +117,12 @@ $(KoreBuildVersion) $(KoreBuildVersion) + 2.2.1-build-20181114.3 + 0.9.9 0.10.13 @@ -212,6 +215,7 @@ 6.0.1 0.20.0 3.12.1 + 2.43.0 17.17134.0 3.12.1 1.4.0 diff --git a/build/external-dependencies.props b/build/external-dependencies.props index 223187a8cc..bc4408f024 100644 --- a/build/external-dependencies.props +++ b/build/external-dependencies.props @@ -71,6 +71,7 @@ + diff --git a/build/repo.props b/build/repo.props index bdf4c80e1a..b3ebfc33d0 100644 --- a/build/repo.props +++ b/build/repo.props @@ -4,6 +4,8 @@ true + true + false false true @@ -13,8 +15,6 @@ $(RepositoryRoot).deps\build\ $(RepositoryRoot).deps\Signed\Packages\ - - true $(RepositoryRoot)eng\signcheck.exclusions.txt true @@ -49,6 +49,22 @@ + + + + + + diff --git a/build/repo.targets b/build/repo.targets index cff950d2cd..2384a606ac 100644 --- a/build/repo.targets +++ b/build/repo.targets @@ -15,20 +15,60 @@ $(IntermediateDir)sources.g.props $(IntermediateDir)branding.g.props - SetTeamCityBuildNumberToVersion;$(PrepareDependsOn);VerifyPackageArtifactConfig;VerifyExternalDependencyConfig;PrepareOutputPaths + SetTeamCityBuildNumberToVersion;$(PrepareDependsOn) + $(PrepareDependsOn);VerifyPackageArtifactConfig;VerifyExternalDependencyConfig;PrepareOutputPaths $(CleanDependsOn);CleanArtifacts;CleanRepoArtifacts - $(RestoreDependsOn);InstallDotNet - $(CompileDependsOn);BuildRepositories;BuildSharedFx - $(PackageDependsOn);CheckExpectedPackagesExist;CodeSign - $(TestDependsOn);_TestRepositories - $(GetArtifactInfoDependsOn);ResolveRepoInfo + $(RestoreDependsOn);InstallDotNet;RestoreProjects + $(CompileDependsOn);BuildProjects + $(CompileDependsOn);PackProjects;BuildRepositories;BuildSharedFx + $(PackageDependsOn);PackProjects + $(PackageDependsOn);CheckExpectedPackagesExist + $(PackageDependsOn);CodeSign + $(TestDependsOn);TestProjects + $(TestDependsOn);_TestRepositories + $(GetArtifactInfoDependsOn);GetProjectArtifactInfo + $(GetArtifactInfoDependsOn);ResolveRepoInfo - + + + + + + + + $(MSBuildThisFileDirectory)..\eng\ProjectReferences.props + + + + + @(_ProjectReferenceProvider->'', '%0A ') + + + ]]> + + + + + + + + + + + + + + $(BuildProperties);MicrosoftNETCoreAppPackageVersion=$(MicrosoftNETCoreAppPackageVersion); @@ -238,14 +278,15 @@ - + - + <_UndeclaredPackageArtifact Include="%(ArtifactInfo.PackageId)" Condition="'%(ArtifactInfo.ArtifactType)' == 'NuGetPackage'" /> <_UndeclaredPackageArtifact Remove="@(PackageArtifact)" /> + + + + + $(RestoreSources); + https://dotnetfeed.blob.core.windows.net/orchestrated-release-2-2/20181110-02/final/index.json; + + $(RestoreSources); https://dotnetfeed.blob.core.windows.net/dotnet-core/index.json; diff --git a/build/submodules.props b/build/submodules.props index 74d00d31ab..45250b9d8c 100644 --- a/build/submodules.props +++ b/build/submodules.props @@ -41,18 +41,14 @@ - - - - @@ -65,7 +61,6 @@ - diff --git a/build/tasks/RepoTasks.csproj b/build/tasks/RepoTasks.csproj index 6be1f375d2..20cbf6cce8 100644 --- a/build/tasks/RepoTasks.csproj +++ b/build/tasks/RepoTasks.csproj @@ -6,6 +6,7 @@ + diff --git a/docs/PreparingPatchUpdates.md b/docs/PreparingPatchUpdates.md new file mode 100644 index 0000000000..34813e8162 --- /dev/null +++ b/docs/PreparingPatchUpdates.md @@ -0,0 +1,41 @@ +Preparing new servicing updates +=============================== + +In order to prepare this repo to build a new servicing update, the following changes need to be made. + +* Increment the patch version in the [version.props](/version.props) file in the repository root. + + ```diff + - 7 + + 8 + ``` + +* Update the package archive baselines. This is used to make sure each build of the package archives we give to Azure only contains new files and does + not require overwriting existing files. See [src/PackageArchive/ZipManifestGenerator/](/src/PackageArchive/ZipManifestGenerator/README.md) for instructions on how to run this tool. + +* Update the package baselines. This is used to ensure packages keep a consistent set of dependencies between releases. + See [eng/tools/BaselineGenerator/](/eng/tools/BaselineGenerator/README.md) for instructions on how to run this tool. + +* **For packages with source code in this repo (not a submodule):** Update the list of packages in [eng/PatchConfig.props](/eng/PatchConfig.props) to list which packages should be patching in this release. + +* **For packages still building from submodules:** Update the list of repositories which will contain changes in [build/submodules.props](/build/submodules.props). + + * `` items represent repos which were released in a previous patch, and will not contain servicing updates in the next patch. + * `` items represent repos which will produce new packages in this patch. + * It is usually best to move everything to `` and then iteratively add them back to `` as new repos receive approval to patch. + * Don't change the `PatchPolicy` attribute. The build system uses this to ensure patching rules are obeyed. + +* For each repository still listed as a ``, update the version.props file in that submodule. For example, https://github.com/aspnet/Templating/pull/824 + + * The version prefix in repos should match the version of ASP.NET Core. + * Exception: SignalR, which is "1.1", not "2.1". + * This leaves holes in versioning, which is okay. This may mean you increment the patch value by more than one. Example: + * EF Core ships patches in 2.1.4 as "2.1.4" + * EF Core does not ship patches in 2.1.5 or 2.1.6 + * EF Core ships in 2.1.7, therefore, EFCore's version.props file should jump from 2.1.4 to 2.1.7. + + ```diff + + - 2.1.4 + + 2.1.7 + ``` diff --git a/eng/Baseline.props b/eng/Baseline.props new file mode 100644 index 0000000000..b8d8c3cb60 --- /dev/null +++ b/eng/Baseline.props @@ -0,0 +1,116 @@ + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + 2.2.0 + + + + 2.2.0 + + + + + 2.2.0 + + + + + + + + + + 2.2.0 + + + + + + + + + + + + + + + 2.2.0 + + + + + 2.2.0 + + + + + + + + + 2.2.0 + + + + + + + + 2.2.0 + + + + + + + + 2.2.0 + + + + + + + + 2.2.0 + + + + + + + + 2.2.0 + + + + + + + + 2.2.0 + + + + + + + 2.2.0 + + + + + + + + 2.2.0 + + + + + + + + \ No newline at end of file diff --git a/eng/Dependencies.props b/eng/Dependencies.props new file mode 100644 index 0000000000..ffa3071b04 --- /dev/null +++ b/eng/Dependencies.props @@ -0,0 +1,72 @@ + + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/eng/NuGetPackageVerifier.json b/eng/NuGetPackageVerifier.json new file mode 100644 index 0000000000..8c6f0eedfa --- /dev/null +++ b/eng/NuGetPackageVerifier.json @@ -0,0 +1,41 @@ +{ + "adx": { + "rules": [ + "AdxVerificationCompositeRule" + ], + "packages": { + "dotnet-watch": { + "packageTypes": [ + "DotnetTool" + ] + }, + "dotnet-sql-cache": { + "packageTypes": [ + "DotnetTool" + ] + }, + "dotnet-user-secrets": { + "packageTypes": [ + "DotnetTool" + ] + }, + "dotnet-dev-certs": { + "packageTypes": [ + "DotnetTool" + ] + }, + "Microsoft.AspNetCore.DeveloperCertificates.XPlat": { + "Exclusions": { + "DOC_MISSING": { + "lib/netcoreapp3.0/Microsoft.AspNetCore.DeveloperCertificates.XPlat.dll": "Docs not required to shipoob package" + } + } + } + } + }, + "Default": { + "rules": [ + "DefaultCompositeRule" + ] + } +} diff --git a/eng/PatchConfig.props b/eng/PatchConfig.props new file mode 100644 index 0000000000..c05b2376c6 --- /dev/null +++ b/eng/PatchConfig.props @@ -0,0 +1,14 @@ + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + + + + + Microsoft.AspNetCore.Server.IIS; + Microsoft.AspNetCore.Server.IISIntegration; + Microsoft.AspNetCore.Server.IntegrationTesting.IIS; + + + + diff --git a/eng/ProjectReferences.props b/eng/ProjectReferences.props new file mode 100644 index 0000000000..55d8dc6094 --- /dev/null +++ b/eng/ProjectReferences.props @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/eng/dependencies.temp.props b/eng/dependencies.temp.props new file mode 100644 index 0000000000..38aeea4dbe --- /dev/null +++ b/eng/dependencies.temp.props @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + diff --git a/eng/targets/CSharp.Common.props b/eng/targets/CSharp.Common.props new file mode 100644 index 0000000000..b3fc97e2d9 --- /dev/null +++ b/eng/targets/CSharp.Common.props @@ -0,0 +1,14 @@ + + + + 7.2 + + + SHA256 + + + + + + + diff --git a/eng/targets/CSharp.Common.targets b/eng/targets/CSharp.Common.targets new file mode 100644 index 0000000000..a7f7b610b6 --- /dev/null +++ b/eng/targets/CSharp.Common.targets @@ -0,0 +1,5 @@ + + + + + diff --git a/eng/targets/Packaging.targets b/eng/targets/Packaging.targets new file mode 100644 index 0000000000..2a1427c2de --- /dev/null +++ b/eng/targets/Packaging.targets @@ -0,0 +1,30 @@ + + + + + + + + + + + $(PackageOutputPath)$(PackageId).$(PackageVersion).nupkg + + + + + NuGetPackage + $(PackageId) + $(PackageVersion) + $(RepositoryRoot) + true + + + + diff --git a/eng/targets/ResolveReferences.targets b/eng/targets/ResolveReferences.targets new file mode 100644 index 0000000000..caf44207ee --- /dev/null +++ b/eng/targets/ResolveReferences.targets @@ -0,0 +1,135 @@ + + + + + ResolveCustomReferences; + $(ResolveReferencesDependsOn); + + + + + + true + true + true + false + + + true + true + false + + + + <_ImplicitPackageReference Include="@(PackageReference->WithMetadataValue('IsImplicitlyDefined', 'true'))" /> + <_ExplicitPackageReference Include="@(PackageReference)" Exclude="@(_ImplicitPackageReference)" /> + <_ExplicitPackageReference Remove="Internal.AspNetCore.Sdk" /> + + + + + <_ProjectReferenceByAssemblyName Condition="'$(UseProjectReferences)' == 'true'" + Include="@(ProjectReferenceProvider)" + Exclude="@(UnusedProjectReferenceProvider)" /> + + + + + + + + + + + + <_LatestPackageReferenceWithVersion Include="@(Reference)" Condition=" '$(UseLatestPackageReferences)' == 'true' "> + %(LatestPackageReference.Identity) + %(LatestPackageReference.Version) + + <_LatestPackageReferenceWithVersion Remove="@(_LatestPackageReferenceWithVersion)" Condition="'%(Id)' != '%(Identity)' " /> + + + + + + + <_BaselinePackageReferenceWithVersion Include="@(Reference)" Condition=" '$(IsServicingBuild)' == 'true' OR '$(UseLatestPackageReferences)' != 'true' "> + %(BaselinePackageReference.Identity) + %(BaselinePackageReference.Version) + + + <_BaselinePackageReferenceWithVersion Remove="@(_BaselinePackageReferenceWithVersion)" Condition="'%(Id)' != '%(Identity)' " /> + + + + + + + <_PrivatePackageReferenceWithVersion Include="@(Reference->WithMetadataValue('PrivateAssets', 'All'))"> + %(LatestPackageReference.Identity) + %(LatestPackageReference.Version) + + + <_PrivatePackageReferenceWithVersion Remove="@(_PrivatePackageReferenceWithVersion)" Condition="'%(Id)' != '%(Identity)' " /> + + + + + + + <_LatestPackageReferenceWithVersion Remove="@(_LatestPackageReferenceWithVersion)" /> + <_BaselinePackageReferenceWithVersion Remove="@(_BaselinePackageReferenceWithVersion)" /> + <_PrivatePackageReferenceWithVersion Remove="@(_PrivatePackageReferenceWithVersion)" /> + <_ImplicitPackageReference Remove="@(_ImplicitPackageReference)" /> + + + + + <_ExplicitPackageReference Remove="@(_ExplicitPackageReference)" /> + + + + + + + + + + <_TargetFramework Remove="@(_TargetFramework)" /> + <_TargetFramework Include="$(TargetFramework)" Condition="'$(TargetFramework)' != '' "/> + <_TargetFramework Include="$(TargetFrameworks)" Condition="'$(TargetFramework)' == '' "/> + + + + + + + + + + + $([MSBuild]::MakeRelative($(RepositoryRoot), $(MSBuildProjectFullPath))) + + + + diff --git a/eng/targets/SharedFx.Common.targets b/eng/targets/SharedFx.Common.targets index 4f83af1176..61b41d9eee 100644 --- a/eng/targets/SharedFx.Common.targets +++ b/eng/targets/SharedFx.Common.targets @@ -332,4 +332,32 @@ This targets file should only be imported by .shfxproj files. + + + + $(PackageOutputPath)$(PackageId).$(PackageVersion).nupkg + $(PackageOutputPath)$(PackageId).$(PackageVersion).symbols.nupkg + + + + + NuGetPackage + $(PackageId) + $(PackageVersion) + $(RepositoryRoot) + $(PackageSigningCertName) + true + true + + + NuGetSymbolsPackage + $(PackageId) + $(PackageVersion) + $(RepositoryRoot) + $(PackageSigningCertName) + true + true + + + diff --git a/eng/tools/BaselineGenerator/BaselineGenerator.csproj b/eng/tools/BaselineGenerator/BaselineGenerator.csproj new file mode 100644 index 0000000000..625777dbd2 --- /dev/null +++ b/eng/tools/BaselineGenerator/BaselineGenerator.csproj @@ -0,0 +1,15 @@ + + + + Exe + netcoreapp2.1 + -o "$(MSBuildThisFileDirectory)../../Baseline.props" + $(MSBuildProjectDirectory) + + + + + + + + diff --git a/eng/tools/BaselineGenerator/Program.cs b/eng/tools/BaselineGenerator/Program.cs new file mode 100644 index 0000000000..689653e199 --- /dev/null +++ b/eng/tools/BaselineGenerator/Program.cs @@ -0,0 +1,138 @@ +// 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.Net.Http; +using System.Text; +using System.Threading.Tasks; +using System.Xml; +using System.Xml.Linq; +using Microsoft.Extensions.CommandLineUtils; +using NuGet.Packaging; +using NuGet.Packaging.Core; + +namespace PackageBaselineGenerator +{ + /// + /// This generates Baseline.props with information about the last RTM release. + /// + class Program : CommandLineApplication + { + static void Main(string[] args) + { + new Program().Execute(args); + } + + private readonly CommandOption _source; + private readonly CommandOption _output; + private readonly CommandOption _feedv3; + + public Program() + { + _source = Option("-s|--source ", "The NuGet v2 source of the package to fetch", CommandOptionType.SingleValue); + _output = Option("-o|--output ", "The generated file output path", CommandOptionType.SingleValue); + _feedv3 = Option("--v3", "Sources is nuget v3", CommandOptionType.NoValue); + + Invoke = () => Run().GetAwaiter().GetResult(); + } + + private async Task Run() + { + var source = _source.HasValue() + ? _source.Value() + : "https://www.nuget.org/api/v2/package"; + + var packageCache = Environment.GetEnvironmentVariable("NUGET_PACKAGES") != null + ? Environment.GetEnvironmentVariable("NUGET_PACKAGES") + : Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".nuget", "packages"); + + var tempDir = Path.Combine(Directory.GetCurrentDirectory(), "obj", "tmp"); + Directory.CreateDirectory(tempDir); + + var input = XDocument.Load(Path.Combine(Directory.GetCurrentDirectory(), "baseline.xml")); + + var output = _output.HasValue() + ? _output.Value() + : Path.Combine(Directory.GetCurrentDirectory(), "Baseline.props"); + + var baselineVersion = input.Root.Attribute("Version").Value; + + var doc = new XDocument( + new XComment(" Auto generated. Do not edit manually, use eng/tools/BaselineGenerator/ to recreate. "), + new XElement("Project", + new XElement("PropertyGroup", + new XElement("MSBuildAllProjects", "$(MSBuildAllProjects);$(MSBuildThisFileFullPath)"), + new XElement("AspNetCoreBaselineVersion", baselineVersion)))); + + var client = new HttpClient(); + + foreach (var pkg in input.Root.Descendants("Package")) + { + var id = pkg.Attribute("Id").Value; + var version = pkg.Attribute("Version").Value; + var packageFileName = $"{id}.{version}.nupkg"; + var nupkgPath = Path.Combine(packageCache, id.ToLowerInvariant(), version, packageFileName); + if (!File.Exists(nupkgPath)) + { + nupkgPath = Path.Combine(tempDir, packageFileName); + } + + if (!File.Exists(nupkgPath)) + { + var url = _feedv3.HasValue() + ? $"{source}/{id.ToLowerInvariant()}/{version}/{id.ToLowerInvariant()}.{version}.nupkg" + : $"{source}/{id}/{version}"; + Console.WriteLine($"Downloading {url}"); + + var response = await client.GetStreamAsync(url); + + using (var file = File.Create(nupkgPath)) + { + await response.CopyToAsync(file); + } + } + + + using (var reader = new PackageArchiveReader(nupkgPath)) + { + var first = true; + foreach (var group in reader.NuspecReader.GetDependencyGroups()) + { + if (first) + { + first = false; + doc.Root.Add(new XComment($" Package: {id}")); + + var propertyGroup = new XElement("PropertyGroup", + new XAttribute("Condition", $" '$(PackageId)' == '{id}' "), + new XElement("BaselinePackageVersion", version)); + doc.Root.Add(propertyGroup); + } + + var itemGroup = new XElement("ItemGroup", new XAttribute("Condition", $" '$(PackageId)' == '{id}' AND '$(TargetFramework)' == '{group.TargetFramework.GetShortFolderName()}' ")); + doc.Root.Add(itemGroup); + + foreach (var dependency in group.Packages) + { + itemGroup.Add(new XElement("BaselinePackageReference", new XAttribute("Include", dependency.Id), new XAttribute("Version", dependency.VersionRange.ToString()))); + } + } + } + } + + var settings = new XmlWriterSettings + { + OmitXmlDeclaration = true, + Encoding = Encoding.UTF8, + Indent = true, + }; + using (var writer = XmlWriter.Create(output, settings)) + { + doc.Save(writer); + } + + return 0; + } + } +} diff --git a/eng/tools/BaselineGenerator/README.md b/eng/tools/BaselineGenerator/README.md new file mode 100644 index 0000000000..1afd97d1b5 --- /dev/null +++ b/eng/tools/BaselineGenerator/README.md @@ -0,0 +1,10 @@ +BaselineGenerator +================= + +This tool is used to generate an MSBuild file which sets the "baseline" against which servicing updates are built. + +## Usage + +1. Add to the [baseline.xml](./baseline.xml) a list of package ID's and their latest released versions. The source of this information can typically + be found in the build.xml file generated during ProdCon builds. See https://github.com/dotnet/versions/blob/master/build-info/dotnet/product/cli/release/2.1.6/build.xml for example. +2. Run `dotnet run` on this project. diff --git a/eng/tools/BaselineGenerator/baseline.xml b/eng/tools/BaselineGenerator/baseline.xml new file mode 100644 index 0000000000..f6ec31acb2 --- /dev/null +++ b/eng/tools/BaselineGenerator/baseline.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/eng/tools/Directory.Build.props b/eng/tools/Directory.Build.props new file mode 100644 index 0000000000..fda3ea0cbe --- /dev/null +++ b/eng/tools/Directory.Build.props @@ -0,0 +1,3 @@ + + + diff --git a/eng/tools/Directory.Build.targets b/eng/tools/Directory.Build.targets new file mode 100644 index 0000000000..f75adf7e4d --- /dev/null +++ b/eng/tools/Directory.Build.targets @@ -0,0 +1,2 @@ + + diff --git a/eng/tools/tools.sln b/eng/tools/tools.sln new file mode 100644 index 0000000000..527e47cbc3 --- /dev/null +++ b/eng/tools/tools.sln @@ -0,0 +1,34 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26124.0 +MinimumVisualStudioVersion = 15.0.26124.0 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BaselineGenerator", "BaselineGenerator\BaselineGenerator.csproj", "{CF76A947-3A72-4824-87E6-BF029D84218B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CF76A947-3A72-4824-87E6-BF029D84218B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CF76A947-3A72-4824-87E6-BF029D84218B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CF76A947-3A72-4824-87E6-BF029D84218B}.Debug|x64.ActiveCfg = Debug|Any CPU + {CF76A947-3A72-4824-87E6-BF029D84218B}.Debug|x64.Build.0 = Debug|Any CPU + {CF76A947-3A72-4824-87E6-BF029D84218B}.Debug|x86.ActiveCfg = Debug|Any CPU + {CF76A947-3A72-4824-87E6-BF029D84218B}.Debug|x86.Build.0 = Debug|Any CPU + {CF76A947-3A72-4824-87E6-BF029D84218B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CF76A947-3A72-4824-87E6-BF029D84218B}.Release|Any CPU.Build.0 = Release|Any CPU + {CF76A947-3A72-4824-87E6-BF029D84218B}.Release|x64.ActiveCfg = Release|Any CPU + {CF76A947-3A72-4824-87E6-BF029D84218B}.Release|x64.Build.0 = Release|Any CPU + {CF76A947-3A72-4824-87E6-BF029D84218B}.Release|x86.ActiveCfg = Release|Any CPU + {CF76A947-3A72-4824-87E6-BF029D84218B}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/global.json b/global.json index 9c74e979dc..6df6220662 100644 --- a/global.json +++ b/global.json @@ -3,6 +3,6 @@ "version": "3.0.100-preview-009750" }, "msbuild-sdks": { - "Internal.AspNetCore.Sdk": "3.0.0-alpha1-20181114.4" + "Internal.AspNetCore.Sdk": "3.0.0-build-20181114.5" } } diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 87afe665b0..73613543d0 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:3.0.0-alpha1-20181114.4 -commithash:576bd9858150e9aec1c3527dc68ebe9f69d55b5a +version:3.0.0-build-20181114.5 +commithash:880e9a204d4ee4a18dfd83c9fb05a192a28bca60 diff --git a/modules/DotNetTools b/modules/DotNetTools deleted file mode 160000 index a24b4ee459..0000000000 --- a/modules/DotNetTools +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a24b4ee4598b425d9e8b2f041be508c32eb41cf5 diff --git a/modules/HtmlAbstractions b/modules/HtmlAbstractions deleted file mode 160000 index 45b7e2ddb7..0000000000 --- a/modules/HtmlAbstractions +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 45b7e2ddb796f0cb909d8f04bc4b5a5cf13b5e46 diff --git a/modules/JsonPatch b/modules/JsonPatch deleted file mode 160000 index bf9fd0d106..0000000000 --- a/modules/JsonPatch +++ /dev/null @@ -1 +0,0 @@ -Subproject commit bf9fd0d10667e605d1df45f89e198be7f3bd1138 diff --git a/scripts/UpdateDependencies.ps1 b/scripts/UpdateDependencies.ps1 index 7aeb8fd3f8..6adaea833e 100755 --- a/scripts/UpdateDependencies.ps1 +++ b/scripts/UpdateDependencies.ps1 @@ -56,7 +56,6 @@ foreach ($package in $remoteDeps.SelectNodes('//Package')) { if (-not $NoCommit) { $currentBranch = Invoke-Block { & git rev-parse --abbrev-ref HEAD } - $destinationBranch = "dotnetbot/UpdateDeps" Invoke-Block { & git checkout -tb $destinationBranch "origin/$GithubUpstreamBranch" } } diff --git a/src/DataProtection/Abstractions/src/Microsoft.AspNetCore.DataProtection.Abstractions.csproj b/src/DataProtection/Abstractions/src/Microsoft.AspNetCore.DataProtection.Abstractions.csproj index 94dc1366dd..021b3fde2c 100644 --- a/src/DataProtection/Abstractions/src/Microsoft.AspNetCore.DataProtection.Abstractions.csproj +++ b/src/DataProtection/Abstractions/src/Microsoft.AspNetCore.DataProtection.Abstractions.csproj @@ -15,7 +15,7 @@ Microsoft.AspNetCore.DataProtection.IDataProtector - + diff --git a/src/DataProtection/Abstractions/test/Microsoft.AspNetCore.DataProtection.Abstractions.Tests.csproj b/src/DataProtection/Abstractions/test/Microsoft.AspNetCore.DataProtection.Abstractions.Tests.csproj index b01ec90350..781387c466 100644 --- a/src/DataProtection/Abstractions/test/Microsoft.AspNetCore.DataProtection.Abstractions.Tests.csproj +++ b/src/DataProtection/Abstractions/test/Microsoft.AspNetCore.DataProtection.Abstractions.Tests.csproj @@ -5,8 +5,8 @@ - - + + diff --git a/src/DataProtection/AzureKeyVault/src/Microsoft.AspNetCore.DataProtection.AzureKeyVault.csproj b/src/DataProtection/AzureKeyVault/src/Microsoft.AspNetCore.DataProtection.AzureKeyVault.csproj index 86b9195c60..42aa2edb13 100644 --- a/src/DataProtection/AzureKeyVault/src/Microsoft.AspNetCore.DataProtection.AzureKeyVault.csproj +++ b/src/DataProtection/AzureKeyVault/src/Microsoft.AspNetCore.DataProtection.AzureKeyVault.csproj @@ -9,12 +9,9 @@ - - - - - - + + + diff --git a/src/DataProtection/AzureKeyVault/test/Microsoft.AspNetCore.DataProtection.AzureKeyVault.Tests.csproj b/src/DataProtection/AzureKeyVault/test/Microsoft.AspNetCore.DataProtection.AzureKeyVault.Tests.csproj index 06993140cc..879b9042a1 100644 --- a/src/DataProtection/AzureKeyVault/test/Microsoft.AspNetCore.DataProtection.AzureKeyVault.Tests.csproj +++ b/src/DataProtection/AzureKeyVault/test/Microsoft.AspNetCore.DataProtection.AzureKeyVault.Tests.csproj @@ -6,12 +6,9 @@ - - - - - - + + + diff --git a/src/DataProtection/AzureStorage/src/Microsoft.AspNetCore.DataProtection.AzureStorage.csproj b/src/DataProtection/AzureStorage/src/Microsoft.AspNetCore.DataProtection.AzureStorage.csproj index 368e6a9934..d65f55a425 100644 --- a/src/DataProtection/AzureStorage/src/Microsoft.AspNetCore.DataProtection.AzureStorage.csproj +++ b/src/DataProtection/AzureStorage/src/Microsoft.AspNetCore.DataProtection.AzureStorage.csproj @@ -9,11 +9,8 @@ - - - - - + + diff --git a/src/DataProtection/AzureStorage/test/Microsoft.AspNetCore.DataProtection.AzureStorage.Tests.csproj b/src/DataProtection/AzureStorage/test/Microsoft.AspNetCore.DataProtection.AzureStorage.Tests.csproj index 9dd2382f0a..f84e84974e 100644 --- a/src/DataProtection/AzureStorage/test/Microsoft.AspNetCore.DataProtection.AzureStorage.Tests.csproj +++ b/src/DataProtection/AzureStorage/test/Microsoft.AspNetCore.DataProtection.AzureStorage.Tests.csproj @@ -6,12 +6,9 @@ - - - - - - + + + diff --git a/src/DataProtection/Cryptography.Internal/test/Microsoft.AspNetCore.Cryptography.Internal.Tests.csproj b/src/DataProtection/Cryptography.Internal/test/Microsoft.AspNetCore.Cryptography.Internal.Tests.csproj index f0ed7c4f52..29e8a7c294 100644 --- a/src/DataProtection/Cryptography.Internal/test/Microsoft.AspNetCore.Cryptography.Internal.Tests.csproj +++ b/src/DataProtection/Cryptography.Internal/test/Microsoft.AspNetCore.Cryptography.Internal.Tests.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/DataProtection/Cryptography.KeyDerivation/src/Microsoft.AspNetCore.Cryptography.KeyDerivation.csproj b/src/DataProtection/Cryptography.KeyDerivation/src/Microsoft.AspNetCore.Cryptography.KeyDerivation.csproj index b4122a7546..3b869383e6 100644 --- a/src/DataProtection/Cryptography.KeyDerivation/src/Microsoft.AspNetCore.Cryptography.KeyDerivation.csproj +++ b/src/DataProtection/Cryptography.KeyDerivation/src/Microsoft.AspNetCore.Cryptography.KeyDerivation.csproj @@ -9,7 +9,7 @@ - + diff --git a/src/DataProtection/Cryptography.KeyDerivation/test/Microsoft.AspNetCore.Cryptography.KeyDerivation.Tests.csproj b/src/DataProtection/Cryptography.KeyDerivation/test/Microsoft.AspNetCore.Cryptography.KeyDerivation.Tests.csproj index caed9fddfa..e7a1be7ece 100644 --- a/src/DataProtection/Cryptography.KeyDerivation/test/Microsoft.AspNetCore.Cryptography.KeyDerivation.Tests.csproj +++ b/src/DataProtection/Cryptography.KeyDerivation/test/Microsoft.AspNetCore.Cryptography.KeyDerivation.Tests.csproj @@ -10,8 +10,8 @@ - - + + diff --git a/src/DataProtection/DataProtection/src/Microsoft.AspNetCore.DataProtection.csproj b/src/DataProtection/DataProtection/src/Microsoft.AspNetCore.DataProtection.csproj index 1428564533..18aa5ddc40 100644 --- a/src/DataProtection/DataProtection/src/Microsoft.AspNetCore.DataProtection.csproj +++ b/src/DataProtection/DataProtection/src/Microsoft.AspNetCore.DataProtection.csproj @@ -14,18 +14,15 @@ - - - - - - - - - - - - + + + + + + + + + diff --git a/src/DataProtection/DataProtection/test/Microsoft.AspNetCore.DataProtection.Tests.csproj b/src/DataProtection/DataProtection/test/Microsoft.AspNetCore.DataProtection.Tests.csproj index c371a1aade..3886642178 100644 --- a/src/DataProtection/DataProtection/test/Microsoft.AspNetCore.DataProtection.Tests.csproj +++ b/src/DataProtection/DataProtection/test/Microsoft.AspNetCore.DataProtection.Tests.csproj @@ -11,12 +11,12 @@ - - + + - - - + + + diff --git a/src/DataProtection/Directory.Build.props b/src/DataProtection/Directory.Build.props deleted file mode 100644 index 4a6e505662..0000000000 --- a/src/DataProtection/Directory.Build.props +++ /dev/null @@ -1,24 +0,0 @@ - - - - - true - - - - - - - - - - - - - - - - - - - diff --git a/src/DataProtection/EntityFrameworkCore/src/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.csproj b/src/DataProtection/EntityFrameworkCore/src/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.csproj index 0903521d3f..85f5e47c55 100644 --- a/src/DataProtection/EntityFrameworkCore/src/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.csproj +++ b/src/DataProtection/EntityFrameworkCore/src/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.csproj @@ -9,15 +9,8 @@ - - - - - - - - - + + diff --git a/src/DataProtection/EntityFrameworkCore/test/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.Test.csproj b/src/DataProtection/EntityFrameworkCore/test/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.Test.csproj index 928e1a5471..f08eb96c9b 100644 --- a/src/DataProtection/EntityFrameworkCore/test/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.Test.csproj +++ b/src/DataProtection/EntityFrameworkCore/test/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.Test.csproj @@ -5,11 +5,8 @@ - - - - - + + diff --git a/src/DataProtection/Extensions/src/Microsoft.AspNetCore.DataProtection.Extensions.csproj b/src/DataProtection/Extensions/src/Microsoft.AspNetCore.DataProtection.Extensions.csproj index e8335310e4..c106a52961 100644 --- a/src/DataProtection/Extensions/src/Microsoft.AspNetCore.DataProtection.Extensions.csproj +++ b/src/DataProtection/Extensions/src/Microsoft.AspNetCore.DataProtection.Extensions.csproj @@ -12,11 +12,8 @@ - - - - - + + diff --git a/src/DataProtection/Extensions/test/Microsoft.AspNetCore.DataProtection.Extensions.Tests.csproj b/src/DataProtection/Extensions/test/Microsoft.AspNetCore.DataProtection.Extensions.Tests.csproj index 4460b6da12..19284dddfd 100644 --- a/src/DataProtection/Extensions/test/Microsoft.AspNetCore.DataProtection.Extensions.Tests.csproj +++ b/src/DataProtection/Extensions/test/Microsoft.AspNetCore.DataProtection.Extensions.Tests.csproj @@ -10,8 +10,9 @@ - - + + + diff --git a/src/DataProtection/StackExchangeRedis/src/Microsoft.AspNetCore.DataProtection.StackExchangeRedis.csproj b/src/DataProtection/StackExchangeRedis/src/Microsoft.AspNetCore.DataProtection.StackExchangeRedis.csproj index 09852c77d0..6e2143d602 100644 --- a/src/DataProtection/StackExchangeRedis/src/Microsoft.AspNetCore.DataProtection.StackExchangeRedis.csproj +++ b/src/DataProtection/StackExchangeRedis/src/Microsoft.AspNetCore.DataProtection.StackExchangeRedis.csproj @@ -9,11 +9,8 @@ - - - - - + + diff --git a/src/DataProtection/StackExchangeRedis/test/Microsoft.AspNetCore.DataProtection.StackExchangeRedis.Tests.csproj b/src/DataProtection/StackExchangeRedis/test/Microsoft.AspNetCore.DataProtection.StackExchangeRedis.Tests.csproj index 0b028a9ea9..964abdb650 100644 --- a/src/DataProtection/StackExchangeRedis/test/Microsoft.AspNetCore.DataProtection.StackExchangeRedis.Tests.csproj +++ b/src/DataProtection/StackExchangeRedis/test/Microsoft.AspNetCore.DataProtection.StackExchangeRedis.Tests.csproj @@ -11,14 +11,11 @@ - - - - - - - - + + + + + diff --git a/src/DataProtection/SystemWeb/src/Microsoft.AspNetCore.DataProtection.SystemWeb.csproj b/src/DataProtection/SystemWeb/src/Microsoft.AspNetCore.DataProtection.SystemWeb.csproj index 03629c1de3..603fe68cc8 100644 --- a/src/DataProtection/SystemWeb/src/Microsoft.AspNetCore.DataProtection.SystemWeb.csproj +++ b/src/DataProtection/SystemWeb/src/Microsoft.AspNetCore.DataProtection.SystemWeb.csproj @@ -13,11 +13,8 @@ - - - - - + + diff --git a/src/DataProtection/build/repo.props b/src/DataProtection/build/repo.props deleted file mode 100644 index b8dd411686..0000000000 --- a/src/DataProtection/build/repo.props +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - true - false - false - $([MSBuild]::NormalizeDirectory('$(MSBuildThisFileDirectory)..\')) - $(DataProtectionRoot)**\*.csproj - - diff --git a/src/DataProtection/samples/AzureBlob/AzureBlob.csproj b/src/DataProtection/samples/AzureBlob/AzureBlob.csproj index fa85d4c68a..55e41b6b18 100644 --- a/src/DataProtection/samples/AzureBlob/AzureBlob.csproj +++ b/src/DataProtection/samples/AzureBlob/AzureBlob.csproj @@ -6,14 +6,11 @@ - - - - - - - - + + + + + diff --git a/src/DataProtection/samples/AzureKeyVault/AzureKeyVault.csproj b/src/DataProtection/samples/AzureKeyVault/AzureKeyVault.csproj index d39e9fd4d7..b577b27124 100644 --- a/src/DataProtection/samples/AzureKeyVault/AzureKeyVault.csproj +++ b/src/DataProtection/samples/AzureKeyVault/AzureKeyVault.csproj @@ -6,15 +6,12 @@ - - - - - - - - - + + + + + + diff --git a/src/DataProtection/samples/CustomEncryptorSample/CustomEncryptorSample.csproj b/src/DataProtection/samples/CustomEncryptorSample/CustomEncryptorSample.csproj index 09c632a2fb..de4c5e9e38 100644 --- a/src/DataProtection/samples/CustomEncryptorSample/CustomEncryptorSample.csproj +++ b/src/DataProtection/samples/CustomEncryptorSample/CustomEncryptorSample.csproj @@ -6,13 +6,10 @@ - - - - - - - + + + + diff --git a/src/DataProtection/samples/KeyManagementSample/KeyManagementSample.csproj b/src/DataProtection/samples/KeyManagementSample/KeyManagementSample.csproj index 9ee112ee7c..5ec8e7b074 100644 --- a/src/DataProtection/samples/KeyManagementSample/KeyManagementSample.csproj +++ b/src/DataProtection/samples/KeyManagementSample/KeyManagementSample.csproj @@ -6,8 +6,8 @@ - - + + diff --git a/src/DataProtection/samples/NonDISample/NonDISample.csproj b/src/DataProtection/samples/NonDISample/NonDISample.csproj index 560c00c1e5..04956556af 100644 --- a/src/DataProtection/samples/NonDISample/NonDISample.csproj +++ b/src/DataProtection/samples/NonDISample/NonDISample.csproj @@ -6,7 +6,7 @@ - + diff --git a/src/DataProtection/samples/Redis/Redis.csproj b/src/DataProtection/samples/Redis/Redis.csproj index 306d4917e8..fe41c02daf 100644 --- a/src/DataProtection/samples/Redis/Redis.csproj +++ b/src/DataProtection/samples/Redis/Redis.csproj @@ -6,13 +6,10 @@ - - - - - - - + + + + diff --git a/src/DataProtection/version.props b/src/DataProtection/version.props deleted file mode 100644 index 1f8b85dec9..0000000000 --- a/src/DataProtection/version.props +++ /dev/null @@ -1,10 +0,0 @@ - - - 3.0.0 - alpha1 - $(VersionPrefix) - $(VersionPrefix)-$(VersionSuffix)-final - t000 - $(VersionSuffix)-$(BuildNumber) - - diff --git a/src/Features/JsonPatch/src/Adapters/AdapterFactory.cs b/src/Features/JsonPatch/src/Adapters/AdapterFactory.cs new file mode 100644 index 0000000000..82aaa56a70 --- /dev/null +++ b/src/Features/JsonPatch/src/Adapters/AdapterFactory.cs @@ -0,0 +1,49 @@ +using Microsoft.AspNetCore.JsonPatch.Internal; +using Newtonsoft.Json.Serialization; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; + +namespace Microsoft.AspNetCore.JsonPatch.Adapters +{ + /// + /// The default AdapterFactory to be used for resolving . + /// + public class AdapterFactory : IAdapterFactory + { + /// + public virtual IAdapter Create(object target, IContractResolver contractResolver) + { + if (target == null) + { + throw new ArgumentNullException(nameof(target)); + } + + if (contractResolver == null) + { + throw new ArgumentNullException(nameof(contractResolver)); + } + + var jsonContract = contractResolver.ResolveContract(target.GetType()); + + if (target is IList) + { + return new ListAdapter(); + } + else if (jsonContract is JsonDictionaryContract jsonDictionaryContract) + { + var type = typeof(DictionaryAdapter<,>).MakeGenericType(jsonDictionaryContract.DictionaryKeyType, jsonDictionaryContract.DictionaryValueType); + return (IAdapter)Activator.CreateInstance(type); + } + else if (jsonContract is JsonDynamicContract) + { + return new DynamicObjectAdapter(); + } + else + { + return new PocoAdapter(); + } + } + } +} diff --git a/src/Features/JsonPatch/src/Adapters/IAdapterFactory.cs b/src/Features/JsonPatch/src/Adapters/IAdapterFactory.cs new file mode 100644 index 0000000000..43ca1e65b6 --- /dev/null +++ b/src/Features/JsonPatch/src/Adapters/IAdapterFactory.cs @@ -0,0 +1,22 @@ +using Microsoft.AspNetCore.JsonPatch.Internal; +using Newtonsoft.Json.Serialization; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Microsoft.AspNetCore.JsonPatch.Adapters +{ + /// + /// Defines the operations used for loading an based on the current object and ContractResolver. + /// + public interface IAdapterFactory + { + /// + /// Creates an for the current object + /// + /// The target object + /// The current contract resolver + /// The needed + IAdapter Create(object target, IContractResolver contractResolver); + } +} diff --git a/src/Features/JsonPatch/src/Adapters/IObjectAdapter.cs b/src/Features/JsonPatch/src/Adapters/IObjectAdapter.cs new file mode 100644 index 0000000000..e5206bfa0d --- /dev/null +++ b/src/Features/JsonPatch/src/Adapters/IObjectAdapter.cs @@ -0,0 +1,112 @@ +// 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.JsonPatch.Operations; + +namespace Microsoft.AspNetCore.JsonPatch.Adapters +{ + /// + /// Defines the operations that can be performed on a JSON patch document. + /// + public interface IObjectAdapter + { + /// + /// Using the "add" operation a new value is inserted into the root of the target + /// document, into the target array at the specified valid index, or to a target object at + /// the specified location. + /// + /// When adding to arrays, the specified index MUST NOT be greater than the number of elements in the array. + /// To append the value to the array, the index of "-" character is used (see [RFC6901]). + /// + /// When adding to an object, if an object member does not already exist, a new member is added to the object at the + /// specified location or if an object member does exist, that member's value is replaced. + /// + /// The operation object MUST contain a "value" member whose content + /// specifies the value to be added. + /// + /// For example: + /// + /// { "op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ] } + /// + /// See RFC 6902 https://tools.ietf.org/html/rfc6902#page-4 + /// + /// The add operation. + /// Object to apply the operation to. + void Add(Operation operation, object objectToApplyTo); + + /// + /// Using the "copy" operation, a value is copied from a specified location to the + /// target location. + /// + /// The operation object MUST contain a "from" member, which references the location in the + /// target document to copy the value from. + /// + /// The "from" location MUST exist for the operation to be successful. + /// + /// For example: + /// + /// { "op": "copy", "from": "/a/b/c", "path": "/a/b/e" } + /// + /// See RFC 6902 https://tools.ietf.org/html/rfc6902#page-7 + /// + /// The copy operation. + /// Object to apply the operation to. + void Copy(Operation operation, object objectToApplyTo); + + /// + /// Using the "move" operation the value at a specified location is removed and + /// added to the target location. + /// + /// The operation object MUST contain a "from" member, which references the location in the + /// target document to move the value from. + /// + /// The "from" location MUST exist for the operation to be successful. + /// + /// For example: + /// + /// { "op": "move", "from": "/a/b/c", "path": "/a/b/d" } + /// + /// A location cannot be moved into one of its children. + /// + /// See RFC 6902 https://tools.ietf.org/html/rfc6902#page-6 + /// + /// The move operation. + /// Object to apply the operation to. + void Move(Operation operation, object objectToApplyTo); + + /// + /// Using the "remove" operation the value at the target location is removed. + /// + /// The target location MUST exist for the operation to be successful. + /// + /// For example: + /// + /// { "op": "remove", "path": "/a/b/c" } + /// + /// If removing an element from an array, any elements above the + /// specified index are shifted one position to the left. + /// + /// See RFC 6902 https://tools.ietf.org/html/rfc6902#page-6 + /// + /// The remove operation. + /// Object to apply the operation to. + void Remove(Operation operation, object objectToApplyTo); + + /// + /// Using the "replace" operation he value at the target location is replaced + /// with a new value. The operation object MUST contain a "value" member + /// which specifies the replacement value. + /// + /// The target location MUST exist for the operation to be successful. + /// + /// For example: + /// + /// { "op": "replace", "path": "/a/b/c", "value": 42 } + /// + /// See RFC 6902 https://tools.ietf.org/html/rfc6902#page-6 + /// + /// The replace operation. + /// Object to apply the operation to. + void Replace(Operation operation, object objectToApplyTo); + } +} \ No newline at end of file diff --git a/src/Features/JsonPatch/src/Adapters/IObjectAdapterWithTest.cs b/src/Features/JsonPatch/src/Adapters/IObjectAdapterWithTest.cs new file mode 100644 index 0000000000..e1b4ce7950 --- /dev/null +++ b/src/Features/JsonPatch/src/Adapters/IObjectAdapterWithTest.cs @@ -0,0 +1,32 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.AspNetCore.JsonPatch.Operations; + +namespace Microsoft.AspNetCore.JsonPatch.Adapters +{ + /// + /// Defines the operations that can be performed on a JSON patch document, including "test". + /// + public interface IObjectAdapterWithTest : IObjectAdapter + { + /// + /// Using the "test" operation a value at the target location is compared for + /// equality to a specified value. + /// + /// The operation object MUST contain a "value" member that specifies + /// value to be compared to the target location's value. + /// + /// The target location MUST be equal to the "value" value for the + /// operation to be considered successful. + /// + /// For example: + /// { "op": "test", "path": "/a/b/c", "value": "foo" } + /// + /// See RFC 6902 https://tools.ietf.org/html/rfc6902#page-7 + /// + /// The test operation. + /// Object to apply the operation to. + void Test(Operation operation, object objectToApplyTo); + } +} diff --git a/src/Features/JsonPatch/src/Adapters/ObjectAdapter.cs b/src/Features/JsonPatch/src/Adapters/ObjectAdapter.cs new file mode 100644 index 0000000000..75cc513312 --- /dev/null +++ b/src/Features/JsonPatch/src/Adapters/ObjectAdapter.cs @@ -0,0 +1,348 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using Microsoft.AspNetCore.JsonPatch.Internal; +using Microsoft.AspNetCore.JsonPatch.Operations; +using Newtonsoft.Json.Serialization; + +namespace Microsoft.AspNetCore.JsonPatch.Adapters +{ + /// + public class ObjectAdapter : IObjectAdapterWithTest + { + /// + /// Initializes a new instance of . + /// + /// The . + /// The for logging . + public ObjectAdapter( + IContractResolver contractResolver, + Action logErrorAction): + this(contractResolver, logErrorAction, new AdapterFactory()) + { + } + + /// + /// Initializes a new instance of . + /// + /// The . + /// The for logging . + /// The to use when creating adaptors. + public ObjectAdapter( + IContractResolver contractResolver, + Action logErrorAction, + IAdapterFactory adapterFactory) + { + ContractResolver = contractResolver ?? throw new ArgumentNullException(nameof(contractResolver)); + LogErrorAction = logErrorAction; + AdapterFactory = adapterFactory ?? throw new ArgumentNullException(nameof(adapterFactory)); + } + + /// + /// Gets or sets the . + /// + public IContractResolver ContractResolver { get; } + + /// + /// Gets or sets the + /// + public IAdapterFactory AdapterFactory { get; } + + /// + /// Action for logging . + /// + public Action LogErrorAction { get; } + + public void Add(Operation operation, object objectToApplyTo) + { + if (operation == null) + { + throw new ArgumentNullException(nameof(operation)); + } + + if (objectToApplyTo == null) + { + throw new ArgumentNullException(nameof(objectToApplyTo)); + } + + Add(operation.path, operation.value, objectToApplyTo, operation); + } + + /// + /// Add is used by various operations (eg: add, copy, ...), yet through different operations; + /// This method allows code reuse yet reporting the correct operation on error + /// + private void Add( + string path, + object value, + object objectToApplyTo, + Operation operation) + { + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + + if (objectToApplyTo == null) + { + throw new ArgumentNullException(nameof(objectToApplyTo)); + } + + if (operation == null) + { + throw new ArgumentNullException(nameof(operation)); + } + + var parsedPath = new ParsedPath(path); + var visitor = new ObjectVisitor(parsedPath, ContractResolver, AdapterFactory); + + var target = objectToApplyTo; + if (!visitor.TryVisit(ref target, out var adapter, out var errorMessage)) + { + var error = CreatePathNotFoundError(objectToApplyTo, path, operation, errorMessage); + ErrorReporter(error); + return; + } + + if (!adapter.TryAdd(target, parsedPath.LastSegment, ContractResolver, value, out errorMessage)) + { + var error = CreateOperationFailedError(objectToApplyTo, path, operation, errorMessage); + ErrorReporter(error); + return; + } + } + + public void Move(Operation operation, object objectToApplyTo) + { + if (operation == null) + { + throw new ArgumentNullException(nameof(operation)); + } + + if (objectToApplyTo == null) + { + throw new ArgumentNullException(nameof(objectToApplyTo)); + } + + // Get value at 'from' location and add that value to the 'path' location + if (TryGetValue(operation.from, objectToApplyTo, operation, out var propertyValue)) + { + // remove that value + Remove(operation.from, objectToApplyTo, operation); + + // add that value to the path location + Add(operation.path, + propertyValue, + objectToApplyTo, + operation); + } + } + + public void Remove(Operation operation, object objectToApplyTo) + { + if (operation == null) + { + throw new ArgumentNullException(nameof(operation)); + } + + if (objectToApplyTo == null) + { + throw new ArgumentNullException(nameof(objectToApplyTo)); + } + + Remove(operation.path, objectToApplyTo, operation); + } + + /// + /// Remove is used by various operations (eg: remove, move, ...), yet through different operations; + /// This method allows code reuse yet reporting the correct operation on error. The return value + /// contains the type of the item that has been removed (and a bool possibly signifying an error) + /// This can be used by other methods, like replace, to ensure that we can pass in the correctly + /// typed value to whatever method follows. + /// + private void Remove(string path, object objectToApplyTo, Operation operationToReport) + { + var parsedPath = new ParsedPath(path); + var visitor = new ObjectVisitor(parsedPath, ContractResolver, AdapterFactory); + + var target = objectToApplyTo; + if (!visitor.TryVisit(ref target, out var adapter, out var errorMessage)) + { + var error = CreatePathNotFoundError(objectToApplyTo, path, operationToReport, errorMessage); + ErrorReporter(error); + return; + } + + if (!adapter.TryRemove(target, parsedPath.LastSegment, ContractResolver, out errorMessage)) + { + var error = CreateOperationFailedError(objectToApplyTo, path, operationToReport, errorMessage); + ErrorReporter(error); + return; + } + } + + public void Replace(Operation operation, object objectToApplyTo) + { + if (operation == null) + { + throw new ArgumentNullException(nameof(operation)); + } + + if (objectToApplyTo == null) + { + throw new ArgumentNullException(nameof(objectToApplyTo)); + } + + var parsedPath = new ParsedPath(operation.path); + var visitor = new ObjectVisitor(parsedPath, ContractResolver, AdapterFactory); + + var target = objectToApplyTo; + if (!visitor.TryVisit(ref target, out var adapter, out var errorMessage)) + { + var error = CreatePathNotFoundError(objectToApplyTo, operation.path, operation, errorMessage); + ErrorReporter(error); + return; + } + + if (!adapter.TryReplace(target, parsedPath.LastSegment, ContractResolver, operation.value, out errorMessage)) + { + var error = CreateOperationFailedError(objectToApplyTo, operation.path, operation, errorMessage); + ErrorReporter(error); + return; + } + } + + public void Copy(Operation operation, object objectToApplyTo) + { + if (operation == null) + { + throw new ArgumentNullException(nameof(operation)); + } + + if (objectToApplyTo == null) + { + throw new ArgumentNullException(nameof(objectToApplyTo)); + } + + // Get value at 'from' location and add that value to the 'path' location + if (TryGetValue(operation.from, objectToApplyTo, operation, out var propertyValue)) + { + // Create deep copy + var copyResult = ConversionResultProvider.CopyTo(propertyValue, propertyValue?.GetType()); + if (copyResult.CanBeConverted) + { + Add(operation.path, + copyResult.ConvertedInstance, + objectToApplyTo, + operation); + } + else + { + var error = CreateOperationFailedError(objectToApplyTo, operation.path, operation, Resources.FormatCannotCopyProperty(operation.from)); + ErrorReporter(error); + return; + } + } + } + + public void Test(Operation operation, object objectToApplyTo) + { + if (operation == null) + { + throw new ArgumentNullException(nameof(operation)); + } + + if (objectToApplyTo == null) + { + throw new ArgumentNullException(nameof(objectToApplyTo)); + } + + var parsedPath = new ParsedPath(operation.path); + var visitor = new ObjectVisitor(parsedPath, ContractResolver, AdapterFactory); + + var target = objectToApplyTo; + if (!visitor.TryVisit(ref target, out var adapter, out var errorMessage)) + { + var error = CreatePathNotFoundError(objectToApplyTo, operation.path, operation, errorMessage); + ErrorReporter(error); + return; + } + + if (!adapter.TryTest(target, parsedPath.LastSegment, ContractResolver, operation.value, out errorMessage)) + { + var error = CreateOperationFailedError(objectToApplyTo, operation.path, operation, errorMessage); + ErrorReporter(error); + return; + } + } + + private bool TryGetValue( + string fromLocation, + object objectToGetValueFrom, + Operation operation, + out object propertyValue) + { + if (fromLocation == null) + { + throw new ArgumentNullException(nameof(fromLocation)); + } + + if (objectToGetValueFrom == null) + { + throw new ArgumentNullException(nameof(objectToGetValueFrom)); + } + + if (operation == null) + { + throw new ArgumentNullException(nameof(operation)); + } + + propertyValue = null; + + var parsedPath = new ParsedPath(fromLocation); + var visitor = new ObjectVisitor(parsedPath, ContractResolver, AdapterFactory); + + var target = objectToGetValueFrom; + if (!visitor.TryVisit(ref target, out var adapter, out var errorMessage)) + { + var error = CreatePathNotFoundError(objectToGetValueFrom, fromLocation, operation, errorMessage); + ErrorReporter(error); + return false; + } + + if (!adapter.TryGet(target, parsedPath.LastSegment, ContractResolver, out propertyValue, out errorMessage)) + { + var error = CreateOperationFailedError(objectToGetValueFrom, fromLocation, operation, errorMessage); + ErrorReporter(error); + return false; + } + + return true; + } + + private Action ErrorReporter + { + get + { + return LogErrorAction ?? Internal.ErrorReporter.Default; + } + } + + private JsonPatchError CreateOperationFailedError(object target, string path, Operation operation, string errorMessage) + { + return new JsonPatchError( + target, + operation, + errorMessage ?? Resources.FormatCannotPerformOperation(operation.op, path)); + } + + private JsonPatchError CreatePathNotFoundError(object target, string path, Operation operation, string errorMessage) + { + return new JsonPatchError( + target, + operation, + errorMessage ?? Resources.FormatTargetLocationNotFound(operation.op, path)); + } + } +} \ No newline at end of file diff --git a/src/Features/JsonPatch/src/Converters/JsonPatchDocumentConverter.cs b/src/Features/JsonPatch/src/Converters/JsonPatchDocumentConverter.cs new file mode 100644 index 0000000000..aed9c48474 --- /dev/null +++ b/src/Features/JsonPatch/src/Converters/JsonPatchDocumentConverter.cs @@ -0,0 +1,76 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using Microsoft.AspNetCore.JsonPatch.Exceptions; +using Microsoft.AspNetCore.JsonPatch.Operations; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Serialization; + +namespace Microsoft.AspNetCore.JsonPatch.Converters +{ + public class JsonPatchDocumentConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + { + return true; + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, + JsonSerializer serializer) + { + if (objectType != typeof(JsonPatchDocument)) + { + throw new ArgumentException(Resources.FormatParameterMustMatchType("objectType", "JsonPatchDocument"), "objectType"); + } + + try + { + if (reader.TokenType == JsonToken.Null) + { + return null; + } + + // load jObject + var jObject = JArray.Load(reader); + + // Create target object for Json => list of operations + var targetOperations = new List(); + + // Create a new reader for this jObject, and set all properties + // to match the original reader. + var jObjectReader = jObject.CreateReader(); + jObjectReader.Culture = reader.Culture; + jObjectReader.DateParseHandling = reader.DateParseHandling; + jObjectReader.DateTimeZoneHandling = reader.DateTimeZoneHandling; + jObjectReader.FloatParseHandling = reader.FloatParseHandling; + + // Populate the object properties + serializer.Populate(jObjectReader, targetOperations); + + // container target: the JsonPatchDocument. + var container = new JsonPatchDocument(targetOperations, new DefaultContractResolver()); + + return container; + } + catch (Exception ex) + { + throw new JsonSerializationException(Resources.InvalidJsonPatchDocument, ex); + } + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + if (value is IJsonPatchDocument) + { + var jsonPatchDoc = (IJsonPatchDocument)value; + var lst = jsonPatchDoc.GetOperations(); + + // write out the operations, no envelope + serializer.Serialize(writer, lst); + } + } + } +} diff --git a/src/Features/JsonPatch/src/Converters/TypedJsonPatchDocumentConverter.cs b/src/Features/JsonPatch/src/Converters/TypedJsonPatchDocumentConverter.cs new file mode 100644 index 0000000000..fd779ba4ee --- /dev/null +++ b/src/Features/JsonPatch/src/Converters/TypedJsonPatchDocumentConverter.cs @@ -0,0 +1,64 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Reflection; +using Microsoft.AspNetCore.JsonPatch.Operations; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Serialization; + +namespace Microsoft.AspNetCore.JsonPatch.Converters +{ + public class TypedJsonPatchDocumentConverter : JsonPatchDocumentConverter + { + public override object ReadJson( + JsonReader reader, + Type objectType, + object existingValue, + JsonSerializer serializer) + { + try + { + if (reader.TokenType == JsonToken.Null) + { + return null; + } + + var genericType = objectType.GetTypeInfo().GenericTypeArguments[0]; + + // load jObject + var jObject = JArray.Load(reader); + + // Create target object for Json => list of operations, typed to genericType + var genericOperation = typeof(Operation<>); + var concreteOperationType = genericOperation.MakeGenericType(genericType); + + var genericList = typeof(List<>); + var concreteList = genericList.MakeGenericType(concreteOperationType); + + var targetOperations = Activator.CreateInstance(concreteList); + + //Create a new reader for this jObject, and set all properties to match the original reader. + var jObjectReader = jObject.CreateReader(); + jObjectReader.Culture = reader.Culture; + jObjectReader.DateParseHandling = reader.DateParseHandling; + jObjectReader.DateTimeZoneHandling = reader.DateTimeZoneHandling; + jObjectReader.FloatParseHandling = reader.FloatParseHandling; + + // Populate the object properties + serializer.Populate(jObjectReader, targetOperations); + + // container target: the typed JsonPatchDocument. + var container = Activator.CreateInstance(objectType, targetOperations, new DefaultContractResolver()); + + return container; + } + catch (Exception ex) + { + throw new JsonSerializationException(Resources.InvalidJsonPatchDocument, ex); + } + } + } +} \ No newline at end of file diff --git a/src/Features/JsonPatch/src/Exceptions/JsonPatchException.cs b/src/Features/JsonPatch/src/Exceptions/JsonPatchException.cs new file mode 100644 index 0000000000..90e080575a --- /dev/null +++ b/src/Features/JsonPatch/src/Exceptions/JsonPatchException.cs @@ -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 System; +using Microsoft.AspNetCore.JsonPatch.Operations; + +namespace Microsoft.AspNetCore.JsonPatch.Exceptions +{ + public class JsonPatchException : Exception + { + public Operation FailedOperation { get; private set; } + public object AffectedObject { get; private set; } + + + public JsonPatchException() + { + + } + + public JsonPatchException(JsonPatchError jsonPatchError, Exception innerException) + : base(jsonPatchError.ErrorMessage, innerException) + { + FailedOperation = jsonPatchError.Operation; + AffectedObject = jsonPatchError.AffectedObject; + } + + public JsonPatchException(JsonPatchError jsonPatchError) + : this(jsonPatchError, null) + { + } + + public JsonPatchException(string message, Exception innerException) + : base (message, innerException) + { + + } + } +} \ No newline at end of file diff --git a/src/Features/JsonPatch/src/Helpers/GetValueResult.cs b/src/Features/JsonPatch/src/Helpers/GetValueResult.cs new file mode 100644 index 0000000000..e2e739a027 --- /dev/null +++ b/src/Features/JsonPatch/src/Helpers/GetValueResult.cs @@ -0,0 +1,30 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.AspNetCore.JsonPatch.Helpers +{ + /// + /// Return value for the helper method used by Copy/Move. Needed to ensure we can make a different + /// decision in the calling method when the value is null because it cannot be fetched (HasError = true) + /// versus when it actually is null (much like why RemovedPropertyTypeResult is used for returning + /// type in the Remove operation). + /// + public class GetValueResult + { + public GetValueResult(object propertyValue, bool hasError) + { + PropertyValue = propertyValue; + HasError = hasError; + } + + /// + /// The value of the property we're trying to get + /// + public object PropertyValue { get; private set; } + + /// + /// HasError: true when an error occurred, the operation didn't complete succesfully + /// + public bool HasError { get; private set; } + } +} diff --git a/src/Features/JsonPatch/src/Helpers/JsonPatchProperty.cs b/src/Features/JsonPatch/src/Helpers/JsonPatchProperty.cs new file mode 100644 index 0000000000..041b0104ac --- /dev/null +++ b/src/Features/JsonPatch/src/Helpers/JsonPatchProperty.cs @@ -0,0 +1,43 @@ +// 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 Newtonsoft.Json.Serialization; + +namespace Microsoft.AspNetCore.JsonPatch +{ + /// + /// Metadata for JsonProperty. + /// + public class JsonPatchProperty + { + /// + /// Initializes a new instance. + /// + public JsonPatchProperty(JsonProperty property, object parent) + { + if (property == null) + { + throw new ArgumentNullException(nameof(property)); + } + + if (parent == null) + { + throw new ArgumentNullException(nameof(parent)); + } + + Property = property; + Parent = parent; + } + + /// + /// Gets or sets JsonProperty. + /// + public JsonProperty Property { get; set; } + + /// + /// Gets or sets Parent. + /// + public object Parent { get; set; } + } +} \ No newline at end of file diff --git a/src/Features/JsonPatch/src/IJsonPatchDocument.cs b/src/Features/JsonPatch/src/IJsonPatchDocument.cs new file mode 100644 index 0000000000..fc5f5bd4d1 --- /dev/null +++ b/src/Features/JsonPatch/src/IJsonPatchDocument.cs @@ -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 Microsoft.AspNetCore.JsonPatch.Operations; +using System.Collections.Generic; +using Newtonsoft.Json.Serialization; + +namespace Microsoft.AspNetCore.JsonPatch +{ + public interface IJsonPatchDocument + { + IContractResolver ContractResolver { get; set; } + + IList GetOperations(); + } +} \ No newline at end of file diff --git a/src/Features/JsonPatch/src/Internal/ConversionResult.cs b/src/Features/JsonPatch/src/Internal/ConversionResult.cs new file mode 100644 index 0000000000..77181eb18d --- /dev/null +++ b/src/Features/JsonPatch/src/Internal/ConversionResult.cs @@ -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. + +namespace Microsoft.AspNetCore.JsonPatch.Internal +{ + public class ConversionResult + { + public ConversionResult(bool canBeConverted, object convertedInstance) + { + CanBeConverted = canBeConverted; + ConvertedInstance = convertedInstance; + } + + public bool CanBeConverted { get; } + public object ConvertedInstance { get; } + } +} \ No newline at end of file diff --git a/src/Features/JsonPatch/src/Internal/ConversionResultProvider.cs b/src/Features/JsonPatch/src/Internal/ConversionResultProvider.cs new file mode 100644 index 0000000000..3d0b6cc979 --- /dev/null +++ b/src/Features/JsonPatch/src/Internal/ConversionResultProvider.cs @@ -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; +using System.Reflection; +using Newtonsoft.Json; + +namespace Microsoft.AspNetCore.JsonPatch.Internal +{ + public static class ConversionResultProvider + { + public static ConversionResult ConvertTo(object value, Type typeToConvertTo) + { + if (value == null) + { + return new ConversionResult(IsNullableType(typeToConvertTo), null); + } + else if (typeToConvertTo.IsAssignableFrom(value.GetType())) + { + // No need to convert + return new ConversionResult(true, value); + } + else + { + try + { + var deserialized = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(value), typeToConvertTo); + return new ConversionResult(true, deserialized); + } + catch + { + return new ConversionResult(canBeConverted: false, convertedInstance: null); + } + } + } + + public static ConversionResult CopyTo(object value, Type typeToConvertTo) + { + var targetType = typeToConvertTo; + if (value == null) + { + return new ConversionResult(canBeConverted: true, convertedInstance: null); + } + else if (typeToConvertTo.IsAssignableFrom(value.GetType())) + { + // Keep original type + targetType = value.GetType(); + } + try + { + var deserialized = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(value), targetType); + return new ConversionResult(true, deserialized); + } + catch + { + return new ConversionResult(canBeConverted: false, convertedInstance: null); + } + } + + private static bool IsNullableType(Type type) + { + var typeInfo = type.GetTypeInfo(); + if (typeInfo.IsValueType) + { + // value types are only nullable if they are Nullable + return typeInfo.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>); + } + else + { + // reference types are always nullable + return true; + } + } + } +} diff --git a/src/Features/JsonPatch/src/Internal/DictionaryAdapterOfTU.cs b/src/Features/JsonPatch/src/Internal/DictionaryAdapterOfTU.cs new file mode 100644 index 0000000000..be2bbffd86 --- /dev/null +++ b/src/Features/JsonPatch/src/Internal/DictionaryAdapterOfTU.cs @@ -0,0 +1,245 @@ +// 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 Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Serialization; + +namespace Microsoft.AspNetCore.JsonPatch.Internal +{ + public class DictionaryAdapter : IAdapter + { + public virtual bool TryAdd( + object target, + string segment, + IContractResolver contractResolver, + object value, + out string errorMessage) + { + var contract = (JsonDictionaryContract)contractResolver.ResolveContract(target.GetType()); + var key = contract.DictionaryKeyResolver(segment); + var dictionary = (IDictionary)target; + + // As per JsonPatch spec, if a key already exists, adding should replace the existing value + if (!TryConvertKey(key, out var convertedKey, out errorMessage)) + { + return false; + } + + if (!TryConvertValue(value, out var convertedValue, out errorMessage)) + { + return false; + } + + dictionary[convertedKey] = convertedValue; + errorMessage = null; + return true; + } + + public virtual bool TryGet( + object target, + string segment, + IContractResolver contractResolver, + out object value, + out string errorMessage) + { + var contract = (JsonDictionaryContract)contractResolver.ResolveContract(target.GetType()); + var key = contract.DictionaryKeyResolver(segment); + var dictionary = (IDictionary)target; + + if (!TryConvertKey(key, out var convertedKey, out errorMessage)) + { + value = null; + return false; + } + + if (!dictionary.ContainsKey(convertedKey)) + { + value = null; + errorMessage = Resources.FormatTargetLocationAtPathSegmentNotFound(segment); + return false; + } + + value = dictionary[convertedKey]; + errorMessage = null; + return true; + } + + public virtual bool TryRemove( + object target, + string segment, + IContractResolver contractResolver, + out string errorMessage) + { + var contract = (JsonDictionaryContract)contractResolver.ResolveContract(target.GetType()); + var key = contract.DictionaryKeyResolver(segment); + var dictionary = (IDictionary)target; + + if (!TryConvertKey(key, out var convertedKey, out errorMessage)) + { + return false; + } + + // As per JsonPatch spec, the target location must exist for remove to be successful + if (!dictionary.ContainsKey(convertedKey)) + { + errorMessage = Resources.FormatTargetLocationAtPathSegmentNotFound(segment); + return false; + } + + dictionary.Remove(convertedKey); + + errorMessage = null; + return true; + } + + public virtual bool TryReplace( + object target, + string segment, + IContractResolver contractResolver, + object value, + out string errorMessage) + { + var contract = (JsonDictionaryContract)contractResolver.ResolveContract(target.GetType()); + var key = contract.DictionaryKeyResolver(segment); + var dictionary = (IDictionary)target; + + if (!TryConvertKey(key, out var convertedKey, out errorMessage)) + { + return false; + } + + // As per JsonPatch spec, the target location must exist for remove to be successful + if (!dictionary.ContainsKey(convertedKey)) + { + errorMessage = Resources.FormatTargetLocationAtPathSegmentNotFound(segment); + return false; + } + + if (!TryConvertValue(value, out var convertedValue, out errorMessage)) + { + return false; + } + + dictionary[convertedKey] = convertedValue; + + errorMessage = null; + return true; + } + + public virtual bool TryTest( + object target, + string segment, + IContractResolver contractResolver, + object value, + out string errorMessage) + { + var contract = (JsonDictionaryContract)contractResolver.ResolveContract(target.GetType()); + var key = contract.DictionaryKeyResolver(segment); + var dictionary = (IDictionary)target; + + if (!TryConvertKey(key, out var convertedKey, out errorMessage)) + { + return false; + } + + // As per JsonPatch spec, the target location must exist for test to be successful + if (!dictionary.ContainsKey(convertedKey)) + { + errorMessage = Resources.FormatTargetLocationAtPathSegmentNotFound(segment); + return false; + } + + if (!TryConvertValue(value, out var convertedValue, out errorMessage)) + { + return false; + } + + var currentValue = dictionary[convertedKey]; + + // The target segment does not have an assigned value to compare the test value with + if (currentValue == null || string.IsNullOrEmpty(currentValue.ToString())) + { + errorMessage = Resources.FormatValueForTargetSegmentCannotBeNullOrEmpty(segment); + return false; + } + + if (!JToken.DeepEquals(JsonConvert.SerializeObject(currentValue), JsonConvert.SerializeObject(convertedValue))) + { + errorMessage = Resources.FormatValueNotEqualToTestValue(currentValue, value, segment); + return false; + } + else + { + errorMessage = null; + return true; + } + } + + public virtual bool TryTraverse( + object target, + string segment, + IContractResolver contractResolver, + out object nextTarget, + out string errorMessage) + { + var contract = (JsonDictionaryContract)contractResolver.ResolveContract(target.GetType()); + var key = contract.DictionaryKeyResolver(segment); + var dictionary = (IDictionary)target; + + if (!TryConvertKey(key, out var convertedKey, out errorMessage)) + { + nextTarget = null; + return false; + } + + if (dictionary.ContainsKey(convertedKey)) + { + nextTarget = dictionary[convertedKey]; + errorMessage = null; + return true; + } + else + { + nextTarget = null; + errorMessage = null; + return false; + } + } + + protected virtual bool TryConvertKey(string key, out TKey convertedKey, out string errorMessage) + { + var conversionResult = ConversionResultProvider.ConvertTo(key, typeof(TKey)); + if (conversionResult.CanBeConverted) + { + errorMessage = null; + convertedKey = (TKey)conversionResult.ConvertedInstance; + return true; + } + else + { + errorMessage = Resources.FormatInvalidPathSegment(key); + convertedKey = default(TKey); + return false; + } + } + + protected virtual bool TryConvertValue(object value, out TValue convertedValue, out string errorMessage) + { + var conversionResult = ConversionResultProvider.ConvertTo(value, typeof(TValue)); + if (conversionResult.CanBeConverted) + { + errorMessage = null; + convertedValue = (TValue)conversionResult.ConvertedInstance; + return true; + } + else + { + errorMessage = Resources.FormatInvalidValueForProperty(value); + convertedValue = default(TValue); + return false; + } + } + } +} diff --git a/src/Features/JsonPatch/src/Internal/DynamicObjectAdapter.cs b/src/Features/JsonPatch/src/Internal/DynamicObjectAdapter.cs new file mode 100644 index 0000000000..5b3d7d8bdd --- /dev/null +++ b/src/Features/JsonPatch/src/Internal/DynamicObjectAdapter.cs @@ -0,0 +1,248 @@ +// 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.Reflection; +using System.Runtime.CompilerServices; +using Microsoft.CSharp.RuntimeBinder; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Serialization; +using CSharpBinder = Microsoft.CSharp.RuntimeBinder; + +namespace Microsoft.AspNetCore.JsonPatch.Internal +{ + public class DynamicObjectAdapter : IAdapter + { + public virtual bool TryAdd( + object target, + string segment, + IContractResolver contractResolver, + object value, + out string errorMessage) + { + if (!TrySetDynamicObjectProperty(target, contractResolver, segment, value, out errorMessage)) + { + return false; + } + + errorMessage = null; + return true; + } + + public virtual bool TryGet( + object target, + string segment, + IContractResolver contractResolver, + out object value, + out string errorMessage) + { + if (!TryGetDynamicObjectProperty(target, contractResolver, segment, out value, out errorMessage)) + { + value = null; + return false; + } + + errorMessage = null; + return true; + } + + public virtual bool TryRemove( + object target, + string segment, + IContractResolver contractResolver, + out string errorMessage) + { + if (!TryGetDynamicObjectProperty(target, contractResolver, segment, out var property, out errorMessage)) + { + return false; + } + + // Setting the value to "null" will use the default value in case of value types, and + // null in case of reference types + object value = null; + if (property.GetType().GetTypeInfo().IsValueType + && Nullable.GetUnderlyingType(property.GetType()) == null) + { + value = Activator.CreateInstance(property.GetType()); + } + + if (!TrySetDynamicObjectProperty(target, contractResolver, segment, value, out errorMessage)) + { + return false; + } + + errorMessage = null; + return true; + + } + + public virtual bool TryReplace( + object target, + string segment, + IContractResolver contractResolver, + object value, + out string errorMessage) + { + if (!TryGetDynamicObjectProperty(target, contractResolver, segment, out var property, out errorMessage)) + { + return false; + } + + if (!TryConvertValue(value, property.GetType(), out var convertedValue)) + { + errorMessage = Resources.FormatInvalidValueForProperty(value); + return false; + } + + if (!TryRemove(target, segment, contractResolver, out errorMessage)) + { + return false; + } + + if (!TrySetDynamicObjectProperty(target, contractResolver, segment, convertedValue, out errorMessage)) + { + return false; + } + + errorMessage = null; + return true; + } + + public virtual bool TryTest( + object target, + string segment, + IContractResolver contractResolver, + object value, + out string errorMessage) + { + if (!TryGetDynamicObjectProperty(target, contractResolver, segment, out var property, out errorMessage)) + { + return false; + } + + if (!TryConvertValue(value, property.GetType(), out var convertedValue)) + { + errorMessage = Resources.FormatInvalidValueForProperty(value); + return false; + } + + if (!JToken.DeepEquals(JsonConvert.SerializeObject(property), JsonConvert.SerializeObject(convertedValue))) + { + errorMessage = Resources.FormatValueNotEqualToTestValue(property, value, segment); + return false; + } + else + { + errorMessage = null; + return true; + } + } + + public virtual bool TryTraverse( + object target, + string segment, + IContractResolver contractResolver, + out object nextTarget, + out string errorMessage) + { + if (!TryGetDynamicObjectProperty(target, contractResolver, segment, out var property, out errorMessage)) + { + nextTarget = null; + return false; + } + else + { + nextTarget = property; + errorMessage = null; + return true; + } + } + + protected virtual bool TryGetDynamicObjectProperty( + object target, + IContractResolver contractResolver, + string segment, + out object value, + out string errorMessage) + { + var jsonDynamicContract = (JsonDynamicContract)contractResolver.ResolveContract(target.GetType()); + + var propertyName = jsonDynamicContract.PropertyNameResolver(segment); + + var binder = CSharpBinder.Binder.GetMember( + CSharpBinderFlags.None, + propertyName, + target.GetType(), + new List + { + CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) + }); + + var callsite = CallSite>.Create(binder); + + try + { + value = callsite.Target(callsite, target); + errorMessage = null; + return true; + } + catch (RuntimeBinderException) + { + value = null; + errorMessage = Resources.FormatTargetLocationAtPathSegmentNotFound(segment); + return false; + } + } + + protected virtual bool TrySetDynamicObjectProperty( + object target, + IContractResolver contractResolver, + string segment, + object value, + out string errorMessage) + { + var jsonDynamicContract = (JsonDynamicContract)contractResolver.ResolveContract(target.GetType()); + + var propertyName = jsonDynamicContract.PropertyNameResolver(segment); + + var binder = CSharpBinder.Binder.SetMember( + CSharpBinderFlags.None, + propertyName, + target.GetType(), + new List + { + CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null), + CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) + }); + + var callsite = CallSite>.Create(binder); + + try + { + callsite.Target(callsite, target, value); + errorMessage = null; + return true; + } + catch (RuntimeBinderException) + { + errorMessage = Resources.FormatTargetLocationAtPathSegmentNotFound(segment); + return false; + } + } + + protected virtual bool TryConvertValue(object value, Type propertyType, out object convertedValue) + { + var conversionResult = ConversionResultProvider.ConvertTo(value, propertyType); + if (!conversionResult.CanBeConverted) + { + convertedValue = null; + return false; + } + + convertedValue = conversionResult.ConvertedInstance; + return true; + } + } +} diff --git a/src/Features/JsonPatch/src/Internal/ErrorReporter.cs b/src/Features/JsonPatch/src/Internal/ErrorReporter.cs new file mode 100644 index 0000000000..76b55a6144 --- /dev/null +++ b/src/Features/JsonPatch/src/Internal/ErrorReporter.cs @@ -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; +using Microsoft.AspNetCore.JsonPatch.Exceptions; + +namespace Microsoft.AspNetCore.JsonPatch.Internal +{ + internal static class ErrorReporter + { + public static readonly Action Default = (error) => + { + throw new JsonPatchException(error); + }; + } +} diff --git a/src/Features/JsonPatch/src/Internal/IAdapter.cs b/src/Features/JsonPatch/src/Internal/IAdapter.cs new file mode 100644 index 0000000000..ec28131f7d --- /dev/null +++ b/src/Features/JsonPatch/src/Internal/IAdapter.cs @@ -0,0 +1,51 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Newtonsoft.Json.Serialization; + +namespace Microsoft.AspNetCore.JsonPatch.Internal +{ + public interface IAdapter + { + bool TryTraverse( + object target, + string segment, + IContractResolver contractResolver, + out object nextTarget, + out string errorMessage); + + bool TryAdd( + object target, + string segment, + IContractResolver contractResolver, + object value, + out string errorMessage); + + bool TryRemove( + object target, + string segment, + IContractResolver contractResolver, + out string errorMessage); + + bool TryGet( + object target, + string segment, + IContractResolver contractResolver, + out object value, + out string errorMessage); + + bool TryReplace( + object target, + string segment, + IContractResolver contractResolver, + object value, + out string errorMessage); + + bool TryTest( + object target, + string segment, + IContractResolver contractResolver, + object value, + out string errorMessage); + } +} diff --git a/src/Features/JsonPatch/src/Internal/ListAdapter.cs b/src/Features/JsonPatch/src/Internal/ListAdapter.cs new file mode 100644 index 0000000000..597f7b9f5f --- /dev/null +++ b/src/Features/JsonPatch/src/Internal/ListAdapter.cs @@ -0,0 +1,349 @@ +// 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 Microsoft.Extensions.Internal; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Serialization; + +namespace Microsoft.AspNetCore.JsonPatch.Internal +{ + public class ListAdapter : IAdapter + { + public virtual bool TryAdd( + object target, + string segment, + IContractResolver contractResolver, + object value, + out string errorMessage) + { + var list = (IList)target; + + if (!TryGetListTypeArgument(list, out var typeArgument, out errorMessage)) + { + return false; + } + + if (!TryGetPositionInfo(list, segment, OperationType.Add, out var positionInfo, out errorMessage)) + { + return false; + } + + if (!TryConvertValue(value, typeArgument, segment, out var convertedValue, out errorMessage)) + { + return false; + } + + if (positionInfo.Type == PositionType.EndOfList) + { + list.Add(convertedValue); + } + else + { + list.Insert(positionInfo.Index, convertedValue); + } + + errorMessage = null; + return true; + } + + public virtual bool TryGet( + object target, + string segment, + IContractResolver contractResolver, + out object value, + out string errorMessage) + { + var list = (IList)target; + + if (!TryGetListTypeArgument(list, out var typeArgument, out errorMessage)) + { + value = null; + return false; + } + + if (!TryGetPositionInfo(list, segment, OperationType.Get, out var positionInfo, out errorMessage)) + { + value = null; + return false; + } + + if (positionInfo.Type == PositionType.EndOfList) + { + value = list[list.Count - 1]; + } + else + { + value = list[positionInfo.Index]; + } + + errorMessage = null; + return true; + } + + public virtual bool TryRemove( + object target, + string segment, + IContractResolver contractResolver, + out string errorMessage) + { + var list = (IList)target; + + if (!TryGetListTypeArgument(list, out var typeArgument, out errorMessage)) + { + return false; + } + + if (!TryGetPositionInfo(list, segment, OperationType.Remove, out var positionInfo, out errorMessage)) + { + return false; + } + + if (positionInfo.Type == PositionType.EndOfList) + { + list.RemoveAt(list.Count - 1); + } + else + { + list.RemoveAt(positionInfo.Index); + } + + errorMessage = null; + return true; + } + + public virtual bool TryReplace( + object target, + string segment, + IContractResolver contractResolver, + object value, + out string errorMessage) + { + var list = (IList)target; + + if (!TryGetListTypeArgument(list, out var typeArgument, out errorMessage)) + { + return false; + } + + if (!TryGetPositionInfo(list, segment, OperationType.Replace, out var positionInfo, out errorMessage)) + { + return false; + } + + if (!TryConvertValue(value, typeArgument, segment, out var convertedValue, out errorMessage)) + { + return false; + } + + if (positionInfo.Type == PositionType.EndOfList) + { + list[list.Count - 1] = convertedValue; + } + else + { + list[positionInfo.Index] = convertedValue; + } + + errorMessage = null; + return true; + } + + public virtual bool TryTest( + object target, + string segment, + IContractResolver contractResolver, + object value, + out string errorMessage) + { + var list = (IList)target; + + if (!TryGetListTypeArgument(list, out var typeArgument, out errorMessage)) + { + return false; + } + + if (!TryGetPositionInfo(list, segment, OperationType.Replace, out var positionInfo, out errorMessage)) + { + return false; + } + + if (!TryConvertValue(value, typeArgument, segment, out var convertedValue, out errorMessage)) + { + return false; + } + + var currentValue = list[positionInfo.Index]; + if (!JToken.DeepEquals(JsonConvert.SerializeObject(currentValue), JsonConvert.SerializeObject(convertedValue))) + { + errorMessage = Resources.FormatValueAtListPositionNotEqualToTestValue(currentValue, value, positionInfo.Index); + return false; + } + else + { + errorMessage = null; + return true; + } + } + + public virtual bool TryTraverse( + object target, + string segment, + IContractResolver contractResolver, + out object value, + out string errorMessage) + { + var list = target as IList; + if (list == null) + { + value = null; + errorMessage = null; + return false; + } + + var index = -1; + if (!int.TryParse(segment, out index)) + { + value = null; + errorMessage = Resources.FormatInvalidIndexValue(segment); + return false; + } + + if (index < 0 || index >= list.Count) + { + value = null; + errorMessage = Resources.FormatIndexOutOfBounds(segment); + return false; + } + + value = list[index]; + errorMessage = null; + return true; + } + + protected virtual bool TryConvertValue( + object originalValue, + Type listTypeArgument, + string segment, + out object convertedValue, + out string errorMessage) + { + var conversionResult = ConversionResultProvider.ConvertTo(originalValue, listTypeArgument); + if (!conversionResult.CanBeConverted) + { + convertedValue = null; + errorMessage = Resources.FormatInvalidValueForProperty(originalValue); + return false; + } + + convertedValue = conversionResult.ConvertedInstance; + errorMessage = null; + return true; + } + + protected virtual bool TryGetListTypeArgument(IList list, out Type listTypeArgument, out string errorMessage) + { + // Arrays are not supported as they have fixed size and operations like Add, Insert do not make sense + var listType = list.GetType(); + if (listType.IsArray) + { + errorMessage = Resources.FormatPatchNotSupportedForArrays(listType.FullName); + listTypeArgument = null; + return false; + } + else + { + var genericList = ClosedGenericMatcher.ExtractGenericInterface(listType, typeof(IList<>)); + if (genericList == null) + { + errorMessage = Resources.FormatPatchNotSupportedForNonGenericLists(listType.FullName); + listTypeArgument = null; + return false; + } + else + { + listTypeArgument = genericList.GenericTypeArguments[0]; + errorMessage = null; + return true; + } + } + } + + protected virtual bool TryGetPositionInfo( + IList list, + string segment, + OperationType operationType, + out PositionInfo positionInfo, + out string errorMessage) + { + if (segment == "-") + { + positionInfo = new PositionInfo(PositionType.EndOfList, -1); + errorMessage = null; + return true; + } + + var position = -1; + if (int.TryParse(segment, out position)) + { + if (position >= 0 && position < list.Count) + { + positionInfo = new PositionInfo(PositionType.Index, position); + errorMessage = null; + return true; + } + // As per JSON Patch spec, for Add operation the index value representing the number of elements is valid, + // where as for other operations like Remove, Replace, Move and Copy the target index MUST exist. + else if (position == list.Count && operationType == OperationType.Add) + { + positionInfo = new PositionInfo(PositionType.EndOfList, -1); + errorMessage = null; + return true; + } + else + { + positionInfo = new PositionInfo(PositionType.OutOfBounds, position); + errorMessage = Resources.FormatIndexOutOfBounds(segment); + return false; + } + } + else + { + positionInfo = new PositionInfo(PositionType.Invalid, -1); + errorMessage = Resources.FormatInvalidIndexValue(segment); + return false; + } + } + + protected struct PositionInfo + { + public PositionInfo(PositionType type, int index) + { + Type = type; + Index = index; + } + + public PositionType Type { get; } + public int Index { get; } + } + + protected enum PositionType + { + Index, // valid index + EndOfList, // '-' + Invalid, // Ex: not an integer + OutOfBounds + } + + protected enum OperationType + { + Add, + Remove, + Get, + Replace + } + } +} diff --git a/src/Features/JsonPatch/src/Internal/ObjectVisitor.cs b/src/Features/JsonPatch/src/Internal/ObjectVisitor.cs new file mode 100644 index 0000000000..6cb4d7450c --- /dev/null +++ b/src/Features/JsonPatch/src/Internal/ObjectVisitor.cs @@ -0,0 +1,79 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using Microsoft.AspNetCore.JsonPatch.Adapters; +using Newtonsoft.Json.Serialization; + +namespace Microsoft.AspNetCore.JsonPatch.Internal +{ + public class ObjectVisitor + { + private readonly IAdapterFactory _adapterFactory; + private readonly IContractResolver _contractResolver; + private readonly ParsedPath _path; + + /// + /// Initializes a new instance of . + /// + /// The path of the JsonPatch operation + /// The . + public ObjectVisitor(ParsedPath path, IContractResolver contractResolver) + :this(path, contractResolver, new AdapterFactory()) + { + } + + /// + /// Initializes a new instance of . + /// + /// The path of the JsonPatch operation + /// The . + /// The to use when creating adaptors. + public ObjectVisitor(ParsedPath path, IContractResolver contractResolver, IAdapterFactory adapterFactory) + { + _path = path; + _contractResolver = contractResolver ?? throw new ArgumentNullException(nameof(contractResolver)); + _adapterFactory = adapterFactory ?? throw new ArgumentNullException(nameof(adapterFactory)); + } + + public bool TryVisit(ref object target, out IAdapter adapter, out string errorMessage) + { + if (target == null) + { + adapter = null; + errorMessage = null; + return false; + } + + adapter = SelectAdapter(target); + + // Traverse until the penultimate segment to get the target object and adapter + for (var i = 0; i < _path.Segments.Count - 1; i++) + { + if (!adapter.TryTraverse(target, _path.Segments[i], _contractResolver, out var next, out errorMessage)) + { + adapter = null; + return false; + } + + // If we hit a null on an interior segment then we need to stop traversing. + if (next == null) + { + adapter = null; + return false; + } + + target = next; + adapter = SelectAdapter(target); + } + + errorMessage = null; + return true; + } + + private IAdapter SelectAdapter(object targetObject) + { + return _adapterFactory.Create(targetObject, _contractResolver); + } + } +} diff --git a/src/Features/JsonPatch/src/Internal/ParsedPath.cs b/src/Features/JsonPatch/src/Internal/ParsedPath.cs new file mode 100644 index 0000000000..8d0e69aa4d --- /dev/null +++ b/src/Features/JsonPatch/src/Internal/ParsedPath.cs @@ -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 Microsoft.AspNetCore.JsonPatch.Exceptions; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Microsoft.AspNetCore.JsonPatch.Internal +{ + public struct ParsedPath + { + private static readonly string[] Empty = null; + + private readonly string[] _segments; + + public ParsedPath(string path) + { + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + + _segments = ParsePath(path); + } + + public string LastSegment + { + get + { + if (_segments == null || _segments.Length == 0) + { + return null; + } + + return _segments[_segments.Length - 1]; + } + } + + public IReadOnlyList Segments => _segments ?? Empty; + + private static string[] ParsePath(string path) + { + var strings = new List(); + var sb = new StringBuilder(path.Length); + + for (var i = 0; i < path.Length; i++) + { + if (path[i] == '/') + { + if (sb.Length > 0) + { + strings.Add(sb.ToString()); + sb.Length = 0; + } + } + else if (path[i] == '~') + { + ++i; + if (i >= path.Length) + { + throw new JsonPatchException(Resources.FormatInvalidValueForPath(path), null); + } + + if (path[i] == '0') + { + sb.Append('~'); + } + else if (path[i] == '1') + { + sb.Append('/'); + } + else + { + throw new JsonPatchException(Resources.FormatInvalidValueForPath(path), null); + } + } + else + { + sb.Append(path[i]); + } + } + + if (sb.Length > 0) + { + strings.Add(sb.ToString()); + } + + return strings.ToArray(); + } + } +} diff --git a/src/Features/JsonPatch/src/Internal/PathHelpers.cs b/src/Features/JsonPatch/src/Internal/PathHelpers.cs new file mode 100644 index 0000000000..f0afedb60e --- /dev/null +++ b/src/Features/JsonPatch/src/Internal/PathHelpers.cs @@ -0,0 +1,32 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.AspNetCore.JsonPatch.Exceptions; +using System; + +namespace Microsoft.AspNetCore.JsonPatch.Internal +{ + internal static class PathHelpers + { + internal static string ValidateAndNormalizePath(string path) + { + // check for most common path errors on create. This is not + // absolutely necessary, but it allows us to already catch mistakes + // on creation of the patch document rather than on execute. + + if (path.Contains("//")) + { + throw new JsonPatchException(Resources.FormatInvalidValueForPath(path), null); + } + + if (!path.StartsWith("/", StringComparison.Ordinal)) + { + return "/" + path; + } + else + { + return path; + } + } + } +} diff --git a/src/Features/JsonPatch/src/Internal/PocoAdapter.cs b/src/Features/JsonPatch/src/Internal/PocoAdapter.cs new file mode 100644 index 0000000000..5ba3e5587b --- /dev/null +++ b/src/Features/JsonPatch/src/Internal/PocoAdapter.cs @@ -0,0 +1,236 @@ +// 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.Reflection; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Serialization; + +namespace Microsoft.AspNetCore.JsonPatch.Internal +{ + public class PocoAdapter : IAdapter + { + public virtual bool TryAdd( + object target, + string segment, + IContractResolver contractResolver, + object value, + out string errorMessage) + { + if (!TryGetJsonProperty(target, contractResolver, segment, out var jsonProperty)) + { + errorMessage = Resources.FormatTargetLocationAtPathSegmentNotFound(segment); + return false; + } + + if (!jsonProperty.Writable) + { + errorMessage = Resources.FormatCannotUpdateProperty(segment); + return false; + } + + if (!TryConvertValue(value, jsonProperty.PropertyType, out var convertedValue)) + { + errorMessage = Resources.FormatInvalidValueForProperty(value); + return false; + } + + jsonProperty.ValueProvider.SetValue(target, convertedValue); + + errorMessage = null; + return true; + } + + public virtual bool TryGet( + object target, + string segment, + IContractResolver contractResolver, + out object value, + out string errorMessage) + { + if (!TryGetJsonProperty(target, contractResolver, segment, out var jsonProperty)) + { + errorMessage = Resources.FormatTargetLocationAtPathSegmentNotFound(segment); + value = null; + return false; + } + + if (!jsonProperty.Readable) + { + errorMessage = Resources.FormatCannotReadProperty(segment); + value = null; + return false; + } + + value = jsonProperty.ValueProvider.GetValue(target); + errorMessage = null; + return true; + } + + public virtual bool TryRemove( + object target, + string segment, + IContractResolver contractResolver, + out string errorMessage) + { + if (!TryGetJsonProperty(target, contractResolver, segment, out var jsonProperty)) + { + errorMessage = Resources.FormatTargetLocationAtPathSegmentNotFound(segment); + return false; + } + + if (!jsonProperty.Writable) + { + errorMessage = Resources.FormatCannotUpdateProperty(segment); + return false; + } + + // Setting the value to "null" will use the default value in case of value types, and + // null in case of reference types + object value = null; + if (jsonProperty.PropertyType.GetTypeInfo().IsValueType + && Nullable.GetUnderlyingType(jsonProperty.PropertyType) == null) + { + value = Activator.CreateInstance(jsonProperty.PropertyType); + } + + jsonProperty.ValueProvider.SetValue(target, value); + + errorMessage = null; + return true; + } + + public virtual bool TryReplace( + object target, + string segment, + IContractResolver + contractResolver, + object value, + out string errorMessage) + { + if (!TryGetJsonProperty(target, contractResolver, segment, out var jsonProperty)) + { + errorMessage = Resources.FormatTargetLocationAtPathSegmentNotFound(segment); + return false; + } + + if (!jsonProperty.Writable) + { + errorMessage = Resources.FormatCannotUpdateProperty(segment); + return false; + } + + if (!TryConvertValue(value, jsonProperty.PropertyType, out var convertedValue)) + { + errorMessage = Resources.FormatInvalidValueForProperty(value); + return false; + } + + jsonProperty.ValueProvider.SetValue(target, convertedValue); + + errorMessage = null; + return true; + } + + public virtual bool TryTest( + object target, + string segment, + IContractResolver + contractResolver, + object value, + out string errorMessage) + { + if (!TryGetJsonProperty(target, contractResolver, segment, out var jsonProperty)) + { + errorMessage = Resources.FormatTargetLocationAtPathSegmentNotFound(segment); + return false; + } + + if (!jsonProperty.Readable) + { + errorMessage = Resources.FormatCannotReadProperty(segment); + return false; + } + + if (!TryConvertValue(value, jsonProperty.PropertyType, out var convertedValue)) + { + errorMessage = Resources.FormatInvalidValueForProperty(value); + return false; + } + + var currentValue = jsonProperty.ValueProvider.GetValue(target); + if (!JToken.DeepEquals(JsonConvert.SerializeObject(currentValue), JsonConvert.SerializeObject(convertedValue))) + { + errorMessage = Resources.FormatValueNotEqualToTestValue(currentValue, value, segment); + return false; + } + + errorMessage = null; + return true; + } + + public virtual bool TryTraverse( + object target, + string segment, + IContractResolver contractResolver, + out object value, + out string errorMessage) + { + if (target == null) + { + value = null; + errorMessage = null; + return false; + } + + if (TryGetJsonProperty(target, contractResolver, segment, out var jsonProperty)) + { + value = jsonProperty.ValueProvider.GetValue(target); + errorMessage = null; + return true; + } + + value = null; + errorMessage = Resources.FormatTargetLocationAtPathSegmentNotFound(segment); + return false; + } + + protected virtual bool TryGetJsonProperty( + object target, + IContractResolver contractResolver, + string segment, + out JsonProperty jsonProperty) + { + if (contractResolver.ResolveContract(target.GetType()) is JsonObjectContract jsonObjectContract) + { + var pocoProperty = jsonObjectContract + .Properties + .FirstOrDefault(p => string.Equals(p.PropertyName, segment, StringComparison.OrdinalIgnoreCase)); + + if (pocoProperty != null) + { + jsonProperty = pocoProperty; + return true; + } + } + + jsonProperty = null; + return false; + } + + protected virtual bool TryConvertValue(object value, Type propertyType, out object convertedValue) + { + var conversionResult = ConversionResultProvider.ConvertTo(value, propertyType); + if (!conversionResult.CanBeConverted) + { + convertedValue = null; + return false; + } + + convertedValue = conversionResult.ConvertedInstance; + return true; + } + } +} diff --git a/src/Features/JsonPatch/src/JsonPatchDocument.cs b/src/Features/JsonPatch/src/JsonPatchDocument.cs new file mode 100644 index 0000000000..1888ea6b4b --- /dev/null +++ b/src/Features/JsonPatch/src/JsonPatchDocument.cs @@ -0,0 +1,271 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using Microsoft.AspNetCore.JsonPatch.Adapters; +using Microsoft.AspNetCore.JsonPatch.Converters; +using Microsoft.AspNetCore.JsonPatch.Exceptions; +using Microsoft.AspNetCore.JsonPatch.Internal; +using Microsoft.AspNetCore.JsonPatch.Operations; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; + +namespace Microsoft.AspNetCore.JsonPatch +{ + // Implementation details: the purpose of this type of patch document is to allow creation of such + // documents for cases where there's no class/DTO to work on. Typical use case: backend not built in + // .NET or architecture doesn't contain a shared DTO layer. + [JsonConverter(typeof(JsonPatchDocumentConverter))] + public class JsonPatchDocument : IJsonPatchDocument + { + public List Operations { get; private set; } + + [JsonIgnore] + public IContractResolver ContractResolver { get; set; } + + public JsonPatchDocument() + { + Operations = new List(); + ContractResolver = new DefaultContractResolver(); + } + + public JsonPatchDocument(List operations, IContractResolver contractResolver) + { + if (operations == null) + { + throw new ArgumentNullException(nameof(operations)); + } + + if (contractResolver == null) + { + throw new ArgumentNullException(nameof(contractResolver)); + } + + Operations = operations; + ContractResolver = contractResolver; + } + + /// + /// Add operation. Will result in, for example, + /// { "op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ] } + /// + /// target location + /// value + /// + public JsonPatchDocument Add(string path, object value) + { + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + + Operations.Add(new Operation("add", PathHelpers.ValidateAndNormalizePath(path), null, value)); + return this; + } + + /// + /// Remove value at target location. Will result in, for example, + /// { "op": "remove", "path": "/a/b/c" } + /// + /// target location + /// + public JsonPatchDocument Remove(string path) + { + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + + Operations.Add(new Operation("remove", PathHelpers.ValidateAndNormalizePath(path), null, null)); + return this; + } + + /// + /// Replace value. Will result in, for example, + /// { "op": "replace", "path": "/a/b/c", "value": 42 } + /// + /// target location + /// value + /// + public JsonPatchDocument Replace(string path, object value) + { + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + + Operations.Add(new Operation("replace", PathHelpers.ValidateAndNormalizePath(path), null, value)); + return this; + } + + /// + /// Test value. Will result in, for example, + /// { "op": "test", "path": "/a/b/c", "value": 42 } + /// + /// target location + /// value + /// + public JsonPatchDocument Test(string path, object value) + { + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + + Operations.Add(new Operation("test", PathHelpers.ValidateAndNormalizePath(path), null, value)); + return this; + } + + /// + /// Removes value at specified location and add it to the target location. Will result in, for example: + /// { "op": "move", "from": "/a/b/c", "path": "/a/b/d" } + /// + /// source location + /// target location + /// + public JsonPatchDocument Move(string from, string path) + { + if (from == null) + { + throw new ArgumentNullException(nameof(from)); + } + + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + + Operations.Add(new Operation("move", PathHelpers.ValidateAndNormalizePath(path), PathHelpers.ValidateAndNormalizePath(from))); + return this; + } + + /// + /// Copy the value at specified location to the target location. Will result in, for example: + /// { "op": "copy", "from": "/a/b/c", "path": "/a/b/e" } + /// + /// source location + /// target location + /// + public JsonPatchDocument Copy(string from, string path) + { + if (from == null) + { + throw new ArgumentNullException(nameof(from)); + } + + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + + Operations.Add(new Operation("copy", PathHelpers.ValidateAndNormalizePath(path), PathHelpers.ValidateAndNormalizePath(from))); + return this; + } + + /// + /// Apply this JsonPatchDocument + /// + /// Object to apply the JsonPatchDocument to + public void ApplyTo(object objectToApplyTo) + { + if (objectToApplyTo == null) + { + throw new ArgumentNullException(nameof(objectToApplyTo)); + } + + ApplyTo(objectToApplyTo, new ObjectAdapter(ContractResolver, null, new AdapterFactory())); + } + + /// + /// Apply this JsonPatchDocument + /// + /// Object to apply the JsonPatchDocument to + /// Action to log errors + public void ApplyTo(object objectToApplyTo, Action logErrorAction) + { + ApplyTo(objectToApplyTo, new ObjectAdapter(ContractResolver, logErrorAction, new AdapterFactory()), logErrorAction); + } + + /// + /// Apply this JsonPatchDocument + /// + /// Object to apply the JsonPatchDocument to + /// IObjectAdapter instance to use when applying + /// Action to log errors + public void ApplyTo(object objectToApplyTo, IObjectAdapter adapter, Action logErrorAction) + { + if (objectToApplyTo == null) + { + throw new ArgumentNullException(nameof(objectToApplyTo)); + } + + if (adapter == null) + { + throw new ArgumentNullException(nameof(adapter)); + } + + foreach (var op in Operations) + { + try + { + op.Apply(objectToApplyTo, adapter); + } + catch (JsonPatchException jsonPatchException) + { + var errorReporter = logErrorAction ?? ErrorReporter.Default; + errorReporter(new JsonPatchError(objectToApplyTo, op, jsonPatchException.Message)); + + // As per JSON Patch spec if an operation results in error, further operations should not be executed. + break; + } + } + } + + /// + /// Apply this JsonPatchDocument + /// + /// Object to apply the JsonPatchDocument to + /// IObjectAdapter instance to use when applying + public void ApplyTo(object objectToApplyTo, IObjectAdapter adapter) + { + if (objectToApplyTo == null) + { + throw new ArgumentNullException(nameof(objectToApplyTo)); + } + + if (adapter == null) + { + throw new ArgumentNullException(nameof(adapter)); + } + + // apply each operation in order + foreach (var op in Operations) + { + op.Apply(objectToApplyTo, adapter); + } + } + + IList IJsonPatchDocument.GetOperations() + { + var allOps = new List(); + + if (Operations != null) + { + foreach (var op in Operations) + { + var untypedOp = new Operation(); + + untypedOp.op = op.op; + untypedOp.value = op.value; + untypedOp.path = op.path; + untypedOp.from = op.from; + + allOps.Add(untypedOp); + } + } + + return allOps; + } + } +} diff --git a/src/Features/JsonPatch/src/JsonPatchDocumentOfT.cs b/src/Features/JsonPatch/src/JsonPatchDocumentOfT.cs new file mode 100644 index 0000000000..e0b4fca240 --- /dev/null +++ b/src/Features/JsonPatch/src/JsonPatchDocumentOfT.cs @@ -0,0 +1,884 @@ +// 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.Collections.Generic; +using System.Globalization; +using System.Linq.Expressions; +using Microsoft.AspNetCore.JsonPatch.Adapters; +using Microsoft.AspNetCore.JsonPatch.Converters; +using Microsoft.AspNetCore.JsonPatch.Exceptions; +using Microsoft.AspNetCore.JsonPatch.Internal; +using Microsoft.AspNetCore.JsonPatch.Operations; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; + +namespace Microsoft.AspNetCore.JsonPatch +{ + // Implementation details: the purpose of this type of patch document is to ensure we can do type-checking + // when producing a JsonPatchDocument. However, we cannot send this "typed" over the wire, as that would require + // including type data in the JsonPatchDocument serialized as JSON (to allow for correct deserialization) - that's + // not according to RFC 6902, and would thus break cross-platform compatibility. + [JsonConverter(typeof(TypedJsonPatchDocumentConverter))] + public class JsonPatchDocument : IJsonPatchDocument where TModel : class + { + public List> Operations { get; private set; } + + [JsonIgnore] + public IContractResolver ContractResolver { get; set; } + + public JsonPatchDocument() + { + Operations = new List>(); + ContractResolver = new DefaultContractResolver(); + } + + // Create from list of operations + public JsonPatchDocument(List> operations, IContractResolver contractResolver) + { + Operations = operations ?? throw new ArgumentNullException(nameof(operations)); + ContractResolver = contractResolver ?? throw new ArgumentNullException(nameof(contractResolver)); + } + + /// + /// Add operation. Will result in, for example, + /// { "op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ] } + /// + /// value type + /// target location + /// value + /// + public JsonPatchDocument Add(Expression> path, TProp value) + { + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + + Operations.Add(new Operation( + "add", + GetPath(path, null), + from: null, + value: value)); + + return this; + } + + /// + /// Add value to list at given position + /// + /// value type + /// target location + /// value + /// position + /// + public JsonPatchDocument Add( + Expression>> path, + TProp value, + int position) + { + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + + Operations.Add(new Operation( + "add", + GetPath(path, position.ToString()), + from: null, + value: value)); + + return this; + } + + /// + /// Add value to the end of the list + /// + /// value type + /// target location + /// value + /// + public JsonPatchDocument Add(Expression>> path, TProp value) + { + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + + Operations.Add(new Operation( + "add", + GetPath(path, "-"), + from: null, + value: value)); + + return this; + } + + /// + /// Remove value at target location. Will result in, for example, + /// { "op": "remove", "path": "/a/b/c" } + /// + /// target location + /// + public JsonPatchDocument Remove(Expression> path) + { + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + + Operations.Add(new Operation("remove", GetPath(path, null), from: null)); + + return this; + } + + /// + /// Remove value from list at given position + /// + /// value type + /// target location + /// position + /// + public JsonPatchDocument Remove(Expression>> path, int position) + { + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + + Operations.Add(new Operation( + "remove", + GetPath(path, position.ToString()), + from: null)); + + return this; + } + + /// + /// Remove value from end of list + /// + /// value type + /// target location + /// + public JsonPatchDocument Remove(Expression>> path) + { + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + + Operations.Add(new Operation( + "remove", + GetPath(path, "-"), + from: null)); + + return this; + } + + /// + /// Replace value. Will result in, for example, + /// { "op": "replace", "path": "/a/b/c", "value": 42 } + /// + /// target location + /// value + /// + public JsonPatchDocument Replace(Expression> path, TProp value) + { + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + + Operations.Add(new Operation( + "replace", + GetPath(path, null), + from: null, + value: value)); + + return this; + } + + /// + /// Replace value in a list at given position + /// + /// value type + /// target location + /// value + /// position + /// + public JsonPatchDocument Replace(Expression>> path, + TProp value, int position) + { + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + + Operations.Add(new Operation( + "replace", + GetPath(path, position.ToString()), + from: null, + value: value)); + + return this; + } + + /// + /// Replace value at end of a list + /// + /// value type + /// target location + /// value + /// + public JsonPatchDocument Replace(Expression>> path, TProp value) + { + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + + Operations.Add(new Operation( + "replace", + GetPath(path, "-"), + from: null, + value: value)); + + return this; + } + + /// + /// Test value. Will result in, for example, + /// { "op": "test", "path": "/a/b/c", "value": 42 } + /// + /// target location + /// value + /// + public JsonPatchDocument Test(Expression> path, TProp value) + { + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + + Operations.Add(new Operation( + "test", + GetPath(path, null), + from: null, + value: value)); + + return this; + } + + /// + /// Test value in a list at given position + /// + /// value type + /// target location + /// value + /// position + /// + public JsonPatchDocument Test(Expression>> path, + TProp value, int position) + { + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + + Operations.Add(new Operation( + "test", + GetPath(path, position.ToString()), + from: null, + value: value)); + + return this; + } + + /// + /// Test value at end of a list + /// + /// value type + /// target location + /// value + /// + public JsonPatchDocument Test(Expression>> path, TProp value) + { + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + + Operations.Add(new Operation( + "test", + GetPath(path, "-"), + from: null, + value: value)); + + return this; + } + + /// + /// Removes value at specified location and add it to the target location. Will result in, for example: + /// { "op": "move", "from": "/a/b/c", "path": "/a/b/d" } + /// + /// source location + /// target location + /// + public JsonPatchDocument Move( + Expression> from, + Expression> path) + { + if (from == null) + { + throw new ArgumentNullException(nameof(from)); + } + + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + + Operations.Add(new Operation( + "move", + GetPath(path, null), + GetPath(from, null))); + + return this; + } + + /// + /// Move from a position in a list to a new location + /// + /// + /// source location + /// position + /// target location + /// + public JsonPatchDocument Move( + Expression>> from, + int positionFrom, + Expression> path) + { + if (from == null) + { + throw new ArgumentNullException(nameof(from)); + } + + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + + Operations.Add(new Operation( + "move", + GetPath(path, null), + GetPath(from, positionFrom.ToString()))); + + return this; + } + + /// + /// Move from a property to a location in a list + /// + /// + /// source location + /// target location + /// position + /// + public JsonPatchDocument Move( + Expression> from, + Expression>> path, + int positionTo) + { + if (from == null) + { + throw new ArgumentNullException(nameof(from)); + } + + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + + Operations.Add(new Operation( + "move", + GetPath(path, positionTo.ToString()), + GetPath(from, null))); + + return this; + } + + /// + /// Move from a position in a list to another location in a list + /// + /// + /// source location + /// position (source) + /// target location + /// position (target) + /// + public JsonPatchDocument Move( + Expression>> from, + int positionFrom, + Expression>> path, + int positionTo) + { + if (from == null) + { + throw new ArgumentNullException(nameof(from)); + } + + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + + Operations.Add(new Operation( + "move", + GetPath(path, positionTo.ToString()), + GetPath(from, positionFrom.ToString()))); + + return this; + } + + /// + /// Move from a position in a list to the end of another list + /// + /// + /// source location + /// position + /// target location + /// + public JsonPatchDocument Move( + Expression>> from, + int positionFrom, + Expression>> path) + { + if (from == null) + { + throw new ArgumentNullException(nameof(from)); + } + + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + + Operations.Add(new Operation( + "move", + GetPath(path, "-"), + GetPath(from, positionFrom.ToString()))); + + return this; + } + + /// + /// Move to the end of a list + /// + /// + /// source location + /// target location + /// + public JsonPatchDocument Move( + Expression> from, + Expression>> path) + { + if (from == null) + { + throw new ArgumentNullException(nameof(from)); + } + + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + + Operations.Add(new Operation( + "move", + GetPath(path, "-"), + GetPath(from, null))); + + return this; + } + + /// + /// Copy the value at specified location to the target location. Will result in, for example: + /// { "op": "copy", "from": "/a/b/c", "path": "/a/b/e" } + /// + /// source location + /// target location + /// + public JsonPatchDocument Copy( + Expression> from, + Expression> path) + { + if (from == null) + { + throw new ArgumentNullException(nameof(from)); + } + + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + + Operations.Add(new Operation( + "copy", + GetPath(path, null), + GetPath(from, null))); + + return this; + } + + /// + /// Copy from a position in a list to a new location + /// + /// + /// source location + /// position + /// target location + /// + public JsonPatchDocument Copy( + Expression>> from, + int positionFrom, + Expression> path) + { + if (from == null) + { + throw new ArgumentNullException(nameof(from)); + } + + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + + Operations.Add(new Operation( + "copy", + GetPath(path, null), + GetPath(from, positionFrom.ToString()))); + + return this; + } + + /// + /// Copy from a property to a location in a list + /// + /// + /// source location + /// target location + /// position + /// + public JsonPatchDocument Copy( + Expression> from, + Expression>> path, + int positionTo) + { + if (from == null) + { + throw new ArgumentNullException(nameof(from)); + } + + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + + Operations.Add(new Operation( + "copy", + GetPath(path, positionTo.ToString()), + GetPath(from, null))); + + return this; + } + + /// + /// Copy from a position in a list to a new location in a list + /// + /// + /// source location + /// position (source) + /// target location + /// position (target) + /// + public JsonPatchDocument Copy( + Expression>> from, + int positionFrom, + Expression>> path, + int positionTo) + { + if (from == null) + { + throw new ArgumentNullException(nameof(from)); + } + + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + + Operations.Add(new Operation( + "copy", + GetPath(path, positionTo.ToString()), + GetPath(from, positionFrom.ToString()))); + + return this; + } + + /// + /// Copy from a position in a list to the end of another list + /// + /// + /// source location + /// position + /// target location + /// + public JsonPatchDocument Copy( + Expression>> from, + int positionFrom, + Expression>> path) + { + if (from == null) + { + throw new ArgumentNullException(nameof(from)); + } + + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + + Operations.Add(new Operation( + "copy", + GetPath(path, "-"), + GetPath(from, positionFrom.ToString()))); + + return this; + } + + /// + /// Copy to the end of a list + /// + /// + /// source location + /// target location + /// + public JsonPatchDocument Copy( + Expression> from, + Expression>> path) + { + if (from == null) + { + throw new ArgumentNullException(nameof(from)); + } + + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + + Operations.Add(new Operation( + "copy", + GetPath(path, "-"), + GetPath(from, null))); + + return this; + } + + /// + /// Apply this JsonPatchDocument + /// + /// Object to apply the JsonPatchDocument to + public void ApplyTo(TModel objectToApplyTo) + { + if (objectToApplyTo == null) + { + throw new ArgumentNullException(nameof(objectToApplyTo)); + } + + ApplyTo(objectToApplyTo, new ObjectAdapter(ContractResolver, null, new AdapterFactory())); + } + + /// + /// Apply this JsonPatchDocument + /// + /// Object to apply the JsonPatchDocument to + /// Action to log errors + public void ApplyTo(TModel objectToApplyTo, Action logErrorAction) + { + ApplyTo(objectToApplyTo, new ObjectAdapter(ContractResolver, logErrorAction, new AdapterFactory()), logErrorAction); + } + + /// + /// Apply this JsonPatchDocument + /// + /// Object to apply the JsonPatchDocument to + /// IObjectAdapter instance to use when applying + /// Action to log errors + public void ApplyTo(TModel objectToApplyTo, IObjectAdapter adapter, Action logErrorAction) + { + if (objectToApplyTo == null) + { + throw new ArgumentNullException(nameof(objectToApplyTo)); + } + + if (adapter == null) + { + throw new ArgumentNullException(nameof(adapter)); + } + + foreach (var op in Operations) + { + try + { + op.Apply(objectToApplyTo, adapter); + } + catch (JsonPatchException jsonPatchException) + { + var errorReporter = logErrorAction ?? ErrorReporter.Default; + errorReporter(new JsonPatchError(objectToApplyTo, op, jsonPatchException.Message)); + + // As per JSON Patch spec if an operation results in error, further operations should not be executed. + break; + } + } + } + + /// + /// Apply this JsonPatchDocument + /// + /// Object to apply the JsonPatchDocument to + /// IObjectAdapter instance to use when applying + public void ApplyTo(TModel objectToApplyTo, IObjectAdapter adapter) + { + if (objectToApplyTo == null) + { + throw new ArgumentNullException(nameof(objectToApplyTo)); + } + + if (adapter == null) + { + throw new ArgumentNullException(nameof(adapter)); + } + + // apply each operation in order + foreach (var op in Operations) + { + op.Apply(objectToApplyTo, adapter); + } + } + + IList IJsonPatchDocument.GetOperations() + { + var allOps = new List(); + + if (Operations != null) + { + foreach (var op in Operations) + { + var untypedOp = new Operation + { + op = op.op, + value = op.value, + path = op.path, + from = op.from + }; + + allOps.Add(untypedOp); + } + } + + return allOps; + } + + // Internal for testing + internal string GetPath(Expression> expr, string position) + { + var segments = GetPathSegments(expr.Body); + var path = String.Join("/", segments); + if (position != null) + { + path += "/" + position; + if (segments.Count == 0) + { + return path; + } + } + + return "/" + path; + } + + private List GetPathSegments(Expression expr) + { + var listOfSegments = new List(); + switch (expr.NodeType) + { + case ExpressionType.ArrayIndex: + var binaryExpression = (BinaryExpression)expr; + listOfSegments.AddRange(GetPathSegments(binaryExpression.Left)); + listOfSegments.Add(binaryExpression.Right.ToString()); + return listOfSegments; + + case ExpressionType.Call: + var methodCallExpression = (MethodCallExpression)expr; + listOfSegments.AddRange(GetPathSegments(methodCallExpression.Object)); + listOfSegments.Add(EvaluateExpression(methodCallExpression.Arguments[0])); + return listOfSegments; + + case ExpressionType.Convert: + listOfSegments.AddRange(GetPathSegments(((UnaryExpression)expr).Operand)); + return listOfSegments; + + case ExpressionType.MemberAccess: + var memberExpression = expr as MemberExpression; + listOfSegments.AddRange(GetPathSegments(memberExpression.Expression)); + // Get property name, respecting JsonProperty attribute + listOfSegments.Add(GetPropertyNameFromMemberExpression(memberExpression)); + return listOfSegments; + + case ExpressionType.Parameter: + // Fits "x => x" (the whole document which is "" as JSON pointer) + return listOfSegments; + + default: + throw new InvalidOperationException(Resources.FormatExpressionTypeNotSupported(expr)); + } + } + + private string GetPropertyNameFromMemberExpression(MemberExpression memberExpression) + { + var jsonObjectContract = ContractResolver.ResolveContract(memberExpression.Expression.Type) as JsonObjectContract; + if (jsonObjectContract != null) + { + return jsonObjectContract.Properties + .First(jsonProperty => jsonProperty.UnderlyingName == memberExpression.Member.Name) + .PropertyName; + } + + return null; + } + + private static bool ContinueWithSubPath(ExpressionType expressionType) + { + return (expressionType == ExpressionType.ArrayIndex + || expressionType == ExpressionType.Call + || expressionType == ExpressionType.Convert + || expressionType == ExpressionType.MemberAccess); + + } + + // Evaluates the value of the key or index which may be an int or a string, + // or some other expression type. + // The expression is converted to a delegate and the result of executing the delegate is returned as a string. + private static string EvaluateExpression(Expression expression) + { + var converted = Expression.Convert(expression, typeof(object)); + var fakeParameter = Expression.Parameter(typeof(object), null); + var lambda = Expression.Lambda>(converted, fakeParameter); + var func = lambda.Compile(); + + return Convert.ToString(func(null), CultureInfo.InvariantCulture); + } + } +} \ No newline at end of file diff --git a/src/Features/JsonPatch/src/JsonPatchError.cs b/src/Features/JsonPatch/src/JsonPatchError.cs new file mode 100644 index 0000000000..a49af7a4e2 --- /dev/null +++ b/src/Features/JsonPatch/src/JsonPatchError.cs @@ -0,0 +1,50 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using Microsoft.AspNetCore.JsonPatch.Operations; + +namespace Microsoft.AspNetCore.JsonPatch +{ + /// + /// Captures error message and the related entity and the operation that caused it. + /// + public class JsonPatchError + { + /// + /// Initializes a new instance of . + /// + /// The object that is affected by the error. + /// The that caused the error. + /// The error message. + public JsonPatchError( + object affectedObject, + Operation operation, + string errorMessage) + { + if (errorMessage == null) + { + throw new ArgumentNullException(nameof(errorMessage)); + } + + AffectedObject = affectedObject; + Operation = operation; + ErrorMessage = errorMessage; + } + + /// + /// Gets the object that is affected by the error. + /// + public object AffectedObject { get; } + + /// + /// Gets the that caused the error. + /// + public Operation Operation { get; } + + /// + /// Gets the error message. + /// + public string ErrorMessage { get; } + } +} \ No newline at end of file diff --git a/src/Features/JsonPatch/src/Microsoft.AspNetCore.JsonPatch.csproj b/src/Features/JsonPatch/src/Microsoft.AspNetCore.JsonPatch.csproj new file mode 100644 index 0000000000..3708e92927 --- /dev/null +++ b/src/Features/JsonPatch/src/Microsoft.AspNetCore.JsonPatch.csproj @@ -0,0 +1,17 @@ + + + + ASP.NET Core support for JSON PATCH. + netstandard2.0 + $(NoWarn);CS1591 + true + aspnetcore;json;jsonpatch + + + + + + + + + diff --git a/src/Features/JsonPatch/src/Operations/Operation.cs b/src/Features/JsonPatch/src/Operations/Operation.cs new file mode 100644 index 0000000000..690ade4776 --- /dev/null +++ b/src/Features/JsonPatch/src/Operations/Operation.cs @@ -0,0 +1,82 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using Microsoft.AspNetCore.JsonPatch.Adapters; +using Newtonsoft.Json; + +namespace Microsoft.AspNetCore.JsonPatch.Operations +{ + public class Operation : OperationBase + { + [JsonProperty("value")] + public object value { get; set; } + + public Operation() + { + + } + + public Operation(string op, string path, string from, object value) + : base(op, path, from) + { + this.value = value; + } + + public Operation(string op, string path, string from) + : base(op, path, from) + { + } + + public void Apply(object objectToApplyTo, IObjectAdapter adapter) + { + if (objectToApplyTo == null) + { + throw new ArgumentNullException(nameof(objectToApplyTo)); + } + + if (adapter == null) + { + throw new ArgumentNullException(nameof(adapter)); + } + + switch (OperationType) + { + case OperationType.Add: + adapter.Add(this, objectToApplyTo); + break; + case OperationType.Remove: + adapter.Remove(this, objectToApplyTo); + break; + case OperationType.Replace: + adapter.Replace(this, objectToApplyTo); + break; + case OperationType.Move: + adapter.Move(this, objectToApplyTo); + break; + case OperationType.Copy: + adapter.Copy(this, objectToApplyTo); + break; + case OperationType.Test: + if (adapter is IObjectAdapterWithTest adapterWithTest) + { + adapterWithTest.Test(this, objectToApplyTo); + break; + } + else + { + throw new NotSupportedException(Resources.TestOperationNotSupported); + } + default: + break; + } + } + + public bool ShouldSerializevalue() + { + return (OperationType == OperationType.Add + || OperationType == OperationType.Replace + || OperationType == OperationType.Test); + } + } +} \ No newline at end of file diff --git a/src/Features/JsonPatch/src/Operations/OperationBase.cs b/src/Features/JsonPatch/src/Operations/OperationBase.cs new file mode 100644 index 0000000000..e629e2308d --- /dev/null +++ b/src/Features/JsonPatch/src/Operations/OperationBase.cs @@ -0,0 +1,76 @@ +// 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 Newtonsoft.Json; + +namespace Microsoft.AspNetCore.JsonPatch.Operations +{ + public class OperationBase + { + private string _op; + private OperationType _operationType; + + [JsonIgnore] + public OperationType OperationType + { + get + { + return _operationType; + } + } + + [JsonProperty("path")] + public string path { get; set; } + + [JsonProperty("op")] + public string op + { + get + { + return _op; + } + set + { + OperationType result; + if (!Enum.TryParse(value, ignoreCase: true, result: out result)) + { + result = OperationType.Invalid; + } + _operationType = result; + _op = value; + } + } + + [JsonProperty("from")] + public string from { get; set; } + + public OperationBase() + { + + } + + public OperationBase(string op, string path, string from) + { + if (op == null) + { + throw new ArgumentNullException(nameof(op)); + } + + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + + this.op = op; + this.path = path; + this.from = from; + } + + public bool ShouldSerializefrom() + { + return (OperationType == OperationType.Move + || OperationType == OperationType.Copy); + } + } +} \ No newline at end of file diff --git a/src/Features/JsonPatch/src/Operations/OperationOfT.cs b/src/Features/JsonPatch/src/Operations/OperationOfT.cs new file mode 100644 index 0000000000..bd13528775 --- /dev/null +++ b/src/Features/JsonPatch/src/Operations/OperationOfT.cs @@ -0,0 +1,94 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using Microsoft.AspNetCore.JsonPatch.Adapters; +using Microsoft.AspNetCore.JsonPatch.Exceptions; + +namespace Microsoft.AspNetCore.JsonPatch.Operations +{ + public class Operation : Operation where TModel : class + { + public Operation() + { + + } + + public Operation(string op, string path, string from, object value) + : base(op, path, from) + { + if (op == null) + { + throw new ArgumentNullException(nameof(op)); + } + + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + + this.value = value; + } + + public Operation(string op, string path, string from) + : base(op, path, from) + { + if (op == null) + { + throw new ArgumentNullException(nameof(op)); + } + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + + } + + public void Apply(TModel objectToApplyTo, IObjectAdapter adapter) + { + if (objectToApplyTo == null) + { + throw new ArgumentNullException(nameof(objectToApplyTo)); + } + + if (adapter == null) + { + throw new ArgumentNullException(nameof(adapter)); + } + + switch (OperationType) + { + case OperationType.Add: + adapter.Add(this, objectToApplyTo); + break; + case OperationType.Remove: + adapter.Remove(this, objectToApplyTo); + break; + case OperationType.Replace: + adapter.Replace(this, objectToApplyTo); + break; + case OperationType.Move: + adapter.Move(this, objectToApplyTo); + break; + case OperationType.Copy: + adapter.Copy(this, objectToApplyTo); + break; + case OperationType.Test: + if (adapter is IObjectAdapterWithTest adapterWithTest) + { + adapterWithTest.Test(this, objectToApplyTo); + break; + } + else + { + throw new JsonPatchException(new JsonPatchError(objectToApplyTo, this, Resources.TestOperationNotSupported)); + } + case OperationType.Invalid: + throw new JsonPatchException( + Resources.FormatInvalidJsonPatchOperation(op), innerException: null); + default: + break; + } + } + } +} \ No newline at end of file diff --git a/src/Features/JsonPatch/src/Operations/OperationType.cs b/src/Features/JsonPatch/src/Operations/OperationType.cs new file mode 100644 index 0000000000..725646df3a --- /dev/null +++ b/src/Features/JsonPatch/src/Operations/OperationType.cs @@ -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. + +namespace Microsoft.AspNetCore.JsonPatch.Operations +{ + public enum OperationType + { + Add, + Remove, + Replace, + Move, + Copy, + Test, + Invalid + } +} \ No newline at end of file diff --git a/src/Features/JsonPatch/src/Properties/AssemblyInfo.cs b/src/Features/JsonPatch/src/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..11fa956b64 --- /dev/null +++ b/src/Features/JsonPatch/src/Properties/AssemblyInfo.cs @@ -0,0 +1,7 @@ + +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Microsoft.AspNetCore.JsonPatch.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] diff --git a/src/Features/JsonPatch/src/Properties/Resources.Designer.cs b/src/Features/JsonPatch/src/Properties/Resources.Designer.cs new file mode 100644 index 0000000000..c314465238 --- /dev/null +++ b/src/Features/JsonPatch/src/Properties/Resources.Designer.cs @@ -0,0 +1,338 @@ +// +namespace Microsoft.AspNetCore.JsonPatch +{ + using System.Globalization; + using System.Reflection; + using System.Resources; + + internal static class Resources + { + private static readonly ResourceManager _resourceManager + = new ResourceManager("Microsoft.AspNetCore.JsonPatch.Resources", typeof(Resources).GetTypeInfo().Assembly); + + /// + /// The property at '{0}' could not be copied. + /// + internal static string CannotCopyProperty + { + get => GetString("CannotCopyProperty"); + } + + /// + /// The property at '{0}' could not be copied. + /// + internal static string FormatCannotCopyProperty(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("CannotCopyProperty"), p0); + + /// + /// The type of the property at path '{0}' could not be determined. + /// + internal static string CannotDeterminePropertyType + { + get => GetString("CannotDeterminePropertyType"); + } + + /// + /// The type of the property at path '{0}' could not be determined. + /// + internal static string FormatCannotDeterminePropertyType(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("CannotDeterminePropertyType"), p0); + + /// + /// The '{0}' operation at path '{1}' could not be performed. + /// + internal static string CannotPerformOperation + { + get => GetString("CannotPerformOperation"); + } + + /// + /// The '{0}' operation at path '{1}' could not be performed. + /// + internal static string FormatCannotPerformOperation(object p0, object p1) + => string.Format(CultureInfo.CurrentCulture, GetString("CannotPerformOperation"), p0, p1); + + /// + /// The property at '{0}' could not be read. + /// + internal static string CannotReadProperty + { + get => GetString("CannotReadProperty"); + } + + /// + /// The property at '{0}' could not be read. + /// + internal static string FormatCannotReadProperty(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("CannotReadProperty"), p0); + + /// + /// The property at path '{0}' could not be updated. + /// + internal static string CannotUpdateProperty + { + get => GetString("CannotUpdateProperty"); + } + + /// + /// The property at path '{0}' could not be updated. + /// + internal static string FormatCannotUpdateProperty(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("CannotUpdateProperty"), p0); + + /// + /// The expression '{0}' is not supported. Supported expressions include member access and indexer expressions. + /// + internal static string ExpressionTypeNotSupported + { + get => GetString("ExpressionTypeNotSupported"); + } + + /// + /// The expression '{0}' is not supported. Supported expressions include member access and indexer expressions. + /// + internal static string FormatExpressionTypeNotSupported(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("ExpressionTypeNotSupported"), p0); + + /// + /// The index value provided by path segment '{0}' is out of bounds of the array size. + /// + internal static string IndexOutOfBounds + { + get => GetString("IndexOutOfBounds"); + } + + /// + /// The index value provided by path segment '{0}' is out of bounds of the array size. + /// + internal static string FormatIndexOutOfBounds(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("IndexOutOfBounds"), p0); + + /// + /// The path segment '{0}' is invalid for an array index. + /// + internal static string InvalidIndexValue + { + get => GetString("InvalidIndexValue"); + } + + /// + /// The path segment '{0}' is invalid for an array index. + /// + internal static string FormatInvalidIndexValue(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("InvalidIndexValue"), p0); + + /// + /// The JSON patch document was malformed and could not be parsed. + /// + internal static string InvalidJsonPatchDocument + { + get => GetString("InvalidJsonPatchDocument"); + } + + /// + /// The JSON patch document was malformed and could not be parsed. + /// + internal static string FormatInvalidJsonPatchDocument() + => GetString("InvalidJsonPatchDocument"); + + /// + /// Invalid JsonPatch operation '{0}'. + /// + internal static string InvalidJsonPatchOperation + { + get => GetString("InvalidJsonPatchOperation"); + } + + /// + /// Invalid JsonPatch operation '{0}'. + /// + internal static string FormatInvalidJsonPatchOperation(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("InvalidJsonPatchOperation"), p0); + + /// + /// The provided path segment '{0}' cannot be converted to the target type. + /// + internal static string InvalidPathSegment + { + get => GetString("InvalidPathSegment"); + } + + /// + /// The provided path segment '{0}' cannot be converted to the target type. + /// + internal static string FormatInvalidPathSegment(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("InvalidPathSegment"), p0); + + /// + /// The provided string '{0}' is an invalid path. + /// + internal static string InvalidValueForPath + { + get => GetString("InvalidValueForPath"); + } + + /// + /// The provided string '{0}' is an invalid path. + /// + internal static string FormatInvalidValueForPath(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("InvalidValueForPath"), p0); + + /// + /// The value '{0}' is invalid for target location. + /// + internal static string InvalidValueForProperty + { + get => GetString("InvalidValueForProperty"); + } + + /// + /// The value '{0}' is invalid for target location. + /// + internal static string FormatInvalidValueForProperty(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("InvalidValueForProperty"), p0); + + /// + /// '{0}' must be of type '{1}'. + /// + internal static string ParameterMustMatchType + { + get => GetString("ParameterMustMatchType"); + } + + /// + /// '{0}' must be of type '{1}'. + /// + internal static string FormatParameterMustMatchType(object p0, object p1) + => string.Format(CultureInfo.CurrentCulture, GetString("ParameterMustMatchType"), p0, p1); + + /// + /// The type '{0}' which is an array is not supported for json patch operations as it has a fixed size. + /// + internal static string PatchNotSupportedForArrays + { + get => GetString("PatchNotSupportedForArrays"); + } + + /// + /// The type '{0}' which is an array is not supported for json patch operations as it has a fixed size. + /// + internal static string FormatPatchNotSupportedForArrays(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("PatchNotSupportedForArrays"), p0); + + /// + /// The type '{0}' which is a non generic list is not supported for json patch operations. Only generic list types are supported. + /// + internal static string PatchNotSupportedForNonGenericLists + { + get => GetString("PatchNotSupportedForNonGenericLists"); + } + + /// + /// The type '{0}' which is a non generic list is not supported for json patch operations. Only generic list types are supported. + /// + internal static string FormatPatchNotSupportedForNonGenericLists(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("PatchNotSupportedForNonGenericLists"), p0); + + /// + /// The target location specified by path segment '{0}' was not found. + /// + internal static string TargetLocationAtPathSegmentNotFound + { + get => GetString("TargetLocationAtPathSegmentNotFound"); + } + + /// + /// The target location specified by path segment '{0}' was not found. + /// + internal static string FormatTargetLocationAtPathSegmentNotFound(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("TargetLocationAtPathSegmentNotFound"), p0); + + /// + /// For operation '{0}', the target location specified by path '{1}' was not found. + /// + internal static string TargetLocationNotFound + { + get => GetString("TargetLocationNotFound"); + } + + /// + /// For operation '{0}', the target location specified by path '{1}' was not found. + /// + internal static string FormatTargetLocationNotFound(object p0, object p1) + => string.Format(CultureInfo.CurrentCulture, GetString("TargetLocationNotFound"), p0, p1); + + /// + /// The test operation is not supported. + /// + internal static string TestOperationNotSupported + { + get => GetString("TestOperationNotSupported"); + } + + /// + /// The test operation is not supported. + /// + internal static string FormatTestOperationNotSupported() + => GetString("TestOperationNotSupported"); + + /// + /// The current value '{0}' at position '{2}' is not equal to the test value '{1}'. + /// + internal static string ValueAtListPositionNotEqualToTestValue + { + get => GetString("ValueAtListPositionNotEqualToTestValue"); + } + + /// + /// The current value '{0}' at position '{2}' is not equal to the test value '{1}'. + /// + internal static string FormatValueAtListPositionNotEqualToTestValue(object p0, object p1, object p2) + => string.Format(CultureInfo.CurrentCulture, GetString("ValueAtListPositionNotEqualToTestValue"), p0, p1, p2); + + /// + /// The value at '{0}' cannot be null or empty to perform the test operation. + /// + internal static string ValueForTargetSegmentCannotBeNullOrEmpty + { + get => GetString("ValueForTargetSegmentCannotBeNullOrEmpty"); + } + + /// + /// The value at '{0}' cannot be null or empty to perform the test operation. + /// + internal static string FormatValueForTargetSegmentCannotBeNullOrEmpty(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("ValueForTargetSegmentCannotBeNullOrEmpty"), p0); + + /// + /// The current value '{0}' at path '{2}' is not equal to the test value '{1}'. + /// + internal static string ValueNotEqualToTestValue + { + get => GetString("ValueNotEqualToTestValue"); + } + + /// + /// The current value '{0}' at path '{2}' is not equal to the test value '{1}'. + /// + internal static string FormatValueNotEqualToTestValue(object p0, object p1, object p2) + => string.Format(CultureInfo.CurrentCulture, GetString("ValueNotEqualToTestValue"), 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; + } + } +} diff --git a/src/Features/JsonPatch/src/Resources.resx b/src/Features/JsonPatch/src/Resources.resx new file mode 100644 index 0000000000..87cc399c62 --- /dev/null +++ b/src/Features/JsonPatch/src/Resources.resx @@ -0,0 +1,186 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + The property at '{0}' could not be copied. + + + The type of the property at path '{0}' could not be determined. + + + The '{0}' operation at path '{1}' could not be performed. + + + The property at '{0}' could not be read. + + + The property at path '{0}' could not be updated. + + + The expression '{0}' is not supported. Supported expressions include member access and indexer expressions. + + + The index value provided by path segment '{0}' is out of bounds of the array size. + + + The path segment '{0}' is invalid for an array index. + + + The JSON patch document was malformed and could not be parsed. + + + Invalid JsonPatch operation '{0}'. + + + The provided path segment '{0}' cannot be converted to the target type. + + + The provided string '{0}' is an invalid path. + + + The value '{0}' is invalid for target location. + + + '{0}' must be of type '{1}'. + + + The type '{0}' which is an array is not supported for json patch operations as it has a fixed size. + + + The type '{0}' which is a non generic list is not supported for json patch operations. Only generic list types are supported. + + + The target location specified by path segment '{0}' was not found. + + + For operation '{0}', the target location specified by path '{1}' was not found. + + + The test operation is not supported. + + + The current value '{0}' at position '{2}' is not equal to the test value '{1}'. + + + The value at '{0}' cannot be null or empty to perform the test operation. + + + The current value '{0}' at path '{2}' is not equal to the test value '{1}'. + + \ No newline at end of file diff --git a/src/Features/JsonPatch/src/baseline.netcore.json b/src/Features/JsonPatch/src/baseline.netcore.json new file mode 100644 index 0000000000..3d90a8f017 --- /dev/null +++ b/src/Features/JsonPatch/src/baseline.netcore.json @@ -0,0 +1,1985 @@ +{ + "AssemblyIdentity": "Microsoft.AspNetCore.JsonPatch, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "Types": [ + { + "Name": "Microsoft.AspNetCore.JsonPatch.JsonPatchProperty", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_Property", + "Parameters": [], + "ReturnType": "Newtonsoft.Json.Serialization.JsonProperty", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Property", + "Parameters": [ + { + "Name": "value", + "Type": "Newtonsoft.Json.Serialization.JsonProperty" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Parent", + "Parameters": [], + "ReturnType": "System.Object", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Parent", + "Parameters": [ + { + "Name": "value", + "Type": "System.Object" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "property", + "Type": "Newtonsoft.Json.Serialization.JsonProperty" + }, + { + "Name": "parent", + "Type": "System.Object" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.JsonPatch.IJsonPatchDocument", + "Visibility": "Public", + "Kind": "Interface", + "Abstract": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_ContractResolver", + "Parameters": [], + "ReturnType": "Newtonsoft.Json.Serialization.IContractResolver", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_ContractResolver", + "Parameters": [ + { + "Name": "value", + "Type": "Newtonsoft.Json.Serialization.IContractResolver" + } + ], + "ReturnType": "System.Void", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "GetOperations", + "Parameters": [], + "ReturnType": "System.Collections.Generic.IList", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.JsonPatch.JsonPatchDocument", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.JsonPatch.IJsonPatchDocument" + ], + "Members": [ + { + "Kind": "Method", + "Name": "get_Operations", + "Parameters": [], + "ReturnType": "System.Collections.Generic.List", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_ContractResolver", + "Parameters": [], + "ReturnType": "Newtonsoft.Json.Serialization.IContractResolver", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.JsonPatch.IJsonPatchDocument", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_ContractResolver", + "Parameters": [ + { + "Name": "value", + "Type": "Newtonsoft.Json.Serialization.IContractResolver" + } + ], + "ReturnType": "System.Void", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.JsonPatch.IJsonPatchDocument", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Add", + "Parameters": [ + { + "Name": "path", + "Type": "System.String" + }, + { + "Name": "value", + "Type": "System.Object" + } + ], + "ReturnType": "Microsoft.AspNetCore.JsonPatch.JsonPatchDocument", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Remove", + "Parameters": [ + { + "Name": "path", + "Type": "System.String" + } + ], + "ReturnType": "Microsoft.AspNetCore.JsonPatch.JsonPatchDocument", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Replace", + "Parameters": [ + { + "Name": "path", + "Type": "System.String" + }, + { + "Name": "value", + "Type": "System.Object" + } + ], + "ReturnType": "Microsoft.AspNetCore.JsonPatch.JsonPatchDocument", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Test", + "Parameters": [ + { + "Name": "path", + "Type": "System.String" + }, + { + "Name": "value", + "Type": "System.Object" + } + ], + "ReturnType": "Microsoft.AspNetCore.JsonPatch.JsonPatchDocument", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Move", + "Parameters": [ + { + "Name": "from", + "Type": "System.String" + }, + { + "Name": "path", + "Type": "System.String" + } + ], + "ReturnType": "Microsoft.AspNetCore.JsonPatch.JsonPatchDocument", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Copy", + "Parameters": [ + { + "Name": "from", + "Type": "System.String" + }, + { + "Name": "path", + "Type": "System.String" + } + ], + "ReturnType": "Microsoft.AspNetCore.JsonPatch.JsonPatchDocument", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "ApplyTo", + "Parameters": [ + { + "Name": "objectToApplyTo", + "Type": "System.Object" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "ApplyTo", + "Parameters": [ + { + "Name": "objectToApplyTo", + "Type": "System.Object" + }, + { + "Name": "logErrorAction", + "Type": "System.Action" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "ApplyTo", + "Parameters": [ + { + "Name": "objectToApplyTo", + "Type": "System.Object" + }, + { + "Name": "adapter", + "Type": "Microsoft.AspNetCore.JsonPatch.Adapters.IObjectAdapter" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "operations", + "Type": "System.Collections.Generic.List" + }, + { + "Name": "contractResolver", + "Type": "Newtonsoft.Json.Serialization.IContractResolver" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.JsonPatch.JsonPatchDocument", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.JsonPatch.IJsonPatchDocument" + ], + "Members": [ + { + "Kind": "Method", + "Name": "get_Operations", + "Parameters": [], + "ReturnType": "System.Collections.Generic.List>", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_ContractResolver", + "Parameters": [], + "ReturnType": "Newtonsoft.Json.Serialization.IContractResolver", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.JsonPatch.IJsonPatchDocument", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_ContractResolver", + "Parameters": [ + { + "Name": "value", + "Type": "Newtonsoft.Json.Serialization.IContractResolver" + } + ], + "ReturnType": "System.Void", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.JsonPatch.IJsonPatchDocument", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Add", + "Parameters": [ + { + "Name": "path", + "Type": "System.Linq.Expressions.Expression>" + }, + { + "Name": "value", + "Type": "T0" + } + ], + "ReturnType": "Microsoft.AspNetCore.JsonPatch.JsonPatchDocument", + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "TProp", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [] + } + ] + }, + { + "Kind": "Method", + "Name": "Add", + "Parameters": [ + { + "Name": "path", + "Type": "System.Linq.Expressions.Expression>>" + }, + { + "Name": "value", + "Type": "T0" + }, + { + "Name": "position", + "Type": "System.Int32" + } + ], + "ReturnType": "Microsoft.AspNetCore.JsonPatch.JsonPatchDocument", + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "TProp", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [] + } + ] + }, + { + "Kind": "Method", + "Name": "Add", + "Parameters": [ + { + "Name": "path", + "Type": "System.Linq.Expressions.Expression>>" + }, + { + "Name": "value", + "Type": "T0" + } + ], + "ReturnType": "Microsoft.AspNetCore.JsonPatch.JsonPatchDocument", + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "TProp", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [] + } + ] + }, + { + "Kind": "Method", + "Name": "Remove", + "Parameters": [ + { + "Name": "path", + "Type": "System.Linq.Expressions.Expression>" + } + ], + "ReturnType": "Microsoft.AspNetCore.JsonPatch.JsonPatchDocument", + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "TProp", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [] + } + ] + }, + { + "Kind": "Method", + "Name": "Remove", + "Parameters": [ + { + "Name": "path", + "Type": "System.Linq.Expressions.Expression>>" + }, + { + "Name": "position", + "Type": "System.Int32" + } + ], + "ReturnType": "Microsoft.AspNetCore.JsonPatch.JsonPatchDocument", + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "TProp", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [] + } + ] + }, + { + "Kind": "Method", + "Name": "Remove", + "Parameters": [ + { + "Name": "path", + "Type": "System.Linq.Expressions.Expression>>" + } + ], + "ReturnType": "Microsoft.AspNetCore.JsonPatch.JsonPatchDocument", + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "TProp", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [] + } + ] + }, + { + "Kind": "Method", + "Name": "Replace", + "Parameters": [ + { + "Name": "path", + "Type": "System.Linq.Expressions.Expression>" + }, + { + "Name": "value", + "Type": "T0" + } + ], + "ReturnType": "Microsoft.AspNetCore.JsonPatch.JsonPatchDocument", + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "TProp", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [] + } + ] + }, + { + "Kind": "Method", + "Name": "Replace", + "Parameters": [ + { + "Name": "path", + "Type": "System.Linq.Expressions.Expression>>" + }, + { + "Name": "value", + "Type": "T0" + }, + { + "Name": "position", + "Type": "System.Int32" + } + ], + "ReturnType": "Microsoft.AspNetCore.JsonPatch.JsonPatchDocument", + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "TProp", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [] + } + ] + }, + { + "Kind": "Method", + "Name": "Replace", + "Parameters": [ + { + "Name": "path", + "Type": "System.Linq.Expressions.Expression>>" + }, + { + "Name": "value", + "Type": "T0" + } + ], + "ReturnType": "Microsoft.AspNetCore.JsonPatch.JsonPatchDocument", + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "TProp", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [] + } + ] + }, + { + "Kind": "Method", + "Name": "Test", + "Parameters": [ + { + "Name": "path", + "Type": "System.Linq.Expressions.Expression>" + }, + { + "Name": "value", + "Type": "T0" + } + ], + "ReturnType": "Microsoft.AspNetCore.JsonPatch.JsonPatchDocument", + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "TProp", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [] + } + ] + }, + { + "Kind": "Method", + "Name": "Test", + "Parameters": [ + { + "Name": "path", + "Type": "System.Linq.Expressions.Expression>>" + }, + { + "Name": "value", + "Type": "T0" + }, + { + "Name": "position", + "Type": "System.Int32" + } + ], + "ReturnType": "Microsoft.AspNetCore.JsonPatch.JsonPatchDocument", + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "TProp", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [] + } + ] + }, + { + "Kind": "Method", + "Name": "Test", + "Parameters": [ + { + "Name": "path", + "Type": "System.Linq.Expressions.Expression>>" + }, + { + "Name": "value", + "Type": "T0" + } + ], + "ReturnType": "Microsoft.AspNetCore.JsonPatch.JsonPatchDocument", + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "TProp", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [] + } + ] + }, + { + "Kind": "Method", + "Name": "Move", + "Parameters": [ + { + "Name": "from", + "Type": "System.Linq.Expressions.Expression>" + }, + { + "Name": "path", + "Type": "System.Linq.Expressions.Expression>" + } + ], + "ReturnType": "Microsoft.AspNetCore.JsonPatch.JsonPatchDocument", + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "TProp", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [] + } + ] + }, + { + "Kind": "Method", + "Name": "Move", + "Parameters": [ + { + "Name": "from", + "Type": "System.Linq.Expressions.Expression>>" + }, + { + "Name": "positionFrom", + "Type": "System.Int32" + }, + { + "Name": "path", + "Type": "System.Linq.Expressions.Expression>" + } + ], + "ReturnType": "Microsoft.AspNetCore.JsonPatch.JsonPatchDocument", + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "TProp", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [] + } + ] + }, + { + "Kind": "Method", + "Name": "Move", + "Parameters": [ + { + "Name": "from", + "Type": "System.Linq.Expressions.Expression>" + }, + { + "Name": "path", + "Type": "System.Linq.Expressions.Expression>>" + }, + { + "Name": "positionTo", + "Type": "System.Int32" + } + ], + "ReturnType": "Microsoft.AspNetCore.JsonPatch.JsonPatchDocument", + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "TProp", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [] + } + ] + }, + { + "Kind": "Method", + "Name": "Move", + "Parameters": [ + { + "Name": "from", + "Type": "System.Linq.Expressions.Expression>>" + }, + { + "Name": "positionFrom", + "Type": "System.Int32" + }, + { + "Name": "path", + "Type": "System.Linq.Expressions.Expression>>" + }, + { + "Name": "positionTo", + "Type": "System.Int32" + } + ], + "ReturnType": "Microsoft.AspNetCore.JsonPatch.JsonPatchDocument", + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "TProp", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [] + } + ] + }, + { + "Kind": "Method", + "Name": "Move", + "Parameters": [ + { + "Name": "from", + "Type": "System.Linq.Expressions.Expression>>" + }, + { + "Name": "positionFrom", + "Type": "System.Int32" + }, + { + "Name": "path", + "Type": "System.Linq.Expressions.Expression>>" + } + ], + "ReturnType": "Microsoft.AspNetCore.JsonPatch.JsonPatchDocument", + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "TProp", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [] + } + ] + }, + { + "Kind": "Method", + "Name": "Move", + "Parameters": [ + { + "Name": "from", + "Type": "System.Linq.Expressions.Expression>" + }, + { + "Name": "path", + "Type": "System.Linq.Expressions.Expression>>" + } + ], + "ReturnType": "Microsoft.AspNetCore.JsonPatch.JsonPatchDocument", + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "TProp", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [] + } + ] + }, + { + "Kind": "Method", + "Name": "Copy", + "Parameters": [ + { + "Name": "from", + "Type": "System.Linq.Expressions.Expression>" + }, + { + "Name": "path", + "Type": "System.Linq.Expressions.Expression>" + } + ], + "ReturnType": "Microsoft.AspNetCore.JsonPatch.JsonPatchDocument", + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "TProp", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [] + } + ] + }, + { + "Kind": "Method", + "Name": "Copy", + "Parameters": [ + { + "Name": "from", + "Type": "System.Linq.Expressions.Expression>>" + }, + { + "Name": "positionFrom", + "Type": "System.Int32" + }, + { + "Name": "path", + "Type": "System.Linq.Expressions.Expression>" + } + ], + "ReturnType": "Microsoft.AspNetCore.JsonPatch.JsonPatchDocument", + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "TProp", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [] + } + ] + }, + { + "Kind": "Method", + "Name": "Copy", + "Parameters": [ + { + "Name": "from", + "Type": "System.Linq.Expressions.Expression>" + }, + { + "Name": "path", + "Type": "System.Linq.Expressions.Expression>>" + }, + { + "Name": "positionTo", + "Type": "System.Int32" + } + ], + "ReturnType": "Microsoft.AspNetCore.JsonPatch.JsonPatchDocument", + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "TProp", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [] + } + ] + }, + { + "Kind": "Method", + "Name": "Copy", + "Parameters": [ + { + "Name": "from", + "Type": "System.Linq.Expressions.Expression>>" + }, + { + "Name": "positionFrom", + "Type": "System.Int32" + }, + { + "Name": "path", + "Type": "System.Linq.Expressions.Expression>>" + }, + { + "Name": "positionTo", + "Type": "System.Int32" + } + ], + "ReturnType": "Microsoft.AspNetCore.JsonPatch.JsonPatchDocument", + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "TProp", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [] + } + ] + }, + { + "Kind": "Method", + "Name": "Copy", + "Parameters": [ + { + "Name": "from", + "Type": "System.Linq.Expressions.Expression>>" + }, + { + "Name": "positionFrom", + "Type": "System.Int32" + }, + { + "Name": "path", + "Type": "System.Linq.Expressions.Expression>>" + } + ], + "ReturnType": "Microsoft.AspNetCore.JsonPatch.JsonPatchDocument", + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "TProp", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [] + } + ] + }, + { + "Kind": "Method", + "Name": "Copy", + "Parameters": [ + { + "Name": "from", + "Type": "System.Linq.Expressions.Expression>" + }, + { + "Name": "path", + "Type": "System.Linq.Expressions.Expression>>" + } + ], + "ReturnType": "Microsoft.AspNetCore.JsonPatch.JsonPatchDocument", + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "TProp", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [] + } + ] + }, + { + "Kind": "Method", + "Name": "ApplyTo", + "Parameters": [ + { + "Name": "objectToApplyTo", + "Type": "T0" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "ApplyTo", + "Parameters": [ + { + "Name": "objectToApplyTo", + "Type": "T0" + }, + { + "Name": "logErrorAction", + "Type": "System.Action" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "ApplyTo", + "Parameters": [ + { + "Name": "objectToApplyTo", + "Type": "T0" + }, + { + "Name": "adapter", + "Type": "Microsoft.AspNetCore.JsonPatch.Adapters.IObjectAdapter" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "operations", + "Type": "System.Collections.Generic.List>" + }, + { + "Name": "contractResolver", + "Type": "Newtonsoft.Json.Serialization.IContractResolver" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [ + { + "ParameterName": "TModel", + "ParameterPosition": 0, + "Class": true, + "BaseTypeOrInterfaces": [] + } + ] + }, + { + "Name": "Microsoft.AspNetCore.JsonPatch.JsonPatchError", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_AffectedObject", + "Parameters": [], + "ReturnType": "System.Object", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Operation", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.JsonPatch.Operations.Operation", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_ErrorMessage", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "affectedObject", + "Type": "System.Object" + }, + { + "Name": "operation", + "Type": "Microsoft.AspNetCore.JsonPatch.Operations.Operation" + }, + { + "Name": "errorMessage", + "Type": "System.String" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.JsonPatch.Operations.Operation", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.JsonPatch.Operations.OperationBase", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_value", + "Parameters": [], + "ReturnType": "System.Object", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_value", + "Parameters": [ + { + "Name": "value", + "Type": "System.Object" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Apply", + "Parameters": [ + { + "Name": "objectToApplyTo", + "Type": "System.Object" + }, + { + "Name": "adapter", + "Type": "Microsoft.AspNetCore.JsonPatch.Adapters.IObjectAdapter" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "ShouldSerializevalue", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "op", + "Type": "System.String" + }, + { + "Name": "path", + "Type": "System.String" + }, + { + "Name": "from", + "Type": "System.String" + }, + { + "Name": "value", + "Type": "System.Object" + } + ], + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "op", + "Type": "System.String" + }, + { + "Name": "path", + "Type": "System.String" + }, + { + "Name": "from", + "Type": "System.String" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.JsonPatch.Operations.OperationBase", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_OperationType", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.JsonPatch.Operations.OperationType", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_path", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_path", + "Parameters": [ + { + "Name": "value", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_op", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_op", + "Parameters": [ + { + "Name": "value", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_from", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_from", + "Parameters": [ + { + "Name": "value", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "ShouldSerializefrom", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "op", + "Type": "System.String" + }, + { + "Name": "path", + "Type": "System.String" + }, + { + "Name": "from", + "Type": "System.String" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.JsonPatch.Operations.Operation", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.JsonPatch.Operations.Operation", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Apply", + "Parameters": [ + { + "Name": "objectToApplyTo", + "Type": "T0" + }, + { + "Name": "adapter", + "Type": "Microsoft.AspNetCore.JsonPatch.Adapters.IObjectAdapter" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "op", + "Type": "System.String" + }, + { + "Name": "path", + "Type": "System.String" + }, + { + "Name": "from", + "Type": "System.String" + }, + { + "Name": "value", + "Type": "System.Object" + } + ], + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "op", + "Type": "System.String" + }, + { + "Name": "path", + "Type": "System.String" + }, + { + "Name": "from", + "Type": "System.String" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [ + { + "ParameterName": "TModel", + "ParameterPosition": 0, + "Class": true, + "BaseTypeOrInterfaces": [] + } + ] + }, + { + "Name": "Microsoft.AspNetCore.JsonPatch.Operations.OperationType", + "Visibility": "Public", + "Kind": "Enumeration", + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Field", + "Name": "Add", + "Parameters": [], + "GenericParameter": [], + "Literal": "0" + }, + { + "Kind": "Field", + "Name": "Remove", + "Parameters": [], + "GenericParameter": [], + "Literal": "1" + }, + { + "Kind": "Field", + "Name": "Replace", + "Parameters": [], + "GenericParameter": [], + "Literal": "2" + }, + { + "Kind": "Field", + "Name": "Move", + "Parameters": [], + "GenericParameter": [], + "Literal": "3" + }, + { + "Kind": "Field", + "Name": "Copy", + "Parameters": [], + "GenericParameter": [], + "Literal": "4" + }, + { + "Kind": "Field", + "Name": "Test", + "Parameters": [], + "GenericParameter": [], + "Literal": "5" + }, + { + "Kind": "Field", + "Name": "Invalid", + "Parameters": [], + "GenericParameter": [], + "Literal": "6" + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.JsonPatch.Helpers.GetValueResult", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_PropertyValue", + "Parameters": [], + "ReturnType": "System.Object", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_HasError", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "propertyValue", + "Type": "System.Object" + }, + { + "Name": "hasError", + "Type": "System.Boolean" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.JsonPatch.Exceptions.JsonPatchException", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "System.Exception", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_FailedOperation", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.JsonPatch.Operations.Operation", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_AffectedObject", + "Parameters": [], + "ReturnType": "System.Object", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "jsonPatchError", + "Type": "Microsoft.AspNetCore.JsonPatch.JsonPatchError" + }, + { + "Name": "innerException", + "Type": "System.Exception" + } + ], + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "jsonPatchError", + "Type": "Microsoft.AspNetCore.JsonPatch.JsonPatchError" + } + ], + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "message", + "Type": "System.String" + }, + { + "Name": "innerException", + "Type": "System.Exception" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.JsonPatch.Converters.JsonPatchDocumentConverter", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Newtonsoft.Json.JsonConverter", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "CanConvert", + "Parameters": [ + { + "Name": "objectType", + "Type": "System.Type" + } + ], + "ReturnType": "System.Boolean", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "ReadJson", + "Parameters": [ + { + "Name": "reader", + "Type": "Newtonsoft.Json.JsonReader" + }, + { + "Name": "objectType", + "Type": "System.Type" + }, + { + "Name": "existingValue", + "Type": "System.Object" + }, + { + "Name": "serializer", + "Type": "Newtonsoft.Json.JsonSerializer" + } + ], + "ReturnType": "System.Object", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "WriteJson", + "Parameters": [ + { + "Name": "writer", + "Type": "Newtonsoft.Json.JsonWriter" + }, + { + "Name": "value", + "Type": "System.Object" + }, + { + "Name": "serializer", + "Type": "Newtonsoft.Json.JsonSerializer" + } + ], + "ReturnType": "System.Void", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.JsonPatch.Converters.TypedJsonPatchDocumentConverter", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.JsonPatch.Converters.JsonPatchDocumentConverter", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "ReadJson", + "Parameters": [ + { + "Name": "reader", + "Type": "Newtonsoft.Json.JsonReader" + }, + { + "Name": "objectType", + "Type": "System.Type" + }, + { + "Name": "existingValue", + "Type": "System.Object" + }, + { + "Name": "serializer", + "Type": "Newtonsoft.Json.JsonSerializer" + } + ], + "ReturnType": "System.Object", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.JsonPatch.Adapters.IObjectAdapter", + "Visibility": "Public", + "Kind": "Interface", + "Abstract": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Add", + "Parameters": [ + { + "Name": "operation", + "Type": "Microsoft.AspNetCore.JsonPatch.Operations.Operation" + }, + { + "Name": "objectToApplyTo", + "Type": "System.Object" + } + ], + "ReturnType": "System.Void", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Copy", + "Parameters": [ + { + "Name": "operation", + "Type": "Microsoft.AspNetCore.JsonPatch.Operations.Operation" + }, + { + "Name": "objectToApplyTo", + "Type": "System.Object" + } + ], + "ReturnType": "System.Void", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Move", + "Parameters": [ + { + "Name": "operation", + "Type": "Microsoft.AspNetCore.JsonPatch.Operations.Operation" + }, + { + "Name": "objectToApplyTo", + "Type": "System.Object" + } + ], + "ReturnType": "System.Void", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Remove", + "Parameters": [ + { + "Name": "operation", + "Type": "Microsoft.AspNetCore.JsonPatch.Operations.Operation" + }, + { + "Name": "objectToApplyTo", + "Type": "System.Object" + } + ], + "ReturnType": "System.Void", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Replace", + "Parameters": [ + { + "Name": "operation", + "Type": "Microsoft.AspNetCore.JsonPatch.Operations.Operation" + }, + { + "Name": "objectToApplyTo", + "Type": "System.Object" + } + ], + "ReturnType": "System.Void", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.JsonPatch.Adapters.IObjectAdapterWithTest", + "Visibility": "Public", + "Kind": "Interface", + "Abstract": true, + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.JsonPatch.Adapters.IObjectAdapter" + ], + "Members": [ + { + "Kind": "Method", + "Name": "Test", + "Parameters": [ + { + "Name": "operation", + "Type": "Microsoft.AspNetCore.JsonPatch.Operations.Operation" + }, + { + "Name": "objectToApplyTo", + "Type": "System.Object" + } + ], + "ReturnType": "System.Void", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.JsonPatch.Adapters.ObjectAdapter", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.JsonPatch.Adapters.IObjectAdapterWithTest" + ], + "Members": [ + { + "Kind": "Method", + "Name": "Add", + "Parameters": [ + { + "Name": "operation", + "Type": "Microsoft.AspNetCore.JsonPatch.Operations.Operation" + }, + { + "Name": "objectToApplyTo", + "Type": "System.Object" + } + ], + "ReturnType": "System.Void", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.JsonPatch.Adapters.IObjectAdapter", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Copy", + "Parameters": [ + { + "Name": "operation", + "Type": "Microsoft.AspNetCore.JsonPatch.Operations.Operation" + }, + { + "Name": "objectToApplyTo", + "Type": "System.Object" + } + ], + "ReturnType": "System.Void", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.JsonPatch.Adapters.IObjectAdapter", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Move", + "Parameters": [ + { + "Name": "operation", + "Type": "Microsoft.AspNetCore.JsonPatch.Operations.Operation" + }, + { + "Name": "objectToApplyTo", + "Type": "System.Object" + } + ], + "ReturnType": "System.Void", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.JsonPatch.Adapters.IObjectAdapter", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Remove", + "Parameters": [ + { + "Name": "operation", + "Type": "Microsoft.AspNetCore.JsonPatch.Operations.Operation" + }, + { + "Name": "objectToApplyTo", + "Type": "System.Object" + } + ], + "ReturnType": "System.Void", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.JsonPatch.Adapters.IObjectAdapter", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Replace", + "Parameters": [ + { + "Name": "operation", + "Type": "Microsoft.AspNetCore.JsonPatch.Operations.Operation" + }, + { + "Name": "objectToApplyTo", + "Type": "System.Object" + } + ], + "ReturnType": "System.Void", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.JsonPatch.Adapters.IObjectAdapter", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_ContractResolver", + "Parameters": [], + "ReturnType": "Newtonsoft.Json.Serialization.IContractResolver", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_LogErrorAction", + "Parameters": [], + "ReturnType": "System.Action", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Test", + "Parameters": [ + { + "Name": "operation", + "Type": "Microsoft.AspNetCore.JsonPatch.Operations.Operation" + }, + { + "Name": "objectToApplyTo", + "Type": "System.Object" + } + ], + "ReturnType": "System.Void", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.JsonPatch.Adapters.IObjectAdapterWithTest", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "contractResolver", + "Type": "Newtonsoft.Json.Serialization.IContractResolver" + }, + { + "Name": "logErrorAction", + "Type": "System.Action" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + } + ] +} \ No newline at end of file diff --git a/src/Features/JsonPatch/test/Adapters/AdapterFactoryTests.cs b/src/Features/JsonPatch/test/Adapters/AdapterFactoryTests.cs new file mode 100644 index 0000000000..1e961c29e9 --- /dev/null +++ b/src/Features/JsonPatch/test/Adapters/AdapterFactoryTests.cs @@ -0,0 +1,73 @@ +using Microsoft.AspNetCore.JsonPatch.Adapters; +using Microsoft.AspNetCore.JsonPatch.Internal; +using Moq; +using Newtonsoft.Json.Serialization; +using System; +using System.Collections.Generic; +using System.Dynamic; +using System.Text; +using Xunit; + +namespace Microsoft.AspNetCore.JsonPatch.Test.Adapters +{ + public class AdapterFactoryTests + { + [Fact] + public void GetListAdapterForListTargets() + { + // Arrange + AdapterFactory factory = new AdapterFactory(); + + //Act: + IAdapter adapter = factory.Create(new List(), new DefaultContractResolver()); + + // Assert + Assert.Equal(typeof(ListAdapter), adapter.GetType()); + } + + [Fact] + public void GetDictionaryAdapterForDictionaryObjects() + { + // Arrange + AdapterFactory factory = new AdapterFactory(); + + //Act: + IAdapter adapter = factory.Create(new Dictionary(), new DefaultContractResolver()); + + // Assert + Assert.Equal(typeof(DictionaryAdapter), adapter.GetType()); + } + + private class PocoModel + {} + + + [Fact] + public void GetPocoAdapterForGenericObjects() + { + // Arrange + AdapterFactory factory = new AdapterFactory(); + + //Act: + IAdapter adapter = factory.Create(new PocoModel(), new DefaultContractResolver()); + + // Assert + Assert.Equal(typeof(PocoAdapter), adapter.GetType()); + } + + + + [Fact] + public void GetDynamicAdapterForGenericObjects() + { + // Arrange + AdapterFactory factory = new AdapterFactory(); + + //Act: + IAdapter adapter = factory.Create(new TestDynamicObject(), new DefaultContractResolver()); + + // Assert + Assert.Equal(typeof(DynamicObjectAdapter), adapter.GetType()); + } + } +} diff --git a/src/Features/JsonPatch/test/Adapters/TestDynamicObject.cs b/src/Features/JsonPatch/test/Adapters/TestDynamicObject.cs new file mode 100644 index 0000000000..08371f25c6 --- /dev/null +++ b/src/Features/JsonPatch/test/Adapters/TestDynamicObject.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Dynamic; +using System.Text; + +namespace Microsoft.AspNetCore.JsonPatch.Test.Adapters +{ + public class TestDynamicObject : DynamicObject + { } +} diff --git a/src/Features/JsonPatch/test/CustomNamingStrategyTests.cs b/src/Features/JsonPatch/test/CustomNamingStrategyTests.cs new file mode 100644 index 0000000000..ebc45874d9 --- /dev/null +++ b/src/Features/JsonPatch/test/CustomNamingStrategyTests.cs @@ -0,0 +1,153 @@ +// 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.Dynamic; +using Newtonsoft.Json.Serialization; +using Xunit; + +namespace Microsoft.AspNetCore.JsonPatch +{ + public class CustomNamingStrategyTests + { + [Fact] + public void AddProperty_ToDynamicTestObject_WithCustomNamingStrategy() + { + // Arrange + var contractResolver = new DefaultContractResolver + { + NamingStrategy = new TestNamingStrategy() + }; + + dynamic targetObject = new DynamicTestObject(); + targetObject.Test = 1; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Add("NewInt", 1); + patchDocument.ContractResolver = contractResolver; + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.Equal(1, targetObject.customNewInt); + Assert.Equal(1, targetObject.Test); + } + + [Fact] + public void CopyPropertyValue_ToDynamicTestObject_WithCustomNamingStrategy() + { + // Arrange + var contractResolver = new DefaultContractResolver + { + NamingStrategy = new TestNamingStrategy() + }; + + dynamic targetObject = new DynamicTestObject(); + targetObject.customStringProperty = "A"; + targetObject.customAnotherStringProperty = "B"; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Copy("StringProperty", "AnotherStringProperty"); + patchDocument.ContractResolver = contractResolver; + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.Equal("A", targetObject.customAnotherStringProperty); + } + + [Fact] + public void MovePropertyValue_ForExpandoObject_WithCustomNamingStrategy() + { + // Arrange + var contractResolver = new DefaultContractResolver + { + NamingStrategy = new TestNamingStrategy() + }; + + dynamic targetObject = new ExpandoObject(); + targetObject.customStringProperty = "A"; + targetObject.customAnotherStringProperty = "B"; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Move("StringProperty", "AnotherStringProperty"); + patchDocument.ContractResolver = contractResolver; + + // Act + patchDocument.ApplyTo(targetObject); + var cont = targetObject as IDictionary; + cont.TryGetValue("customStringProperty", out var valueFromDictionary); + + // Assert + Assert.Equal("A", targetObject.customAnotherStringProperty); + Assert.Null(valueFromDictionary); + } + + [Fact] + public void RemoveProperty_FromDictionaryObject_WithCustomNamingStrategy() + { + // Arrange + var contractResolver = new DefaultContractResolver + { + NamingStrategy = new TestNamingStrategy() + }; + + var targetObject = new Dictionary() + { + { "customTest", 1}, + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Remove("Test"); + patchDocument.ContractResolver = contractResolver; + + // Act + patchDocument.ApplyTo(targetObject); + var cont = targetObject as IDictionary; + cont.TryGetValue("customTest", out var valueFromDictionary); + + // Assert + Assert.Equal(0, valueFromDictionary); + } + + [Fact] + public void ReplacePropertyValue_ForExpandoObject_WithCustomNamingStrategy() + { + // Arrange + var contractResolver = new DefaultContractResolver + { + NamingStrategy = new TestNamingStrategy() + }; + + dynamic targetObject = new ExpandoObject(); + targetObject.customTest = 1; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Replace("Test", 2); + patchDocument.ContractResolver = contractResolver; + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.Equal(2, targetObject.customTest); + } + + private class TestNamingStrategy : NamingStrategy + { + public new bool ProcessDictionaryKeys => true; + + public override string GetDictionaryKey(string key) + { + return "custom" + key; + } + + protected override string ResolvePropertyName(string name) + { + return name; + } + } + } +} diff --git a/src/Features/JsonPatch/test/IntegrationTests/AnonymousObjectIntegrationTest.cs b/src/Features/JsonPatch/test/IntegrationTests/AnonymousObjectIntegrationTest.cs new file mode 100644 index 0000000000..4f290aae2f --- /dev/null +++ b/src/Features/JsonPatch/test/IntegrationTests/AnonymousObjectIntegrationTest.cs @@ -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.AspNetCore.JsonPatch.Exceptions; +using Xunit; + +namespace Microsoft.AspNetCore.JsonPatch.IntegrationTests +{ + public class AnonymousObjectIntegrationTest + { + [Fact] + public void AddNewProperty_ShouldFail() + { + // Arrange + var targetObject = new { }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Add("NewProperty", 4); + + // Act + var exception = Assert.Throws(() => + { + patchDocument.ApplyTo(targetObject); + }); + + // Assert + Assert.Equal("The target location specified by path segment 'NewProperty' was not found.", + exception.Message); + } + + [Fact] + public void AddNewProperty_ToNestedAnonymousObject_ShouldFail() + { + // Arrange + dynamic targetObject = new + { + Test = 1, + nested = new { } + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Add("Nested/NewInt", 1); + + // Act + var exception = Assert.Throws(() => + { + patchDocument.ApplyTo(targetObject); + }); + + // Assert + Assert.Equal("The target location specified by path segment 'NewInt' was not found.", + exception.Message); + } + + [Fact] + public void AddDoesNotReplace() + { + // Arrange + var targetObject = new + { + StringProperty = "A" + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Add("StringProperty", "B"); + + // Act + var exception = Assert.Throws(() => + { + patchDocument.ApplyTo(targetObject); + }); + + // Assert + Assert.Equal("The property at path 'StringProperty' could not be updated.", + exception.Message); + } + + [Fact] + public void RemoveProperty_ShouldFail() + { + // Arrange + dynamic targetObject = new + { + Test = 1 + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Remove("Test"); + + // Act + var exception = Assert.Throws(() => + { + patchDocument.ApplyTo(targetObject); + }); + + // Assert + Assert.Equal("The property at path 'Test' could not be updated.", + exception.Message); + } + + [Fact] + public void ReplaceProperty_ShouldFail() + { + // Arrange + var targetObject = new + { + StringProperty = "A", + AnotherStringProperty = "B" + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Replace("StringProperty", "AnotherStringProperty"); + + // Act + var exception = Assert.Throws(() => + { + patchDocument.ApplyTo(targetObject); + }); + + // Assert + Assert.Equal("The property at path 'StringProperty' could not be updated.", + exception.Message); + } + + [Fact] + public void MoveProperty_ShouldFail() + { + // Arrange + var targetObject = new + { + StringProperty = "A", + AnotherStringProperty = "B" + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Move("StringProperty", "AnotherStringProperty"); + + // Act + var exception = Assert.Throws(() => + { + patchDocument.ApplyTo(targetObject); + }); + + // Assert + Assert.Equal("The property at path 'StringProperty' could not be updated.", + exception.Message); + } + + [Fact] + public void TestStringProperty_IsSucessful() + { + // Arrange + var targetObject = new + { + StringProperty = "A", + AnotherStringProperty = "B" + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Test("StringProperty", "A"); + + // Act & Assert + patchDocument.ApplyTo(targetObject); + } + + [Fact] + public void TestStringProperty_Fails() + { + // Arrange + var targetObject = new + { + StringProperty = "A", + AnotherStringProperty = "B" + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Test("StringProperty", "B"); + + // Act + var exception = Assert.Throws(() => + { + patchDocument.ApplyTo(targetObject); + }); + + // Assert + Assert.Equal("The current value 'A' at path 'StringProperty' is not equal to the test value 'B'.", + exception.Message); + } + } +} diff --git a/src/Features/JsonPatch/test/IntegrationTests/DictionaryIntegrationTest.cs b/src/Features/JsonPatch/test/IntegrationTests/DictionaryIntegrationTest.cs new file mode 100644 index 0000000000..da990e3e8c --- /dev/null +++ b/src/Features/JsonPatch/test/IntegrationTests/DictionaryIntegrationTest.cs @@ -0,0 +1,319 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Collections.Generic; +using Microsoft.AspNetCore.JsonPatch.Exceptions; +using Xunit; + +namespace Microsoft.AspNetCore.JsonPatch.IntegrationTests +{ + public class DictionaryTest + { + [Fact] + public void TestIntegerValue_IsSuccessful() + { + // Arrange + var model = new IntDictionary(); + model.DictionaryOfStringToInteger["one"] = 1; + model.DictionaryOfStringToInteger["two"] = 2; + var patchDocument = new JsonPatchDocument(); + patchDocument.Test("/DictionaryOfStringToInteger/two", 2); + + // Act & Assert + patchDocument.ApplyTo(model); + } + + [Fact] + public void AddIntegerValue_Succeeds() + { + // Arrange + var model = new IntDictionary(); + model.DictionaryOfStringToInteger["one"] = 1; + model.DictionaryOfStringToInteger["two"] = 2; + var patchDocument = new JsonPatchDocument(); + patchDocument.Add("/DictionaryOfStringToInteger/three", 3); + + // Act + patchDocument.ApplyTo(model); + + // Assert + Assert.Equal(3, model.DictionaryOfStringToInteger.Count); + Assert.Equal(1, model.DictionaryOfStringToInteger["one"]); + Assert.Equal(2, model.DictionaryOfStringToInteger["two"]); + Assert.Equal(3, model.DictionaryOfStringToInteger["three"]); + } + + [Fact] + public void RemoveIntegerValue_Succeeds() + { + // Arrange + var model = new IntDictionary(); + model.DictionaryOfStringToInteger["one"] = 1; + model.DictionaryOfStringToInteger["two"] = 2; + var patchDocument = new JsonPatchDocument(); + patchDocument.Remove("/DictionaryOfStringToInteger/two"); + + // Act + patchDocument.ApplyTo(model); + + // Assert + Assert.Equal(1, model.DictionaryOfStringToInteger.Count); + Assert.Equal(1, model.DictionaryOfStringToInteger["one"]); + } + + [Fact] + public void MoveIntegerValue_Succeeds() + { + // Arrange + var model = new IntDictionary(); + model.DictionaryOfStringToInteger["one"] = 1; + model.DictionaryOfStringToInteger["two"] = 2; + var patchDocument = new JsonPatchDocument(); + patchDocument.Move("/DictionaryOfStringToInteger/one", "/DictionaryOfStringToInteger/two"); + + // Act + patchDocument.ApplyTo(model); + + // Assert + Assert.Equal(1, model.DictionaryOfStringToInteger.Count); + Assert.Equal(1, model.DictionaryOfStringToInteger["two"]); + } + + [Fact] + public void ReplaceIntegerValue_Succeeds() + { + // Arrange + var model = new IntDictionary(); + model.DictionaryOfStringToInteger["one"] = 1; + model.DictionaryOfStringToInteger["two"] = 2; + var patchDocument = new JsonPatchDocument(); + patchDocument.Replace("/DictionaryOfStringToInteger/two", 20); + + // Act + patchDocument.ApplyTo(model); + + // Assert + Assert.Equal(2, model.DictionaryOfStringToInteger.Count); + Assert.Equal(1, model.DictionaryOfStringToInteger["one"]); + Assert.Equal(20, model.DictionaryOfStringToInteger["two"]); + } + + [Fact] + public void CopyIntegerValue_Succeeds() + { + // Arrange + var model = new IntDictionary(); + model.DictionaryOfStringToInteger["one"] = 1; + model.DictionaryOfStringToInteger["two"] = 2; + var patchDocument = new JsonPatchDocument(); + patchDocument.Copy("/DictionaryOfStringToInteger/one", "/DictionaryOfStringToInteger/two"); + + // Act + patchDocument.ApplyTo(model); + + // Assert + Assert.Equal(2, model.DictionaryOfStringToInteger.Count); + Assert.Equal(1, model.DictionaryOfStringToInteger["one"]); + Assert.Equal(1, model.DictionaryOfStringToInteger["two"]); + } + + private class Customer + { + public string Name { get; set; } + public Address Address { get; set; } + } + + private class Address + { + public string City { get; set; } + } + + private class IntDictionary + { + public IDictionary DictionaryOfStringToInteger { get; } = new Dictionary(); + } + + private class CustomerDictionary + { + public IDictionary DictionaryOfStringToCustomer { get; } = new Dictionary(); + } + + [Fact] + public void TestPocoObject_Succeeds() + { + // Arrange + var key1 = 100; + var value1 = new Customer() { Name = "James" }; + var model = new CustomerDictionary(); + model.DictionaryOfStringToCustomer[key1] = value1; + var patchDocument = new JsonPatchDocument(); + patchDocument.Test($"/DictionaryOfStringToCustomer/{key1}/Name", "James"); + + // Act & Assert + patchDocument.ApplyTo(model); + } + + [Fact] + public void TestPocoObject_FailsWhenTestValueIsNotEqualToObjectValue() + { + // Arrange + var key1 = 100; + var value1 = new Customer() { Name = "James" }; + var model = new CustomerDictionary(); + model.DictionaryOfStringToCustomer[key1] = value1; + var patchDocument = new JsonPatchDocument(); + patchDocument.Test($"/DictionaryOfStringToCustomer/{key1}/Name", "Mike"); + + // Act + var exception = Assert.Throws(() => + { + patchDocument.ApplyTo(model); + }); + + // Assert + Assert.Equal("The current value 'James' at path 'Name' is not equal to the test value 'Mike'.", exception.Message); + } + + [Fact] + public void AddReplacesPocoObject_Succeeds() + { + // Arrange + var key1 = 100; + var value1 = new Customer() { Name = "Jamesss" }; + var key2 = 200; + var value2 = new Customer() { Name = "Mike" }; + var model = new CustomerDictionary(); + model.DictionaryOfStringToCustomer[key1] = value1; + model.DictionaryOfStringToCustomer[key2] = value2; + var patchDocument = new JsonPatchDocument(); + patchDocument.Add($"/DictionaryOfStringToCustomer/{key1}/Name", "James"); + + // Act + patchDocument.ApplyTo(model); + + // Assert + Assert.Equal(2, model.DictionaryOfStringToCustomer.Count); + var actualValue1 = model.DictionaryOfStringToCustomer[key1]; + Assert.NotNull(actualValue1); + Assert.Equal("James", actualValue1.Name); + } + + [Fact] + public void RemovePocoObject_Succeeds() + { + // Arrange + var key1 = 100; + var value1 = new Customer() { Name = "Jamesss" }; + var key2 = 200; + var value2 = new Customer() { Name = "Mike" }; + var model = new CustomerDictionary(); + model.DictionaryOfStringToCustomer[key1] = value1; + model.DictionaryOfStringToCustomer[key2] = value2; + var patchDocument = new JsonPatchDocument(); + patchDocument.Remove($"/DictionaryOfStringToCustomer/{key1}/Name"); + + // Act + patchDocument.ApplyTo(model); + + // Assert + var actualValue1 = model.DictionaryOfStringToCustomer[key1]; + Assert.Null(actualValue1.Name); + } + + [Fact] + public void MovePocoObject_Succeeds() + { + // Arrange + var key1 = 100; + var value1 = new Customer() { Name = "James" }; + var key2 = 200; + var value2 = new Customer() { Name = "Mike" }; + var model = new CustomerDictionary(); + model.DictionaryOfStringToCustomer[key1] = value1; + model.DictionaryOfStringToCustomer[key2] = value2; + var patchDocument = new JsonPatchDocument(); + patchDocument.Move($"/DictionaryOfStringToCustomer/{key1}/Name", $"/DictionaryOfStringToCustomer/{key2}/Name"); + + // Act + patchDocument.ApplyTo(model); + + // Assert + var actualValue2 = model.DictionaryOfStringToCustomer[key2]; + Assert.NotNull(actualValue2); + Assert.Equal("James", actualValue2.Name); + } + + [Fact] + public void CopyPocoObject_Succeeds() + { + // Arrange + var key1 = 100; + var value1 = new Customer() { Name = "James" }; + var key2 = 200; + var value2 = new Customer() { Name = "Mike" }; + var model = new CustomerDictionary(); + model.DictionaryOfStringToCustomer[key1] = value1; + model.DictionaryOfStringToCustomer[key2] = value2; + var patchDocument = new JsonPatchDocument(); + patchDocument.Copy($"/DictionaryOfStringToCustomer/{key1}/Name", $"/DictionaryOfStringToCustomer/{key2}/Name"); + + // Act + patchDocument.ApplyTo(model); + + // Assert + Assert.Equal(2, model.DictionaryOfStringToCustomer.Count); + var actualValue2 = model.DictionaryOfStringToCustomer[key2]; + Assert.NotNull(actualValue2); + Assert.Equal("James", actualValue2.Name); + } + + [Fact] + public void ReplacePocoObject_Succeeds() + { + // Arrange + var key1 = 100; + var value1 = new Customer() { Name = "Jamesss" }; + var key2 = 200; + var value2 = new Customer() { Name = "Mike" }; + var model = new CustomerDictionary(); + model.DictionaryOfStringToCustomer[key1] = value1; + model.DictionaryOfStringToCustomer[key2] = value2; + var patchDocument = new JsonPatchDocument(); + patchDocument.Replace($"/DictionaryOfStringToCustomer/{key1}/Name", "James"); + + // Act + patchDocument.ApplyTo(model); + + // Assert + Assert.Equal(2, model.DictionaryOfStringToCustomer.Count); + var actualValue1 = model.DictionaryOfStringToCustomer[key1]; + Assert.NotNull(actualValue1); + Assert.Equal("James", actualValue1.Name); + } + + [Fact] + public void ReplacePocoObject_WithEscaping_Succeeds() + { + // Arrange + var key1 = "Foo/Name"; + var value1 = 100; + var key2 = "Foo"; + var value2 = 200; + var model = new IntDictionary(); + model.DictionaryOfStringToInteger[key1] = value1; + model.DictionaryOfStringToInteger[key2] = value2; + var patchDocument = new JsonPatchDocument(); + patchDocument.Replace($"/DictionaryOfStringToInteger/Foo~1Name", 300); + + // Act + patchDocument.ApplyTo(model); + + // Assert + Assert.Equal(2, model.DictionaryOfStringToInteger.Count); + var actualValue1 = model.DictionaryOfStringToInteger[key1]; + var actualValue2 = model.DictionaryOfStringToInteger[key2]; + Assert.Equal(300, actualValue1); + Assert.Equal(200, actualValue2); + } + } +} diff --git a/src/Features/JsonPatch/test/IntegrationTests/DynamicObjectIntegrationTest.cs b/src/Features/JsonPatch/test/IntegrationTests/DynamicObjectIntegrationTest.cs new file mode 100644 index 0000000000..ec15951a85 --- /dev/null +++ b/src/Features/JsonPatch/test/IntegrationTests/DynamicObjectIntegrationTest.cs @@ -0,0 +1,236 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Collections.Generic; +using Microsoft.AspNetCore.JsonPatch.Exceptions; +using Xunit; + +namespace Microsoft.AspNetCore.JsonPatch.IntegrationTests +{ + public class DynamicObjectIntegrationTest + { + [Fact] + public void AddResults_ShouldReplaceExistingPropertyValue_InNestedDynamicObject() + { + // Arrange + dynamic dynamicTestObject = new DynamicTestObject(); + dynamicTestObject.Nested = new NestedObject(); + dynamicTestObject.Nested.DynamicProperty = new DynamicTestObject(); + dynamicTestObject.Nested.DynamicProperty.InBetweenFirst = new DynamicTestObject(); + dynamicTestObject.Nested.DynamicProperty.InBetweenFirst.InBetweenSecond = new DynamicTestObject(); + dynamicTestObject.Nested.DynamicProperty.InBetweenFirst.InBetweenSecond.StringProperty = "A"; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Add("/Nested/DynamicProperty/InBetweenFirst/InBetweenSecond/StringProperty", "B"); + + // Act + patchDocument.ApplyTo(dynamicTestObject); + + // Assert + Assert.Equal("B", dynamicTestObject.Nested.DynamicProperty.InBetweenFirst.InBetweenSecond.StringProperty); + } + + [Fact] + public void ShouldNotBeAbleToAdd_ToNonExistingProperty_ThatIsNotTheRoot() + { + //Adding to a Nonexistent Target + // + // An example target JSON document: + // { "foo": "bar" } + // A JSON Patch document: + // [ + // { "op": "add", "path": "/baz/bat", "value": "qux" } + // ] + // This JSON Patch document, applied to the target JSON document above, + // would result in an error (therefore, it would not be applied), + // because the "add" operation's target location that references neither + // the root of the document, nor a member of an existing object, nor a + // member of an existing array. + + // Arrange + var nestedObject = new NestedObject() + { + DynamicProperty = new DynamicTestObject() + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Add("DynamicProperty/OtherProperty/IntProperty", 1); + + // Act + var exception = Assert.Throws(() => + { + patchDocument.ApplyTo(nestedObject); + }); + + // Assert + Assert.Equal("The target location specified by path segment 'OtherProperty' was not found.", exception.Message); + } + + [Fact] + public void CopyProperties_InNestedDynamicObject() + { + // Arrange + dynamic dynamicTestObject = new DynamicTestObject(); + dynamicTestObject.NestedDynamicObject = new DynamicTestObject(); + dynamicTestObject.NestedDynamicObject.StringProperty = "A"; + dynamicTestObject.NestedDynamicObject.AnotherStringProperty = "B"; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Copy("NestedDynamicObject/StringProperty", "NestedDynamicObject/AnotherStringProperty"); + + // Act + patchDocument.ApplyTo(dynamicTestObject); + + // Assert + Assert.Equal("A", dynamicTestObject.NestedDynamicObject.AnotherStringProperty); + } + + + [Fact] + public void MoveToNonExistingProperty_InDynamicObject_ShouldAddNewProperty() + { + // Arrange + dynamic dynamicTestObject = new DynamicTestObject(); + dynamicTestObject.StringProperty = "A"; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Move("StringProperty", "AnotherStringProperty"); + + // Act + patchDocument.ApplyTo(dynamicTestObject); + dynamicTestObject.TryGetValue("StringProperty", out object valueFromDictionary); + + // Assert + Assert.Equal("A", dynamicTestObject.AnotherStringProperty); + Assert.Null(valueFromDictionary); + } + + [Fact] + public void MovePropertyValue_FromDynamicObject_ToTypedObject() + { + // Arrange + dynamic dynamicTestObject = new DynamicTestObject(); + dynamicTestObject.StringProperty = "A"; + dynamicTestObject.SimpleObject = new SimpleObject() { AnotherStringProperty = "B" }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Move("StringProperty", "SimpleObject/AnotherStringProperty"); + + // Act + patchDocument.ApplyTo(dynamicTestObject); + dynamicTestObject.TryGetValue("StringProperty", out object valueFromDictionary); + + // Assert + Assert.Equal("A", dynamicTestObject.SimpleObject.AnotherStringProperty); + Assert.Null(valueFromDictionary); + } + + [Fact] + public void RemoveNestedProperty_FromDynamicObject() + { + // Arrange + dynamic dynamicTestObject = new DynamicTestObject(); + dynamicTestObject.Test = new DynamicTestObject(); + dynamicTestObject.Test.AnotherTest = "A"; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Remove("Test"); + + // Act + patchDocument.ApplyTo(dynamicTestObject); + dynamicTestObject.TryGetValue("Test", out object valueFromDictionary); + + // Assert + Assert.Null(valueFromDictionary); + } + + [Fact] + public void RemoveFromNestedObject_InDynamicObject_MixedCase_ThrowsPathNotFoundException() + { + // Arrange + dynamic dynamicTestObject = new DynamicTestObject(); + dynamicTestObject.SimpleObject = new SimpleObject() + { + StringProperty = "A" + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Remove("Simpleobject/stringProperty"); + + // Act + var exception = Assert.Throws(() => + { + patchDocument.ApplyTo(dynamicTestObject); + }); + + // Assert + Assert.Equal("The target location specified by path segment 'Simpleobject' was not found.", exception.Message); + } + + + [Fact] + public void ReplaceNestedTypedObject_InDynamicObject() + { + // Arrange + dynamic dynamicTestObject = new DynamicTestObject(); + dynamicTestObject.SimpleObject = new SimpleObject() + { + IntegerValue = 5, + IntegerList = new List() { 1, 2, 3 } + }; + + var newObject = new SimpleObject() + { + DoubleValue = 1 + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Replace("SimpleObject", newObject); + + // Act + patchDocument.ApplyTo(dynamicTestObject); + + // Assert + Assert.Equal(1, dynamicTestObject.SimpleObject.DoubleValue); + Assert.Equal(0, dynamicTestObject.SimpleObject.IntegerValue); + Assert.Null(dynamicTestObject.SimpleObject.IntegerList); + } + + [Fact] + public void TestStringPropertyValue_IsSuccessful() + { + // Arrange + dynamic dynamicTestObject = new DynamicTestObject(); + dynamicTestObject.Property = "A"; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Test("Property", "A"); + + // Act & Assert + patchDocument.ApplyTo(dynamicTestObject); + } + + [Fact] + public void TestIntegerPropertyValue_ThrowsJsonPatchException_IfTestFails() + { + // Arrange + dynamic dynamicTestObject = new DynamicTestObject(); + dynamicTestObject.Nested = new SimpleObject() + { + IntegerList = new List() { 1, 2, 3 } + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Test("Nested/IntegerList/0", 2); + + // Act + var exception = Assert.Throws(() => + { + patchDocument.ApplyTo(dynamicTestObject); + }); + + // Assert + Assert.Equal("The current value '1' at position '0' is not equal to the test value '2'.", exception.Message); + } + } +} diff --git a/src/Features/JsonPatch/test/IntegrationTests/ExpandoObjectIntegrationTest.cs b/src/Features/JsonPatch/test/IntegrationTests/ExpandoObjectIntegrationTest.cs new file mode 100644 index 0000000000..29fa5fc731 --- /dev/null +++ b/src/Features/JsonPatch/test/IntegrationTests/ExpandoObjectIntegrationTest.cs @@ -0,0 +1,346 @@ +// 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.Dynamic; +using Microsoft.AspNetCore.JsonPatch.Exceptions; +using Xunit; + +namespace Microsoft.AspNetCore.JsonPatch.IntegrationTests +{ + public class ExpandoObjectIntegrationTest + { + [Fact] + public void AddNewIntProperty() + { + // Arrange + dynamic targetObject = new ExpandoObject(); + targetObject.Test = 1; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Add("NewInt", 1); + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.Equal(1, targetObject.NewInt); + Assert.Equal(1, targetObject.Test); + } + + [Fact] + public void AddNewProperty_ToTypedObject_InExpandoObject() + { + // Arrange + dynamic dynamicProperty = new ExpandoObject(); + dynamicProperty.StringProperty = "A"; + + var targetObject = new NestedObject() + { + DynamicProperty = dynamicProperty + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Add("DynamicProperty/StringProperty", "B"); + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.Equal("B", targetObject.DynamicProperty.StringProperty); + } + + [Fact] + public void AddReplaces_ExistingProperty() + { + // Arrange + dynamic targetObject = new ExpandoObject(); + targetObject.StringProperty = "A"; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Add("StringProperty", "B"); + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.Equal("B", targetObject.StringProperty); + } + + [Fact] + public void AddReplaces_ExistingProperty_InNestedExpandoObject() + { + // Arrange + dynamic targetObject = new ExpandoObject(); + targetObject.InBetweenFirst = new ExpandoObject(); + targetObject.InBetweenFirst.InBetweenSecond = new ExpandoObject(); + targetObject.InBetweenFirst.InBetweenSecond.StringProperty = "A"; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Add("/InBetweenFirst/InBetweenSecond/StringProperty", "B"); + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.Equal("B", targetObject.InBetweenFirst.InBetweenSecond.StringProperty); + } + + [Fact] + public void ShouldNotReplaceProperty_WithDifferentCase() + { + // Arrange + dynamic targetObject = new ExpandoObject(); + targetObject.StringProperty = "A"; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Add("stringproperty", "B"); + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.Equal("A", targetObject.StringProperty); + Assert.Equal("B", targetObject.stringproperty); + } + + [Fact] + public void TestIntegerProperty_IsSucessful() + { + // Arrange + dynamic targetObject = new ExpandoObject(); + targetObject.Test = 1; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Test("Test", 1); + + // Act & Assert + patchDocument.ApplyTo(targetObject); + } + + [Fact] + public void TestStringProperty_ThrowsJsonPatchException_IfTestFails() + { + // Arrange + dynamic targetObject = new ExpandoObject(); + targetObject.Test = "Value"; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Test("Test", "TestValue"); + + // Act + var exception = Assert.Throws(() => + { + patchDocument.ApplyTo(targetObject); + }); + + // Assert + Assert.Equal("The current value 'Value' at path 'Test' is not equal to the test value 'TestValue'.", + exception.Message); + } + + [Fact] + public void CopyStringProperty_ToAnotherStringProperty() + { + // Arrange + dynamic targetObject = new ExpandoObject(); + + targetObject.StringProperty = "A"; + targetObject.AnotherStringProperty = "B"; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Copy("StringProperty", "AnotherStringProperty"); + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.Equal("A", targetObject.AnotherStringProperty); + } + + [Fact] + public void CopyNullStringProperty_ToAnotherStringProperty() + { + // Arrange + dynamic targetObject = new ExpandoObject(); + + targetObject.StringProperty = null; + targetObject.AnotherStringProperty = "B"; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Copy("StringProperty", "AnotherStringProperty"); + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.Null(targetObject.AnotherStringProperty); + } + + [Fact] + public void MoveIntegerValue_ToAnotherIntegerProperty() + { + // Arrange + dynamic targetObject = new ExpandoObject(); + targetObject.IntegerValue = 100; + targetObject.AnotherIntegerValue = 200; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Move("IntegerValue", "AnotherIntegerValue"); + + // Act + patchDocument.ApplyTo(targetObject); + + Assert.Equal(100, targetObject.AnotherIntegerValue); + + var cont = targetObject as IDictionary; + cont.TryGetValue("IntegerValue", out object valueFromDictionary); + + // Assert + Assert.Null(valueFromDictionary); + } + + [Fact] + public void Move_ToNonExistingProperty() + { + // Arrange + dynamic targetObject = new ExpandoObject(); + targetObject.StringProperty = "A"; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Move("StringProperty", "AnotherStringProperty"); + + // Act + patchDocument.ApplyTo(targetObject); + + Assert.Equal("A", targetObject.AnotherStringProperty); + + var cont = targetObject as IDictionary; + cont.TryGetValue("StringProperty", out var valueFromDictionary); + + // Assert + Assert.Null(valueFromDictionary); + } + + [Fact] + public void RemoveProperty_ShouldFail_IfItDoesntExist() + { + // Arrange + dynamic targetObject = new ExpandoObject(); + targetObject.Test = 1; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Remove("NonExisting"); + + // Act + var exception = Assert.Throws(() => + { + patchDocument.ApplyTo(targetObject); + }); + + // Assert + Assert.Equal("The target location specified by path segment 'NonExisting' was not found.", exception.Message); + } + + [Fact] + public void RemoveStringProperty() + { + // Arrange + dynamic targetObject = new ExpandoObject(); + targetObject.Test = 1; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Remove("Test"); + + // Act + patchDocument.ApplyTo(targetObject); + + var cont = targetObject as IDictionary; + cont.TryGetValue("Test", out object valueFromDictionary); + + // Assert + Assert.Null(valueFromDictionary); + } + + [Fact] + public void RemoveProperty_MixedCase_ThrowsPathNotFoundException() + { + // Arrange + dynamic targetObject = new ExpandoObject(); + targetObject.Test = 1; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Remove("test"); + + // Act + var exception = Assert.Throws(() => + { + patchDocument.ApplyTo(targetObject); + }); + + // Assert + Assert.Equal("The target location specified by path segment 'test' was not found.", exception.Message); + } + + [Fact] + public void RemoveNestedProperty() + { + // Arrange + dynamic targetObject = new ExpandoObject(); + targetObject.Test = new ExpandoObject(); + targetObject.Test.AnotherTest = "A"; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Remove("Test"); + + // Act + patchDocument.ApplyTo(targetObject); + + var cont = targetObject as IDictionary; + cont.TryGetValue("Test", out object valueFromDictionary); + + // Assert + Assert.Null(valueFromDictionary); + } + + [Fact] + public void RemoveNestedProperty_MixedCase_ThrowsPathNotFoundException() + { + // Arrange + dynamic targetObject = new ExpandoObject(); + targetObject.Test = new ExpandoObject(); + targetObject.Test.AnotherTest = "A"; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Remove("test"); + + // Act + var exception = Assert.Throws(() => + { + patchDocument.ApplyTo(targetObject); + }); + + // Assert + Assert.Equal("The target location specified by path segment 'test' was not found.", exception.Message); + } + + [Fact] + public void ReplaceGuid() + { + // Arrange + dynamic targetObject = new ExpandoObject(); + targetObject.GuidValue = Guid.NewGuid(); + + var newGuid = Guid.NewGuid(); + var patchDocument = new JsonPatchDocument(); + patchDocument.Replace("GuidValue", newGuid); + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.Equal(newGuid, targetObject.GuidValue); + } + } +} \ No newline at end of file diff --git a/src/Features/JsonPatch/test/IntegrationTests/ListIntegrationTest.cs b/src/Features/JsonPatch/test/IntegrationTests/ListIntegrationTest.cs new file mode 100644 index 0000000000..5e261ea08b --- /dev/null +++ b/src/Features/JsonPatch/test/IntegrationTests/ListIntegrationTest.cs @@ -0,0 +1,366 @@ +// 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.Collections.ObjectModel; +using Microsoft.AspNetCore.JsonPatch.Exceptions; +using Xunit; + +namespace Microsoft.AspNetCore.JsonPatch.IntegrationTests +{ + public class ListIntegrationTest + { + [Fact] + public void TestInList_IsSuccessful() + { + // Arrange + var targetObject = new SimpleObjectWithNestedObject() + { + SimpleObject = new SimpleObject() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Test(o => o.SimpleObject.IntegerList, 3, 2); + + // Act & Assert + patchDocument.ApplyTo(targetObject); + } + + [Fact] + public void TestInList_InvalidPosition() + { + // Arrange + var targetObject = new SimpleObjectWithNestedObject() + { + SimpleObject = new SimpleObject() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Test(o => o.SimpleObject.IntegerList, 4, -1); + + // Act & Assert + var exception = Assert.Throws(() => { patchDocument.ApplyTo(targetObject); }); + Assert.Equal("The index value provided by path segment '-1' is out of bounds of the array size.", + exception.Message); + } + + [Fact] + public void AddToIntegerIList() + { + // Arrange + var targetObject = new SimpleObjectWithNestedObject() + { + SimpleObject = new SimpleObject() + { + IntegerIList = new List() { 1, 2, 3 } + } + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Add(o => (List)o.SimpleObject.IntegerIList, 4, 0); + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.Equal(new List() { 4, 1, 2, 3 }, targetObject.SimpleObject.IntegerIList); + } + + [Fact] + public void AddToComplextTypeList_SpecifyIndex() + { + // Arrange + var targetObject = new SimpleObjectWithNestedObject() + { + SimpleObjectList = new List() + { + new SimpleObject + { + StringProperty = "String1" + }, + new SimpleObject + { + StringProperty = "String2" + } + } + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Add(o => o.SimpleObjectList[0].StringProperty, "ChangedString1"); + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.Equal("ChangedString1", targetObject.SimpleObjectList[0].StringProperty); + } + + [Fact] + public void AddToListAppend() + { + // Arrange + var targetObject = new SimpleObjectWithNestedObject() + { + SimpleObject = new SimpleObject() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Add(o => o.SimpleObject.IntegerList, 4); + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.Equal(new List() { 1, 2, 3, 4 }, targetObject.SimpleObject.IntegerList); + } + + [Fact] + public void RemoveFromList() + { + // Arrange + var targetObject = new SimpleObject() + { + IntegerList = new List() { 1, 2, 3 } + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Remove("IntegerList/2"); + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.Equal(new List() { 1, 2 }, targetObject.IntegerList); + } + + [Theory] + [InlineData("3")] + [InlineData("-1")] + public void RemoveFromList_InvalidPosition(string position) + { + // Arrange + var targetObject = new SimpleObject() + { + IntegerList = new List() { 1, 2, 3 } + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Remove("IntegerList/" + position); + + // Act + var exception = Assert.Throws(() => + { + patchDocument.ApplyTo(targetObject); + }); + + // Assert + Assert.Equal($"The index value provided by path segment '{position}' is out of bounds of the array size.", exception.Message); + } + + [Fact] + public void Remove_FromEndOfList() + { + // Arrange + var targetObject = new SimpleObjectWithNestedObject() + { + SimpleObject = new SimpleObject() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Remove(o => o.SimpleObject.IntegerList); + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.Equal(new List() { 1, 2 }, targetObject.SimpleObject.IntegerList); + } + + [Fact] + public void ReplaceFullList_WithCollection() + { + // Arrange + var targetObject = new SimpleObject() + { + IntegerList = new List() { 1, 2, 3 } + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Replace("IntegerList", new Collection() { 4, 5, 6 }); + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.Equal(new List() { 4, 5, 6 }, targetObject.IntegerList); + } + + [Fact] + public void Replace_AtEndOfList() + { + // Arrange + var targetObject = new SimpleObjectWithNestedObject() + { + SimpleObject = new SimpleObject() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Replace(o => o.SimpleObject.IntegerList, 5); + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.Equal(new List() { 1, 2, 5 }, targetObject.SimpleObject.IntegerList); + } + + [Fact] + public void Replace_InList_InvalidPosition() + { + // Arrange + var targetObject = new SimpleObjectWithNestedObject() + { + SimpleObject = new SimpleObject() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Replace(o => o.SimpleObject.IntegerList, 5, -1); + + // Act + var exception = Assert.Throws(() => { patchDocument.ApplyTo(targetObject); }); + + // Assert + Assert.Equal("The index value provided by path segment '-1' is out of bounds of the array size.", exception.Message); + } + + [Fact] + public void CopyFromListToEndOfList() + { + // Arrange + var targetObject = new SimpleObject() + { + IntegerList = new List() { 1, 2, 3 } + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Copy("IntegerList/0", "IntegerList/-"); + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.Equal(new List() { 1, 2, 3, 1 }, targetObject.IntegerList); + } + + [Fact] + public void CopyFromListToNonList() + { + // Arrange + var targetObject = new SimpleObject() + { + IntegerList = new List() { 1, 2, 3 } + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Copy("IntegerList/0", "IntegerValue"); + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.Equal(1, targetObject.IntegerValue); + } + + [Fact] + public void MoveToEndOfList() + { + // Arrange + var targetObject = new SimpleObject() + { + IntegerValue = 5, + IntegerList = new List() { 1, 2, 3 } + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Move("IntegerValue", "IntegerList/-"); + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.Equal(0, targetObject.IntegerValue); + Assert.Equal(new List() { 1, 2, 3, 5 }, targetObject.IntegerList); + } + + [Fact] + public void Move_KeepsObjectReferenceInList() + { + // Arrange + var simpleObject1 = new SimpleObject() { IntegerValue = 1 }; + var simpleObject2 = new SimpleObject() { IntegerValue = 2 }; + var simpleObject3 = new SimpleObject() { IntegerValue = 3 }; + var targetObject = new SimpleObjectWithNestedObject() + { + SimpleObjectList = new List() { + simpleObject1, + simpleObject2, + simpleObject3 + } + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Move(o => o.SimpleObjectList, 0, o => o.SimpleObjectList, 1); + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.Equal(new List() { simpleObject2, simpleObject1, simpleObject3 }, targetObject.SimpleObjectList); + Assert.Equal(2, targetObject.SimpleObjectList[0].IntegerValue); + Assert.Equal(1, targetObject.SimpleObjectList[1].IntegerValue); + Assert.Same(simpleObject2, targetObject.SimpleObjectList[0]); + Assert.Same(simpleObject1, targetObject.SimpleObjectList[1]); + } + + [Fact] + public void MoveFromList_ToNonList_BetweenHierarchy() + { + // Arrange + var targetObject = new SimpleObjectWithNestedObject() + { + SimpleObject = new SimpleObject() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Move(o => o.SimpleObject.IntegerList, 0, o => o.IntegerValue); + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.Equal(new List() { 2, 3 }, targetObject.SimpleObject.IntegerList); + Assert.Equal(1, targetObject.IntegerValue); + } + } +} diff --git a/src/Features/JsonPatch/test/IntegrationTests/NestedObjectIntegrationTest.cs b/src/Features/JsonPatch/test/IntegrationTests/NestedObjectIntegrationTest.cs new file mode 100644 index 0000000000..2a7d6f7cd2 --- /dev/null +++ b/src/Features/JsonPatch/test/IntegrationTests/NestedObjectIntegrationTest.cs @@ -0,0 +1,365 @@ +// 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.Dynamic; +using Newtonsoft.Json; +using Xunit; + +namespace Microsoft.AspNetCore.JsonPatch.IntegrationTests +{ + public class NestedObjectIntegrationTest + { + [Fact] + public void Replace_DTOWithNullCheck() + { + // Arrange + var targetObject = new SimpleObjectWithNestedObjectWithNullCheck() + { + SimpleObjectWithNullCheck = new SimpleObjectWithNullCheck() + { + StringProperty = "A" + } + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Replace(o => o.SimpleObjectWithNullCheck.StringProperty, "B"); + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.Equal("B", targetObject.SimpleObjectWithNullCheck.StringProperty); + } + + [Fact] + public void ReplaceNestedObject_WithSerialization() + { + // Arrange + var targetObject = new SimpleObjectWithNestedObject() + { + IntegerValue = 1 + }; + + var newNested = new NestedObject() { StringProperty = "B" }; + var patchDocument = new JsonPatchDocument(); + patchDocument.Replace(o => o.NestedObject, newNested); + + var serialized = JsonConvert.SerializeObject(patchDocument); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(targetObject); + + // Assert + Assert.Equal("B", targetObject.NestedObject.StringProperty); + } + + [Fact] + public void TestStringProperty_InNestedObject() + { + // Arrange + var targetObject = new SimpleObjectWithNestedObject() + { + NestedObject = new NestedObject() { StringProperty = "A"} + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Test(o => o.StringProperty, "A"); + + // Act + patchDocument.ApplyTo(targetObject.NestedObject); + + // Assert + Assert.Equal("A", targetObject.NestedObject.StringProperty); + } + + [Fact] + public void TestNestedObject() + { + // Arrange + var targetObject = new SimpleObjectWithNestedObject() + { + NestedObject = new NestedObject() { StringProperty = "B"} + }; + + var testNested = new NestedObject() { StringProperty = "B" }; + var patchDocument = new JsonPatchDocument(); + patchDocument.Test(o => o.NestedObject, testNested); + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.Equal("B", targetObject.NestedObject.StringProperty); + } + + [Fact] + public void AddReplaces_ExistingStringProperty() + { + // Arrange + var targetObject = new SimpleObjectWithNestedObject() + { + SimpleObject = new SimpleObject() + { + StringProperty = "A" + } + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Add(o => o.SimpleObject.StringProperty, "B"); + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.Equal("B", targetObject.SimpleObject.StringProperty); + } + + [Fact] + public void AddNewProperty_ToExpandoOject_InTypedObject() + { + var targetObject = new NestedObject() + { + DynamicProperty = new ExpandoObject() + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Add("DynamicProperty/NewInt", 1); + + patchDocument.ApplyTo(targetObject); + + Assert.Equal(1, targetObject.DynamicProperty.NewInt); + } + + [Fact] + public void RemoveStringProperty() + { + // Arrange + var targetObject = new SimpleObjectWithNestedObject() + { + SimpleObject = new SimpleObject() + { + StringProperty = "A" + } + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Remove(o => o.SimpleObject.StringProperty); + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.Null(targetObject.SimpleObject.StringProperty); + } + + [Fact] + public void CopyStringProperty_ToAnotherStringProperty() + { + // Arrange + var targetObject = new SimpleObjectWithNestedObject() + { + SimpleObject = new SimpleObject() + { + StringProperty = "A", + AnotherStringProperty = "B" + } + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Copy(o => o.SimpleObject.StringProperty, o => o.SimpleObject.AnotherStringProperty); + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.Equal("A", targetObject.SimpleObject.AnotherStringProperty); + } + + [Fact] + public void CopyNullStringProperty_ToAnotherStringProperty() + { + // Arrange + var targetObject = new SimpleObjectWithNestedObject() + { + SimpleObject = new SimpleObject() + { + StringProperty = null, + AnotherStringProperty = "B" + } + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Copy(o => o.SimpleObject.StringProperty, o => o.SimpleObject.AnotherStringProperty); + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.Null(targetObject.SimpleObject.AnotherStringProperty); + } + + [Fact] + public void Copy_DeepClonesObject() + { + // Arrange + var targetObject = new SimpleObjectWithNestedObject() + { + SimpleObject = new SimpleObject() + { + StringProperty = "A", + AnotherStringProperty = "B" + }, + InheritedObject = new InheritedObject() + { + StringProperty = "C", + AnotherStringProperty = "D" + } + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Copy(o => o.InheritedObject, o => o.SimpleObject); + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.Equal("C", targetObject.SimpleObject.StringProperty); + Assert.Equal("D", targetObject.SimpleObject.AnotherStringProperty); + Assert.Equal("C", targetObject.InheritedObject.StringProperty); + Assert.Equal("D", targetObject.InheritedObject.AnotherStringProperty); + Assert.NotSame(targetObject.SimpleObject.StringProperty, targetObject.InheritedObject.StringProperty); + } + + [Fact] + public void Copy_KeepsObjectType() + { + // Arrange + var targetObject = new SimpleObjectWithNestedObject() + { + SimpleObject = new SimpleObject(), + InheritedObject = new InheritedObject() + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Copy(o => o.InheritedObject, o => o.SimpleObject); + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.Equal(typeof(InheritedObject), targetObject.SimpleObject.GetType()); + } + + [Fact] + public void Copy_BreaksObjectReference() + { + // Arrange + var targetObject = new SimpleObjectWithNestedObject() + { + SimpleObject = new SimpleObject(), + InheritedObject = new InheritedObject() + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Copy(o => o.InheritedObject, o => o.SimpleObject); + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.NotSame(targetObject.SimpleObject, targetObject.InheritedObject); + } + + [Fact] + public void MoveIntegerValue_ToAnotherIntegerProperty() + { + // Arrange + var targetObject = new SimpleObjectWithNestedObject() + { + SimpleObject = new SimpleObject() + { + IntegerValue = 2, + AnotherIntegerValue = 3 + } + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Move(o => o.SimpleObject.IntegerValue, o => o.SimpleObject.AnotherIntegerValue); + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.Equal(2, targetObject.SimpleObject.AnotherIntegerValue); + Assert.Equal(0, targetObject.SimpleObject.IntegerValue); + } + + [Fact] + public void Move_KeepsObjectReference() + { + // Arrange + var sDto = new SimpleObject() + { + StringProperty = "A", + AnotherStringProperty = "B" + }; + var iDto = new InheritedObject() + { + StringProperty = "C", + AnotherStringProperty = "D" + }; + var targetObject = new SimpleObjectWithNestedObject() + { + SimpleObject = sDto, + InheritedObject = iDto + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Move(o => o.InheritedObject, o => o.SimpleObject); + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.Equal("C", targetObject.SimpleObject.StringProperty); + Assert.Equal("D", targetObject.SimpleObject.AnotherStringProperty); + Assert.Same(iDto, targetObject.SimpleObject); + Assert.Null(targetObject.InheritedObject); + } + + private class SimpleObjectWithNullCheck + { + private string stringProperty; + + public string StringProperty + { + get + { + return stringProperty; + } + + set + { + if (value == null) + { + throw new ArgumentNullException(); + } + + stringProperty = value; + } + } + } + + private class SimpleObjectWithNestedObjectWithNullCheck + { + public SimpleObjectWithNullCheck SimpleObjectWithNullCheck { get; set; } + + public SimpleObjectWithNestedObjectWithNullCheck() + { + SimpleObjectWithNullCheck = new SimpleObjectWithNullCheck(); + } + } + } +} diff --git a/src/Features/JsonPatch/test/IntegrationTests/SimpleObjectIntegrationTest.cs b/src/Features/JsonPatch/test/IntegrationTests/SimpleObjectIntegrationTest.cs new file mode 100644 index 0000000000..731e181697 --- /dev/null +++ b/src/Features/JsonPatch/test/IntegrationTests/SimpleObjectIntegrationTest.cs @@ -0,0 +1,175 @@ +// 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.Dynamic; +using Microsoft.AspNetCore.JsonPatch.Exceptions; +using Xunit; + +namespace Microsoft.AspNetCore.JsonPatch.IntegrationTests +{ + public class SimpleObjectIntegrationTest + { + [Fact] + public void TestDoubleValueProperty() + { + // Arrange + var targetObject = new SimpleObject() + { + DoubleValue = 9.8 + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Test("DoubleValue", 9.8); + + // Act & Assert + patchDocument.ApplyTo(targetObject); + } + + [Fact] + public void CopyStringProperty_ToAnotherStringProperty() + { + // Arrange + var targetObject = new SimpleObject() + { + StringProperty = "A", + AnotherStringProperty = "B" + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Copy("StringProperty", "AnotherStringProperty"); + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.Equal("A", targetObject.AnotherStringProperty); + } + + [Fact] + public void CopyNullStringProperty_ToAnotherStringProperty() + { + // Arrange + var targetObject = new SimpleObject() + { + StringProperty = null, + AnotherStringProperty = "B" + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Copy("StringProperty", "AnotherStringProperty"); + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.Null(targetObject.AnotherStringProperty); + } + + [Fact] + public void MoveIntegerProperty_ToAnotherIntegerProperty() + { + // Arrange + var targetObject = new SimpleObject() + { + IntegerValue = 2, + AnotherIntegerValue = 3 + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Move("IntegerValue", "AnotherIntegerValue"); + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.Equal(2, targetObject.AnotherIntegerValue); + Assert.Equal(0, targetObject.IntegerValue); + } + + [Fact] + public void RemoveDecimalPropertyValue() + { + // Arrange + var targetObject = new SimpleObject() + { + DecimalValue = 9.8M + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Remove("DecimalValue"); + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.Equal(0, targetObject.DecimalValue); + } + + [Fact] + public void ReplaceGuid() + { + // Arrange + var targetObject = new SimpleObject() + { + GuidValue = Guid.NewGuid() + }; + + var newGuid = Guid.NewGuid(); + var patchDocument = new JsonPatchDocument(); + patchDocument.Replace("GuidValue", newGuid); + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.Equal(newGuid, targetObject.GuidValue); + } + + [Fact] + public void AddReplacesGuid() + { + // Arrange + var targetObject = new SimpleObject() + { + GuidValue = Guid.NewGuid() + }; + + var newGuid = Guid.NewGuid(); + var patchDocument = new JsonPatchDocument(); + patchDocument.Add("GuidValue", newGuid); + + // Act + patchDocument.ApplyTo(targetObject); + + // Assert + Assert.Equal(newGuid, targetObject.GuidValue); + } + + // https://github.com/aspnet/AspNetCore/issues/3634 + [Fact] + public void Regression_AspNetCore3634() + { + // Assert + var document = new JsonPatchDocument(); + document.Move("/Object", "/Object/goodbye"); + + dynamic @object = new ExpandoObject(); + @object.hello = "world"; + + var target = new Regression_AspNetCore3634_Object(); + target.Object = @object; + + // Act + var ex = Assert.Throws(() => document.ApplyTo(target)); + + // Assert + Assert.Equal("For operation 'move', the target location specified by path '/Object/goodbye' was not found.", ex.Message); + } + + private class Regression_AspNetCore3634_Object + { + public dynamic Object { get; set; } + } + } +} diff --git a/src/Features/JsonPatch/test/Internal/DictionaryAdapterTest.cs b/src/Features/JsonPatch/test/Internal/DictionaryAdapterTest.cs new file mode 100644 index 0000000000..a0dcd82ab0 --- /dev/null +++ b/src/Features/JsonPatch/test/Internal/DictionaryAdapterTest.cs @@ -0,0 +1,311 @@ +// 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 Newtonsoft.Json.Serialization; +using Xunit; + +namespace Microsoft.AspNetCore.JsonPatch.Internal +{ + public class DictionaryAdapterTest + { + [Fact] + public void Add_KeyWhichAlreadyExists_ReplacesExistingValue() + { + // Arrange + var key = "Status"; + var dictionary = new Dictionary(StringComparer.Ordinal); + dictionary[key] = 404; + var dictionaryAdapter = new DictionaryAdapter(); + var resolver = new DefaultContractResolver(); + + // Act + var addStatus = dictionaryAdapter.TryAdd(dictionary, key, resolver, 200, out var message); + + // Assert + Assert.True(addStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.Single(dictionary); + Assert.Equal(200, dictionary[key]); + } + + [Fact] + public void Add_IntKeyWhichAlreadyExists_ReplacesExistingValue() + { + // Arrange + var intKey = 1; + var dictionary = new Dictionary(); + dictionary[intKey] = "Mike"; + var dictionaryAdapter = new DictionaryAdapter(); + var resolver = new DefaultContractResolver(); + + // Act + var addStatus = dictionaryAdapter.TryAdd(dictionary, intKey.ToString(), resolver, "James", out var message); + + // Assert + Assert.True(addStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.Single(dictionary); + Assert.Equal("James", dictionary[intKey]); + } + + [Fact] + public void GetInvalidKey_ThrowsInvalidPathSegmentException() + { + // Arrange + var dictionaryAdapter = new DictionaryAdapter(); + var resolver = new DefaultContractResolver(); + var key = 1; + var dictionary = new Dictionary(); + + // Act + var addStatus = dictionaryAdapter.TryAdd(dictionary, key.ToString(), resolver, "James", out var message); + + // Assert + Assert.True(addStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.Single(dictionary); + Assert.Equal("James", dictionary[key]); + + // Act + var guidKey = new Guid(); + var getStatus = dictionaryAdapter.TryGet(dictionary, guidKey.ToString(), resolver, out var outValue, out message); + + // Assert + Assert.False(getStatus); + Assert.Equal($"The provided path segment '{guidKey.ToString()}' cannot be converted to the target type.", message); + Assert.Null(outValue); + } + + [Fact] + public void Get_UsingCaseSensitiveKey_FailureScenario() + { + // Arrange + var dictionaryAdapter = new DictionaryAdapter(); + var resolver = new DefaultContractResolver(); + var nameKey = "Name"; + var dictionary = new Dictionary(StringComparer.Ordinal); + + // Act + var addStatus = dictionaryAdapter.TryAdd(dictionary, nameKey, resolver, "James", out var message); + + // Assert + Assert.True(addStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.Single(dictionary); + Assert.Equal("James", dictionary[nameKey]); + + // Act + var getStatus = dictionaryAdapter.TryGet(dictionary, nameKey.ToUpper(), resolver, out var outValue, out message); + + // Assert + Assert.False(getStatus); + Assert.Equal("The target location specified by path segment 'NAME' was not found.", message); + Assert.Null(outValue); + } + + [Fact] + public void Get_UsingCaseSensitiveKey_SuccessScenario() + { + // Arrange + var dictionaryAdapter = new DictionaryAdapter(); + var resolver = new DefaultContractResolver(); + var nameKey = "Name"; + var dictionary = new Dictionary(StringComparer.Ordinal); + + // Act + var addStatus = dictionaryAdapter.TryAdd(dictionary, nameKey, resolver, "James", out var message); + + // Assert + Assert.True(addStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.Single(dictionary); + Assert.Equal("James", dictionary[nameKey]); + + // Act + addStatus = dictionaryAdapter.TryGet(dictionary, nameKey, resolver, out var outValue, out message); + + // Assert + Assert.True(addStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.Equal("James", outValue?.ToString()); + } + + [Fact] + public void ReplacingExistingItem() + { + // Arrange + var nameKey = "Name"; + var dictionary = new Dictionary(StringComparer.Ordinal); + dictionary.Add(nameKey, "Mike"); + var dictionaryAdapter = new DictionaryAdapter(); + var resolver = new DefaultContractResolver(); + + // Act + var replaceStatus = dictionaryAdapter.TryReplace(dictionary, nameKey, resolver, "James", out var message); + + // Assert + Assert.True(replaceStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.Single(dictionary); + Assert.Equal("James", dictionary[nameKey]); + } + + [Fact] + public void ReplacingExistingItem_WithGuidKey() + { + // Arrange + var guidKey = new Guid(); + var dictionary = new Dictionary(); + dictionary.Add(guidKey, "Mike"); + var dictionaryAdapter = new DictionaryAdapter(); + var resolver = new DefaultContractResolver(); + + // Act + var replaceStatus = dictionaryAdapter.TryReplace(dictionary, guidKey.ToString(), resolver, "James", out var message); + + // Assert + Assert.True(replaceStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.Single(dictionary); + Assert.Equal("James", dictionary[guidKey]); + } + + [Fact] + public void ReplacingWithInvalidValue_ThrowsInvalidValueForPropertyException() + { + // Arrange + var guidKey = new Guid(); + var dictionary = new Dictionary(); + dictionary.Add(guidKey, 5); + var dictionaryAdapter = new DictionaryAdapter(); + var resolver = new DefaultContractResolver(); + + // Act + var replaceStatus = dictionaryAdapter.TryReplace(dictionary, guidKey.ToString(), resolver, "test", out var message); + + // Assert + Assert.False(replaceStatus); + Assert.Equal("The value 'test' is invalid for target location.", message); + Assert.Equal(5, dictionary[guidKey]); + } + + [Fact] + public void Replace_NonExistingKey_Fails() + { + // Arrange + var nameKey = "Name"; + var dictionary = new Dictionary(StringComparer.Ordinal); + var dictionaryAdapter = new DictionaryAdapter(); + var resolver = new DefaultContractResolver(); + + // Act + var replaceStatus = dictionaryAdapter.TryReplace(dictionary, nameKey, resolver, "Mike", out var message); + + // Assert + Assert.False(replaceStatus); + Assert.Equal("The target location specified by path segment 'Name' was not found.", message); + Assert.Empty(dictionary); + } + + [Fact] + public void Remove_NonExistingKey_Fails() + { + // Arrange + var nameKey = "Name"; + var dictionary = new Dictionary(StringComparer.Ordinal); + var dictionaryAdapter = new DictionaryAdapter(); + var resolver = new DefaultContractResolver(); + + // Act + var removeStatus = dictionaryAdapter.TryRemove(dictionary, nameKey, resolver, out var message); + + // Assert + Assert.False(removeStatus); + Assert.Equal("The target location specified by path segment 'Name' was not found.", message); + Assert.Empty(dictionary); + } + + [Fact] + public void Remove_RemovesFromDictionary() + { + // Arrange + var nameKey = "Name"; + var dictionary = new Dictionary(StringComparer.Ordinal); + dictionary[nameKey] = "James"; + var dictionaryAdapter = new DictionaryAdapter(); + var resolver = new DefaultContractResolver(); + + // Act + var removeStatus = dictionaryAdapter.TryRemove(dictionary, nameKey, resolver, out var message); + + //Assert + Assert.True(removeStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.Empty(dictionary); + } + + [Fact] + public void Remove_RemovesFromDictionary_WithUriKey() + { + // Arrange + var uriKey = new Uri("http://www.test.com/name"); + var dictionary = new Dictionary(); + dictionary[uriKey] = "James"; + var dictionaryAdapter = new DictionaryAdapter(); + var resolver = new DefaultContractResolver(); + + // Act + var removeStatus = dictionaryAdapter.TryRemove(dictionary, uriKey.ToString(), resolver, out var message); + + //Assert + Assert.True(removeStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.Empty(dictionary); + } + + [Fact] + public void Test_DoesNotThrowException_IfTestIsSuccessful() + { + // Arrange + var key = "Name"; + var dictionary = new Dictionary>(); + var value = new List() + { + "James", + 2, + new Customer("James", 25) + }; + dictionary[key] = value; + var dictionaryAdapter = new DictionaryAdapter>(); + var resolver = new DefaultContractResolver(); + + // Act + var testStatus = dictionaryAdapter.TryTest(dictionary, key, resolver, value, out var message); + + //Assert + Assert.True(testStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + } + + [Fact] + public void Test_ThrowsJsonPatchException_IfTestFails() + { + // Arrange + var key = "Name"; + var dictionary = new Dictionary(); + dictionary[key] = "James"; + var dictionaryAdapter = new DictionaryAdapter(); + var resolver = new DefaultContractResolver(); + var expectedErrorMessage = "The current value 'James' at path 'Name' is not equal to the test value 'John'."; + + // Act + var testStatus = dictionaryAdapter.TryTest(dictionary, key, resolver, "John", out var errorMessage); + + //Assert + Assert.False(testStatus); + Assert.Equal(expectedErrorMessage, errorMessage); + } + } +} diff --git a/src/Features/JsonPatch/test/Internal/DynamicObjectAdapterTest.cs b/src/Features/JsonPatch/test/Internal/DynamicObjectAdapterTest.cs new file mode 100644 index 0000000000..9d5eb2595c --- /dev/null +++ b/src/Features/JsonPatch/test/Internal/DynamicObjectAdapterTest.cs @@ -0,0 +1,274 @@ +// 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 Newtonsoft.Json.Serialization; +using Xunit; + +namespace Microsoft.AspNetCore.JsonPatch.Internal +{ + public class DynamicObjectAdapterTest + { + [Fact] + public void TryAdd_AddsNewProperty() + { + // Arrange + var adapter = new DynamicObjectAdapter(); + dynamic target = new DynamicTestObject(); + var segment = "NewProperty"; + var resolver = new DefaultContractResolver(); + + // Act + var status = adapter.TryAdd(target, segment, resolver, "new", out string errorMessage); + + // Assert + Assert.True(status); + Assert.Null(errorMessage); + Assert.Equal("new", target.NewProperty); + } + + [Fact] + public void TryAdd_ReplacesExistingPropertyValue() + { + // Arrange + var adapter = new DynamicObjectAdapter(); + dynamic target = new DynamicTestObject(); + target.List = new List() { 1, 2, 3 }; + var value = new List() { "stringValue1", "stringValue2" }; + var segment = "List"; + var resolver = new DefaultContractResolver(); + + // Act + var status = adapter.TryAdd(target, segment, resolver, value, out string errorMessage); + + // Assert + Assert.True(status); + Assert.Null(errorMessage); + Assert.Equal(value, target.List); + } + + [Fact] + public void TryGet_GetsPropertyValue_ForExistingProperty() + { + // Arrange + var adapter = new DynamicObjectAdapter(); + dynamic target = new DynamicTestObject(); + var segment = "NewProperty"; + var resolver = new DefaultContractResolver(); + + // Act 1 + var addStatus = adapter.TryAdd(target, segment, resolver, "new", out string errorMessage); + + // Assert 1 + Assert.True(addStatus); + Assert.Null(errorMessage); + Assert.Equal("new", target.NewProperty); + + // Act 2 + var getStatus = adapter.TryGet(target, segment, resolver, out object getValue, out string getErrorMessage); + + // Assert 2 + Assert.True(getStatus); + Assert.Null(getErrorMessage); + Assert.Equal(getValue, target.NewProperty); + } + + [Fact] + public void TryGet_ThrowsPathNotFoundException_ForNonExistingProperty() + { + // Arrange + var adapter = new DynamicObjectAdapter(); + dynamic target = new DynamicTestObject(); + var segment = "NewProperty"; + var resolver = new DefaultContractResolver(); + + // Act + var getStatus = adapter.TryGet(target, segment, resolver, out object getValue, out string getErrorMessage); + + // Assert + Assert.False(getStatus); + Assert.Null(getValue); + Assert.Equal($"The target location specified by path segment '{segment}' was not found.", getErrorMessage); + } + + [Fact] + public void TryTraverse_FindsNextTarget() + { + // Arrange + var adapter = new DynamicObjectAdapter(); + dynamic target = new DynamicTestObject(); + target.NestedObject = new DynamicTestObject(); + target.NestedObject.NewProperty = "A"; + var segment = "NestedObject"; + var resolver = new DefaultContractResolver(); + + // Act + var status = adapter.TryTraverse(target, segment, resolver, out object nextTarget, out string errorMessage); + + // Assert + Assert.True(status); + Assert.Null(errorMessage); + Assert.Equal(target.NestedObject, nextTarget); + } + + [Fact] + public void TryTraverse_ThrowsPathNotFoundException_ForNonExistingProperty() + { + // Arrange + var adapter = new DynamicObjectAdapter(); + dynamic target = new DynamicTestObject(); + target.NestedObject = new DynamicTestObject(); + var segment = "NewProperty"; + var resolver = new DefaultContractResolver(); + + // Act + var status = adapter.TryTraverse(target.NestedObject, segment, resolver, out object nextTarget, out string errorMessage); + + // Assert + Assert.False(status); + Assert.Equal($"The target location specified by path segment '{segment}' was not found.", errorMessage); + } + + [Fact] + public void TryReplace_RemovesExistingValue_BeforeAddingNewValue() + { + // Arrange + var adapter = new DynamicObjectAdapter(); + dynamic target = new WriteOnceDynamicTestObject(); + target.NewProperty = new object(); + var segment = "NewProperty"; + var resolver = new DefaultContractResolver(); + + // Act + var status = adapter.TryReplace(target, segment, resolver, "new", out string errorMessage); + + // Assert + Assert.True(status); + Assert.Null(errorMessage); + Assert.Equal("new", target.NewProperty); + } + + [Fact] + public void TryReplace_ThrowsPathNotFoundException_ForNonExistingProperty() + { + // Arrange + var adapter = new DynamicObjectAdapter(); + dynamic target = new DynamicTestObject(); + var segment = "NewProperty"; + var resolver = new DefaultContractResolver(); + + // Act + var status = adapter.TryReplace(target, segment, resolver, "test", out string errorMessage); + + // Assert + Assert.False(status); + Assert.Equal($"The target location specified by path segment '{segment}' was not found.", errorMessage); + } + + [Fact] + public void TryReplace_ThrowsPropertyInvalidException_IfNewValueIsNotTheSameTypeAsInitialValue() + { + // Arrange + var adapter = new DynamicObjectAdapter(); + dynamic target = new DynamicTestObject(); + target.NewProperty = 1; + var segment = "NewProperty"; + var resolver = new DefaultContractResolver(); + + // Act + var status = adapter.TryReplace(target, segment, resolver, "test", out string errorMessage); + + // Assert + Assert.False(status); + Assert.Equal($"The value 'test' is invalid for target location.", errorMessage); + } + + [Theory] + [InlineData(1, 0)] + [InlineData("new", null)] + public void TryRemove_SetsPropertyToDefaultOrNull(object value, object expectedValue) + { + // Arrange + var adapter = new DynamicObjectAdapter(); + dynamic target = new DynamicTestObject(); + var segment = "NewProperty"; + var resolver = new DefaultContractResolver(); + + // Act 1 + var addStatus = adapter.TryAdd(target, segment, resolver, value, out string errorMessage); + + // Assert 1 + Assert.True(addStatus); + Assert.Null(errorMessage); + Assert.Equal(value, target.NewProperty); + + // Act 2 + var removeStatus = adapter.TryRemove(target, segment, resolver, out string removeErrorMessage); + + // Assert 2 + Assert.True(removeStatus); + Assert.Null(removeErrorMessage); + Assert.Equal(expectedValue, target.NewProperty); + } + + [Fact] + public void TryRemove_ThrowsPathNotFoundException_ForNonExistingProperty() + { + // Arrange + var adapter = new DynamicObjectAdapter(); + dynamic target = new DynamicTestObject(); + var segment = "NewProperty"; + var resolver = new DefaultContractResolver(); + + // Act + var removeStatus = adapter.TryRemove(target, segment, resolver, out string removeErrorMessage); + + // Assert + Assert.False(removeStatus); + Assert.Equal($"The target location specified by path segment '{segment}' was not found.", removeErrorMessage); + } + + [Fact] + public void TryTest_DoesNotThrowException_IfTestSuccessful() + { + var adapter = new DynamicObjectAdapter(); + dynamic target = new DynamicTestObject(); + var value = new List() + { + "Joana", + 2, + new Customer("Joana", 25) + }; + target.NewProperty = value; + var segment = "NewProperty"; + var resolver = new DefaultContractResolver(); + + // Act + var testStatus = adapter.TryTest(target, segment, resolver, value, out string errorMessage); + + // Assert + Assert.Equal(value, target.NewProperty); + Assert.True(testStatus); + Assert.True(string.IsNullOrEmpty(errorMessage), "Expected no error message"); + } + + [Fact] + public void TryTest_ThrowsJsonPatchException_IfTestFails() + { + // Arrange + var adapter = new DynamicObjectAdapter(); + dynamic target = new DynamicTestObject(); + target.NewProperty = "Joana"; + var segment = "NewProperty"; + var resolver = new DefaultContractResolver(); + var expectedErrorMessage = $"The current value 'Joana' at path '{segment}' is not equal to the test value 'John'."; + + // Act + var testStatus = adapter.TryTest(target, segment, resolver, "John", out string errorMessage); + + // Assert + Assert.False(testStatus); + Assert.Equal(expectedErrorMessage, errorMessage); + } + } +} diff --git a/src/Features/JsonPatch/test/Internal/ListAdapterTest.cs b/src/Features/JsonPatch/test/Internal/ListAdapterTest.cs new file mode 100644 index 0000000000..f31e57541b --- /dev/null +++ b/src/Features/JsonPatch/test/Internal/ListAdapterTest.cs @@ -0,0 +1,497 @@ +// 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; +using System.Collections.Generic; +using Moq; +using Newtonsoft.Json.Serialization; +using Xunit; + +namespace Microsoft.AspNetCore.JsonPatch.Internal +{ + public class ListAdapterTest + { + [Fact] + public void Patch_OnArrayObject_Fails() + { + // Arrange + var resolver = new Mock(MockBehavior.Strict); + var targetObject = new[] { 20, 30 }; + var listAdapter = new ListAdapter(); + + // Act + var addStatus = listAdapter.TryAdd(targetObject, "0", resolver.Object, "40", out var message); + + // Assert + Assert.False(addStatus); + Assert.Equal($"The type '{targetObject.GetType().FullName}' which is an array is not supported for json patch operations as it has a fixed size.", message); + } + + [Fact] + public void Patch_OnNonGenericListObject_Fails() + { + // Arrange + var resolver = new Mock(MockBehavior.Strict); + var targetObject = new ArrayList(); + targetObject.Add(20); + targetObject.Add(30); + var listAdapter = new ListAdapter(); + + // Act + var addStatus = listAdapter.TryAdd(targetObject, "-", resolver.Object, "40", out var message); + + // Assert + Assert.False(addStatus); + Assert.Equal($"The type '{targetObject.GetType().FullName}' which is a non generic list is not supported for json patch operations. Only generic list types are supported.", message); + } + + [Fact] + public void Add_WithIndexSameAsNumberOfElements_Works() + { + // Arrange + var resolver = new Mock(MockBehavior.Strict); + var targetObject = new List() { "James", "Mike" }; + var listAdapter = new ListAdapter(); + var position = targetObject.Count.ToString(); + + // Act + var addStatus = listAdapter.TryAdd(targetObject, position, resolver.Object, "Rob", out var message); + + // Assert + Assert.Null(message); + Assert.True(addStatus); + Assert.Equal(3, targetObject.Count); + Assert.Equal(new List() { "James", "Mike", "Rob" }, targetObject); + } + + [Theory] + [InlineData("-1")] + [InlineData("-2")] + [InlineData("3")] + public void Add_WithOutOfBoundsIndex_Fails(string position) + { + // Arrange + var resolver = new Mock(MockBehavior.Strict); + var targetObject = new List() { "James", "Mike" }; + var listAdapter = new ListAdapter(); + + // Act + var addStatus = listAdapter.TryAdd(targetObject, position, resolver.Object, "40", out var message); + + // Assert + Assert.False(addStatus); + Assert.Equal($"The index value provided by path segment '{position}' is out of bounds of the array size.", message); + } + + [Theory] + [InlineData("_")] + [InlineData("blah")] + public void Patch_WithInvalidPositionFormat_Fails(string position) + { + // Arrange + var resolver = new Mock(MockBehavior.Strict); + var targetObject = new List() { "James", "Mike" }; + var listAdapter = new ListAdapter(); + + // Act + var addStatus = listAdapter.TryAdd(targetObject, position, resolver.Object, "40", out var message); + + // Assert + Assert.False(addStatus); + Assert.Equal($"The path segment '{position}' is invalid for an array index.", message); + } + + public static TheoryData, List> AppendAtEndOfListData + { + get + { + return new TheoryData, List>() + { + { + new List() { }, + new List() { 20 } + }, + { + new List() { 5, 10 }, + new List() { 5, 10, 20 } + } + }; + } + } + + [Theory] + [MemberData(nameof(AppendAtEndOfListData))] + public void Add_Appends_AtTheEnd(List targetObject, List expected) + { + // Arrange + var resolver = new Mock(MockBehavior.Strict); + var listAdapter = new ListAdapter(); + + // Act + var addStatus = listAdapter.TryAdd(targetObject, "-", resolver.Object, "20", out var message); + + // Assert + Assert.True(addStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.Equal(expected.Count, targetObject.Count); + Assert.Equal(expected, targetObject); + } + + [Fact] + public void Add_NullObject_ToReferenceTypeListWorks() + { + // Arrange + var resolver = new Mock(MockBehavior.Strict); + var listAdapter = new ListAdapter(); + var targetObject = new List() { "James", "Mike" }; + + // Act + var addStatus = listAdapter.TryAdd(targetObject, "-", resolver.Object, value: null, errorMessage: out var message); + + // Assert + Assert.True(addStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.Equal(3, targetObject.Count); + Assert.Equal(new List() { "James", "Mike", null }, targetObject); + } + + [Fact] + public void Add_CompatibleTypeWorks() + { + // Arrange + var sDto = new SimpleObject(); + var iDto = new InheritedObject(); + var resolver = new Mock(MockBehavior.Strict); + var targetObject = new List() { sDto }; + var listAdapter = new ListAdapter(); + + // Act + var addStatus = listAdapter.TryAdd(targetObject, "-", resolver.Object, iDto, out var message); + + // Assert + Assert.True(addStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.Equal(2, targetObject.Count); + Assert.Equal(new List() { sDto, iDto }, targetObject); + } + + [Fact] + public void Add_NonCompatibleType_Fails() + { + // Arrange + var resolver = new Mock(MockBehavior.Strict); + var targetObject = new List() { 10, 20 }; + var listAdapter = new ListAdapter(); + + // Act + var addStatus = listAdapter.TryAdd(targetObject, "-", resolver.Object, "James", out var message); + + // Assert + Assert.False(addStatus); + Assert.Equal("The value 'James' is invalid for target location.", message); + } + + public static TheoryData AddingDifferentComplexTypeWorksData + { + get + { + return new TheoryData() + { + { + new List() { }, + "a", + "-", + new List() { "a" } + }, + { + new List() { "a", "b" }, + "c", + "-", + new List() { "a", "b", "c" } + }, + { + new List() { "a", "b" }, + "c", + "0", + new List() { "c", "a", "b" } + }, + { + new List() { "a", "b" }, + "c", + "1", + new List() { "a", "c", "b" } + } + }; + } + } + + [Theory] + [MemberData(nameof(AddingDifferentComplexTypeWorksData))] + public void Add_DifferentComplexTypeWorks(IList targetObject, object value, string position, IList expected) + { + // Arrange + var resolver = new Mock(MockBehavior.Strict); + var listAdapter = new ListAdapter(); + + // Act + var addStatus = listAdapter.TryAdd(targetObject, position, resolver.Object, value, out var message); + + // Assert + Assert.True(addStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.Equal(expected.Count, targetObject.Count); + Assert.Equal(expected, targetObject); + } + + public static TheoryData AddingKeepsObjectReferenceData + { + get + { + var sDto1 = new SimpleObject(); + var sDto2 = new SimpleObject(); + var sDto3 = new SimpleObject(); + return new TheoryData() + { + { + new List() { }, + sDto1, + "-", + new List() { sDto1 } + }, + { + new List() { sDto1, sDto2 }, + sDto3, + "-", + new List() { sDto1, sDto2, sDto3 } + }, + { + new List() { sDto1, sDto2 }, + sDto3, + "0", + new List() { sDto3, sDto1, sDto2 } + }, + { + new List() { sDto1, sDto2 }, + sDto3, + "1", + new List() { sDto1, sDto3, sDto2 } + } + }; + } + } + + [Theory] + [MemberData(nameof(AddingKeepsObjectReferenceData))] + public void Add_KeepsObjectReference(IList targetObject, object value, string position, IList expected) + { + // Arrange + var resolver = new Mock(MockBehavior.Strict); + var listAdapter = new ListAdapter(); + + // Act + var addStatus = listAdapter.TryAdd(targetObject, position, resolver.Object, value, out var message); + + // Assert + Assert.True(addStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.Equal(expected.Count, targetObject.Count); + Assert.Equal(expected, targetObject); + } + + [Theory] + [InlineData(new int[] { }, "0")] + [InlineData(new[] { 10, 20 }, "-1")] + [InlineData(new[] { 10, 20 }, "2")] + public void Get_IndexOutOfBounds(int[] input, string position) + { + // Arrange + var resolver = new Mock(MockBehavior.Strict); + var targetObject = new List(input); + var listAdapter = new ListAdapter(); + + // Act + var getStatus = listAdapter.TryGet(targetObject, position, resolver.Object, out var value, out var message); + + // Assert + Assert.False(getStatus); + Assert.Equal($"The index value provided by path segment '{position}' is out of bounds of the array size.", message); + } + + [Theory] + [InlineData(new[] { 10, 20 }, "0", 10)] + [InlineData(new[] { 10, 20 }, "1", 20)] + [InlineData(new[] { 10 }, "0", 10)] + public void Get(int[] input, string position, object expected) + { + // Arrange + var resolver = new Mock(MockBehavior.Strict); + var targetObject = new List(input); + var listAdapter = new ListAdapter(); + + // Act + var getStatus = listAdapter.TryGet(targetObject, position, resolver.Object, out var value, out var message); + + // Assert + Assert.True(getStatus); + Assert.Equal(expected, value); + Assert.Equal(new List(input), targetObject); + } + + [Theory] + [InlineData(new int[] { }, "0")] + [InlineData(new[] { 10, 20 }, "-1")] + [InlineData(new[] { 10, 20 }, "2")] + public void Remove_IndexOutOfBounds(int[] input, string position) + { + // Arrange + var resolver = new Mock(MockBehavior.Strict); + var targetObject = new List(input); + var listAdapter = new ListAdapter(); + + // Act + var removeStatus = listAdapter.TryRemove(targetObject, position, resolver.Object, out var message); + + // Assert + Assert.False(removeStatus); + Assert.Equal($"The index value provided by path segment '{position}' is out of bounds of the array size.", message); + } + + [Theory] + [InlineData(new[] { 10, 20 }, "0", new[] { 20 })] + [InlineData(new[] { 10, 20 }, "1", new[] { 10 })] + [InlineData(new[] { 10 }, "0", new int[] { })] + public void Remove(int[] input, string position, int[] expected) + { + // Arrange + var resolver = new Mock(MockBehavior.Strict); + var targetObject = new List(input); + var listAdapter = new ListAdapter(); + + // Act + var removeStatus = listAdapter.TryRemove(targetObject, position, resolver.Object, out var message); + + // Assert + Assert.True(removeStatus); + Assert.Equal(new List(expected), targetObject); + } + + [Fact] + public void Replace_NonCompatibleType_Fails() + { + // Arrange + var resolver = new Mock(MockBehavior.Strict); + var targetObject = new List() { 10, 20 }; + var listAdapter = new ListAdapter(); + + // Act + var replaceStatus = listAdapter.TryReplace(targetObject, "-", resolver.Object, "James", out var message); + + // Assert + Assert.False(replaceStatus); + Assert.Equal("The value 'James' is invalid for target location.", message); + } + + [Fact] + public void Replace_ReplacesValue_AtTheEnd() + { + // Arrange + var resolver = new Mock(MockBehavior.Strict); + var targetObject = new List() { 10, 20 }; + var listAdapter = new ListAdapter(); + + // Act + var replaceStatus = listAdapter.TryReplace(targetObject, "-", resolver.Object, "30", out var message); + + // Assert + Assert.True(replaceStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.Equal(new List() { 10, 30 }, targetObject); + } + + public static TheoryData> ReplacesValuesAtPositionData + { + get + { + return new TheoryData>() + { + { + "0", + new List() { 30, 20 } + }, + { + "1", + new List() { 10, 30 } + } + }; + } + } + + [Theory] + [MemberData(nameof(ReplacesValuesAtPositionData))] + public void Replace_ReplacesValue_AtGivenPosition(string position, List expected) + { + // Arrange + var resolver = new Mock(MockBehavior.Strict); + var targetObject = new List() { 10, 20 }; + var listAdapter = new ListAdapter(); + + // Act + var replaceStatus = listAdapter.TryReplace(targetObject, position, resolver.Object, "30", out var message); + + // Assert + Assert.True(replaceStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.Equal(expected, targetObject); + } + + [Fact] + public void Test_DoesNotThrowException_IfTestIsSuccessful() + { + // Arrange + var resolver = new Mock(MockBehavior.Strict); + var targetObject = new List() { 10, 20 }; + var listAdapter = new ListAdapter(); + + // Act + var testStatus = listAdapter.TryTest(targetObject, "0", resolver.Object, "10", out var message); + + //Assert + Assert.True(testStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + } + + [Fact] + public void Test_ThrowsJsonPatchException_IfTestFails() + { + // Arrange + var resolver = new Mock(MockBehavior.Strict); + var targetObject = new List() { 10, 20 }; + var listAdapter = new ListAdapter(); + var expectedErrorMessage = "The current value '20' at position '1' is not equal to the test value '10'."; + + // Act + var testStatus = listAdapter.TryTest(targetObject, "1", resolver.Object, "10", out var errorMessage); + + //Assert + Assert.False(testStatus); + Assert.Equal(expectedErrorMessage, errorMessage); + } + + [Fact] + public void Test_ThrowsJsonPatchException_IfListPositionOutOfBounds() + { + // Arrange + var resolver = new Mock(MockBehavior.Strict); + var targetObject = new List() { 10, 20 }; + var listAdapter = new ListAdapter(); + var expectedErrorMessage = "The index value provided by path segment '2' is out of bounds of the array size."; + + // Act + var testStatus = listAdapter.TryTest(targetObject, "2", resolver.Object, "10", out var errorMessage); + + //Assert + Assert.False(testStatus); + Assert.Equal(expectedErrorMessage, errorMessage); + } + } +} diff --git a/src/Features/JsonPatch/test/Internal/ObjectVisitorTest.cs b/src/Features/JsonPatch/test/Internal/ObjectVisitorTest.cs new file mode 100644 index 0000000000..44f6fc81ae --- /dev/null +++ b/src/Features/JsonPatch/test/Internal/ObjectVisitorTest.cs @@ -0,0 +1,240 @@ +// 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.Dynamic; +using Newtonsoft.Json.Serialization; +using Xunit; + +namespace Microsoft.AspNetCore.JsonPatch.Internal +{ + public class ObjectVisitorTest + { + private class Class1 + { + public string Name { get; set; } + public IList States { get; set; } = new List(); + public IDictionary Countries = new Dictionary(); + public dynamic Items { get; set; } = new ExpandoObject(); + } + + private class Class1Nested + { + public List Customers { get; set; } = new List(); + } + + public static IEnumerable ReturnsListAdapterData + { + get + { + var model = new Class1(); + yield return new object[] { model, "/States/-", model.States }; + yield return new object[] { model.States, "/-", model.States }; + + var nestedModel = new Class1Nested(); + nestedModel.Customers.Add(new Class1()); + yield return new object[] { nestedModel, "/Customers/0/States/-", nestedModel.Customers[0].States }; + yield return new object[] { nestedModel, "/Customers/0/States/0", nestedModel.Customers[0].States }; + yield return new object[] { nestedModel.Customers, "/0/States/-", nestedModel.Customers[0].States }; + yield return new object[] { nestedModel.Customers[0], "/States/-", nestedModel.Customers[0].States }; + } + } + + [Theory] + [MemberData(nameof(ReturnsListAdapterData))] + public void Visit_ValidPathToArray_ReturnsListAdapter(object targetObject, string path, object expectedTargetObject) + { + // Arrange + var visitor = new ObjectVisitor(new ParsedPath(path), new DefaultContractResolver()); + + // Act + var visitStatus = visitor.TryVisit(ref targetObject, out var adapter, out var message); + + // Assert + Assert.True(visitStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.Same(expectedTargetObject, targetObject); + Assert.IsType(adapter); + } + + public static IEnumerable ReturnsDictionaryAdapterData + { + get + { + var model = new Class1(); + yield return new object[] { model, "/Countries/USA", model.Countries }; + yield return new object[] { model.Countries, "/USA", model.Countries }; + + var nestedModel = new Class1Nested(); + nestedModel.Customers.Add(new Class1()); + yield return new object[] { nestedModel, "/Customers/0/Countries/USA", nestedModel.Customers[0].Countries }; + yield return new object[] { nestedModel.Customers, "/0/Countries/USA", nestedModel.Customers[0].Countries }; + yield return new object[] { nestedModel.Customers[0], "/Countries/USA", nestedModel.Customers[0].Countries }; + } + } + + [Theory] + [MemberData(nameof(ReturnsDictionaryAdapterData))] + public void Visit_ValidPathToDictionary_ReturnsDictionaryAdapter(object targetObject, string path, object expectedTargetObject) + { + // Arrange + var visitor = new ObjectVisitor(new ParsedPath(path), new DefaultContractResolver()); + + // Act + var visitStatus = visitor.TryVisit(ref targetObject, out var adapter, out var message); + + // Assert + Assert.True(visitStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.Same(expectedTargetObject, targetObject); + Assert.Equal(typeof(DictionaryAdapter), adapter.GetType()); + } + + public static IEnumerable ReturnsExpandoAdapterData + { + get + { + var nestedModel = new Class1Nested(); + nestedModel.Customers.Add(new Class1()); + yield return new object[] { nestedModel, "/Customers/0/Items/Name", nestedModel.Customers[0].Items }; + yield return new object[] { nestedModel.Customers, "/0/Items/Name", nestedModel.Customers[0].Items }; + yield return new object[] { nestedModel.Customers[0], "/Items/Name", nestedModel.Customers[0].Items }; + } + } + + [Theory] + [MemberData(nameof(ReturnsExpandoAdapterData))] + public void Visit_ValidPathToExpandoObject_ReturnsExpandoAdapter(object targetObject, string path, object expectedTargetObject) + { + // Arrange + var contractResolver = new DefaultContractResolver(); + var visitor = new ObjectVisitor(new ParsedPath(path), contractResolver); + + // Act + var visitStatus = visitor.TryVisit(ref targetObject, out var adapter, out var message); + + // Assert + Assert.True(visitStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.Same(expectedTargetObject, targetObject); + Assert.Same(typeof(DictionaryAdapter), adapter.GetType()); + } + + public static IEnumerable ReturnsPocoAdapterData + { + get + { + var model = new Class1(); + yield return new object[] { model, "/Name", model }; + + var nestedModel = new Class1Nested(); + nestedModel.Customers.Add(new Class1()); + yield return new object[] { nestedModel, "/Customers/0/Name", nestedModel.Customers[0] }; + yield return new object[] { nestedModel.Customers, "/0/Name", nestedModel.Customers[0] }; + yield return new object[] { nestedModel.Customers[0], "/Name", nestedModel.Customers[0] }; + } + } + + [Theory] + [MemberData(nameof(ReturnsPocoAdapterData))] + public void Visit_ValidPath_ReturnsExpandoAdapter(object targetObject, string path, object expectedTargetObject) + { + // Arrange + var visitor = new ObjectVisitor(new ParsedPath(path), new DefaultContractResolver()); + + // Act + var visitStatus = visitor.TryVisit(ref targetObject, out var adapter, out var message); + + // Assert + Assert.True(visitStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.Same(expectedTargetObject, targetObject); + Assert.IsType(adapter); + } + + [Theory] + [InlineData("0")] + [InlineData("-1")] + public void Visit_InvalidIndexToArray_Fails(string position) + { + // Arrange + var visitor = new ObjectVisitor(new ParsedPath($"/Customers/{position}/States/-"), new DefaultContractResolver()); + var automobileDepartment = new Class1Nested(); + object targetObject = automobileDepartment; + + // Act + var visitStatus = visitor.TryVisit(ref targetObject, out var adapter, out var message); + + // Assert + Assert.False(visitStatus); + Assert.Equal($"The index value provided by path segment '{position}' is out of bounds of the array size.", message); + } + + [Theory] + [InlineData("-")] + [InlineData("foo")] + public void Visit_InvalidIndexFormatToArray_Fails(string position) + { + // Arrange + var visitor = new ObjectVisitor(new ParsedPath($"/Customers/{position}/States/-"), new DefaultContractResolver()); + var automobileDepartment = new Class1Nested(); + object targetObject = automobileDepartment; + + // Act + var visitStatus = visitor.TryVisit(ref targetObject, out var adapter, out var message); + + // Assert + Assert.False(visitStatus); + Assert.Equal($"The path segment '{position}' is invalid for an array index.", message); + } + + [Fact] + public void Visit_DoesNotValidate_FinalPathSegment() + { + // Arrange + var visitor = new ObjectVisitor(new ParsedPath($"/NonExisting"), new DefaultContractResolver()); + var model = new Class1(); + object targetObject = model; + + // Act + var visitStatus = visitor.TryVisit(ref targetObject, out var adapter, out var message); + + // Assert + Assert.True(visitStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.IsType(adapter); + } + + [Fact] + public void Visit_NullInteriorTarget_ReturnsFalse() + { + // Arrange + var visitor = new ObjectVisitor(new ParsedPath("/States/0"), new DefaultContractResolver()); + + // Act + object target = new Class1() { States = null, }; + var visitStatus = visitor.TryVisit(ref target, out var adapter, out var message); + + // Assert + Assert.False(visitStatus); + Assert.Null(adapter); + Assert.Null(message); + } + + [Fact] + public void Visit_NullTarget_ReturnsNullAdapter() + { + // Arrange + var visitor = new ObjectVisitor(new ParsedPath("test"), new DefaultContractResolver()); + + // Act + object target = null; + var visitStatus = visitor.TryVisit(ref target, out var adapter, out var message); + + // Assert + Assert.False(visitStatus); + Assert.Null(adapter); + Assert.Null(message); + } + } +} diff --git a/src/Features/JsonPatch/test/Internal/ParsedPathTests.cs b/src/Features/JsonPatch/test/Internal/ParsedPathTests.cs new file mode 100644 index 0000000000..c23abcdb5e --- /dev/null +++ b/src/Features/JsonPatch/test/Internal/ParsedPathTests.cs @@ -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 Microsoft.AspNetCore.JsonPatch.Exceptions; +using Xunit; + +namespace Microsoft.AspNetCore.JsonPatch.Internal +{ + public class ParsedPathTests + { + [Theory] + [InlineData("foo/bar~0baz", new string[] { "foo", "bar~baz" })] + [InlineData("foo/bar~00baz", new string[] { "foo", "bar~0baz" })] + [InlineData("foo/bar~01baz", new string[] { "foo", "bar~1baz" })] + [InlineData("foo/bar~10baz", new string[] { "foo", "bar/0baz" })] + [InlineData("foo/bar~1baz", new string[] { "foo", "bar/baz" })] + [InlineData("foo/bar~0/~0/~1~1/~0~0/baz", new string[] { "foo", "bar~", "~", "//", "~~", "baz" })] + [InlineData("~0~1foo", new string[] { "~/foo" })] + public void ParsingValidPathShouldSucceed(string path, string[] expected) + { + // Arrange & Act + var parsedPath = new ParsedPath(path); + + // Assert + Assert.Equal(expected, parsedPath.Segments); + } + + [Theory] + [InlineData("foo/bar~")] + [InlineData("~")] + [InlineData("~2")] + [InlineData("foo~3bar")] + public void PathWithInvalidEscapeSequenceShouldFail(string path) + { + // Arrange, Act & Assert + Assert.Throws(() => + { + var parsedPath = new ParsedPath(path); + }); + } + } +} diff --git a/src/Features/JsonPatch/test/Internal/PocoAdapterTest.cs b/src/Features/JsonPatch/test/Internal/PocoAdapterTest.cs new file mode 100644 index 0000000000..9a31ea11a8 --- /dev/null +++ b/src/Features/JsonPatch/test/Internal/PocoAdapterTest.cs @@ -0,0 +1,241 @@ +// 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 Newtonsoft.Json.Serialization; +using Xunit; + +namespace Microsoft.AspNetCore.JsonPatch.Internal +{ + public class PocoAdapterTest + { + [Fact] + public void TryAdd_ReplacesExistingProperty() + { + // Arrange + var adapter = new PocoAdapter(); + var contractResolver = new DefaultContractResolver(); + var model = new Customer + { + Name = "Joana" + }; + + // Act + var addStatus = adapter.TryAdd(model, "Name", contractResolver, "John", out var errorMessage); + + // Assert + Assert.Equal("John", model.Name); + Assert.True(addStatus); + Assert.True(string.IsNullOrEmpty(errorMessage), "Expected no error message"); + } + + [Fact] + public void TryAdd_ThrowsJsonPatchException_IfPropertyDoesNotExist() + { + // Arrange + var adapter = new PocoAdapter(); + var contractResolver = new DefaultContractResolver(); + var model = new Customer + { + Name = "Joana" + }; + var expectedErrorMessage = "The target location specified by path segment 'LastName' was not found."; + + // Act + var addStatus = adapter.TryAdd(model, "LastName", contractResolver, "Smith", out var errorMessage); + + // Assert + Assert.False(addStatus); + Assert.Equal(expectedErrorMessage, errorMessage); + } + + [Fact] + public void TryGet_ExistingProperty() + { + // Arrange + var adapter = new PocoAdapter(); + var contractResolver = new DefaultContractResolver(); + var model = new Customer + { + Name = "Joana" + }; + + // Act + var getStatus = adapter.TryGet(model, "Name", contractResolver, out var value, out var errorMessage); + + // Assert + Assert.Equal("Joana", value); + Assert.True(getStatus); + Assert.True(string.IsNullOrEmpty(errorMessage), "Expected no error message"); + } + + [Fact] + public void TryGet_ThrowsJsonPatchException_IfPropertyDoesNotExist() + { + // Arrange + var adapter = new PocoAdapter(); + var contractResolver = new DefaultContractResolver(); + var model = new Customer + { + Name = "Joana" + }; + var expectedErrorMessage = "The target location specified by path segment 'LastName' was not found."; + + // Act + var getStatus = adapter.TryGet(model, "LastName", contractResolver, out var value, out var errorMessage); + + // Assert + Assert.Null(value); + Assert.False(getStatus); + Assert.Equal(expectedErrorMessage, errorMessage); + } + + [Fact] + public void TryRemove_SetsPropertyToNull() + { + // Arrange + var adapter = new PocoAdapter(); + var contractResolver = new DefaultContractResolver(); + var model = new Customer + { + Name = "Joana" + }; + + // Act + var removeStatus = adapter.TryRemove(model, "Name", contractResolver, out var errorMessage); + + // Assert + Assert.Null(model.Name); + Assert.True(removeStatus); + Assert.True(string.IsNullOrEmpty(errorMessage), "Expected no error message"); + } + + [Fact] + public void TryRemove_ThrowsJsonPatchException_IfPropertyDoesNotExist() + { + // Arrange + var adapter = new PocoAdapter(); + var contractResolver = new DefaultContractResolver(); + var model = new Customer + { + Name = "Joana" + }; + var expectedErrorMessage = "The target location specified by path segment 'LastName' was not found."; + + // Act + var removeStatus = adapter.TryRemove(model, "LastName", contractResolver, out var errorMessage); + + // Assert + Assert.False(removeStatus); + Assert.Equal(expectedErrorMessage, errorMessage); + } + + [Fact] + public void TryReplace_OverwritesExistingValue() + { + // Arrange + var adapter = new PocoAdapter(); + var contractResolver = new DefaultContractResolver(); + var model = new Customer + { + Name = "Joana" + }; + + // Act + var replaceStatus = adapter.TryReplace(model, "Name", contractResolver, "John", out var errorMessage); + + // Assert + Assert.Equal("John", model.Name); + Assert.True(replaceStatus); + Assert.True(string.IsNullOrEmpty(errorMessage), "Expected no error message"); + } + + [Fact] + public void TryReplace_ThrowsJsonPatchException_IfNewValueIsInvalidType() + { + // Arrange + var adapter = new PocoAdapter(); + var contractResolver = new DefaultContractResolver(); + var model = new Customer + { + Age = 25 + }; + + var expectedErrorMessage = "The value 'TwentySix' is invalid for target location."; + + // Act + var replaceStatus = adapter.TryReplace(model, "Age", contractResolver, "TwentySix", out var errorMessage); + + // Assert + Assert.Equal(25, model.Age); + Assert.False(replaceStatus); + Assert.Equal(expectedErrorMessage, errorMessage); + } + + [Fact] + public void TryReplace_ThrowsJsonPatchException_IfPropertyDoesNotExist() + { + // Arrange + var adapter = new PocoAdapter(); + var contractResolver = new DefaultContractResolver(); + var model = new Customer + { + Name = "Joana" + }; + var expectedErrorMessage = "The target location specified by path segment 'LastName' was not found."; + + // Act + var replaceStatus = adapter.TryReplace(model, "LastName", contractResolver, "Smith", out var errorMessage); + + // Assert + Assert.Equal("Joana", model.Name); + Assert.False(replaceStatus); + Assert.Equal(expectedErrorMessage, errorMessage); + } + + [Fact] + public void TryTest_DoesNotThrowException_IfTestSuccessful() + { + var adapter = new PocoAdapter(); + var contractResolver = new DefaultContractResolver(); + var model = new Customer + { + Name = "Joana" + }; + + // Act + var testStatus = adapter.TryTest(model, "Name", contractResolver, "Joana", out var errorMessage); + + // Assert + Assert.Equal("Joana", model.Name); + Assert.True(testStatus); + Assert.True(string.IsNullOrEmpty(errorMessage), "Expected no error message"); + } + + [Fact] + public void TryTest_ThrowsJsonPatchException_IfTestFails() + { + // Arrange + var adapter = new PocoAdapter(); + var contractResolver = new DefaultContractResolver(); + var model = new Customer + { + Name = "Joana" + }; + var expectedErrorMessage = "The current value 'Joana' at path 'Name' is not equal to the test value 'John'."; + + // Act + var testStatus = adapter.TryTest(model, "Name", contractResolver, "John", out var errorMessage); + + // Assert + Assert.False(testStatus); + Assert.Equal(expectedErrorMessage, errorMessage); + } + + private class Customer + { + public string Name { get; set; } + + public int Age { get; set; } + } + } +} diff --git a/src/Features/JsonPatch/test/JsonPatchDocumentGetPathTest.cs b/src/Features/JsonPatch/test/JsonPatchDocumentGetPathTest.cs new file mode 100644 index 0000000000..266202c7a5 --- /dev/null +++ b/src/Features/JsonPatch/test/JsonPatchDocumentGetPathTest.cs @@ -0,0 +1,122 @@ +// 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 Xunit; + +namespace Microsoft.AspNetCore.JsonPatch +{ + public class JsonPatchDocumentGetPathTest + { + [Fact] + public void ExpressionType_MemberAccess() + { + // Arrange + var patchDocument = new JsonPatchDocument(); + + // Act + var path = patchDocument.GetPath(p => p.SimpleObject.IntegerList, "-"); + + // Assert + Assert.Equal("/SimpleObject/IntegerList/-", path); + } + + [Fact] + public void ExpressionType_ArrayIndex() + { + // Arrange + var patchDocument = new JsonPatchDocument(); + + // Act + var path = patchDocument.GetPath(p => p[3], null); + + // Assert + Assert.Equal("/3", path); + } + + [Fact] + public void ExpressionType_Call() + { + // Arrange + var patchDocument = new JsonPatchDocument>(); + + // Act + var path = patchDocument.GetPath(p => p["key"], "3"); + + // Assert + Assert.Equal("/key/3", path); + } + + [Fact] + public void ExpressionType_Parameter_NullPosition() + { + // Arrange + var patchDocument = new JsonPatchDocument(); + + // Act + var path = patchDocument.GetPath(p => p, null); + + // Assert + Assert.Equal("/", path); + } + + [Fact] + public void ExpressionType_Parameter_WithPosition() + { + // Arrange + var patchDocument = new JsonPatchDocument(); + + // Act + var path = patchDocument.GetPath(p => p, "-"); + + // Assert + Assert.Equal("/-", path); + } + + [Fact] + public void ExpressionType_Convert() + { + // Arrange + var patchDocument = new JsonPatchDocument(); + + // Act + var path = patchDocument.GetPath(p => (BaseClass)p.DerivedObject, null); + + // Assert + Assert.Equal("/DerivedObject", path); + } + + [Fact] + public void ExpressionType_NotSupported() + { + // Arrange + var patchDocument = new JsonPatchDocument(); + + // Act + var exception = Assert.Throws(() => + { + patchDocument.GetPath(p => p.IntegerValue >= 4, null); + }); + + // Assert + Assert.Equal("The expression '(p.IntegerValue >= 4)' is not supported. Supported expressions include member access and indexer expressions.", exception.Message); + } + } + + internal class DerivedClass : BaseClass + { + public DerivedClass() + { + } + } + + internal class NestedObjectWithDerivedClass + { + public DerivedClass DerivedObject { get; set; } + } + + internal class BaseClass + { + } +} diff --git a/src/Features/JsonPatch/test/JsonPatchDocumentJsonPropertyAttributeTest.cs b/src/Features/JsonPatch/test/JsonPatchDocumentJsonPropertyAttributeTest.cs new file mode 100644 index 0000000000..a9c3d8500b --- /dev/null +++ b/src/Features/JsonPatch/test/JsonPatchDocumentJsonPropertyAttributeTest.cs @@ -0,0 +1,90 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Linq; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using Xunit; + +namespace Microsoft.AspNetCore.JsonPatch +{ + public class JsonPatchDocumentJsonPropertyAttributeTest + { + [Fact] + public void Add_RespectsJsonPropertyAttribute() + { + // Arrange + var patchDocument = new JsonPatchDocument(); + + // Act + patchDocument.Add(p => p.Name, "John"); + + // Assert + var pathToCheck = patchDocument.Operations.First().path; + Assert.Equal("/AnotherName", pathToCheck); + } + + [Fact] + public void Add_RespectsJsonPropertyAttribute_WithDotWhitespaceAndBackslashInName() + { + // Arrange + var obj = new JsonPropertyObjectWithStrangeNames(); + var patchDocument = new JsonPatchDocument(); + + // Act + patchDocument.Add("/First Name.", "John"); + patchDocument.Add("Last\\Name", "Doe"); + patchDocument.ApplyTo(obj); + + // Assert + Assert.Equal("John", obj.FirstName); + Assert.Equal("Doe", obj.LastName); + } + + [Fact] + public void Move_FallsbackToPropertyName_WhenJsonPropertyAttributeName_IsEmpty() + { + // Arrange + var patchDocument = new JsonPatchDocument(); + + // Act + patchDocument.Move(m => m.StringProperty, m => m.StringProperty2); + + // Assert + var fromPath = patchDocument.Operations.First().from; + Assert.Equal("/StringProperty", fromPath); + var toPath = patchDocument.Operations.First().path; + Assert.Equal("/StringProperty2", toPath); + } + + private class JsonPropertyObject + { + [JsonProperty("AnotherName")] + public string Name { get; set; } + } + + private class JsonPropertyObjectWithStrangeNames + { + [JsonProperty("First Name.")] + public string FirstName { get; set; } + + [JsonProperty("Last\\Name")] + public string LastName { get; set; } + } + + private class JsonPropertyWithNoPropertyName + { + [JsonProperty] + public string StringProperty { get; set; } + + [JsonProperty] + public string[] ArrayProperty { get; set; } + + [JsonProperty] + public string StringProperty2 { get; set; } + + [JsonProperty] + public string SSN { get; set; } + } + } +} diff --git a/src/Features/JsonPatch/test/JsonPatchDocumentTest.cs b/src/Features/JsonPatch/test/JsonPatchDocumentTest.cs new file mode 100644 index 0000000000..197e514cee --- /dev/null +++ b/src/Features/JsonPatch/test/JsonPatchDocumentTest.cs @@ -0,0 +1,162 @@ +// 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.JsonPatch.Exceptions; +using Newtonsoft.Json; +using Xunit; + +namespace Microsoft.AspNetCore.JsonPatch +{ + public class JsonPatchDocumentTest + { + [Fact] + public void InvalidPathAtBeginningShouldThrowException() + { + // Arrange + var patchDocument = new JsonPatchDocument(); + + // Act + var exception = Assert.Throws(() => + { + patchDocument.Add("//NewInt", 1); + }); + + // Assert + Assert.Equal( + "The provided string '//NewInt' is an invalid path.", + exception.Message); + } + + [Fact] + public void InvalidPathAtEndShouldThrowException() + { + // Arrange + var patchDocument = new JsonPatchDocument(); + + // Act + var exception = Assert.Throws(() => + { + patchDocument.Add("NewInt//", 1); + }); + + // Assert + Assert.Equal( + "The provided string 'NewInt//' is an invalid path.", + exception.Message); + } + + [Fact] + public void NonGenericPatchDocToGenericMustSerialize() + { + // Arrange + var targetObject = new SimpleObject() + { + StringProperty = "A", + AnotherStringProperty = "B" + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Copy("StringProperty", "AnotherStringProperty"); + + var serialized = JsonConvert.SerializeObject(patchDocument); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(targetObject); + + // Assert + Assert.Equal("A", targetObject.AnotherStringProperty); + } + + [Fact] + public void GenericPatchDocToNonGenericMustSerialize() + { + // Arrange + var targetObject = new SimpleObject() + { + StringProperty = "A", + AnotherStringProperty = "B" + }; + + var patchDocTyped = new JsonPatchDocument(); + patchDocTyped.Copy(o => o.StringProperty, o => o.AnotherStringProperty); + + var patchDocUntyped = new JsonPatchDocument(); + patchDocUntyped.Copy("StringProperty", "AnotherStringProperty"); + + var serializedTyped = JsonConvert.SerializeObject(patchDocTyped); + var serializedUntyped = JsonConvert.SerializeObject(patchDocUntyped); + var deserialized = JsonConvert.DeserializeObject(serializedTyped); + + // Act + deserialized.ApplyTo(targetObject); + + // Assert + Assert.Equal("A", targetObject.AnotherStringProperty); + } + + [Fact] + public void Deserialization_Successful_ForValidJsonPatchDocument() + { + // Arrange + var doc = new SimpleObject() + { + StringProperty = "A", + DecimalValue = 10, + DoubleValue = 10, + FloatValue = 10, + IntegerValue = 10 + }; + + var patchDocument = new JsonPatchDocument(); + patchDocument.Replace(o => o.StringProperty, "B"); + patchDocument.Replace(o => o.DecimalValue, 12); + patchDocument.Replace(o => o.DoubleValue, 12); + patchDocument.Replace(o => o.FloatValue, 12); + patchDocument.Replace(o => o.IntegerValue, 12); + + // default: no envelope + var serialized = JsonConvert.SerializeObject(patchDocument); + + // Act + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Assert + Assert.IsType>(deserialized); + } + + [Fact] + public void Deserialization_Fails_ForInvalidJsonPatchDocument() + { + // Arrange + var serialized = "{\"Operations\": [{ \"op\": \"replace\", \"path\": \"/title\", \"value\": \"New Title\"}]}"; + + // Act + var exception = Assert.Throws(() => + { + var deserialized + = JsonConvert.DeserializeObject(serialized); + }); + + // Assert + Assert.Equal("The JSON patch document was malformed and could not be parsed.", exception.Message); + } + + [Fact] + public void Deserialization_Fails_ForInvalidTypedJsonPatchDocument() + { + // Arrange + var serialized = "{\"Operations\": [{ \"op\": \"replace\", \"path\": \"/title\", \"value\": \"New Title\"}]}"; + + // Act + var exception = Assert.Throws(() => + { + var deserialized + = JsonConvert.DeserializeObject>(serialized); + }); + + // Assert + Assert.Equal("The JSON patch document was malformed and could not be parsed.", exception.Message); + } + } +} diff --git a/src/Features/JsonPatch/test/Microsoft.AspNetCore.JsonPatch.Tests.csproj b/src/Features/JsonPatch/test/Microsoft.AspNetCore.JsonPatch.Tests.csproj new file mode 100644 index 0000000000..28d501111a --- /dev/null +++ b/src/Features/JsonPatch/test/Microsoft.AspNetCore.JsonPatch.Tests.csproj @@ -0,0 +1,11 @@ + + + + netcoreapp3.0;net461 + + + + + + + diff --git a/src/Features/JsonPatch/test/OperationBaseTests.cs b/src/Features/JsonPatch/test/OperationBaseTests.cs new file mode 100644 index 0000000000..955344404f --- /dev/null +++ b/src/Features/JsonPatch/test/OperationBaseTests.cs @@ -0,0 +1,41 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Xunit; + +namespace Microsoft.AspNetCore.JsonPatch.Operations +{ + public class OperationBaseTests + { + [Theory] + [InlineData("ADd", OperationType.Add)] + [InlineData("Copy", OperationType.Copy)] + [InlineData("mOVE", OperationType.Move)] + [InlineData("REMOVE", OperationType.Remove)] + [InlineData("replace", OperationType.Replace)] + [InlineData("TeSt", OperationType.Test)] + public void SetValidOperationType(string op, OperationType operationType) + { + // Arrange + var operationBase = new OperationBase(); + operationBase.op = op; + + // Act & Assert + Assert.Equal(operationType, operationBase.OperationType); + } + + [Theory] + [InlineData("invalid", OperationType.Invalid)] + [InlineData("coppy", OperationType.Invalid)] + [InlineData("notvalid", OperationType.Invalid)] + public void InvalidOperationType_SetsOperationTypeInvalid(string op, OperationType operationType) + { + // Arrange + var operationBase = new OperationBase(); + operationBase.op = op; + + // Act & Assert + Assert.Equal(operationType, operationBase.OperationType); + } + } +} diff --git a/src/Features/JsonPatch/test/TestErrorLogger.cs b/src/Features/JsonPatch/test/TestErrorLogger.cs new file mode 100644 index 0000000000..2cd6a4453e --- /dev/null +++ b/src/Features/JsonPatch/test/TestErrorLogger.cs @@ -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. + +namespace Microsoft.AspNetCore.JsonPatch +{ + public class TestErrorLogger where T : class + { + public string ErrorMessage { get; set; } + + public void LogErrorMessage(JsonPatchError patchError) + { + ErrorMessage = patchError.ErrorMessage; + } + } +} diff --git a/src/Features/JsonPatch/test/TestObjectModels/Customer.cs b/src/Features/JsonPatch/test/TestObjectModels/Customer.cs new file mode 100644 index 0000000000..c8a5aa22b1 --- /dev/null +++ b/src/Features/JsonPatch/test/TestObjectModels/Customer.cs @@ -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. + +namespace Microsoft.AspNetCore.JsonPatch.Internal +{ + internal class Customer + { + private string _name; + private int _age; + + public Customer(string name, int age) + { + _name = name; + _age = age; + } + } +} diff --git a/src/Features/JsonPatch/test/TestObjectModels/DynamicTestObject.cs b/src/Features/JsonPatch/test/TestObjectModels/DynamicTestObject.cs new file mode 100644 index 0000000000..94ecf1685d --- /dev/null +++ b/src/Features/JsonPatch/test/TestObjectModels/DynamicTestObject.cs @@ -0,0 +1,87 @@ +// 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.Dynamic; + +namespace Microsoft.AspNetCore.JsonPatch +{ + public class DynamicTestObject : DynamicObject + { + private Dictionary _dictionary = new Dictionary(); + + public object this[string key] { get => ((IDictionary)_dictionary)[key]; set => ((IDictionary)_dictionary)[key] = value; } + + public ICollection Keys => ((IDictionary)_dictionary).Keys; + + public ICollection Values => ((IDictionary)_dictionary).Values; + + public int Count => ((IDictionary)_dictionary).Count; + + public bool IsReadOnly => ((IDictionary)_dictionary).IsReadOnly; + + public void Add(string key, object value) + { + ((IDictionary)_dictionary).Add(key, value); + } + + public void Add(KeyValuePair item) + { + ((IDictionary)_dictionary).Add(item); + } + + public void Clear() + { + ((IDictionary)_dictionary).Clear(); + } + + public bool Contains(KeyValuePair item) + { + return ((IDictionary)_dictionary).Contains(item); + } + + public bool ContainsKey(string key) + { + return ((IDictionary)_dictionary).ContainsKey(key); + } + + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + ((IDictionary)_dictionary).CopyTo(array, arrayIndex); + } + + public IEnumerator> GetEnumerator() + { + return ((IDictionary)_dictionary).GetEnumerator(); + } + + public bool Remove(string key) + { + return ((IDictionary)_dictionary).Remove(key); + } + + public bool Remove(KeyValuePair item) + { + return ((IDictionary)_dictionary).Remove(item); + } + + public bool TryGetValue(string key, out object value) + { + return ((IDictionary)_dictionary).TryGetValue(key, out value); + } + + public override bool TryGetMember(GetMemberBinder binder, out object result) + { + var name = binder.Name; + + return TryGetValue(name, out result); + } + + public override bool TrySetMember(SetMemberBinder binder, object value) + { + _dictionary[binder.Name] = value; + + return true; + } + } +} diff --git a/src/Features/JsonPatch/test/TestObjectModels/InheritedObject.cs b/src/Features/JsonPatch/test/TestObjectModels/InheritedObject.cs new file mode 100644 index 0000000000..37b8a10dc9 --- /dev/null +++ b/src/Features/JsonPatch/test/TestObjectModels/InheritedObject.cs @@ -0,0 +1,10 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.AspNetCore.JsonPatch +{ + public class InheritedObject : SimpleObject + { + public string AdditionalStringProperty { get; set; } + } +} \ No newline at end of file diff --git a/src/Features/JsonPatch/test/TestObjectModels/NestedObject.cs b/src/Features/JsonPatch/test/TestObjectModels/NestedObject.cs new file mode 100644 index 0000000000..1b42d0d7ef --- /dev/null +++ b/src/Features/JsonPatch/test/TestObjectModels/NestedObject.cs @@ -0,0 +1,11 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.AspNetCore.JsonPatch +{ + public class NestedObject + { + public string StringProperty { get; set; } + public dynamic DynamicProperty { get; set; } + } +} \ No newline at end of file diff --git a/src/Features/JsonPatch/test/TestObjectModels/SimpleObject.cs b/src/Features/JsonPatch/test/TestObjectModels/SimpleObject.cs new file mode 100644 index 0000000000..651a91bdcf --- /dev/null +++ b/src/Features/JsonPatch/test/TestObjectModels/SimpleObject.cs @@ -0,0 +1,23 @@ +// 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; + +namespace Microsoft.AspNetCore.JsonPatch +{ + public class SimpleObject + { + public List SimpleObjectList { get; set; } + public List IntegerList { get; set; } + public IList IntegerIList { get; set; } + public int IntegerValue { get; set; } + public int AnotherIntegerValue { get; set; } + public string StringProperty { get; set; } + public string AnotherStringProperty { get; set; } + public decimal DecimalValue { get; set; } + public double DoubleValue { get; set; } + public float FloatValue { get; set; } + public Guid GuidValue { get; set; } + } +} \ No newline at end of file diff --git a/src/Features/JsonPatch/test/TestObjectModels/SimpleObjectWithNestedObject.cs b/src/Features/JsonPatch/test/TestObjectModels/SimpleObjectWithNestedObject.cs new file mode 100644 index 0000000000..4d7c0e2bd8 --- /dev/null +++ b/src/Features/JsonPatch/test/TestObjectModels/SimpleObjectWithNestedObject.cs @@ -0,0 +1,30 @@ +// 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; + +namespace Microsoft.AspNetCore.JsonPatch +{ + public class SimpleObjectWithNestedObject + { + public int IntegerValue { get; set; } + + public NestedObject NestedObject { get; set; } + + public SimpleObject SimpleObject { get; set; } + + public InheritedObject InheritedObject { get; set; } + + public List SimpleObjectList { get; set; } + + public IList SimpleObjectIList { get; set; } + + public SimpleObjectWithNestedObject() + { + NestedObject = new NestedObject(); + SimpleObject = new SimpleObject(); + InheritedObject = new InheritedObject(); + SimpleObjectList = new List(); + } + } +} \ No newline at end of file diff --git a/src/Features/JsonPatch/test/WriteOnceDynamicTestObject.cs b/src/Features/JsonPatch/test/WriteOnceDynamicTestObject.cs new file mode 100644 index 0000000000..769ddcc154 --- /dev/null +++ b/src/Features/JsonPatch/test/WriteOnceDynamicTestObject.cs @@ -0,0 +1,117 @@ +// 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.Dynamic; + +namespace Microsoft.AspNetCore.JsonPatch.Internal +{ + /// + /// + /// This class is used specifically to test that JSON patch "replace" operations are functionally equivalent to + /// "add" and "remove" operations applied sequentially using the same path. + /// + /// + /// This is done by asserting that no value exists for a particular key before setting its value. To replace the + /// value for a key, the key must first be removed, and then re-added with the new value. + /// + /// + /// See JsonPatch#110 for further details. + /// + /// + public class WriteOnceDynamicTestObject : DynamicObject + { + private Dictionary _dictionary = new Dictionary(); + + public object this[string key] { get => ((IDictionary)_dictionary)[key]; set => SetValueForKey(key, value); } + + public ICollection Keys => ((IDictionary)_dictionary).Keys; + + public ICollection Values => ((IDictionary)_dictionary).Values; + + public int Count => ((IDictionary)_dictionary).Count; + + public bool IsReadOnly => ((IDictionary)_dictionary).IsReadOnly; + + public void Add(string key, object value) + { + SetValueForKey(key, value); + } + + public void Add(KeyValuePair item) + { + SetValueForKey(item.Key, item.Value); + } + + public void Clear() + { + ((IDictionary)_dictionary).Clear(); + } + + public bool Contains(KeyValuePair item) + { + return ((IDictionary)_dictionary).Contains(item); + } + + public bool ContainsKey(string key) + { + return ((IDictionary)_dictionary).ContainsKey(key); + } + + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + ((IDictionary)_dictionary).CopyTo(array, arrayIndex); + } + + public IEnumerator> GetEnumerator() + { + return ((IDictionary)_dictionary).GetEnumerator(); + } + + public bool Remove(string key) + { + return ((IDictionary)_dictionary).Remove(key); + } + + public bool Remove(KeyValuePair item) + { + return ((IDictionary)_dictionary).Remove(item); + } + + public bool TryGetValue(string key, out object value) + { + return ((IDictionary)_dictionary).TryGetValue(key, out value); + } + + public override bool TryGetMember(GetMemberBinder binder, out object result) + { + var name = binder.Name; + + return TryGetValue(name, out result); + } + + public override bool TrySetMember(SetMemberBinder binder, object value) + { + SetValueForKey(binder.Name, value); + + return true; + } + + private void SetValueForKey(string key, object value) + { + if (value == null) + { + _dictionary.Remove(key); + return; + } + + if (_dictionary.ContainsKey(key)) + { + throw new ArgumentException($"Value for {key} already exists"); + } + + _dictionary[key] = value; + } + } +} diff --git a/src/Framework/Directory.Build.props b/src/Framework/Directory.Build.props index d04c942d21..cc051ae360 100644 --- a/src/Framework/Directory.Build.props +++ b/src/Framework/Directory.Build.props @@ -1,6 +1,10 @@ + + true + + true diff --git a/src/Framework/Directory.Build.targets b/src/Framework/Directory.Build.targets index 1ff9f7da4b..80354ba35b 100644 --- a/src/Framework/Directory.Build.targets +++ b/src/Framework/Directory.Build.targets @@ -26,14 +26,4 @@ - - - - NuGetPackage - $(PackageId) - $(PackageVersion) - - - - diff --git a/src/Framework/Framework.UnitTests/Framework.UnitTests.csproj b/src/Framework/Framework.UnitTests/Framework.UnitTests.csproj index e1cb8ce5c9..612980dc53 100644 --- a/src/Framework/Framework.UnitTests/Framework.UnitTests.csproj +++ b/src/Framework/Framework.UnitTests/Framework.UnitTests.csproj @@ -27,10 +27,6 @@ - - - - diff --git a/src/Html/Abstractions/src/HtmlContentBuilder.cs b/src/Html/Abstractions/src/HtmlContentBuilder.cs new file mode 100644 index 0000000000..e61d9f7dc8 --- /dev/null +++ b/src/Html/Abstractions/src/HtmlContentBuilder.cs @@ -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.Collections.Generic; +using System.IO; +using System.Text.Encodings.Web; + +namespace Microsoft.AspNetCore.Html +{ + /// + /// An implementation using an in memory list. + /// + public class HtmlContentBuilder : IHtmlContentBuilder + { + /// + /// Creates a new . + /// + public HtmlContentBuilder() + : this(new List()) + { + } + + /// + /// Creates a new with the given initial capacity. + /// + /// The initial capacity of the backing store. + public HtmlContentBuilder(int capacity) + : this(new List(capacity)) + { + } + + /// + /// Gets the number of elements in the . + /// + public int Count => Entries.Count; + + /// + /// Creates a new with the given list of entries. + /// + /// + /// The list of entries. The will use this list without making a copy. + /// + public HtmlContentBuilder(IList entries) + { + if (entries == null) + { + throw new ArgumentNullException(nameof(entries)); + } + + Entries = entries; + } + + // This is not List because that would lead to wrapping all strings to IHtmlContent + // which is not space performant. + // + // In general unencoded strings are added here. We're optimizing for that case, and allocating + // a wrapper when encoded strings are used. + // + // internal for testing. + internal IList Entries { get; } + + /// + public IHtmlContentBuilder Append(string unencoded) + { + if (!string.IsNullOrEmpty(unencoded)) + { + Entries.Add(unencoded); + } + + return this; + } + + /// + public IHtmlContentBuilder AppendHtml(IHtmlContent htmlContent) + { + if (htmlContent == null) + { + return this; + } + + Entries.Add(htmlContent); + return this; + } + + /// + public IHtmlContentBuilder AppendHtml(string encoded) + { + if (!string.IsNullOrEmpty(encoded)) + { + Entries.Add(new HtmlString(encoded)); + } + + return this; + } + + /// + public IHtmlContentBuilder Clear() + { + Entries.Clear(); + return this; + } + + /// + public void CopyTo(IHtmlContentBuilder destination) + { + if (destination == null) + { + throw new ArgumentNullException(nameof(destination)); + } + + for (var i = 0; i < Entries.Count; i++) + { + var entry = Entries[i]; + + string entryAsString; + IHtmlContentContainer entryAsContainer; + if ((entryAsString = entry as string) != null) + { + destination.Append(entryAsString); + } + else if ((entryAsContainer = entry as IHtmlContentContainer) != null) + { + // Since we're copying, do a deep flatten. + entryAsContainer.CopyTo(destination); + } + else + { + // Only string, IHtmlContent values can be added to the buffer. + destination.AppendHtml((IHtmlContent)entry); + } + } + } + + /// + public void MoveTo(IHtmlContentBuilder destination) + { + if (destination == null) + { + throw new ArgumentNullException(nameof(destination)); + } + + for (var i = 0; i < Entries.Count; i++) + { + var entry = Entries[i]; + + string entryAsString; + IHtmlContentContainer entryAsContainer; + if ((entryAsString = entry as string) != null) + { + destination.Append(entryAsString); + } + else if ((entryAsContainer = entry as IHtmlContentContainer) != null) + { + // Since we're moving, do a deep flatten. + entryAsContainer.MoveTo(destination); + } + else + { + // Only string, IHtmlContent values can be added to the buffer. + destination.AppendHtml((IHtmlContent)entry); + } + } + + Entries.Clear(); + } + + /// + public void WriteTo(TextWriter writer, HtmlEncoder encoder) + { + if (writer == null) + { + throw new ArgumentNullException(nameof(writer)); + } + + if (encoder == null) + { + throw new ArgumentNullException(nameof(encoder)); + } + + for (var i = 0; i < Entries.Count; i++) + { + var entry = Entries[i]; + + var entryAsString = entry as string; + if (entryAsString != null) + { + encoder.Encode(writer, entryAsString); + } + else + { + // Only string, IHtmlContent values can be added to the buffer. + ((IHtmlContent)entry).WriteTo(writer, encoder); + } + } + } + + private string DebuggerToString() + { + using (var writer = new StringWriter()) + { + WriteTo(writer, HtmlEncoder.Default); + return writer.ToString(); + } + } + } +} diff --git a/src/Html/Abstractions/src/HtmlContentBuilderExtensions.cs b/src/Html/Abstractions/src/HtmlContentBuilderExtensions.cs new file mode 100644 index 0000000000..a5a83fdbb3 --- /dev/null +++ b/src/Html/Abstractions/src/HtmlContentBuilderExtensions.cs @@ -0,0 +1,223 @@ +// 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.Globalization; +using System.IO; +using System.Text.Encodings.Web; + +namespace Microsoft.AspNetCore.Html +{ + /// + /// Extension methods for . + /// + public static class HtmlContentBuilderExtensions + { + /// + /// Appends the specified to the existing content after replacing each format + /// item with the HTML encoded representation of the corresponding item in the + /// array. + /// + /// The . + /// + /// The composite format (see http://msdn.microsoft.com/en-us/library/txafckwd.aspx). + /// The format string is assumed to be HTML encoded as-provided, and no further encoding will be performed. + /// + /// + /// The object array to format. Each element in the array will be formatted and then HTML encoded. + /// + /// A reference to this instance after the append operation has completed. + public static IHtmlContentBuilder AppendFormat( + this IHtmlContentBuilder builder, + string format, + params object[] args) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + if (format == null) + { + throw new ArgumentNullException(nameof(format)); + } + + if (args == null) + { + throw new ArgumentNullException(nameof(args)); + } + + builder.AppendHtml(new HtmlFormattableString(format, args)); + return builder; + } + + /// + /// Appends the specified to the existing content with information from the + /// after replacing each format item with the HTML encoded + /// representation of the corresponding item in the array. + /// + /// The . + /// An object that supplies culture-specific formatting information. + /// + /// The composite format (see http://msdn.microsoft.com/en-us/library/txafckwd.aspx). + /// The format string is assumed to be HTML encoded as-provided, and no further encoding will be performed. + /// + /// + /// The object array to format. Each element in the array will be formatted and then HTML encoded. + /// + /// A reference to this instance after the append operation has completed. + public static IHtmlContentBuilder AppendFormat( + this IHtmlContentBuilder builder, + IFormatProvider formatProvider, + string format, + params object[] args) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + if (format == null) + { + throw new ArgumentNullException(nameof(format)); + } + + if (args == null) + { + throw new ArgumentNullException(nameof(args)); + } + + builder.AppendHtml(new HtmlFormattableString(formatProvider, format, args)); + return builder; + } + + /// + /// Appends an . + /// + /// The . + /// The . + public static IHtmlContentBuilder AppendLine(this IHtmlContentBuilder builder) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + builder.AppendHtml(HtmlString.NewLine); + return builder; + } + + /// + /// Appends an after appending the value. + /// The value is treated as unencoded as-provided, and will be HTML encoded before writing to output. + /// + /// The . + /// The to append. + /// The . + public static IHtmlContentBuilder AppendLine(this IHtmlContentBuilder builder, string unencoded) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + builder.Append(unencoded); + builder.AppendHtml(HtmlString.NewLine); + return builder; + } + + /// + /// Appends an after appending the value. + /// + /// The . + /// The to append. + /// The . + public static IHtmlContentBuilder AppendLine(this IHtmlContentBuilder builder, IHtmlContent content) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + builder.AppendHtml(content); + builder.AppendHtml(HtmlString.NewLine); + return builder; + } + + /// + /// Appends an after appending the value. + /// The value is treated as HTML encoded as-provided, and no further encoding will be performed. + /// + /// The . + /// The HTML encoded to append. + /// The . + public static IHtmlContentBuilder AppendHtmlLine(this IHtmlContentBuilder builder, string encoded) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + builder.AppendHtml(encoded); + builder.AppendHtml(HtmlString.NewLine); + return builder; + } + + /// + /// Sets the content to the value. The value is treated as unencoded as-provided, + /// and will be HTML encoded before writing to output. + /// + /// The . + /// The value that replaces the content. + /// The . + public static IHtmlContentBuilder SetContent(this IHtmlContentBuilder builder, string unencoded) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + builder.Clear(); + builder.Append(unencoded); + return builder; + } + + /// + /// Sets the content to the value. + /// + /// The . + /// The value that replaces the content. + /// The . + public static IHtmlContentBuilder SetHtmlContent(this IHtmlContentBuilder builder, IHtmlContent content) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + builder.Clear(); + builder.AppendHtml(content); + return builder; + } + + /// + /// Sets the content to the value. The value is treated as HTML encoded as-provided, and + /// no further encoding will be performed. + /// + /// The . + /// The HTML encoded that replaces the content. + /// The . + public static IHtmlContentBuilder SetHtmlContent(this IHtmlContentBuilder builder, string encoded) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + builder.Clear(); + builder.AppendHtml(encoded); + return builder; + } + } +} diff --git a/src/Html/Abstractions/src/HtmlFormattableString.cs b/src/Html/Abstractions/src/HtmlFormattableString.cs new file mode 100644 index 0000000000..24bc7c5e2f --- /dev/null +++ b/src/Html/Abstractions/src/HtmlFormattableString.cs @@ -0,0 +1,184 @@ +// 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.Globalization; +using System.IO; +using System.Text.Encodings.Web; + +namespace Microsoft.AspNetCore.Html +{ + /// + /// An implementation of composite string formatting + /// (see https://msdn.microsoft.com/en-us/library/txafckwd(v=vs.110).aspx) which HTML encodes + /// formatted arguments. + /// + [DebuggerDisplay("{DebuggerToString()}")] + public class HtmlFormattableString : IHtmlContent + { + private readonly IFormatProvider _formatProvider; + private readonly string _format; + private readonly object[] _args; + + /// + /// Creates a new with the given and + /// . + /// + /// A composite format string. + /// An array that contains objects to format. + public HtmlFormattableString(string format, params object[] args) + : this(formatProvider: null, format: format, args: args) + { + } + + /// + /// Creates a new with the given , + /// and . + /// + /// An object that provides culture-specific formatting information. + /// A composite format string. + /// An array that contains objects to format. + public HtmlFormattableString(IFormatProvider formatProvider, string format, params object[] args) + { + if (format == null) + { + throw new ArgumentNullException(nameof(format)); + } + + if (args == null) + { + throw new ArgumentNullException(nameof(args)); + } + + _formatProvider = formatProvider ?? CultureInfo.CurrentCulture; + _format = format; + _args = args; + } + + /// + public void WriteTo(TextWriter writer, HtmlEncoder encoder) + { + if (writer == null) + { + throw new ArgumentNullException(nameof(writer)); + } + + if (encoder == null) + { + throw new ArgumentNullException(nameof(encoder)); + } + + var formatProvider = new EncodingFormatProvider(_formatProvider, encoder); + writer.Write(string.Format(formatProvider, _format, _args)); + } + + private string DebuggerToString() + { + using (var writer = new StringWriter()) + { + WriteTo(writer, HtmlEncoder.Default); + return writer.ToString(); + } + } + + // This class implements Html encoding via an ICustomFormatter. Passing an instance of this + // class into a string.Format method or anything similar will evaluate arguments implementing + // IHtmlContent without HTML encoding them, and will give other arguments the standard + // composite format string treatment, and then HTML encode the result. + // + // Plenty of examples of ICustomFormatter and the interactions with string.Format here: + // https://msdn.microsoft.com/en-us/library/system.string.format(v=vs.110).aspx#Format6_Example + private class EncodingFormatProvider : IFormatProvider, ICustomFormatter + { + private readonly HtmlEncoder _encoder; + private readonly IFormatProvider _formatProvider; + + private StringWriter _writer; + + public EncodingFormatProvider(IFormatProvider formatProvider, HtmlEncoder encoder) + { + Debug.Assert(formatProvider != null); + Debug.Assert(encoder != null); + + _formatProvider = formatProvider; + _encoder = encoder; + } + + public string Format(string format, object arg, IFormatProvider formatProvider) + { + // These are the cases we need to special case. We trust the HtmlString or IHtmlContent instance + // to do the right thing with encoding. + var htmlString = arg as HtmlString; + if (htmlString != null) + { + return htmlString.ToString(); + } + + var htmlContent = arg as IHtmlContent; + if (htmlContent != null) + { + _writer = _writer ?? new StringWriter(); + + htmlContent.WriteTo(_writer, _encoder); + + var result = _writer.ToString(); + _writer.GetStringBuilder().Clear(); + + return result; + } + + // If we get here then 'arg' is not an IHtmlContent, and we want to handle it the way a normal + // string.Format would work, but then HTML encode the result. + // + // First check for an ICustomFormatter - if the IFormatProvider is a CultureInfo, then it's likely + // that ICustomFormatter will be null. + var customFormatter = (ICustomFormatter)_formatProvider.GetFormat(typeof(ICustomFormatter)); + if (customFormatter != null) + { + var result = customFormatter.Format(format, arg, _formatProvider); + if (result != null) + { + return _encoder.Encode(result); + } + } + + // Next check if 'arg' is an IFormattable (DateTime is an example). + // + // An IFormattable will likely call back into the IFormatterProvider and ask for more information + // about how to format itself. This is the typical case when IFormatterProvider is a CultureInfo. + var formattable = arg as IFormattable; + if (formattable != null) + { + var result = formattable.ToString(format, _formatProvider); + if (result != null) + { + return _encoder.Encode(result); + } + } + + // If we get here then there's nothing really smart left to try. + if (arg != null) + { + var result = arg.ToString(); + if (result != null) + { + return _encoder.Encode(result); + } + } + + return string.Empty; + } + + public object GetFormat(Type formatType) + { + if (formatType == typeof(ICustomFormatter)) + { + return this; + } + + return null; + } + } + } +} diff --git a/src/Html/Abstractions/src/HtmlString.cs b/src/Html/Abstractions/src/HtmlString.cs new file mode 100644 index 0000000000..e7a516bd04 --- /dev/null +++ b/src/Html/Abstractions/src/HtmlString.cs @@ -0,0 +1,61 @@ +// 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.Text.Encodings.Web; + +namespace Microsoft.AspNetCore.Html +{ + /// + /// An implementation that wraps an HTML encoded . + /// + public class HtmlString : IHtmlContent + { + /// + /// An instance for . + /// + public static readonly HtmlString NewLine = new HtmlString(Environment.NewLine); + + /// + /// An instance for . + /// + public static readonly HtmlString Empty = new HtmlString(string.Empty); + + /// + /// Creates a new . + /// + /// The HTML encoded value. + public HtmlString(string value) + { + Value = value; + } + + /// + /// Gets the HTML encoded value. + /// + public string Value { get; } + + /// + public void WriteTo(TextWriter writer, HtmlEncoder encoder) + { + if (writer == null) + { + throw new ArgumentNullException(nameof(writer)); + } + + if (encoder == null) + { + throw new ArgumentNullException(nameof(encoder)); + } + + writer.Write(Value); + } + + /// + public override string ToString() + { + return Value ?? string.Empty; + } + } +} diff --git a/src/Html/Abstractions/src/IHtmlContent.cs b/src/Html/Abstractions/src/IHtmlContent.cs new file mode 100644 index 0000000000..2e9a0f19e2 --- /dev/null +++ b/src/Html/Abstractions/src/IHtmlContent.cs @@ -0,0 +1,22 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.IO; +using System.Text.Encodings.Web; + +namespace Microsoft.AspNetCore.Html +{ + /// + /// HTML content which can be written to a TextWriter. + /// + public interface IHtmlContent + { + /// + /// Writes the content by encoding it with the specified + /// to the specified . + /// + /// The to which the content is written. + /// The which encodes the content to be written. + void WriteTo(TextWriter writer, HtmlEncoder encoder); + } +} \ No newline at end of file diff --git a/src/Html/Abstractions/src/IHtmlContentBuilder.cs b/src/Html/Abstractions/src/IHtmlContentBuilder.cs new file mode 100644 index 0000000000..912fe442aa --- /dev/null +++ b/src/Html/Abstractions/src/IHtmlContentBuilder.cs @@ -0,0 +1,40 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.AspNetCore.Html +{ + /// + /// A builder for HTML content. + /// + public interface IHtmlContentBuilder : IHtmlContentContainer + { + /// + /// Appends an instance. + /// + /// The to append. + /// The . + IHtmlContentBuilder AppendHtml(IHtmlContent content); + + /// + /// Appends a value. The value is treated as unencoded as-provided, and will be HTML + /// encoded before writing to output. + /// + /// The to append. + /// The . + IHtmlContentBuilder Append(string unencoded); + + /// + /// Appends an HTML encoded value. The value is treated as HTML encoded as-provided, and + /// no further encoding will be performed. + /// + /// The HTML encoded to append. + /// The . + IHtmlContentBuilder AppendHtml(string encoded); + + /// + /// Clears the content. + /// + /// The . + IHtmlContentBuilder Clear(); + } +} diff --git a/src/Html/Abstractions/src/IHtmlContentContainer.cs b/src/Html/Abstractions/src/IHtmlContentContainer.cs new file mode 100644 index 0000000000..f17811433c --- /dev/null +++ b/src/Html/Abstractions/src/IHtmlContentContainer.cs @@ -0,0 +1,30 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.AspNetCore.Html +{ + /// + /// Defines a contract for instances made up of several components which + /// can be copied into an . + /// + public interface IHtmlContentContainer : IHtmlContent + { + /// + /// Copies the contained content of this into . + /// + /// The . + void CopyTo(IHtmlContentBuilder builder); + + /// + /// + /// Moves the contained content of this into . + /// + /// + /// After is called, this instance should be left + /// in an empty state. + /// + /// + /// The . + void MoveTo(IHtmlContentBuilder builder); + } +} diff --git a/src/Html/Abstractions/src/Microsoft.AspNetCore.Html.Abstractions.csproj b/src/Html/Abstractions/src/Microsoft.AspNetCore.Html.Abstractions.csproj new file mode 100644 index 0000000000..f914769d17 --- /dev/null +++ b/src/Html/Abstractions/src/Microsoft.AspNetCore.Html.Abstractions.csproj @@ -0,0 +1,18 @@ + + + + ASP.NET Core HTML abstractions used for building HTML content. + +Commonly used types: +Microsoft.AspNetCore.Html.HtmlString +Microsoft.AspNetCore.Html.IHtmlContent + netstandard2.0 + true + aspnetcore + + + + + + + diff --git a/src/Html/Abstractions/src/Properties/AssemblyInfo.cs b/src/Html/Abstractions/src/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..cb0b47442c --- /dev/null +++ b/src/Html/Abstractions/src/Properties/AssemblyInfo.cs @@ -0,0 +1,8 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Html.Abstractions.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] diff --git a/src/Html/Abstractions/src/baseline.netcore.json b/src/Html/Abstractions/src/baseline.netcore.json new file mode 100644 index 0000000000..29f855f97b --- /dev/null +++ b/src/Html/Abstractions/src/baseline.netcore.json @@ -0,0 +1,626 @@ +{ + "AssemblyIdentity": "Microsoft.AspNetCore.Html.Abstractions, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "Types": [ + { + "Name": "Microsoft.AspNetCore.Html.HtmlContentBuilder", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.Html.IHtmlContentBuilder" + ], + "Members": [ + { + "Kind": "Method", + "Name": "CopyTo", + "Parameters": [ + { + "Name": "destination", + "Type": "Microsoft.AspNetCore.Html.IHtmlContentBuilder" + } + ], + "ReturnType": "System.Void", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Html.IHtmlContentContainer", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "MoveTo", + "Parameters": [ + { + "Name": "destination", + "Type": "Microsoft.AspNetCore.Html.IHtmlContentBuilder" + } + ], + "ReturnType": "System.Void", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Html.IHtmlContentContainer", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "WriteTo", + "Parameters": [ + { + "Name": "writer", + "Type": "System.IO.TextWriter" + }, + { + "Name": "encoder", + "Type": "System.Text.Encodings.Web.HtmlEncoder" + } + ], + "ReturnType": "System.Void", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Html.IHtmlContent", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Count", + "Parameters": [], + "ReturnType": "System.Int32", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Append", + "Parameters": [ + { + "Name": "unencoded", + "Type": "System.String" + } + ], + "ReturnType": "Microsoft.AspNetCore.Html.IHtmlContentBuilder", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Html.IHtmlContentBuilder", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AppendHtml", + "Parameters": [ + { + "Name": "htmlContent", + "Type": "Microsoft.AspNetCore.Html.IHtmlContent" + } + ], + "ReturnType": "Microsoft.AspNetCore.Html.IHtmlContentBuilder", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Html.IHtmlContentBuilder", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AppendHtml", + "Parameters": [ + { + "Name": "encoded", + "Type": "System.String" + } + ], + "ReturnType": "Microsoft.AspNetCore.Html.IHtmlContentBuilder", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Html.IHtmlContentBuilder", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Clear", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Html.IHtmlContentBuilder", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Html.IHtmlContentBuilder", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "capacity", + "Type": "System.Int32" + } + ], + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "entries", + "Type": "System.Collections.Generic.IList" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Html.HtmlContentBuilderExtensions", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "AppendFormat", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Html.IHtmlContentBuilder" + }, + { + "Name": "format", + "Type": "System.String" + }, + { + "Name": "args", + "Type": "System.Object[]", + "IsParams": true + } + ], + "ReturnType": "Microsoft.AspNetCore.Html.IHtmlContentBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AppendFormat", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Html.IHtmlContentBuilder" + }, + { + "Name": "formatProvider", + "Type": "System.IFormatProvider" + }, + { + "Name": "format", + "Type": "System.String" + }, + { + "Name": "args", + "Type": "System.Object[]", + "IsParams": true + } + ], + "ReturnType": "Microsoft.AspNetCore.Html.IHtmlContentBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AppendLine", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Html.IHtmlContentBuilder" + } + ], + "ReturnType": "Microsoft.AspNetCore.Html.IHtmlContentBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AppendLine", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Html.IHtmlContentBuilder" + }, + { + "Name": "unencoded", + "Type": "System.String" + } + ], + "ReturnType": "Microsoft.AspNetCore.Html.IHtmlContentBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AppendLine", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Html.IHtmlContentBuilder" + }, + { + "Name": "content", + "Type": "Microsoft.AspNetCore.Html.IHtmlContent" + } + ], + "ReturnType": "Microsoft.AspNetCore.Html.IHtmlContentBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AppendHtmlLine", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Html.IHtmlContentBuilder" + }, + { + "Name": "encoded", + "Type": "System.String" + } + ], + "ReturnType": "Microsoft.AspNetCore.Html.IHtmlContentBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "SetContent", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Html.IHtmlContentBuilder" + }, + { + "Name": "unencoded", + "Type": "System.String" + } + ], + "ReturnType": "Microsoft.AspNetCore.Html.IHtmlContentBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "SetHtmlContent", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Html.IHtmlContentBuilder" + }, + { + "Name": "content", + "Type": "Microsoft.AspNetCore.Html.IHtmlContent" + } + ], + "ReturnType": "Microsoft.AspNetCore.Html.IHtmlContentBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "SetHtmlContent", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Html.IHtmlContentBuilder" + }, + { + "Name": "encoded", + "Type": "System.String" + } + ], + "ReturnType": "Microsoft.AspNetCore.Html.IHtmlContentBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Html.HtmlFormattableString", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.Html.IHtmlContent" + ], + "Members": [ + { + "Kind": "Method", + "Name": "WriteTo", + "Parameters": [ + { + "Name": "writer", + "Type": "System.IO.TextWriter" + }, + { + "Name": "encoder", + "Type": "System.Text.Encodings.Web.HtmlEncoder" + } + ], + "ReturnType": "System.Void", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Html.IHtmlContent", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "format", + "Type": "System.String" + }, + { + "Name": "args", + "Type": "System.Object[]", + "IsParams": true + } + ], + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "formatProvider", + "Type": "System.IFormatProvider" + }, + { + "Name": "format", + "Type": "System.String" + }, + { + "Name": "args", + "Type": "System.Object[]", + "IsParams": true + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Html.HtmlString", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.Html.IHtmlContent" + ], + "Members": [ + { + "Kind": "Method", + "Name": "get_Value", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "WriteTo", + "Parameters": [ + { + "Name": "writer", + "Type": "System.IO.TextWriter" + }, + { + "Name": "encoder", + "Type": "System.Text.Encodings.Web.HtmlEncoder" + } + ], + "ReturnType": "System.Void", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Html.IHtmlContent", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "ToString", + "Parameters": [], + "ReturnType": "System.String", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "value", + "Type": "System.String" + } + ], + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Field", + "Name": "NewLine", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Html.HtmlString", + "Static": true, + "ReadOnly": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Field", + "Name": "Empty", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Html.HtmlString", + "Static": true, + "ReadOnly": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Html.IHtmlContent", + "Visibility": "Public", + "Kind": "Interface", + "Abstract": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "WriteTo", + "Parameters": [ + { + "Name": "writer", + "Type": "System.IO.TextWriter" + }, + { + "Name": "encoder", + "Type": "System.Text.Encodings.Web.HtmlEncoder" + } + ], + "ReturnType": "System.Void", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Html.IHtmlContentBuilder", + "Visibility": "Public", + "Kind": "Interface", + "Abstract": true, + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.Html.IHtmlContentContainer" + ], + "Members": [ + { + "Kind": "Method", + "Name": "AppendHtml", + "Parameters": [ + { + "Name": "content", + "Type": "Microsoft.AspNetCore.Html.IHtmlContent" + } + ], + "ReturnType": "Microsoft.AspNetCore.Html.IHtmlContentBuilder", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Append", + "Parameters": [ + { + "Name": "unencoded", + "Type": "System.String" + } + ], + "ReturnType": "Microsoft.AspNetCore.Html.IHtmlContentBuilder", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AppendHtml", + "Parameters": [ + { + "Name": "encoded", + "Type": "System.String" + } + ], + "ReturnType": "Microsoft.AspNetCore.Html.IHtmlContentBuilder", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Clear", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Html.IHtmlContentBuilder", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Html.IHtmlContentContainer", + "Visibility": "Public", + "Kind": "Interface", + "Abstract": true, + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.Html.IHtmlContent" + ], + "Members": [ + { + "Kind": "Method", + "Name": "CopyTo", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Html.IHtmlContentBuilder" + } + ], + "ReturnType": "System.Void", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "MoveTo", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Html.IHtmlContentBuilder" + } + ], + "ReturnType": "System.Void", + "GenericParameter": [] + } + ], + "GenericParameters": [] + } + ] +} \ No newline at end of file diff --git a/src/Html/Abstractions/test/HtmlContentBuilderExtensionsTest.cs b/src/Html/Abstractions/test/HtmlContentBuilderExtensionsTest.cs new file mode 100644 index 0000000000..c14daeeebb --- /dev/null +++ b/src/Html/Abstractions/test/HtmlContentBuilderExtensionsTest.cs @@ -0,0 +1,463 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Text.Encodings.Web; +using Microsoft.AspNetCore.Testing; +using Microsoft.Extensions.WebEncoders.Testing; +using Xunit; + +namespace Microsoft.AspNetCore.Html.Test +{ + public class HtmlContentBuilderExtensionsTest + { + [Fact] + public void Builder_AppendLine_Empty() + { + // Arrange + var builder = new TestHtmlContentBuilder(); + + // Act + builder.AppendLine(); + + // Assert + Assert.Collection( + builder.Entries, + entry => Assert.Equal(Environment.NewLine, HtmlContentToString(entry))); + } + + [Fact] + public void Builder_AppendLine_String() + { + // Arrange + var builder = new TestHtmlContentBuilder(); + + // Act + builder.AppendLine("Hi"); + + // Assert + Assert.Collection( + builder.Entries, + entry => Assert.Equal("Hi", Assert.IsType(entry).Value), + entry => Assert.Equal(Environment.NewLine, HtmlContentToString(entry))); + } + + [Fact] + public void Builder_AppendLine_IHtmlContent() + { + // Arrange + var builder = new TestHtmlContentBuilder(); + var content = new OtherHtmlContent("Hi"); + + // Act + builder.AppendLine(content); + + // Assert + Assert.Collection( + builder.Entries, + entry => Assert.Same(content, entry), + entry => Assert.Equal(Environment.NewLine, HtmlContentToString(entry))); + } + + [Fact] + public void Builder_AppendHtmlLine_String() + { + // Arrange + var builder = new TestHtmlContentBuilder(); + + // Act + builder.AppendHtmlLine("Hi"); + + // Assert + Assert.Collection( + builder.Entries, + entry => Assert.Equal("Hi", Assert.IsType(entry).Value), + entry => Assert.Equal(Environment.NewLine, HtmlContentToString(entry))); + } + + [Fact] + public void Builder_SetContent_String() + { + // Arrange + var builder = new TestHtmlContentBuilder(); + builder.Append("Existing Content. Will be Cleared."); + + // Act + builder.SetContent("Hi"); + + // Assert + Assert.Collection( + builder.Entries, + entry => Assert.Equal("Hi", Assert.IsType(entry).Value)); + } + + [Fact] + public void Builder_SetContent_IHtmlContent() + { + // Arrange + var builder = new TestHtmlContentBuilder(); + builder.Append("Existing Content. Will be Cleared."); + + var content = new OtherHtmlContent("Hi"); + + // Act + builder.SetHtmlContent(content); + + // Assert + Assert.Collection( + builder.Entries, + entry => Assert.Same(content, entry)); + } + + [Fact] + public void Builder_SetHtmlContent_String() + { + // Arrange + var builder = new TestHtmlContentBuilder(); + builder.Append("Existing Content. Will be Cleared."); + + // Act + builder.SetHtmlContent("Hi"); + + // Assert + Assert.Collection( + builder.Entries, + entry => Assert.Equal("Hi", Assert.IsType(entry).Value)); + } + + [Fact] + public void Builder_AppendFormat() + { + // Arrange + var builder = new TestHtmlContentBuilder(); + + // Act + builder.AppendFormat("{0} {1} {2} {3}!", "First", "Second", "Third", "Fourth"); + + // Assert + Assert.Equal( + "HtmlEncode[[First]] HtmlEncode[[Second]] HtmlEncode[[Third]] HtmlEncode[[Fourth]]!", + HtmlContentToString(builder)); + } + + [Fact] + public void Builder_AppendFormat_HtmlContent() + { + // Arrange + var builder = new TestHtmlContentBuilder(); + + // Act + builder.AppendFormat("{0}!", new EncodedString("First")); + + // Assert + Assert.Equal( + "First!", + HtmlContentToString(builder)); + } + + [Fact] + public void Builder_AppendFormat_HtmlString() + { + // Arrange + var builder = new TestHtmlContentBuilder(); + + // Act + builder.AppendFormat("{0}!", new HtmlString("First")); + + // Assert + Assert.Equal("First!", HtmlContentToString(builder)); + } + + [Fact] + public void Builder_AppendFormatContent_With1Argument() + { + // Arrange + var builder = new TestHtmlContentBuilder(); + + // Act + builder.AppendFormat("0x{0:X} - hex equivalent for 50.", 50); + + // Assert + Assert.Equal( + "0xHtmlEncode[[32]] - hex equivalent for 50.", + HtmlContentToString(builder)); + } + + [Fact] + public void Builder_AppendFormatContent_With2Arguments() + { + // Arrange + var builder = new TestHtmlContentBuilder(); + + // Act + builder.AppendFormat("0x{0:X} - hex equivalent for {1}.", 50, 50); + + // Assert + Assert.Equal( + "0xHtmlEncode[[32]] - hex equivalent for HtmlEncode[[50]].", + HtmlContentToString(builder)); + } + + [Fact] + public void Builder_AppendFormatContent_With3Arguments() + { + // Arrange + var builder = new TestHtmlContentBuilder(); + + // Act + builder.AppendFormat("0x{0:X} - {1} equivalent for {2}.", 50, "hex", 50); + + // Assert + Assert.Equal( + "0xHtmlEncode[[32]] - HtmlEncode[[hex]] equivalent for HtmlEncode[[50]].", + HtmlContentToString(builder)); + } + + [Fact] + public void Builder_AppendFormat_WithAlignmentComponent() + { + // Arrange + var builder = new TestHtmlContentBuilder(); + + // Act + builder.AppendFormat("{0, -25} World!", "Hello"); + + // Assert + Assert.Equal( + "HtmlEncode[[Hello]] World!", + HtmlContentToString(builder)); + } + + [Fact] + public void Builder_AppendFormat_WithFormatStringComponent() + { + // Arrange + var builder = new TestHtmlContentBuilder(); + + // Act + builder.AppendFormat("0x{0:X}", 50); + + // Assert + Assert.Equal("0xHtmlEncode[[32]]", HtmlContentToString(builder)); + } + + [Fact] + public void Builder_AppendFormat_WithCulture() + { + // Arrange + var builder = new TestHtmlContentBuilder(); + + // Act + builder.AppendFormat( + CultureInfo.InvariantCulture, + "Numbers in InvariantCulture - {0, -5:N} {1} {2} {3}!", + 1.1, + 2.98, + 145.82, + 32.86); + + // Assert + Assert.Equal( + "Numbers in InvariantCulture - HtmlEncode[[1.10]] HtmlEncode[[2.98]] " + + "HtmlEncode[[145.82]] HtmlEncode[[32.86]]!", + HtmlContentToString(builder)); + } + + [Fact] + public void Builder_AppendFormat_WithCulture_1Argument() + { + // Arrange + var builder = new TestHtmlContentBuilder(); + + // Act + builder.AppendFormat( + CultureInfo.InvariantCulture, + "Numbers in InvariantCulture - {0:N}!", + 1.1); + + // Assert + Assert.Equal( + "Numbers in InvariantCulture - HtmlEncode[[1.10]]!", + HtmlContentToString(builder)); + } + + [Fact] + public void Builder_AppendFormat_WithCulture_2Arguments() + { + // Arrange + var builder = new TestHtmlContentBuilder(); + + // Act + builder.AppendFormat( + CultureInfo.InvariantCulture, + "Numbers in InvariantCulture - {0:N} {1}!", + 1.1, + 2.98); + + // Assert + Assert.Equal( + "Numbers in InvariantCulture - HtmlEncode[[1.10]] HtmlEncode[[2.98]]!", + HtmlContentToString(builder)); + } + + [Fact] + public void Builder_AppendFormat_WithCulture_3Arguments() + { + // Arrange + var builder = new TestHtmlContentBuilder(); + + // Act + builder.AppendFormat( + CultureInfo.InvariantCulture, + "Numbers in InvariantCulture - {0:N} {1} {2}!", + 1.1, + 2.98, + 3.12); + + // Assert + Assert.Equal( + "Numbers in InvariantCulture - HtmlEncode[[1.10]] HtmlEncode[[2.98]] HtmlEncode[[3.12]]!", + HtmlContentToString(builder)); + } + + [Fact] + public void Builder_AppendFormat_WithDifferentCulture() + { + // Arrange + var builder = new TestHtmlContentBuilder(); + var culture = new CultureInfo("fr-FR"); + + // Act + builder.AppendFormat(culture, "{0} in french!", 1.21); + + // Assert + Assert.Equal( + "HtmlEncode[[1,21]] in french!", + HtmlContentToString(builder)); + } + + [Fact] + [ReplaceCulture("de-DE", "de-DE")] + public void Builder_AppendFormat_WithDifferentCurrentCulture() + { + // Arrange + var builder = new TestHtmlContentBuilder(); + + // Act + builder.AppendFormat(CultureInfo.CurrentCulture, "{0:D}", DateTime.Parse("01/02/2015")); + + // Assert + Assert.Equal( + "HtmlEncode[[Sonntag, 1. Februar 2015]]", + HtmlContentToString(builder)); + } + + private static string HtmlContentToString(IHtmlContent content) + { + using (var writer = new StringWriter()) + { + content.WriteTo(writer, new HtmlTestEncoder()); + return writer.ToString(); + } + } + + private class TestHtmlContentBuilder : IHtmlContentBuilder + { + public List Entries { get; } = new List(); + + public IHtmlContentBuilder Append(string unencoded) + { + Entries.Add(new UnencodedString(unencoded)); + return this; + } + + public IHtmlContentBuilder AppendHtml(IHtmlContent content) + { + Entries.Add(content); + return this; + } + + public IHtmlContentBuilder AppendHtml(string encoded) + { + Entries.Add(new EncodedString(encoded)); + return this; + } + + public IHtmlContentBuilder Clear() + { + Entries.Clear(); + return this; + } + + public void CopyTo(IHtmlContentBuilder destination) + { + foreach (var entry in Entries) + { + destination.AppendHtml(entry); + } + } + + public void MoveTo(IHtmlContentBuilder destination) + { + CopyTo(destination); + Clear(); + } + + public void WriteTo(TextWriter writer, HtmlEncoder encoder) + { + foreach (var entry in Entries) + { + entry.WriteTo(writer, encoder); + } + } + } + + private class EncodedString : IHtmlContent + { + public EncodedString(string value) + { + Value = value; + } + + public string Value { get; } + + public void WriteTo(TextWriter writer, HtmlEncoder encoder) + { + writer.Write(Value); + } + } + + private class UnencodedString : IHtmlContent + { + public UnencodedString(string value) + { + Value = value; + } + + public string Value { get; } + + public void WriteTo(TextWriter writer, HtmlEncoder encoder) + { + encoder.Encode(writer, Value); + } + } + + private class OtherHtmlContent : IHtmlContent + { + public OtherHtmlContent(string value) + { + Value = value; + } + + public string Value { get; } + + public void WriteTo(TextWriter writer, HtmlEncoder encoder) + { + throw new NotImplementedException(); + } + } + } +} diff --git a/src/Html/Abstractions/test/HtmlContentBuilderTest.cs b/src/Html/Abstractions/test/HtmlContentBuilderTest.cs new file mode 100644 index 0000000000..c3cb7d1954 --- /dev/null +++ b/src/Html/Abstractions/test/HtmlContentBuilderTest.cs @@ -0,0 +1,276 @@ +// 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.Text.Encodings.Web; +using Microsoft.AspNetCore.Html; +using Microsoft.Extensions.WebEncoders.Testing; +using Xunit; + +namespace Microsoft.Extensions.Internal +{ + public class HtmlContentBuilderTest + { + [Fact] + public void AppendString_AppendsAString() + { + // Arrange + var content = new HtmlContentBuilder(); + + // Act + content.Append("Hello"); + + // Assert + Assert.Equal(1, content.Count); + var result = Assert.Single(content.Entries); + Assert.IsType(result); + } + + [Fact] + public void AppendString_WrittenAsEncoded() + { + // Arrange + var content = new HtmlContentBuilder(); + content.Append("Hello"); + + var writer = new StringWriter(); + + // Act + content.WriteTo(writer, new HtmlTestEncoder()); + + // Assert + Assert.Equal("HtmlEncode[[Hello]]", writer.ToString()); + } + + [Fact] + public void AppendHtml_DoesNotGetWrittenAsEncoded() + { + // Arrange + var content = new HtmlContentBuilder(); + content.AppendHtml("Hello"); + + var writer = new StringWriter(); + + // Act + content.WriteTo(writer, new HtmlTestEncoder()); + + // Assert + Assert.Equal("Hello", writer.ToString()); + } + + [Fact] + public void AppendIHtmlContent_AppendsAsIs() + { + // Arrange + var content = new HtmlContentBuilder(); + var writer = new StringWriter(); + + // Act + content.AppendHtml(new TestHtmlContent("Hello")); + + // Assert + Assert.Equal(1, content.Count); + var result = Assert.Single(content.Entries); + var testHtmlContent = Assert.IsType(result); + testHtmlContent.WriteTo(writer, new HtmlTestEncoder()); + Assert.Equal("Written from TestHtmlContent: Hello", writer.ToString()); + } + + [Fact] + public void CanAppendMultipleItems() + { + // Arrange + var content = new HtmlContentBuilder(); + + // Act + content.AppendHtml(new TestHtmlContent("hello")); + content.Append("Test"); + + // Assert + Assert.Equal(2, content.Count); + Assert.Collection( + content.Entries, + entry => Assert.Equal("Written from TestHtmlContent: hello", entry.ToString()), + entry => Assert.Equal("Test", entry)); + } + + [Fact] + public void Clear_DeletesAllItems() + { + // Arrange + var content = new HtmlContentBuilder(); + content.AppendHtml(new TestHtmlContent("hello")); + content.Append("Test"); + + // Act + content.Clear(); + + // Assert + Assert.Equal(0, content.Count); + Assert.Empty(content.Entries); + } + + [Fact] + public void CopyTo_CopiesAllItems() + { + // Arrange + var source = new HtmlContentBuilder(); + source.AppendHtml(new TestHtmlContent("hello")); + source.Append("Test"); + + var destination = new HtmlContentBuilder(); + destination.Append("some-content"); + + // Act + source.CopyTo(destination); + + // Assert + Assert.Equal(2, source.Count); + Assert.Equal(3, destination.Count); + Assert.Collection( + destination.Entries, + entry => Assert.Equal("some-content", Assert.IsType(entry)), + entry => Assert.Equal(new TestHtmlContent("hello"), Assert.IsType(entry)), + entry => Assert.Equal("Test", Assert.IsType(entry))); + } + + [Fact] + public void CopyTo_DoesDeepCopy() + { + // Arrange + var source = new HtmlContentBuilder(); + + var nested = new HtmlContentBuilder(); + source.AppendHtml(nested); + nested.AppendHtml(new TestHtmlContent("hello")); + source.Append("Test"); + + var destination = new HtmlContentBuilder(); + destination.Append("some-content"); + + // Act + source.CopyTo(destination); + + // Assert + Assert.Equal(2, source.Count); + Assert.Equal(1, nested.Count); + Assert.Equal(3, destination.Count); + Assert.Collection( + destination.Entries, + entry => Assert.Equal("some-content", Assert.IsType(entry)), + entry => Assert.Equal(new TestHtmlContent("hello"), Assert.IsType(entry)), + entry => Assert.Equal("Test", Assert.IsType(entry))); + } + + [Fact] + public void MoveTo_CopiesAllItems_AndClears() + { + // Arrange + var source = new HtmlContentBuilder(); + source.AppendHtml(new TestHtmlContent("hello")); + source.Append("Test"); + + var destination = new HtmlContentBuilder(); + destination.Append("some-content"); + + // Act + source.MoveTo(destination); + + // Assert + Assert.Equal(0, source.Count); + Assert.Equal(3, destination.Count); + Assert.Collection( + destination.Entries, + entry => Assert.Equal("some-content", Assert.IsType(entry)), + entry => Assert.Equal(new TestHtmlContent("hello"), Assert.IsType(entry)), + entry => Assert.Equal("Test", Assert.IsType(entry))); + } + + [Fact] + public void MoveTo_DoesDeepMove() + { + // Arrange + var source = new HtmlContentBuilder(); + + var nested = new HtmlContentBuilder(); + source.AppendHtml(nested); + nested.AppendHtml(new TestHtmlContent("hello")); + source.Append("Test"); + + var destination = new HtmlContentBuilder(); + destination.Append("some-content"); + + // Act + source.MoveTo(destination); + + // Assert + Assert.Equal(0, source.Count); + Assert.Equal(0, nested.Count); + Assert.Equal(3, destination.Count); + Assert.Collection( + destination.Entries, + entry => Assert.Equal("some-content", Assert.IsType(entry)), + entry => Assert.Equal(new TestHtmlContent("hello"), Assert.IsType(entry)), + entry => Assert.Equal("Test", Assert.IsType(entry))); + } + + [Fact] + public void WriteTo_WritesAllItems() + { + // Arrange + var content = new HtmlContentBuilder(); + var writer = new StringWriter(); + content.AppendHtml(new TestHtmlContent("Hello")); + content.Append("Test"); + + // Act + content.WriteTo(writer, new HtmlTestEncoder()); + + // Assert + Assert.Equal(2, content.Count); + Assert.Equal("Written from TestHtmlContent: HelloHtmlEncode[[Test]]", writer.ToString()); + } + + private class TestHtmlContent : IHtmlContent, IEquatable + { + private string _content; + + public TestHtmlContent(string content) + { + _content = content; + } + + public void WriteTo(TextWriter writer, HtmlEncoder encoder) + { + writer.Write(ToString()); + } + + public override string ToString() + { + return "Written from TestHtmlContent: " + _content; + } + + public override int GetHashCode() + { + return _content.GetHashCode(); + } + + public override bool Equals(object obj) + { + var other = obj as TestHtmlContent; + if (other != null) + { + return Equals(other); + } + + return base.Equals(obj); + } + + public bool Equals(TestHtmlContent other) + { + return string.Equals(_content, other._content); + } + } + } +} diff --git a/src/Html/Abstractions/test/HtmlFormattableStringTest.cs b/src/Html/Abstractions/test/HtmlFormattableStringTest.cs new file mode 100644 index 0000000000..64e000751e --- /dev/null +++ b/src/Html/Abstractions/test/HtmlFormattableStringTest.cs @@ -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.Globalization; +using System.IO; +using Microsoft.AspNetCore.Testing; +using Microsoft.Extensions.WebEncoders.Testing; +using Xunit; + +namespace Microsoft.AspNetCore.Html +{ + public class HtmlFormattableStringTest + { + [Fact] + public void HtmlFormattableString_EmptyArgs() + { + // Arrange + var formattableString = new HtmlFormattableString("Hello, World!"); + + // Act + var result = HtmlContentToString(formattableString); + + // Assert + Assert.Equal("Hello, World!", result); + } + + [Fact] + public void HtmlFormattableString_EmptyArgsAndCulture() + { + // Arrange + var formattableString = new HtmlFormattableString(CultureInfo.CurrentCulture, "Hello, World!"); + + // Act + var result = HtmlContentToString(formattableString); + + // Assert + Assert.Equal("Hello, World!", result); + } + + [Fact] + public void HtmlFormattableString_MultipleArguments() + { + // Arrange + var formattableString = new HtmlFormattableString("{0} {1} {2} {3}!", "First", "Second", "Third", "Fourth"); + + // Act + var result = HtmlContentToString(formattableString); + + // Assert + Assert.Equal( + "HtmlEncode[[First]] HtmlEncode[[Second]] HtmlEncode[[Third]] HtmlEncode[[Fourth]]!", + result); + } + + [Fact] + public void HtmlFormattableString_WithHtmlString() + { + // Arrange + var formattableString = new HtmlFormattableString("{0}!", new HtmlString("First")); + + // Act + var result = HtmlContentToString(formattableString); + + // Assert + Assert.Equal("First!", result); + } + + [Fact] + public void HtmlFormattableString_WithOtherIHtmlContent() + { + // Arrange + var builder = new HtmlContentBuilder(); + builder.Append("First"); + + var formattableString = new HtmlFormattableString("{0}!", builder); + + // Act + var result = HtmlContentToString(formattableString); + + // Assert + Assert.Equal("HtmlEncode[[First]]!", result); + } + + // This test is needed to ensure the shared StringWriter gets cleared. + [Fact] + public void HtmlFormattableString_WithMultipleHtmlContentArguments() + { + // Arrange + var formattableString = new HtmlFormattableString( + "Happy {0}, {1}!", + new HtmlString("Birthday"), + new HtmlContentBuilder().Append("Billy")); + + // Act + var result = HtmlContentToString(formattableString); + + // Assert + Assert.Equal("Happy Birthday, HtmlEncode[[Billy]]!", result); + } + + [Fact] + public void HtmlFormattableString_WithHtmlString_AndOffset() + { + // Arrange + var formattableString = new HtmlFormattableString("{0, 20}!", new HtmlString("First")); + + // Act + var result = HtmlContentToString(formattableString); + + // Assert + Assert.Equal(" First!", result); + } + + [Fact] + public void HtmlFormattableString_With3Arguments() + { + // Arrange + var formattableString = new HtmlFormattableString("0x{0:X} - {1} equivalent for {2}.", 50, "hex", 50); + + // Act + var result = HtmlContentToString(formattableString); + + // Assert + Assert.Equal( + "0xHtmlEncode[[32]] - HtmlEncode[[hex]] equivalent for HtmlEncode[[50]].", + result); + } + + [Fact] + public void HtmlFormattableString_WithAlignmentComponent() + { + // Arrange + var formattableString = new HtmlFormattableString("{0, -25} World!", "Hello"); + + // Act + var result = HtmlContentToString(formattableString); + + // Assert + Assert.Equal( + "HtmlEncode[[Hello]] World!", result); + } + + [Fact] + public void HtmlFormattableString_WithFormatStringComponent() + { + // Arrange + var formattableString = new HtmlFormattableString("0x{0:X}", 50); + + // Act + var result = HtmlContentToString(formattableString); + + // Assert + Assert.Equal("0xHtmlEncode[[32]]", result); + } + + [Fact] + public void HtmlFormattableString_WithCulture() + { + // Arrange + var formattableString = new HtmlFormattableString( + CultureInfo.InvariantCulture, + "Numbers in InvariantCulture - {0, -5:N} {1} {2} {3}!", + 1.1, + 2.98, + 145.82, + 32.86); + + // Act + var result = HtmlContentToString(formattableString); + + // Assert + Assert.Equal( + "Numbers in InvariantCulture - HtmlEncode[[1.10]] HtmlEncode[[2.98]] " + + "HtmlEncode[[145.82]] HtmlEncode[[32.86]]!", + result); + } + + [Fact] + [ReplaceCulture("en-US", "en-US")] + public void HtmlFormattableString_UsesPassedInCulture() + { + // Arrange + var culture = new CultureInfo("fr-FR"); + var formattableString = new HtmlFormattableString(culture, "{0} in french!", 1.21); + + // Act + var result = HtmlContentToString(formattableString); + + // Assert + Assert.Equal("HtmlEncode[[1,21]] in french!", result); + } + + [Fact] + [ReplaceCulture("de-DE", "de-DE")] + public void HtmlFormattableString_UsesCurrentCulture() + { + // Arrange + var formattableString = new HtmlFormattableString("{0:D}", DateTime.Parse("01/02/2015")); + + // Act + var result = HtmlContentToString(formattableString); + + // Assert + Assert.Equal("HtmlEncode[[Sonntag, 1. Februar 2015]]", result); + } + + private static string HtmlContentToString(IHtmlContent content) + { + using (var writer = new StringWriter()) + { + content.WriteTo(writer, new HtmlTestEncoder()); + return writer.ToString(); + } + } + } +} diff --git a/src/Html/Abstractions/test/Microsoft.AspNetCore.Html.Abstractions.Tests.csproj b/src/Html/Abstractions/test/Microsoft.AspNetCore.Html.Abstractions.Tests.csproj new file mode 100644 index 0000000000..0e77dbbfb3 --- /dev/null +++ b/src/Html/Abstractions/test/Microsoft.AspNetCore.Html.Abstractions.Tests.csproj @@ -0,0 +1,12 @@ + + + + $(StandardTestTfms) + + + + + + + + diff --git a/src/IISIntegration/Directory.Build.props b/src/IISIntegration/Directory.Build.props index 82bbde4ef9..9b394c5bd7 100644 --- a/src/IISIntegration/Directory.Build.props +++ b/src/IISIntegration/Directory.Build.props @@ -6,6 +6,8 @@ + false + true false diff --git a/src/IISIntegration/dependencies.overrides.props b/src/IISIntegration/dependencies.overrides.props index 8fa5d9fc58..5fb926e6f8 100644 --- a/src/IISIntegration/dependencies.overrides.props +++ b/src/IISIntegration/dependencies.overrides.props @@ -2,11 +2,12 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - - 2.2.0-rtm-35665 - 2.2.0-rtm-35665 - 2.2.0-rtm-35665 + + 2.2.0-preview3-35497 + 2.2.0-preview3-35497 + 2.2.0-preview3-35497 + 2.1.0 2.1.0 2.1.0 diff --git a/src/IISIntegration/version.props b/src/IISIntegration/version.props index 26703bffbe..97afbbb038 100644 --- a/src/IISIntegration/version.props +++ b/src/IISIntegration/version.props @@ -3,16 +3,15 @@ 3 0 0 + alpha1 + $([System.DateTime]::Now.ToString('yyMMdd'))-99 $(DotNetMajorVersion).$(DotNetMinorVersion).$(DotNetPatchVersion) 13 $(DotNetMinorVersion) $(DotNetPatchVersion) - alpha1 - ancm-oob - $(VersionPrefix) - $(VersionPrefix)-$(VersionSuffix)-final - t000 - $(VersionSuffix)-$(BuildNumber) + $(VersionPrefix) + $(VersionPrefix)-$(PreReleaseLabel)-$(BuildNumber) + $(PackageVersion) 2.0.0 diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/ANCMPackageResolver/ANCMPackageResolver.csproj b/src/Installers/Windows/AspNetCoreModule-Setup/ANCMPackageResolver/ANCMPackageResolver.csproj index e09c9574bb..c585d69ae2 100644 --- a/src/Installers/Windows/AspNetCoreModule-Setup/ANCMPackageResolver/ANCMPackageResolver.csproj +++ b/src/Installers/Windows/AspNetCoreModule-Setup/ANCMPackageResolver/ANCMPackageResolver.csproj @@ -7,6 +7,7 @@ + @@ -23,4 +24,4 @@ - \ No newline at end of file + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/Directory.Build.props b/src/Installers/Windows/AspNetCoreModule-Setup/Directory.Build.props index 4892060bb8..f6801907b6 100644 --- a/src/Installers/Windows/AspNetCoreModule-Setup/Directory.Build.props +++ b/src/Installers/Windows/AspNetCoreModule-Setup/Directory.Build.props @@ -21,7 +21,7 @@ The actual handler folder version is dependent on the ANCMMsiVersion --> 2.0.0 - + $(RepositoryRoot)src\Installers\Windows\AspNetCoreModule-Setup\ $(AspNetCoreSetupRoot)IIS-Setup\ $(IIS-Setup)IIS-Common\ diff --git a/src/Middleware/Middleware.sln b/src/Middleware/Middleware.sln new file mode 100644 index 0000000000..28a99b57c6 --- /dev/null +++ b/src/Middleware/Middleware.sln @@ -0,0 +1,120 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26124.0 +MinimumVisualStudioVersion = 15.0.26124.0 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WebSockets", "WebSockets", "{E0D9867D-C23D-43EB-8D9C-DE0398A25432}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{A86EE055-ACD3-4BAC-A51D-1B3C71067AE0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EchoApp", "WebSockets\samples\EchoApp\EchoApp.csproj", "{0792C20B-1D18-4D7C-9C0F-A6F45A0F378E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestServer", "WebSockets\samples\TestServer\TestServer.csproj", "{4E5F5FCC-172C-44D9-BEA0-39098A79CD0B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.WebSockets", "WebSockets\src\Microsoft.AspNetCore.WebSockets.csproj", "{BECAA6A1-1AA4-415E-ADF3-07C103333826}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AutobahnTestApp", "WebSockets\test\AutobahnTestApp\AutobahnTestApp.csproj", "{76B25812-AAFB-45BA-A71A-24F0C654ADFB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.WebSockets.ConformanceTests", "WebSockets\test\ConformanceTests\Microsoft.AspNetCore.WebSockets.ConformanceTests.csproj", "{88BDEE69-4DE3-40B5-A478-677EA355FB52}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.WebSockets.Tests", "WebSockets\test\UnitTests\Microsoft.AspNetCore.WebSockets.Tests.csproj", "{93970702-1BDB-4A8C-B7F6-020294464BB6}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0792C20B-1D18-4D7C-9C0F-A6F45A0F378E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0792C20B-1D18-4D7C-9C0F-A6F45A0F378E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0792C20B-1D18-4D7C-9C0F-A6F45A0F378E}.Debug|x64.ActiveCfg = Debug|Any CPU + {0792C20B-1D18-4D7C-9C0F-A6F45A0F378E}.Debug|x64.Build.0 = Debug|Any CPU + {0792C20B-1D18-4D7C-9C0F-A6F45A0F378E}.Debug|x86.ActiveCfg = Debug|Any CPU + {0792C20B-1D18-4D7C-9C0F-A6F45A0F378E}.Debug|x86.Build.0 = Debug|Any CPU + {0792C20B-1D18-4D7C-9C0F-A6F45A0F378E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0792C20B-1D18-4D7C-9C0F-A6F45A0F378E}.Release|Any CPU.Build.0 = Release|Any CPU + {0792C20B-1D18-4D7C-9C0F-A6F45A0F378E}.Release|x64.ActiveCfg = Release|Any CPU + {0792C20B-1D18-4D7C-9C0F-A6F45A0F378E}.Release|x64.Build.0 = Release|Any CPU + {0792C20B-1D18-4D7C-9C0F-A6F45A0F378E}.Release|x86.ActiveCfg = Release|Any CPU + {0792C20B-1D18-4D7C-9C0F-A6F45A0F378E}.Release|x86.Build.0 = Release|Any CPU + {4E5F5FCC-172C-44D9-BEA0-39098A79CD0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4E5F5FCC-172C-44D9-BEA0-39098A79CD0B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4E5F5FCC-172C-44D9-BEA0-39098A79CD0B}.Debug|x64.ActiveCfg = Debug|Any CPU + {4E5F5FCC-172C-44D9-BEA0-39098A79CD0B}.Debug|x64.Build.0 = Debug|Any CPU + {4E5F5FCC-172C-44D9-BEA0-39098A79CD0B}.Debug|x86.ActiveCfg = Debug|Any CPU + {4E5F5FCC-172C-44D9-BEA0-39098A79CD0B}.Debug|x86.Build.0 = Debug|Any CPU + {4E5F5FCC-172C-44D9-BEA0-39098A79CD0B}.Release|Any CPU.ActiveCfg = Debug|Any CPU + {4E5F5FCC-172C-44D9-BEA0-39098A79CD0B}.Release|Any CPU.Build.0 = Debug|Any CPU + {4E5F5FCC-172C-44D9-BEA0-39098A79CD0B}.Release|x64.ActiveCfg = Debug|Any CPU + {4E5F5FCC-172C-44D9-BEA0-39098A79CD0B}.Release|x64.Build.0 = Debug|Any CPU + {4E5F5FCC-172C-44D9-BEA0-39098A79CD0B}.Release|x86.ActiveCfg = Debug|Any CPU + {4E5F5FCC-172C-44D9-BEA0-39098A79CD0B}.Release|x86.Build.0 = Debug|Any CPU + {BECAA6A1-1AA4-415E-ADF3-07C103333826}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BECAA6A1-1AA4-415E-ADF3-07C103333826}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BECAA6A1-1AA4-415E-ADF3-07C103333826}.Debug|x64.ActiveCfg = Debug|Any CPU + {BECAA6A1-1AA4-415E-ADF3-07C103333826}.Debug|x64.Build.0 = Debug|Any CPU + {BECAA6A1-1AA4-415E-ADF3-07C103333826}.Debug|x86.ActiveCfg = Debug|Any CPU + {BECAA6A1-1AA4-415E-ADF3-07C103333826}.Debug|x86.Build.0 = Debug|Any CPU + {BECAA6A1-1AA4-415E-ADF3-07C103333826}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BECAA6A1-1AA4-415E-ADF3-07C103333826}.Release|Any CPU.Build.0 = Release|Any CPU + {BECAA6A1-1AA4-415E-ADF3-07C103333826}.Release|x64.ActiveCfg = Release|Any CPU + {BECAA6A1-1AA4-415E-ADF3-07C103333826}.Release|x64.Build.0 = Release|Any CPU + {BECAA6A1-1AA4-415E-ADF3-07C103333826}.Release|x86.ActiveCfg = Release|Any CPU + {BECAA6A1-1AA4-415E-ADF3-07C103333826}.Release|x86.Build.0 = Release|Any CPU + {76B25812-AAFB-45BA-A71A-24F0C654ADFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {76B25812-AAFB-45BA-A71A-24F0C654ADFB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {76B25812-AAFB-45BA-A71A-24F0C654ADFB}.Debug|x64.ActiveCfg = Debug|Any CPU + {76B25812-AAFB-45BA-A71A-24F0C654ADFB}.Debug|x64.Build.0 = Debug|Any CPU + {76B25812-AAFB-45BA-A71A-24F0C654ADFB}.Debug|x86.ActiveCfg = Debug|Any CPU + {76B25812-AAFB-45BA-A71A-24F0C654ADFB}.Debug|x86.Build.0 = Debug|Any CPU + {76B25812-AAFB-45BA-A71A-24F0C654ADFB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {76B25812-AAFB-45BA-A71A-24F0C654ADFB}.Release|Any CPU.Build.0 = Release|Any CPU + {76B25812-AAFB-45BA-A71A-24F0C654ADFB}.Release|x64.ActiveCfg = Release|Any CPU + {76B25812-AAFB-45BA-A71A-24F0C654ADFB}.Release|x64.Build.0 = Release|Any CPU + {76B25812-AAFB-45BA-A71A-24F0C654ADFB}.Release|x86.ActiveCfg = Release|Any CPU + {76B25812-AAFB-45BA-A71A-24F0C654ADFB}.Release|x86.Build.0 = Release|Any CPU + {88BDEE69-4DE3-40B5-A478-677EA355FB52}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {88BDEE69-4DE3-40B5-A478-677EA355FB52}.Debug|Any CPU.Build.0 = Debug|Any CPU + {88BDEE69-4DE3-40B5-A478-677EA355FB52}.Debug|x64.ActiveCfg = Debug|Any CPU + {88BDEE69-4DE3-40B5-A478-677EA355FB52}.Debug|x64.Build.0 = Debug|Any CPU + {88BDEE69-4DE3-40B5-A478-677EA355FB52}.Debug|x86.ActiveCfg = Debug|Any CPU + {88BDEE69-4DE3-40B5-A478-677EA355FB52}.Debug|x86.Build.0 = Debug|Any CPU + {88BDEE69-4DE3-40B5-A478-677EA355FB52}.Release|Any CPU.ActiveCfg = Release|Any CPU + {88BDEE69-4DE3-40B5-A478-677EA355FB52}.Release|Any CPU.Build.0 = Release|Any CPU + {88BDEE69-4DE3-40B5-A478-677EA355FB52}.Release|x64.ActiveCfg = Release|Any CPU + {88BDEE69-4DE3-40B5-A478-677EA355FB52}.Release|x64.Build.0 = Release|Any CPU + {88BDEE69-4DE3-40B5-A478-677EA355FB52}.Release|x86.ActiveCfg = Release|Any CPU + {88BDEE69-4DE3-40B5-A478-677EA355FB52}.Release|x86.Build.0 = Release|Any CPU + {93970702-1BDB-4A8C-B7F6-020294464BB6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {93970702-1BDB-4A8C-B7F6-020294464BB6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {93970702-1BDB-4A8C-B7F6-020294464BB6}.Debug|x64.ActiveCfg = Debug|Any CPU + {93970702-1BDB-4A8C-B7F6-020294464BB6}.Debug|x64.Build.0 = Debug|Any CPU + {93970702-1BDB-4A8C-B7F6-020294464BB6}.Debug|x86.ActiveCfg = Debug|Any CPU + {93970702-1BDB-4A8C-B7F6-020294464BB6}.Debug|x86.Build.0 = Debug|Any CPU + {93970702-1BDB-4A8C-B7F6-020294464BB6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {93970702-1BDB-4A8C-B7F6-020294464BB6}.Release|Any CPU.Build.0 = Release|Any CPU + {93970702-1BDB-4A8C-B7F6-020294464BB6}.Release|x64.ActiveCfg = Release|Any CPU + {93970702-1BDB-4A8C-B7F6-020294464BB6}.Release|x64.Build.0 = Release|Any CPU + {93970702-1BDB-4A8C-B7F6-020294464BB6}.Release|x86.ActiveCfg = Release|Any CPU + {93970702-1BDB-4A8C-B7F6-020294464BB6}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {A86EE055-ACD3-4BAC-A51D-1B3C71067AE0} = {E0D9867D-C23D-43EB-8D9C-DE0398A25432} + {0792C20B-1D18-4D7C-9C0F-A6F45A0F378E} = {A86EE055-ACD3-4BAC-A51D-1B3C71067AE0} + {4E5F5FCC-172C-44D9-BEA0-39098A79CD0B} = {A86EE055-ACD3-4BAC-A51D-1B3C71067AE0} + {BECAA6A1-1AA4-415E-ADF3-07C103333826} = {E0D9867D-C23D-43EB-8D9C-DE0398A25432} + {76B25812-AAFB-45BA-A71A-24F0C654ADFB} = {E0D9867D-C23D-43EB-8D9C-DE0398A25432} + {88BDEE69-4DE3-40B5-A478-677EA355FB52} = {E0D9867D-C23D-43EB-8D9C-DE0398A25432} + {93970702-1BDB-4A8C-B7F6-020294464BB6} = {E0D9867D-C23D-43EB-8D9C-DE0398A25432} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {83786312-A93B-4BB4-AB06-7C6913A59AFA} + EndGlobalSection +EndGlobal diff --git a/src/Middleware/WebSockets/README.md b/src/Middleware/WebSockets/README.md new file mode 100644 index 0000000000..19061a2ad5 --- /dev/null +++ b/src/Middleware/WebSockets/README.md @@ -0,0 +1,12 @@ +WebSockets +========== + +Contains a managed implementation of the WebSocket protocol, along with server integration components. + +## System Requirements + +This repo has a few special system requirements/prerequisites. + +1. Windows IIS Express tests require IIS Express 10 and Windows 8 for WebSockets support +2. HttpListener/ASP.NET 4.6 samples require at least Windows 8 +3. Autobahn Test Suite requires special installation see the README.md in [test/AutobahnTestApp](./test/AutobahnTestApp/README.md) diff --git a/src/WebSockets/samples/AutobahnTestAppAspNet4/AutobahnTestAppAspNet4.csproj.aspnet4 b/src/Middleware/WebSockets/samples/AutobahnTestAppAspNet4/AutobahnTestAppAspNet4.csproj.aspnet4 similarity index 100% rename from src/WebSockets/samples/AutobahnTestAppAspNet4/AutobahnTestAppAspNet4.csproj.aspnet4 rename to src/Middleware/WebSockets/samples/AutobahnTestAppAspNet4/AutobahnTestAppAspNet4.csproj.aspnet4 diff --git a/src/WebSockets/samples/AutobahnTestAppAspNet4/EchoSocket.ashx b/src/Middleware/WebSockets/samples/AutobahnTestAppAspNet4/EchoSocket.ashx similarity index 100% rename from src/WebSockets/samples/AutobahnTestAppAspNet4/EchoSocket.ashx rename to src/Middleware/WebSockets/samples/AutobahnTestAppAspNet4/EchoSocket.ashx diff --git a/src/WebSockets/samples/AutobahnTestAppAspNet4/EchoSocket.ashx.cs b/src/Middleware/WebSockets/samples/AutobahnTestAppAspNet4/EchoSocket.ashx.cs similarity index 100% rename from src/WebSockets/samples/AutobahnTestAppAspNet4/EchoSocket.ashx.cs rename to src/Middleware/WebSockets/samples/AutobahnTestAppAspNet4/EchoSocket.ashx.cs diff --git a/src/WebSockets/samples/AutobahnTestAppAspNet4/Properties/AssemblyInfo.cs b/src/Middleware/WebSockets/samples/AutobahnTestAppAspNet4/Properties/AssemblyInfo.cs similarity index 100% rename from src/WebSockets/samples/AutobahnTestAppAspNet4/Properties/AssemblyInfo.cs rename to src/Middleware/WebSockets/samples/AutobahnTestAppAspNet4/Properties/AssemblyInfo.cs diff --git a/src/WebSockets/samples/AutobahnTestAppAspNet4/Web.Debug.config b/src/Middleware/WebSockets/samples/AutobahnTestAppAspNet4/Web.Debug.config similarity index 100% rename from src/WebSockets/samples/AutobahnTestAppAspNet4/Web.Debug.config rename to src/Middleware/WebSockets/samples/AutobahnTestAppAspNet4/Web.Debug.config diff --git a/src/WebSockets/samples/AutobahnTestAppAspNet4/Web.Release.config b/src/Middleware/WebSockets/samples/AutobahnTestAppAspNet4/Web.Release.config similarity index 100% rename from src/WebSockets/samples/AutobahnTestAppAspNet4/Web.Release.config rename to src/Middleware/WebSockets/samples/AutobahnTestAppAspNet4/Web.Release.config diff --git a/src/WebSockets/samples/AutobahnTestAppAspNet4/Web.config b/src/Middleware/WebSockets/samples/AutobahnTestAppAspNet4/Web.config similarity index 100% rename from src/WebSockets/samples/AutobahnTestAppAspNet4/Web.config rename to src/Middleware/WebSockets/samples/AutobahnTestAppAspNet4/Web.config diff --git a/src/WebSockets/samples/AutobahnTestAppAspNet4/packages.config b/src/Middleware/WebSockets/samples/AutobahnTestAppAspNet4/packages.config similarity index 100% rename from src/WebSockets/samples/AutobahnTestAppAspNet4/packages.config rename to src/Middleware/WebSockets/samples/AutobahnTestAppAspNet4/packages.config diff --git a/src/WebSockets/samples/AutobahnTestAppAspNet4/wstest-spec.json b/src/Middleware/WebSockets/samples/AutobahnTestAppAspNet4/wstest-spec.json similarity index 100% rename from src/WebSockets/samples/AutobahnTestAppAspNet4/wstest-spec.json rename to src/Middleware/WebSockets/samples/AutobahnTestAppAspNet4/wstest-spec.json diff --git a/src/WebSockets/samples/AutobahnTestAppHttpListener/App.config b/src/Middleware/WebSockets/samples/AutobahnTestAppHttpListener/App.config similarity index 100% rename from src/WebSockets/samples/AutobahnTestAppHttpListener/App.config rename to src/Middleware/WebSockets/samples/AutobahnTestAppHttpListener/App.config diff --git a/src/WebSockets/samples/AutobahnTestAppHttpListener/AutobahnTestAppHttpListener.csproj.net461 b/src/Middleware/WebSockets/samples/AutobahnTestAppHttpListener/AutobahnTestAppHttpListener.csproj.net461 similarity index 100% rename from src/WebSockets/samples/AutobahnTestAppHttpListener/AutobahnTestAppHttpListener.csproj.net461 rename to src/Middleware/WebSockets/samples/AutobahnTestAppHttpListener/AutobahnTestAppHttpListener.csproj.net461 diff --git a/src/WebSockets/samples/AutobahnTestAppHttpListener/Program.cs b/src/Middleware/WebSockets/samples/AutobahnTestAppHttpListener/Program.cs similarity index 100% rename from src/WebSockets/samples/AutobahnTestAppHttpListener/Program.cs rename to src/Middleware/WebSockets/samples/AutobahnTestAppHttpListener/Program.cs diff --git a/src/WebSockets/samples/AutobahnTestAppHttpListener/Properties/AssemblyInfo.cs b/src/Middleware/WebSockets/samples/AutobahnTestAppHttpListener/Properties/AssemblyInfo.cs similarity index 100% rename from src/WebSockets/samples/AutobahnTestAppHttpListener/Properties/AssemblyInfo.cs rename to src/Middleware/WebSockets/samples/AutobahnTestAppHttpListener/Properties/AssemblyInfo.cs diff --git a/src/Middleware/WebSockets/samples/EchoApp/EchoApp.csproj b/src/Middleware/WebSockets/samples/EchoApp/EchoApp.csproj new file mode 100644 index 0000000000..7ea4ba53b0 --- /dev/null +++ b/src/Middleware/WebSockets/samples/EchoApp/EchoApp.csproj @@ -0,0 +1,16 @@ + + + + netcoreapp2.2;net461 + + + + + + + + + + + + diff --git a/src/WebSockets/samples/EchoApp/Program.cs b/src/Middleware/WebSockets/samples/EchoApp/Program.cs similarity index 100% rename from src/WebSockets/samples/EchoApp/Program.cs rename to src/Middleware/WebSockets/samples/EchoApp/Program.cs diff --git a/src/WebSockets/samples/EchoApp/Properties/launchSettings.json b/src/Middleware/WebSockets/samples/EchoApp/Properties/launchSettings.json similarity index 100% rename from src/WebSockets/samples/EchoApp/Properties/launchSettings.json rename to src/Middleware/WebSockets/samples/EchoApp/Properties/launchSettings.json diff --git a/src/WebSockets/samples/EchoApp/Startup.cs b/src/Middleware/WebSockets/samples/EchoApp/Startup.cs similarity index 100% rename from src/WebSockets/samples/EchoApp/Startup.cs rename to src/Middleware/WebSockets/samples/EchoApp/Startup.cs diff --git a/src/WebSockets/samples/EchoApp/wwwroot/index.html b/src/Middleware/WebSockets/samples/EchoApp/wwwroot/index.html similarity index 100% rename from src/WebSockets/samples/EchoApp/wwwroot/index.html rename to src/Middleware/WebSockets/samples/EchoApp/wwwroot/index.html diff --git a/src/WebSockets/samples/TestServer/App.config b/src/Middleware/WebSockets/samples/TestServer/App.config similarity index 100% rename from src/WebSockets/samples/TestServer/App.config rename to src/Middleware/WebSockets/samples/TestServer/App.config diff --git a/src/WebSockets/samples/TestServer/Program.cs b/src/Middleware/WebSockets/samples/TestServer/Program.cs similarity index 100% rename from src/WebSockets/samples/TestServer/Program.cs rename to src/Middleware/WebSockets/samples/TestServer/Program.cs diff --git a/src/WebSockets/samples/TestServer/Properties/AssemblyInfo.cs b/src/Middleware/WebSockets/samples/TestServer/Properties/AssemblyInfo.cs similarity index 100% rename from src/WebSockets/samples/TestServer/Properties/AssemblyInfo.cs rename to src/Middleware/WebSockets/samples/TestServer/Properties/AssemblyInfo.cs diff --git a/src/WebSockets/samples/TestServer/TestServer.csproj b/src/Middleware/WebSockets/samples/TestServer/TestServer.csproj similarity index 100% rename from src/WebSockets/samples/TestServer/TestServer.csproj rename to src/Middleware/WebSockets/samples/TestServer/TestServer.csproj diff --git a/src/WebSockets/build/setup-wstest.ps1 b/src/Middleware/WebSockets/setup-wstest.ps1 similarity index 100% rename from src/WebSockets/build/setup-wstest.ps1 rename to src/Middleware/WebSockets/setup-wstest.ps1 diff --git a/src/WebSockets/build/setup-wstest.sh b/src/Middleware/WebSockets/setup-wstest.sh old mode 100755 new mode 100644 similarity index 100% rename from src/WebSockets/build/setup-wstest.sh rename to src/Middleware/WebSockets/setup-wstest.sh diff --git a/src/WebSockets/src/Microsoft.AspNetCore.WebSockets/ExtendedWebSocketAcceptContext.cs b/src/Middleware/WebSockets/src/ExtendedWebSocketAcceptContext.cs similarity index 100% rename from src/WebSockets/src/Microsoft.AspNetCore.WebSockets/ExtendedWebSocketAcceptContext.cs rename to src/Middleware/WebSockets/src/ExtendedWebSocketAcceptContext.cs diff --git a/src/WebSockets/src/Microsoft.AspNetCore.WebSockets/Internal/Constants.cs b/src/Middleware/WebSockets/src/Internal/Constants.cs similarity index 100% rename from src/WebSockets/src/Microsoft.AspNetCore.WebSockets/Internal/Constants.cs rename to src/Middleware/WebSockets/src/Internal/Constants.cs diff --git a/src/WebSockets/src/Microsoft.AspNetCore.WebSockets/Internal/HandshakeHelpers.cs b/src/Middleware/WebSockets/src/Internal/HandshakeHelpers.cs similarity index 100% rename from src/WebSockets/src/Microsoft.AspNetCore.WebSockets/Internal/HandshakeHelpers.cs rename to src/Middleware/WebSockets/src/Internal/HandshakeHelpers.cs diff --git a/src/Middleware/WebSockets/src/Microsoft.AspNetCore.WebSockets.csproj b/src/Middleware/WebSockets/src/Microsoft.AspNetCore.WebSockets.csproj new file mode 100644 index 0000000000..12c92f3d55 --- /dev/null +++ b/src/Middleware/WebSockets/src/Microsoft.AspNetCore.WebSockets.csproj @@ -0,0 +1,19 @@ + + + + ASP.NET Core web socket middleware for use on top of opaque servers. + netstandard2.0 + $(NoWarn);CS1591 + true + true + aspnetcore + + + + + + + + + + diff --git a/src/WebSockets/src/Microsoft.AspNetCore.WebSockets/WebSocketMiddleware.cs b/src/Middleware/WebSockets/src/WebSocketMiddleware.cs similarity index 100% rename from src/WebSockets/src/Microsoft.AspNetCore.WebSockets/WebSocketMiddleware.cs rename to src/Middleware/WebSockets/src/WebSocketMiddleware.cs diff --git a/src/WebSockets/src/Microsoft.AspNetCore.WebSockets/WebSocketMiddlewareExtensions.cs b/src/Middleware/WebSockets/src/WebSocketMiddlewareExtensions.cs similarity index 100% rename from src/WebSockets/src/Microsoft.AspNetCore.WebSockets/WebSocketMiddlewareExtensions.cs rename to src/Middleware/WebSockets/src/WebSocketMiddlewareExtensions.cs diff --git a/src/WebSockets/src/Microsoft.AspNetCore.WebSockets/WebSocketOptions.cs b/src/Middleware/WebSockets/src/WebSocketOptions.cs similarity index 100% rename from src/WebSockets/src/Microsoft.AspNetCore.WebSockets/WebSocketOptions.cs rename to src/Middleware/WebSockets/src/WebSocketOptions.cs diff --git a/src/WebSockets/src/Microsoft.AspNetCore.WebSockets/WebSocketsDependencyInjectionExtensions.cs b/src/Middleware/WebSockets/src/WebSocketsDependencyInjectionExtensions.cs similarity index 100% rename from src/WebSockets/src/Microsoft.AspNetCore.WebSockets/WebSocketsDependencyInjectionExtensions.cs rename to src/Middleware/WebSockets/src/WebSocketsDependencyInjectionExtensions.cs diff --git a/src/WebSockets/src/Microsoft.AspNetCore.WebSockets/baseline.netcore.json b/src/Middleware/WebSockets/src/baseline.netcore.json similarity index 100% rename from src/WebSockets/src/Microsoft.AspNetCore.WebSockets/baseline.netcore.json rename to src/Middleware/WebSockets/src/baseline.netcore.json diff --git a/src/WebSockets/test/AutobahnTestApp/AutobahnTestApp.csproj b/src/Middleware/WebSockets/test/AutobahnTestApp/AutobahnTestApp.csproj similarity index 70% rename from src/WebSockets/test/AutobahnTestApp/AutobahnTestApp.csproj rename to src/Middleware/WebSockets/test/AutobahnTestApp/AutobahnTestApp.csproj index 8f470696bc..43595a6d8c 100644 --- a/src/WebSockets/test/AutobahnTestApp/AutobahnTestApp.csproj +++ b/src/Middleware/WebSockets/test/AutobahnTestApp/AutobahnTestApp.csproj @@ -1,7 +1,8 @@ - netcoreapp2.2 + netcoreapp2.2 + true @@ -9,21 +10,20 @@ - + + + + + + + + + + - - - - - - - - - - diff --git a/src/WebSockets/test/AutobahnTestApp/Program.cs b/src/Middleware/WebSockets/test/AutobahnTestApp/Program.cs similarity index 100% rename from src/WebSockets/test/AutobahnTestApp/Program.cs rename to src/Middleware/WebSockets/test/AutobahnTestApp/Program.cs diff --git a/src/WebSockets/test/AutobahnTestApp/Properties/launchSettings.json b/src/Middleware/WebSockets/test/AutobahnTestApp/Properties/launchSettings.json similarity index 100% rename from src/WebSockets/test/AutobahnTestApp/Properties/launchSettings.json rename to src/Middleware/WebSockets/test/AutobahnTestApp/Properties/launchSettings.json diff --git a/src/WebSockets/test/AutobahnTestApp/README.md b/src/Middleware/WebSockets/test/AutobahnTestApp/README.md similarity index 100% rename from src/WebSockets/test/AutobahnTestApp/README.md rename to src/Middleware/WebSockets/test/AutobahnTestApp/README.md diff --git a/src/WebSockets/test/AutobahnTestApp/Startup.cs b/src/Middleware/WebSockets/test/AutobahnTestApp/Startup.cs similarity index 100% rename from src/WebSockets/test/AutobahnTestApp/Startup.cs rename to src/Middleware/WebSockets/test/AutobahnTestApp/Startup.cs diff --git a/src/WebSockets/test/AutobahnTestApp/TestResources/testCert.pfx b/src/Middleware/WebSockets/test/AutobahnTestApp/TestResources/testCert.pfx similarity index 100% rename from src/WebSockets/test/AutobahnTestApp/TestResources/testCert.pfx rename to src/Middleware/WebSockets/test/AutobahnTestApp/TestResources/testCert.pfx diff --git a/src/WebSockets/test/AutobahnTestApp/TestResources/testCert.txt b/src/Middleware/WebSockets/test/AutobahnTestApp/TestResources/testCert.txt similarity index 100% rename from src/WebSockets/test/AutobahnTestApp/TestResources/testCert.txt rename to src/Middleware/WebSockets/test/AutobahnTestApp/TestResources/testCert.txt diff --git a/src/WebSockets/test/AutobahnTestApp/scripts/RunAutobahnTests.ps1 b/src/Middleware/WebSockets/test/AutobahnTestApp/scripts/RunAutobahnTests.ps1 similarity index 100% rename from src/WebSockets/test/AutobahnTestApp/scripts/RunAutobahnTests.ps1 rename to src/Middleware/WebSockets/test/AutobahnTestApp/scripts/RunAutobahnTests.ps1 diff --git a/src/WebSockets/test/AutobahnTestApp/scripts/autobahn.spec.json b/src/Middleware/WebSockets/test/AutobahnTestApp/scripts/autobahn.spec.json similarity index 100% rename from src/WebSockets/test/AutobahnTestApp/scripts/autobahn.spec.json rename to src/Middleware/WebSockets/test/AutobahnTestApp/scripts/autobahn.spec.json diff --git a/src/WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest/Autobahn/AutobahnCaseResult.cs b/src/Middleware/WebSockets/test/ConformanceTests/Autobahn/AutobahnCaseResult.cs similarity index 100% rename from src/WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest/Autobahn/AutobahnCaseResult.cs rename to src/Middleware/WebSockets/test/ConformanceTests/Autobahn/AutobahnCaseResult.cs diff --git a/src/WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest/Autobahn/AutobahnExpectations.cs b/src/Middleware/WebSockets/test/ConformanceTests/Autobahn/AutobahnExpectations.cs similarity index 100% rename from src/WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest/Autobahn/AutobahnExpectations.cs rename to src/Middleware/WebSockets/test/ConformanceTests/Autobahn/AutobahnExpectations.cs diff --git a/src/WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest/Autobahn/AutobahnResult.cs b/src/Middleware/WebSockets/test/ConformanceTests/Autobahn/AutobahnResult.cs similarity index 100% rename from src/WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest/Autobahn/AutobahnResult.cs rename to src/Middleware/WebSockets/test/ConformanceTests/Autobahn/AutobahnResult.cs diff --git a/src/WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest/Autobahn/AutobahnServerResult.cs b/src/Middleware/WebSockets/test/ConformanceTests/Autobahn/AutobahnServerResult.cs similarity index 100% rename from src/WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest/Autobahn/AutobahnServerResult.cs rename to src/Middleware/WebSockets/test/ConformanceTests/Autobahn/AutobahnServerResult.cs diff --git a/src/WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest/Autobahn/AutobahnSpec.cs b/src/Middleware/WebSockets/test/ConformanceTests/Autobahn/AutobahnSpec.cs similarity index 100% rename from src/WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest/Autobahn/AutobahnSpec.cs rename to src/Middleware/WebSockets/test/ConformanceTests/Autobahn/AutobahnSpec.cs diff --git a/src/WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest/Autobahn/AutobahnTester.cs b/src/Middleware/WebSockets/test/ConformanceTests/Autobahn/AutobahnTester.cs similarity index 100% rename from src/WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest/Autobahn/AutobahnTester.cs rename to src/Middleware/WebSockets/test/ConformanceTests/Autobahn/AutobahnTester.cs diff --git a/src/WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest/Autobahn/Executable.cs b/src/Middleware/WebSockets/test/ConformanceTests/Autobahn/Executable.cs similarity index 100% rename from src/WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest/Autobahn/Executable.cs rename to src/Middleware/WebSockets/test/ConformanceTests/Autobahn/Executable.cs diff --git a/src/WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest/Autobahn/Expectation.cs b/src/Middleware/WebSockets/test/ConformanceTests/Autobahn/Expectation.cs similarity index 100% rename from src/WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest/Autobahn/Expectation.cs rename to src/Middleware/WebSockets/test/ConformanceTests/Autobahn/Expectation.cs diff --git a/src/WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest/Autobahn/ServerSpec.cs b/src/Middleware/WebSockets/test/ConformanceTests/Autobahn/ServerSpec.cs similarity index 100% rename from src/WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest/Autobahn/ServerSpec.cs rename to src/Middleware/WebSockets/test/ConformanceTests/Autobahn/ServerSpec.cs diff --git a/src/WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest/Autobahn/Wstest.cs b/src/Middleware/WebSockets/test/ConformanceTests/Autobahn/Wstest.cs similarity index 100% rename from src/WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest/Autobahn/Wstest.cs rename to src/Middleware/WebSockets/test/ConformanceTests/Autobahn/Wstest.cs diff --git a/src/WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest/AutobahnTests.cs b/src/Middleware/WebSockets/test/ConformanceTests/AutobahnTests.cs similarity index 100% rename from src/WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest/AutobahnTests.cs rename to src/Middleware/WebSockets/test/ConformanceTests/AutobahnTests.cs diff --git a/src/WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest/Helpers.cs b/src/Middleware/WebSockets/test/ConformanceTests/Helpers.cs similarity index 100% rename from src/WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest/Helpers.cs rename to src/Middleware/WebSockets/test/ConformanceTests/Helpers.cs diff --git a/src/WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest/Http.config b/src/Middleware/WebSockets/test/ConformanceTests/Http.config similarity index 100% rename from src/WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest/Http.config rename to src/Middleware/WebSockets/test/ConformanceTests/Http.config diff --git a/src/Middleware/WebSockets/test/ConformanceTests/Microsoft.AspNetCore.WebSockets.ConformanceTests.csproj b/src/Middleware/WebSockets/test/ConformanceTests/Microsoft.AspNetCore.WebSockets.ConformanceTests.csproj new file mode 100644 index 0000000000..13e075308f --- /dev/null +++ b/src/Middleware/WebSockets/test/ConformanceTests/Microsoft.AspNetCore.WebSockets.ConformanceTests.csproj @@ -0,0 +1,14 @@ + + + + netcoreapp2.2 + + + + + + + + + + diff --git a/src/WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest/SkipIfWsTestNotPresentAttribute.cs b/src/Middleware/WebSockets/test/ConformanceTests/SkipIfWsTestNotPresentAttribute.cs similarity index 100% rename from src/WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest/SkipIfWsTestNotPresentAttribute.cs rename to src/Middleware/WebSockets/test/ConformanceTests/SkipIfWsTestNotPresentAttribute.cs diff --git a/src/Middleware/WebSockets/test/Directory.Build.props b/src/Middleware/WebSockets/test/Directory.Build.props new file mode 100644 index 0000000000..d5cd124cc9 --- /dev/null +++ b/src/Middleware/WebSockets/test/Directory.Build.props @@ -0,0 +1,27 @@ + + + + + + + true + + + + + + 2.2.0 + 2.2.0 + 2.2.0 + 2.2.0 + 2.2.0 + 0.6.0-rtm-final + 2.2.0 + 2.2.0 + 2.2.0 + + + diff --git a/src/WebSockets/test/Microsoft.AspNetCore.WebSockets.Test/AddWebSocketsTests.cs b/src/Middleware/WebSockets/test/UnitTests/AddWebSocketsTests.cs similarity index 100% rename from src/WebSockets/test/Microsoft.AspNetCore.WebSockets.Test/AddWebSocketsTests.cs rename to src/Middleware/WebSockets/test/UnitTests/AddWebSocketsTests.cs diff --git a/src/WebSockets/test/Microsoft.AspNetCore.WebSockets.Test/BufferStream.cs b/src/Middleware/WebSockets/test/UnitTests/BufferStream.cs similarity index 100% rename from src/WebSockets/test/Microsoft.AspNetCore.WebSockets.Test/BufferStream.cs rename to src/Middleware/WebSockets/test/UnitTests/BufferStream.cs diff --git a/src/WebSockets/test/Microsoft.AspNetCore.WebSockets.Test/DuplexStream.cs b/src/Middleware/WebSockets/test/UnitTests/DuplexStream.cs similarity index 100% rename from src/WebSockets/test/Microsoft.AspNetCore.WebSockets.Test/DuplexStream.cs rename to src/Middleware/WebSockets/test/UnitTests/DuplexStream.cs diff --git a/src/WebSockets/test/Microsoft.AspNetCore.WebSockets.Test/IWebHostPortExtensions.cs b/src/Middleware/WebSockets/test/UnitTests/IWebHostPortExtensions.cs similarity index 100% rename from src/WebSockets/test/Microsoft.AspNetCore.WebSockets.Test/IWebHostPortExtensions.cs rename to src/Middleware/WebSockets/test/UnitTests/IWebHostPortExtensions.cs diff --git a/src/WebSockets/test/Microsoft.AspNetCore.WebSockets.Test/KestrelWebSocketHelpers.cs b/src/Middleware/WebSockets/test/UnitTests/KestrelWebSocketHelpers.cs similarity index 100% rename from src/WebSockets/test/Microsoft.AspNetCore.WebSockets.Test/KestrelWebSocketHelpers.cs rename to src/Middleware/WebSockets/test/UnitTests/KestrelWebSocketHelpers.cs diff --git a/src/Middleware/WebSockets/test/UnitTests/Microsoft.AspNetCore.WebSockets.Tests.csproj b/src/Middleware/WebSockets/test/UnitTests/Microsoft.AspNetCore.WebSockets.Tests.csproj new file mode 100644 index 0000000000..fc5fb268d5 --- /dev/null +++ b/src/Middleware/WebSockets/test/UnitTests/Microsoft.AspNetCore.WebSockets.Tests.csproj @@ -0,0 +1,14 @@ + + + + $(StandardTestTfms) + + + + + + + + + + diff --git a/src/WebSockets/test/Microsoft.AspNetCore.WebSockets.Test/SendReceiveTests.cs b/src/Middleware/WebSockets/test/UnitTests/SendReceiveTests.cs similarity index 100% rename from src/WebSockets/test/Microsoft.AspNetCore.WebSockets.Test/SendReceiveTests.cs rename to src/Middleware/WebSockets/test/UnitTests/SendReceiveTests.cs diff --git a/src/WebSockets/test/Microsoft.AspNetCore.WebSockets.Test/WebSocketMiddlewareTests.cs b/src/Middleware/WebSockets/test/UnitTests/WebSocketMiddlewareTests.cs similarity index 100% rename from src/WebSockets/test/Microsoft.AspNetCore.WebSockets.Test/WebSocketMiddlewareTests.cs rename to src/Middleware/WebSockets/test/UnitTests/WebSocketMiddlewareTests.cs diff --git a/src/WebSockets/test/Microsoft.AspNetCore.WebSockets.Test/WebSocketPair.cs b/src/Middleware/WebSockets/test/UnitTests/WebSocketPair.cs similarity index 100% rename from src/WebSockets/test/Microsoft.AspNetCore.WebSockets.Test/WebSocketPair.cs rename to src/Middleware/WebSockets/test/UnitTests/WebSocketPair.cs diff --git a/src/PackageArchive/Archive.CiServer.Patch.Compat/ArchiveBaseline.2.1.6.txt b/src/PackageArchive/Archive.CiServer.Patch.Compat/ArchiveBaseline.2.1.6.txt new file mode 100644 index 0000000000..62153a6836 --- /dev/null +++ b/src/PackageArchive/Archive.CiServer.Patch.Compat/ArchiveBaseline.2.1.6.txt @@ -0,0 +1,675 @@ +libuv\1.10.0\.nupkg.metadata +libuv\1.10.0\.signature.p7s +messagepack\1.7.3.4\.nupkg.metadata +messagepack\1.7.3.4\.signature.p7s +microsoft.applicationinsights.aspnetcore\2.1.1\.nupkg.metadata +microsoft.applicationinsights.aspnetcore\2.1.1\.signature.p7s +microsoft.applicationinsights.dependencycollector\2.4.1\.nupkg.metadata +microsoft.applicationinsights.dependencycollector\2.4.1\.signature.p7s +microsoft.applicationinsights\2.4.0\.nupkg.metadata +microsoft.applicationinsights\2.4.0\.signature.p7s +microsoft.aspnet.webapi.client\5.2.6\.nupkg.metadata +microsoft.aspnetcore.all\2.1.1\.nupkg.metadata +microsoft.aspnetcore.antiforgery\2.1.1\.nupkg.metadata +microsoft.aspnetcore.app\2.1.1\.nupkg.metadata +microsoft.aspnetcore.applicationinsights.hostingstartup\2.1.1\.nupkg.metadata +microsoft.aspnetcore.authentication.abstractions\2.1.1\.nupkg.metadata +microsoft.aspnetcore.authentication.azuread.ui\2.1.1\.nupkg.metadata +microsoft.aspnetcore.authentication.azureadb2c.ui\2.1.1\.nupkg.metadata +microsoft.aspnetcore.authentication.cookies\2.1.1\.nupkg.metadata +microsoft.aspnetcore.authentication.core\2.1.1\.nupkg.metadata +microsoft.aspnetcore.authentication.facebook\2.1.1\.nupkg.metadata +microsoft.aspnetcore.authentication.google\2.1.1\.nupkg.metadata +microsoft.aspnetcore.authentication.jwtbearer\2.1.1\.nupkg.metadata +microsoft.aspnetcore.authentication.microsoftaccount\2.1.1\.nupkg.metadata +microsoft.aspnetcore.authentication.oauth\2.1.1\.nupkg.metadata +microsoft.aspnetcore.authentication.openidconnect\2.1.1\.nupkg.metadata +microsoft.aspnetcore.authentication.twitter\2.1.1\.nupkg.metadata +microsoft.aspnetcore.authentication.wsfederation\2.1.1\.nupkg.metadata +microsoft.aspnetcore.authentication\2.1.1\.nupkg.metadata +microsoft.aspnetcore.authorization.policy\2.1.1\.nupkg.metadata +microsoft.aspnetcore.authorization\2.1.1\.nupkg.metadata +microsoft.aspnetcore.azureappservices.hostingstartup\2.1.1\.nupkg.metadata +microsoft.aspnetcore.azureappservicesintegration\2.1.1\.nupkg.metadata +microsoft.aspnetcore.connections.abstractions\2.1.1\.nupkg.metadata +microsoft.aspnetcore.cookiepolicy\2.1.1\.nupkg.metadata +microsoft.aspnetcore.cors\2.1.1\.nupkg.metadata +microsoft.aspnetcore.cryptography.internal\2.1.1\.nupkg.metadata +microsoft.aspnetcore.cryptography.keyderivation\2.1.1\.nupkg.metadata +microsoft.aspnetcore.dataprotection.abstractions\2.1.1\.nupkg.metadata +microsoft.aspnetcore.dataprotection.azurekeyvault\2.1.1\.nupkg.metadata +microsoft.aspnetcore.dataprotection.azurestorage\2.1.1\.nupkg.metadata +microsoft.aspnetcore.dataprotection.extensions\2.1.1\.nupkg.metadata +microsoft.aspnetcore.dataprotection\2.1.1\.nupkg.metadata +microsoft.aspnetcore.diagnostics.abstractions\2.1.1\.nupkg.metadata +microsoft.aspnetcore.diagnostics.entityframeworkcore\2.1.1\.nupkg.metadata +microsoft.aspnetcore.diagnostics\2.1.1\.nupkg.metadata +microsoft.aspnetcore.hostfiltering\2.1.1\.nupkg.metadata +microsoft.aspnetcore.hosting.abstractions\2.1.1\.nupkg.metadata +microsoft.aspnetcore.hosting.server.abstractions\2.1.1\.nupkg.metadata +microsoft.aspnetcore.hosting\2.1.1\.nupkg.metadata +microsoft.aspnetcore.html.abstractions\2.1.1\.nupkg.metadata +microsoft.aspnetcore.http.abstractions\2.1.1\.nupkg.metadata +microsoft.aspnetcore.http.connections.common\1.0.1\.nupkg.metadata +microsoft.aspnetcore.http.connections\1.0.1\.nupkg.metadata +microsoft.aspnetcore.http.extensions\2.1.1\.nupkg.metadata +microsoft.aspnetcore.http.features\2.1.1\.nupkg.metadata +microsoft.aspnetcore.http\2.1.1\.nupkg.metadata +microsoft.aspnetcore.httpoverrides\2.1.1\.nupkg.metadata +microsoft.aspnetcore.httpspolicy\2.1.1\.nupkg.metadata +microsoft.aspnetcore.identity.entityframeworkcore\2.1.1\.nupkg.metadata +microsoft.aspnetcore.identity.ui\2.1.1\.nupkg.metadata +microsoft.aspnetcore.identity\2.1.1\.nupkg.metadata +microsoft.aspnetcore.jsonpatch\2.1.1\.nupkg.metadata +microsoft.aspnetcore.localization.routing\2.1.1\.nupkg.metadata +microsoft.aspnetcore.localization\2.1.1\.nupkg.metadata +microsoft.aspnetcore.middlewareanalysis\2.1.1\.nupkg.metadata +microsoft.aspnetcore.mvc.abstractions\2.1.1\.nupkg.metadata +microsoft.aspnetcore.mvc.analyzers\2.1.1\.nupkg.metadata +microsoft.aspnetcore.mvc.apiexplorer\2.1.1\.nupkg.metadata +microsoft.aspnetcore.mvc.core\2.1.1\.nupkg.metadata +microsoft.aspnetcore.mvc.cors\2.1.1\.nupkg.metadata +microsoft.aspnetcore.mvc.dataannotations\2.1.1\.nupkg.metadata +microsoft.aspnetcore.mvc.formatters.json\2.1.1\.nupkg.metadata +microsoft.aspnetcore.mvc.formatters.xml\2.1.1\.nupkg.metadata +microsoft.aspnetcore.mvc.localization\2.1.1\.nupkg.metadata +microsoft.aspnetcore.mvc.razor.extensions\2.1.1\.nupkg.metadata +microsoft.aspnetcore.mvc.razor.viewcompilation\2.1.1\.nupkg.metadata +microsoft.aspnetcore.mvc.razor\2.1.1\.nupkg.metadata +microsoft.aspnetcore.mvc.razorpages\2.1.1\.nupkg.metadata +microsoft.aspnetcore.mvc.taghelpers\2.1.1\.nupkg.metadata +microsoft.aspnetcore.mvc.viewfeatures\2.1.1\.nupkg.metadata +microsoft.aspnetcore.mvc\2.1.1\.nupkg.metadata +microsoft.aspnetcore.nodeservices\2.1.1\.nupkg.metadata +microsoft.aspnetcore.owin\2.1.1\.nupkg.metadata +microsoft.aspnetcore.razor.design\2.1.2\.nupkg.metadata +microsoft.aspnetcore.razor.language\2.1.1\.nupkg.metadata +microsoft.aspnetcore.razor.runtime\2.1.1\.nupkg.metadata +microsoft.aspnetcore.razor\2.1.1\.nupkg.metadata +microsoft.aspnetcore.responsecaching.abstractions\2.1.1\.nupkg.metadata +microsoft.aspnetcore.responsecaching\2.1.1\.nupkg.metadata +microsoft.aspnetcore.responsecompression\2.1.1\.nupkg.metadata +microsoft.aspnetcore.rewrite\2.1.1\.nupkg.metadata +microsoft.aspnetcore.routing.abstractions\2.1.1\.nupkg.metadata +microsoft.aspnetcore.routing\2.1.1\.nupkg.metadata +microsoft.aspnetcore.server.httpsys\2.1.1\.nupkg.metadata +microsoft.aspnetcore.server.iisintegration\2.1.1\.nupkg.metadata +microsoft.aspnetcore.server.kestrel.core\2.1.1\.nupkg.metadata +microsoft.aspnetcore.server.kestrel.https\2.1.1\.nupkg.metadata +microsoft.aspnetcore.server.kestrel.transport.abstractions\2.1.1\.nupkg.metadata +microsoft.aspnetcore.server.kestrel.transport.libuv\2.1.1\.nupkg.metadata +microsoft.aspnetcore.server.kestrel.transport.sockets\2.1.1\.nupkg.metadata +microsoft.aspnetcore.server.kestrel\2.1.1\.nupkg.metadata +microsoft.aspnetcore.session\2.1.1\.nupkg.metadata +microsoft.aspnetcore.signalr.common\1.0.1\.nupkg.metadata +microsoft.aspnetcore.signalr.core\1.0.1\.nupkg.metadata +microsoft.aspnetcore.signalr.protocols.json\1.0.1\.nupkg.metadata +microsoft.aspnetcore.signalr.redis\1.0.1\.nupkg.metadata +microsoft.aspnetcore.signalr\1.0.1\.nupkg.metadata +microsoft.aspnetcore.spaservices.extensions\2.1.1\.nupkg.metadata +microsoft.aspnetcore.spaservices\2.1.1\.nupkg.metadata +microsoft.aspnetcore.staticfiles\2.1.1\.nupkg.metadata +microsoft.aspnetcore.websockets\2.1.1\.nupkg.metadata +microsoft.aspnetcore.webutilities\2.1.1\.nupkg.metadata +microsoft.aspnetcore\2.1.1\.nupkg.metadata +microsoft.azure.keyvault.webkey\2.0.7\.nupkg.metadata +microsoft.azure.keyvault.webkey\2.0.7\.signature.p7s +microsoft.azure.keyvault\2.3.2\.nupkg.metadata +microsoft.azure.keyvault\2.3.2\.signature.p7s +microsoft.azure.services.appauthentication\1.0.1\.nupkg.metadata +microsoft.azure.services.appauthentication\1.0.1\.signature.p7s +microsoft.codeanalysis.analyzers\1.1.0\.nupkg.metadata +microsoft.codeanalysis.common\2.8.0\.nupkg.metadata +microsoft.codeanalysis.csharp.workspaces\2.8.0\.nupkg.metadata +microsoft.codeanalysis.csharp\2.8.0\.nupkg.metadata +microsoft.codeanalysis.razor\2.1.1\.nupkg.metadata +microsoft.codeanalysis.workspaces.common\2.8.0\.nupkg.metadata +microsoft.csharp\4.0.1\.nupkg.metadata +microsoft.csharp\4.3.0\.nupkg.metadata +microsoft.csharp\4.5.0\.nupkg.metadata +microsoft.data.edm\5.8.2\.nupkg.metadata +microsoft.data.odata\5.8.2\.nupkg.metadata +microsoft.data.sqlite.core\2.1.0\.nupkg.metadata +microsoft.data.sqlite\2.1.0\.nupkg.metadata +microsoft.dotnet.platformabstractions\2.1.0\.nupkg.metadata +microsoft.entityframeworkcore.abstractions\2.1.1\.nupkg.metadata +microsoft.entityframeworkcore.analyzers\2.1.1\.nupkg.metadata +microsoft.entityframeworkcore.design\2.1.1\.nupkg.metadata +microsoft.entityframeworkcore.inmemory\2.1.1\.nupkg.metadata +microsoft.entityframeworkcore.relational\2.1.1\.nupkg.metadata +microsoft.entityframeworkcore.sqlite.core\2.1.1\.nupkg.metadata +microsoft.entityframeworkcore.sqlite\2.1.1\.nupkg.metadata +microsoft.entityframeworkcore.sqlserver\2.1.1\.nupkg.metadata +microsoft.entityframeworkcore.tools\2.1.1\.nupkg.metadata +microsoft.entityframeworkcore\2.1.1\.nupkg.metadata +microsoft.extensions.caching.abstractions\2.1.1\.nupkg.metadata +microsoft.extensions.caching.memory\2.1.1\.nupkg.metadata +microsoft.extensions.caching.redis\2.1.1\.nupkg.metadata +microsoft.extensions.caching.sqlserver\2.1.1\.nupkg.metadata +microsoft.extensions.configuration.abstractions\2.1.1\.nupkg.metadata +microsoft.extensions.configuration.azurekeyvault\2.1.1\.nupkg.metadata +microsoft.extensions.configuration.binder\2.1.1\.nupkg.metadata +microsoft.extensions.configuration.commandline\2.1.1\.nupkg.metadata +microsoft.extensions.configuration.environmentvariables\2.1.1\.nupkg.metadata +microsoft.extensions.configuration.fileextensions\2.1.1\.nupkg.metadata +microsoft.extensions.configuration.ini\2.1.1\.nupkg.metadata +microsoft.extensions.configuration.json\2.1.1\.nupkg.metadata +microsoft.extensions.configuration.keyperfile\2.1.1\.nupkg.metadata +microsoft.extensions.configuration.usersecrets\2.1.1\.nupkg.metadata +microsoft.extensions.configuration.xml\2.1.1\.nupkg.metadata +microsoft.extensions.configuration\2.1.1\.nupkg.metadata +microsoft.extensions.dependencyinjection.abstractions\2.1.1\.nupkg.metadata +microsoft.extensions.dependencyinjection\2.1.1\.nupkg.metadata +microsoft.extensions.dependencymodel\2.1.0\.nupkg.metadata +microsoft.extensions.diagnosticadapter\2.1.0\.nupkg.metadata +microsoft.extensions.fileproviders.abstractions\2.1.1\.nupkg.metadata +microsoft.extensions.fileproviders.composite\2.1.1\.nupkg.metadata +microsoft.extensions.fileproviders.embedded\2.1.1\.nupkg.metadata +microsoft.extensions.fileproviders.physical\2.1.1\.nupkg.metadata +microsoft.extensions.filesystemglobbing\2.1.1\.nupkg.metadata +microsoft.extensions.hosting.abstractions\2.1.1\.nupkg.metadata +microsoft.extensions.hosting\2.1.1\.nupkg.metadata +microsoft.extensions.http\2.1.1\.nupkg.metadata +microsoft.extensions.identity.core\2.1.1\.nupkg.metadata +microsoft.extensions.identity.stores\2.1.1\.nupkg.metadata +microsoft.extensions.localization.abstractions\2.1.1\.nupkg.metadata +microsoft.extensions.localization\2.1.1\.nupkg.metadata +microsoft.extensions.logging.abstractions\2.1.1\.nupkg.metadata +microsoft.extensions.logging.azureappservices\2.1.1\.nupkg.metadata +microsoft.extensions.logging.configuration\2.1.1\.nupkg.metadata +microsoft.extensions.logging.console\2.1.1\.nupkg.metadata +microsoft.extensions.logging.debug\2.1.1\.nupkg.metadata +microsoft.extensions.logging.eventsource\2.1.1\.nupkg.metadata +microsoft.extensions.logging.tracesource\2.1.1\.nupkg.metadata +microsoft.extensions.logging\2.1.1\.nupkg.metadata +microsoft.extensions.objectpool\2.1.1\.nupkg.metadata +microsoft.extensions.options.configurationextensions\2.1.1\.nupkg.metadata +microsoft.extensions.options\2.1.1\.nupkg.metadata +microsoft.extensions.platformabstractions\1.1.0\.nupkg.metadata +microsoft.extensions.primitives\2.1.1\.nupkg.metadata +microsoft.extensions.webencoders\2.1.1\.nupkg.metadata +microsoft.identitymodel.clients.activedirectory\3.14.2\.nupkg.metadata +microsoft.identitymodel.clients.activedirectory\3.14.2\.signature.p7s +microsoft.identitymodel.logging\5.2.0\.nupkg.metadata +microsoft.identitymodel.logging\5.2.0\.signature.p7s +microsoft.identitymodel.protocols.openidconnect\5.2.0\.nupkg.metadata +microsoft.identitymodel.protocols.openidconnect\5.2.0\.signature.p7s +microsoft.identitymodel.protocols.wsfederation\5.2.0\.nupkg.metadata +microsoft.identitymodel.protocols.wsfederation\5.2.0\.signature.p7s +microsoft.identitymodel.protocols\5.2.0\.nupkg.metadata +microsoft.identitymodel.protocols\5.2.0\.signature.p7s +microsoft.identitymodel.tokens.saml\5.2.0\.nupkg.metadata +microsoft.identitymodel.tokens.saml\5.2.0\.signature.p7s +microsoft.identitymodel.tokens\5.2.0\.nupkg.metadata +microsoft.identitymodel.tokens\5.2.0\.signature.p7s +microsoft.identitymodel.xml\5.2.0\.nupkg.metadata +microsoft.identitymodel.xml\5.2.0\.signature.p7s +microsoft.net.http.headers\2.1.1\.nupkg.metadata +microsoft.netcore.app\2.1.0\.nupkg.metadata +microsoft.netcore.dotnetapphost\2.1.0\.nupkg.metadata +microsoft.netcore.dotnethostpolicy\2.1.0\.nupkg.metadata +microsoft.netcore.dotnethostresolver\2.1.0\.nupkg.metadata +microsoft.netcore.platforms\1.0.1\.nupkg.metadata +microsoft.netcore.platforms\1.0.1\.signature.p7s +microsoft.netcore.platforms\1.0.2\.nupkg.metadata +microsoft.netcore.platforms\1.0.2\.signature.p7s +microsoft.netcore.platforms\1.1.0\.nupkg.metadata +microsoft.netcore.platforms\1.1.0\.signature.p7s +microsoft.netcore.platforms\2.0.0\.nupkg.metadata +microsoft.netcore.platforms\2.0.0\.signature.p7s +microsoft.netcore.platforms\2.1.0\.nupkg.metadata +microsoft.netcore.targets\1.0.1\.nupkg.metadata +microsoft.netcore.targets\1.1.0\.nupkg.metadata +microsoft.netcore.targets\2.1.0\.nupkg.metadata +microsoft.rest.clientruntime.azure\3.3.7\.nupkg.metadata +microsoft.rest.clientruntime.azure\3.3.7\.signature.p7s +microsoft.rest.clientruntime\2.3.8\.nupkg.metadata +microsoft.rest.clientruntime\2.3.8\.signature.p7s +microsoft.visualstudio.web.browserlink\2.1.1\.nupkg.metadata +microsoft.visualstudio.web.codegeneration.contracts\2.1.6\.nupkg.metadata +microsoft.visualstudio.web.codegeneration.contracts\2.1.6\.signature.p7s +microsoft.visualstudio.web.codegeneration.contracts\2.1.6\lib\netstandard2.0\Microsoft.VisualStudio.Web.CodeGeneration.Contracts.dll +microsoft.visualstudio.web.codegeneration.contracts\2.1.6\microsoft.visualstudio.web.codegeneration.contracts.2.1.6.nupkg +microsoft.visualstudio.web.codegeneration.contracts\2.1.6\microsoft.visualstudio.web.codegeneration.contracts.2.1.6.nupkg.sha512 +microsoft.visualstudio.web.codegeneration.contracts\2.1.6\microsoft.visualstudio.web.codegeneration.contracts.nuspec +microsoft.visualstudio.web.codegeneration.core\2.1.6\.nupkg.metadata +microsoft.visualstudio.web.codegeneration.core\2.1.6\.signature.p7s +microsoft.visualstudio.web.codegeneration.core\2.1.6\lib\netstandard2.0\Microsoft.VisualStudio.Web.CodeGeneration.Core.dll +microsoft.visualstudio.web.codegeneration.core\2.1.6\microsoft.visualstudio.web.codegeneration.core.2.1.6.nupkg +microsoft.visualstudio.web.codegeneration.core\2.1.6\microsoft.visualstudio.web.codegeneration.core.2.1.6.nupkg.sha512 +microsoft.visualstudio.web.codegeneration.core\2.1.6\microsoft.visualstudio.web.codegeneration.core.nuspec +microsoft.visualstudio.web.codegeneration.design\2.1.6\.nupkg.metadata +microsoft.visualstudio.web.codegeneration.design\2.1.6\.signature.p7s +microsoft.visualstudio.web.codegeneration.design\2.1.6\lib\net461\dotnet-aspnet-codegenerator-design.exe +microsoft.visualstudio.web.codegeneration.design\2.1.6\lib\netstandard2.0\dotnet-aspnet-codegenerator-design.dll +microsoft.visualstudio.web.codegeneration.design\2.1.6\microsoft.visualstudio.web.codegeneration.design.2.1.6.nupkg +microsoft.visualstudio.web.codegeneration.design\2.1.6\microsoft.visualstudio.web.codegeneration.design.2.1.6.nupkg.sha512 +microsoft.visualstudio.web.codegeneration.design\2.1.6\microsoft.visualstudio.web.codegeneration.design.nuspec +microsoft.visualstudio.web.codegeneration.design\2.1.6\runtimes\win7-x64\lib\net461\dotnet-aspnet-codegenerator-design.exe +microsoft.visualstudio.web.codegeneration.design\2.1.6\runtimes\win7-x86\lib\net461\dotnet-aspnet-codegenerator-design.exe +microsoft.visualstudio.web.codegeneration.design\2.1.6\runtimes\win-arm\lib\net461\dotnet-aspnet-codegenerator-design.exe +microsoft.visualstudio.web.codegeneration.design\2.1.6\runtimes\win-arm64\lib\net461\dotnet-aspnet-codegenerator-design.exe +microsoft.visualstudio.web.codegeneration.entityframeworkcore\2.1.6\.nupkg.metadata +microsoft.visualstudio.web.codegeneration.entityframeworkcore\2.1.6\.signature.p7s +microsoft.visualstudio.web.codegeneration.entityframeworkcore\2.1.6\lib\netstandard2.0\Microsoft.VisualStudio.Web.CodeGeneration.EntityFrameworkCore.dll +microsoft.visualstudio.web.codegeneration.entityframeworkcore\2.1.6\microsoft.visualstudio.web.codegeneration.entityframeworkcore.2.1.6.nupkg +microsoft.visualstudio.web.codegeneration.entityframeworkcore\2.1.6\microsoft.visualstudio.web.codegeneration.entityframeworkcore.2.1.6.nupkg.sha512 +microsoft.visualstudio.web.codegeneration.entityframeworkcore\2.1.6\microsoft.visualstudio.web.codegeneration.entityframeworkcore.nuspec +microsoft.visualstudio.web.codegeneration.entityframeworkcore\2.1.6\Templates\DbContext\NewLocalDbContext.cshtml +microsoft.visualstudio.web.codegeneration.templating\2.1.6\.nupkg.metadata +microsoft.visualstudio.web.codegeneration.templating\2.1.6\.signature.p7s +microsoft.visualstudio.web.codegeneration.templating\2.1.6\lib\netstandard2.0\Microsoft.VisualStudio.Web.CodeGeneration.Templating.dll +microsoft.visualstudio.web.codegeneration.templating\2.1.6\microsoft.visualstudio.web.codegeneration.templating.2.1.6.nupkg +microsoft.visualstudio.web.codegeneration.templating\2.1.6\microsoft.visualstudio.web.codegeneration.templating.2.1.6.nupkg.sha512 +microsoft.visualstudio.web.codegeneration.templating\2.1.6\microsoft.visualstudio.web.codegeneration.templating.nuspec +microsoft.visualstudio.web.codegeneration.utils\2.1.6\.nupkg.metadata +microsoft.visualstudio.web.codegeneration.utils\2.1.6\.signature.p7s +microsoft.visualstudio.web.codegeneration.utils\2.1.6\lib\netstandard2.0\Microsoft.VisualStudio.Web.CodeGeneration.Utils.dll +microsoft.visualstudio.web.codegeneration.utils\2.1.6\microsoft.visualstudio.web.codegeneration.utils.2.1.6.nupkg +microsoft.visualstudio.web.codegeneration.utils\2.1.6\microsoft.visualstudio.web.codegeneration.utils.2.1.6.nupkg.sha512 +microsoft.visualstudio.web.codegeneration.utils\2.1.6\microsoft.visualstudio.web.codegeneration.utils.nuspec +microsoft.visualstudio.web.codegeneration\2.1.6\.nupkg.metadata +microsoft.visualstudio.web.codegeneration\2.1.6\.signature.p7s +microsoft.visualstudio.web.codegeneration\2.1.6\lib\netstandard2.0\Microsoft.VisualStudio.Web.CodeGeneration.dll +microsoft.visualstudio.web.codegeneration\2.1.6\microsoft.visualstudio.web.codegeneration.2.1.6.nupkg +microsoft.visualstudio.web.codegeneration\2.1.6\microsoft.visualstudio.web.codegeneration.2.1.6.nupkg.sha512 +microsoft.visualstudio.web.codegeneration\2.1.6\microsoft.visualstudio.web.codegeneration.nuspec +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\.nupkg.metadata +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\.signature.p7s +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Generators\ParameterDefinitions\area.json +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Generators\ParameterDefinitions\controller.json +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Generators\ParameterDefinitions\identity.json +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Generators\ParameterDefinitions\razorpage.json +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Generators\ParameterDefinitions\view.json +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\lib\netstandard2.0\identitygeneratorfilesconfig.json +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\lib\netstandard2.0\Microsoft.VisualStudio.Web.CodeGenerators.Mvc.dll +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\microsoft.visualstudio.web.codegenerators.mvc.2.1.6.nupkg +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\microsoft.visualstudio.web.codegenerators.mvc.2.1.6.nupkg.sha512 +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\microsoft.visualstudio.web.codegenerators.mvc.nuspec +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\ControllerGenerator\ApiControllerWithActions.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\ControllerGenerator\ApiControllerWithContext.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\ControllerGenerator\ApiEmptyController.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\ControllerGenerator\ControllerWithActions.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\ControllerGenerator\EmptyController.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\ControllerGenerator\MvcControllerWithContext.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\_LoginPartial.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Data\ApplicationDbContext.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Data\ApplicationUser.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\IdentityHostingStartup.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\_Layout.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\_ValidationScriptsPartial.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\_ViewImports.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\_ViewStart.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account._ViewImports.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.AccessDenied.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.AccessDenied.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.ConfirmEmail.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.ConfirmEmail.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.ExternalLogin.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.ExternalLogin.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.ForgotPassword.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.ForgotPassword.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.ForgotPasswordConfirmation.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.ForgotPasswordConfirmation.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.Lockout.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.Lockout.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.Login.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.Login.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.LoginWith2fa.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.LoginWith2fa.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.LoginWithRecoveryCode.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.LoginWithRecoveryCode.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.Logout.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.Logout.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.Register.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.Register.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.ResetPassword.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.ResetPassword.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.ResetPasswordConfirmation.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.ResetPasswordConfirmation.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage._Layout.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage._ManageNav.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage._StatusMessage.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage._ViewImports.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.ChangePassword.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.ChangePassword.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.DeletePersonalData.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.DeletePersonalData.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.Disable2fa.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.Disable2fa.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.DownloadPersonalData.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.DownloadPersonalData.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.EnableAuthenticator.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.EnableAuthenticator.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.ExternalLogins.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.ExternalLogins.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.GenerateRecoveryCodes.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.GenerateRecoveryCodes.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.Index.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.Index.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.ManageNavPages.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.PersonalData.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.PersonalData.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.ResetAuthenticator.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.ResetAuthenticator.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.SetPassword.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.SetPassword.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.ShowRecoveryCodes.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.ShowRecoveryCodes.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.TwoFactorAuthentication.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.TwoFactorAuthentication.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Error.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Error.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\ScaffoldingReadme.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\SupportPages._CookieConsentPartial.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\SupportPages._ViewImports.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\SupportPages._ViewStart.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\css\site.css +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\css\site.min.css +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\favicon.ico +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\images\banner1.svg +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\images\banner2.svg +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\images\banner3.svg +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\js\site.js +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\js\site.min.js +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\bootstrap\.bower.json +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\bootstrap\dist\css\bootstrap.css +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\bootstrap\dist\css\bootstrap.css.map +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\bootstrap\dist\css\bootstrap.min.css +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\bootstrap\dist\css\bootstrap.min.css.map +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\bootstrap\dist\css\bootstrap-theme.css +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\bootstrap\dist\css\bootstrap-theme.css.map +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\bootstrap\dist\css\bootstrap-theme.min.css +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\bootstrap\dist\css\bootstrap-theme.min.css.map +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\bootstrap\dist\fonts\glyphicons-halflings-regular.eot +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\bootstrap\dist\fonts\glyphicons-halflings-regular.svg +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\bootstrap\dist\fonts\glyphicons-halflings-regular.ttf +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\bootstrap\dist\fonts\glyphicons-halflings-regular.woff +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\bootstrap\dist\fonts\glyphicons-halflings-regular.woff2 +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\bootstrap\dist\js\bootstrap.js +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\bootstrap\dist\js\bootstrap.min.js +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\bootstrap\dist\js\npm.js +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\bootstrap\LICENSE +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\jquery\.bower.json +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\jquery\dist\jquery.js +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\jquery\dist\jquery.min.js +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\jquery\dist\jquery.min.map +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\jquery\LICENSE.txt +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\jquery-validation\.bower.json +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\jquery-validation\dist\additional-methods.js +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\jquery-validation\dist\additional-methods.min.js +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\jquery-validation\dist\jquery.validate.js +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\jquery-validation\dist\jquery.validate.min.js +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\jquery-validation\LICENSE.md +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\jquery-validation-unobtrusive\.bower.json +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\jquery-validation-unobtrusive\jquery.validate.unobtrusive.js +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\jquery-validation-unobtrusive\jquery.validate.unobtrusive.min.js +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\jquery-validation-unobtrusive\LICENSE.txt +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\MvcLayout\_Layout.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\MvcLayout\Error.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\RazorPageGenerator\_ValidationScriptsPartial.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\RazorPageGenerator\Create.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\RazorPageGenerator\CreatePageModel.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\RazorPageGenerator\Delete.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\RazorPageGenerator\DeletePageModel.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\RazorPageGenerator\Details.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\RazorPageGenerator\DetailsPageModel.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\RazorPageGenerator\Edit.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\RazorPageGenerator\EditPageModel.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\RazorPageGenerator\Empty.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\RazorPageGenerator\EmptyPageModel.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\RazorPageGenerator\List.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\RazorPageGenerator\ListPageModel.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Startup\ReadMe.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Startup\Startup.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\ViewGenerator\_ValidationScriptsPartial.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\ViewGenerator\Create.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\ViewGenerator\Delete.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\ViewGenerator\Details.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\ViewGenerator\Edit.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\ViewGenerator\Empty.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\ViewGenerator\List.cshtml +microsoft.win32.primitives\4.0.1\.nupkg.metadata +microsoft.win32.primitives\4.3.0\.nupkg.metadata +microsoft.win32.registry\4.3.0\.nupkg.metadata +microsoft.win32.registry\4.5.0\.nupkg.metadata +netstandard.library\1.6.0\.nupkg.metadata +netstandard.library\1.6.1\.nupkg.metadata +netstandard.library\2.0.3\.nupkg.metadata +newtonsoft.json.bson\1.0.1\.nupkg.metadata +newtonsoft.json.bson\1.0.1\.signature.p7s +newtonsoft.json\10.0.1\.nupkg.metadata +newtonsoft.json\10.0.1\.signature.p7s +newtonsoft.json\11.0.2\.nupkg.metadata +newtonsoft.json\11.0.2\.signature.p7s +newtonsoft.json\9.0.1\.nupkg.metadata +nuget.frameworks\4.7.0\.nupkg.metadata +remotion.linq\2.2.0\.nupkg.metadata +remotion.linq\2.2.0\.signature.p7s +runtime.debian.8-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.fedora.23-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.fedora.24-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.native.system.data.sqlclient.sni\4.4.0\.nupkg.metadata +runtime.native.system.io.compression\4.1.0\.nupkg.metadata +runtime.native.system.io.compression\4.3.0\.nupkg.metadata +runtime.native.system.net.http\4.0.1\.nupkg.metadata +runtime.native.system.net.http\4.3.0\.nupkg.metadata +runtime.native.system.net.security\4.3.0\.nupkg.metadata +runtime.native.system.security.cryptography.apple\4.3.0\.nupkg.metadata +runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.native.system.security.cryptography\4.0.0\.nupkg.metadata +runtime.native.system\4.0.0\.nupkg.metadata +runtime.native.system\4.3.0\.nupkg.metadata +runtime.opensuse.13.2-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.opensuse.42.1-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.osx.10.10-x64.runtime.native.system.security.cryptography.apple\4.3.0\.nupkg.metadata +runtime.osx.10.10-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.rhel.7-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.ubuntu.14.04-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.ubuntu.16.04-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.ubuntu.16.10-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.win-arm64.runtime.native.system.data.sqlclient.sni\4.4.0\.nupkg.metadata +runtime.win-x64.runtime.native.system.data.sqlclient.sni\4.4.0\.nupkg.metadata +runtime.win-x86.runtime.native.system.data.sqlclient.sni\4.4.0\.nupkg.metadata +sqlitepclraw.bundle_green\1.1.11\.nupkg.metadata +sqlitepclraw.bundle_green\1.1.11\.signature.p7s +sqlitepclraw.core\1.1.11\.nupkg.metadata +sqlitepclraw.core\1.1.11\.signature.p7s +sqlitepclraw.lib.e_sqlite3.linux\1.1.11\.nupkg.metadata +sqlitepclraw.lib.e_sqlite3.linux\1.1.11\.signature.p7s +sqlitepclraw.lib.e_sqlite3.osx\1.1.11\.nupkg.metadata +sqlitepclraw.lib.e_sqlite3.osx\1.1.11\.signature.p7s +sqlitepclraw.lib.e_sqlite3.v110_xp\1.1.11\.nupkg.metadata +sqlitepclraw.lib.e_sqlite3.v110_xp\1.1.11\.signature.p7s +sqlitepclraw.provider.e_sqlite3.netstandard11\1.1.11\.nupkg.metadata +sqlitepclraw.provider.e_sqlite3.netstandard11\1.1.11\.signature.p7s +stackexchange.redis.strongname\1.2.4\.nupkg.metadata +stackexchange.redis.strongname\1.2.4\.signature.p7s +system.appcontext\4.1.0\.nupkg.metadata +system.appcontext\4.3.0\.nupkg.metadata +system.buffers\4.0.0\.nupkg.metadata +system.buffers\4.3.0\.nupkg.metadata +system.buffers\4.5.0\.nupkg.metadata +system.collections.concurrent\4.0.12\.nupkg.metadata +system.collections.concurrent\4.3.0\.nupkg.metadata +system.collections.immutable\1.3.0\.nupkg.metadata +system.collections.immutable\1.3.1\.nupkg.metadata +system.collections.immutable\1.5.0\.nupkg.metadata +system.collections.nongeneric\4.3.0\.nupkg.metadata +system.collections.specialized\4.3.0\.nupkg.metadata +system.collections\4.0.11\.nupkg.metadata +system.collections\4.3.0\.nupkg.metadata +system.componentmodel.annotations\4.5.0\.nupkg.metadata +system.componentmodel.primitives\4.3.0\.nupkg.metadata +system.componentmodel.typeconverter\4.3.0\.nupkg.metadata +system.componentmodel\4.3.0\.nupkg.metadata +system.composition.attributedmodel\1.0.31\.nupkg.metadata +system.composition.convention\1.0.31\.nupkg.metadata +system.composition.hosting\1.0.31\.nupkg.metadata +system.composition.runtime\1.0.31\.nupkg.metadata +system.composition.typedparts\1.0.31\.nupkg.metadata +system.composition\1.0.31\.nupkg.metadata +system.console\4.0.0\.nupkg.metadata +system.console\4.3.0\.nupkg.metadata +system.data.sqlclient\4.5.1\.nupkg.metadata +system.diagnostics.contracts\4.3.0\.nupkg.metadata +system.diagnostics.debug\4.0.11\.nupkg.metadata +system.diagnostics.debug\4.3.0\.nupkg.metadata +system.diagnostics.diagnosticsource\4.0.0\.nupkg.metadata +system.diagnostics.diagnosticsource\4.3.0\.nupkg.metadata +system.diagnostics.diagnosticsource\4.4.0\.nupkg.metadata +system.diagnostics.diagnosticsource\4.4.0\.signature.p7s +system.diagnostics.diagnosticsource\4.5.0\.nupkg.metadata +system.diagnostics.fileversioninfo\4.3.0\.nupkg.metadata +system.diagnostics.process\4.3.0\.nupkg.metadata +system.diagnostics.stacktrace\4.3.0\.nupkg.metadata +system.diagnostics.tools\4.0.1\.nupkg.metadata +system.diagnostics.tools\4.3.0\.nupkg.metadata +system.diagnostics.tracing\4.1.0\.nupkg.metadata +system.diagnostics.tracing\4.3.0\.nupkg.metadata +system.dynamic.runtime\4.0.11\.nupkg.metadata +system.dynamic.runtime\4.3.0\.nupkg.metadata +system.globalization.calendars\4.0.1\.nupkg.metadata +system.globalization.calendars\4.3.0\.nupkg.metadata +system.globalization.extensions\4.0.1\.nupkg.metadata +system.globalization.extensions\4.3.0\.nupkg.metadata +system.globalization\4.0.11\.nupkg.metadata +system.globalization\4.3.0\.nupkg.metadata +system.identitymodel.tokens.jwt\5.2.0\.nupkg.metadata +system.identitymodel.tokens.jwt\5.2.0\.signature.p7s +system.interactive.async\3.1.1\.nupkg.metadata +system.interactive.async\3.1.1\.signature.p7s +system.io.compression.zipfile\4.0.1\.nupkg.metadata +system.io.compression.zipfile\4.3.0\.nupkg.metadata +system.io.compression\4.1.0\.nupkg.metadata +system.io.compression\4.3.0\.nupkg.metadata +system.io.filesystem.primitives\4.0.1\.nupkg.metadata +system.io.filesystem.primitives\4.3.0\.nupkg.metadata +system.io.filesystem\4.0.1\.nupkg.metadata +system.io.filesystem\4.3.0\.nupkg.metadata +system.io.pipelines\4.5.0\.nupkg.metadata +system.io\4.1.0\.nupkg.metadata +system.io\4.3.0\.nupkg.metadata +system.linq.expressions\4.1.0\.nupkg.metadata +system.linq.expressions\4.3.0\.nupkg.metadata +system.linq.parallel\4.3.0\.nupkg.metadata +system.linq.queryable\4.0.1\.nupkg.metadata +system.linq\4.1.0\.nupkg.metadata +system.linq\4.3.0\.nupkg.metadata +system.memory\4.5.1\.nupkg.metadata +system.net.http\4.1.0\.nupkg.metadata +system.net.http\4.1.0\.signature.p7s +system.net.http\4.3.0\.nupkg.metadata +system.net.http\4.3.0\.signature.p7s +system.net.nameresolution\4.3.0\.nupkg.metadata +system.net.primitives\4.0.11\.nupkg.metadata +system.net.primitives\4.3.0\.nupkg.metadata +system.net.security\4.3.0\.nupkg.metadata +system.net.sockets\4.1.0\.nupkg.metadata +system.net.sockets\4.3.0\.nupkg.metadata +system.net.websockets.websocketprotocol\4.5.1\.nupkg.metadata +system.numerics.vectors\4.5.0\.nupkg.metadata +system.objectmodel\4.0.12\.nupkg.metadata +system.objectmodel\4.3.0\.nupkg.metadata +system.private.datacontractserialization\4.1.1\.nupkg.metadata +system.private.datacontractserialization\4.3.0\.nupkg.metadata +system.reflection.emit.ilgeneration\4.0.1\.nupkg.metadata +system.reflection.emit.ilgeneration\4.3.0\.nupkg.metadata +system.reflection.emit.lightweight\4.0.1\.nupkg.metadata +system.reflection.emit.lightweight\4.3.0\.nupkg.metadata +system.reflection.emit\4.0.1\.nupkg.metadata +system.reflection.emit\4.3.0\.nupkg.metadata +system.reflection.extensions\4.0.1\.nupkg.metadata +system.reflection.extensions\4.3.0\.nupkg.metadata +system.reflection.metadata\1.4.1\.nupkg.metadata +system.reflection.metadata\1.4.2\.nupkg.metadata +system.reflection.metadata\1.6.0\.nupkg.metadata +system.reflection.primitives\4.0.1\.nupkg.metadata +system.reflection.primitives\4.3.0\.nupkg.metadata +system.reflection.typeextensions\4.1.0\.nupkg.metadata +system.reflection.typeextensions\4.3.0\.nupkg.metadata +system.reflection\4.1.0\.nupkg.metadata +system.reflection\4.3.0\.nupkg.metadata +system.resources.resourcemanager\4.0.1\.nupkg.metadata +system.resources.resourcemanager\4.3.0\.nupkg.metadata +system.runtime.compilerservices.unsafe\4.5.0\.nupkg.metadata +system.runtime.compilerservices.unsafe\4.5.1\.nupkg.metadata +system.runtime.extensions\4.1.0\.nupkg.metadata +system.runtime.extensions\4.3.0\.nupkg.metadata +system.runtime.handles\4.0.1\.nupkg.metadata +system.runtime.handles\4.3.0\.nupkg.metadata +system.runtime.interopservices.runtimeinformation\4.0.0\.nupkg.metadata +system.runtime.interopservices.runtimeinformation\4.3.0\.nupkg.metadata +system.runtime.interopservices\4.1.0\.nupkg.metadata +system.runtime.interopservices\4.3.0\.nupkg.metadata +system.runtime.numerics\4.0.1\.nupkg.metadata +system.runtime.numerics\4.3.0\.nupkg.metadata +system.runtime.serialization.formatters\4.3.0\.nupkg.metadata +system.runtime.serialization.json\4.0.2\.nupkg.metadata +system.runtime.serialization.primitives\4.1.1\.nupkg.metadata +system.runtime.serialization.primitives\4.3.0\.nupkg.metadata +system.runtime.serialization.xml\4.3.0\.nupkg.metadata +system.runtime\4.1.0\.nupkg.metadata +system.runtime\4.3.0\.nupkg.metadata +system.security.accesscontrol\4.5.0\.nupkg.metadata +system.security.claims\4.3.0\.nupkg.metadata +system.security.cryptography.algorithms\4.2.0\.nupkg.metadata +system.security.cryptography.algorithms\4.3.0\.nupkg.metadata +system.security.cryptography.cng\4.2.0\.nupkg.metadata +system.security.cryptography.cng\4.3.0\.nupkg.metadata +system.security.cryptography.cng\4.5.0\.nupkg.metadata +system.security.cryptography.csp\4.0.0\.nupkg.metadata +system.security.cryptography.csp\4.3.0\.nupkg.metadata +system.security.cryptography.encoding\4.0.0\.nupkg.metadata +system.security.cryptography.encoding\4.3.0\.nupkg.metadata +system.security.cryptography.openssl\4.0.0\.nupkg.metadata +system.security.cryptography.openssl\4.3.0\.nupkg.metadata +system.security.cryptography.pkcs\4.5.0\.nupkg.metadata +system.security.cryptography.primitives\4.0.0\.nupkg.metadata +system.security.cryptography.primitives\4.3.0\.nupkg.metadata +system.security.cryptography.x509certificates\4.1.0\.nupkg.metadata +system.security.cryptography.x509certificates\4.3.0\.nupkg.metadata +system.security.cryptography.xml\4.5.0\.nupkg.metadata +system.security.permissions\4.5.0\.nupkg.metadata +system.security.principal.windows\4.3.0\.nupkg.metadata +system.security.principal.windows\4.5.0\.nupkg.metadata +system.security.principal\4.3.0\.nupkg.metadata +system.spatial\5.8.2\.nupkg.metadata +system.text.encoding.codepages\4.3.0\.nupkg.metadata +system.text.encoding.codepages\4.5.0\.nupkg.metadata +system.text.encoding.extensions\4.0.11\.nupkg.metadata +system.text.encoding.extensions\4.3.0\.nupkg.metadata +system.text.encoding\4.0.11\.nupkg.metadata +system.text.encoding\4.3.0\.nupkg.metadata +system.text.encodings.web\4.3.1\.nupkg.metadata +system.text.encodings.web\4.3.1\.signature.p7s +system.text.encodings.web\4.5.0\.nupkg.metadata +system.text.regularexpressions\4.1.0\.nupkg.metadata +system.text.regularexpressions\4.3.0\.nupkg.metadata +system.threading.channels\4.5.0\.nupkg.metadata +system.threading.tasks.extensions\4.0.0\.nupkg.metadata +system.threading.tasks.extensions\4.3.0\.nupkg.metadata +system.threading.tasks.extensions\4.5.1\.nupkg.metadata +system.threading.tasks.parallel\4.3.0\.nupkg.metadata +system.threading.tasks\4.0.11\.nupkg.metadata +system.threading.tasks\4.3.0\.nupkg.metadata +system.threading.thread\4.3.0\.nupkg.metadata +system.threading.threadpool\4.3.0\.nupkg.metadata +system.threading.timer\4.0.1\.nupkg.metadata +system.threading.timer\4.3.0\.nupkg.metadata +system.threading\4.0.11\.nupkg.metadata +system.threading\4.3.0\.nupkg.metadata +system.valuetuple\4.3.0\.nupkg.metadata +system.valuetuple\4.5.0\.nupkg.metadata +system.xml.readerwriter\4.0.11\.nupkg.metadata +system.xml.readerwriter\4.3.0\.nupkg.metadata +system.xml.xdocument\4.0.11\.nupkg.metadata +system.xml.xdocument\4.3.0\.nupkg.metadata +system.xml.xmldocument\4.0.1\.nupkg.metadata +system.xml.xmldocument\4.3.0\.nupkg.metadata +system.xml.xmlserializer\4.0.11\.nupkg.metadata +system.xml.xmlserializer\4.3.0\.nupkg.metadata +system.xml.xpath.xdocument\4.3.0\.nupkg.metadata +system.xml.xpath\4.3.0\.nupkg.metadata +windowsazure.storage\8.1.4\.nupkg.metadata +windowsazure.storage\8.1.4\.signature.p7s diff --git a/src/PackageArchive/Archive.CiServer.Patch.Compat/ArchiveBaseline.2.2.0.txt b/src/PackageArchive/Archive.CiServer.Patch.Compat/ArchiveBaseline.2.2.0.txt new file mode 100644 index 0000000000..08d3462b03 --- /dev/null +++ b/src/PackageArchive/Archive.CiServer.Patch.Compat/ArchiveBaseline.2.2.0.txt @@ -0,0 +1,1817 @@ +libuv\1.10.0\.nupkg.metadata +libuv\1.10.0\.signature.p7s +messagepack\1.7.3.4\.nupkg.metadata +messagepack\1.7.3.4\.signature.p7s +microsoft.applicationinsights.aspnetcore\2.1.1\.nupkg.metadata +microsoft.applicationinsights.aspnetcore\2.1.1\.signature.p7s +microsoft.applicationinsights.dependencycollector\2.4.1\.nupkg.metadata +microsoft.applicationinsights.dependencycollector\2.4.1\.signature.p7s +microsoft.applicationinsights\2.4.0\.nupkg.metadata +microsoft.applicationinsights\2.4.0\.signature.p7s +microsoft.aspnet.webapi.client\5.2.6\.nupkg.metadata +microsoft.aspnetcore.all\2.2.0\.nupkg.metadata +microsoft.aspnetcore.all\2.2.0\.signature.p7s +microsoft.aspnetcore.all\2.2.0\build\netcoreapp2.2\Microsoft.AspNetCore.All.props +microsoft.aspnetcore.all\2.2.0\build\netcoreapp2.2\Microsoft.AspNetCore.All.targets +microsoft.aspnetcore.all\2.2.0\lib\netcoreapp2.2\_._ +microsoft.aspnetcore.all\2.2.0\microsoft.aspnetcore.all.2.2.0.nupkg +microsoft.aspnetcore.all\2.2.0\microsoft.aspnetcore.all.2.2.0.nupkg.sha512 +microsoft.aspnetcore.all\2.2.0\microsoft.aspnetcore.all.nuspec +microsoft.aspnetcore.antiforgery\2.2.0\.nupkg.metadata +microsoft.aspnetcore.antiforgery\2.2.0\.signature.p7s +microsoft.aspnetcore.antiforgery\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Antiforgery.dll +microsoft.aspnetcore.antiforgery\2.2.0\microsoft.aspnetcore.antiforgery.2.2.0.nupkg +microsoft.aspnetcore.antiforgery\2.2.0\microsoft.aspnetcore.antiforgery.2.2.0.nupkg.sha512 +microsoft.aspnetcore.antiforgery\2.2.0\microsoft.aspnetcore.antiforgery.nuspec +microsoft.aspnetcore.app\2.2.0\.nupkg.metadata +microsoft.aspnetcore.app\2.2.0\.signature.p7s +microsoft.aspnetcore.app\2.2.0\build\netcoreapp2.2\Microsoft.AspNetCore.App.props +microsoft.aspnetcore.app\2.2.0\build\netcoreapp2.2\Microsoft.AspNetCore.App.targets +microsoft.aspnetcore.app\2.2.0\lib\netcoreapp2.2\_._ +microsoft.aspnetcore.app\2.2.0\microsoft.aspnetcore.app.2.2.0.nupkg +microsoft.aspnetcore.app\2.2.0\microsoft.aspnetcore.app.2.2.0.nupkg.sha512 +microsoft.aspnetcore.app\2.2.0\microsoft.aspnetcore.app.nuspec +microsoft.aspnetcore.applicationinsights.hostingstartup\2.2.0\.nupkg.metadata +microsoft.aspnetcore.applicationinsights.hostingstartup\2.2.0\.signature.p7s +microsoft.aspnetcore.applicationinsights.hostingstartup\2.2.0\lib\net461\Microsoft.AspNetCore.ApplicationInsights.HostingStartup.dll +microsoft.aspnetcore.applicationinsights.hostingstartup\2.2.0\lib\netcoreapp2.0\Microsoft.AspNetCore.ApplicationInsights.HostingStartup.dll +microsoft.aspnetcore.applicationinsights.hostingstartup\2.2.0\lib\netcoreapp2.1\Microsoft.AspNetCore.ApplicationInsights.HostingStartup.dll +microsoft.aspnetcore.applicationinsights.hostingstartup\2.2.0\microsoft.aspnetcore.applicationinsights.hostingstartup.2.2.0.nupkg +microsoft.aspnetcore.applicationinsights.hostingstartup\2.2.0\microsoft.aspnetcore.applicationinsights.hostingstartup.2.2.0.nupkg.sha512 +microsoft.aspnetcore.applicationinsights.hostingstartup\2.2.0\microsoft.aspnetcore.applicationinsights.hostingstartup.nuspec +microsoft.aspnetcore.authentication.abstractions\2.2.0\.nupkg.metadata +microsoft.aspnetcore.authentication.abstractions\2.2.0\.signature.p7s +microsoft.aspnetcore.authentication.abstractions\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Authentication.Abstractions.dll +microsoft.aspnetcore.authentication.abstractions\2.2.0\microsoft.aspnetcore.authentication.abstractions.2.2.0.nupkg +microsoft.aspnetcore.authentication.abstractions\2.2.0\microsoft.aspnetcore.authentication.abstractions.2.2.0.nupkg.sha512 +microsoft.aspnetcore.authentication.abstractions\2.2.0\microsoft.aspnetcore.authentication.abstractions.nuspec +microsoft.aspnetcore.authentication.azuread.ui\2.2.0\.nupkg.metadata +microsoft.aspnetcore.authentication.azuread.ui\2.2.0\.signature.p7s +microsoft.aspnetcore.authentication.azuread.ui\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Authentication.AzureAD.UI.dll +microsoft.aspnetcore.authentication.azuread.ui\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Authentication.AzureAD.UI.Views.dll +microsoft.aspnetcore.authentication.azuread.ui\2.2.0\microsoft.aspnetcore.authentication.azuread.ui.2.2.0.nupkg +microsoft.aspnetcore.authentication.azuread.ui\2.2.0\microsoft.aspnetcore.authentication.azuread.ui.2.2.0.nupkg.sha512 +microsoft.aspnetcore.authentication.azuread.ui\2.2.0\microsoft.aspnetcore.authentication.azuread.ui.nuspec +microsoft.aspnetcore.authentication.azureadb2c.ui\2.2.0\.nupkg.metadata +microsoft.aspnetcore.authentication.azureadb2c.ui\2.2.0\.signature.p7s +microsoft.aspnetcore.authentication.azureadb2c.ui\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Authentication.AzureADB2C.UI.dll +microsoft.aspnetcore.authentication.azureadb2c.ui\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Authentication.AzureADB2C.UI.Views.dll +microsoft.aspnetcore.authentication.azureadb2c.ui\2.2.0\microsoft.aspnetcore.authentication.azureadb2c.ui.2.2.0.nupkg +microsoft.aspnetcore.authentication.azureadb2c.ui\2.2.0\microsoft.aspnetcore.authentication.azureadb2c.ui.2.2.0.nupkg.sha512 +microsoft.aspnetcore.authentication.azureadb2c.ui\2.2.0\microsoft.aspnetcore.authentication.azureadb2c.ui.nuspec +microsoft.aspnetcore.authentication.cookies\2.2.0\.nupkg.metadata +microsoft.aspnetcore.authentication.cookies\2.2.0\.signature.p7s +microsoft.aspnetcore.authentication.cookies\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Authentication.Cookies.dll +microsoft.aspnetcore.authentication.cookies\2.2.0\microsoft.aspnetcore.authentication.cookies.2.2.0.nupkg +microsoft.aspnetcore.authentication.cookies\2.2.0\microsoft.aspnetcore.authentication.cookies.2.2.0.nupkg.sha512 +microsoft.aspnetcore.authentication.cookies\2.2.0\microsoft.aspnetcore.authentication.cookies.nuspec +microsoft.aspnetcore.authentication.core\2.2.0\.nupkg.metadata +microsoft.aspnetcore.authentication.core\2.2.0\.signature.p7s +microsoft.aspnetcore.authentication.core\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Authentication.Core.dll +microsoft.aspnetcore.authentication.core\2.2.0\microsoft.aspnetcore.authentication.core.2.2.0.nupkg +microsoft.aspnetcore.authentication.core\2.2.0\microsoft.aspnetcore.authentication.core.2.2.0.nupkg.sha512 +microsoft.aspnetcore.authentication.core\2.2.0\microsoft.aspnetcore.authentication.core.nuspec +microsoft.aspnetcore.authentication.facebook\2.2.0\.nupkg.metadata +microsoft.aspnetcore.authentication.facebook\2.2.0\.signature.p7s +microsoft.aspnetcore.authentication.facebook\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Authentication.Facebook.dll +microsoft.aspnetcore.authentication.facebook\2.2.0\microsoft.aspnetcore.authentication.facebook.2.2.0.nupkg +microsoft.aspnetcore.authentication.facebook\2.2.0\microsoft.aspnetcore.authentication.facebook.2.2.0.nupkg.sha512 +microsoft.aspnetcore.authentication.facebook\2.2.0\microsoft.aspnetcore.authentication.facebook.nuspec +microsoft.aspnetcore.authentication.google\2.2.0\.nupkg.metadata +microsoft.aspnetcore.authentication.google\2.2.0\.signature.p7s +microsoft.aspnetcore.authentication.google\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Authentication.Google.dll +microsoft.aspnetcore.authentication.google\2.2.0\microsoft.aspnetcore.authentication.google.2.2.0.nupkg +microsoft.aspnetcore.authentication.google\2.2.0\microsoft.aspnetcore.authentication.google.2.2.0.nupkg.sha512 +microsoft.aspnetcore.authentication.google\2.2.0\microsoft.aspnetcore.authentication.google.nuspec +microsoft.aspnetcore.authentication.jwtbearer\2.2.0\.nupkg.metadata +microsoft.aspnetcore.authentication.jwtbearer\2.2.0\.signature.p7s +microsoft.aspnetcore.authentication.jwtbearer\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Authentication.JwtBearer.dll +microsoft.aspnetcore.authentication.jwtbearer\2.2.0\microsoft.aspnetcore.authentication.jwtbearer.2.2.0.nupkg +microsoft.aspnetcore.authentication.jwtbearer\2.2.0\microsoft.aspnetcore.authentication.jwtbearer.2.2.0.nupkg.sha512 +microsoft.aspnetcore.authentication.jwtbearer\2.2.0\microsoft.aspnetcore.authentication.jwtbearer.nuspec +microsoft.aspnetcore.authentication.microsoftaccount\2.2.0\.nupkg.metadata +microsoft.aspnetcore.authentication.microsoftaccount\2.2.0\.signature.p7s +microsoft.aspnetcore.authentication.microsoftaccount\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Authentication.MicrosoftAccount.dll +microsoft.aspnetcore.authentication.microsoftaccount\2.2.0\microsoft.aspnetcore.authentication.microsoftaccount.2.2.0.nupkg +microsoft.aspnetcore.authentication.microsoftaccount\2.2.0\microsoft.aspnetcore.authentication.microsoftaccount.2.2.0.nupkg.sha512 +microsoft.aspnetcore.authentication.microsoftaccount\2.2.0\microsoft.aspnetcore.authentication.microsoftaccount.nuspec +microsoft.aspnetcore.authentication.oauth\2.2.0\.nupkg.metadata +microsoft.aspnetcore.authentication.oauth\2.2.0\.signature.p7s +microsoft.aspnetcore.authentication.oauth\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Authentication.OAuth.dll +microsoft.aspnetcore.authentication.oauth\2.2.0\microsoft.aspnetcore.authentication.oauth.2.2.0.nupkg +microsoft.aspnetcore.authentication.oauth\2.2.0\microsoft.aspnetcore.authentication.oauth.2.2.0.nupkg.sha512 +microsoft.aspnetcore.authentication.oauth\2.2.0\microsoft.aspnetcore.authentication.oauth.nuspec +microsoft.aspnetcore.authentication.openidconnect\2.2.0\.nupkg.metadata +microsoft.aspnetcore.authentication.openidconnect\2.2.0\.signature.p7s +microsoft.aspnetcore.authentication.openidconnect\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Authentication.OpenIdConnect.dll +microsoft.aspnetcore.authentication.openidconnect\2.2.0\microsoft.aspnetcore.authentication.openidconnect.2.2.0.nupkg +microsoft.aspnetcore.authentication.openidconnect\2.2.0\microsoft.aspnetcore.authentication.openidconnect.2.2.0.nupkg.sha512 +microsoft.aspnetcore.authentication.openidconnect\2.2.0\microsoft.aspnetcore.authentication.openidconnect.nuspec +microsoft.aspnetcore.authentication.twitter\2.2.0\.nupkg.metadata +microsoft.aspnetcore.authentication.twitter\2.2.0\.signature.p7s +microsoft.aspnetcore.authentication.twitter\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Authentication.Twitter.dll +microsoft.aspnetcore.authentication.twitter\2.2.0\microsoft.aspnetcore.authentication.twitter.2.2.0.nupkg +microsoft.aspnetcore.authentication.twitter\2.2.0\microsoft.aspnetcore.authentication.twitter.2.2.0.nupkg.sha512 +microsoft.aspnetcore.authentication.twitter\2.2.0\microsoft.aspnetcore.authentication.twitter.nuspec +microsoft.aspnetcore.authentication.wsfederation\2.2.0\.nupkg.metadata +microsoft.aspnetcore.authentication.wsfederation\2.2.0\.signature.p7s +microsoft.aspnetcore.authentication.wsfederation\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Authentication.WsFederation.dll +microsoft.aspnetcore.authentication.wsfederation\2.2.0\microsoft.aspnetcore.authentication.wsfederation.2.2.0.nupkg +microsoft.aspnetcore.authentication.wsfederation\2.2.0\microsoft.aspnetcore.authentication.wsfederation.2.2.0.nupkg.sha512 +microsoft.aspnetcore.authentication.wsfederation\2.2.0\microsoft.aspnetcore.authentication.wsfederation.nuspec +microsoft.aspnetcore.authentication\2.2.0\.nupkg.metadata +microsoft.aspnetcore.authentication\2.2.0\.signature.p7s +microsoft.aspnetcore.authentication\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Authentication.dll +microsoft.aspnetcore.authentication\2.2.0\microsoft.aspnetcore.authentication.2.2.0.nupkg +microsoft.aspnetcore.authentication\2.2.0\microsoft.aspnetcore.authentication.2.2.0.nupkg.sha512 +microsoft.aspnetcore.authentication\2.2.0\microsoft.aspnetcore.authentication.nuspec +microsoft.aspnetcore.authorization.policy\2.2.0\.nupkg.metadata +microsoft.aspnetcore.authorization.policy\2.2.0\.signature.p7s +microsoft.aspnetcore.authorization.policy\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Authorization.Policy.dll +microsoft.aspnetcore.authorization.policy\2.2.0\microsoft.aspnetcore.authorization.policy.2.2.0.nupkg +microsoft.aspnetcore.authorization.policy\2.2.0\microsoft.aspnetcore.authorization.policy.2.2.0.nupkg.sha512 +microsoft.aspnetcore.authorization.policy\2.2.0\microsoft.aspnetcore.authorization.policy.nuspec +microsoft.aspnetcore.authorization\2.2.0\.nupkg.metadata +microsoft.aspnetcore.authorization\2.2.0\.signature.p7s +microsoft.aspnetcore.authorization\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Authorization.dll +microsoft.aspnetcore.authorization\2.2.0\microsoft.aspnetcore.authorization.2.2.0.nupkg +microsoft.aspnetcore.authorization\2.2.0\microsoft.aspnetcore.authorization.2.2.0.nupkg.sha512 +microsoft.aspnetcore.authorization\2.2.0\microsoft.aspnetcore.authorization.nuspec +microsoft.aspnetcore.azureappservices.hostingstartup\2.2.0\.nupkg.metadata +microsoft.aspnetcore.azureappservices.hostingstartup\2.2.0\.signature.p7s +microsoft.aspnetcore.azureappservices.hostingstartup\2.2.0\lib\net461\Microsoft.AspNetCore.AzureAppServices.HostingStartup.dll +microsoft.aspnetcore.azureappservices.hostingstartup\2.2.0\lib\netcoreapp2.0\Microsoft.AspNetCore.AzureAppServices.HostingStartup.dll +microsoft.aspnetcore.azureappservices.hostingstartup\2.2.0\lib\netcoreapp2.1\Microsoft.AspNetCore.AzureAppServices.HostingStartup.dll +microsoft.aspnetcore.azureappservices.hostingstartup\2.2.0\microsoft.aspnetcore.azureappservices.hostingstartup.2.2.0.nupkg +microsoft.aspnetcore.azureappservices.hostingstartup\2.2.0\microsoft.aspnetcore.azureappservices.hostingstartup.2.2.0.nupkg.sha512 +microsoft.aspnetcore.azureappservices.hostingstartup\2.2.0\microsoft.aspnetcore.azureappservices.hostingstartup.nuspec +microsoft.aspnetcore.azureappservicesintegration\2.2.0\.nupkg.metadata +microsoft.aspnetcore.azureappservicesintegration\2.2.0\.signature.p7s +microsoft.aspnetcore.azureappservicesintegration\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.AzureAppServicesIntegration.dll +microsoft.aspnetcore.azureappservicesintegration\2.2.0\microsoft.aspnetcore.azureappservicesintegration.2.2.0.nupkg +microsoft.aspnetcore.azureappservicesintegration\2.2.0\microsoft.aspnetcore.azureappservicesintegration.2.2.0.nupkg.sha512 +microsoft.aspnetcore.azureappservicesintegration\2.2.0\microsoft.aspnetcore.azureappservicesintegration.nuspec +microsoft.aspnetcore.connections.abstractions\2.2.0\.nupkg.metadata +microsoft.aspnetcore.connections.abstractions\2.2.0\.signature.p7s +microsoft.aspnetcore.connections.abstractions\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Connections.Abstractions.dll +microsoft.aspnetcore.connections.abstractions\2.2.0\microsoft.aspnetcore.connections.abstractions.2.2.0.nupkg +microsoft.aspnetcore.connections.abstractions\2.2.0\microsoft.aspnetcore.connections.abstractions.2.2.0.nupkg.sha512 +microsoft.aspnetcore.connections.abstractions\2.2.0\microsoft.aspnetcore.connections.abstractions.nuspec +microsoft.aspnetcore.cookiepolicy\2.2.0\.nupkg.metadata +microsoft.aspnetcore.cookiepolicy\2.2.0\.signature.p7s +microsoft.aspnetcore.cookiepolicy\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.CookiePolicy.dll +microsoft.aspnetcore.cookiepolicy\2.2.0\microsoft.aspnetcore.cookiepolicy.2.2.0.nupkg +microsoft.aspnetcore.cookiepolicy\2.2.0\microsoft.aspnetcore.cookiepolicy.2.2.0.nupkg.sha512 +microsoft.aspnetcore.cookiepolicy\2.2.0\microsoft.aspnetcore.cookiepolicy.nuspec +microsoft.aspnetcore.cors\2.2.0\.nupkg.metadata +microsoft.aspnetcore.cors\2.2.0\.signature.p7s +microsoft.aspnetcore.cors\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Cors.dll +microsoft.aspnetcore.cors\2.2.0\microsoft.aspnetcore.cors.2.2.0.nupkg +microsoft.aspnetcore.cors\2.2.0\microsoft.aspnetcore.cors.2.2.0.nupkg.sha512 +microsoft.aspnetcore.cors\2.2.0\microsoft.aspnetcore.cors.nuspec +microsoft.aspnetcore.cryptography.internal\2.2.0\.nupkg.metadata +microsoft.aspnetcore.cryptography.internal\2.2.0\.signature.p7s +microsoft.aspnetcore.cryptography.internal\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Cryptography.Internal.dll +microsoft.aspnetcore.cryptography.internal\2.2.0\microsoft.aspnetcore.cryptography.internal.2.2.0.nupkg +microsoft.aspnetcore.cryptography.internal\2.2.0\microsoft.aspnetcore.cryptography.internal.2.2.0.nupkg.sha512 +microsoft.aspnetcore.cryptography.internal\2.2.0\microsoft.aspnetcore.cryptography.internal.nuspec +microsoft.aspnetcore.cryptography.keyderivation\2.2.0\.nupkg.metadata +microsoft.aspnetcore.cryptography.keyderivation\2.2.0\.signature.p7s +microsoft.aspnetcore.cryptography.keyderivation\2.2.0\lib\netcoreapp2.0\Microsoft.AspNetCore.Cryptography.KeyDerivation.dll +microsoft.aspnetcore.cryptography.keyderivation\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Cryptography.KeyDerivation.dll +microsoft.aspnetcore.cryptography.keyderivation\2.2.0\microsoft.aspnetcore.cryptography.keyderivation.2.2.0.nupkg +microsoft.aspnetcore.cryptography.keyderivation\2.2.0\microsoft.aspnetcore.cryptography.keyderivation.2.2.0.nupkg.sha512 +microsoft.aspnetcore.cryptography.keyderivation\2.2.0\microsoft.aspnetcore.cryptography.keyderivation.nuspec +microsoft.aspnetcore.dataprotection.abstractions\2.2.0\.nupkg.metadata +microsoft.aspnetcore.dataprotection.abstractions\2.2.0\.signature.p7s +microsoft.aspnetcore.dataprotection.abstractions\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.DataProtection.Abstractions.dll +microsoft.aspnetcore.dataprotection.abstractions\2.2.0\microsoft.aspnetcore.dataprotection.abstractions.2.2.0.nupkg +microsoft.aspnetcore.dataprotection.abstractions\2.2.0\microsoft.aspnetcore.dataprotection.abstractions.2.2.0.nupkg.sha512 +microsoft.aspnetcore.dataprotection.abstractions\2.2.0\microsoft.aspnetcore.dataprotection.abstractions.nuspec +microsoft.aspnetcore.dataprotection.azurekeyvault\2.2.0\.nupkg.metadata +microsoft.aspnetcore.dataprotection.azurekeyvault\2.2.0\.signature.p7s +microsoft.aspnetcore.dataprotection.azurekeyvault\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.DataProtection.AzureKeyVault.dll +microsoft.aspnetcore.dataprotection.azurekeyvault\2.2.0\microsoft.aspnetcore.dataprotection.azurekeyvault.2.2.0.nupkg +microsoft.aspnetcore.dataprotection.azurekeyvault\2.2.0\microsoft.aspnetcore.dataprotection.azurekeyvault.2.2.0.nupkg.sha512 +microsoft.aspnetcore.dataprotection.azurekeyvault\2.2.0\microsoft.aspnetcore.dataprotection.azurekeyvault.nuspec +microsoft.aspnetcore.dataprotection.azurestorage\2.2.0\.nupkg.metadata +microsoft.aspnetcore.dataprotection.azurestorage\2.2.0\.signature.p7s +microsoft.aspnetcore.dataprotection.azurestorage\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.DataProtection.AzureStorage.dll +microsoft.aspnetcore.dataprotection.azurestorage\2.2.0\microsoft.aspnetcore.dataprotection.azurestorage.2.2.0.nupkg +microsoft.aspnetcore.dataprotection.azurestorage\2.2.0\microsoft.aspnetcore.dataprotection.azurestorage.2.2.0.nupkg.sha512 +microsoft.aspnetcore.dataprotection.azurestorage\2.2.0\microsoft.aspnetcore.dataprotection.azurestorage.nuspec +microsoft.aspnetcore.dataprotection.extensions\2.2.0\.nupkg.metadata +microsoft.aspnetcore.dataprotection.extensions\2.2.0\.signature.p7s +microsoft.aspnetcore.dataprotection.extensions\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.DataProtection.Extensions.dll +microsoft.aspnetcore.dataprotection.extensions\2.2.0\microsoft.aspnetcore.dataprotection.extensions.2.2.0.nupkg +microsoft.aspnetcore.dataprotection.extensions\2.2.0\microsoft.aspnetcore.dataprotection.extensions.2.2.0.nupkg.sha512 +microsoft.aspnetcore.dataprotection.extensions\2.2.0\microsoft.aspnetcore.dataprotection.extensions.nuspec +microsoft.aspnetcore.dataprotection\2.2.0\.nupkg.metadata +microsoft.aspnetcore.dataprotection\2.2.0\.signature.p7s +microsoft.aspnetcore.dataprotection\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.DataProtection.dll +microsoft.aspnetcore.dataprotection\2.2.0\microsoft.aspnetcore.dataprotection.2.2.0.nupkg +microsoft.aspnetcore.dataprotection\2.2.0\microsoft.aspnetcore.dataprotection.2.2.0.nupkg.sha512 +microsoft.aspnetcore.dataprotection\2.2.0\microsoft.aspnetcore.dataprotection.nuspec +microsoft.aspnetcore.diagnostics.abstractions\2.2.0\.nupkg.metadata +microsoft.aspnetcore.diagnostics.abstractions\2.2.0\.signature.p7s +microsoft.aspnetcore.diagnostics.abstractions\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Diagnostics.Abstractions.dll +microsoft.aspnetcore.diagnostics.abstractions\2.2.0\microsoft.aspnetcore.diagnostics.abstractions.2.2.0.nupkg +microsoft.aspnetcore.diagnostics.abstractions\2.2.0\microsoft.aspnetcore.diagnostics.abstractions.2.2.0.nupkg.sha512 +microsoft.aspnetcore.diagnostics.abstractions\2.2.0\microsoft.aspnetcore.diagnostics.abstractions.nuspec +microsoft.aspnetcore.diagnostics.entityframeworkcore\2.2.0\.nupkg.metadata +microsoft.aspnetcore.diagnostics.entityframeworkcore\2.2.0\.signature.p7s +microsoft.aspnetcore.diagnostics.entityframeworkcore\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.dll +microsoft.aspnetcore.diagnostics.entityframeworkcore\2.2.0\microsoft.aspnetcore.diagnostics.entityframeworkcore.2.2.0.nupkg +microsoft.aspnetcore.diagnostics.entityframeworkcore\2.2.0\microsoft.aspnetcore.diagnostics.entityframeworkcore.2.2.0.nupkg.sha512 +microsoft.aspnetcore.diagnostics.entityframeworkcore\2.2.0\microsoft.aspnetcore.diagnostics.entityframeworkcore.nuspec +microsoft.aspnetcore.diagnostics.healthchecks\2.2.0\.nupkg.metadata +microsoft.aspnetcore.diagnostics.healthchecks\2.2.0\.signature.p7s +microsoft.aspnetcore.diagnostics.healthchecks\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Diagnostics.HealthChecks.dll +microsoft.aspnetcore.diagnostics.healthchecks\2.2.0\microsoft.aspnetcore.diagnostics.healthchecks.2.2.0.nupkg +microsoft.aspnetcore.diagnostics.healthchecks\2.2.0\microsoft.aspnetcore.diagnostics.healthchecks.2.2.0.nupkg.sha512 +microsoft.aspnetcore.diagnostics.healthchecks\2.2.0\microsoft.aspnetcore.diagnostics.healthchecks.nuspec +microsoft.aspnetcore.diagnostics\2.2.0\.nupkg.metadata +microsoft.aspnetcore.diagnostics\2.2.0\.signature.p7s +microsoft.aspnetcore.diagnostics\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Diagnostics.dll +microsoft.aspnetcore.diagnostics\2.2.0\microsoft.aspnetcore.diagnostics.2.2.0.nupkg +microsoft.aspnetcore.diagnostics\2.2.0\microsoft.aspnetcore.diagnostics.2.2.0.nupkg.sha512 +microsoft.aspnetcore.diagnostics\2.2.0\microsoft.aspnetcore.diagnostics.nuspec +microsoft.aspnetcore.hostfiltering\2.2.0\.nupkg.metadata +microsoft.aspnetcore.hostfiltering\2.2.0\.signature.p7s +microsoft.aspnetcore.hostfiltering\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.HostFiltering.dll +microsoft.aspnetcore.hostfiltering\2.2.0\microsoft.aspnetcore.hostfiltering.2.2.0.nupkg +microsoft.aspnetcore.hostfiltering\2.2.0\microsoft.aspnetcore.hostfiltering.2.2.0.nupkg.sha512 +microsoft.aspnetcore.hostfiltering\2.2.0\microsoft.aspnetcore.hostfiltering.nuspec +microsoft.aspnetcore.hosting.abstractions\2.2.0\.nupkg.metadata +microsoft.aspnetcore.hosting.abstractions\2.2.0\.signature.p7s +microsoft.aspnetcore.hosting.abstractions\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Hosting.Abstractions.dll +microsoft.aspnetcore.hosting.abstractions\2.2.0\microsoft.aspnetcore.hosting.abstractions.2.2.0.nupkg +microsoft.aspnetcore.hosting.abstractions\2.2.0\microsoft.aspnetcore.hosting.abstractions.2.2.0.nupkg.sha512 +microsoft.aspnetcore.hosting.abstractions\2.2.0\microsoft.aspnetcore.hosting.abstractions.nuspec +microsoft.aspnetcore.hosting.server.abstractions\2.2.0\.nupkg.metadata +microsoft.aspnetcore.hosting.server.abstractions\2.2.0\.signature.p7s +microsoft.aspnetcore.hosting.server.abstractions\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Hosting.Server.Abstractions.dll +microsoft.aspnetcore.hosting.server.abstractions\2.2.0\microsoft.aspnetcore.hosting.server.abstractions.2.2.0.nupkg +microsoft.aspnetcore.hosting.server.abstractions\2.2.0\microsoft.aspnetcore.hosting.server.abstractions.2.2.0.nupkg.sha512 +microsoft.aspnetcore.hosting.server.abstractions\2.2.0\microsoft.aspnetcore.hosting.server.abstractions.nuspec +microsoft.aspnetcore.hosting\2.2.0\.nupkg.metadata +microsoft.aspnetcore.hosting\2.2.0\.signature.p7s +microsoft.aspnetcore.hosting\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Hosting.dll +microsoft.aspnetcore.hosting\2.2.0\microsoft.aspnetcore.hosting.2.2.0.nupkg +microsoft.aspnetcore.hosting\2.2.0\microsoft.aspnetcore.hosting.2.2.0.nupkg.sha512 +microsoft.aspnetcore.hosting\2.2.0\microsoft.aspnetcore.hosting.nuspec +microsoft.aspnetcore.html.abstractions\2.2.0\.nupkg.metadata +microsoft.aspnetcore.html.abstractions\2.2.0\.signature.p7s +microsoft.aspnetcore.html.abstractions\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Html.Abstractions.dll +microsoft.aspnetcore.html.abstractions\2.2.0\microsoft.aspnetcore.html.abstractions.2.2.0.nupkg +microsoft.aspnetcore.html.abstractions\2.2.0\microsoft.aspnetcore.html.abstractions.2.2.0.nupkg.sha512 +microsoft.aspnetcore.html.abstractions\2.2.0\microsoft.aspnetcore.html.abstractions.nuspec +microsoft.aspnetcore.http.abstractions\2.2.0\.nupkg.metadata +microsoft.aspnetcore.http.abstractions\2.2.0\.signature.p7s +microsoft.aspnetcore.http.abstractions\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Http.Abstractions.dll +microsoft.aspnetcore.http.abstractions\2.2.0\microsoft.aspnetcore.http.abstractions.2.2.0.nupkg +microsoft.aspnetcore.http.abstractions\2.2.0\microsoft.aspnetcore.http.abstractions.2.2.0.nupkg.sha512 +microsoft.aspnetcore.http.abstractions\2.2.0\microsoft.aspnetcore.http.abstractions.nuspec +microsoft.aspnetcore.http.connections.common\1.1.0\.nupkg.metadata +microsoft.aspnetcore.http.connections.common\1.1.0\.signature.p7s +microsoft.aspnetcore.http.connections.common\1.1.0\lib\netstandard2.0\Microsoft.AspNetCore.Http.Connections.Common.dll +microsoft.aspnetcore.http.connections.common\1.1.0\microsoft.aspnetcore.http.connections.common.1.1.0.nupkg +microsoft.aspnetcore.http.connections.common\1.1.0\microsoft.aspnetcore.http.connections.common.1.1.0.nupkg.sha512 +microsoft.aspnetcore.http.connections.common\1.1.0\microsoft.aspnetcore.http.connections.common.nuspec +microsoft.aspnetcore.http.connections\1.1.0\.nupkg.metadata +microsoft.aspnetcore.http.connections\1.1.0\.signature.p7s +microsoft.aspnetcore.http.connections\1.1.0\lib\netcoreapp2.2\Microsoft.AspNetCore.Http.Connections.dll +microsoft.aspnetcore.http.connections\1.1.0\lib\netstandard2.0\Microsoft.AspNetCore.Http.Connections.dll +microsoft.aspnetcore.http.connections\1.1.0\microsoft.aspnetcore.http.connections.1.1.0.nupkg +microsoft.aspnetcore.http.connections\1.1.0\microsoft.aspnetcore.http.connections.1.1.0.nupkg.sha512 +microsoft.aspnetcore.http.connections\1.1.0\microsoft.aspnetcore.http.connections.nuspec +microsoft.aspnetcore.http.extensions\2.2.0\.nupkg.metadata +microsoft.aspnetcore.http.extensions\2.2.0\.signature.p7s +microsoft.aspnetcore.http.extensions\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Http.Extensions.dll +microsoft.aspnetcore.http.extensions\2.2.0\microsoft.aspnetcore.http.extensions.2.2.0.nupkg +microsoft.aspnetcore.http.extensions\2.2.0\microsoft.aspnetcore.http.extensions.2.2.0.nupkg.sha512 +microsoft.aspnetcore.http.extensions\2.2.0\microsoft.aspnetcore.http.extensions.nuspec +microsoft.aspnetcore.http.features\2.2.0\.nupkg.metadata +microsoft.aspnetcore.http.features\2.2.0\.signature.p7s +microsoft.aspnetcore.http.features\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Http.Features.dll +microsoft.aspnetcore.http.features\2.2.0\microsoft.aspnetcore.http.features.2.2.0.nupkg +microsoft.aspnetcore.http.features\2.2.0\microsoft.aspnetcore.http.features.2.2.0.nupkg.sha512 +microsoft.aspnetcore.http.features\2.2.0\microsoft.aspnetcore.http.features.nuspec +microsoft.aspnetcore.http\2.2.0\.nupkg.metadata +microsoft.aspnetcore.http\2.2.0\.signature.p7s +microsoft.aspnetcore.http\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Http.dll +microsoft.aspnetcore.http\2.2.0\microsoft.aspnetcore.http.2.2.0.nupkg +microsoft.aspnetcore.http\2.2.0\microsoft.aspnetcore.http.2.2.0.nupkg.sha512 +microsoft.aspnetcore.http\2.2.0\microsoft.aspnetcore.http.nuspec +microsoft.aspnetcore.httpoverrides\2.2.0\.nupkg.metadata +microsoft.aspnetcore.httpoverrides\2.2.0\.signature.p7s +microsoft.aspnetcore.httpoverrides\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.HttpOverrides.dll +microsoft.aspnetcore.httpoverrides\2.2.0\microsoft.aspnetcore.httpoverrides.2.2.0.nupkg +microsoft.aspnetcore.httpoverrides\2.2.0\microsoft.aspnetcore.httpoverrides.2.2.0.nupkg.sha512 +microsoft.aspnetcore.httpoverrides\2.2.0\microsoft.aspnetcore.httpoverrides.nuspec +microsoft.aspnetcore.httpspolicy\2.2.0\.nupkg.metadata +microsoft.aspnetcore.httpspolicy\2.2.0\.signature.p7s +microsoft.aspnetcore.httpspolicy\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.HttpsPolicy.dll +microsoft.aspnetcore.httpspolicy\2.2.0\microsoft.aspnetcore.httpspolicy.2.2.0.nupkg +microsoft.aspnetcore.httpspolicy\2.2.0\microsoft.aspnetcore.httpspolicy.2.2.0.nupkg.sha512 +microsoft.aspnetcore.httpspolicy\2.2.0\microsoft.aspnetcore.httpspolicy.nuspec +microsoft.aspnetcore.identity.entityframeworkcore\2.2.0\.nupkg.metadata +microsoft.aspnetcore.identity.entityframeworkcore\2.2.0\.signature.p7s +microsoft.aspnetcore.identity.entityframeworkcore\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Identity.EntityFrameworkCore.dll +microsoft.aspnetcore.identity.entityframeworkcore\2.2.0\microsoft.aspnetcore.identity.entityframeworkcore.2.2.0.nupkg +microsoft.aspnetcore.identity.entityframeworkcore\2.2.0\microsoft.aspnetcore.identity.entityframeworkcore.2.2.0.nupkg.sha512 +microsoft.aspnetcore.identity.entityframeworkcore\2.2.0\microsoft.aspnetcore.identity.entityframeworkcore.nuspec +microsoft.aspnetcore.identity.ui\2.2.0\.nupkg.metadata +microsoft.aspnetcore.identity.ui\2.2.0\.signature.p7s +microsoft.aspnetcore.identity.ui\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Identity.UI.dll +microsoft.aspnetcore.identity.ui\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Identity.UI.Views.V3.dll +microsoft.aspnetcore.identity.ui\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Identity.UI.Views.V4.dll +microsoft.aspnetcore.identity.ui\2.2.0\microsoft.aspnetcore.identity.ui.2.2.0.nupkg +microsoft.aspnetcore.identity.ui\2.2.0\microsoft.aspnetcore.identity.ui.2.2.0.nupkg.sha512 +microsoft.aspnetcore.identity.ui\2.2.0\microsoft.aspnetcore.identity.ui.nuspec +microsoft.aspnetcore.identity.ui\2.2.0\THIRD-PARTY-NOTICES.txt +microsoft.aspnetcore.identity\2.2.0\.nupkg.metadata +microsoft.aspnetcore.identity\2.2.0\.signature.p7s +microsoft.aspnetcore.identity\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Identity.dll +microsoft.aspnetcore.identity\2.2.0\microsoft.aspnetcore.identity.2.2.0.nupkg +microsoft.aspnetcore.identity\2.2.0\microsoft.aspnetcore.identity.2.2.0.nupkg.sha512 +microsoft.aspnetcore.identity\2.2.0\microsoft.aspnetcore.identity.nuspec +microsoft.aspnetcore.jsonpatch\2.2.0\.nupkg.metadata +microsoft.aspnetcore.jsonpatch\2.2.0\.signature.p7s +microsoft.aspnetcore.jsonpatch\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.JsonPatch.dll +microsoft.aspnetcore.jsonpatch\2.2.0\microsoft.aspnetcore.jsonpatch.2.2.0.nupkg +microsoft.aspnetcore.jsonpatch\2.2.0\microsoft.aspnetcore.jsonpatch.2.2.0.nupkg.sha512 +microsoft.aspnetcore.jsonpatch\2.2.0\microsoft.aspnetcore.jsonpatch.nuspec +microsoft.aspnetcore.localization.routing\2.2.0\.nupkg.metadata +microsoft.aspnetcore.localization.routing\2.2.0\.signature.p7s +microsoft.aspnetcore.localization.routing\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Localization.Routing.dll +microsoft.aspnetcore.localization.routing\2.2.0\microsoft.aspnetcore.localization.routing.2.2.0.nupkg +microsoft.aspnetcore.localization.routing\2.2.0\microsoft.aspnetcore.localization.routing.2.2.0.nupkg.sha512 +microsoft.aspnetcore.localization.routing\2.2.0\microsoft.aspnetcore.localization.routing.nuspec +microsoft.aspnetcore.localization\2.2.0\.nupkg.metadata +microsoft.aspnetcore.localization\2.2.0\.signature.p7s +microsoft.aspnetcore.localization\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Localization.dll +microsoft.aspnetcore.localization\2.2.0\microsoft.aspnetcore.localization.2.2.0.nupkg +microsoft.aspnetcore.localization\2.2.0\microsoft.aspnetcore.localization.2.2.0.nupkg.sha512 +microsoft.aspnetcore.localization\2.2.0\microsoft.aspnetcore.localization.nuspec +microsoft.aspnetcore.middlewareanalysis\2.2.0\.nupkg.metadata +microsoft.aspnetcore.middlewareanalysis\2.2.0\.signature.p7s +microsoft.aspnetcore.middlewareanalysis\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.MiddlewareAnalysis.dll +microsoft.aspnetcore.middlewareanalysis\2.2.0\microsoft.aspnetcore.middlewareanalysis.2.2.0.nupkg +microsoft.aspnetcore.middlewareanalysis\2.2.0\microsoft.aspnetcore.middlewareanalysis.2.2.0.nupkg.sha512 +microsoft.aspnetcore.middlewareanalysis\2.2.0\microsoft.aspnetcore.middlewareanalysis.nuspec +microsoft.aspnetcore.mvc.abstractions\2.2.0\.nupkg.metadata +microsoft.aspnetcore.mvc.abstractions\2.2.0\.signature.p7s +microsoft.aspnetcore.mvc.abstractions\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Mvc.Abstractions.dll +microsoft.aspnetcore.mvc.abstractions\2.2.0\microsoft.aspnetcore.mvc.abstractions.2.2.0.nupkg +microsoft.aspnetcore.mvc.abstractions\2.2.0\microsoft.aspnetcore.mvc.abstractions.2.2.0.nupkg.sha512 +microsoft.aspnetcore.mvc.abstractions\2.2.0\microsoft.aspnetcore.mvc.abstractions.nuspec +microsoft.aspnetcore.mvc.analyzers\2.2.0\.nupkg.metadata +microsoft.aspnetcore.mvc.analyzers\2.2.0\.signature.p7s +microsoft.aspnetcore.mvc.analyzers\2.2.0\analyzers\dotnet\cs\Microsoft.AspNetCore.Mvc.Analyzers.dll +microsoft.aspnetcore.mvc.analyzers\2.2.0\microsoft.aspnetcore.mvc.analyzers.2.2.0.nupkg +microsoft.aspnetcore.mvc.analyzers\2.2.0\microsoft.aspnetcore.mvc.analyzers.2.2.0.nupkg.sha512 +microsoft.aspnetcore.mvc.analyzers\2.2.0\microsoft.aspnetcore.mvc.analyzers.nuspec +microsoft.aspnetcore.mvc.apiexplorer\2.2.0\.nupkg.metadata +microsoft.aspnetcore.mvc.apiexplorer\2.2.0\.signature.p7s +microsoft.aspnetcore.mvc.apiexplorer\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Mvc.ApiExplorer.dll +microsoft.aspnetcore.mvc.apiexplorer\2.2.0\microsoft.aspnetcore.mvc.apiexplorer.2.2.0.nupkg +microsoft.aspnetcore.mvc.apiexplorer\2.2.0\microsoft.aspnetcore.mvc.apiexplorer.2.2.0.nupkg.sha512 +microsoft.aspnetcore.mvc.apiexplorer\2.2.0\microsoft.aspnetcore.mvc.apiexplorer.nuspec +microsoft.aspnetcore.mvc.core\2.2.0\.nupkg.metadata +microsoft.aspnetcore.mvc.core\2.2.0\.signature.p7s +microsoft.aspnetcore.mvc.core\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Mvc.Core.dll +microsoft.aspnetcore.mvc.core\2.2.0\microsoft.aspnetcore.mvc.core.2.2.0.nupkg +microsoft.aspnetcore.mvc.core\2.2.0\microsoft.aspnetcore.mvc.core.2.2.0.nupkg.sha512 +microsoft.aspnetcore.mvc.core\2.2.0\microsoft.aspnetcore.mvc.core.nuspec +microsoft.aspnetcore.mvc.cors\2.2.0\.nupkg.metadata +microsoft.aspnetcore.mvc.cors\2.2.0\.signature.p7s +microsoft.aspnetcore.mvc.cors\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Mvc.Cors.dll +microsoft.aspnetcore.mvc.cors\2.2.0\microsoft.aspnetcore.mvc.cors.2.2.0.nupkg +microsoft.aspnetcore.mvc.cors\2.2.0\microsoft.aspnetcore.mvc.cors.2.2.0.nupkg.sha512 +microsoft.aspnetcore.mvc.cors\2.2.0\microsoft.aspnetcore.mvc.cors.nuspec +microsoft.aspnetcore.mvc.dataannotations\2.2.0\.nupkg.metadata +microsoft.aspnetcore.mvc.dataannotations\2.2.0\.signature.p7s +microsoft.aspnetcore.mvc.dataannotations\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Mvc.DataAnnotations.dll +microsoft.aspnetcore.mvc.dataannotations\2.2.0\microsoft.aspnetcore.mvc.dataannotations.2.2.0.nupkg +microsoft.aspnetcore.mvc.dataannotations\2.2.0\microsoft.aspnetcore.mvc.dataannotations.2.2.0.nupkg.sha512 +microsoft.aspnetcore.mvc.dataannotations\2.2.0\microsoft.aspnetcore.mvc.dataannotations.nuspec +microsoft.aspnetcore.mvc.formatters.json\2.2.0\.nupkg.metadata +microsoft.aspnetcore.mvc.formatters.json\2.2.0\.signature.p7s +microsoft.aspnetcore.mvc.formatters.json\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Mvc.Formatters.Json.dll +microsoft.aspnetcore.mvc.formatters.json\2.2.0\microsoft.aspnetcore.mvc.formatters.json.2.2.0.nupkg +microsoft.aspnetcore.mvc.formatters.json\2.2.0\microsoft.aspnetcore.mvc.formatters.json.2.2.0.nupkg.sha512 +microsoft.aspnetcore.mvc.formatters.json\2.2.0\microsoft.aspnetcore.mvc.formatters.json.nuspec +microsoft.aspnetcore.mvc.formatters.xml\2.2.0\.nupkg.metadata +microsoft.aspnetcore.mvc.formatters.xml\2.2.0\.signature.p7s +microsoft.aspnetcore.mvc.formatters.xml\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Mvc.Formatters.Xml.dll +microsoft.aspnetcore.mvc.formatters.xml\2.2.0\microsoft.aspnetcore.mvc.formatters.xml.2.2.0.nupkg +microsoft.aspnetcore.mvc.formatters.xml\2.2.0\microsoft.aspnetcore.mvc.formatters.xml.2.2.0.nupkg.sha512 +microsoft.aspnetcore.mvc.formatters.xml\2.2.0\microsoft.aspnetcore.mvc.formatters.xml.nuspec +microsoft.aspnetcore.mvc.localization\2.2.0\.nupkg.metadata +microsoft.aspnetcore.mvc.localization\2.2.0\.signature.p7s +microsoft.aspnetcore.mvc.localization\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Mvc.Localization.dll +microsoft.aspnetcore.mvc.localization\2.2.0\microsoft.aspnetcore.mvc.localization.2.2.0.nupkg +microsoft.aspnetcore.mvc.localization\2.2.0\microsoft.aspnetcore.mvc.localization.2.2.0.nupkg.sha512 +microsoft.aspnetcore.mvc.localization\2.2.0\microsoft.aspnetcore.mvc.localization.nuspec +microsoft.aspnetcore.mvc.razor.extensions\2.2.0\.nupkg.metadata +microsoft.aspnetcore.mvc.razor.extensions\2.2.0\.signature.p7s +microsoft.aspnetcore.mvc.razor.extensions\2.2.0\build\netstandard2.0\Microsoft.AspNetCore.Mvc.Razor.Extensions.props +microsoft.aspnetcore.mvc.razor.extensions\2.2.0\build\netstandard2.0\Microsoft.AspNetCore.Mvc.Razor.Extensions.targets +microsoft.aspnetcore.mvc.razor.extensions\2.2.0\lib\net46\Microsoft.AspNetCore.Mvc.Razor.Extensions.dll +microsoft.aspnetcore.mvc.razor.extensions\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Mvc.Razor.Extensions.dll +microsoft.aspnetcore.mvc.razor.extensions\2.2.0\microsoft.aspnetcore.mvc.razor.extensions.2.2.0.nupkg +microsoft.aspnetcore.mvc.razor.extensions\2.2.0\microsoft.aspnetcore.mvc.razor.extensions.2.2.0.nupkg.sha512 +microsoft.aspnetcore.mvc.razor.extensions\2.2.0\microsoft.aspnetcore.mvc.razor.extensions.nuspec +microsoft.aspnetcore.mvc.razor.viewcompilation\2.2.0\.nupkg.metadata +microsoft.aspnetcore.mvc.razor.viewcompilation\2.2.0\.signature.p7s +microsoft.aspnetcore.mvc.razor.viewcompilation\2.2.0\build\netstandard2.0\Microsoft.AspNetCore.Mvc.Razor.ViewCompilation.targets +microsoft.aspnetcore.mvc.razor.viewcompilation\2.2.0\build\netstandard2.0\Microsoft.AspNetCore.Mvc.Razor.ViewCompilation.Tasks.dll +microsoft.aspnetcore.mvc.razor.viewcompilation\2.2.0\build\netstandard2.0\net461\Microsoft.AspNetCore.Mvc.Razor.ViewCompilation.exe +microsoft.aspnetcore.mvc.razor.viewcompilation\2.2.0\build\netstandard2.0\net461\Microsoft.AspNetCore.Mvc.Razor.ViewCompilation-x86.exe +microsoft.aspnetcore.mvc.razor.viewcompilation\2.2.0\build\netstandard2.0\netcoreapp2.0\Microsoft.AspNetCore.Mvc.Razor.ViewCompilation.dll +microsoft.aspnetcore.mvc.razor.viewcompilation\2.2.0\microsoft.aspnetcore.mvc.razor.viewcompilation.2.2.0.nupkg +microsoft.aspnetcore.mvc.razor.viewcompilation\2.2.0\microsoft.aspnetcore.mvc.razor.viewcompilation.2.2.0.nupkg.sha512 +microsoft.aspnetcore.mvc.razor.viewcompilation\2.2.0\microsoft.aspnetcore.mvc.razor.viewcompilation.nuspec +microsoft.aspnetcore.mvc.razor\2.2.0\.nupkg.metadata +microsoft.aspnetcore.mvc.razor\2.2.0\.signature.p7s +microsoft.aspnetcore.mvc.razor\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Mvc.Razor.dll +microsoft.aspnetcore.mvc.razor\2.2.0\microsoft.aspnetcore.mvc.razor.2.2.0.nupkg +microsoft.aspnetcore.mvc.razor\2.2.0\microsoft.aspnetcore.mvc.razor.2.2.0.nupkg.sha512 +microsoft.aspnetcore.mvc.razor\2.2.0\microsoft.aspnetcore.mvc.razor.nuspec +microsoft.aspnetcore.mvc.razorpages\2.2.0\.nupkg.metadata +microsoft.aspnetcore.mvc.razorpages\2.2.0\.signature.p7s +microsoft.aspnetcore.mvc.razorpages\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Mvc.RazorPages.dll +microsoft.aspnetcore.mvc.razorpages\2.2.0\microsoft.aspnetcore.mvc.razorpages.2.2.0.nupkg +microsoft.aspnetcore.mvc.razorpages\2.2.0\microsoft.aspnetcore.mvc.razorpages.2.2.0.nupkg.sha512 +microsoft.aspnetcore.mvc.razorpages\2.2.0\microsoft.aspnetcore.mvc.razorpages.nuspec +microsoft.aspnetcore.mvc.taghelpers\2.2.0\.nupkg.metadata +microsoft.aspnetcore.mvc.taghelpers\2.2.0\.signature.p7s +microsoft.aspnetcore.mvc.taghelpers\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Mvc.TagHelpers.dll +microsoft.aspnetcore.mvc.taghelpers\2.2.0\microsoft.aspnetcore.mvc.taghelpers.2.2.0.nupkg +microsoft.aspnetcore.mvc.taghelpers\2.2.0\microsoft.aspnetcore.mvc.taghelpers.2.2.0.nupkg.sha512 +microsoft.aspnetcore.mvc.taghelpers\2.2.0\microsoft.aspnetcore.mvc.taghelpers.nuspec +microsoft.aspnetcore.mvc.viewfeatures\2.2.0\.nupkg.metadata +microsoft.aspnetcore.mvc.viewfeatures\2.2.0\.signature.p7s +microsoft.aspnetcore.mvc.viewfeatures\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Mvc.ViewFeatures.dll +microsoft.aspnetcore.mvc.viewfeatures\2.2.0\microsoft.aspnetcore.mvc.viewfeatures.2.2.0.nupkg +microsoft.aspnetcore.mvc.viewfeatures\2.2.0\microsoft.aspnetcore.mvc.viewfeatures.2.2.0.nupkg.sha512 +microsoft.aspnetcore.mvc.viewfeatures\2.2.0\microsoft.aspnetcore.mvc.viewfeatures.nuspec +microsoft.aspnetcore.mvc\2.2.0\.nupkg.metadata +microsoft.aspnetcore.mvc\2.2.0\.signature.p7s +microsoft.aspnetcore.mvc\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Mvc.dll +microsoft.aspnetcore.mvc\2.2.0\microsoft.aspnetcore.mvc.2.2.0.nupkg +microsoft.aspnetcore.mvc\2.2.0\microsoft.aspnetcore.mvc.2.2.0.nupkg.sha512 +microsoft.aspnetcore.mvc\2.2.0\microsoft.aspnetcore.mvc.nuspec +microsoft.aspnetcore.nodeservices\2.2.0\.nupkg.metadata +microsoft.aspnetcore.nodeservices\2.2.0\.signature.p7s +microsoft.aspnetcore.nodeservices\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.NodeServices.dll +microsoft.aspnetcore.nodeservices\2.2.0\microsoft.aspnetcore.nodeservices.2.2.0.nupkg +microsoft.aspnetcore.nodeservices\2.2.0\microsoft.aspnetcore.nodeservices.2.2.0.nupkg.sha512 +microsoft.aspnetcore.nodeservices\2.2.0\microsoft.aspnetcore.nodeservices.nuspec +microsoft.aspnetcore.owin\2.2.0\.nupkg.metadata +microsoft.aspnetcore.owin\2.2.0\.signature.p7s +microsoft.aspnetcore.owin\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Owin.dll +microsoft.aspnetcore.owin\2.2.0\microsoft.aspnetcore.owin.2.2.0.nupkg +microsoft.aspnetcore.owin\2.2.0\microsoft.aspnetcore.owin.2.2.0.nupkg.sha512 +microsoft.aspnetcore.owin\2.2.0\microsoft.aspnetcore.owin.nuspec +microsoft.aspnetcore.razor.design\2.2.0\.nupkg.metadata +microsoft.aspnetcore.razor.design\2.2.0\.signature.p7s +microsoft.aspnetcore.razor.design\2.2.0\build\netstandard2.0\Microsoft.AspNetCore.Razor.Design.CodeGeneration.targets +microsoft.aspnetcore.razor.design\2.2.0\build\netstandard2.0\Microsoft.AspNetCore.Razor.Design.props +microsoft.aspnetcore.razor.design\2.2.0\buildMultiTargeting\Microsoft.AspNetCore.Razor.Design.props +microsoft.aspnetcore.razor.design\2.2.0\microsoft.aspnetcore.razor.design.2.2.0.nupkg +microsoft.aspnetcore.razor.design\2.2.0\microsoft.aspnetcore.razor.design.2.2.0.nupkg.sha512 +microsoft.aspnetcore.razor.design\2.2.0\microsoft.aspnetcore.razor.design.nuspec +microsoft.aspnetcore.razor.design\2.2.0\tools\Microsoft.AspNetCore.Razor.Language.dll +microsoft.aspnetcore.razor.design\2.2.0\tools\Microsoft.CodeAnalysis.CSharp.dll +microsoft.aspnetcore.razor.design\2.2.0\tools\Microsoft.CodeAnalysis.dll +microsoft.aspnetcore.razor.design\2.2.0\tools\Microsoft.CodeAnalysis.Razor.dll +microsoft.aspnetcore.razor.design\2.2.0\tools\Newtonsoft.Json.dll +microsoft.aspnetcore.razor.design\2.2.0\tools\runtimes\unix\lib\netstandard1.3\System.Text.Encoding.CodePages.dll +microsoft.aspnetcore.razor.design\2.2.0\tools\runtimes\win\lib\netstandard1.3\System.Text.Encoding.CodePages.dll +microsoft.aspnetcore.razor.design\2.2.0\tools\rzc.deps.json +microsoft.aspnetcore.razor.design\2.2.0\tools\rzc.dll +microsoft.aspnetcore.razor.design\2.2.0\tools\rzc.runtimeconfig.json +microsoft.aspnetcore.razor.language\2.2.0\.nupkg.metadata +microsoft.aspnetcore.razor.language\2.2.0\.signature.p7s +microsoft.aspnetcore.razor.language\2.2.0\lib\net46\Microsoft.AspNetCore.Razor.Language.dll +microsoft.aspnetcore.razor.language\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Razor.Language.dll +microsoft.aspnetcore.razor.language\2.2.0\microsoft.aspnetcore.razor.language.2.2.0.nupkg +microsoft.aspnetcore.razor.language\2.2.0\microsoft.aspnetcore.razor.language.2.2.0.nupkg.sha512 +microsoft.aspnetcore.razor.language\2.2.0\microsoft.aspnetcore.razor.language.nuspec +microsoft.aspnetcore.razor.runtime\2.2.0\.nupkg.metadata +microsoft.aspnetcore.razor.runtime\2.2.0\.signature.p7s +microsoft.aspnetcore.razor.runtime\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Razor.Runtime.dll +microsoft.aspnetcore.razor.runtime\2.2.0\microsoft.aspnetcore.razor.runtime.2.2.0.nupkg +microsoft.aspnetcore.razor.runtime\2.2.0\microsoft.aspnetcore.razor.runtime.2.2.0.nupkg.sha512 +microsoft.aspnetcore.razor.runtime\2.2.0\microsoft.aspnetcore.razor.runtime.nuspec +microsoft.aspnetcore.razor\2.2.0\.nupkg.metadata +microsoft.aspnetcore.razor\2.2.0\.signature.p7s +microsoft.aspnetcore.razor\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Razor.dll +microsoft.aspnetcore.razor\2.2.0\microsoft.aspnetcore.razor.2.2.0.nupkg +microsoft.aspnetcore.razor\2.2.0\microsoft.aspnetcore.razor.2.2.0.nupkg.sha512 +microsoft.aspnetcore.razor\2.2.0\microsoft.aspnetcore.razor.nuspec +microsoft.aspnetcore.responsecaching.abstractions\2.2.0\.nupkg.metadata +microsoft.aspnetcore.responsecaching.abstractions\2.2.0\.signature.p7s +microsoft.aspnetcore.responsecaching.abstractions\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.ResponseCaching.Abstractions.dll +microsoft.aspnetcore.responsecaching.abstractions\2.2.0\microsoft.aspnetcore.responsecaching.abstractions.2.2.0.nupkg +microsoft.aspnetcore.responsecaching.abstractions\2.2.0\microsoft.aspnetcore.responsecaching.abstractions.2.2.0.nupkg.sha512 +microsoft.aspnetcore.responsecaching.abstractions\2.2.0\microsoft.aspnetcore.responsecaching.abstractions.nuspec +microsoft.aspnetcore.responsecaching\2.2.0\.nupkg.metadata +microsoft.aspnetcore.responsecaching\2.2.0\.signature.p7s +microsoft.aspnetcore.responsecaching\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.ResponseCaching.dll +microsoft.aspnetcore.responsecaching\2.2.0\microsoft.aspnetcore.responsecaching.2.2.0.nupkg +microsoft.aspnetcore.responsecaching\2.2.0\microsoft.aspnetcore.responsecaching.2.2.0.nupkg.sha512 +microsoft.aspnetcore.responsecaching\2.2.0\microsoft.aspnetcore.responsecaching.nuspec +microsoft.aspnetcore.responsecompression\2.2.0\.nupkg.metadata +microsoft.aspnetcore.responsecompression\2.2.0\.signature.p7s +microsoft.aspnetcore.responsecompression\2.2.0\lib\net461\Microsoft.AspNetCore.ResponseCompression.dll +microsoft.aspnetcore.responsecompression\2.2.0\lib\netcoreapp2.1\Microsoft.AspNetCore.ResponseCompression.dll +microsoft.aspnetcore.responsecompression\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.ResponseCompression.dll +microsoft.aspnetcore.responsecompression\2.2.0\microsoft.aspnetcore.responsecompression.2.2.0.nupkg +microsoft.aspnetcore.responsecompression\2.2.0\microsoft.aspnetcore.responsecompression.2.2.0.nupkg.sha512 +microsoft.aspnetcore.responsecompression\2.2.0\microsoft.aspnetcore.responsecompression.nuspec +microsoft.aspnetcore.rewrite\2.2.0\.nupkg.metadata +microsoft.aspnetcore.rewrite\2.2.0\.signature.p7s +microsoft.aspnetcore.rewrite\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Rewrite.dll +microsoft.aspnetcore.rewrite\2.2.0\microsoft.aspnetcore.rewrite.2.2.0.nupkg +microsoft.aspnetcore.rewrite\2.2.0\microsoft.aspnetcore.rewrite.2.2.0.nupkg.sha512 +microsoft.aspnetcore.rewrite\2.2.0\microsoft.aspnetcore.rewrite.nuspec +microsoft.aspnetcore.routing.abstractions\2.2.0\.nupkg.metadata +microsoft.aspnetcore.routing.abstractions\2.2.0\.signature.p7s +microsoft.aspnetcore.routing.abstractions\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Routing.Abstractions.dll +microsoft.aspnetcore.routing.abstractions\2.2.0\microsoft.aspnetcore.routing.abstractions.2.2.0.nupkg +microsoft.aspnetcore.routing.abstractions\2.2.0\microsoft.aspnetcore.routing.abstractions.2.2.0.nupkg.sha512 +microsoft.aspnetcore.routing.abstractions\2.2.0\microsoft.aspnetcore.routing.abstractions.nuspec +microsoft.aspnetcore.routing\2.2.0\.nupkg.metadata +microsoft.aspnetcore.routing\2.2.0\.signature.p7s +microsoft.aspnetcore.routing\2.2.0\lib\netcoreapp2.2\Microsoft.AspNetCore.Routing.dll +microsoft.aspnetcore.routing\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Routing.dll +microsoft.aspnetcore.routing\2.2.0\microsoft.aspnetcore.routing.2.2.0.nupkg +microsoft.aspnetcore.routing\2.2.0\microsoft.aspnetcore.routing.2.2.0.nupkg.sha512 +microsoft.aspnetcore.routing\2.2.0\microsoft.aspnetcore.routing.nuspec +microsoft.aspnetcore.server.httpsys\2.2.0\.nupkg.metadata +microsoft.aspnetcore.server.httpsys\2.2.0\.signature.p7s +microsoft.aspnetcore.server.httpsys\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Server.HttpSys.dll +microsoft.aspnetcore.server.httpsys\2.2.0\microsoft.aspnetcore.server.httpsys.2.2.0.nupkg +microsoft.aspnetcore.server.httpsys\2.2.0\microsoft.aspnetcore.server.httpsys.2.2.0.nupkg.sha512 +microsoft.aspnetcore.server.httpsys\2.2.0\microsoft.aspnetcore.server.httpsys.nuspec +microsoft.aspnetcore.server.iis\2.2.0\.nupkg.metadata +microsoft.aspnetcore.server.iis\2.2.0\.signature.p7s +microsoft.aspnetcore.server.iis\2.2.0\build\netstandard2.0\Microsoft.AspNetCore.Server.IIS.targets +microsoft.aspnetcore.server.iis\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Server.IIS.dll +microsoft.aspnetcore.server.iis\2.2.0\microsoft.aspnetcore.server.iis.2.2.0.nupkg +microsoft.aspnetcore.server.iis\2.2.0\microsoft.aspnetcore.server.iis.2.2.0.nupkg.sha512 +microsoft.aspnetcore.server.iis\2.2.0\microsoft.aspnetcore.server.iis.nuspec +microsoft.aspnetcore.server.iis\2.2.0\runtimes\win-x64\nativeassets\netcoreapp2.2\aspnetcorev2_inprocess.dll +microsoft.aspnetcore.server.iis\2.2.0\runtimes\win-x86\nativeassets\netcoreapp2.2\aspnetcorev2_inprocess.dll +microsoft.aspnetcore.server.iisintegration\2.2.0\.nupkg.metadata +microsoft.aspnetcore.server.iisintegration\2.2.0\.signature.p7s +microsoft.aspnetcore.server.iisintegration\2.2.0\build\netstandard2.0\Microsoft.AspNetCore.Server.IISIntegration.targets +microsoft.aspnetcore.server.iisintegration\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Server.IISIntegration.dll +microsoft.aspnetcore.server.iisintegration\2.2.0\microsoft.aspnetcore.server.iisintegration.2.2.0.nupkg +microsoft.aspnetcore.server.iisintegration\2.2.0\microsoft.aspnetcore.server.iisintegration.2.2.0.nupkg.sha512 +microsoft.aspnetcore.server.iisintegration\2.2.0\microsoft.aspnetcore.server.iisintegration.nuspec +microsoft.aspnetcore.server.kestrel.core\2.2.0\.nupkg.metadata +microsoft.aspnetcore.server.kestrel.core\2.2.0\.signature.p7s +microsoft.aspnetcore.server.kestrel.core\2.2.0\lib\netcoreapp2.1\Microsoft.AspNetCore.Server.Kestrel.Core.dll +microsoft.aspnetcore.server.kestrel.core\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Server.Kestrel.Core.dll +microsoft.aspnetcore.server.kestrel.core\2.2.0\microsoft.aspnetcore.server.kestrel.core.2.2.0.nupkg +microsoft.aspnetcore.server.kestrel.core\2.2.0\microsoft.aspnetcore.server.kestrel.core.2.2.0.nupkg.sha512 +microsoft.aspnetcore.server.kestrel.core\2.2.0\microsoft.aspnetcore.server.kestrel.core.nuspec +microsoft.aspnetcore.server.kestrel.https\2.2.0\.nupkg.metadata +microsoft.aspnetcore.server.kestrel.https\2.2.0\.signature.p7s +microsoft.aspnetcore.server.kestrel.https\2.2.0\lib\netcoreapp2.1\Microsoft.AspNetCore.Server.Kestrel.Https.dll +microsoft.aspnetcore.server.kestrel.https\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Server.Kestrel.Https.dll +microsoft.aspnetcore.server.kestrel.https\2.2.0\microsoft.aspnetcore.server.kestrel.https.2.2.0.nupkg +microsoft.aspnetcore.server.kestrel.https\2.2.0\microsoft.aspnetcore.server.kestrel.https.2.2.0.nupkg.sha512 +microsoft.aspnetcore.server.kestrel.https\2.2.0\microsoft.aspnetcore.server.kestrel.https.nuspec +microsoft.aspnetcore.server.kestrel.transport.abstractions\2.2.0\.nupkg.metadata +microsoft.aspnetcore.server.kestrel.transport.abstractions\2.2.0\.signature.p7s +microsoft.aspnetcore.server.kestrel.transport.abstractions\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.dll +microsoft.aspnetcore.server.kestrel.transport.abstractions\2.2.0\microsoft.aspnetcore.server.kestrel.transport.abstractions.2.2.0.nupkg +microsoft.aspnetcore.server.kestrel.transport.abstractions\2.2.0\microsoft.aspnetcore.server.kestrel.transport.abstractions.2.2.0.nupkg.sha512 +microsoft.aspnetcore.server.kestrel.transport.abstractions\2.2.0\microsoft.aspnetcore.server.kestrel.transport.abstractions.nuspec +microsoft.aspnetcore.server.kestrel.transport.libuv\2.2.0\.nupkg.metadata +microsoft.aspnetcore.server.kestrel.transport.libuv\2.2.0\.signature.p7s +microsoft.aspnetcore.server.kestrel.transport.libuv\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.dll +microsoft.aspnetcore.server.kestrel.transport.libuv\2.2.0\microsoft.aspnetcore.server.kestrel.transport.libuv.2.2.0.nupkg +microsoft.aspnetcore.server.kestrel.transport.libuv\2.2.0\microsoft.aspnetcore.server.kestrel.transport.libuv.2.2.0.nupkg.sha512 +microsoft.aspnetcore.server.kestrel.transport.libuv\2.2.0\microsoft.aspnetcore.server.kestrel.transport.libuv.nuspec +microsoft.aspnetcore.server.kestrel.transport.sockets\2.2.0\.nupkg.metadata +microsoft.aspnetcore.server.kestrel.transport.sockets\2.2.0\.signature.p7s +microsoft.aspnetcore.server.kestrel.transport.sockets\2.2.0\lib\netcoreapp2.1\Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.dll +microsoft.aspnetcore.server.kestrel.transport.sockets\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.dll +microsoft.aspnetcore.server.kestrel.transport.sockets\2.2.0\microsoft.aspnetcore.server.kestrel.transport.sockets.2.2.0.nupkg +microsoft.aspnetcore.server.kestrel.transport.sockets\2.2.0\microsoft.aspnetcore.server.kestrel.transport.sockets.2.2.0.nupkg.sha512 +microsoft.aspnetcore.server.kestrel.transport.sockets\2.2.0\microsoft.aspnetcore.server.kestrel.transport.sockets.nuspec +microsoft.aspnetcore.server.kestrel\2.2.0\.nupkg.metadata +microsoft.aspnetcore.server.kestrel\2.2.0\.signature.p7s +microsoft.aspnetcore.server.kestrel\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Server.Kestrel.dll +microsoft.aspnetcore.server.kestrel\2.2.0\microsoft.aspnetcore.server.kestrel.2.2.0.nupkg +microsoft.aspnetcore.server.kestrel\2.2.0\microsoft.aspnetcore.server.kestrel.2.2.0.nupkg.sha512 +microsoft.aspnetcore.server.kestrel\2.2.0\microsoft.aspnetcore.server.kestrel.nuspec +microsoft.aspnetcore.session\2.2.0\.nupkg.metadata +microsoft.aspnetcore.session\2.2.0\.signature.p7s +microsoft.aspnetcore.session\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Session.dll +microsoft.aspnetcore.session\2.2.0\microsoft.aspnetcore.session.2.2.0.nupkg +microsoft.aspnetcore.session\2.2.0\microsoft.aspnetcore.session.2.2.0.nupkg.sha512 +microsoft.aspnetcore.session\2.2.0\microsoft.aspnetcore.session.nuspec +microsoft.aspnetcore.signalr.common\1.1.0\.nupkg.metadata +microsoft.aspnetcore.signalr.common\1.1.0\.signature.p7s +microsoft.aspnetcore.signalr.common\1.1.0\lib\netcoreapp2.2\Microsoft.AspNetCore.SignalR.Common.dll +microsoft.aspnetcore.signalr.common\1.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Common.dll +microsoft.aspnetcore.signalr.common\1.1.0\microsoft.aspnetcore.signalr.common.1.1.0.nupkg +microsoft.aspnetcore.signalr.common\1.1.0\microsoft.aspnetcore.signalr.common.1.1.0.nupkg.sha512 +microsoft.aspnetcore.signalr.common\1.1.0\microsoft.aspnetcore.signalr.common.nuspec +microsoft.aspnetcore.signalr.core\1.1.0\.nupkg.metadata +microsoft.aspnetcore.signalr.core\1.1.0\.signature.p7s +microsoft.aspnetcore.signalr.core\1.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Core.dll +microsoft.aspnetcore.signalr.core\1.1.0\microsoft.aspnetcore.signalr.core.1.1.0.nupkg +microsoft.aspnetcore.signalr.core\1.1.0\microsoft.aspnetcore.signalr.core.1.1.0.nupkg.sha512 +microsoft.aspnetcore.signalr.core\1.1.0\microsoft.aspnetcore.signalr.core.nuspec +microsoft.aspnetcore.signalr.protocols.json\1.1.0\.nupkg.metadata +microsoft.aspnetcore.signalr.protocols.json\1.1.0\.signature.p7s +microsoft.aspnetcore.signalr.protocols.json\1.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Protocols.Json.dll +microsoft.aspnetcore.signalr.protocols.json\1.1.0\microsoft.aspnetcore.signalr.protocols.json.1.1.0.nupkg +microsoft.aspnetcore.signalr.protocols.json\1.1.0\microsoft.aspnetcore.signalr.protocols.json.1.1.0.nupkg.sha512 +microsoft.aspnetcore.signalr.protocols.json\1.1.0\microsoft.aspnetcore.signalr.protocols.json.nuspec +microsoft.aspnetcore.signalr.redis\1.1.0\.nupkg.metadata +microsoft.aspnetcore.signalr.redis\1.1.0\.signature.p7s +microsoft.aspnetcore.signalr.redis\1.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Redis.dll +microsoft.aspnetcore.signalr.redis\1.1.0\microsoft.aspnetcore.signalr.redis.1.1.0.nupkg +microsoft.aspnetcore.signalr.redis\1.1.0\microsoft.aspnetcore.signalr.redis.1.1.0.nupkg.sha512 +microsoft.aspnetcore.signalr.redis\1.1.0\microsoft.aspnetcore.signalr.redis.nuspec +microsoft.aspnetcore.signalr\1.1.0\.nupkg.metadata +microsoft.aspnetcore.signalr\1.1.0\.signature.p7s +microsoft.aspnetcore.signalr\1.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.dll +microsoft.aspnetcore.signalr\1.1.0\microsoft.aspnetcore.signalr.1.1.0.nupkg +microsoft.aspnetcore.signalr\1.1.0\microsoft.aspnetcore.signalr.1.1.0.nupkg.sha512 +microsoft.aspnetcore.signalr\1.1.0\microsoft.aspnetcore.signalr.nuspec +microsoft.aspnetcore.spaservices.extensions\2.2.0\.nupkg.metadata +microsoft.aspnetcore.spaservices.extensions\2.2.0\.signature.p7s +microsoft.aspnetcore.spaservices.extensions\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.SpaServices.Extensions.dll +microsoft.aspnetcore.spaservices.extensions\2.2.0\microsoft.aspnetcore.spaservices.extensions.2.2.0.nupkg +microsoft.aspnetcore.spaservices.extensions\2.2.0\microsoft.aspnetcore.spaservices.extensions.2.2.0.nupkg.sha512 +microsoft.aspnetcore.spaservices.extensions\2.2.0\microsoft.aspnetcore.spaservices.extensions.nuspec +microsoft.aspnetcore.spaservices\2.2.0\.nupkg.metadata +microsoft.aspnetcore.spaservices\2.2.0\.signature.p7s +microsoft.aspnetcore.spaservices\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.SpaServices.dll +microsoft.aspnetcore.spaservices\2.2.0\microsoft.aspnetcore.spaservices.2.2.0.nupkg +microsoft.aspnetcore.spaservices\2.2.0\microsoft.aspnetcore.spaservices.2.2.0.nupkg.sha512 +microsoft.aspnetcore.spaservices\2.2.0\microsoft.aspnetcore.spaservices.nuspec +microsoft.aspnetcore.staticfiles\2.2.0\.nupkg.metadata +microsoft.aspnetcore.staticfiles\2.2.0\.signature.p7s +microsoft.aspnetcore.staticfiles\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.StaticFiles.dll +microsoft.aspnetcore.staticfiles\2.2.0\microsoft.aspnetcore.staticfiles.2.2.0.nupkg +microsoft.aspnetcore.staticfiles\2.2.0\microsoft.aspnetcore.staticfiles.2.2.0.nupkg.sha512 +microsoft.aspnetcore.staticfiles\2.2.0\microsoft.aspnetcore.staticfiles.nuspec +microsoft.aspnetcore.websockets\2.2.0\.nupkg.metadata +microsoft.aspnetcore.websockets\2.2.0\.signature.p7s +microsoft.aspnetcore.websockets\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.WebSockets.dll +microsoft.aspnetcore.websockets\2.2.0\microsoft.aspnetcore.websockets.2.2.0.nupkg +microsoft.aspnetcore.websockets\2.2.0\microsoft.aspnetcore.websockets.2.2.0.nupkg.sha512 +microsoft.aspnetcore.websockets\2.2.0\microsoft.aspnetcore.websockets.nuspec +microsoft.aspnetcore.webutilities\2.2.0\.nupkg.metadata +microsoft.aspnetcore.webutilities\2.2.0\.signature.p7s +microsoft.aspnetcore.webutilities\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.WebUtilities.dll +microsoft.aspnetcore.webutilities\2.2.0\microsoft.aspnetcore.webutilities.2.2.0.nupkg +microsoft.aspnetcore.webutilities\2.2.0\microsoft.aspnetcore.webutilities.2.2.0.nupkg.sha512 +microsoft.aspnetcore.webutilities\2.2.0\microsoft.aspnetcore.webutilities.nuspec +microsoft.aspnetcore\2.2.0\.nupkg.metadata +microsoft.aspnetcore\2.2.0\.signature.p7s +microsoft.aspnetcore\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.dll +microsoft.aspnetcore\2.2.0\microsoft.aspnetcore.2.2.0.nupkg +microsoft.aspnetcore\2.2.0\microsoft.aspnetcore.2.2.0.nupkg.sha512 +microsoft.aspnetcore\2.2.0\microsoft.aspnetcore.nuspec +microsoft.azure.keyvault.webkey\2.0.7\.nupkg.metadata +microsoft.azure.keyvault.webkey\2.0.7\.signature.p7s +microsoft.azure.keyvault\2.3.2\.nupkg.metadata +microsoft.azure.keyvault\2.3.2\.signature.p7s +microsoft.azure.services.appauthentication\1.0.1\.nupkg.metadata +microsoft.azure.services.appauthentication\1.0.1\.signature.p7s +microsoft.codeanalysis.analyzers\1.1.0\.nupkg.metadata +microsoft.codeanalysis.common\2.8.0\.nupkg.metadata +microsoft.codeanalysis.csharp\2.8.0\.nupkg.metadata +microsoft.codeanalysis.razor\2.2.0\.nupkg.metadata +microsoft.codeanalysis.razor\2.2.0\.signature.p7s +microsoft.codeanalysis.razor\2.2.0\lib\net46\Microsoft.CodeAnalysis.Razor.dll +microsoft.codeanalysis.razor\2.2.0\lib\netstandard2.0\Microsoft.CodeAnalysis.Razor.dll +microsoft.codeanalysis.razor\2.2.0\microsoft.codeanalysis.razor.2.2.0.nupkg +microsoft.codeanalysis.razor\2.2.0\microsoft.codeanalysis.razor.2.2.0.nupkg.sha512 +microsoft.codeanalysis.razor\2.2.0\microsoft.codeanalysis.razor.nuspec +microsoft.csharp\4.0.1\.nupkg.metadata +microsoft.csharp\4.3.0\.nupkg.metadata +microsoft.csharp\4.5.0\.nupkg.metadata +microsoft.data.edm\5.8.2\.nupkg.metadata +microsoft.data.odata\5.8.2\.nupkg.metadata +microsoft.data.sqlite.core\2.2.0\.nupkg.metadata +microsoft.data.sqlite.core\2.2.0\.signature.p7s +microsoft.data.sqlite.core\2.2.0\lib\netstandard2.0\Microsoft.Data.Sqlite.dll +microsoft.data.sqlite.core\2.2.0\microsoft.data.sqlite.core.2.2.0.nupkg +microsoft.data.sqlite.core\2.2.0\microsoft.data.sqlite.core.2.2.0.nupkg.sha512 +microsoft.data.sqlite.core\2.2.0\microsoft.data.sqlite.core.nuspec +microsoft.data.sqlite\2.2.0\.nupkg.metadata +microsoft.data.sqlite\2.2.0\.signature.p7s +microsoft.data.sqlite\2.2.0\lib\netstandard2.0\_._ +microsoft.data.sqlite\2.2.0\microsoft.data.sqlite.2.2.0.nupkg +microsoft.data.sqlite\2.2.0\microsoft.data.sqlite.2.2.0.nupkg.sha512 +microsoft.data.sqlite\2.2.0\microsoft.data.sqlite.nuspec +microsoft.dotnet.platformabstractions\2.1.0\.nupkg.metadata +microsoft.entityframeworkcore.abstractions\2.2.0\.nupkg.metadata +microsoft.entityframeworkcore.abstractions\2.2.0\.signature.p7s +microsoft.entityframeworkcore.abstractions\2.2.0\lib\netstandard2.0\Microsoft.EntityFrameworkCore.Abstractions.dll +microsoft.entityframeworkcore.abstractions\2.2.0\microsoft.entityframeworkcore.abstractions.2.2.0.nupkg +microsoft.entityframeworkcore.abstractions\2.2.0\microsoft.entityframeworkcore.abstractions.2.2.0.nupkg.sha512 +microsoft.entityframeworkcore.abstractions\2.2.0\microsoft.entityframeworkcore.abstractions.nuspec +microsoft.entityframeworkcore.analyzers\2.2.0\.nupkg.metadata +microsoft.entityframeworkcore.analyzers\2.2.0\.signature.p7s +microsoft.entityframeworkcore.analyzers\2.2.0\analyzers\dotnet\cs\Microsoft.EntityFrameworkCore.Analyzers.dll +microsoft.entityframeworkcore.analyzers\2.2.0\microsoft.entityframeworkcore.analyzers.2.2.0.nupkg +microsoft.entityframeworkcore.analyzers\2.2.0\microsoft.entityframeworkcore.analyzers.2.2.0.nupkg.sha512 +microsoft.entityframeworkcore.analyzers\2.2.0\microsoft.entityframeworkcore.analyzers.nuspec +microsoft.entityframeworkcore.design\2.2.0\.nupkg.metadata +microsoft.entityframeworkcore.design\2.2.0\.signature.p7s +microsoft.entityframeworkcore.design\2.2.0\build\net461\Microsoft.EntityFrameworkCore.Design.props +microsoft.entityframeworkcore.design\2.2.0\build\netcoreapp2.0\Microsoft.EntityFrameworkCore.Design.props +microsoft.entityframeworkcore.design\2.2.0\lib\net461\Microsoft.EntityFrameworkCore.Design.dll +microsoft.entityframeworkcore.design\2.2.0\lib\netstandard2.0\Microsoft.EntityFrameworkCore.Design.dll +microsoft.entityframeworkcore.design\2.2.0\microsoft.entityframeworkcore.design.2.2.0.nupkg +microsoft.entityframeworkcore.design\2.2.0\microsoft.entityframeworkcore.design.2.2.0.nupkg.sha512 +microsoft.entityframeworkcore.design\2.2.0\microsoft.entityframeworkcore.design.nuspec +microsoft.entityframeworkcore.inmemory\2.2.0\.nupkg.metadata +microsoft.entityframeworkcore.inmemory\2.2.0\.signature.p7s +microsoft.entityframeworkcore.inmemory\2.2.0\lib\netstandard2.0\Microsoft.EntityFrameworkCore.InMemory.dll +microsoft.entityframeworkcore.inmemory\2.2.0\microsoft.entityframeworkcore.inmemory.2.2.0.nupkg +microsoft.entityframeworkcore.inmemory\2.2.0\microsoft.entityframeworkcore.inmemory.2.2.0.nupkg.sha512 +microsoft.entityframeworkcore.inmemory\2.2.0\microsoft.entityframeworkcore.inmemory.nuspec +microsoft.entityframeworkcore.relational\2.2.0\.nupkg.metadata +microsoft.entityframeworkcore.relational\2.2.0\.signature.p7s +microsoft.entityframeworkcore.relational\2.2.0\lib\netstandard2.0\Microsoft.EntityFrameworkCore.Relational.dll +microsoft.entityframeworkcore.relational\2.2.0\microsoft.entityframeworkcore.relational.2.2.0.nupkg +microsoft.entityframeworkcore.relational\2.2.0\microsoft.entityframeworkcore.relational.2.2.0.nupkg.sha512 +microsoft.entityframeworkcore.relational\2.2.0\microsoft.entityframeworkcore.relational.nuspec +microsoft.entityframeworkcore.sqlite.core\2.2.0\.nupkg.metadata +microsoft.entityframeworkcore.sqlite.core\2.2.0\.signature.p7s +microsoft.entityframeworkcore.sqlite.core\2.2.0\lib\netstandard2.0\Microsoft.EntityFrameworkCore.Sqlite.dll +microsoft.entityframeworkcore.sqlite.core\2.2.0\microsoft.entityframeworkcore.sqlite.core.2.2.0.nupkg +microsoft.entityframeworkcore.sqlite.core\2.2.0\microsoft.entityframeworkcore.sqlite.core.2.2.0.nupkg.sha512 +microsoft.entityframeworkcore.sqlite.core\2.2.0\microsoft.entityframeworkcore.sqlite.core.nuspec +microsoft.entityframeworkcore.sqlite\2.2.0\.nupkg.metadata +microsoft.entityframeworkcore.sqlite\2.2.0\.signature.p7s +microsoft.entityframeworkcore.sqlite\2.2.0\lib\netstandard2.0\_._ +microsoft.entityframeworkcore.sqlite\2.2.0\microsoft.entityframeworkcore.sqlite.2.2.0.nupkg +microsoft.entityframeworkcore.sqlite\2.2.0\microsoft.entityframeworkcore.sqlite.2.2.0.nupkg.sha512 +microsoft.entityframeworkcore.sqlite\2.2.0\microsoft.entityframeworkcore.sqlite.nuspec +microsoft.entityframeworkcore.sqlserver\2.2.0\.nupkg.metadata +microsoft.entityframeworkcore.sqlserver\2.2.0\.signature.p7s +microsoft.entityframeworkcore.sqlserver\2.2.0\lib\netstandard2.0\Microsoft.EntityFrameworkCore.SqlServer.dll +microsoft.entityframeworkcore.sqlserver\2.2.0\microsoft.entityframeworkcore.sqlserver.2.2.0.nupkg +microsoft.entityframeworkcore.sqlserver\2.2.0\microsoft.entityframeworkcore.sqlserver.2.2.0.nupkg.sha512 +microsoft.entityframeworkcore.sqlserver\2.2.0\microsoft.entityframeworkcore.sqlserver.nuspec +microsoft.entityframeworkcore.tools\2.2.0\.nupkg.metadata +microsoft.entityframeworkcore.tools\2.2.0\.signature.p7s +microsoft.entityframeworkcore.tools\2.2.0\lib\netstandard2.0\_._ +microsoft.entityframeworkcore.tools\2.2.0\microsoft.entityframeworkcore.tools.2.2.0.nupkg +microsoft.entityframeworkcore.tools\2.2.0\microsoft.entityframeworkcore.tools.2.2.0.nupkg.sha512 +microsoft.entityframeworkcore.tools\2.2.0\microsoft.entityframeworkcore.tools.nuspec +microsoft.entityframeworkcore.tools\2.2.0\tools\about_EntityFrameworkCore.help.txt +microsoft.entityframeworkcore.tools\2.2.0\tools\EntityFrameworkCore.PowerShell2.psd1 +microsoft.entityframeworkcore.tools\2.2.0\tools\EntityFrameworkCore.PowerShell2.psm1 +microsoft.entityframeworkcore.tools\2.2.0\tools\EntityFrameworkCore.psd1 +microsoft.entityframeworkcore.tools\2.2.0\tools\EntityFrameworkCore.psm1 +microsoft.entityframeworkcore.tools\2.2.0\tools\init.ps1 +microsoft.entityframeworkcore.tools\2.2.0\tools\install.ps1 +microsoft.entityframeworkcore.tools\2.2.0\tools\net461\any\ef.exe +microsoft.entityframeworkcore.tools\2.2.0\tools\net461\win-x86\ef.exe +microsoft.entityframeworkcore.tools\2.2.0\tools\netcoreapp2.0\any\ef.dll +microsoft.entityframeworkcore.tools\2.2.0\tools\netcoreapp2.0\any\ef.runtimeconfig.json +microsoft.entityframeworkcore\2.2.0\.nupkg.metadata +microsoft.entityframeworkcore\2.2.0\.signature.p7s +microsoft.entityframeworkcore\2.2.0\lib\netstandard2.0\Microsoft.EntityFrameworkCore.dll +microsoft.entityframeworkcore\2.2.0\microsoft.entityframeworkcore.2.2.0.nupkg +microsoft.entityframeworkcore\2.2.0\microsoft.entityframeworkcore.2.2.0.nupkg.sha512 +microsoft.entityframeworkcore\2.2.0\microsoft.entityframeworkcore.nuspec +microsoft.extensions.caching.abstractions\2.2.0\.nupkg.metadata +microsoft.extensions.caching.abstractions\2.2.0\.signature.p7s +microsoft.extensions.caching.abstractions\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Caching.Abstractions.dll +microsoft.extensions.caching.abstractions\2.2.0\microsoft.extensions.caching.abstractions.2.2.0.nupkg +microsoft.extensions.caching.abstractions\2.2.0\microsoft.extensions.caching.abstractions.2.2.0.nupkg.sha512 +microsoft.extensions.caching.abstractions\2.2.0\microsoft.extensions.caching.abstractions.nuspec +microsoft.extensions.caching.memory\2.2.0\.nupkg.metadata +microsoft.extensions.caching.memory\2.2.0\.signature.p7s +microsoft.extensions.caching.memory\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Caching.Memory.dll +microsoft.extensions.caching.memory\2.2.0\microsoft.extensions.caching.memory.2.2.0.nupkg +microsoft.extensions.caching.memory\2.2.0\microsoft.extensions.caching.memory.2.2.0.nupkg.sha512 +microsoft.extensions.caching.memory\2.2.0\microsoft.extensions.caching.memory.nuspec +microsoft.extensions.caching.redis\2.2.0\.nupkg.metadata +microsoft.extensions.caching.redis\2.2.0\.signature.p7s +microsoft.extensions.caching.redis\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Caching.Redis.dll +microsoft.extensions.caching.redis\2.2.0\microsoft.extensions.caching.redis.2.2.0.nupkg +microsoft.extensions.caching.redis\2.2.0\microsoft.extensions.caching.redis.2.2.0.nupkg.sha512 +microsoft.extensions.caching.redis\2.2.0\microsoft.extensions.caching.redis.nuspec +microsoft.extensions.caching.sqlserver\2.2.0\.nupkg.metadata +microsoft.extensions.caching.sqlserver\2.2.0\.signature.p7s +microsoft.extensions.caching.sqlserver\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Caching.SqlServer.dll +microsoft.extensions.caching.sqlserver\2.2.0\microsoft.extensions.caching.sqlserver.2.2.0.nupkg +microsoft.extensions.caching.sqlserver\2.2.0\microsoft.extensions.caching.sqlserver.2.2.0.nupkg.sha512 +microsoft.extensions.caching.sqlserver\2.2.0\microsoft.extensions.caching.sqlserver.nuspec +microsoft.extensions.configuration.abstractions\2.2.0\.nupkg.metadata +microsoft.extensions.configuration.abstractions\2.2.0\.signature.p7s +microsoft.extensions.configuration.abstractions\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Abstractions.dll +microsoft.extensions.configuration.abstractions\2.2.0\microsoft.extensions.configuration.abstractions.2.2.0.nupkg +microsoft.extensions.configuration.abstractions\2.2.0\microsoft.extensions.configuration.abstractions.2.2.0.nupkg.sha512 +microsoft.extensions.configuration.abstractions\2.2.0\microsoft.extensions.configuration.abstractions.nuspec +microsoft.extensions.configuration.azurekeyvault\2.2.0\.nupkg.metadata +microsoft.extensions.configuration.azurekeyvault\2.2.0\.signature.p7s +microsoft.extensions.configuration.azurekeyvault\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.AzureKeyVault.dll +microsoft.extensions.configuration.azurekeyvault\2.2.0\microsoft.extensions.configuration.azurekeyvault.2.2.0.nupkg +microsoft.extensions.configuration.azurekeyvault\2.2.0\microsoft.extensions.configuration.azurekeyvault.2.2.0.nupkg.sha512 +microsoft.extensions.configuration.azurekeyvault\2.2.0\microsoft.extensions.configuration.azurekeyvault.nuspec +microsoft.extensions.configuration.binder\2.2.0\.nupkg.metadata +microsoft.extensions.configuration.binder\2.2.0\.signature.p7s +microsoft.extensions.configuration.binder\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Binder.dll +microsoft.extensions.configuration.binder\2.2.0\microsoft.extensions.configuration.binder.2.2.0.nupkg +microsoft.extensions.configuration.binder\2.2.0\microsoft.extensions.configuration.binder.2.2.0.nupkg.sha512 +microsoft.extensions.configuration.binder\2.2.0\microsoft.extensions.configuration.binder.nuspec +microsoft.extensions.configuration.commandline\2.2.0\.nupkg.metadata +microsoft.extensions.configuration.commandline\2.2.0\.signature.p7s +microsoft.extensions.configuration.commandline\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.CommandLine.dll +microsoft.extensions.configuration.commandline\2.2.0\microsoft.extensions.configuration.commandline.2.2.0.nupkg +microsoft.extensions.configuration.commandline\2.2.0\microsoft.extensions.configuration.commandline.2.2.0.nupkg.sha512 +microsoft.extensions.configuration.commandline\2.2.0\microsoft.extensions.configuration.commandline.nuspec +microsoft.extensions.configuration.environmentvariables\2.2.0\.nupkg.metadata +microsoft.extensions.configuration.environmentvariables\2.2.0\.signature.p7s +microsoft.extensions.configuration.environmentvariables\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.EnvironmentVariables.dll +microsoft.extensions.configuration.environmentvariables\2.2.0\microsoft.extensions.configuration.environmentvariables.2.2.0.nupkg +microsoft.extensions.configuration.environmentvariables\2.2.0\microsoft.extensions.configuration.environmentvariables.2.2.0.nupkg.sha512 +microsoft.extensions.configuration.environmentvariables\2.2.0\microsoft.extensions.configuration.environmentvariables.nuspec +microsoft.extensions.configuration.fileextensions\2.2.0\.nupkg.metadata +microsoft.extensions.configuration.fileextensions\2.2.0\.signature.p7s +microsoft.extensions.configuration.fileextensions\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.FileExtensions.dll +microsoft.extensions.configuration.fileextensions\2.2.0\microsoft.extensions.configuration.fileextensions.2.2.0.nupkg +microsoft.extensions.configuration.fileextensions\2.2.0\microsoft.extensions.configuration.fileextensions.2.2.0.nupkg.sha512 +microsoft.extensions.configuration.fileextensions\2.2.0\microsoft.extensions.configuration.fileextensions.nuspec +microsoft.extensions.configuration.ini\2.2.0\.nupkg.metadata +microsoft.extensions.configuration.ini\2.2.0\.signature.p7s +microsoft.extensions.configuration.ini\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Ini.dll +microsoft.extensions.configuration.ini\2.2.0\microsoft.extensions.configuration.ini.2.2.0.nupkg +microsoft.extensions.configuration.ini\2.2.0\microsoft.extensions.configuration.ini.2.2.0.nupkg.sha512 +microsoft.extensions.configuration.ini\2.2.0\microsoft.extensions.configuration.ini.nuspec +microsoft.extensions.configuration.json\2.2.0\.nupkg.metadata +microsoft.extensions.configuration.json\2.2.0\.signature.p7s +microsoft.extensions.configuration.json\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Json.dll +microsoft.extensions.configuration.json\2.2.0\microsoft.extensions.configuration.json.2.2.0.nupkg +microsoft.extensions.configuration.json\2.2.0\microsoft.extensions.configuration.json.2.2.0.nupkg.sha512 +microsoft.extensions.configuration.json\2.2.0\microsoft.extensions.configuration.json.nuspec +microsoft.extensions.configuration.keyperfile\2.2.0\.nupkg.metadata +microsoft.extensions.configuration.keyperfile\2.2.0\.signature.p7s +microsoft.extensions.configuration.keyperfile\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.KeyPerFile.dll +microsoft.extensions.configuration.keyperfile\2.2.0\microsoft.extensions.configuration.keyperfile.2.2.0.nupkg +microsoft.extensions.configuration.keyperfile\2.2.0\microsoft.extensions.configuration.keyperfile.2.2.0.nupkg.sha512 +microsoft.extensions.configuration.keyperfile\2.2.0\microsoft.extensions.configuration.keyperfile.nuspec +microsoft.extensions.configuration.usersecrets\2.2.0\.nupkg.metadata +microsoft.extensions.configuration.usersecrets\2.2.0\.signature.p7s +microsoft.extensions.configuration.usersecrets\2.2.0\build\netstandard2.0\Microsoft.Extensions.Configuration.UserSecrets.props +microsoft.extensions.configuration.usersecrets\2.2.0\build\netstandard2.0\Microsoft.Extensions.Configuration.UserSecrets.targets +microsoft.extensions.configuration.usersecrets\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.UserSecrets.dll +microsoft.extensions.configuration.usersecrets\2.2.0\microsoft.extensions.configuration.usersecrets.2.2.0.nupkg +microsoft.extensions.configuration.usersecrets\2.2.0\microsoft.extensions.configuration.usersecrets.2.2.0.nupkg.sha512 +microsoft.extensions.configuration.usersecrets\2.2.0\microsoft.extensions.configuration.usersecrets.nuspec +microsoft.extensions.configuration.xml\2.2.0\.nupkg.metadata +microsoft.extensions.configuration.xml\2.2.0\.signature.p7s +microsoft.extensions.configuration.xml\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Xml.dll +microsoft.extensions.configuration.xml\2.2.0\microsoft.extensions.configuration.xml.2.2.0.nupkg +microsoft.extensions.configuration.xml\2.2.0\microsoft.extensions.configuration.xml.2.2.0.nupkg.sha512 +microsoft.extensions.configuration.xml\2.2.0\microsoft.extensions.configuration.xml.nuspec +microsoft.extensions.configuration\2.2.0\.nupkg.metadata +microsoft.extensions.configuration\2.2.0\.signature.p7s +microsoft.extensions.configuration\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.dll +microsoft.extensions.configuration\2.2.0\microsoft.extensions.configuration.2.2.0.nupkg +microsoft.extensions.configuration\2.2.0\microsoft.extensions.configuration.2.2.0.nupkg.sha512 +microsoft.extensions.configuration\2.2.0\microsoft.extensions.configuration.nuspec +microsoft.extensions.dependencyinjection.abstractions\2.2.0\.nupkg.metadata +microsoft.extensions.dependencyinjection.abstractions\2.2.0\.signature.p7s +microsoft.extensions.dependencyinjection.abstractions\2.2.0\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll +microsoft.extensions.dependencyinjection.abstractions\2.2.0\microsoft.extensions.dependencyinjection.abstractions.2.2.0.nupkg +microsoft.extensions.dependencyinjection.abstractions\2.2.0\microsoft.extensions.dependencyinjection.abstractions.2.2.0.nupkg.sha512 +microsoft.extensions.dependencyinjection.abstractions\2.2.0\microsoft.extensions.dependencyinjection.abstractions.nuspec +microsoft.extensions.dependencyinjection\2.2.0\.nupkg.metadata +microsoft.extensions.dependencyinjection\2.2.0\.signature.p7s +microsoft.extensions.dependencyinjection\2.2.0\lib\net461\Microsoft.Extensions.DependencyInjection.dll +microsoft.extensions.dependencyinjection\2.2.0\lib\netcoreapp2.0\Microsoft.Extensions.DependencyInjection.dll +microsoft.extensions.dependencyinjection\2.2.0\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.dll +microsoft.extensions.dependencyinjection\2.2.0\microsoft.extensions.dependencyinjection.2.2.0.nupkg +microsoft.extensions.dependencyinjection\2.2.0\microsoft.extensions.dependencyinjection.2.2.0.nupkg.sha512 +microsoft.extensions.dependencyinjection\2.2.0\microsoft.extensions.dependencyinjection.nuspec +microsoft.extensions.dependencymodel\2.1.0\.nupkg.metadata +microsoft.extensions.diagnosticadapter\2.2.0\.nupkg.metadata +microsoft.extensions.diagnosticadapter\2.2.0\.signature.p7s +microsoft.extensions.diagnosticadapter\2.2.0\lib\net461\Microsoft.Extensions.DiagnosticAdapter.dll +microsoft.extensions.diagnosticadapter\2.2.0\lib\netcoreapp2.0\Microsoft.Extensions.DiagnosticAdapter.dll +microsoft.extensions.diagnosticadapter\2.2.0\lib\netstandard2.0\Microsoft.Extensions.DiagnosticAdapter.dll +microsoft.extensions.diagnosticadapter\2.2.0\microsoft.extensions.diagnosticadapter.2.2.0.nupkg +microsoft.extensions.diagnosticadapter\2.2.0\microsoft.extensions.diagnosticadapter.2.2.0.nupkg.sha512 +microsoft.extensions.diagnosticadapter\2.2.0\microsoft.extensions.diagnosticadapter.nuspec +microsoft.extensions.diagnostics.healthchecks.abstractions\2.2.0\.nupkg.metadata +microsoft.extensions.diagnostics.healthchecks.abstractions\2.2.0\.signature.p7s +microsoft.extensions.diagnostics.healthchecks.abstractions\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions.dll +microsoft.extensions.diagnostics.healthchecks.abstractions\2.2.0\microsoft.extensions.diagnostics.healthchecks.abstractions.2.2.0.nupkg +microsoft.extensions.diagnostics.healthchecks.abstractions\2.2.0\microsoft.extensions.diagnostics.healthchecks.abstractions.2.2.0.nupkg.sha512 +microsoft.extensions.diagnostics.healthchecks.abstractions\2.2.0\microsoft.extensions.diagnostics.healthchecks.abstractions.nuspec +microsoft.extensions.diagnostics.healthchecks\2.2.0\.nupkg.metadata +microsoft.extensions.diagnostics.healthchecks\2.2.0\.signature.p7s +microsoft.extensions.diagnostics.healthchecks\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Diagnostics.HealthChecks.dll +microsoft.extensions.diagnostics.healthchecks\2.2.0\microsoft.extensions.diagnostics.healthchecks.2.2.0.nupkg +microsoft.extensions.diagnostics.healthchecks\2.2.0\microsoft.extensions.diagnostics.healthchecks.2.2.0.nupkg.sha512 +microsoft.extensions.diagnostics.healthchecks\2.2.0\microsoft.extensions.diagnostics.healthchecks.nuspec +microsoft.extensions.fileproviders.abstractions\2.2.0\.nupkg.metadata +microsoft.extensions.fileproviders.abstractions\2.2.0\.signature.p7s +microsoft.extensions.fileproviders.abstractions\2.2.0\lib\netstandard2.0\Microsoft.Extensions.FileProviders.Abstractions.dll +microsoft.extensions.fileproviders.abstractions\2.2.0\microsoft.extensions.fileproviders.abstractions.2.2.0.nupkg +microsoft.extensions.fileproviders.abstractions\2.2.0\microsoft.extensions.fileproviders.abstractions.2.2.0.nupkg.sha512 +microsoft.extensions.fileproviders.abstractions\2.2.0\microsoft.extensions.fileproviders.abstractions.nuspec +microsoft.extensions.fileproviders.composite\2.2.0\.nupkg.metadata +microsoft.extensions.fileproviders.composite\2.2.0\.signature.p7s +microsoft.extensions.fileproviders.composite\2.2.0\lib\netstandard2.0\Microsoft.Extensions.FileProviders.Composite.dll +microsoft.extensions.fileproviders.composite\2.2.0\microsoft.extensions.fileproviders.composite.2.2.0.nupkg +microsoft.extensions.fileproviders.composite\2.2.0\microsoft.extensions.fileproviders.composite.2.2.0.nupkg.sha512 +microsoft.extensions.fileproviders.composite\2.2.0\microsoft.extensions.fileproviders.composite.nuspec +microsoft.extensions.fileproviders.embedded\2.2.0\.nupkg.metadata +microsoft.extensions.fileproviders.embedded\2.2.0\.signature.p7s +microsoft.extensions.fileproviders.embedded\2.2.0\build\netstandard2.0\Microsoft.Extensions.FileProviders.Embedded.props +microsoft.extensions.fileproviders.embedded\2.2.0\build\netstandard2.0\Microsoft.Extensions.FileProviders.Embedded.targets +microsoft.extensions.fileproviders.embedded\2.2.0\buildMultiTargeting\Microsoft.Extensions.FileProviders.Embedded.props +microsoft.extensions.fileproviders.embedded\2.2.0\buildMultiTargeting\Microsoft.Extensions.FileProviders.Embedded.targets +microsoft.extensions.fileproviders.embedded\2.2.0\lib\netstandard2.0\Microsoft.Extensions.FileProviders.Embedded.dll +microsoft.extensions.fileproviders.embedded\2.2.0\microsoft.extensions.fileproviders.embedded.2.2.0.nupkg +microsoft.extensions.fileproviders.embedded\2.2.0\microsoft.extensions.fileproviders.embedded.2.2.0.nupkg.sha512 +microsoft.extensions.fileproviders.embedded\2.2.0\microsoft.extensions.fileproviders.embedded.nuspec +microsoft.extensions.fileproviders.embedded\2.2.0\tasks\net461\Microsoft.Extensions.FileProviders.Embedded.Manifest.Task.dll +microsoft.extensions.fileproviders.embedded\2.2.0\tasks\netstandard1.5\Microsoft.Extensions.FileProviders.Embedded.Manifest.Task.dll +microsoft.extensions.fileproviders.physical\2.2.0\.nupkg.metadata +microsoft.extensions.fileproviders.physical\2.2.0\.signature.p7s +microsoft.extensions.fileproviders.physical\2.2.0\lib\netstandard2.0\Microsoft.Extensions.FileProviders.Physical.dll +microsoft.extensions.fileproviders.physical\2.2.0\microsoft.extensions.fileproviders.physical.2.2.0.nupkg +microsoft.extensions.fileproviders.physical\2.2.0\microsoft.extensions.fileproviders.physical.2.2.0.nupkg.sha512 +microsoft.extensions.fileproviders.physical\2.2.0\microsoft.extensions.fileproviders.physical.nuspec +microsoft.extensions.filesystemglobbing\2.2.0\.nupkg.metadata +microsoft.extensions.filesystemglobbing\2.2.0\.signature.p7s +microsoft.extensions.filesystemglobbing\2.2.0\lib\netstandard2.0\Microsoft.Extensions.FileSystemGlobbing.dll +microsoft.extensions.filesystemglobbing\2.2.0\microsoft.extensions.filesystemglobbing.2.2.0.nupkg +microsoft.extensions.filesystemglobbing\2.2.0\microsoft.extensions.filesystemglobbing.2.2.0.nupkg.sha512 +microsoft.extensions.filesystemglobbing\2.2.0\microsoft.extensions.filesystemglobbing.nuspec +microsoft.extensions.hosting.abstractions\2.2.0\.nupkg.metadata +microsoft.extensions.hosting.abstractions\2.2.0\.signature.p7s +microsoft.extensions.hosting.abstractions\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Hosting.Abstractions.dll +microsoft.extensions.hosting.abstractions\2.2.0\microsoft.extensions.hosting.abstractions.2.2.0.nupkg +microsoft.extensions.hosting.abstractions\2.2.0\microsoft.extensions.hosting.abstractions.2.2.0.nupkg.sha512 +microsoft.extensions.hosting.abstractions\2.2.0\microsoft.extensions.hosting.abstractions.nuspec +microsoft.extensions.hosting\2.2.0\.nupkg.metadata +microsoft.extensions.hosting\2.2.0\.signature.p7s +microsoft.extensions.hosting\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Hosting.dll +microsoft.extensions.hosting\2.2.0\microsoft.extensions.hosting.2.2.0.nupkg +microsoft.extensions.hosting\2.2.0\microsoft.extensions.hosting.2.2.0.nupkg.sha512 +microsoft.extensions.hosting\2.2.0\microsoft.extensions.hosting.nuspec +microsoft.extensions.http\2.2.0\.nupkg.metadata +microsoft.extensions.http\2.2.0\.signature.p7s +microsoft.extensions.http\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Http.dll +microsoft.extensions.http\2.2.0\microsoft.extensions.http.2.2.0.nupkg +microsoft.extensions.http\2.2.0\microsoft.extensions.http.2.2.0.nupkg.sha512 +microsoft.extensions.http\2.2.0\microsoft.extensions.http.nuspec +microsoft.extensions.identity.core\2.2.0\.nupkg.metadata +microsoft.extensions.identity.core\2.2.0\.signature.p7s +microsoft.extensions.identity.core\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Identity.Core.dll +microsoft.extensions.identity.core\2.2.0\microsoft.extensions.identity.core.2.2.0.nupkg +microsoft.extensions.identity.core\2.2.0\microsoft.extensions.identity.core.2.2.0.nupkg.sha512 +microsoft.extensions.identity.core\2.2.0\microsoft.extensions.identity.core.nuspec +microsoft.extensions.identity.stores\2.2.0\.nupkg.metadata +microsoft.extensions.identity.stores\2.2.0\.signature.p7s +microsoft.extensions.identity.stores\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Identity.Stores.dll +microsoft.extensions.identity.stores\2.2.0\microsoft.extensions.identity.stores.2.2.0.nupkg +microsoft.extensions.identity.stores\2.2.0\microsoft.extensions.identity.stores.2.2.0.nupkg.sha512 +microsoft.extensions.identity.stores\2.2.0\microsoft.extensions.identity.stores.nuspec +microsoft.extensions.localization.abstractions\2.2.0\.nupkg.metadata +microsoft.extensions.localization.abstractions\2.2.0\.signature.p7s +microsoft.extensions.localization.abstractions\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Localization.Abstractions.dll +microsoft.extensions.localization.abstractions\2.2.0\microsoft.extensions.localization.abstractions.2.2.0.nupkg +microsoft.extensions.localization.abstractions\2.2.0\microsoft.extensions.localization.abstractions.2.2.0.nupkg.sha512 +microsoft.extensions.localization.abstractions\2.2.0\microsoft.extensions.localization.abstractions.nuspec +microsoft.extensions.localization\2.2.0\.nupkg.metadata +microsoft.extensions.localization\2.2.0\.signature.p7s +microsoft.extensions.localization\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Localization.dll +microsoft.extensions.localization\2.2.0\microsoft.extensions.localization.2.2.0.nupkg +microsoft.extensions.localization\2.2.0\microsoft.extensions.localization.2.2.0.nupkg.sha512 +microsoft.extensions.localization\2.2.0\microsoft.extensions.localization.nuspec +microsoft.extensions.logging.abstractions\2.2.0\.nupkg.metadata +microsoft.extensions.logging.abstractions\2.2.0\.signature.p7s +microsoft.extensions.logging.abstractions\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.dll +microsoft.extensions.logging.abstractions\2.2.0\microsoft.extensions.logging.abstractions.2.2.0.nupkg +microsoft.extensions.logging.abstractions\2.2.0\microsoft.extensions.logging.abstractions.2.2.0.nupkg.sha512 +microsoft.extensions.logging.abstractions\2.2.0\microsoft.extensions.logging.abstractions.nuspec +microsoft.extensions.logging.azureappservices\2.2.0\.nupkg.metadata +microsoft.extensions.logging.azureappservices\2.2.0\.signature.p7s +microsoft.extensions.logging.azureappservices\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Logging.AzureAppServices.dll +microsoft.extensions.logging.azureappservices\2.2.0\microsoft.extensions.logging.azureappservices.2.2.0.nupkg +microsoft.extensions.logging.azureappservices\2.2.0\microsoft.extensions.logging.azureappservices.2.2.0.nupkg.sha512 +microsoft.extensions.logging.azureappservices\2.2.0\microsoft.extensions.logging.azureappservices.nuspec +microsoft.extensions.logging.configuration\2.2.0\.nupkg.metadata +microsoft.extensions.logging.configuration\2.2.0\.signature.p7s +microsoft.extensions.logging.configuration\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Logging.Configuration.dll +microsoft.extensions.logging.configuration\2.2.0\microsoft.extensions.logging.configuration.2.2.0.nupkg +microsoft.extensions.logging.configuration\2.2.0\microsoft.extensions.logging.configuration.2.2.0.nupkg.sha512 +microsoft.extensions.logging.configuration\2.2.0\microsoft.extensions.logging.configuration.nuspec +microsoft.extensions.logging.console\2.2.0\.nupkg.metadata +microsoft.extensions.logging.console\2.2.0\.signature.p7s +microsoft.extensions.logging.console\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Logging.Console.dll +microsoft.extensions.logging.console\2.2.0\microsoft.extensions.logging.console.2.2.0.nupkg +microsoft.extensions.logging.console\2.2.0\microsoft.extensions.logging.console.2.2.0.nupkg.sha512 +microsoft.extensions.logging.console\2.2.0\microsoft.extensions.logging.console.nuspec +microsoft.extensions.logging.debug\2.2.0\.nupkg.metadata +microsoft.extensions.logging.debug\2.2.0\.signature.p7s +microsoft.extensions.logging.debug\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Logging.Debug.dll +microsoft.extensions.logging.debug\2.2.0\microsoft.extensions.logging.debug.2.2.0.nupkg +microsoft.extensions.logging.debug\2.2.0\microsoft.extensions.logging.debug.2.2.0.nupkg.sha512 +microsoft.extensions.logging.debug\2.2.0\microsoft.extensions.logging.debug.nuspec +microsoft.extensions.logging.eventsource\2.2.0\.nupkg.metadata +microsoft.extensions.logging.eventsource\2.2.0\.signature.p7s +microsoft.extensions.logging.eventsource\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Logging.EventSource.dll +microsoft.extensions.logging.eventsource\2.2.0\microsoft.extensions.logging.eventsource.2.2.0.nupkg +microsoft.extensions.logging.eventsource\2.2.0\microsoft.extensions.logging.eventsource.2.2.0.nupkg.sha512 +microsoft.extensions.logging.eventsource\2.2.0\microsoft.extensions.logging.eventsource.nuspec +microsoft.extensions.logging.tracesource\2.2.0\.nupkg.metadata +microsoft.extensions.logging.tracesource\2.2.0\.signature.p7s +microsoft.extensions.logging.tracesource\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Logging.TraceSource.dll +microsoft.extensions.logging.tracesource\2.2.0\microsoft.extensions.logging.tracesource.2.2.0.nupkg +microsoft.extensions.logging.tracesource\2.2.0\microsoft.extensions.logging.tracesource.2.2.0.nupkg.sha512 +microsoft.extensions.logging.tracesource\2.2.0\microsoft.extensions.logging.tracesource.nuspec +microsoft.extensions.logging\2.2.0\.nupkg.metadata +microsoft.extensions.logging\2.2.0\.signature.p7s +microsoft.extensions.logging\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Logging.dll +microsoft.extensions.logging\2.2.0\microsoft.extensions.logging.2.2.0.nupkg +microsoft.extensions.logging\2.2.0\microsoft.extensions.logging.2.2.0.nupkg.sha512 +microsoft.extensions.logging\2.2.0\microsoft.extensions.logging.nuspec +microsoft.extensions.objectpool\2.2.0\.nupkg.metadata +microsoft.extensions.objectpool\2.2.0\.signature.p7s +microsoft.extensions.objectpool\2.2.0\lib\netstandard2.0\Microsoft.Extensions.ObjectPool.dll +microsoft.extensions.objectpool\2.2.0\microsoft.extensions.objectpool.2.2.0.nupkg +microsoft.extensions.objectpool\2.2.0\microsoft.extensions.objectpool.2.2.0.nupkg.sha512 +microsoft.extensions.objectpool\2.2.0\microsoft.extensions.objectpool.nuspec +microsoft.extensions.options.configurationextensions\2.2.0\.nupkg.metadata +microsoft.extensions.options.configurationextensions\2.2.0\.signature.p7s +microsoft.extensions.options.configurationextensions\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Options.ConfigurationExtensions.dll +microsoft.extensions.options.configurationextensions\2.2.0\microsoft.extensions.options.configurationextensions.2.2.0.nupkg +microsoft.extensions.options.configurationextensions\2.2.0\microsoft.extensions.options.configurationextensions.2.2.0.nupkg.sha512 +microsoft.extensions.options.configurationextensions\2.2.0\microsoft.extensions.options.configurationextensions.nuspec +microsoft.extensions.options.dataannotations\2.2.0\.nupkg.metadata +microsoft.extensions.options.dataannotations\2.2.0\.signature.p7s +microsoft.extensions.options.dataannotations\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Options.DataAnnotations.dll +microsoft.extensions.options.dataannotations\2.2.0\microsoft.extensions.options.dataannotations.2.2.0.nupkg +microsoft.extensions.options.dataannotations\2.2.0\microsoft.extensions.options.dataannotations.2.2.0.nupkg.sha512 +microsoft.extensions.options.dataannotations\2.2.0\microsoft.extensions.options.dataannotations.nuspec +microsoft.extensions.options\2.2.0\.nupkg.metadata +microsoft.extensions.options\2.2.0\.signature.p7s +microsoft.extensions.options\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Options.dll +microsoft.extensions.options\2.2.0\microsoft.extensions.options.2.2.0.nupkg +microsoft.extensions.options\2.2.0\microsoft.extensions.options.2.2.0.nupkg.sha512 +microsoft.extensions.options\2.2.0\microsoft.extensions.options.nuspec +microsoft.extensions.platformabstractions\1.1.0\.nupkg.metadata +microsoft.extensions.primitives\2.2.0\.nupkg.metadata +microsoft.extensions.primitives\2.2.0\.signature.p7s +microsoft.extensions.primitives\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll +microsoft.extensions.primitives\2.2.0\microsoft.extensions.primitives.2.2.0.nupkg +microsoft.extensions.primitives\2.2.0\microsoft.extensions.primitives.2.2.0.nupkg.sha512 +microsoft.extensions.primitives\2.2.0\microsoft.extensions.primitives.nuspec +microsoft.extensions.webencoders\2.2.0\.nupkg.metadata +microsoft.extensions.webencoders\2.2.0\.signature.p7s +microsoft.extensions.webencoders\2.2.0\lib\netstandard2.0\Microsoft.Extensions.WebEncoders.dll +microsoft.extensions.webencoders\2.2.0\microsoft.extensions.webencoders.2.2.0.nupkg +microsoft.extensions.webencoders\2.2.0\microsoft.extensions.webencoders.2.2.0.nupkg.sha512 +microsoft.extensions.webencoders\2.2.0\microsoft.extensions.webencoders.nuspec +microsoft.identitymodel.clients.activedirectory\3.14.2\.nupkg.metadata +microsoft.identitymodel.clients.activedirectory\3.14.2\.signature.p7s +microsoft.identitymodel.clients.activedirectory\3.19.8\.nupkg.metadata +microsoft.identitymodel.clients.activedirectory\3.19.8\.signature.p7s +microsoft.identitymodel.clients.activedirectory\3.19.8\lib\MonoAndroid7\Microsoft.IdentityModel.Clients.ActiveDirectory.dll +microsoft.identitymodel.clients.activedirectory\3.19.8\lib\MonoAndroid7\Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll +microsoft.identitymodel.clients.activedirectory\3.19.8\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll +microsoft.identitymodel.clients.activedirectory\3.19.8\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll +microsoft.identitymodel.clients.activedirectory\3.19.8\lib\netcore45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll +microsoft.identitymodel.clients.activedirectory\3.19.8\lib\netcore45\Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll +microsoft.identitymodel.clients.activedirectory\3.19.8\lib\netstandard1.1\Microsoft.IdentityModel.Clients.ActiveDirectory.dll +microsoft.identitymodel.clients.activedirectory\3.19.8\lib\netstandard1.1\Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll +microsoft.identitymodel.clients.activedirectory\3.19.8\lib\netstandard1.3\Microsoft.IdentityModel.Clients.ActiveDirectory.dll +microsoft.identitymodel.clients.activedirectory\3.19.8\lib\netstandard1.3\Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll +microsoft.identitymodel.clients.activedirectory\3.19.8\lib\portable-net45+win\Microsoft.IdentityModel.Clients.ActiveDirectory.dll +microsoft.identitymodel.clients.activedirectory\3.19.8\lib\portable-net45+win\Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll +microsoft.identitymodel.clients.activedirectory\3.19.8\lib\Xamarin.iOS10\Microsoft.IdentityModel.Clients.ActiveDirectory.dll +microsoft.identitymodel.clients.activedirectory\3.19.8\lib\Xamarin.iOS10\Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll +microsoft.identitymodel.clients.activedirectory\3.19.8\microsoft.identitymodel.clients.activedirectory.3.19.8.nupkg +microsoft.identitymodel.clients.activedirectory\3.19.8\microsoft.identitymodel.clients.activedirectory.3.19.8.nupkg.sha512 +microsoft.identitymodel.clients.activedirectory\3.19.8\microsoft.identitymodel.clients.activedirectory.nuspec +microsoft.identitymodel.jsonwebtokens\5.3.0\.nupkg.metadata +microsoft.identitymodel.jsonwebtokens\5.3.0\.signature.p7s +microsoft.identitymodel.jsonwebtokens\5.3.0\lib\net45\Microsoft.IdentityModel.JsonWebTokens.dll +microsoft.identitymodel.jsonwebtokens\5.3.0\lib\net45\Microsoft.IdentityModel.JsonWebTokens.pdb +microsoft.identitymodel.jsonwebtokens\5.3.0\lib\net451\Microsoft.IdentityModel.JsonWebTokens.dll +microsoft.identitymodel.jsonwebtokens\5.3.0\lib\net451\Microsoft.IdentityModel.JsonWebTokens.pdb +microsoft.identitymodel.jsonwebtokens\5.3.0\lib\net461\Microsoft.IdentityModel.JsonWebTokens.dll +microsoft.identitymodel.jsonwebtokens\5.3.0\lib\net461\Microsoft.IdentityModel.JsonWebTokens.pdb +microsoft.identitymodel.jsonwebtokens\5.3.0\lib\netstandard1.4\Microsoft.IdentityModel.JsonWebTokens.dll +microsoft.identitymodel.jsonwebtokens\5.3.0\lib\netstandard1.4\Microsoft.IdentityModel.JsonWebTokens.pdb +microsoft.identitymodel.jsonwebtokens\5.3.0\lib\netstandard2.0\Microsoft.IdentityModel.JsonWebTokens.dll +microsoft.identitymodel.jsonwebtokens\5.3.0\lib\netstandard2.0\Microsoft.IdentityModel.JsonWebTokens.pdb +microsoft.identitymodel.jsonwebtokens\5.3.0\microsoft.identitymodel.jsonwebtokens.5.3.0.nupkg +microsoft.identitymodel.jsonwebtokens\5.3.0\microsoft.identitymodel.jsonwebtokens.5.3.0.nupkg.sha512 +microsoft.identitymodel.jsonwebtokens\5.3.0\microsoft.identitymodel.jsonwebtokens.nuspec +microsoft.identitymodel.logging\5.3.0\.nupkg.metadata +microsoft.identitymodel.logging\5.3.0\.signature.p7s +microsoft.identitymodel.logging\5.3.0\lib\net45\Microsoft.IdentityModel.Logging.dll +microsoft.identitymodel.logging\5.3.0\lib\net45\Microsoft.IdentityModel.Logging.pdb +microsoft.identitymodel.logging\5.3.0\lib\net451\Microsoft.IdentityModel.Logging.dll +microsoft.identitymodel.logging\5.3.0\lib\net451\Microsoft.IdentityModel.Logging.pdb +microsoft.identitymodel.logging\5.3.0\lib\net461\Microsoft.IdentityModel.Logging.dll +microsoft.identitymodel.logging\5.3.0\lib\net461\Microsoft.IdentityModel.Logging.pdb +microsoft.identitymodel.logging\5.3.0\lib\netstandard1.4\Microsoft.IdentityModel.Logging.dll +microsoft.identitymodel.logging\5.3.0\lib\netstandard1.4\Microsoft.IdentityModel.Logging.pdb +microsoft.identitymodel.logging\5.3.0\lib\netstandard2.0\Microsoft.IdentityModel.Logging.dll +microsoft.identitymodel.logging\5.3.0\lib\netstandard2.0\Microsoft.IdentityModel.Logging.pdb +microsoft.identitymodel.logging\5.3.0\microsoft.identitymodel.logging.5.3.0.nupkg +microsoft.identitymodel.logging\5.3.0\microsoft.identitymodel.logging.5.3.0.nupkg.sha512 +microsoft.identitymodel.logging\5.3.0\microsoft.identitymodel.logging.nuspec +microsoft.identitymodel.protocols.openidconnect\5.3.0\.nupkg.metadata +microsoft.identitymodel.protocols.openidconnect\5.3.0\.signature.p7s +microsoft.identitymodel.protocols.openidconnect\5.3.0\lib\net45\Microsoft.IdentityModel.Protocols.OpenIdConnect.dll +microsoft.identitymodel.protocols.openidconnect\5.3.0\lib\net45\Microsoft.IdentityModel.Protocols.OpenIdConnect.pdb +microsoft.identitymodel.protocols.openidconnect\5.3.0\lib\net451\Microsoft.IdentityModel.Protocols.OpenIdConnect.dll +microsoft.identitymodel.protocols.openidconnect\5.3.0\lib\net451\Microsoft.IdentityModel.Protocols.OpenIdConnect.pdb +microsoft.identitymodel.protocols.openidconnect\5.3.0\lib\net461\Microsoft.IdentityModel.Protocols.OpenIdConnect.dll +microsoft.identitymodel.protocols.openidconnect\5.3.0\lib\net461\Microsoft.IdentityModel.Protocols.OpenIdConnect.pdb +microsoft.identitymodel.protocols.openidconnect\5.3.0\lib\netstandard1.4\Microsoft.IdentityModel.Protocols.OpenIdConnect.dll +microsoft.identitymodel.protocols.openidconnect\5.3.0\lib\netstandard1.4\Microsoft.IdentityModel.Protocols.OpenIdConnect.pdb +microsoft.identitymodel.protocols.openidconnect\5.3.0\lib\netstandard2.0\Microsoft.IdentityModel.Protocols.OpenIdConnect.dll +microsoft.identitymodel.protocols.openidconnect\5.3.0\lib\netstandard2.0\Microsoft.IdentityModel.Protocols.OpenIdConnect.pdb +microsoft.identitymodel.protocols.openidconnect\5.3.0\microsoft.identitymodel.protocols.openidconnect.5.3.0.nupkg +microsoft.identitymodel.protocols.openidconnect\5.3.0\microsoft.identitymodel.protocols.openidconnect.5.3.0.nupkg.sha512 +microsoft.identitymodel.protocols.openidconnect\5.3.0\microsoft.identitymodel.protocols.openidconnect.nuspec +microsoft.identitymodel.protocols.wsfederation\5.3.0\.nupkg.metadata +microsoft.identitymodel.protocols.wsfederation\5.3.0\.signature.p7s +microsoft.identitymodel.protocols.wsfederation\5.3.0\lib\net45\Microsoft.IdentityModel.Protocols.WsFederation.dll +microsoft.identitymodel.protocols.wsfederation\5.3.0\lib\net45\Microsoft.IdentityModel.Protocols.WsFederation.pdb +microsoft.identitymodel.protocols.wsfederation\5.3.0\lib\net451\Microsoft.IdentityModel.Protocols.WsFederation.dll +microsoft.identitymodel.protocols.wsfederation\5.3.0\lib\net451\Microsoft.IdentityModel.Protocols.WsFederation.pdb +microsoft.identitymodel.protocols.wsfederation\5.3.0\lib\net461\Microsoft.IdentityModel.Protocols.WsFederation.dll +microsoft.identitymodel.protocols.wsfederation\5.3.0\lib\net461\Microsoft.IdentityModel.Protocols.WsFederation.pdb +microsoft.identitymodel.protocols.wsfederation\5.3.0\lib\netstandard1.4\Microsoft.IdentityModel.Protocols.WsFederation.dll +microsoft.identitymodel.protocols.wsfederation\5.3.0\lib\netstandard1.4\Microsoft.IdentityModel.Protocols.WsFederation.pdb +microsoft.identitymodel.protocols.wsfederation\5.3.0\lib\netstandard2.0\Microsoft.IdentityModel.Protocols.WsFederation.dll +microsoft.identitymodel.protocols.wsfederation\5.3.0\lib\netstandard2.0\Microsoft.IdentityModel.Protocols.WsFederation.pdb +microsoft.identitymodel.protocols.wsfederation\5.3.0\microsoft.identitymodel.protocols.wsfederation.5.3.0.nupkg +microsoft.identitymodel.protocols.wsfederation\5.3.0\microsoft.identitymodel.protocols.wsfederation.5.3.0.nupkg.sha512 +microsoft.identitymodel.protocols.wsfederation\5.3.0\microsoft.identitymodel.protocols.wsfederation.nuspec +microsoft.identitymodel.protocols\5.3.0\.nupkg.metadata +microsoft.identitymodel.protocols\5.3.0\.signature.p7s +microsoft.identitymodel.protocols\5.3.0\lib\net45\Microsoft.IdentityModel.Protocols.dll +microsoft.identitymodel.protocols\5.3.0\lib\net45\Microsoft.IdentityModel.Protocols.pdb +microsoft.identitymodel.protocols\5.3.0\lib\net451\Microsoft.IdentityModel.Protocols.dll +microsoft.identitymodel.protocols\5.3.0\lib\net451\Microsoft.IdentityModel.Protocols.pdb +microsoft.identitymodel.protocols\5.3.0\lib\net461\Microsoft.IdentityModel.Protocols.dll +microsoft.identitymodel.protocols\5.3.0\lib\net461\Microsoft.IdentityModel.Protocols.pdb +microsoft.identitymodel.protocols\5.3.0\lib\netstandard1.4\Microsoft.IdentityModel.Protocols.dll +microsoft.identitymodel.protocols\5.3.0\lib\netstandard1.4\Microsoft.IdentityModel.Protocols.pdb +microsoft.identitymodel.protocols\5.3.0\lib\netstandard2.0\Microsoft.IdentityModel.Protocols.dll +microsoft.identitymodel.protocols\5.3.0\lib\netstandard2.0\Microsoft.IdentityModel.Protocols.pdb +microsoft.identitymodel.protocols\5.3.0\microsoft.identitymodel.protocols.5.3.0.nupkg +microsoft.identitymodel.protocols\5.3.0\microsoft.identitymodel.protocols.5.3.0.nupkg.sha512 +microsoft.identitymodel.protocols\5.3.0\microsoft.identitymodel.protocols.nuspec +microsoft.identitymodel.tokens.saml\5.3.0\.nupkg.metadata +microsoft.identitymodel.tokens.saml\5.3.0\.signature.p7s +microsoft.identitymodel.tokens.saml\5.3.0\lib\net45\Microsoft.IdentityModel.Tokens.Saml.dll +microsoft.identitymodel.tokens.saml\5.3.0\lib\net45\Microsoft.IdentityModel.Tokens.Saml.pdb +microsoft.identitymodel.tokens.saml\5.3.0\lib\net451\Microsoft.IdentityModel.Tokens.Saml.dll +microsoft.identitymodel.tokens.saml\5.3.0\lib\net451\Microsoft.IdentityModel.Tokens.Saml.pdb +microsoft.identitymodel.tokens.saml\5.3.0\lib\net461\Microsoft.IdentityModel.Tokens.Saml.dll +microsoft.identitymodel.tokens.saml\5.3.0\lib\net461\Microsoft.IdentityModel.Tokens.Saml.pdb +microsoft.identitymodel.tokens.saml\5.3.0\lib\netstandard1.4\Microsoft.IdentityModel.Tokens.Saml.dll +microsoft.identitymodel.tokens.saml\5.3.0\lib\netstandard1.4\Microsoft.IdentityModel.Tokens.Saml.pdb +microsoft.identitymodel.tokens.saml\5.3.0\lib\netstandard2.0\Microsoft.IdentityModel.Tokens.Saml.dll +microsoft.identitymodel.tokens.saml\5.3.0\lib\netstandard2.0\Microsoft.IdentityModel.Tokens.Saml.pdb +microsoft.identitymodel.tokens.saml\5.3.0\microsoft.identitymodel.tokens.saml.5.3.0.nupkg +microsoft.identitymodel.tokens.saml\5.3.0\microsoft.identitymodel.tokens.saml.5.3.0.nupkg.sha512 +microsoft.identitymodel.tokens.saml\5.3.0\microsoft.identitymodel.tokens.saml.nuspec +microsoft.identitymodel.tokens\5.3.0\.nupkg.metadata +microsoft.identitymodel.tokens\5.3.0\.signature.p7s +microsoft.identitymodel.tokens\5.3.0\lib\net45\Microsoft.IdentityModel.Tokens.dll +microsoft.identitymodel.tokens\5.3.0\lib\net45\Microsoft.IdentityModel.Tokens.pdb +microsoft.identitymodel.tokens\5.3.0\lib\net451\Microsoft.IdentityModel.Tokens.dll +microsoft.identitymodel.tokens\5.3.0\lib\net451\Microsoft.IdentityModel.Tokens.pdb +microsoft.identitymodel.tokens\5.3.0\lib\net461\Microsoft.IdentityModel.Tokens.dll +microsoft.identitymodel.tokens\5.3.0\lib\net461\Microsoft.IdentityModel.Tokens.pdb +microsoft.identitymodel.tokens\5.3.0\lib\netstandard1.4\Microsoft.IdentityModel.Tokens.dll +microsoft.identitymodel.tokens\5.3.0\lib\netstandard1.4\Microsoft.IdentityModel.Tokens.pdb +microsoft.identitymodel.tokens\5.3.0\lib\netstandard2.0\Microsoft.IdentityModel.Tokens.dll +microsoft.identitymodel.tokens\5.3.0\lib\netstandard2.0\Microsoft.IdentityModel.Tokens.pdb +microsoft.identitymodel.tokens\5.3.0\microsoft.identitymodel.tokens.5.3.0.nupkg +microsoft.identitymodel.tokens\5.3.0\microsoft.identitymodel.tokens.5.3.0.nupkg.sha512 +microsoft.identitymodel.tokens\5.3.0\microsoft.identitymodel.tokens.nuspec +microsoft.identitymodel.xml\5.3.0\.nupkg.metadata +microsoft.identitymodel.xml\5.3.0\.signature.p7s +microsoft.identitymodel.xml\5.3.0\lib\net45\Microsoft.IdentityModel.Xml.dll +microsoft.identitymodel.xml\5.3.0\lib\net45\Microsoft.IdentityModel.Xml.pdb +microsoft.identitymodel.xml\5.3.0\lib\net451\Microsoft.IdentityModel.Xml.dll +microsoft.identitymodel.xml\5.3.0\lib\net451\Microsoft.IdentityModel.Xml.pdb +microsoft.identitymodel.xml\5.3.0\lib\net461\Microsoft.IdentityModel.Xml.dll +microsoft.identitymodel.xml\5.3.0\lib\net461\Microsoft.IdentityModel.Xml.pdb +microsoft.identitymodel.xml\5.3.0\lib\netstandard1.4\Microsoft.IdentityModel.Xml.dll +microsoft.identitymodel.xml\5.3.0\lib\netstandard1.4\Microsoft.IdentityModel.Xml.pdb +microsoft.identitymodel.xml\5.3.0\lib\netstandard2.0\Microsoft.IdentityModel.Xml.dll +microsoft.identitymodel.xml\5.3.0\lib\netstandard2.0\Microsoft.IdentityModel.Xml.pdb +microsoft.identitymodel.xml\5.3.0\microsoft.identitymodel.xml.5.3.0.nupkg +microsoft.identitymodel.xml\5.3.0\microsoft.identitymodel.xml.5.3.0.nupkg.sha512 +microsoft.identitymodel.xml\5.3.0\microsoft.identitymodel.xml.nuspec +microsoft.net.http.headers\2.2.0\.nupkg.metadata +microsoft.net.http.headers\2.2.0\.signature.p7s +microsoft.net.http.headers\2.2.0\lib\netstandard2.0\Microsoft.Net.Http.Headers.dll +microsoft.net.http.headers\2.2.0\microsoft.net.http.headers.2.2.0.nupkg +microsoft.net.http.headers\2.2.0\microsoft.net.http.headers.2.2.0.nupkg.sha512 +microsoft.net.http.headers\2.2.0\microsoft.net.http.headers.nuspec +microsoft.netcore.app\2.2.0\.nupkg.metadata +microsoft.netcore.app\2.2.0\.signature.p7s +microsoft.netcore.app\2.2.0\build\netcoreapp2.2\Microsoft.NETCore.App.PlatformManifest.txt +microsoft.netcore.app\2.2.0\build\netcoreapp2.2\Microsoft.NETCore.App.props +microsoft.netcore.app\2.2.0\build\netcoreapp2.2\Microsoft.NETCore.App.targets +microsoft.netcore.app\2.2.0\LICENSE.TXT +microsoft.netcore.app\2.2.0\microsoft.netcore.app.2.2.0.nupkg +microsoft.netcore.app\2.2.0\microsoft.netcore.app.2.2.0.nupkg.sha512 +microsoft.netcore.app\2.2.0\microsoft.netcore.app.nuspec +microsoft.netcore.app\2.2.0\Microsoft.NETCore.App.versions.txt +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\Microsoft.CSharp.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\Microsoft.VisualBasic.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\Microsoft.Win32.Primitives.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\mscorlib.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\netstandard.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.AppContext.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Buffers.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Collections.Concurrent.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Collections.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Collections.Immutable.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Collections.NonGeneric.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Collections.Specialized.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.ComponentModel.Annotations.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.ComponentModel.DataAnnotations.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.ComponentModel.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.ComponentModel.EventBasedAsync.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.ComponentModel.Primitives.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.ComponentModel.TypeConverter.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Configuration.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Console.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Core.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Data.Common.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Data.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Diagnostics.Contracts.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Diagnostics.Debug.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Diagnostics.DiagnosticSource.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Diagnostics.FileVersionInfo.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Diagnostics.Process.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Diagnostics.StackTrace.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Diagnostics.TextWriterTraceListener.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Diagnostics.Tools.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Diagnostics.TraceSource.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Diagnostics.Tracing.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Drawing.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Drawing.Primitives.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Dynamic.Runtime.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Globalization.Calendars.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Globalization.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Globalization.Extensions.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.IO.Compression.Brotli.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.IO.Compression.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.IO.Compression.FileSystem.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.IO.Compression.ZipFile.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.IO.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.IO.FileSystem.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.IO.FileSystem.DriveInfo.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.IO.FileSystem.Primitives.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.IO.FileSystem.Watcher.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.IO.IsolatedStorage.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.IO.MemoryMappedFiles.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.IO.Pipes.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.IO.UnmanagedMemoryStream.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Linq.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Linq.Expressions.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Linq.Parallel.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Linq.Queryable.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Memory.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Net.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Net.Http.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Net.HttpListener.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Net.Mail.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Net.NameResolution.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Net.NetworkInformation.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Net.Ping.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Net.Primitives.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Net.Requests.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Net.Security.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Net.ServicePoint.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Net.Sockets.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Net.WebClient.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Net.WebHeaderCollection.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Net.WebProxy.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Net.WebSockets.Client.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Net.WebSockets.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Numerics.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Numerics.Vectors.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.ObjectModel.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Reflection.DispatchProxy.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Reflection.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Reflection.Emit.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Reflection.Emit.ILGeneration.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Reflection.Emit.Lightweight.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Reflection.Extensions.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Reflection.Metadata.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Reflection.Primitives.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Reflection.TypeExtensions.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Resources.Reader.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Resources.ResourceManager.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Resources.Writer.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Runtime.CompilerServices.VisualC.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Runtime.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Runtime.Extensions.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Runtime.Handles.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Runtime.InteropServices.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Runtime.InteropServices.RuntimeInformation.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Runtime.InteropServices.WindowsRuntime.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Runtime.Loader.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Runtime.Numerics.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Runtime.Serialization.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Runtime.Serialization.Formatters.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Runtime.Serialization.Json.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Runtime.Serialization.Primitives.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Runtime.Serialization.Xml.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Security.Claims.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Security.Cryptography.Algorithms.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Security.Cryptography.Csp.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Security.Cryptography.Encoding.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Security.Cryptography.Primitives.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Security.Cryptography.X509Certificates.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Security.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Security.Principal.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Security.SecureString.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.ServiceModel.Web.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.ServiceProcess.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Text.Encoding.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Text.Encoding.Extensions.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Text.RegularExpressions.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Threading.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Threading.Overlapped.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Threading.Tasks.Dataflow.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Threading.Tasks.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Threading.Tasks.Extensions.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Threading.Tasks.Parallel.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Threading.Thread.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Threading.ThreadPool.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Threading.Timer.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Transactions.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Transactions.Local.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.ValueTuple.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Web.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Web.HttpUtility.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Windows.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Xml.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Xml.Linq.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Xml.ReaderWriter.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Xml.Serialization.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Xml.XDocument.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Xml.XmlDocument.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Xml.XmlSerializer.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Xml.XPath.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Xml.XPath.XDocument.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\WindowsBase.dll +microsoft.netcore.app\2.2.0\runtime.json +microsoft.netcore.app\2.2.0\THIRD-PARTY-NOTICES.TXT +microsoft.netcore.dotnetapphost\2.2.0\.nupkg.metadata +microsoft.netcore.dotnetapphost\2.2.0\.signature.p7s +microsoft.netcore.dotnetapphost\2.2.0\LICENSE.TXT +microsoft.netcore.dotnetapphost\2.2.0\microsoft.netcore.dotnetapphost.2.2.0.nupkg +microsoft.netcore.dotnetapphost\2.2.0\microsoft.netcore.dotnetapphost.2.2.0.nupkg.sha512 +microsoft.netcore.dotnetapphost\2.2.0\microsoft.netcore.dotnetapphost.nuspec +microsoft.netcore.dotnetapphost\2.2.0\runtime.json +microsoft.netcore.dotnetapphost\2.2.0\THIRD-PARTY-NOTICES.TXT +microsoft.netcore.dotnethostpolicy\2.2.0\.nupkg.metadata +microsoft.netcore.dotnethostpolicy\2.2.0\.signature.p7s +microsoft.netcore.dotnethostpolicy\2.2.0\LICENSE.TXT +microsoft.netcore.dotnethostpolicy\2.2.0\microsoft.netcore.dotnethostpolicy.2.2.0.nupkg +microsoft.netcore.dotnethostpolicy\2.2.0\microsoft.netcore.dotnethostpolicy.2.2.0.nupkg.sha512 +microsoft.netcore.dotnethostpolicy\2.2.0\microsoft.netcore.dotnethostpolicy.nuspec +microsoft.netcore.dotnethostpolicy\2.2.0\runtime.json +microsoft.netcore.dotnethostpolicy\2.2.0\THIRD-PARTY-NOTICES.TXT +microsoft.netcore.dotnethostresolver\2.2.0\.nupkg.metadata +microsoft.netcore.dotnethostresolver\2.2.0\.signature.p7s +microsoft.netcore.dotnethostresolver\2.2.0\LICENSE.TXT +microsoft.netcore.dotnethostresolver\2.2.0\microsoft.netcore.dotnethostresolver.2.2.0.nupkg +microsoft.netcore.dotnethostresolver\2.2.0\microsoft.netcore.dotnethostresolver.2.2.0.nupkg.sha512 +microsoft.netcore.dotnethostresolver\2.2.0\microsoft.netcore.dotnethostresolver.nuspec +microsoft.netcore.dotnethostresolver\2.2.0\runtime.json +microsoft.netcore.dotnethostresolver\2.2.0\THIRD-PARTY-NOTICES.TXT +microsoft.netcore.platforms\1.0.1\.nupkg.metadata +microsoft.netcore.platforms\1.0.1\.signature.p7s +microsoft.netcore.platforms\1.0.2\.nupkg.metadata +microsoft.netcore.platforms\1.0.2\.signature.p7s +microsoft.netcore.platforms\1.1.0\.nupkg.metadata +microsoft.netcore.platforms\1.1.0\.signature.p7s +microsoft.netcore.platforms\2.0.0\.nupkg.metadata +microsoft.netcore.platforms\2.0.0\.signature.p7s +microsoft.netcore.platforms\2.2.0\.nupkg.metadata +microsoft.netcore.platforms\2.2.0\.signature.p7s +microsoft.netcore.platforms\2.2.0\lib\netstandard1.0\_._ +microsoft.netcore.platforms\2.2.0\LICENSE.TXT +microsoft.netcore.platforms\2.2.0\microsoft.netcore.platforms.2.2.0.nupkg +microsoft.netcore.platforms\2.2.0\microsoft.netcore.platforms.2.2.0.nupkg.sha512 +microsoft.netcore.platforms\2.2.0\microsoft.netcore.platforms.nuspec +microsoft.netcore.platforms\2.2.0\runtime.json +microsoft.netcore.platforms\2.2.0\THIRD-PARTY-NOTICES.TXT +microsoft.netcore.platforms\2.2.0\useSharedDesignerContext.txt +microsoft.netcore.platforms\2.2.0\version.txt +microsoft.netcore.targets\1.0.1\.nupkg.metadata +microsoft.netcore.targets\1.1.0\.nupkg.metadata +microsoft.netcore.targets\2.0.0\.nupkg.metadata +microsoft.rest.clientruntime.azure\3.3.7\.nupkg.metadata +microsoft.rest.clientruntime.azure\3.3.7\.signature.p7s +microsoft.rest.clientruntime\2.3.8\.nupkg.metadata +microsoft.rest.clientruntime\2.3.8\.signature.p7s +microsoft.visualstudio.web.browserlink\2.2.0\.nupkg.metadata +microsoft.visualstudio.web.browserlink\2.2.0\.signature.p7s +microsoft.visualstudio.web.browserlink\2.2.0\lib\netstandard2.0\Microsoft.VisualStudio.Web.BrowserLink.dll +microsoft.visualstudio.web.browserlink\2.2.0\microsoft.visualstudio.web.browserlink.2.2.0.nupkg +microsoft.visualstudio.web.browserlink\2.2.0\microsoft.visualstudio.web.browserlink.2.2.0.nupkg.sha512 +microsoft.visualstudio.web.browserlink\2.2.0\microsoft.visualstudio.web.browserlink.nuspec +microsoft.win32.primitives\4.0.1\.nupkg.metadata +microsoft.win32.primitives\4.3.0\.nupkg.metadata +microsoft.win32.registry\4.3.0\.nupkg.metadata +microsoft.win32.registry\4.5.0\.nupkg.metadata +netstandard.library\1.6.0\.nupkg.metadata +netstandard.library\1.6.1\.nupkg.metadata +netstandard.library\2.0.3\.nupkg.metadata +newtonsoft.json.bson\1.0.1\.nupkg.metadata +newtonsoft.json.bson\1.0.1\.signature.p7s +newtonsoft.json\10.0.1\.nupkg.metadata +newtonsoft.json\10.0.1\.signature.p7s +newtonsoft.json\11.0.2\.nupkg.metadata +newtonsoft.json\11.0.2\.signature.p7s +newtonsoft.json\9.0.1\.nupkg.metadata +remotion.linq\2.2.0\.nupkg.metadata +remotion.linq\2.2.0\.signature.p7s +runtime.debian.8-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.fedora.23-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.fedora.24-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.native.system.data.sqlclient.sni\4.5.0\.nupkg.metadata +runtime.native.system.data.sqlclient.sni\4.5.0\.signature.p7s +runtime.native.system.data.sqlclient.sni\4.5.0\LICENSE.TXT +runtime.native.system.data.sqlclient.sni\4.5.0\runtime.native.system.data.sqlclient.sni.4.5.0.nupkg +runtime.native.system.data.sqlclient.sni\4.5.0\runtime.native.system.data.sqlclient.sni.4.5.0.nupkg.sha512 +runtime.native.system.data.sqlclient.sni\4.5.0\runtime.native.system.data.sqlclient.sni.nuspec +runtime.native.system.data.sqlclient.sni\4.5.0\THIRD-PARTY-NOTICES.TXT +runtime.native.system.data.sqlclient.sni\4.5.0\useSharedDesignerContext.txt +runtime.native.system.data.sqlclient.sni\4.5.0\version.txt +runtime.native.system.io.compression\4.1.0\.nupkg.metadata +runtime.native.system.io.compression\4.3.0\.nupkg.metadata +runtime.native.system.net.http\4.0.1\.nupkg.metadata +runtime.native.system.net.http\4.3.0\.nupkg.metadata +runtime.native.system.net.security\4.3.0\.nupkg.metadata +runtime.native.system.security.cryptography.apple\4.3.0\.nupkg.metadata +runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.native.system.security.cryptography\4.0.0\.nupkg.metadata +runtime.native.system\4.0.0\.nupkg.metadata +runtime.native.system\4.3.0\.nupkg.metadata +runtime.opensuse.13.2-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.opensuse.42.1-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.osx.10.10-x64.runtime.native.system.security.cryptography.apple\4.3.0\.nupkg.metadata +runtime.osx.10.10-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.rhel.7-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.ubuntu.14.04-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.ubuntu.16.04-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.ubuntu.16.10-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.win-arm64.runtime.native.system.data.sqlclient.sni\4.4.0\.nupkg.metadata +runtime.win-x64.runtime.native.system.data.sqlclient.sni\4.4.0\.nupkg.metadata +runtime.win-x86.runtime.native.system.data.sqlclient.sni\4.4.0\.nupkg.metadata +sqlitepclraw.bundle_green\1.1.11\.nupkg.metadata +sqlitepclraw.bundle_green\1.1.11\.signature.p7s +sqlitepclraw.core\1.1.11\.nupkg.metadata +sqlitepclraw.core\1.1.11\.signature.p7s +sqlitepclraw.lib.e_sqlite3.linux\1.1.11\.nupkg.metadata +sqlitepclraw.lib.e_sqlite3.linux\1.1.11\.signature.p7s +sqlitepclraw.lib.e_sqlite3.osx\1.1.11\.nupkg.metadata +sqlitepclraw.lib.e_sqlite3.osx\1.1.11\.signature.p7s +sqlitepclraw.lib.e_sqlite3.v110_xp\1.1.11\.nupkg.metadata +sqlitepclraw.lib.e_sqlite3.v110_xp\1.1.11\.signature.p7s +sqlitepclraw.provider.e_sqlite3.netstandard11\1.1.11\.nupkg.metadata +sqlitepclraw.provider.e_sqlite3.netstandard11\1.1.11\.signature.p7s +stackexchange.redis.strongname\1.2.6\.nupkg.metadata +stackexchange.redis.strongname\1.2.6\.signature.p7s +stackexchange.redis.strongname\1.2.6\lib\net45\StackExchange.Redis.StrongName.dll +stackexchange.redis.strongname\1.2.6\lib\net46\StackExchange.Redis.StrongName.dll +stackexchange.redis.strongname\1.2.6\lib\netstandard1.5\StackExchange.Redis.StrongName.dll +stackexchange.redis.strongname\1.2.6\stackexchange.redis.strongname.1.2.6.nupkg +stackexchange.redis.strongname\1.2.6\stackexchange.redis.strongname.1.2.6.nupkg.sha512 +stackexchange.redis.strongname\1.2.6\stackexchange.redis.strongname.nuspec +system.appcontext\4.1.0\.nupkg.metadata +system.appcontext\4.3.0\.nupkg.metadata +system.buffers\4.0.0\.nupkg.metadata +system.buffers\4.3.0\.nupkg.metadata +system.buffers\4.5.0\.nupkg.metadata +system.collections.concurrent\4.0.12\.nupkg.metadata +system.collections.concurrent\4.3.0\.nupkg.metadata +system.collections.immutable\1.3.0\.nupkg.metadata +system.collections.immutable\1.3.1\.nupkg.metadata +system.collections.immutable\1.5.0\.nupkg.metadata +system.collections.nongeneric\4.3.0\.nupkg.metadata +system.collections.nongeneric\4.3.0\.signature.p7s +system.collections.specialized\4.3.0\.nupkg.metadata +system.collections\4.0.11\.nupkg.metadata +system.collections\4.3.0\.nupkg.metadata +system.componentmodel.annotations\4.5.0\.nupkg.metadata +system.componentmodel.primitives\4.3.0\.nupkg.metadata +system.componentmodel.typeconverter\4.3.0\.nupkg.metadata +system.componentmodel\4.3.0\.nupkg.metadata +system.console\4.0.0\.nupkg.metadata +system.console\4.3.0\.nupkg.metadata +system.data.sqlclient\4.6.0\.nupkg.metadata +system.data.sqlclient\4.6.0\.signature.p7s +system.data.sqlclient\4.6.0\lib\MonoAndroid10\_._ +system.data.sqlclient\4.6.0\lib\MonoTouch10\_._ +system.data.sqlclient\4.6.0\lib\net451\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\lib\net46\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\lib\net461\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\lib\netcoreapp2.1\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\lib\netstandard1.2\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\lib\netstandard1.3\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\lib\netstandard2.0\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\lib\xamarinios10\_._ +system.data.sqlclient\4.6.0\lib\xamarinmac20\_._ +system.data.sqlclient\4.6.0\lib\xamarintvos10\_._ +system.data.sqlclient\4.6.0\lib\xamarinwatchos10\_._ +system.data.sqlclient\4.6.0\LICENSE.TXT +system.data.sqlclient\4.6.0\ref\MonoAndroid10\_._ +system.data.sqlclient\4.6.0\ref\MonoTouch10\_._ +system.data.sqlclient\4.6.0\ref\net451\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\ref\net46\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\ref\net461\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\ref\netcoreapp2.1\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\ref\netstandard1.2\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\ref\netstandard1.3\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\ref\netstandard2.0\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\ref\xamarinios10\_._ +system.data.sqlclient\4.6.0\ref\xamarinmac20\_._ +system.data.sqlclient\4.6.0\ref\xamarintvos10\_._ +system.data.sqlclient\4.6.0\ref\xamarinwatchos10\_._ +system.data.sqlclient\4.6.0\runtimes\unix\lib\netcoreapp2.1\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\runtimes\unix\lib\netstandard1.3\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\runtimes\unix\lib\netstandard2.0\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\runtimes\win\lib\net451\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\runtimes\win\lib\net46\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\runtimes\win\lib\net461\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\runtimes\win\lib\netcoreapp2.1\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\runtimes\win\lib\netstandard1.3\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\runtimes\win\lib\netstandard2.0\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\runtimes\win\lib\uap10.0.16299\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\system.data.sqlclient.4.6.0.nupkg +system.data.sqlclient\4.6.0\system.data.sqlclient.4.6.0.nupkg.sha512 +system.data.sqlclient\4.6.0\system.data.sqlclient.nuspec +system.data.sqlclient\4.6.0\THIRD-PARTY-NOTICES.TXT +system.data.sqlclient\4.6.0\useSharedDesignerContext.txt +system.data.sqlclient\4.6.0\version.txt +system.diagnostics.contracts\4.3.0\.nupkg.metadata +system.diagnostics.contracts\4.3.0\.signature.p7s +system.diagnostics.debug\4.0.11\.nupkg.metadata +system.diagnostics.debug\4.3.0\.nupkg.metadata +system.diagnostics.diagnosticsource\4.0.0\.nupkg.metadata +system.diagnostics.diagnosticsource\4.3.0\.nupkg.metadata +system.diagnostics.diagnosticsource\4.4.0\.nupkg.metadata +system.diagnostics.diagnosticsource\4.4.0\.signature.p7s +system.diagnostics.diagnosticsource\4.5.0\.nupkg.metadata +system.diagnostics.fileversioninfo\4.3.0\.nupkg.metadata +system.diagnostics.fileversioninfo\4.3.0\.signature.p7s +system.diagnostics.process\4.3.0\.nupkg.metadata +system.diagnostics.stacktrace\4.3.0\.nupkg.metadata +system.diagnostics.tools\4.0.1\.nupkg.metadata +system.diagnostics.tools\4.3.0\.nupkg.metadata +system.diagnostics.tracing\4.1.0\.nupkg.metadata +system.diagnostics.tracing\4.3.0\.nupkg.metadata +system.dynamic.runtime\4.0.11\.nupkg.metadata +system.dynamic.runtime\4.3.0\.nupkg.metadata +system.globalization.calendars\4.0.1\.nupkg.metadata +system.globalization.calendars\4.3.0\.nupkg.metadata +system.globalization.extensions\4.0.1\.nupkg.metadata +system.globalization.extensions\4.3.0\.nupkg.metadata +system.globalization\4.0.11\.nupkg.metadata +system.globalization\4.3.0\.nupkg.metadata +system.identitymodel.tokens.jwt\5.3.0\.nupkg.metadata +system.identitymodel.tokens.jwt\5.3.0\.signature.p7s +system.identitymodel.tokens.jwt\5.3.0\lib\net45\System.IdentityModel.Tokens.Jwt.dll +system.identitymodel.tokens.jwt\5.3.0\lib\net45\System.IdentityModel.Tokens.Jwt.pdb +system.identitymodel.tokens.jwt\5.3.0\lib\net451\System.IdentityModel.Tokens.Jwt.dll +system.identitymodel.tokens.jwt\5.3.0\lib\net451\System.IdentityModel.Tokens.Jwt.pdb +system.identitymodel.tokens.jwt\5.3.0\lib\net461\System.IdentityModel.Tokens.Jwt.dll +system.identitymodel.tokens.jwt\5.3.0\lib\net461\System.IdentityModel.Tokens.Jwt.pdb +system.identitymodel.tokens.jwt\5.3.0\lib\netstandard1.4\System.IdentityModel.Tokens.Jwt.dll +system.identitymodel.tokens.jwt\5.3.0\lib\netstandard1.4\System.IdentityModel.Tokens.Jwt.pdb +system.identitymodel.tokens.jwt\5.3.0\lib\netstandard2.0\System.IdentityModel.Tokens.Jwt.dll +system.identitymodel.tokens.jwt\5.3.0\lib\netstandard2.0\System.IdentityModel.Tokens.Jwt.pdb +system.identitymodel.tokens.jwt\5.3.0\system.identitymodel.tokens.jwt.5.3.0.nupkg +system.identitymodel.tokens.jwt\5.3.0\system.identitymodel.tokens.jwt.5.3.0.nupkg.sha512 +system.identitymodel.tokens.jwt\5.3.0\system.identitymodel.tokens.jwt.nuspec +system.interactive.async\3.2.0\.nupkg.metadata +system.interactive.async\3.2.0\.signature.p7s +system.interactive.async\3.2.0\lib\net45\System.Interactive.Async.dll +system.interactive.async\3.2.0\lib\net46\System.Interactive.Async.dll +system.interactive.async\3.2.0\lib\netstandard1.0\System.Interactive.Async.dll +system.interactive.async\3.2.0\lib\netstandard1.3\System.Interactive.Async.dll +system.interactive.async\3.2.0\lib\netstandard2.0\System.Interactive.Async.dll +system.interactive.async\3.2.0\system.interactive.async.3.2.0.nupkg +system.interactive.async\3.2.0\system.interactive.async.3.2.0.nupkg.sha512 +system.interactive.async\3.2.0\system.interactive.async.nuspec +system.io.compression.zipfile\4.0.1\.nupkg.metadata +system.io.compression.zipfile\4.3.0\.nupkg.metadata +system.io.compression\4.1.0\.nupkg.metadata +system.io.compression\4.3.0\.nupkg.metadata +system.io.filesystem.primitives\4.0.1\.nupkg.metadata +system.io.filesystem.primitives\4.3.0\.nupkg.metadata +system.io.filesystem\4.0.1\.nupkg.metadata +system.io.filesystem\4.3.0\.nupkg.metadata +system.io.pipelines\4.5.2\.nupkg.metadata +system.io.pipelines\4.5.2\.signature.p7s +system.io.pipelines\4.5.2\lib\netcoreapp2.1\System.IO.Pipelines.dll +system.io.pipelines\4.5.2\lib\netstandard1.3\System.IO.Pipelines.dll +system.io.pipelines\4.5.2\lib\netstandard2.0\System.IO.Pipelines.dll +system.io.pipelines\4.5.2\LICENSE.TXT +system.io.pipelines\4.5.2\ref\netstandard1.3\System.IO.Pipelines.dll +system.io.pipelines\4.5.2\system.io.pipelines.4.5.2.nupkg +system.io.pipelines\4.5.2\system.io.pipelines.4.5.2.nupkg.sha512 +system.io.pipelines\4.5.2\system.io.pipelines.nuspec +system.io.pipelines\4.5.2\THIRD-PARTY-NOTICES.TXT +system.io.pipelines\4.5.2\useSharedDesignerContext.txt +system.io.pipelines\4.5.2\version.txt +system.io\4.1.0\.nupkg.metadata +system.io\4.3.0\.nupkg.metadata +system.linq.expressions\4.1.0\.nupkg.metadata +system.linq.expressions\4.3.0\.nupkg.metadata +system.linq.queryable\4.0.1\.nupkg.metadata +system.linq\4.1.0\.nupkg.metadata +system.linq\4.3.0\.nupkg.metadata +system.memory\4.5.1\.nupkg.metadata +system.net.http\4.1.0\.nupkg.metadata +system.net.http\4.1.0\.signature.p7s +system.net.http\4.3.0\.nupkg.metadata +system.net.http\4.3.0\.signature.p7s +system.net.nameresolution\4.3.0\.nupkg.metadata +system.net.primitives\4.0.11\.nupkg.metadata +system.net.primitives\4.3.0\.nupkg.metadata +system.net.security\4.3.0\.nupkg.metadata +system.net.sockets\4.1.0\.nupkg.metadata +system.net.sockets\4.3.0\.nupkg.metadata +system.net.websockets.websocketprotocol\4.5.1\.nupkg.metadata +system.numerics.vectors\4.5.0\.nupkg.metadata +system.objectmodel\4.0.12\.nupkg.metadata +system.objectmodel\4.3.0\.nupkg.metadata +system.private.datacontractserialization\4.1.1\.nupkg.metadata +system.private.datacontractserialization\4.3.0\.nupkg.metadata +system.private.datacontractserialization\4.3.0\.signature.p7s +system.reflection.emit.ilgeneration\4.0.1\.nupkg.metadata +system.reflection.emit.ilgeneration\4.3.0\.nupkg.metadata +system.reflection.emit.lightweight\4.0.1\.nupkg.metadata +system.reflection.emit.lightweight\4.3.0\.nupkg.metadata +system.reflection.emit\4.0.1\.nupkg.metadata +system.reflection.emit\4.3.0\.nupkg.metadata +system.reflection.extensions\4.0.1\.nupkg.metadata +system.reflection.extensions\4.3.0\.nupkg.metadata +system.reflection.metadata\1.4.1\.nupkg.metadata +system.reflection.metadata\1.4.2\.nupkg.metadata +system.reflection.metadata\1.6.0\.nupkg.metadata +system.reflection.primitives\4.0.1\.nupkg.metadata +system.reflection.primitives\4.3.0\.nupkg.metadata +system.reflection.typeextensions\4.1.0\.nupkg.metadata +system.reflection.typeextensions\4.3.0\.nupkg.metadata +system.reflection\4.1.0\.nupkg.metadata +system.reflection\4.3.0\.nupkg.metadata +system.resources.resourcemanager\4.0.1\.nupkg.metadata +system.resources.resourcemanager\4.3.0\.nupkg.metadata +system.runtime.compilerservices.unsafe\4.5.0\.nupkg.metadata +system.runtime.compilerservices.unsafe\4.5.1\.nupkg.metadata +system.runtime.extensions\4.1.0\.nupkg.metadata +system.runtime.extensions\4.3.0\.nupkg.metadata +system.runtime.handles\4.0.1\.nupkg.metadata +system.runtime.handles\4.3.0\.nupkg.metadata +system.runtime.interopservices.runtimeinformation\4.0.0\.nupkg.metadata +system.runtime.interopservices.runtimeinformation\4.3.0\.nupkg.metadata +system.runtime.interopservices\4.1.0\.nupkg.metadata +system.runtime.interopservices\4.3.0\.nupkg.metadata +system.runtime.numerics\4.0.1\.nupkg.metadata +system.runtime.numerics\4.3.0\.nupkg.metadata +system.runtime.serialization.formatters\4.3.0\.nupkg.metadata +system.runtime.serialization.json\4.0.2\.nupkg.metadata +system.runtime.serialization.json\4.3.0\.nupkg.metadata +system.runtime.serialization.json\4.3.0\dotnet_library_license.txt +system.runtime.serialization.json\4.3.0\lib\MonoAndroid10\_._ +system.runtime.serialization.json\4.3.0\lib\MonoTouch10\_._ +system.runtime.serialization.json\4.3.0\lib\net45\_._ +system.runtime.serialization.json\4.3.0\lib\netcore50\System.Runtime.Serialization.Json.dll +system.runtime.serialization.json\4.3.0\lib\netstandard1.3\System.Runtime.Serialization.Json.dll +system.runtime.serialization.json\4.3.0\lib\portable-net45+win8+wp8+wpa81\_._ +system.runtime.serialization.json\4.3.0\lib\win8\_._ +system.runtime.serialization.json\4.3.0\lib\wp80\_._ +system.runtime.serialization.json\4.3.0\lib\wpa81\_._ +system.runtime.serialization.json\4.3.0\lib\xamarinios10\_._ +system.runtime.serialization.json\4.3.0\lib\xamarinmac20\_._ +system.runtime.serialization.json\4.3.0\lib\xamarintvos10\_._ +system.runtime.serialization.json\4.3.0\lib\xamarinwatchos10\_._ +system.runtime.serialization.json\4.3.0\ref\MonoAndroid10\_._ +system.runtime.serialization.json\4.3.0\ref\MonoTouch10\_._ +system.runtime.serialization.json\4.3.0\ref\net45\_._ +system.runtime.serialization.json\4.3.0\ref\netcore50\System.Runtime.Serialization.Json.dll +system.runtime.serialization.json\4.3.0\ref\netstandard1.0\System.Runtime.Serialization.Json.dll +system.runtime.serialization.json\4.3.0\ref\portable-net45+win8+wp8+wpa81\_._ +system.runtime.serialization.json\4.3.0\ref\win8\_._ +system.runtime.serialization.json\4.3.0\ref\wp80\_._ +system.runtime.serialization.json\4.3.0\ref\wpa81\_._ +system.runtime.serialization.json\4.3.0\ref\xamarinios10\_._ +system.runtime.serialization.json\4.3.0\ref\xamarinmac20\_._ +system.runtime.serialization.json\4.3.0\ref\xamarintvos10\_._ +system.runtime.serialization.json\4.3.0\ref\xamarinwatchos10\_._ +system.runtime.serialization.json\4.3.0\system.runtime.serialization.json.4.3.0.nupkg +system.runtime.serialization.json\4.3.0\system.runtime.serialization.json.4.3.0.nupkg.sha512 +system.runtime.serialization.json\4.3.0\system.runtime.serialization.json.nuspec +system.runtime.serialization.json\4.3.0\ThirdPartyNotices.txt +system.runtime.serialization.primitives\4.1.1\.nupkg.metadata +system.runtime.serialization.primitives\4.3.0\.nupkg.metadata +system.runtime.serialization.xml\4.3.0\.nupkg.metadata +system.runtime.serialization.xml\4.3.0\.signature.p7s +system.runtime\4.1.0\.nupkg.metadata +system.runtime\4.3.0\.nupkg.metadata +system.security.accesscontrol\4.5.0\.nupkg.metadata +system.security.claims\4.3.0\.nupkg.metadata +system.security.cryptography.algorithms\4.2.0\.nupkg.metadata +system.security.cryptography.algorithms\4.3.0\.nupkg.metadata +system.security.cryptography.cng\4.2.0\.nupkg.metadata +system.security.cryptography.cng\4.3.0\.nupkg.metadata +system.security.cryptography.cng\4.5.0\.nupkg.metadata +system.security.cryptography.csp\4.0.0\.nupkg.metadata +system.security.cryptography.csp\4.3.0\.nupkg.metadata +system.security.cryptography.encoding\4.0.0\.nupkg.metadata +system.security.cryptography.encoding\4.3.0\.nupkg.metadata +system.security.cryptography.openssl\4.0.0\.nupkg.metadata +system.security.cryptography.openssl\4.3.0\.nupkg.metadata +system.security.cryptography.pkcs\4.5.0\.nupkg.metadata +system.security.cryptography.primitives\4.0.0\.nupkg.metadata +system.security.cryptography.primitives\4.3.0\.nupkg.metadata +system.security.cryptography.x509certificates\4.1.0\.nupkg.metadata +system.security.cryptography.x509certificates\4.3.0\.nupkg.metadata +system.security.cryptography.xml\4.5.0\.nupkg.metadata +system.security.permissions\4.5.0\.nupkg.metadata +system.security.principal.windows\4.3.0\.nupkg.metadata +system.security.principal.windows\4.5.0\.nupkg.metadata +system.security.principal\4.3.0\.nupkg.metadata +system.spatial\5.8.2\.nupkg.metadata +system.text.encoding.codepages\4.3.0\.nupkg.metadata +system.text.encoding.codepages\4.5.0\.nupkg.metadata +system.text.encoding.extensions\4.0.11\.nupkg.metadata +system.text.encoding.extensions\4.3.0\.nupkg.metadata +system.text.encoding\4.0.11\.nupkg.metadata +system.text.encoding\4.3.0\.nupkg.metadata +system.text.encodings.web\4.3.1\.nupkg.metadata +system.text.encodings.web\4.3.1\.signature.p7s +system.text.encodings.web\4.5.0\.nupkg.metadata +system.text.regularexpressions\4.1.0\.nupkg.metadata +system.text.regularexpressions\4.3.0\.nupkg.metadata +system.threading.channels\4.5.0\.nupkg.metadata +system.threading.tasks.extensions\4.0.0\.nupkg.metadata +system.threading.tasks.extensions\4.3.0\.nupkg.metadata +system.threading.tasks.extensions\4.5.1\.nupkg.metadata +system.threading.tasks.parallel\4.3.0\.nupkg.metadata +system.threading.tasks.parallel\4.3.0\.signature.p7s +system.threading.tasks\4.0.11\.nupkg.metadata +system.threading.tasks\4.3.0\.nupkg.metadata +system.threading.thread\4.3.0\.nupkg.metadata +system.threading.threadpool\4.3.0\.nupkg.metadata +system.threading.timer\4.0.1\.nupkg.metadata +system.threading.timer\4.3.0\.nupkg.metadata +system.threading\4.0.11\.nupkg.metadata +system.threading\4.3.0\.nupkg.metadata +system.valuetuple\4.3.0\.nupkg.metadata +system.valuetuple\4.5.0\.nupkg.metadata +system.xml.readerwriter\4.0.11\.nupkg.metadata +system.xml.readerwriter\4.3.0\.nupkg.metadata +system.xml.xdocument\4.0.11\.nupkg.metadata +system.xml.xdocument\4.3.0\.nupkg.metadata +system.xml.xmldocument\4.0.1\.nupkg.metadata +system.xml.xmldocument\4.3.0\.nupkg.metadata +system.xml.xmldocument\4.3.0\.signature.p7s +system.xml.xmlserializer\4.0.11\.nupkg.metadata +system.xml.xmlserializer\4.3.0\.nupkg.metadata +system.xml.xmlserializer\4.3.0\.signature.p7s +system.xml.xpath.xdocument\4.3.0\.nupkg.metadata +system.xml.xpath\4.3.0\.nupkg.metadata +system.xml.xpath\4.3.0\.signature.p7s +windowsazure.storage\8.1.4\.nupkg.metadata +windowsazure.storage\8.1.4\.signature.p7s diff --git a/src/PackageArchive/Archive.CiServer.Patch/ArchiveBaseline.2.1.6.txt b/src/PackageArchive/Archive.CiServer.Patch/ArchiveBaseline.2.1.6.txt new file mode 100644 index 0000000000..ba2033ed81 --- /dev/null +++ b/src/PackageArchive/Archive.CiServer.Patch/ArchiveBaseline.2.1.6.txt @@ -0,0 +1,667 @@ +libuv\1.10.0\.nupkg.metadata +libuv\1.10.0\.signature.p7s +messagepack\1.7.3.4\.nupkg.metadata +messagepack\1.7.3.4\.signature.p7s +microsoft.applicationinsights.aspnetcore\2.1.1\.nupkg.metadata +microsoft.applicationinsights.aspnetcore\2.1.1\.signature.p7s +microsoft.applicationinsights.dependencycollector\2.4.1\.nupkg.metadata +microsoft.applicationinsights.dependencycollector\2.4.1\.signature.p7s +microsoft.applicationinsights\2.4.0\.nupkg.metadata +microsoft.applicationinsights\2.4.0\.signature.p7s +microsoft.aspnet.webapi.client\5.2.6\.nupkg.metadata +microsoft.aspnetcore.all\2.1.1\.nupkg.metadata +microsoft.aspnetcore.antiforgery\2.1.1\.nupkg.metadata +microsoft.aspnetcore.app\2.1.1\.nupkg.metadata +microsoft.aspnetcore.applicationinsights.hostingstartup\2.1.1\.nupkg.metadata +microsoft.aspnetcore.authentication.abstractions\2.1.1\.nupkg.metadata +microsoft.aspnetcore.authentication.azuread.ui\2.1.1\.nupkg.metadata +microsoft.aspnetcore.authentication.azureadb2c.ui\2.1.1\.nupkg.metadata +microsoft.aspnetcore.authentication.cookies\2.1.1\.nupkg.metadata +microsoft.aspnetcore.authentication.core\2.1.1\.nupkg.metadata +microsoft.aspnetcore.authentication.facebook\2.1.1\.nupkg.metadata +microsoft.aspnetcore.authentication.google\2.1.1\.nupkg.metadata +microsoft.aspnetcore.authentication.jwtbearer\2.1.1\.nupkg.metadata +microsoft.aspnetcore.authentication.microsoftaccount\2.1.1\.nupkg.metadata +microsoft.aspnetcore.authentication.oauth\2.1.1\.nupkg.metadata +microsoft.aspnetcore.authentication.openidconnect\2.1.1\.nupkg.metadata +microsoft.aspnetcore.authentication.twitter\2.1.1\.nupkg.metadata +microsoft.aspnetcore.authentication.wsfederation\2.1.1\.nupkg.metadata +microsoft.aspnetcore.authentication\2.1.1\.nupkg.metadata +microsoft.aspnetcore.authorization.policy\2.1.1\.nupkg.metadata +microsoft.aspnetcore.authorization\2.1.1\.nupkg.metadata +microsoft.aspnetcore.azureappservices.hostingstartup\2.1.1\.nupkg.metadata +microsoft.aspnetcore.azureappservicesintegration\2.1.1\.nupkg.metadata +microsoft.aspnetcore.connections.abstractions\2.1.1\.nupkg.metadata +microsoft.aspnetcore.cookiepolicy\2.1.1\.nupkg.metadata +microsoft.aspnetcore.cors\2.1.1\.nupkg.metadata +microsoft.aspnetcore.cryptography.internal\2.1.1\.nupkg.metadata +microsoft.aspnetcore.cryptography.keyderivation\2.1.1\.nupkg.metadata +microsoft.aspnetcore.dataprotection.abstractions\2.1.1\.nupkg.metadata +microsoft.aspnetcore.dataprotection.azurekeyvault\2.1.1\.nupkg.metadata +microsoft.aspnetcore.dataprotection.azurestorage\2.1.1\.nupkg.metadata +microsoft.aspnetcore.dataprotection.extensions\2.1.1\.nupkg.metadata +microsoft.aspnetcore.dataprotection\2.1.1\.nupkg.metadata +microsoft.aspnetcore.diagnostics.abstractions\2.1.1\.nupkg.metadata +microsoft.aspnetcore.diagnostics.entityframeworkcore\2.1.1\.nupkg.metadata +microsoft.aspnetcore.diagnostics\2.1.1\.nupkg.metadata +microsoft.aspnetcore.hostfiltering\2.1.1\.nupkg.metadata +microsoft.aspnetcore.hosting.abstractions\2.1.1\.nupkg.metadata +microsoft.aspnetcore.hosting.server.abstractions\2.1.1\.nupkg.metadata +microsoft.aspnetcore.hosting\2.1.1\.nupkg.metadata +microsoft.aspnetcore.html.abstractions\2.1.1\.nupkg.metadata +microsoft.aspnetcore.http.abstractions\2.1.1\.nupkg.metadata +microsoft.aspnetcore.http.connections.common\1.0.1\.nupkg.metadata +microsoft.aspnetcore.http.connections\1.0.1\.nupkg.metadata +microsoft.aspnetcore.http.extensions\2.1.1\.nupkg.metadata +microsoft.aspnetcore.http.features\2.1.1\.nupkg.metadata +microsoft.aspnetcore.http\2.1.1\.nupkg.metadata +microsoft.aspnetcore.httpoverrides\2.1.1\.nupkg.metadata +microsoft.aspnetcore.httpspolicy\2.1.1\.nupkg.metadata +microsoft.aspnetcore.identity.entityframeworkcore\2.1.1\.nupkg.metadata +microsoft.aspnetcore.identity.ui\2.1.1\.nupkg.metadata +microsoft.aspnetcore.identity\2.1.1\.nupkg.metadata +microsoft.aspnetcore.jsonpatch\2.1.1\.nupkg.metadata +microsoft.aspnetcore.localization.routing\2.1.1\.nupkg.metadata +microsoft.aspnetcore.localization\2.1.1\.nupkg.metadata +microsoft.aspnetcore.middlewareanalysis\2.1.1\.nupkg.metadata +microsoft.aspnetcore.mvc.abstractions\2.1.1\.nupkg.metadata +microsoft.aspnetcore.mvc.analyzers\2.1.1\.nupkg.metadata +microsoft.aspnetcore.mvc.apiexplorer\2.1.1\.nupkg.metadata +microsoft.aspnetcore.mvc.core\2.1.1\.nupkg.metadata +microsoft.aspnetcore.mvc.cors\2.1.1\.nupkg.metadata +microsoft.aspnetcore.mvc.dataannotations\2.1.1\.nupkg.metadata +microsoft.aspnetcore.mvc.formatters.json\2.1.1\.nupkg.metadata +microsoft.aspnetcore.mvc.formatters.xml\2.1.1\.nupkg.metadata +microsoft.aspnetcore.mvc.localization\2.1.1\.nupkg.metadata +microsoft.aspnetcore.mvc.razor.extensions\2.1.1\.nupkg.metadata +microsoft.aspnetcore.mvc.razor.viewcompilation\2.1.1\.nupkg.metadata +microsoft.aspnetcore.mvc.razor\2.1.1\.nupkg.metadata +microsoft.aspnetcore.mvc.razorpages\2.1.1\.nupkg.metadata +microsoft.aspnetcore.mvc.taghelpers\2.1.1\.nupkg.metadata +microsoft.aspnetcore.mvc.viewfeatures\2.1.1\.nupkg.metadata +microsoft.aspnetcore.mvc\2.1.1\.nupkg.metadata +microsoft.aspnetcore.nodeservices\2.1.1\.nupkg.metadata +microsoft.aspnetcore.owin\2.1.1\.nupkg.metadata +microsoft.aspnetcore.razor.design\2.1.2\.nupkg.metadata +microsoft.aspnetcore.razor.language\2.1.1\.nupkg.metadata +microsoft.aspnetcore.razor.runtime\2.1.1\.nupkg.metadata +microsoft.aspnetcore.razor\2.1.1\.nupkg.metadata +microsoft.aspnetcore.responsecaching.abstractions\2.1.1\.nupkg.metadata +microsoft.aspnetcore.responsecaching\2.1.1\.nupkg.metadata +microsoft.aspnetcore.responsecompression\2.1.1\.nupkg.metadata +microsoft.aspnetcore.rewrite\2.1.1\.nupkg.metadata +microsoft.aspnetcore.routing.abstractions\2.1.1\.nupkg.metadata +microsoft.aspnetcore.routing\2.1.1\.nupkg.metadata +microsoft.aspnetcore.server.httpsys\2.1.1\.nupkg.metadata +microsoft.aspnetcore.server.iisintegration\2.1.1\.nupkg.metadata +microsoft.aspnetcore.server.kestrel.core\2.1.1\.nupkg.metadata +microsoft.aspnetcore.server.kestrel.https\2.1.1\.nupkg.metadata +microsoft.aspnetcore.server.kestrel.transport.abstractions\2.1.1\.nupkg.metadata +microsoft.aspnetcore.server.kestrel.transport.libuv\2.1.1\.nupkg.metadata +microsoft.aspnetcore.server.kestrel.transport.sockets\2.1.1\.nupkg.metadata +microsoft.aspnetcore.server.kestrel\2.1.1\.nupkg.metadata +microsoft.aspnetcore.session\2.1.1\.nupkg.metadata +microsoft.aspnetcore.signalr.common\1.0.1\.nupkg.metadata +microsoft.aspnetcore.signalr.core\1.0.1\.nupkg.metadata +microsoft.aspnetcore.signalr.protocols.json\1.0.1\.nupkg.metadata +microsoft.aspnetcore.signalr.redis\1.0.1\.nupkg.metadata +microsoft.aspnetcore.signalr\1.0.1\.nupkg.metadata +microsoft.aspnetcore.spaservices.extensions\2.1.1\.nupkg.metadata +microsoft.aspnetcore.spaservices\2.1.1\.nupkg.metadata +microsoft.aspnetcore.staticfiles\2.1.1\.nupkg.metadata +microsoft.aspnetcore.websockets\2.1.1\.nupkg.metadata +microsoft.aspnetcore.webutilities\2.1.1\.nupkg.metadata +microsoft.aspnetcore\2.1.1\.nupkg.metadata +microsoft.azure.keyvault.webkey\2.0.7\.nupkg.metadata +microsoft.azure.keyvault.webkey\2.0.7\.signature.p7s +microsoft.azure.keyvault\2.3.2\.nupkg.metadata +microsoft.azure.keyvault\2.3.2\.signature.p7s +microsoft.azure.services.appauthentication\1.0.1\.nupkg.metadata +microsoft.azure.services.appauthentication\1.0.1\.signature.p7s +microsoft.codeanalysis.analyzers\1.1.0\.nupkg.metadata +microsoft.codeanalysis.common\2.8.0\.nupkg.metadata +microsoft.codeanalysis.csharp.workspaces\2.8.0\.nupkg.metadata +microsoft.codeanalysis.csharp\2.8.0\.nupkg.metadata +microsoft.codeanalysis.razor\2.1.1\.nupkg.metadata +microsoft.codeanalysis.workspaces.common\2.8.0\.nupkg.metadata +microsoft.csharp\4.0.1\.nupkg.metadata +microsoft.csharp\4.3.0\.nupkg.metadata +microsoft.csharp\4.5.0\.nupkg.metadata +microsoft.data.edm\5.8.2\.nupkg.metadata +microsoft.data.odata\5.8.2\.nupkg.metadata +microsoft.data.sqlite.core\2.1.0\.nupkg.metadata +microsoft.data.sqlite\2.1.0\.nupkg.metadata +microsoft.dotnet.platformabstractions\2.1.0\.nupkg.metadata +microsoft.entityframeworkcore.abstractions\2.1.1\.nupkg.metadata +microsoft.entityframeworkcore.analyzers\2.1.1\.nupkg.metadata +microsoft.entityframeworkcore.design\2.1.1\.nupkg.metadata +microsoft.entityframeworkcore.inmemory\2.1.1\.nupkg.metadata +microsoft.entityframeworkcore.relational\2.1.1\.nupkg.metadata +microsoft.entityframeworkcore.sqlite.core\2.1.1\.nupkg.metadata +microsoft.entityframeworkcore.sqlite\2.1.1\.nupkg.metadata +microsoft.entityframeworkcore.sqlserver\2.1.1\.nupkg.metadata +microsoft.entityframeworkcore.tools\2.1.1\.nupkg.metadata +microsoft.entityframeworkcore\2.1.1\.nupkg.metadata +microsoft.extensions.caching.abstractions\2.1.1\.nupkg.metadata +microsoft.extensions.caching.memory\2.1.1\.nupkg.metadata +microsoft.extensions.caching.redis\2.1.1\.nupkg.metadata +microsoft.extensions.caching.sqlserver\2.1.1\.nupkg.metadata +microsoft.extensions.configuration.abstractions\2.1.1\.nupkg.metadata +microsoft.extensions.configuration.azurekeyvault\2.1.1\.nupkg.metadata +microsoft.extensions.configuration.binder\2.1.1\.nupkg.metadata +microsoft.extensions.configuration.commandline\2.1.1\.nupkg.metadata +microsoft.extensions.configuration.environmentvariables\2.1.1\.nupkg.metadata +microsoft.extensions.configuration.fileextensions\2.1.1\.nupkg.metadata +microsoft.extensions.configuration.ini\2.1.1\.nupkg.metadata +microsoft.extensions.configuration.json\2.1.1\.nupkg.metadata +microsoft.extensions.configuration.keyperfile\2.1.1\.nupkg.metadata +microsoft.extensions.configuration.usersecrets\2.1.1\.nupkg.metadata +microsoft.extensions.configuration.xml\2.1.1\.nupkg.metadata +microsoft.extensions.configuration\2.1.1\.nupkg.metadata +microsoft.extensions.dependencyinjection.abstractions\2.1.1\.nupkg.metadata +microsoft.extensions.dependencyinjection\2.1.1\.nupkg.metadata +microsoft.extensions.dependencymodel\2.1.0\.nupkg.metadata +microsoft.extensions.diagnosticadapter\2.1.0\.nupkg.metadata +microsoft.extensions.fileproviders.abstractions\2.1.1\.nupkg.metadata +microsoft.extensions.fileproviders.composite\2.1.1\.nupkg.metadata +microsoft.extensions.fileproviders.embedded\2.1.1\.nupkg.metadata +microsoft.extensions.fileproviders.physical\2.1.1\.nupkg.metadata +microsoft.extensions.filesystemglobbing\2.1.1\.nupkg.metadata +microsoft.extensions.hosting.abstractions\2.1.1\.nupkg.metadata +microsoft.extensions.hosting\2.1.1\.nupkg.metadata +microsoft.extensions.http\2.1.1\.nupkg.metadata +microsoft.extensions.identity.core\2.1.1\.nupkg.metadata +microsoft.extensions.identity.stores\2.1.1\.nupkg.metadata +microsoft.extensions.localization.abstractions\2.1.1\.nupkg.metadata +microsoft.extensions.localization\2.1.1\.nupkg.metadata +microsoft.extensions.logging.abstractions\2.1.1\.nupkg.metadata +microsoft.extensions.logging.azureappservices\2.1.1\.nupkg.metadata +microsoft.extensions.logging.configuration\2.1.1\.nupkg.metadata +microsoft.extensions.logging.console\2.1.1\.nupkg.metadata +microsoft.extensions.logging.debug\2.1.1\.nupkg.metadata +microsoft.extensions.logging.eventsource\2.1.1\.nupkg.metadata +microsoft.extensions.logging.tracesource\2.1.1\.nupkg.metadata +microsoft.extensions.logging\2.1.1\.nupkg.metadata +microsoft.extensions.objectpool\2.1.1\.nupkg.metadata +microsoft.extensions.options.configurationextensions\2.1.1\.nupkg.metadata +microsoft.extensions.options\2.1.1\.nupkg.metadata +microsoft.extensions.platformabstractions\1.1.0\.nupkg.metadata +microsoft.extensions.primitives\2.1.1\.nupkg.metadata +microsoft.extensions.webencoders\2.1.1\.nupkg.metadata +microsoft.identitymodel.clients.activedirectory\3.14.2\.nupkg.metadata +microsoft.identitymodel.clients.activedirectory\3.14.2\.signature.p7s +microsoft.identitymodel.logging\5.2.0\.nupkg.metadata +microsoft.identitymodel.logging\5.2.0\.signature.p7s +microsoft.identitymodel.protocols.openidconnect\5.2.0\.nupkg.metadata +microsoft.identitymodel.protocols.openidconnect\5.2.0\.signature.p7s +microsoft.identitymodel.protocols.wsfederation\5.2.0\.nupkg.metadata +microsoft.identitymodel.protocols.wsfederation\5.2.0\.signature.p7s +microsoft.identitymodel.protocols\5.2.0\.nupkg.metadata +microsoft.identitymodel.protocols\5.2.0\.signature.p7s +microsoft.identitymodel.tokens.saml\5.2.0\.nupkg.metadata +microsoft.identitymodel.tokens.saml\5.2.0\.signature.p7s +microsoft.identitymodel.tokens\5.2.0\.nupkg.metadata +microsoft.identitymodel.tokens\5.2.0\.signature.p7s +microsoft.identitymodel.xml\5.2.0\.nupkg.metadata +microsoft.identitymodel.xml\5.2.0\.signature.p7s +microsoft.net.http.headers\2.1.1\.nupkg.metadata +microsoft.netcore.app\2.1.0\.nupkg.metadata +microsoft.netcore.dotnetapphost\2.1.0\.nupkg.metadata +microsoft.netcore.dotnethostpolicy\2.1.0\.nupkg.metadata +microsoft.netcore.dotnethostresolver\2.1.0\.nupkg.metadata +microsoft.netcore.platforms\1.0.1\.nupkg.metadata +microsoft.netcore.platforms\1.0.1\.signature.p7s +microsoft.netcore.platforms\1.0.2\.nupkg.metadata +microsoft.netcore.platforms\1.0.2\.signature.p7s +microsoft.netcore.platforms\1.1.0\.nupkg.metadata +microsoft.netcore.platforms\1.1.0\.signature.p7s +microsoft.netcore.platforms\2.0.0\.nupkg.metadata +microsoft.netcore.platforms\2.0.0\.signature.p7s +microsoft.netcore.platforms\2.1.0\.nupkg.metadata +microsoft.netcore.targets\1.0.1\.nupkg.metadata +microsoft.netcore.targets\1.1.0\.nupkg.metadata +microsoft.netcore.targets\2.1.0\.nupkg.metadata +microsoft.rest.clientruntime.azure\3.3.7\.nupkg.metadata +microsoft.rest.clientruntime.azure\3.3.7\.signature.p7s +microsoft.rest.clientruntime\2.3.8\.nupkg.metadata +microsoft.rest.clientruntime\2.3.8\.signature.p7s +microsoft.visualstudio.web.browserlink\2.1.1\.nupkg.metadata +microsoft.visualstudio.web.codegeneration.contracts\2.1.6\.nupkg.metadata +microsoft.visualstudio.web.codegeneration.contracts\2.1.6\.signature.p7s +microsoft.visualstudio.web.codegeneration.contracts\2.1.6\lib\netstandard2.0\Microsoft.VisualStudio.Web.CodeGeneration.Contracts.dll +microsoft.visualstudio.web.codegeneration.contracts\2.1.6\microsoft.visualstudio.web.codegeneration.contracts.2.1.6.nupkg.sha512 +microsoft.visualstudio.web.codegeneration.contracts\2.1.6\microsoft.visualstudio.web.codegeneration.contracts.nuspec +microsoft.visualstudio.web.codegeneration.core\2.1.6\.nupkg.metadata +microsoft.visualstudio.web.codegeneration.core\2.1.6\.signature.p7s +microsoft.visualstudio.web.codegeneration.core\2.1.6\lib\netstandard2.0\Microsoft.VisualStudio.Web.CodeGeneration.Core.dll +microsoft.visualstudio.web.codegeneration.core\2.1.6\microsoft.visualstudio.web.codegeneration.core.2.1.6.nupkg.sha512 +microsoft.visualstudio.web.codegeneration.core\2.1.6\microsoft.visualstudio.web.codegeneration.core.nuspec +microsoft.visualstudio.web.codegeneration.design\2.1.6\.nupkg.metadata +microsoft.visualstudio.web.codegeneration.design\2.1.6\.signature.p7s +microsoft.visualstudio.web.codegeneration.design\2.1.6\lib\net461\dotnet-aspnet-codegenerator-design.exe +microsoft.visualstudio.web.codegeneration.design\2.1.6\lib\netstandard2.0\dotnet-aspnet-codegenerator-design.dll +microsoft.visualstudio.web.codegeneration.design\2.1.6\microsoft.visualstudio.web.codegeneration.design.2.1.6.nupkg.sha512 +microsoft.visualstudio.web.codegeneration.design\2.1.6\microsoft.visualstudio.web.codegeneration.design.nuspec +microsoft.visualstudio.web.codegeneration.design\2.1.6\runtimes\win7-x64\lib\net461\dotnet-aspnet-codegenerator-design.exe +microsoft.visualstudio.web.codegeneration.design\2.1.6\runtimes\win7-x86\lib\net461\dotnet-aspnet-codegenerator-design.exe +microsoft.visualstudio.web.codegeneration.design\2.1.6\runtimes\win-arm\lib\net461\dotnet-aspnet-codegenerator-design.exe +microsoft.visualstudio.web.codegeneration.design\2.1.6\runtimes\win-arm64\lib\net461\dotnet-aspnet-codegenerator-design.exe +microsoft.visualstudio.web.codegeneration.entityframeworkcore\2.1.6\.nupkg.metadata +microsoft.visualstudio.web.codegeneration.entityframeworkcore\2.1.6\.signature.p7s +microsoft.visualstudio.web.codegeneration.entityframeworkcore\2.1.6\lib\netstandard2.0\Microsoft.VisualStudio.Web.CodeGeneration.EntityFrameworkCore.dll +microsoft.visualstudio.web.codegeneration.entityframeworkcore\2.1.6\microsoft.visualstudio.web.codegeneration.entityframeworkcore.2.1.6.nupkg.sha512 +microsoft.visualstudio.web.codegeneration.entityframeworkcore\2.1.6\microsoft.visualstudio.web.codegeneration.entityframeworkcore.nuspec +microsoft.visualstudio.web.codegeneration.entityframeworkcore\2.1.6\Templates\DbContext\NewLocalDbContext.cshtml +microsoft.visualstudio.web.codegeneration.templating\2.1.6\.nupkg.metadata +microsoft.visualstudio.web.codegeneration.templating\2.1.6\.signature.p7s +microsoft.visualstudio.web.codegeneration.templating\2.1.6\lib\netstandard2.0\Microsoft.VisualStudio.Web.CodeGeneration.Templating.dll +microsoft.visualstudio.web.codegeneration.templating\2.1.6\microsoft.visualstudio.web.codegeneration.templating.2.1.6.nupkg.sha512 +microsoft.visualstudio.web.codegeneration.templating\2.1.6\microsoft.visualstudio.web.codegeneration.templating.nuspec +microsoft.visualstudio.web.codegeneration.utils\2.1.6\.nupkg.metadata +microsoft.visualstudio.web.codegeneration.utils\2.1.6\.signature.p7s +microsoft.visualstudio.web.codegeneration.utils\2.1.6\lib\netstandard2.0\Microsoft.VisualStudio.Web.CodeGeneration.Utils.dll +microsoft.visualstudio.web.codegeneration.utils\2.1.6\microsoft.visualstudio.web.codegeneration.utils.2.1.6.nupkg.sha512 +microsoft.visualstudio.web.codegeneration.utils\2.1.6\microsoft.visualstudio.web.codegeneration.utils.nuspec +microsoft.visualstudio.web.codegeneration\2.1.6\.nupkg.metadata +microsoft.visualstudio.web.codegeneration\2.1.6\.signature.p7s +microsoft.visualstudio.web.codegeneration\2.1.6\lib\netstandard2.0\Microsoft.VisualStudio.Web.CodeGeneration.dll +microsoft.visualstudio.web.codegeneration\2.1.6\microsoft.visualstudio.web.codegeneration.2.1.6.nupkg.sha512 +microsoft.visualstudio.web.codegeneration\2.1.6\microsoft.visualstudio.web.codegeneration.nuspec +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\.nupkg.metadata +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\.signature.p7s +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Generators\ParameterDefinitions\area.json +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Generators\ParameterDefinitions\controller.json +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Generators\ParameterDefinitions\identity.json +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Generators\ParameterDefinitions\razorpage.json +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Generators\ParameterDefinitions\view.json +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\lib\netstandard2.0\identitygeneratorfilesconfig.json +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\lib\netstandard2.0\Microsoft.VisualStudio.Web.CodeGenerators.Mvc.dll +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\microsoft.visualstudio.web.codegenerators.mvc.2.1.6.nupkg.sha512 +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\microsoft.visualstudio.web.codegenerators.mvc.nuspec +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\ControllerGenerator\ApiControllerWithActions.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\ControllerGenerator\ApiControllerWithContext.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\ControllerGenerator\ApiEmptyController.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\ControllerGenerator\ControllerWithActions.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\ControllerGenerator\EmptyController.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\ControllerGenerator\MvcControllerWithContext.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\_LoginPartial.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Data\ApplicationDbContext.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Data\ApplicationUser.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\IdentityHostingStartup.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\_Layout.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\_ValidationScriptsPartial.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\_ViewImports.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\_ViewStart.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account._ViewImports.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.AccessDenied.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.AccessDenied.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.ConfirmEmail.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.ConfirmEmail.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.ExternalLogin.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.ExternalLogin.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.ForgotPassword.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.ForgotPassword.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.ForgotPasswordConfirmation.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.ForgotPasswordConfirmation.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.Lockout.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.Lockout.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.Login.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.Login.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.LoginWith2fa.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.LoginWith2fa.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.LoginWithRecoveryCode.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.LoginWithRecoveryCode.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.Logout.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.Logout.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.Register.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.Register.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.ResetPassword.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.ResetPassword.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.ResetPasswordConfirmation.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Account.ResetPasswordConfirmation.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage._Layout.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage._ManageNav.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage._StatusMessage.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage._ViewImports.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.ChangePassword.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.ChangePassword.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.DeletePersonalData.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.DeletePersonalData.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.Disable2fa.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.Disable2fa.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.DownloadPersonalData.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.DownloadPersonalData.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.EnableAuthenticator.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.EnableAuthenticator.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.ExternalLogins.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.ExternalLogins.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.GenerateRecoveryCodes.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.GenerateRecoveryCodes.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.Index.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.Index.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.ManageNavPages.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.PersonalData.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.PersonalData.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.ResetAuthenticator.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.ResetAuthenticator.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.SetPassword.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.SetPassword.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.ShowRecoveryCodes.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.ShowRecoveryCodes.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.TwoFactorAuthentication.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Account\Manage\Account.Manage.TwoFactorAuthentication.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Error.cs.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\Pages\Error.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\ScaffoldingReadme.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\SupportPages._CookieConsentPartial.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\SupportPages._ViewImports.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\SupportPages._ViewStart.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\css\site.css +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\css\site.min.css +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\favicon.ico +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\images\banner1.svg +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\images\banner2.svg +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\images\banner3.svg +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\js\site.js +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\js\site.min.js +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\bootstrap\.bower.json +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\bootstrap\dist\css\bootstrap.css +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\bootstrap\dist\css\bootstrap.css.map +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\bootstrap\dist\css\bootstrap.min.css +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\bootstrap\dist\css\bootstrap.min.css.map +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\bootstrap\dist\css\bootstrap-theme.css +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\bootstrap\dist\css\bootstrap-theme.css.map +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\bootstrap\dist\css\bootstrap-theme.min.css +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\bootstrap\dist\css\bootstrap-theme.min.css.map +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\bootstrap\dist\fonts\glyphicons-halflings-regular.eot +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\bootstrap\dist\fonts\glyphicons-halflings-regular.svg +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\bootstrap\dist\fonts\glyphicons-halflings-regular.ttf +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\bootstrap\dist\fonts\glyphicons-halflings-regular.woff +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\bootstrap\dist\fonts\glyphicons-halflings-regular.woff2 +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\bootstrap\dist\js\bootstrap.js +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\bootstrap\dist\js\bootstrap.min.js +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\bootstrap\dist\js\npm.js +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\bootstrap\LICENSE +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\jquery\.bower.json +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\jquery\dist\jquery.js +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\jquery\dist\jquery.min.js +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\jquery\dist\jquery.min.map +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\jquery\LICENSE.txt +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\jquery-validation\.bower.json +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\jquery-validation\dist\additional-methods.js +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\jquery-validation\dist\additional-methods.min.js +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\jquery-validation\dist\jquery.validate.js +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\jquery-validation\dist\jquery.validate.min.js +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\jquery-validation\LICENSE.md +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\jquery-validation-unobtrusive\.bower.json +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\jquery-validation-unobtrusive\jquery.validate.unobtrusive.js +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\jquery-validation-unobtrusive\jquery.validate.unobtrusive.min.js +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Identity\wwwroot\lib\jquery-validation-unobtrusive\LICENSE.txt +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\MvcLayout\_Layout.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\MvcLayout\Error.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\RazorPageGenerator\_ValidationScriptsPartial.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\RazorPageGenerator\Create.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\RazorPageGenerator\CreatePageModel.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\RazorPageGenerator\Delete.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\RazorPageGenerator\DeletePageModel.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\RazorPageGenerator\Details.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\RazorPageGenerator\DetailsPageModel.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\RazorPageGenerator\Edit.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\RazorPageGenerator\EditPageModel.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\RazorPageGenerator\Empty.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\RazorPageGenerator\EmptyPageModel.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\RazorPageGenerator\List.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\RazorPageGenerator\ListPageModel.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Startup\ReadMe.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\Startup\Startup.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\ViewGenerator\_ValidationScriptsPartial.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\ViewGenerator\Create.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\ViewGenerator\Delete.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\ViewGenerator\Details.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\ViewGenerator\Edit.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\ViewGenerator\Empty.cshtml +microsoft.visualstudio.web.codegenerators.mvc\2.1.6\Templates\ViewGenerator\List.cshtml +microsoft.win32.primitives\4.0.1\.nupkg.metadata +microsoft.win32.primitives\4.3.0\.nupkg.metadata +microsoft.win32.registry\4.3.0\.nupkg.metadata +microsoft.win32.registry\4.5.0\.nupkg.metadata +netstandard.library\1.6.0\.nupkg.metadata +netstandard.library\1.6.1\.nupkg.metadata +netstandard.library\2.0.3\.nupkg.metadata +newtonsoft.json.bson\1.0.1\.nupkg.metadata +newtonsoft.json.bson\1.0.1\.signature.p7s +newtonsoft.json\10.0.1\.nupkg.metadata +newtonsoft.json\10.0.1\.signature.p7s +newtonsoft.json\11.0.2\.nupkg.metadata +newtonsoft.json\11.0.2\.signature.p7s +newtonsoft.json\9.0.1\.nupkg.metadata +nuget.frameworks\4.7.0\.nupkg.metadata +remotion.linq\2.2.0\.nupkg.metadata +remotion.linq\2.2.0\.signature.p7s +runtime.debian.8-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.fedora.23-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.fedora.24-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.native.system.data.sqlclient.sni\4.4.0\.nupkg.metadata +runtime.native.system.io.compression\4.1.0\.nupkg.metadata +runtime.native.system.io.compression\4.3.0\.nupkg.metadata +runtime.native.system.net.http\4.0.1\.nupkg.metadata +runtime.native.system.net.http\4.3.0\.nupkg.metadata +runtime.native.system.net.security\4.3.0\.nupkg.metadata +runtime.native.system.security.cryptography.apple\4.3.0\.nupkg.metadata +runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.native.system.security.cryptography\4.0.0\.nupkg.metadata +runtime.native.system\4.0.0\.nupkg.metadata +runtime.native.system\4.3.0\.nupkg.metadata +runtime.opensuse.13.2-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.opensuse.42.1-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.osx.10.10-x64.runtime.native.system.security.cryptography.apple\4.3.0\.nupkg.metadata +runtime.osx.10.10-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.rhel.7-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.ubuntu.14.04-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.ubuntu.16.04-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.ubuntu.16.10-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.win-arm64.runtime.native.system.data.sqlclient.sni\4.4.0\.nupkg.metadata +runtime.win-x64.runtime.native.system.data.sqlclient.sni\4.4.0\.nupkg.metadata +runtime.win-x86.runtime.native.system.data.sqlclient.sni\4.4.0\.nupkg.metadata +sqlitepclraw.bundle_green\1.1.11\.nupkg.metadata +sqlitepclraw.bundle_green\1.1.11\.signature.p7s +sqlitepclraw.core\1.1.11\.nupkg.metadata +sqlitepclraw.core\1.1.11\.signature.p7s +sqlitepclraw.lib.e_sqlite3.linux\1.1.11\.nupkg.metadata +sqlitepclraw.lib.e_sqlite3.linux\1.1.11\.signature.p7s +sqlitepclraw.lib.e_sqlite3.osx\1.1.11\.nupkg.metadata +sqlitepclraw.lib.e_sqlite3.osx\1.1.11\.signature.p7s +sqlitepclraw.lib.e_sqlite3.v110_xp\1.1.11\.nupkg.metadata +sqlitepclraw.lib.e_sqlite3.v110_xp\1.1.11\.signature.p7s +sqlitepclraw.provider.e_sqlite3.netstandard11\1.1.11\.nupkg.metadata +sqlitepclraw.provider.e_sqlite3.netstandard11\1.1.11\.signature.p7s +stackexchange.redis.strongname\1.2.4\.nupkg.metadata +stackexchange.redis.strongname\1.2.4\.signature.p7s +system.appcontext\4.1.0\.nupkg.metadata +system.appcontext\4.3.0\.nupkg.metadata +system.buffers\4.0.0\.nupkg.metadata +system.buffers\4.3.0\.nupkg.metadata +system.buffers\4.5.0\.nupkg.metadata +system.collections.concurrent\4.0.12\.nupkg.metadata +system.collections.concurrent\4.3.0\.nupkg.metadata +system.collections.immutable\1.3.0\.nupkg.metadata +system.collections.immutable\1.3.1\.nupkg.metadata +system.collections.immutable\1.5.0\.nupkg.metadata +system.collections.nongeneric\4.3.0\.nupkg.metadata +system.collections.specialized\4.3.0\.nupkg.metadata +system.collections\4.0.11\.nupkg.metadata +system.collections\4.3.0\.nupkg.metadata +system.componentmodel.annotations\4.5.0\.nupkg.metadata +system.componentmodel.primitives\4.3.0\.nupkg.metadata +system.componentmodel.typeconverter\4.3.0\.nupkg.metadata +system.componentmodel\4.3.0\.nupkg.metadata +system.composition.attributedmodel\1.0.31\.nupkg.metadata +system.composition.convention\1.0.31\.nupkg.metadata +system.composition.hosting\1.0.31\.nupkg.metadata +system.composition.runtime\1.0.31\.nupkg.metadata +system.composition.typedparts\1.0.31\.nupkg.metadata +system.composition\1.0.31\.nupkg.metadata +system.console\4.0.0\.nupkg.metadata +system.console\4.3.0\.nupkg.metadata +system.data.sqlclient\4.5.1\.nupkg.metadata +system.diagnostics.contracts\4.3.0\.nupkg.metadata +system.diagnostics.debug\4.0.11\.nupkg.metadata +system.diagnostics.debug\4.3.0\.nupkg.metadata +system.diagnostics.diagnosticsource\4.0.0\.nupkg.metadata +system.diagnostics.diagnosticsource\4.3.0\.nupkg.metadata +system.diagnostics.diagnosticsource\4.4.0\.nupkg.metadata +system.diagnostics.diagnosticsource\4.4.0\.signature.p7s +system.diagnostics.diagnosticsource\4.5.0\.nupkg.metadata +system.diagnostics.fileversioninfo\4.3.0\.nupkg.metadata +system.diagnostics.process\4.3.0\.nupkg.metadata +system.diagnostics.stacktrace\4.3.0\.nupkg.metadata +system.diagnostics.tools\4.0.1\.nupkg.metadata +system.diagnostics.tools\4.3.0\.nupkg.metadata +system.diagnostics.tracing\4.1.0\.nupkg.metadata +system.diagnostics.tracing\4.3.0\.nupkg.metadata +system.dynamic.runtime\4.0.11\.nupkg.metadata +system.dynamic.runtime\4.3.0\.nupkg.metadata +system.globalization.calendars\4.0.1\.nupkg.metadata +system.globalization.calendars\4.3.0\.nupkg.metadata +system.globalization.extensions\4.0.1\.nupkg.metadata +system.globalization.extensions\4.3.0\.nupkg.metadata +system.globalization\4.0.11\.nupkg.metadata +system.globalization\4.3.0\.nupkg.metadata +system.identitymodel.tokens.jwt\5.2.0\.nupkg.metadata +system.identitymodel.tokens.jwt\5.2.0\.signature.p7s +system.interactive.async\3.1.1\.nupkg.metadata +system.interactive.async\3.1.1\.signature.p7s +system.io.compression.zipfile\4.0.1\.nupkg.metadata +system.io.compression.zipfile\4.3.0\.nupkg.metadata +system.io.compression\4.1.0\.nupkg.metadata +system.io.compression\4.3.0\.nupkg.metadata +system.io.filesystem.primitives\4.0.1\.nupkg.metadata +system.io.filesystem.primitives\4.3.0\.nupkg.metadata +system.io.filesystem\4.0.1\.nupkg.metadata +system.io.filesystem\4.3.0\.nupkg.metadata +system.io.pipelines\4.5.0\.nupkg.metadata +system.io\4.1.0\.nupkg.metadata +system.io\4.3.0\.nupkg.metadata +system.linq.expressions\4.1.0\.nupkg.metadata +system.linq.expressions\4.3.0\.nupkg.metadata +system.linq.parallel\4.3.0\.nupkg.metadata +system.linq.queryable\4.0.1\.nupkg.metadata +system.linq\4.1.0\.nupkg.metadata +system.linq\4.3.0\.nupkg.metadata +system.memory\4.5.1\.nupkg.metadata +system.net.http\4.1.0\.nupkg.metadata +system.net.http\4.1.0\.signature.p7s +system.net.http\4.3.0\.nupkg.metadata +system.net.http\4.3.0\.signature.p7s +system.net.nameresolution\4.3.0\.nupkg.metadata +system.net.primitives\4.0.11\.nupkg.metadata +system.net.primitives\4.3.0\.nupkg.metadata +system.net.security\4.3.0\.nupkg.metadata +system.net.sockets\4.1.0\.nupkg.metadata +system.net.sockets\4.3.0\.nupkg.metadata +system.net.websockets.websocketprotocol\4.5.1\.nupkg.metadata +system.numerics.vectors\4.5.0\.nupkg.metadata +system.objectmodel\4.0.12\.nupkg.metadata +system.objectmodel\4.3.0\.nupkg.metadata +system.private.datacontractserialization\4.1.1\.nupkg.metadata +system.private.datacontractserialization\4.3.0\.nupkg.metadata +system.reflection.emit.ilgeneration\4.0.1\.nupkg.metadata +system.reflection.emit.ilgeneration\4.3.0\.nupkg.metadata +system.reflection.emit.lightweight\4.0.1\.nupkg.metadata +system.reflection.emit.lightweight\4.3.0\.nupkg.metadata +system.reflection.emit\4.0.1\.nupkg.metadata +system.reflection.emit\4.3.0\.nupkg.metadata +system.reflection.extensions\4.0.1\.nupkg.metadata +system.reflection.extensions\4.3.0\.nupkg.metadata +system.reflection.metadata\1.4.1\.nupkg.metadata +system.reflection.metadata\1.4.2\.nupkg.metadata +system.reflection.metadata\1.6.0\.nupkg.metadata +system.reflection.primitives\4.0.1\.nupkg.metadata +system.reflection.primitives\4.3.0\.nupkg.metadata +system.reflection.typeextensions\4.1.0\.nupkg.metadata +system.reflection.typeextensions\4.3.0\.nupkg.metadata +system.reflection\4.1.0\.nupkg.metadata +system.reflection\4.3.0\.nupkg.metadata +system.resources.resourcemanager\4.0.1\.nupkg.metadata +system.resources.resourcemanager\4.3.0\.nupkg.metadata +system.runtime.compilerservices.unsafe\4.5.0\.nupkg.metadata +system.runtime.compilerservices.unsafe\4.5.1\.nupkg.metadata +system.runtime.extensions\4.1.0\.nupkg.metadata +system.runtime.extensions\4.3.0\.nupkg.metadata +system.runtime.handles\4.0.1\.nupkg.metadata +system.runtime.handles\4.3.0\.nupkg.metadata +system.runtime.interopservices.runtimeinformation\4.0.0\.nupkg.metadata +system.runtime.interopservices.runtimeinformation\4.3.0\.nupkg.metadata +system.runtime.interopservices\4.1.0\.nupkg.metadata +system.runtime.interopservices\4.3.0\.nupkg.metadata +system.runtime.numerics\4.0.1\.nupkg.metadata +system.runtime.numerics\4.3.0\.nupkg.metadata +system.runtime.serialization.formatters\4.3.0\.nupkg.metadata +system.runtime.serialization.json\4.0.2\.nupkg.metadata +system.runtime.serialization.primitives\4.1.1\.nupkg.metadata +system.runtime.serialization.primitives\4.3.0\.nupkg.metadata +system.runtime.serialization.xml\4.3.0\.nupkg.metadata +system.runtime\4.1.0\.nupkg.metadata +system.runtime\4.3.0\.nupkg.metadata +system.security.accesscontrol\4.5.0\.nupkg.metadata +system.security.claims\4.3.0\.nupkg.metadata +system.security.cryptography.algorithms\4.2.0\.nupkg.metadata +system.security.cryptography.algorithms\4.3.0\.nupkg.metadata +system.security.cryptography.cng\4.2.0\.nupkg.metadata +system.security.cryptography.cng\4.3.0\.nupkg.metadata +system.security.cryptography.cng\4.5.0\.nupkg.metadata +system.security.cryptography.csp\4.0.0\.nupkg.metadata +system.security.cryptography.csp\4.3.0\.nupkg.metadata +system.security.cryptography.encoding\4.0.0\.nupkg.metadata +system.security.cryptography.encoding\4.3.0\.nupkg.metadata +system.security.cryptography.openssl\4.0.0\.nupkg.metadata +system.security.cryptography.openssl\4.3.0\.nupkg.metadata +system.security.cryptography.pkcs\4.5.0\.nupkg.metadata +system.security.cryptography.primitives\4.0.0\.nupkg.metadata +system.security.cryptography.primitives\4.3.0\.nupkg.metadata +system.security.cryptography.x509certificates\4.1.0\.nupkg.metadata +system.security.cryptography.x509certificates\4.3.0\.nupkg.metadata +system.security.cryptography.xml\4.5.0\.nupkg.metadata +system.security.permissions\4.5.0\.nupkg.metadata +system.security.principal.windows\4.3.0\.nupkg.metadata +system.security.principal.windows\4.5.0\.nupkg.metadata +system.security.principal\4.3.0\.nupkg.metadata +system.spatial\5.8.2\.nupkg.metadata +system.text.encoding.codepages\4.3.0\.nupkg.metadata +system.text.encoding.codepages\4.5.0\.nupkg.metadata +system.text.encoding.extensions\4.0.11\.nupkg.metadata +system.text.encoding.extensions\4.3.0\.nupkg.metadata +system.text.encoding\4.0.11\.nupkg.metadata +system.text.encoding\4.3.0\.nupkg.metadata +system.text.encodings.web\4.3.1\.nupkg.metadata +system.text.encodings.web\4.3.1\.signature.p7s +system.text.encodings.web\4.5.0\.nupkg.metadata +system.text.regularexpressions\4.1.0\.nupkg.metadata +system.text.regularexpressions\4.3.0\.nupkg.metadata +system.threading.channels\4.5.0\.nupkg.metadata +system.threading.tasks.extensions\4.0.0\.nupkg.metadata +system.threading.tasks.extensions\4.3.0\.nupkg.metadata +system.threading.tasks.extensions\4.5.1\.nupkg.metadata +system.threading.tasks.parallel\4.3.0\.nupkg.metadata +system.threading.tasks\4.0.11\.nupkg.metadata +system.threading.tasks\4.3.0\.nupkg.metadata +system.threading.thread\4.3.0\.nupkg.metadata +system.threading.threadpool\4.3.0\.nupkg.metadata +system.threading.timer\4.0.1\.nupkg.metadata +system.threading.timer\4.3.0\.nupkg.metadata +system.threading\4.0.11\.nupkg.metadata +system.threading\4.3.0\.nupkg.metadata +system.valuetuple\4.3.0\.nupkg.metadata +system.valuetuple\4.5.0\.nupkg.metadata +system.xml.readerwriter\4.0.11\.nupkg.metadata +system.xml.readerwriter\4.3.0\.nupkg.metadata +system.xml.xdocument\4.0.11\.nupkg.metadata +system.xml.xdocument\4.3.0\.nupkg.metadata +system.xml.xmldocument\4.0.1\.nupkg.metadata +system.xml.xmldocument\4.3.0\.nupkg.metadata +system.xml.xmlserializer\4.0.11\.nupkg.metadata +system.xml.xmlserializer\4.3.0\.nupkg.metadata +system.xml.xpath.xdocument\4.3.0\.nupkg.metadata +system.xml.xpath\4.3.0\.nupkg.metadata +windowsazure.storage\8.1.4\.nupkg.metadata +windowsazure.storage\8.1.4\.signature.p7s diff --git a/src/PackageArchive/Archive.CiServer.Patch/ArchiveBaseline.2.2.0.txt b/src/PackageArchive/Archive.CiServer.Patch/ArchiveBaseline.2.2.0.txt new file mode 100644 index 0000000000..7579756141 --- /dev/null +++ b/src/PackageArchive/Archive.CiServer.Patch/ArchiveBaseline.2.2.0.txt @@ -0,0 +1,1629 @@ +libuv\1.10.0\.nupkg.metadata +libuv\1.10.0\.signature.p7s +messagepack\1.7.3.4\.nupkg.metadata +messagepack\1.7.3.4\.signature.p7s +microsoft.applicationinsights.aspnetcore\2.1.1\.nupkg.metadata +microsoft.applicationinsights.aspnetcore\2.1.1\.signature.p7s +microsoft.applicationinsights.dependencycollector\2.4.1\.nupkg.metadata +microsoft.applicationinsights.dependencycollector\2.4.1\.signature.p7s +microsoft.applicationinsights\2.4.0\.nupkg.metadata +microsoft.applicationinsights\2.4.0\.signature.p7s +microsoft.aspnet.webapi.client\5.2.6\.nupkg.metadata +microsoft.aspnetcore.all\2.2.0\.nupkg.metadata +microsoft.aspnetcore.all\2.2.0\.signature.p7s +microsoft.aspnetcore.all\2.2.0\build\netcoreapp2.2\Microsoft.AspNetCore.All.props +microsoft.aspnetcore.all\2.2.0\build\netcoreapp2.2\Microsoft.AspNetCore.All.targets +microsoft.aspnetcore.all\2.2.0\lib\netcoreapp2.2\_._ +microsoft.aspnetcore.all\2.2.0\microsoft.aspnetcore.all.2.2.0.nupkg.sha512 +microsoft.aspnetcore.all\2.2.0\microsoft.aspnetcore.all.nuspec +microsoft.aspnetcore.antiforgery\2.2.0\.nupkg.metadata +microsoft.aspnetcore.antiforgery\2.2.0\.signature.p7s +microsoft.aspnetcore.antiforgery\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Antiforgery.dll +microsoft.aspnetcore.antiforgery\2.2.0\microsoft.aspnetcore.antiforgery.2.2.0.nupkg.sha512 +microsoft.aspnetcore.antiforgery\2.2.0\microsoft.aspnetcore.antiforgery.nuspec +microsoft.aspnetcore.app\2.2.0\.nupkg.metadata +microsoft.aspnetcore.app\2.2.0\.signature.p7s +microsoft.aspnetcore.app\2.2.0\build\netcoreapp2.2\Microsoft.AspNetCore.App.props +microsoft.aspnetcore.app\2.2.0\build\netcoreapp2.2\Microsoft.AspNetCore.App.targets +microsoft.aspnetcore.app\2.2.0\lib\netcoreapp2.2\_._ +microsoft.aspnetcore.app\2.2.0\microsoft.aspnetcore.app.2.2.0.nupkg.sha512 +microsoft.aspnetcore.app\2.2.0\microsoft.aspnetcore.app.nuspec +microsoft.aspnetcore.applicationinsights.hostingstartup\2.2.0\.nupkg.metadata +microsoft.aspnetcore.applicationinsights.hostingstartup\2.2.0\.signature.p7s +microsoft.aspnetcore.applicationinsights.hostingstartup\2.2.0\lib\net461\Microsoft.AspNetCore.ApplicationInsights.HostingStartup.dll +microsoft.aspnetcore.applicationinsights.hostingstartup\2.2.0\lib\netcoreapp2.0\Microsoft.AspNetCore.ApplicationInsights.HostingStartup.dll +microsoft.aspnetcore.applicationinsights.hostingstartup\2.2.0\lib\netcoreapp2.1\Microsoft.AspNetCore.ApplicationInsights.HostingStartup.dll +microsoft.aspnetcore.applicationinsights.hostingstartup\2.2.0\microsoft.aspnetcore.applicationinsights.hostingstartup.2.2.0.nupkg.sha512 +microsoft.aspnetcore.applicationinsights.hostingstartup\2.2.0\microsoft.aspnetcore.applicationinsights.hostingstartup.nuspec +microsoft.aspnetcore.authentication.abstractions\2.2.0\.nupkg.metadata +microsoft.aspnetcore.authentication.abstractions\2.2.0\.signature.p7s +microsoft.aspnetcore.authentication.abstractions\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Authentication.Abstractions.dll +microsoft.aspnetcore.authentication.abstractions\2.2.0\microsoft.aspnetcore.authentication.abstractions.2.2.0.nupkg.sha512 +microsoft.aspnetcore.authentication.abstractions\2.2.0\microsoft.aspnetcore.authentication.abstractions.nuspec +microsoft.aspnetcore.authentication.azuread.ui\2.2.0\.nupkg.metadata +microsoft.aspnetcore.authentication.azuread.ui\2.2.0\.signature.p7s +microsoft.aspnetcore.authentication.azuread.ui\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Authentication.AzureAD.UI.dll +microsoft.aspnetcore.authentication.azuread.ui\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Authentication.AzureAD.UI.Views.dll +microsoft.aspnetcore.authentication.azuread.ui\2.2.0\microsoft.aspnetcore.authentication.azuread.ui.2.2.0.nupkg.sha512 +microsoft.aspnetcore.authentication.azuread.ui\2.2.0\microsoft.aspnetcore.authentication.azuread.ui.nuspec +microsoft.aspnetcore.authentication.azureadb2c.ui\2.2.0\.nupkg.metadata +microsoft.aspnetcore.authentication.azureadb2c.ui\2.2.0\.signature.p7s +microsoft.aspnetcore.authentication.azureadb2c.ui\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Authentication.AzureADB2C.UI.dll +microsoft.aspnetcore.authentication.azureadb2c.ui\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Authentication.AzureADB2C.UI.Views.dll +microsoft.aspnetcore.authentication.azureadb2c.ui\2.2.0\microsoft.aspnetcore.authentication.azureadb2c.ui.2.2.0.nupkg.sha512 +microsoft.aspnetcore.authentication.azureadb2c.ui\2.2.0\microsoft.aspnetcore.authentication.azureadb2c.ui.nuspec +microsoft.aspnetcore.authentication.cookies\2.2.0\.nupkg.metadata +microsoft.aspnetcore.authentication.cookies\2.2.0\.signature.p7s +microsoft.aspnetcore.authentication.cookies\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Authentication.Cookies.dll +microsoft.aspnetcore.authentication.cookies\2.2.0\microsoft.aspnetcore.authentication.cookies.2.2.0.nupkg.sha512 +microsoft.aspnetcore.authentication.cookies\2.2.0\microsoft.aspnetcore.authentication.cookies.nuspec +microsoft.aspnetcore.authentication.core\2.2.0\.nupkg.metadata +microsoft.aspnetcore.authentication.core\2.2.0\.signature.p7s +microsoft.aspnetcore.authentication.core\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Authentication.Core.dll +microsoft.aspnetcore.authentication.core\2.2.0\microsoft.aspnetcore.authentication.core.2.2.0.nupkg.sha512 +microsoft.aspnetcore.authentication.core\2.2.0\microsoft.aspnetcore.authentication.core.nuspec +microsoft.aspnetcore.authentication.facebook\2.2.0\.nupkg.metadata +microsoft.aspnetcore.authentication.facebook\2.2.0\.signature.p7s +microsoft.aspnetcore.authentication.facebook\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Authentication.Facebook.dll +microsoft.aspnetcore.authentication.facebook\2.2.0\microsoft.aspnetcore.authentication.facebook.2.2.0.nupkg.sha512 +microsoft.aspnetcore.authentication.facebook\2.2.0\microsoft.aspnetcore.authentication.facebook.nuspec +microsoft.aspnetcore.authentication.google\2.2.0\.nupkg.metadata +microsoft.aspnetcore.authentication.google\2.2.0\.signature.p7s +microsoft.aspnetcore.authentication.google\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Authentication.Google.dll +microsoft.aspnetcore.authentication.google\2.2.0\microsoft.aspnetcore.authentication.google.2.2.0.nupkg.sha512 +microsoft.aspnetcore.authentication.google\2.2.0\microsoft.aspnetcore.authentication.google.nuspec +microsoft.aspnetcore.authentication.jwtbearer\2.2.0\.nupkg.metadata +microsoft.aspnetcore.authentication.jwtbearer\2.2.0\.signature.p7s +microsoft.aspnetcore.authentication.jwtbearer\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Authentication.JwtBearer.dll +microsoft.aspnetcore.authentication.jwtbearer\2.2.0\microsoft.aspnetcore.authentication.jwtbearer.2.2.0.nupkg.sha512 +microsoft.aspnetcore.authentication.jwtbearer\2.2.0\microsoft.aspnetcore.authentication.jwtbearer.nuspec +microsoft.aspnetcore.authentication.microsoftaccount\2.2.0\.nupkg.metadata +microsoft.aspnetcore.authentication.microsoftaccount\2.2.0\.signature.p7s +microsoft.aspnetcore.authentication.microsoftaccount\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Authentication.MicrosoftAccount.dll +microsoft.aspnetcore.authentication.microsoftaccount\2.2.0\microsoft.aspnetcore.authentication.microsoftaccount.2.2.0.nupkg.sha512 +microsoft.aspnetcore.authentication.microsoftaccount\2.2.0\microsoft.aspnetcore.authentication.microsoftaccount.nuspec +microsoft.aspnetcore.authentication.oauth\2.2.0\.nupkg.metadata +microsoft.aspnetcore.authentication.oauth\2.2.0\.signature.p7s +microsoft.aspnetcore.authentication.oauth\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Authentication.OAuth.dll +microsoft.aspnetcore.authentication.oauth\2.2.0\microsoft.aspnetcore.authentication.oauth.2.2.0.nupkg.sha512 +microsoft.aspnetcore.authentication.oauth\2.2.0\microsoft.aspnetcore.authentication.oauth.nuspec +microsoft.aspnetcore.authentication.openidconnect\2.2.0\.nupkg.metadata +microsoft.aspnetcore.authentication.openidconnect\2.2.0\.signature.p7s +microsoft.aspnetcore.authentication.openidconnect\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Authentication.OpenIdConnect.dll +microsoft.aspnetcore.authentication.openidconnect\2.2.0\microsoft.aspnetcore.authentication.openidconnect.2.2.0.nupkg.sha512 +microsoft.aspnetcore.authentication.openidconnect\2.2.0\microsoft.aspnetcore.authentication.openidconnect.nuspec +microsoft.aspnetcore.authentication.twitter\2.2.0\.nupkg.metadata +microsoft.aspnetcore.authentication.twitter\2.2.0\.signature.p7s +microsoft.aspnetcore.authentication.twitter\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Authentication.Twitter.dll +microsoft.aspnetcore.authentication.twitter\2.2.0\microsoft.aspnetcore.authentication.twitter.2.2.0.nupkg.sha512 +microsoft.aspnetcore.authentication.twitter\2.2.0\microsoft.aspnetcore.authentication.twitter.nuspec +microsoft.aspnetcore.authentication.wsfederation\2.2.0\.nupkg.metadata +microsoft.aspnetcore.authentication.wsfederation\2.2.0\.signature.p7s +microsoft.aspnetcore.authentication.wsfederation\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Authentication.WsFederation.dll +microsoft.aspnetcore.authentication.wsfederation\2.2.0\microsoft.aspnetcore.authentication.wsfederation.2.2.0.nupkg.sha512 +microsoft.aspnetcore.authentication.wsfederation\2.2.0\microsoft.aspnetcore.authentication.wsfederation.nuspec +microsoft.aspnetcore.authentication\2.2.0\.nupkg.metadata +microsoft.aspnetcore.authentication\2.2.0\.signature.p7s +microsoft.aspnetcore.authentication\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Authentication.dll +microsoft.aspnetcore.authentication\2.2.0\microsoft.aspnetcore.authentication.2.2.0.nupkg.sha512 +microsoft.aspnetcore.authentication\2.2.0\microsoft.aspnetcore.authentication.nuspec +microsoft.aspnetcore.authorization.policy\2.2.0\.nupkg.metadata +microsoft.aspnetcore.authorization.policy\2.2.0\.signature.p7s +microsoft.aspnetcore.authorization.policy\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Authorization.Policy.dll +microsoft.aspnetcore.authorization.policy\2.2.0\microsoft.aspnetcore.authorization.policy.2.2.0.nupkg.sha512 +microsoft.aspnetcore.authorization.policy\2.2.0\microsoft.aspnetcore.authorization.policy.nuspec +microsoft.aspnetcore.authorization\2.2.0\.nupkg.metadata +microsoft.aspnetcore.authorization\2.2.0\.signature.p7s +microsoft.aspnetcore.authorization\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Authorization.dll +microsoft.aspnetcore.authorization\2.2.0\microsoft.aspnetcore.authorization.2.2.0.nupkg.sha512 +microsoft.aspnetcore.authorization\2.2.0\microsoft.aspnetcore.authorization.nuspec +microsoft.aspnetcore.azureappservices.hostingstartup\2.2.0\.nupkg.metadata +microsoft.aspnetcore.azureappservices.hostingstartup\2.2.0\.signature.p7s +microsoft.aspnetcore.azureappservices.hostingstartup\2.2.0\lib\net461\Microsoft.AspNetCore.AzureAppServices.HostingStartup.dll +microsoft.aspnetcore.azureappservices.hostingstartup\2.2.0\lib\netcoreapp2.0\Microsoft.AspNetCore.AzureAppServices.HostingStartup.dll +microsoft.aspnetcore.azureappservices.hostingstartup\2.2.0\lib\netcoreapp2.1\Microsoft.AspNetCore.AzureAppServices.HostingStartup.dll +microsoft.aspnetcore.azureappservices.hostingstartup\2.2.0\microsoft.aspnetcore.azureappservices.hostingstartup.2.2.0.nupkg.sha512 +microsoft.aspnetcore.azureappservices.hostingstartup\2.2.0\microsoft.aspnetcore.azureappservices.hostingstartup.nuspec +microsoft.aspnetcore.azureappservicesintegration\2.2.0\.nupkg.metadata +microsoft.aspnetcore.azureappservicesintegration\2.2.0\.signature.p7s +microsoft.aspnetcore.azureappservicesintegration\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.AzureAppServicesIntegration.dll +microsoft.aspnetcore.azureappservicesintegration\2.2.0\microsoft.aspnetcore.azureappservicesintegration.2.2.0.nupkg.sha512 +microsoft.aspnetcore.azureappservicesintegration\2.2.0\microsoft.aspnetcore.azureappservicesintegration.nuspec +microsoft.aspnetcore.connections.abstractions\2.2.0\.nupkg.metadata +microsoft.aspnetcore.connections.abstractions\2.2.0\.signature.p7s +microsoft.aspnetcore.connections.abstractions\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Connections.Abstractions.dll +microsoft.aspnetcore.connections.abstractions\2.2.0\microsoft.aspnetcore.connections.abstractions.2.2.0.nupkg.sha512 +microsoft.aspnetcore.connections.abstractions\2.2.0\microsoft.aspnetcore.connections.abstractions.nuspec +microsoft.aspnetcore.cookiepolicy\2.2.0\.nupkg.metadata +microsoft.aspnetcore.cookiepolicy\2.2.0\.signature.p7s +microsoft.aspnetcore.cookiepolicy\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.CookiePolicy.dll +microsoft.aspnetcore.cookiepolicy\2.2.0\microsoft.aspnetcore.cookiepolicy.2.2.0.nupkg.sha512 +microsoft.aspnetcore.cookiepolicy\2.2.0\microsoft.aspnetcore.cookiepolicy.nuspec +microsoft.aspnetcore.cors\2.2.0\.nupkg.metadata +microsoft.aspnetcore.cors\2.2.0\.signature.p7s +microsoft.aspnetcore.cors\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Cors.dll +microsoft.aspnetcore.cors\2.2.0\microsoft.aspnetcore.cors.2.2.0.nupkg.sha512 +microsoft.aspnetcore.cors\2.2.0\microsoft.aspnetcore.cors.nuspec +microsoft.aspnetcore.cryptography.internal\2.2.0\.nupkg.metadata +microsoft.aspnetcore.cryptography.internal\2.2.0\.signature.p7s +microsoft.aspnetcore.cryptography.internal\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Cryptography.Internal.dll +microsoft.aspnetcore.cryptography.internal\2.2.0\microsoft.aspnetcore.cryptography.internal.2.2.0.nupkg.sha512 +microsoft.aspnetcore.cryptography.internal\2.2.0\microsoft.aspnetcore.cryptography.internal.nuspec +microsoft.aspnetcore.cryptography.keyderivation\2.2.0\.nupkg.metadata +microsoft.aspnetcore.cryptography.keyderivation\2.2.0\.signature.p7s +microsoft.aspnetcore.cryptography.keyderivation\2.2.0\lib\netcoreapp2.0\Microsoft.AspNetCore.Cryptography.KeyDerivation.dll +microsoft.aspnetcore.cryptography.keyderivation\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Cryptography.KeyDerivation.dll +microsoft.aspnetcore.cryptography.keyderivation\2.2.0\microsoft.aspnetcore.cryptography.keyderivation.2.2.0.nupkg.sha512 +microsoft.aspnetcore.cryptography.keyderivation\2.2.0\microsoft.aspnetcore.cryptography.keyderivation.nuspec +microsoft.aspnetcore.dataprotection.abstractions\2.2.0\.nupkg.metadata +microsoft.aspnetcore.dataprotection.abstractions\2.2.0\.signature.p7s +microsoft.aspnetcore.dataprotection.abstractions\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.DataProtection.Abstractions.dll +microsoft.aspnetcore.dataprotection.abstractions\2.2.0\microsoft.aspnetcore.dataprotection.abstractions.2.2.0.nupkg.sha512 +microsoft.aspnetcore.dataprotection.abstractions\2.2.0\microsoft.aspnetcore.dataprotection.abstractions.nuspec +microsoft.aspnetcore.dataprotection.azurekeyvault\2.2.0\.nupkg.metadata +microsoft.aspnetcore.dataprotection.azurekeyvault\2.2.0\.signature.p7s +microsoft.aspnetcore.dataprotection.azurekeyvault\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.DataProtection.AzureKeyVault.dll +microsoft.aspnetcore.dataprotection.azurekeyvault\2.2.0\microsoft.aspnetcore.dataprotection.azurekeyvault.2.2.0.nupkg.sha512 +microsoft.aspnetcore.dataprotection.azurekeyvault\2.2.0\microsoft.aspnetcore.dataprotection.azurekeyvault.nuspec +microsoft.aspnetcore.dataprotection.azurestorage\2.2.0\.nupkg.metadata +microsoft.aspnetcore.dataprotection.azurestorage\2.2.0\.signature.p7s +microsoft.aspnetcore.dataprotection.azurestorage\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.DataProtection.AzureStorage.dll +microsoft.aspnetcore.dataprotection.azurestorage\2.2.0\microsoft.aspnetcore.dataprotection.azurestorage.2.2.0.nupkg.sha512 +microsoft.aspnetcore.dataprotection.azurestorage\2.2.0\microsoft.aspnetcore.dataprotection.azurestorage.nuspec +microsoft.aspnetcore.dataprotection.extensions\2.2.0\.nupkg.metadata +microsoft.aspnetcore.dataprotection.extensions\2.2.0\.signature.p7s +microsoft.aspnetcore.dataprotection.extensions\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.DataProtection.Extensions.dll +microsoft.aspnetcore.dataprotection.extensions\2.2.0\microsoft.aspnetcore.dataprotection.extensions.2.2.0.nupkg.sha512 +microsoft.aspnetcore.dataprotection.extensions\2.2.0\microsoft.aspnetcore.dataprotection.extensions.nuspec +microsoft.aspnetcore.dataprotection\2.2.0\.nupkg.metadata +microsoft.aspnetcore.dataprotection\2.2.0\.signature.p7s +microsoft.aspnetcore.dataprotection\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.DataProtection.dll +microsoft.aspnetcore.dataprotection\2.2.0\microsoft.aspnetcore.dataprotection.2.2.0.nupkg.sha512 +microsoft.aspnetcore.dataprotection\2.2.0\microsoft.aspnetcore.dataprotection.nuspec +microsoft.aspnetcore.diagnostics.abstractions\2.2.0\.nupkg.metadata +microsoft.aspnetcore.diagnostics.abstractions\2.2.0\.signature.p7s +microsoft.aspnetcore.diagnostics.abstractions\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Diagnostics.Abstractions.dll +microsoft.aspnetcore.diagnostics.abstractions\2.2.0\microsoft.aspnetcore.diagnostics.abstractions.2.2.0.nupkg.sha512 +microsoft.aspnetcore.diagnostics.abstractions\2.2.0\microsoft.aspnetcore.diagnostics.abstractions.nuspec +microsoft.aspnetcore.diagnostics.entityframeworkcore\2.2.0\.nupkg.metadata +microsoft.aspnetcore.diagnostics.entityframeworkcore\2.2.0\.signature.p7s +microsoft.aspnetcore.diagnostics.entityframeworkcore\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.dll +microsoft.aspnetcore.diagnostics.entityframeworkcore\2.2.0\microsoft.aspnetcore.diagnostics.entityframeworkcore.2.2.0.nupkg.sha512 +microsoft.aspnetcore.diagnostics.entityframeworkcore\2.2.0\microsoft.aspnetcore.diagnostics.entityframeworkcore.nuspec +microsoft.aspnetcore.diagnostics.healthchecks\2.2.0\.nupkg.metadata +microsoft.aspnetcore.diagnostics.healthchecks\2.2.0\.signature.p7s +microsoft.aspnetcore.diagnostics.healthchecks\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Diagnostics.HealthChecks.dll +microsoft.aspnetcore.diagnostics.healthchecks\2.2.0\microsoft.aspnetcore.diagnostics.healthchecks.2.2.0.nupkg.sha512 +microsoft.aspnetcore.diagnostics.healthchecks\2.2.0\microsoft.aspnetcore.diagnostics.healthchecks.nuspec +microsoft.aspnetcore.diagnostics\2.2.0\.nupkg.metadata +microsoft.aspnetcore.diagnostics\2.2.0\.signature.p7s +microsoft.aspnetcore.diagnostics\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Diagnostics.dll +microsoft.aspnetcore.diagnostics\2.2.0\microsoft.aspnetcore.diagnostics.2.2.0.nupkg.sha512 +microsoft.aspnetcore.diagnostics\2.2.0\microsoft.aspnetcore.diagnostics.nuspec +microsoft.aspnetcore.hostfiltering\2.2.0\.nupkg.metadata +microsoft.aspnetcore.hostfiltering\2.2.0\.signature.p7s +microsoft.aspnetcore.hostfiltering\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.HostFiltering.dll +microsoft.aspnetcore.hostfiltering\2.2.0\microsoft.aspnetcore.hostfiltering.2.2.0.nupkg.sha512 +microsoft.aspnetcore.hostfiltering\2.2.0\microsoft.aspnetcore.hostfiltering.nuspec +microsoft.aspnetcore.hosting.abstractions\2.2.0\.nupkg.metadata +microsoft.aspnetcore.hosting.abstractions\2.2.0\.signature.p7s +microsoft.aspnetcore.hosting.abstractions\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Hosting.Abstractions.dll +microsoft.aspnetcore.hosting.abstractions\2.2.0\microsoft.aspnetcore.hosting.abstractions.2.2.0.nupkg.sha512 +microsoft.aspnetcore.hosting.abstractions\2.2.0\microsoft.aspnetcore.hosting.abstractions.nuspec +microsoft.aspnetcore.hosting.server.abstractions\2.2.0\.nupkg.metadata +microsoft.aspnetcore.hosting.server.abstractions\2.2.0\.signature.p7s +microsoft.aspnetcore.hosting.server.abstractions\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Hosting.Server.Abstractions.dll +microsoft.aspnetcore.hosting.server.abstractions\2.2.0\microsoft.aspnetcore.hosting.server.abstractions.2.2.0.nupkg.sha512 +microsoft.aspnetcore.hosting.server.abstractions\2.2.0\microsoft.aspnetcore.hosting.server.abstractions.nuspec +microsoft.aspnetcore.hosting\2.2.0\.nupkg.metadata +microsoft.aspnetcore.hosting\2.2.0\.signature.p7s +microsoft.aspnetcore.hosting\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Hosting.dll +microsoft.aspnetcore.hosting\2.2.0\microsoft.aspnetcore.hosting.2.2.0.nupkg.sha512 +microsoft.aspnetcore.hosting\2.2.0\microsoft.aspnetcore.hosting.nuspec +microsoft.aspnetcore.html.abstractions\2.2.0\.nupkg.metadata +microsoft.aspnetcore.html.abstractions\2.2.0\.signature.p7s +microsoft.aspnetcore.html.abstractions\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Html.Abstractions.dll +microsoft.aspnetcore.html.abstractions\2.2.0\microsoft.aspnetcore.html.abstractions.2.2.0.nupkg.sha512 +microsoft.aspnetcore.html.abstractions\2.2.0\microsoft.aspnetcore.html.abstractions.nuspec +microsoft.aspnetcore.http.abstractions\2.2.0\.nupkg.metadata +microsoft.aspnetcore.http.abstractions\2.2.0\.signature.p7s +microsoft.aspnetcore.http.abstractions\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Http.Abstractions.dll +microsoft.aspnetcore.http.abstractions\2.2.0\microsoft.aspnetcore.http.abstractions.2.2.0.nupkg.sha512 +microsoft.aspnetcore.http.abstractions\2.2.0\microsoft.aspnetcore.http.abstractions.nuspec +microsoft.aspnetcore.http.connections.common\1.1.0\.nupkg.metadata +microsoft.aspnetcore.http.connections.common\1.1.0\.signature.p7s +microsoft.aspnetcore.http.connections.common\1.1.0\lib\netstandard2.0\Microsoft.AspNetCore.Http.Connections.Common.dll +microsoft.aspnetcore.http.connections.common\1.1.0\microsoft.aspnetcore.http.connections.common.1.1.0.nupkg.sha512 +microsoft.aspnetcore.http.connections.common\1.1.0\microsoft.aspnetcore.http.connections.common.nuspec +microsoft.aspnetcore.http.connections\1.1.0\.nupkg.metadata +microsoft.aspnetcore.http.connections\1.1.0\.signature.p7s +microsoft.aspnetcore.http.connections\1.1.0\lib\netcoreapp2.2\Microsoft.AspNetCore.Http.Connections.dll +microsoft.aspnetcore.http.connections\1.1.0\lib\netstandard2.0\Microsoft.AspNetCore.Http.Connections.dll +microsoft.aspnetcore.http.connections\1.1.0\microsoft.aspnetcore.http.connections.1.1.0.nupkg.sha512 +microsoft.aspnetcore.http.connections\1.1.0\microsoft.aspnetcore.http.connections.nuspec +microsoft.aspnetcore.http.extensions\2.2.0\.nupkg.metadata +microsoft.aspnetcore.http.extensions\2.2.0\.signature.p7s +microsoft.aspnetcore.http.extensions\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Http.Extensions.dll +microsoft.aspnetcore.http.extensions\2.2.0\microsoft.aspnetcore.http.extensions.2.2.0.nupkg.sha512 +microsoft.aspnetcore.http.extensions\2.2.0\microsoft.aspnetcore.http.extensions.nuspec +microsoft.aspnetcore.http.features\2.2.0\.nupkg.metadata +microsoft.aspnetcore.http.features\2.2.0\.signature.p7s +microsoft.aspnetcore.http.features\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Http.Features.dll +microsoft.aspnetcore.http.features\2.2.0\microsoft.aspnetcore.http.features.2.2.0.nupkg.sha512 +microsoft.aspnetcore.http.features\2.2.0\microsoft.aspnetcore.http.features.nuspec +microsoft.aspnetcore.http\2.2.0\.nupkg.metadata +microsoft.aspnetcore.http\2.2.0\.signature.p7s +microsoft.aspnetcore.http\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Http.dll +microsoft.aspnetcore.http\2.2.0\microsoft.aspnetcore.http.2.2.0.nupkg.sha512 +microsoft.aspnetcore.http\2.2.0\microsoft.aspnetcore.http.nuspec +microsoft.aspnetcore.httpoverrides\2.2.0\.nupkg.metadata +microsoft.aspnetcore.httpoverrides\2.2.0\.signature.p7s +microsoft.aspnetcore.httpoverrides\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.HttpOverrides.dll +microsoft.aspnetcore.httpoverrides\2.2.0\microsoft.aspnetcore.httpoverrides.2.2.0.nupkg.sha512 +microsoft.aspnetcore.httpoverrides\2.2.0\microsoft.aspnetcore.httpoverrides.nuspec +microsoft.aspnetcore.httpspolicy\2.2.0\.nupkg.metadata +microsoft.aspnetcore.httpspolicy\2.2.0\.signature.p7s +microsoft.aspnetcore.httpspolicy\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.HttpsPolicy.dll +microsoft.aspnetcore.httpspolicy\2.2.0\microsoft.aspnetcore.httpspolicy.2.2.0.nupkg.sha512 +microsoft.aspnetcore.httpspolicy\2.2.0\microsoft.aspnetcore.httpspolicy.nuspec +microsoft.aspnetcore.identity.entityframeworkcore\2.2.0\.nupkg.metadata +microsoft.aspnetcore.identity.entityframeworkcore\2.2.0\.signature.p7s +microsoft.aspnetcore.identity.entityframeworkcore\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Identity.EntityFrameworkCore.dll +microsoft.aspnetcore.identity.entityframeworkcore\2.2.0\microsoft.aspnetcore.identity.entityframeworkcore.2.2.0.nupkg.sha512 +microsoft.aspnetcore.identity.entityframeworkcore\2.2.0\microsoft.aspnetcore.identity.entityframeworkcore.nuspec +microsoft.aspnetcore.identity.ui\2.2.0\.nupkg.metadata +microsoft.aspnetcore.identity.ui\2.2.0\.signature.p7s +microsoft.aspnetcore.identity.ui\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Identity.UI.dll +microsoft.aspnetcore.identity.ui\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Identity.UI.Views.V3.dll +microsoft.aspnetcore.identity.ui\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Identity.UI.Views.V4.dll +microsoft.aspnetcore.identity.ui\2.2.0\microsoft.aspnetcore.identity.ui.2.2.0.nupkg.sha512 +microsoft.aspnetcore.identity.ui\2.2.0\microsoft.aspnetcore.identity.ui.nuspec +microsoft.aspnetcore.identity.ui\2.2.0\THIRD-PARTY-NOTICES.txt +microsoft.aspnetcore.identity\2.2.0\.nupkg.metadata +microsoft.aspnetcore.identity\2.2.0\.signature.p7s +microsoft.aspnetcore.identity\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Identity.dll +microsoft.aspnetcore.identity\2.2.0\microsoft.aspnetcore.identity.2.2.0.nupkg.sha512 +microsoft.aspnetcore.identity\2.2.0\microsoft.aspnetcore.identity.nuspec +microsoft.aspnetcore.jsonpatch\2.2.0\.nupkg.metadata +microsoft.aspnetcore.jsonpatch\2.2.0\.signature.p7s +microsoft.aspnetcore.jsonpatch\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.JsonPatch.dll +microsoft.aspnetcore.jsonpatch\2.2.0\microsoft.aspnetcore.jsonpatch.2.2.0.nupkg.sha512 +microsoft.aspnetcore.jsonpatch\2.2.0\microsoft.aspnetcore.jsonpatch.nuspec +microsoft.aspnetcore.localization.routing\2.2.0\.nupkg.metadata +microsoft.aspnetcore.localization.routing\2.2.0\.signature.p7s +microsoft.aspnetcore.localization.routing\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Localization.Routing.dll +microsoft.aspnetcore.localization.routing\2.2.0\microsoft.aspnetcore.localization.routing.2.2.0.nupkg.sha512 +microsoft.aspnetcore.localization.routing\2.2.0\microsoft.aspnetcore.localization.routing.nuspec +microsoft.aspnetcore.localization\2.2.0\.nupkg.metadata +microsoft.aspnetcore.localization\2.2.0\.signature.p7s +microsoft.aspnetcore.localization\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Localization.dll +microsoft.aspnetcore.localization\2.2.0\microsoft.aspnetcore.localization.2.2.0.nupkg.sha512 +microsoft.aspnetcore.localization\2.2.0\microsoft.aspnetcore.localization.nuspec +microsoft.aspnetcore.middlewareanalysis\2.2.0\.nupkg.metadata +microsoft.aspnetcore.middlewareanalysis\2.2.0\.signature.p7s +microsoft.aspnetcore.middlewareanalysis\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.MiddlewareAnalysis.dll +microsoft.aspnetcore.middlewareanalysis\2.2.0\microsoft.aspnetcore.middlewareanalysis.2.2.0.nupkg.sha512 +microsoft.aspnetcore.middlewareanalysis\2.2.0\microsoft.aspnetcore.middlewareanalysis.nuspec +microsoft.aspnetcore.mvc.abstractions\2.2.0\.nupkg.metadata +microsoft.aspnetcore.mvc.abstractions\2.2.0\.signature.p7s +microsoft.aspnetcore.mvc.abstractions\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Mvc.Abstractions.dll +microsoft.aspnetcore.mvc.abstractions\2.2.0\microsoft.aspnetcore.mvc.abstractions.2.2.0.nupkg.sha512 +microsoft.aspnetcore.mvc.abstractions\2.2.0\microsoft.aspnetcore.mvc.abstractions.nuspec +microsoft.aspnetcore.mvc.analyzers\2.2.0\.nupkg.metadata +microsoft.aspnetcore.mvc.analyzers\2.2.0\.signature.p7s +microsoft.aspnetcore.mvc.analyzers\2.2.0\analyzers\dotnet\cs\Microsoft.AspNetCore.Mvc.Analyzers.dll +microsoft.aspnetcore.mvc.analyzers\2.2.0\microsoft.aspnetcore.mvc.analyzers.2.2.0.nupkg.sha512 +microsoft.aspnetcore.mvc.analyzers\2.2.0\microsoft.aspnetcore.mvc.analyzers.nuspec +microsoft.aspnetcore.mvc.apiexplorer\2.2.0\.nupkg.metadata +microsoft.aspnetcore.mvc.apiexplorer\2.2.0\.signature.p7s +microsoft.aspnetcore.mvc.apiexplorer\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Mvc.ApiExplorer.dll +microsoft.aspnetcore.mvc.apiexplorer\2.2.0\microsoft.aspnetcore.mvc.apiexplorer.2.2.0.nupkg.sha512 +microsoft.aspnetcore.mvc.apiexplorer\2.2.0\microsoft.aspnetcore.mvc.apiexplorer.nuspec +microsoft.aspnetcore.mvc.core\2.2.0\.nupkg.metadata +microsoft.aspnetcore.mvc.core\2.2.0\.signature.p7s +microsoft.aspnetcore.mvc.core\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Mvc.Core.dll +microsoft.aspnetcore.mvc.core\2.2.0\microsoft.aspnetcore.mvc.core.2.2.0.nupkg.sha512 +microsoft.aspnetcore.mvc.core\2.2.0\microsoft.aspnetcore.mvc.core.nuspec +microsoft.aspnetcore.mvc.cors\2.2.0\.nupkg.metadata +microsoft.aspnetcore.mvc.cors\2.2.0\.signature.p7s +microsoft.aspnetcore.mvc.cors\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Mvc.Cors.dll +microsoft.aspnetcore.mvc.cors\2.2.0\microsoft.aspnetcore.mvc.cors.2.2.0.nupkg.sha512 +microsoft.aspnetcore.mvc.cors\2.2.0\microsoft.aspnetcore.mvc.cors.nuspec +microsoft.aspnetcore.mvc.dataannotations\2.2.0\.nupkg.metadata +microsoft.aspnetcore.mvc.dataannotations\2.2.0\.signature.p7s +microsoft.aspnetcore.mvc.dataannotations\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Mvc.DataAnnotations.dll +microsoft.aspnetcore.mvc.dataannotations\2.2.0\microsoft.aspnetcore.mvc.dataannotations.2.2.0.nupkg.sha512 +microsoft.aspnetcore.mvc.dataannotations\2.2.0\microsoft.aspnetcore.mvc.dataannotations.nuspec +microsoft.aspnetcore.mvc.formatters.json\2.2.0\.nupkg.metadata +microsoft.aspnetcore.mvc.formatters.json\2.2.0\.signature.p7s +microsoft.aspnetcore.mvc.formatters.json\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Mvc.Formatters.Json.dll +microsoft.aspnetcore.mvc.formatters.json\2.2.0\microsoft.aspnetcore.mvc.formatters.json.2.2.0.nupkg.sha512 +microsoft.aspnetcore.mvc.formatters.json\2.2.0\microsoft.aspnetcore.mvc.formatters.json.nuspec +microsoft.aspnetcore.mvc.formatters.xml\2.2.0\.nupkg.metadata +microsoft.aspnetcore.mvc.formatters.xml\2.2.0\.signature.p7s +microsoft.aspnetcore.mvc.formatters.xml\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Mvc.Formatters.Xml.dll +microsoft.aspnetcore.mvc.formatters.xml\2.2.0\microsoft.aspnetcore.mvc.formatters.xml.2.2.0.nupkg.sha512 +microsoft.aspnetcore.mvc.formatters.xml\2.2.0\microsoft.aspnetcore.mvc.formatters.xml.nuspec +microsoft.aspnetcore.mvc.localization\2.2.0\.nupkg.metadata +microsoft.aspnetcore.mvc.localization\2.2.0\.signature.p7s +microsoft.aspnetcore.mvc.localization\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Mvc.Localization.dll +microsoft.aspnetcore.mvc.localization\2.2.0\microsoft.aspnetcore.mvc.localization.2.2.0.nupkg.sha512 +microsoft.aspnetcore.mvc.localization\2.2.0\microsoft.aspnetcore.mvc.localization.nuspec +microsoft.aspnetcore.mvc.razor.extensions\2.2.0\.nupkg.metadata +microsoft.aspnetcore.mvc.razor.extensions\2.2.0\.signature.p7s +microsoft.aspnetcore.mvc.razor.extensions\2.2.0\build\netstandard2.0\Microsoft.AspNetCore.Mvc.Razor.Extensions.props +microsoft.aspnetcore.mvc.razor.extensions\2.2.0\build\netstandard2.0\Microsoft.AspNetCore.Mvc.Razor.Extensions.targets +microsoft.aspnetcore.mvc.razor.extensions\2.2.0\lib\net46\Microsoft.AspNetCore.Mvc.Razor.Extensions.dll +microsoft.aspnetcore.mvc.razor.extensions\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Mvc.Razor.Extensions.dll +microsoft.aspnetcore.mvc.razor.extensions\2.2.0\microsoft.aspnetcore.mvc.razor.extensions.2.2.0.nupkg.sha512 +microsoft.aspnetcore.mvc.razor.extensions\2.2.0\microsoft.aspnetcore.mvc.razor.extensions.nuspec +microsoft.aspnetcore.mvc.razor.viewcompilation\2.2.0\.nupkg.metadata +microsoft.aspnetcore.mvc.razor.viewcompilation\2.2.0\.signature.p7s +microsoft.aspnetcore.mvc.razor.viewcompilation\2.2.0\build\netstandard2.0\Microsoft.AspNetCore.Mvc.Razor.ViewCompilation.targets +microsoft.aspnetcore.mvc.razor.viewcompilation\2.2.0\build\netstandard2.0\Microsoft.AspNetCore.Mvc.Razor.ViewCompilation.Tasks.dll +microsoft.aspnetcore.mvc.razor.viewcompilation\2.2.0\build\netstandard2.0\net461\Microsoft.AspNetCore.Mvc.Razor.ViewCompilation.exe +microsoft.aspnetcore.mvc.razor.viewcompilation\2.2.0\build\netstandard2.0\net461\Microsoft.AspNetCore.Mvc.Razor.ViewCompilation-x86.exe +microsoft.aspnetcore.mvc.razor.viewcompilation\2.2.0\build\netstandard2.0\netcoreapp2.0\Microsoft.AspNetCore.Mvc.Razor.ViewCompilation.dll +microsoft.aspnetcore.mvc.razor.viewcompilation\2.2.0\microsoft.aspnetcore.mvc.razor.viewcompilation.2.2.0.nupkg.sha512 +microsoft.aspnetcore.mvc.razor.viewcompilation\2.2.0\microsoft.aspnetcore.mvc.razor.viewcompilation.nuspec +microsoft.aspnetcore.mvc.razor\2.2.0\.nupkg.metadata +microsoft.aspnetcore.mvc.razor\2.2.0\.signature.p7s +microsoft.aspnetcore.mvc.razor\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Mvc.Razor.dll +microsoft.aspnetcore.mvc.razor\2.2.0\microsoft.aspnetcore.mvc.razor.2.2.0.nupkg.sha512 +microsoft.aspnetcore.mvc.razor\2.2.0\microsoft.aspnetcore.mvc.razor.nuspec +microsoft.aspnetcore.mvc.razorpages\2.2.0\.nupkg.metadata +microsoft.aspnetcore.mvc.razorpages\2.2.0\.signature.p7s +microsoft.aspnetcore.mvc.razorpages\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Mvc.RazorPages.dll +microsoft.aspnetcore.mvc.razorpages\2.2.0\microsoft.aspnetcore.mvc.razorpages.2.2.0.nupkg.sha512 +microsoft.aspnetcore.mvc.razorpages\2.2.0\microsoft.aspnetcore.mvc.razorpages.nuspec +microsoft.aspnetcore.mvc.taghelpers\2.2.0\.nupkg.metadata +microsoft.aspnetcore.mvc.taghelpers\2.2.0\.signature.p7s +microsoft.aspnetcore.mvc.taghelpers\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Mvc.TagHelpers.dll +microsoft.aspnetcore.mvc.taghelpers\2.2.0\microsoft.aspnetcore.mvc.taghelpers.2.2.0.nupkg.sha512 +microsoft.aspnetcore.mvc.taghelpers\2.2.0\microsoft.aspnetcore.mvc.taghelpers.nuspec +microsoft.aspnetcore.mvc.viewfeatures\2.2.0\.nupkg.metadata +microsoft.aspnetcore.mvc.viewfeatures\2.2.0\.signature.p7s +microsoft.aspnetcore.mvc.viewfeatures\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Mvc.ViewFeatures.dll +microsoft.aspnetcore.mvc.viewfeatures\2.2.0\microsoft.aspnetcore.mvc.viewfeatures.2.2.0.nupkg.sha512 +microsoft.aspnetcore.mvc.viewfeatures\2.2.0\microsoft.aspnetcore.mvc.viewfeatures.nuspec +microsoft.aspnetcore.mvc\2.2.0\.nupkg.metadata +microsoft.aspnetcore.mvc\2.2.0\.signature.p7s +microsoft.aspnetcore.mvc\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Mvc.dll +microsoft.aspnetcore.mvc\2.2.0\microsoft.aspnetcore.mvc.2.2.0.nupkg.sha512 +microsoft.aspnetcore.mvc\2.2.0\microsoft.aspnetcore.mvc.nuspec +microsoft.aspnetcore.nodeservices\2.2.0\.nupkg.metadata +microsoft.aspnetcore.nodeservices\2.2.0\.signature.p7s +microsoft.aspnetcore.nodeservices\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.NodeServices.dll +microsoft.aspnetcore.nodeservices\2.2.0\microsoft.aspnetcore.nodeservices.2.2.0.nupkg.sha512 +microsoft.aspnetcore.nodeservices\2.2.0\microsoft.aspnetcore.nodeservices.nuspec +microsoft.aspnetcore.owin\2.2.0\.nupkg.metadata +microsoft.aspnetcore.owin\2.2.0\.signature.p7s +microsoft.aspnetcore.owin\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Owin.dll +microsoft.aspnetcore.owin\2.2.0\microsoft.aspnetcore.owin.2.2.0.nupkg.sha512 +microsoft.aspnetcore.owin\2.2.0\microsoft.aspnetcore.owin.nuspec +microsoft.aspnetcore.razor.design\2.2.0\.nupkg.metadata +microsoft.aspnetcore.razor.design\2.2.0\.signature.p7s +microsoft.aspnetcore.razor.design\2.2.0\build\netstandard2.0\Microsoft.AspNetCore.Razor.Design.CodeGeneration.targets +microsoft.aspnetcore.razor.design\2.2.0\build\netstandard2.0\Microsoft.AspNetCore.Razor.Design.props +microsoft.aspnetcore.razor.design\2.2.0\buildMultiTargeting\Microsoft.AspNetCore.Razor.Design.props +microsoft.aspnetcore.razor.design\2.2.0\microsoft.aspnetcore.razor.design.2.2.0.nupkg.sha512 +microsoft.aspnetcore.razor.design\2.2.0\microsoft.aspnetcore.razor.design.nuspec +microsoft.aspnetcore.razor.design\2.2.0\tools\Microsoft.AspNetCore.Razor.Language.dll +microsoft.aspnetcore.razor.design\2.2.0\tools\Microsoft.CodeAnalysis.CSharp.dll +microsoft.aspnetcore.razor.design\2.2.0\tools\Microsoft.CodeAnalysis.dll +microsoft.aspnetcore.razor.design\2.2.0\tools\Microsoft.CodeAnalysis.Razor.dll +microsoft.aspnetcore.razor.design\2.2.0\tools\Newtonsoft.Json.dll +microsoft.aspnetcore.razor.design\2.2.0\tools\runtimes\unix\lib\netstandard1.3\System.Text.Encoding.CodePages.dll +microsoft.aspnetcore.razor.design\2.2.0\tools\runtimes\win\lib\netstandard1.3\System.Text.Encoding.CodePages.dll +microsoft.aspnetcore.razor.design\2.2.0\tools\rzc.deps.json +microsoft.aspnetcore.razor.design\2.2.0\tools\rzc.dll +microsoft.aspnetcore.razor.design\2.2.0\tools\rzc.runtimeconfig.json +microsoft.aspnetcore.razor.language\2.2.0\.nupkg.metadata +microsoft.aspnetcore.razor.language\2.2.0\.signature.p7s +microsoft.aspnetcore.razor.language\2.2.0\lib\net46\Microsoft.AspNetCore.Razor.Language.dll +microsoft.aspnetcore.razor.language\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Razor.Language.dll +microsoft.aspnetcore.razor.language\2.2.0\microsoft.aspnetcore.razor.language.2.2.0.nupkg.sha512 +microsoft.aspnetcore.razor.language\2.2.0\microsoft.aspnetcore.razor.language.nuspec +microsoft.aspnetcore.razor.runtime\2.2.0\.nupkg.metadata +microsoft.aspnetcore.razor.runtime\2.2.0\.signature.p7s +microsoft.aspnetcore.razor.runtime\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Razor.Runtime.dll +microsoft.aspnetcore.razor.runtime\2.2.0\microsoft.aspnetcore.razor.runtime.2.2.0.nupkg.sha512 +microsoft.aspnetcore.razor.runtime\2.2.0\microsoft.aspnetcore.razor.runtime.nuspec +microsoft.aspnetcore.razor\2.2.0\.nupkg.metadata +microsoft.aspnetcore.razor\2.2.0\.signature.p7s +microsoft.aspnetcore.razor\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Razor.dll +microsoft.aspnetcore.razor\2.2.0\microsoft.aspnetcore.razor.2.2.0.nupkg.sha512 +microsoft.aspnetcore.razor\2.2.0\microsoft.aspnetcore.razor.nuspec +microsoft.aspnetcore.responsecaching.abstractions\2.2.0\.nupkg.metadata +microsoft.aspnetcore.responsecaching.abstractions\2.2.0\.signature.p7s +microsoft.aspnetcore.responsecaching.abstractions\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.ResponseCaching.Abstractions.dll +microsoft.aspnetcore.responsecaching.abstractions\2.2.0\microsoft.aspnetcore.responsecaching.abstractions.2.2.0.nupkg.sha512 +microsoft.aspnetcore.responsecaching.abstractions\2.2.0\microsoft.aspnetcore.responsecaching.abstractions.nuspec +microsoft.aspnetcore.responsecaching\2.2.0\.nupkg.metadata +microsoft.aspnetcore.responsecaching\2.2.0\.signature.p7s +microsoft.aspnetcore.responsecaching\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.ResponseCaching.dll +microsoft.aspnetcore.responsecaching\2.2.0\microsoft.aspnetcore.responsecaching.2.2.0.nupkg.sha512 +microsoft.aspnetcore.responsecaching\2.2.0\microsoft.aspnetcore.responsecaching.nuspec +microsoft.aspnetcore.responsecompression\2.2.0\.nupkg.metadata +microsoft.aspnetcore.responsecompression\2.2.0\.signature.p7s +microsoft.aspnetcore.responsecompression\2.2.0\lib\net461\Microsoft.AspNetCore.ResponseCompression.dll +microsoft.aspnetcore.responsecompression\2.2.0\lib\netcoreapp2.1\Microsoft.AspNetCore.ResponseCompression.dll +microsoft.aspnetcore.responsecompression\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.ResponseCompression.dll +microsoft.aspnetcore.responsecompression\2.2.0\microsoft.aspnetcore.responsecompression.2.2.0.nupkg.sha512 +microsoft.aspnetcore.responsecompression\2.2.0\microsoft.aspnetcore.responsecompression.nuspec +microsoft.aspnetcore.rewrite\2.2.0\.nupkg.metadata +microsoft.aspnetcore.rewrite\2.2.0\.signature.p7s +microsoft.aspnetcore.rewrite\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Rewrite.dll +microsoft.aspnetcore.rewrite\2.2.0\microsoft.aspnetcore.rewrite.2.2.0.nupkg.sha512 +microsoft.aspnetcore.rewrite\2.2.0\microsoft.aspnetcore.rewrite.nuspec +microsoft.aspnetcore.routing.abstractions\2.2.0\.nupkg.metadata +microsoft.aspnetcore.routing.abstractions\2.2.0\.signature.p7s +microsoft.aspnetcore.routing.abstractions\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Routing.Abstractions.dll +microsoft.aspnetcore.routing.abstractions\2.2.0\microsoft.aspnetcore.routing.abstractions.2.2.0.nupkg.sha512 +microsoft.aspnetcore.routing.abstractions\2.2.0\microsoft.aspnetcore.routing.abstractions.nuspec +microsoft.aspnetcore.routing\2.2.0\.nupkg.metadata +microsoft.aspnetcore.routing\2.2.0\.signature.p7s +microsoft.aspnetcore.routing\2.2.0\lib\netcoreapp2.2\Microsoft.AspNetCore.Routing.dll +microsoft.aspnetcore.routing\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Routing.dll +microsoft.aspnetcore.routing\2.2.0\microsoft.aspnetcore.routing.2.2.0.nupkg.sha512 +microsoft.aspnetcore.routing\2.2.0\microsoft.aspnetcore.routing.nuspec +microsoft.aspnetcore.server.httpsys\2.2.0\.nupkg.metadata +microsoft.aspnetcore.server.httpsys\2.2.0\.signature.p7s +microsoft.aspnetcore.server.httpsys\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Server.HttpSys.dll +microsoft.aspnetcore.server.httpsys\2.2.0\microsoft.aspnetcore.server.httpsys.2.2.0.nupkg.sha512 +microsoft.aspnetcore.server.httpsys\2.2.0\microsoft.aspnetcore.server.httpsys.nuspec +microsoft.aspnetcore.server.iis\2.2.0\.nupkg.metadata +microsoft.aspnetcore.server.iis\2.2.0\.signature.p7s +microsoft.aspnetcore.server.iis\2.2.0\build\netstandard2.0\Microsoft.AspNetCore.Server.IIS.targets +microsoft.aspnetcore.server.iis\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Server.IIS.dll +microsoft.aspnetcore.server.iis\2.2.0\microsoft.aspnetcore.server.iis.2.2.0.nupkg.sha512 +microsoft.aspnetcore.server.iis\2.2.0\microsoft.aspnetcore.server.iis.nuspec +microsoft.aspnetcore.server.iis\2.2.0\runtimes\win-x64\nativeassets\netcoreapp2.2\aspnetcorev2_inprocess.dll +microsoft.aspnetcore.server.iis\2.2.0\runtimes\win-x86\nativeassets\netcoreapp2.2\aspnetcorev2_inprocess.dll +microsoft.aspnetcore.server.iisintegration\2.2.0\.nupkg.metadata +microsoft.aspnetcore.server.iisintegration\2.2.0\.signature.p7s +microsoft.aspnetcore.server.iisintegration\2.2.0\build\netstandard2.0\Microsoft.AspNetCore.Server.IISIntegration.targets +microsoft.aspnetcore.server.iisintegration\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Server.IISIntegration.dll +microsoft.aspnetcore.server.iisintegration\2.2.0\microsoft.aspnetcore.server.iisintegration.2.2.0.nupkg.sha512 +microsoft.aspnetcore.server.iisintegration\2.2.0\microsoft.aspnetcore.server.iisintegration.nuspec +microsoft.aspnetcore.server.kestrel.core\2.2.0\.nupkg.metadata +microsoft.aspnetcore.server.kestrel.core\2.2.0\.signature.p7s +microsoft.aspnetcore.server.kestrel.core\2.2.0\lib\netcoreapp2.1\Microsoft.AspNetCore.Server.Kestrel.Core.dll +microsoft.aspnetcore.server.kestrel.core\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Server.Kestrel.Core.dll +microsoft.aspnetcore.server.kestrel.core\2.2.0\microsoft.aspnetcore.server.kestrel.core.2.2.0.nupkg.sha512 +microsoft.aspnetcore.server.kestrel.core\2.2.0\microsoft.aspnetcore.server.kestrel.core.nuspec +microsoft.aspnetcore.server.kestrel.https\2.2.0\.nupkg.metadata +microsoft.aspnetcore.server.kestrel.https\2.2.0\.signature.p7s +microsoft.aspnetcore.server.kestrel.https\2.2.0\lib\netcoreapp2.1\Microsoft.AspNetCore.Server.Kestrel.Https.dll +microsoft.aspnetcore.server.kestrel.https\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Server.Kestrel.Https.dll +microsoft.aspnetcore.server.kestrel.https\2.2.0\microsoft.aspnetcore.server.kestrel.https.2.2.0.nupkg.sha512 +microsoft.aspnetcore.server.kestrel.https\2.2.0\microsoft.aspnetcore.server.kestrel.https.nuspec +microsoft.aspnetcore.server.kestrel.transport.abstractions\2.2.0\.nupkg.metadata +microsoft.aspnetcore.server.kestrel.transport.abstractions\2.2.0\.signature.p7s +microsoft.aspnetcore.server.kestrel.transport.abstractions\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.dll +microsoft.aspnetcore.server.kestrel.transport.abstractions\2.2.0\microsoft.aspnetcore.server.kestrel.transport.abstractions.2.2.0.nupkg.sha512 +microsoft.aspnetcore.server.kestrel.transport.abstractions\2.2.0\microsoft.aspnetcore.server.kestrel.transport.abstractions.nuspec +microsoft.aspnetcore.server.kestrel.transport.libuv\2.2.0\.nupkg.metadata +microsoft.aspnetcore.server.kestrel.transport.libuv\2.2.0\.signature.p7s +microsoft.aspnetcore.server.kestrel.transport.libuv\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.dll +microsoft.aspnetcore.server.kestrel.transport.libuv\2.2.0\microsoft.aspnetcore.server.kestrel.transport.libuv.2.2.0.nupkg.sha512 +microsoft.aspnetcore.server.kestrel.transport.libuv\2.2.0\microsoft.aspnetcore.server.kestrel.transport.libuv.nuspec +microsoft.aspnetcore.server.kestrel.transport.sockets\2.2.0\.nupkg.metadata +microsoft.aspnetcore.server.kestrel.transport.sockets\2.2.0\.signature.p7s +microsoft.aspnetcore.server.kestrel.transport.sockets\2.2.0\lib\netcoreapp2.1\Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.dll +microsoft.aspnetcore.server.kestrel.transport.sockets\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.dll +microsoft.aspnetcore.server.kestrel.transport.sockets\2.2.0\microsoft.aspnetcore.server.kestrel.transport.sockets.2.2.0.nupkg.sha512 +microsoft.aspnetcore.server.kestrel.transport.sockets\2.2.0\microsoft.aspnetcore.server.kestrel.transport.sockets.nuspec +microsoft.aspnetcore.server.kestrel\2.2.0\.nupkg.metadata +microsoft.aspnetcore.server.kestrel\2.2.0\.signature.p7s +microsoft.aspnetcore.server.kestrel\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Server.Kestrel.dll +microsoft.aspnetcore.server.kestrel\2.2.0\microsoft.aspnetcore.server.kestrel.2.2.0.nupkg.sha512 +microsoft.aspnetcore.server.kestrel\2.2.0\microsoft.aspnetcore.server.kestrel.nuspec +microsoft.aspnetcore.session\2.2.0\.nupkg.metadata +microsoft.aspnetcore.session\2.2.0\.signature.p7s +microsoft.aspnetcore.session\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Session.dll +microsoft.aspnetcore.session\2.2.0\microsoft.aspnetcore.session.2.2.0.nupkg.sha512 +microsoft.aspnetcore.session\2.2.0\microsoft.aspnetcore.session.nuspec +microsoft.aspnetcore.signalr.common\1.1.0\.nupkg.metadata +microsoft.aspnetcore.signalr.common\1.1.0\.signature.p7s +microsoft.aspnetcore.signalr.common\1.1.0\lib\netcoreapp2.2\Microsoft.AspNetCore.SignalR.Common.dll +microsoft.aspnetcore.signalr.common\1.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Common.dll +microsoft.aspnetcore.signalr.common\1.1.0\microsoft.aspnetcore.signalr.common.1.1.0.nupkg.sha512 +microsoft.aspnetcore.signalr.common\1.1.0\microsoft.aspnetcore.signalr.common.nuspec +microsoft.aspnetcore.signalr.core\1.1.0\.nupkg.metadata +microsoft.aspnetcore.signalr.core\1.1.0\.signature.p7s +microsoft.aspnetcore.signalr.core\1.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Core.dll +microsoft.aspnetcore.signalr.core\1.1.0\microsoft.aspnetcore.signalr.core.1.1.0.nupkg.sha512 +microsoft.aspnetcore.signalr.core\1.1.0\microsoft.aspnetcore.signalr.core.nuspec +microsoft.aspnetcore.signalr.protocols.json\1.1.0\.nupkg.metadata +microsoft.aspnetcore.signalr.protocols.json\1.1.0\.signature.p7s +microsoft.aspnetcore.signalr.protocols.json\1.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Protocols.Json.dll +microsoft.aspnetcore.signalr.protocols.json\1.1.0\microsoft.aspnetcore.signalr.protocols.json.1.1.0.nupkg.sha512 +microsoft.aspnetcore.signalr.protocols.json\1.1.0\microsoft.aspnetcore.signalr.protocols.json.nuspec +microsoft.aspnetcore.signalr.redis\1.1.0\.nupkg.metadata +microsoft.aspnetcore.signalr.redis\1.1.0\.signature.p7s +microsoft.aspnetcore.signalr.redis\1.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Redis.dll +microsoft.aspnetcore.signalr.redis\1.1.0\microsoft.aspnetcore.signalr.redis.1.1.0.nupkg.sha512 +microsoft.aspnetcore.signalr.redis\1.1.0\microsoft.aspnetcore.signalr.redis.nuspec +microsoft.aspnetcore.signalr\1.1.0\.nupkg.metadata +microsoft.aspnetcore.signalr\1.1.0\.signature.p7s +microsoft.aspnetcore.signalr\1.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.dll +microsoft.aspnetcore.signalr\1.1.0\microsoft.aspnetcore.signalr.1.1.0.nupkg.sha512 +microsoft.aspnetcore.signalr\1.1.0\microsoft.aspnetcore.signalr.nuspec +microsoft.aspnetcore.spaservices.extensions\2.2.0\.nupkg.metadata +microsoft.aspnetcore.spaservices.extensions\2.2.0\.signature.p7s +microsoft.aspnetcore.spaservices.extensions\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.SpaServices.Extensions.dll +microsoft.aspnetcore.spaservices.extensions\2.2.0\microsoft.aspnetcore.spaservices.extensions.2.2.0.nupkg.sha512 +microsoft.aspnetcore.spaservices.extensions\2.2.0\microsoft.aspnetcore.spaservices.extensions.nuspec +microsoft.aspnetcore.spaservices\2.2.0\.nupkg.metadata +microsoft.aspnetcore.spaservices\2.2.0\.signature.p7s +microsoft.aspnetcore.spaservices\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.SpaServices.dll +microsoft.aspnetcore.spaservices\2.2.0\microsoft.aspnetcore.spaservices.2.2.0.nupkg.sha512 +microsoft.aspnetcore.spaservices\2.2.0\microsoft.aspnetcore.spaservices.nuspec +microsoft.aspnetcore.staticfiles\2.2.0\.nupkg.metadata +microsoft.aspnetcore.staticfiles\2.2.0\.signature.p7s +microsoft.aspnetcore.staticfiles\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.StaticFiles.dll +microsoft.aspnetcore.staticfiles\2.2.0\microsoft.aspnetcore.staticfiles.2.2.0.nupkg.sha512 +microsoft.aspnetcore.staticfiles\2.2.0\microsoft.aspnetcore.staticfiles.nuspec +microsoft.aspnetcore.websockets\2.2.0\.nupkg.metadata +microsoft.aspnetcore.websockets\2.2.0\.signature.p7s +microsoft.aspnetcore.websockets\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.WebSockets.dll +microsoft.aspnetcore.websockets\2.2.0\microsoft.aspnetcore.websockets.2.2.0.nupkg.sha512 +microsoft.aspnetcore.websockets\2.2.0\microsoft.aspnetcore.websockets.nuspec +microsoft.aspnetcore.webutilities\2.2.0\.nupkg.metadata +microsoft.aspnetcore.webutilities\2.2.0\.signature.p7s +microsoft.aspnetcore.webutilities\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.WebUtilities.dll +microsoft.aspnetcore.webutilities\2.2.0\microsoft.aspnetcore.webutilities.2.2.0.nupkg.sha512 +microsoft.aspnetcore.webutilities\2.2.0\microsoft.aspnetcore.webutilities.nuspec +microsoft.aspnetcore\2.2.0\.nupkg.metadata +microsoft.aspnetcore\2.2.0\.signature.p7s +microsoft.aspnetcore\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.dll +microsoft.aspnetcore\2.2.0\microsoft.aspnetcore.2.2.0.nupkg.sha512 +microsoft.aspnetcore\2.2.0\microsoft.aspnetcore.nuspec +microsoft.azure.keyvault.webkey\2.0.7\.nupkg.metadata +microsoft.azure.keyvault.webkey\2.0.7\.signature.p7s +microsoft.azure.keyvault\2.3.2\.nupkg.metadata +microsoft.azure.keyvault\2.3.2\.signature.p7s +microsoft.azure.services.appauthentication\1.0.1\.nupkg.metadata +microsoft.azure.services.appauthentication\1.0.1\.signature.p7s +microsoft.codeanalysis.analyzers\1.1.0\.nupkg.metadata +microsoft.codeanalysis.common\2.8.0\.nupkg.metadata +microsoft.codeanalysis.csharp\2.8.0\.nupkg.metadata +microsoft.codeanalysis.razor\2.2.0\.nupkg.metadata +microsoft.codeanalysis.razor\2.2.0\.signature.p7s +microsoft.codeanalysis.razor\2.2.0\lib\net46\Microsoft.CodeAnalysis.Razor.dll +microsoft.codeanalysis.razor\2.2.0\lib\netstandard2.0\Microsoft.CodeAnalysis.Razor.dll +microsoft.codeanalysis.razor\2.2.0\microsoft.codeanalysis.razor.2.2.0.nupkg.sha512 +microsoft.codeanalysis.razor\2.2.0\microsoft.codeanalysis.razor.nuspec +microsoft.csharp\4.0.1\.nupkg.metadata +microsoft.csharp\4.3.0\.nupkg.metadata +microsoft.csharp\4.5.0\.nupkg.metadata +microsoft.data.edm\5.8.2\.nupkg.metadata +microsoft.data.odata\5.8.2\.nupkg.metadata +microsoft.data.sqlite.core\2.2.0\.nupkg.metadata +microsoft.data.sqlite.core\2.2.0\.signature.p7s +microsoft.data.sqlite.core\2.2.0\lib\netstandard2.0\Microsoft.Data.Sqlite.dll +microsoft.data.sqlite.core\2.2.0\microsoft.data.sqlite.core.2.2.0.nupkg.sha512 +microsoft.data.sqlite.core\2.2.0\microsoft.data.sqlite.core.nuspec +microsoft.data.sqlite\2.2.0\.nupkg.metadata +microsoft.data.sqlite\2.2.0\.signature.p7s +microsoft.data.sqlite\2.2.0\lib\netstandard2.0\_._ +microsoft.data.sqlite\2.2.0\microsoft.data.sqlite.2.2.0.nupkg.sha512 +microsoft.data.sqlite\2.2.0\microsoft.data.sqlite.nuspec +microsoft.dotnet.platformabstractions\2.1.0\.nupkg.metadata +microsoft.entityframeworkcore.abstractions\2.2.0\.nupkg.metadata +microsoft.entityframeworkcore.abstractions\2.2.0\.signature.p7s +microsoft.entityframeworkcore.abstractions\2.2.0\lib\netstandard2.0\Microsoft.EntityFrameworkCore.Abstractions.dll +microsoft.entityframeworkcore.abstractions\2.2.0\microsoft.entityframeworkcore.abstractions.2.2.0.nupkg.sha512 +microsoft.entityframeworkcore.abstractions\2.2.0\microsoft.entityframeworkcore.abstractions.nuspec +microsoft.entityframeworkcore.analyzers\2.2.0\.nupkg.metadata +microsoft.entityframeworkcore.analyzers\2.2.0\.signature.p7s +microsoft.entityframeworkcore.analyzers\2.2.0\analyzers\dotnet\cs\Microsoft.EntityFrameworkCore.Analyzers.dll +microsoft.entityframeworkcore.analyzers\2.2.0\microsoft.entityframeworkcore.analyzers.2.2.0.nupkg.sha512 +microsoft.entityframeworkcore.analyzers\2.2.0\microsoft.entityframeworkcore.analyzers.nuspec +microsoft.entityframeworkcore.design\2.2.0\.nupkg.metadata +microsoft.entityframeworkcore.design\2.2.0\.signature.p7s +microsoft.entityframeworkcore.design\2.2.0\build\net461\Microsoft.EntityFrameworkCore.Design.props +microsoft.entityframeworkcore.design\2.2.0\build\netcoreapp2.0\Microsoft.EntityFrameworkCore.Design.props +microsoft.entityframeworkcore.design\2.2.0\lib\net461\Microsoft.EntityFrameworkCore.Design.dll +microsoft.entityframeworkcore.design\2.2.0\lib\netstandard2.0\Microsoft.EntityFrameworkCore.Design.dll +microsoft.entityframeworkcore.design\2.2.0\microsoft.entityframeworkcore.design.2.2.0.nupkg.sha512 +microsoft.entityframeworkcore.design\2.2.0\microsoft.entityframeworkcore.design.nuspec +microsoft.entityframeworkcore.inmemory\2.2.0\.nupkg.metadata +microsoft.entityframeworkcore.inmemory\2.2.0\.signature.p7s +microsoft.entityframeworkcore.inmemory\2.2.0\lib\netstandard2.0\Microsoft.EntityFrameworkCore.InMemory.dll +microsoft.entityframeworkcore.inmemory\2.2.0\microsoft.entityframeworkcore.inmemory.2.2.0.nupkg.sha512 +microsoft.entityframeworkcore.inmemory\2.2.0\microsoft.entityframeworkcore.inmemory.nuspec +microsoft.entityframeworkcore.relational\2.2.0\.nupkg.metadata +microsoft.entityframeworkcore.relational\2.2.0\.signature.p7s +microsoft.entityframeworkcore.relational\2.2.0\lib\netstandard2.0\Microsoft.EntityFrameworkCore.Relational.dll +microsoft.entityframeworkcore.relational\2.2.0\microsoft.entityframeworkcore.relational.2.2.0.nupkg.sha512 +microsoft.entityframeworkcore.relational\2.2.0\microsoft.entityframeworkcore.relational.nuspec +microsoft.entityframeworkcore.sqlite.core\2.2.0\.nupkg.metadata +microsoft.entityframeworkcore.sqlite.core\2.2.0\.signature.p7s +microsoft.entityframeworkcore.sqlite.core\2.2.0\lib\netstandard2.0\Microsoft.EntityFrameworkCore.Sqlite.dll +microsoft.entityframeworkcore.sqlite.core\2.2.0\microsoft.entityframeworkcore.sqlite.core.2.2.0.nupkg.sha512 +microsoft.entityframeworkcore.sqlite.core\2.2.0\microsoft.entityframeworkcore.sqlite.core.nuspec +microsoft.entityframeworkcore.sqlite\2.2.0\.nupkg.metadata +microsoft.entityframeworkcore.sqlite\2.2.0\.signature.p7s +microsoft.entityframeworkcore.sqlite\2.2.0\lib\netstandard2.0\_._ +microsoft.entityframeworkcore.sqlite\2.2.0\microsoft.entityframeworkcore.sqlite.2.2.0.nupkg.sha512 +microsoft.entityframeworkcore.sqlite\2.2.0\microsoft.entityframeworkcore.sqlite.nuspec +microsoft.entityframeworkcore.sqlserver\2.2.0\.nupkg.metadata +microsoft.entityframeworkcore.sqlserver\2.2.0\.signature.p7s +microsoft.entityframeworkcore.sqlserver\2.2.0\lib\netstandard2.0\Microsoft.EntityFrameworkCore.SqlServer.dll +microsoft.entityframeworkcore.sqlserver\2.2.0\microsoft.entityframeworkcore.sqlserver.2.2.0.nupkg.sha512 +microsoft.entityframeworkcore.sqlserver\2.2.0\microsoft.entityframeworkcore.sqlserver.nuspec +microsoft.entityframeworkcore.tools\2.2.0\.nupkg.metadata +microsoft.entityframeworkcore.tools\2.2.0\.signature.p7s +microsoft.entityframeworkcore.tools\2.2.0\lib\netstandard2.0\_._ +microsoft.entityframeworkcore.tools\2.2.0\microsoft.entityframeworkcore.tools.2.2.0.nupkg.sha512 +microsoft.entityframeworkcore.tools\2.2.0\microsoft.entityframeworkcore.tools.nuspec +microsoft.entityframeworkcore.tools\2.2.0\tools\about_EntityFrameworkCore.help.txt +microsoft.entityframeworkcore.tools\2.2.0\tools\EntityFrameworkCore.PowerShell2.psd1 +microsoft.entityframeworkcore.tools\2.2.0\tools\EntityFrameworkCore.PowerShell2.psm1 +microsoft.entityframeworkcore.tools\2.2.0\tools\EntityFrameworkCore.psd1 +microsoft.entityframeworkcore.tools\2.2.0\tools\EntityFrameworkCore.psm1 +microsoft.entityframeworkcore.tools\2.2.0\tools\init.ps1 +microsoft.entityframeworkcore.tools\2.2.0\tools\install.ps1 +microsoft.entityframeworkcore.tools\2.2.0\tools\net461\any\ef.exe +microsoft.entityframeworkcore.tools\2.2.0\tools\net461\win-x86\ef.exe +microsoft.entityframeworkcore.tools\2.2.0\tools\netcoreapp2.0\any\ef.dll +microsoft.entityframeworkcore.tools\2.2.0\tools\netcoreapp2.0\any\ef.runtimeconfig.json +microsoft.entityframeworkcore\2.2.0\.nupkg.metadata +microsoft.entityframeworkcore\2.2.0\.signature.p7s +microsoft.entityframeworkcore\2.2.0\lib\netstandard2.0\Microsoft.EntityFrameworkCore.dll +microsoft.entityframeworkcore\2.2.0\microsoft.entityframeworkcore.2.2.0.nupkg.sha512 +microsoft.entityframeworkcore\2.2.0\microsoft.entityframeworkcore.nuspec +microsoft.extensions.caching.abstractions\2.2.0\.nupkg.metadata +microsoft.extensions.caching.abstractions\2.2.0\.signature.p7s +microsoft.extensions.caching.abstractions\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Caching.Abstractions.dll +microsoft.extensions.caching.abstractions\2.2.0\microsoft.extensions.caching.abstractions.2.2.0.nupkg.sha512 +microsoft.extensions.caching.abstractions\2.2.0\microsoft.extensions.caching.abstractions.nuspec +microsoft.extensions.caching.memory\2.2.0\.nupkg.metadata +microsoft.extensions.caching.memory\2.2.0\.signature.p7s +microsoft.extensions.caching.memory\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Caching.Memory.dll +microsoft.extensions.caching.memory\2.2.0\microsoft.extensions.caching.memory.2.2.0.nupkg.sha512 +microsoft.extensions.caching.memory\2.2.0\microsoft.extensions.caching.memory.nuspec +microsoft.extensions.caching.redis\2.2.0\.nupkg.metadata +microsoft.extensions.caching.redis\2.2.0\.signature.p7s +microsoft.extensions.caching.redis\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Caching.Redis.dll +microsoft.extensions.caching.redis\2.2.0\microsoft.extensions.caching.redis.2.2.0.nupkg.sha512 +microsoft.extensions.caching.redis\2.2.0\microsoft.extensions.caching.redis.nuspec +microsoft.extensions.caching.sqlserver\2.2.0\.nupkg.metadata +microsoft.extensions.caching.sqlserver\2.2.0\.signature.p7s +microsoft.extensions.caching.sqlserver\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Caching.SqlServer.dll +microsoft.extensions.caching.sqlserver\2.2.0\microsoft.extensions.caching.sqlserver.2.2.0.nupkg.sha512 +microsoft.extensions.caching.sqlserver\2.2.0\microsoft.extensions.caching.sqlserver.nuspec +microsoft.extensions.configuration.abstractions\2.2.0\.nupkg.metadata +microsoft.extensions.configuration.abstractions\2.2.0\.signature.p7s +microsoft.extensions.configuration.abstractions\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Abstractions.dll +microsoft.extensions.configuration.abstractions\2.2.0\microsoft.extensions.configuration.abstractions.2.2.0.nupkg.sha512 +microsoft.extensions.configuration.abstractions\2.2.0\microsoft.extensions.configuration.abstractions.nuspec +microsoft.extensions.configuration.azurekeyvault\2.2.0\.nupkg.metadata +microsoft.extensions.configuration.azurekeyvault\2.2.0\.signature.p7s +microsoft.extensions.configuration.azurekeyvault\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.AzureKeyVault.dll +microsoft.extensions.configuration.azurekeyvault\2.2.0\microsoft.extensions.configuration.azurekeyvault.2.2.0.nupkg.sha512 +microsoft.extensions.configuration.azurekeyvault\2.2.0\microsoft.extensions.configuration.azurekeyvault.nuspec +microsoft.extensions.configuration.binder\2.2.0\.nupkg.metadata +microsoft.extensions.configuration.binder\2.2.0\.signature.p7s +microsoft.extensions.configuration.binder\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Binder.dll +microsoft.extensions.configuration.binder\2.2.0\microsoft.extensions.configuration.binder.2.2.0.nupkg.sha512 +microsoft.extensions.configuration.binder\2.2.0\microsoft.extensions.configuration.binder.nuspec +microsoft.extensions.configuration.commandline\2.2.0\.nupkg.metadata +microsoft.extensions.configuration.commandline\2.2.0\.signature.p7s +microsoft.extensions.configuration.commandline\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.CommandLine.dll +microsoft.extensions.configuration.commandline\2.2.0\microsoft.extensions.configuration.commandline.2.2.0.nupkg.sha512 +microsoft.extensions.configuration.commandline\2.2.0\microsoft.extensions.configuration.commandline.nuspec +microsoft.extensions.configuration.environmentvariables\2.2.0\.nupkg.metadata +microsoft.extensions.configuration.environmentvariables\2.2.0\.signature.p7s +microsoft.extensions.configuration.environmentvariables\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.EnvironmentVariables.dll +microsoft.extensions.configuration.environmentvariables\2.2.0\microsoft.extensions.configuration.environmentvariables.2.2.0.nupkg.sha512 +microsoft.extensions.configuration.environmentvariables\2.2.0\microsoft.extensions.configuration.environmentvariables.nuspec +microsoft.extensions.configuration.fileextensions\2.2.0\.nupkg.metadata +microsoft.extensions.configuration.fileextensions\2.2.0\.signature.p7s +microsoft.extensions.configuration.fileextensions\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.FileExtensions.dll +microsoft.extensions.configuration.fileextensions\2.2.0\microsoft.extensions.configuration.fileextensions.2.2.0.nupkg.sha512 +microsoft.extensions.configuration.fileextensions\2.2.0\microsoft.extensions.configuration.fileextensions.nuspec +microsoft.extensions.configuration.ini\2.2.0\.nupkg.metadata +microsoft.extensions.configuration.ini\2.2.0\.signature.p7s +microsoft.extensions.configuration.ini\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Ini.dll +microsoft.extensions.configuration.ini\2.2.0\microsoft.extensions.configuration.ini.2.2.0.nupkg.sha512 +microsoft.extensions.configuration.ini\2.2.0\microsoft.extensions.configuration.ini.nuspec +microsoft.extensions.configuration.json\2.2.0\.nupkg.metadata +microsoft.extensions.configuration.json\2.2.0\.signature.p7s +microsoft.extensions.configuration.json\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Json.dll +microsoft.extensions.configuration.json\2.2.0\microsoft.extensions.configuration.json.2.2.0.nupkg.sha512 +microsoft.extensions.configuration.json\2.2.0\microsoft.extensions.configuration.json.nuspec +microsoft.extensions.configuration.keyperfile\2.2.0\.nupkg.metadata +microsoft.extensions.configuration.keyperfile\2.2.0\.signature.p7s +microsoft.extensions.configuration.keyperfile\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.KeyPerFile.dll +microsoft.extensions.configuration.keyperfile\2.2.0\microsoft.extensions.configuration.keyperfile.2.2.0.nupkg.sha512 +microsoft.extensions.configuration.keyperfile\2.2.0\microsoft.extensions.configuration.keyperfile.nuspec +microsoft.extensions.configuration.usersecrets\2.2.0\.nupkg.metadata +microsoft.extensions.configuration.usersecrets\2.2.0\.signature.p7s +microsoft.extensions.configuration.usersecrets\2.2.0\build\netstandard2.0\Microsoft.Extensions.Configuration.UserSecrets.props +microsoft.extensions.configuration.usersecrets\2.2.0\build\netstandard2.0\Microsoft.Extensions.Configuration.UserSecrets.targets +microsoft.extensions.configuration.usersecrets\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.UserSecrets.dll +microsoft.extensions.configuration.usersecrets\2.2.0\microsoft.extensions.configuration.usersecrets.2.2.0.nupkg.sha512 +microsoft.extensions.configuration.usersecrets\2.2.0\microsoft.extensions.configuration.usersecrets.nuspec +microsoft.extensions.configuration.xml\2.2.0\.nupkg.metadata +microsoft.extensions.configuration.xml\2.2.0\.signature.p7s +microsoft.extensions.configuration.xml\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Xml.dll +microsoft.extensions.configuration.xml\2.2.0\microsoft.extensions.configuration.xml.2.2.0.nupkg.sha512 +microsoft.extensions.configuration.xml\2.2.0\microsoft.extensions.configuration.xml.nuspec +microsoft.extensions.configuration\2.2.0\.nupkg.metadata +microsoft.extensions.configuration\2.2.0\.signature.p7s +microsoft.extensions.configuration\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.dll +microsoft.extensions.configuration\2.2.0\microsoft.extensions.configuration.2.2.0.nupkg.sha512 +microsoft.extensions.configuration\2.2.0\microsoft.extensions.configuration.nuspec +microsoft.extensions.dependencyinjection.abstractions\2.2.0\.nupkg.metadata +microsoft.extensions.dependencyinjection.abstractions\2.2.0\.signature.p7s +microsoft.extensions.dependencyinjection.abstractions\2.2.0\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll +microsoft.extensions.dependencyinjection.abstractions\2.2.0\microsoft.extensions.dependencyinjection.abstractions.2.2.0.nupkg.sha512 +microsoft.extensions.dependencyinjection.abstractions\2.2.0\microsoft.extensions.dependencyinjection.abstractions.nuspec +microsoft.extensions.dependencyinjection\2.2.0\.nupkg.metadata +microsoft.extensions.dependencyinjection\2.2.0\.signature.p7s +microsoft.extensions.dependencyinjection\2.2.0\lib\net461\Microsoft.Extensions.DependencyInjection.dll +microsoft.extensions.dependencyinjection\2.2.0\lib\netcoreapp2.0\Microsoft.Extensions.DependencyInjection.dll +microsoft.extensions.dependencyinjection\2.2.0\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.dll +microsoft.extensions.dependencyinjection\2.2.0\microsoft.extensions.dependencyinjection.2.2.0.nupkg.sha512 +microsoft.extensions.dependencyinjection\2.2.0\microsoft.extensions.dependencyinjection.nuspec +microsoft.extensions.dependencymodel\2.1.0\.nupkg.metadata +microsoft.extensions.diagnosticadapter\2.2.0\.nupkg.metadata +microsoft.extensions.diagnosticadapter\2.2.0\.signature.p7s +microsoft.extensions.diagnosticadapter\2.2.0\lib\net461\Microsoft.Extensions.DiagnosticAdapter.dll +microsoft.extensions.diagnosticadapter\2.2.0\lib\netcoreapp2.0\Microsoft.Extensions.DiagnosticAdapter.dll +microsoft.extensions.diagnosticadapter\2.2.0\lib\netstandard2.0\Microsoft.Extensions.DiagnosticAdapter.dll +microsoft.extensions.diagnosticadapter\2.2.0\microsoft.extensions.diagnosticadapter.2.2.0.nupkg.sha512 +microsoft.extensions.diagnosticadapter\2.2.0\microsoft.extensions.diagnosticadapter.nuspec +microsoft.extensions.diagnostics.healthchecks.abstractions\2.2.0\.nupkg.metadata +microsoft.extensions.diagnostics.healthchecks.abstractions\2.2.0\.signature.p7s +microsoft.extensions.diagnostics.healthchecks.abstractions\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions.dll +microsoft.extensions.diagnostics.healthchecks.abstractions\2.2.0\microsoft.extensions.diagnostics.healthchecks.abstractions.2.2.0.nupkg.sha512 +microsoft.extensions.diagnostics.healthchecks.abstractions\2.2.0\microsoft.extensions.diagnostics.healthchecks.abstractions.nuspec +microsoft.extensions.diagnostics.healthchecks\2.2.0\.nupkg.metadata +microsoft.extensions.diagnostics.healthchecks\2.2.0\.signature.p7s +microsoft.extensions.diagnostics.healthchecks\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Diagnostics.HealthChecks.dll +microsoft.extensions.diagnostics.healthchecks\2.2.0\microsoft.extensions.diagnostics.healthchecks.2.2.0.nupkg.sha512 +microsoft.extensions.diagnostics.healthchecks\2.2.0\microsoft.extensions.diagnostics.healthchecks.nuspec +microsoft.extensions.fileproviders.abstractions\2.2.0\.nupkg.metadata +microsoft.extensions.fileproviders.abstractions\2.2.0\.signature.p7s +microsoft.extensions.fileproviders.abstractions\2.2.0\lib\netstandard2.0\Microsoft.Extensions.FileProviders.Abstractions.dll +microsoft.extensions.fileproviders.abstractions\2.2.0\microsoft.extensions.fileproviders.abstractions.2.2.0.nupkg.sha512 +microsoft.extensions.fileproviders.abstractions\2.2.0\microsoft.extensions.fileproviders.abstractions.nuspec +microsoft.extensions.fileproviders.composite\2.2.0\.nupkg.metadata +microsoft.extensions.fileproviders.composite\2.2.0\.signature.p7s +microsoft.extensions.fileproviders.composite\2.2.0\lib\netstandard2.0\Microsoft.Extensions.FileProviders.Composite.dll +microsoft.extensions.fileproviders.composite\2.2.0\microsoft.extensions.fileproviders.composite.2.2.0.nupkg.sha512 +microsoft.extensions.fileproviders.composite\2.2.0\microsoft.extensions.fileproviders.composite.nuspec +microsoft.extensions.fileproviders.embedded\2.2.0\.nupkg.metadata +microsoft.extensions.fileproviders.embedded\2.2.0\.signature.p7s +microsoft.extensions.fileproviders.embedded\2.2.0\build\netstandard2.0\Microsoft.Extensions.FileProviders.Embedded.props +microsoft.extensions.fileproviders.embedded\2.2.0\build\netstandard2.0\Microsoft.Extensions.FileProviders.Embedded.targets +microsoft.extensions.fileproviders.embedded\2.2.0\buildMultiTargeting\Microsoft.Extensions.FileProviders.Embedded.props +microsoft.extensions.fileproviders.embedded\2.2.0\buildMultiTargeting\Microsoft.Extensions.FileProviders.Embedded.targets +microsoft.extensions.fileproviders.embedded\2.2.0\lib\netstandard2.0\Microsoft.Extensions.FileProviders.Embedded.dll +microsoft.extensions.fileproviders.embedded\2.2.0\microsoft.extensions.fileproviders.embedded.2.2.0.nupkg.sha512 +microsoft.extensions.fileproviders.embedded\2.2.0\microsoft.extensions.fileproviders.embedded.nuspec +microsoft.extensions.fileproviders.embedded\2.2.0\tasks\net461\Microsoft.Extensions.FileProviders.Embedded.Manifest.Task.dll +microsoft.extensions.fileproviders.embedded\2.2.0\tasks\netstandard1.5\Microsoft.Extensions.FileProviders.Embedded.Manifest.Task.dll +microsoft.extensions.fileproviders.physical\2.2.0\.nupkg.metadata +microsoft.extensions.fileproviders.physical\2.2.0\.signature.p7s +microsoft.extensions.fileproviders.physical\2.2.0\lib\netstandard2.0\Microsoft.Extensions.FileProviders.Physical.dll +microsoft.extensions.fileproviders.physical\2.2.0\microsoft.extensions.fileproviders.physical.2.2.0.nupkg.sha512 +microsoft.extensions.fileproviders.physical\2.2.0\microsoft.extensions.fileproviders.physical.nuspec +microsoft.extensions.filesystemglobbing\2.2.0\.nupkg.metadata +microsoft.extensions.filesystemglobbing\2.2.0\.signature.p7s +microsoft.extensions.filesystemglobbing\2.2.0\lib\netstandard2.0\Microsoft.Extensions.FileSystemGlobbing.dll +microsoft.extensions.filesystemglobbing\2.2.0\microsoft.extensions.filesystemglobbing.2.2.0.nupkg.sha512 +microsoft.extensions.filesystemglobbing\2.2.0\microsoft.extensions.filesystemglobbing.nuspec +microsoft.extensions.hosting.abstractions\2.2.0\.nupkg.metadata +microsoft.extensions.hosting.abstractions\2.2.0\.signature.p7s +microsoft.extensions.hosting.abstractions\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Hosting.Abstractions.dll +microsoft.extensions.hosting.abstractions\2.2.0\microsoft.extensions.hosting.abstractions.2.2.0.nupkg.sha512 +microsoft.extensions.hosting.abstractions\2.2.0\microsoft.extensions.hosting.abstractions.nuspec +microsoft.extensions.hosting\2.2.0\.nupkg.metadata +microsoft.extensions.hosting\2.2.0\.signature.p7s +microsoft.extensions.hosting\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Hosting.dll +microsoft.extensions.hosting\2.2.0\microsoft.extensions.hosting.2.2.0.nupkg.sha512 +microsoft.extensions.hosting\2.2.0\microsoft.extensions.hosting.nuspec +microsoft.extensions.http\2.2.0\.nupkg.metadata +microsoft.extensions.http\2.2.0\.signature.p7s +microsoft.extensions.http\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Http.dll +microsoft.extensions.http\2.2.0\microsoft.extensions.http.2.2.0.nupkg.sha512 +microsoft.extensions.http\2.2.0\microsoft.extensions.http.nuspec +microsoft.extensions.identity.core\2.2.0\.nupkg.metadata +microsoft.extensions.identity.core\2.2.0\.signature.p7s +microsoft.extensions.identity.core\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Identity.Core.dll +microsoft.extensions.identity.core\2.2.0\microsoft.extensions.identity.core.2.2.0.nupkg.sha512 +microsoft.extensions.identity.core\2.2.0\microsoft.extensions.identity.core.nuspec +microsoft.extensions.identity.stores\2.2.0\.nupkg.metadata +microsoft.extensions.identity.stores\2.2.0\.signature.p7s +microsoft.extensions.identity.stores\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Identity.Stores.dll +microsoft.extensions.identity.stores\2.2.0\microsoft.extensions.identity.stores.2.2.0.nupkg.sha512 +microsoft.extensions.identity.stores\2.2.0\microsoft.extensions.identity.stores.nuspec +microsoft.extensions.localization.abstractions\2.2.0\.nupkg.metadata +microsoft.extensions.localization.abstractions\2.2.0\.signature.p7s +microsoft.extensions.localization.abstractions\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Localization.Abstractions.dll +microsoft.extensions.localization.abstractions\2.2.0\microsoft.extensions.localization.abstractions.2.2.0.nupkg.sha512 +microsoft.extensions.localization.abstractions\2.2.0\microsoft.extensions.localization.abstractions.nuspec +microsoft.extensions.localization\2.2.0\.nupkg.metadata +microsoft.extensions.localization\2.2.0\.signature.p7s +microsoft.extensions.localization\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Localization.dll +microsoft.extensions.localization\2.2.0\microsoft.extensions.localization.2.2.0.nupkg.sha512 +microsoft.extensions.localization\2.2.0\microsoft.extensions.localization.nuspec +microsoft.extensions.logging.abstractions\2.2.0\.nupkg.metadata +microsoft.extensions.logging.abstractions\2.2.0\.signature.p7s +microsoft.extensions.logging.abstractions\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.dll +microsoft.extensions.logging.abstractions\2.2.0\microsoft.extensions.logging.abstractions.2.2.0.nupkg.sha512 +microsoft.extensions.logging.abstractions\2.2.0\microsoft.extensions.logging.abstractions.nuspec +microsoft.extensions.logging.azureappservices\2.2.0\.nupkg.metadata +microsoft.extensions.logging.azureappservices\2.2.0\.signature.p7s +microsoft.extensions.logging.azureappservices\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Logging.AzureAppServices.dll +microsoft.extensions.logging.azureappservices\2.2.0\microsoft.extensions.logging.azureappservices.2.2.0.nupkg.sha512 +microsoft.extensions.logging.azureappservices\2.2.0\microsoft.extensions.logging.azureappservices.nuspec +microsoft.extensions.logging.configuration\2.2.0\.nupkg.metadata +microsoft.extensions.logging.configuration\2.2.0\.signature.p7s +microsoft.extensions.logging.configuration\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Logging.Configuration.dll +microsoft.extensions.logging.configuration\2.2.0\microsoft.extensions.logging.configuration.2.2.0.nupkg.sha512 +microsoft.extensions.logging.configuration\2.2.0\microsoft.extensions.logging.configuration.nuspec +microsoft.extensions.logging.console\2.2.0\.nupkg.metadata +microsoft.extensions.logging.console\2.2.0\.signature.p7s +microsoft.extensions.logging.console\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Logging.Console.dll +microsoft.extensions.logging.console\2.2.0\microsoft.extensions.logging.console.2.2.0.nupkg.sha512 +microsoft.extensions.logging.console\2.2.0\microsoft.extensions.logging.console.nuspec +microsoft.extensions.logging.debug\2.2.0\.nupkg.metadata +microsoft.extensions.logging.debug\2.2.0\.signature.p7s +microsoft.extensions.logging.debug\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Logging.Debug.dll +microsoft.extensions.logging.debug\2.2.0\microsoft.extensions.logging.debug.2.2.0.nupkg.sha512 +microsoft.extensions.logging.debug\2.2.0\microsoft.extensions.logging.debug.nuspec +microsoft.extensions.logging.eventsource\2.2.0\.nupkg.metadata +microsoft.extensions.logging.eventsource\2.2.0\.signature.p7s +microsoft.extensions.logging.eventsource\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Logging.EventSource.dll +microsoft.extensions.logging.eventsource\2.2.0\microsoft.extensions.logging.eventsource.2.2.0.nupkg.sha512 +microsoft.extensions.logging.eventsource\2.2.0\microsoft.extensions.logging.eventsource.nuspec +microsoft.extensions.logging.tracesource\2.2.0\.nupkg.metadata +microsoft.extensions.logging.tracesource\2.2.0\.signature.p7s +microsoft.extensions.logging.tracesource\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Logging.TraceSource.dll +microsoft.extensions.logging.tracesource\2.2.0\microsoft.extensions.logging.tracesource.2.2.0.nupkg.sha512 +microsoft.extensions.logging.tracesource\2.2.0\microsoft.extensions.logging.tracesource.nuspec +microsoft.extensions.logging\2.2.0\.nupkg.metadata +microsoft.extensions.logging\2.2.0\.signature.p7s +microsoft.extensions.logging\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Logging.dll +microsoft.extensions.logging\2.2.0\microsoft.extensions.logging.2.2.0.nupkg.sha512 +microsoft.extensions.logging\2.2.0\microsoft.extensions.logging.nuspec +microsoft.extensions.objectpool\2.2.0\.nupkg.metadata +microsoft.extensions.objectpool\2.2.0\.signature.p7s +microsoft.extensions.objectpool\2.2.0\lib\netstandard2.0\Microsoft.Extensions.ObjectPool.dll +microsoft.extensions.objectpool\2.2.0\microsoft.extensions.objectpool.2.2.0.nupkg.sha512 +microsoft.extensions.objectpool\2.2.0\microsoft.extensions.objectpool.nuspec +microsoft.extensions.options.configurationextensions\2.2.0\.nupkg.metadata +microsoft.extensions.options.configurationextensions\2.2.0\.signature.p7s +microsoft.extensions.options.configurationextensions\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Options.ConfigurationExtensions.dll +microsoft.extensions.options.configurationextensions\2.2.0\microsoft.extensions.options.configurationextensions.2.2.0.nupkg.sha512 +microsoft.extensions.options.configurationextensions\2.2.0\microsoft.extensions.options.configurationextensions.nuspec +microsoft.extensions.options.dataannotations\2.2.0\.nupkg.metadata +microsoft.extensions.options.dataannotations\2.2.0\.signature.p7s +microsoft.extensions.options.dataannotations\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Options.DataAnnotations.dll +microsoft.extensions.options.dataannotations\2.2.0\microsoft.extensions.options.dataannotations.2.2.0.nupkg.sha512 +microsoft.extensions.options.dataannotations\2.2.0\microsoft.extensions.options.dataannotations.nuspec +microsoft.extensions.options\2.2.0\.nupkg.metadata +microsoft.extensions.options\2.2.0\.signature.p7s +microsoft.extensions.options\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Options.dll +microsoft.extensions.options\2.2.0\microsoft.extensions.options.2.2.0.nupkg.sha512 +microsoft.extensions.options\2.2.0\microsoft.extensions.options.nuspec +microsoft.extensions.platformabstractions\1.1.0\.nupkg.metadata +microsoft.extensions.primitives\2.2.0\.nupkg.metadata +microsoft.extensions.primitives\2.2.0\.signature.p7s +microsoft.extensions.primitives\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll +microsoft.extensions.primitives\2.2.0\microsoft.extensions.primitives.2.2.0.nupkg.sha512 +microsoft.extensions.primitives\2.2.0\microsoft.extensions.primitives.nuspec +microsoft.extensions.webencoders\2.2.0\.nupkg.metadata +microsoft.extensions.webencoders\2.2.0\.signature.p7s +microsoft.extensions.webencoders\2.2.0\lib\netstandard2.0\Microsoft.Extensions.WebEncoders.dll +microsoft.extensions.webencoders\2.2.0\microsoft.extensions.webencoders.2.2.0.nupkg.sha512 +microsoft.extensions.webencoders\2.2.0\microsoft.extensions.webencoders.nuspec +microsoft.identitymodel.clients.activedirectory\3.14.2\.nupkg.metadata +microsoft.identitymodel.clients.activedirectory\3.14.2\.signature.p7s +microsoft.identitymodel.clients.activedirectory\3.19.8\.nupkg.metadata +microsoft.identitymodel.clients.activedirectory\3.19.8\.signature.p7s +microsoft.identitymodel.clients.activedirectory\3.19.8\lib\MonoAndroid7\Microsoft.IdentityModel.Clients.ActiveDirectory.dll +microsoft.identitymodel.clients.activedirectory\3.19.8\lib\MonoAndroid7\Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll +microsoft.identitymodel.clients.activedirectory\3.19.8\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll +microsoft.identitymodel.clients.activedirectory\3.19.8\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll +microsoft.identitymodel.clients.activedirectory\3.19.8\lib\netcore45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll +microsoft.identitymodel.clients.activedirectory\3.19.8\lib\netcore45\Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll +microsoft.identitymodel.clients.activedirectory\3.19.8\lib\netstandard1.1\Microsoft.IdentityModel.Clients.ActiveDirectory.dll +microsoft.identitymodel.clients.activedirectory\3.19.8\lib\netstandard1.1\Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll +microsoft.identitymodel.clients.activedirectory\3.19.8\lib\netstandard1.3\Microsoft.IdentityModel.Clients.ActiveDirectory.dll +microsoft.identitymodel.clients.activedirectory\3.19.8\lib\netstandard1.3\Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll +microsoft.identitymodel.clients.activedirectory\3.19.8\lib\portable-net45+win\Microsoft.IdentityModel.Clients.ActiveDirectory.dll +microsoft.identitymodel.clients.activedirectory\3.19.8\lib\portable-net45+win\Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll +microsoft.identitymodel.clients.activedirectory\3.19.8\lib\Xamarin.iOS10\Microsoft.IdentityModel.Clients.ActiveDirectory.dll +microsoft.identitymodel.clients.activedirectory\3.19.8\lib\Xamarin.iOS10\Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll +microsoft.identitymodel.clients.activedirectory\3.19.8\microsoft.identitymodel.clients.activedirectory.3.19.8.nupkg.sha512 +microsoft.identitymodel.clients.activedirectory\3.19.8\microsoft.identitymodel.clients.activedirectory.nuspec +microsoft.identitymodel.jsonwebtokens\5.3.0\.nupkg.metadata +microsoft.identitymodel.jsonwebtokens\5.3.0\.signature.p7s +microsoft.identitymodel.jsonwebtokens\5.3.0\lib\net45\Microsoft.IdentityModel.JsonWebTokens.dll +microsoft.identitymodel.jsonwebtokens\5.3.0\lib\net45\Microsoft.IdentityModel.JsonWebTokens.pdb +microsoft.identitymodel.jsonwebtokens\5.3.0\lib\net451\Microsoft.IdentityModel.JsonWebTokens.dll +microsoft.identitymodel.jsonwebtokens\5.3.0\lib\net451\Microsoft.IdentityModel.JsonWebTokens.pdb +microsoft.identitymodel.jsonwebtokens\5.3.0\lib\net461\Microsoft.IdentityModel.JsonWebTokens.dll +microsoft.identitymodel.jsonwebtokens\5.3.0\lib\net461\Microsoft.IdentityModel.JsonWebTokens.pdb +microsoft.identitymodel.jsonwebtokens\5.3.0\lib\netstandard1.4\Microsoft.IdentityModel.JsonWebTokens.dll +microsoft.identitymodel.jsonwebtokens\5.3.0\lib\netstandard1.4\Microsoft.IdentityModel.JsonWebTokens.pdb +microsoft.identitymodel.jsonwebtokens\5.3.0\lib\netstandard2.0\Microsoft.IdentityModel.JsonWebTokens.dll +microsoft.identitymodel.jsonwebtokens\5.3.0\lib\netstandard2.0\Microsoft.IdentityModel.JsonWebTokens.pdb +microsoft.identitymodel.jsonwebtokens\5.3.0\microsoft.identitymodel.jsonwebtokens.5.3.0.nupkg.sha512 +microsoft.identitymodel.jsonwebtokens\5.3.0\microsoft.identitymodel.jsonwebtokens.nuspec +microsoft.identitymodel.logging\5.3.0\.nupkg.metadata +microsoft.identitymodel.logging\5.3.0\.signature.p7s +microsoft.identitymodel.logging\5.3.0\lib\net45\Microsoft.IdentityModel.Logging.dll +microsoft.identitymodel.logging\5.3.0\lib\net45\Microsoft.IdentityModel.Logging.pdb +microsoft.identitymodel.logging\5.3.0\lib\net451\Microsoft.IdentityModel.Logging.dll +microsoft.identitymodel.logging\5.3.0\lib\net451\Microsoft.IdentityModel.Logging.pdb +microsoft.identitymodel.logging\5.3.0\lib\net461\Microsoft.IdentityModel.Logging.dll +microsoft.identitymodel.logging\5.3.0\lib\net461\Microsoft.IdentityModel.Logging.pdb +microsoft.identitymodel.logging\5.3.0\lib\netstandard1.4\Microsoft.IdentityModel.Logging.dll +microsoft.identitymodel.logging\5.3.0\lib\netstandard1.4\Microsoft.IdentityModel.Logging.pdb +microsoft.identitymodel.logging\5.3.0\lib\netstandard2.0\Microsoft.IdentityModel.Logging.dll +microsoft.identitymodel.logging\5.3.0\lib\netstandard2.0\Microsoft.IdentityModel.Logging.pdb +microsoft.identitymodel.logging\5.3.0\microsoft.identitymodel.logging.5.3.0.nupkg.sha512 +microsoft.identitymodel.logging\5.3.0\microsoft.identitymodel.logging.nuspec +microsoft.identitymodel.protocols.openidconnect\5.3.0\.nupkg.metadata +microsoft.identitymodel.protocols.openidconnect\5.3.0\.signature.p7s +microsoft.identitymodel.protocols.openidconnect\5.3.0\lib\net45\Microsoft.IdentityModel.Protocols.OpenIdConnect.dll +microsoft.identitymodel.protocols.openidconnect\5.3.0\lib\net45\Microsoft.IdentityModel.Protocols.OpenIdConnect.pdb +microsoft.identitymodel.protocols.openidconnect\5.3.0\lib\net451\Microsoft.IdentityModel.Protocols.OpenIdConnect.dll +microsoft.identitymodel.protocols.openidconnect\5.3.0\lib\net451\Microsoft.IdentityModel.Protocols.OpenIdConnect.pdb +microsoft.identitymodel.protocols.openidconnect\5.3.0\lib\net461\Microsoft.IdentityModel.Protocols.OpenIdConnect.dll +microsoft.identitymodel.protocols.openidconnect\5.3.0\lib\net461\Microsoft.IdentityModel.Protocols.OpenIdConnect.pdb +microsoft.identitymodel.protocols.openidconnect\5.3.0\lib\netstandard1.4\Microsoft.IdentityModel.Protocols.OpenIdConnect.dll +microsoft.identitymodel.protocols.openidconnect\5.3.0\lib\netstandard1.4\Microsoft.IdentityModel.Protocols.OpenIdConnect.pdb +microsoft.identitymodel.protocols.openidconnect\5.3.0\lib\netstandard2.0\Microsoft.IdentityModel.Protocols.OpenIdConnect.dll +microsoft.identitymodel.protocols.openidconnect\5.3.0\lib\netstandard2.0\Microsoft.IdentityModel.Protocols.OpenIdConnect.pdb +microsoft.identitymodel.protocols.openidconnect\5.3.0\microsoft.identitymodel.protocols.openidconnect.5.3.0.nupkg.sha512 +microsoft.identitymodel.protocols.openidconnect\5.3.0\microsoft.identitymodel.protocols.openidconnect.nuspec +microsoft.identitymodel.protocols.wsfederation\5.3.0\.nupkg.metadata +microsoft.identitymodel.protocols.wsfederation\5.3.0\.signature.p7s +microsoft.identitymodel.protocols.wsfederation\5.3.0\lib\net45\Microsoft.IdentityModel.Protocols.WsFederation.dll +microsoft.identitymodel.protocols.wsfederation\5.3.0\lib\net45\Microsoft.IdentityModel.Protocols.WsFederation.pdb +microsoft.identitymodel.protocols.wsfederation\5.3.0\lib\net451\Microsoft.IdentityModel.Protocols.WsFederation.dll +microsoft.identitymodel.protocols.wsfederation\5.3.0\lib\net451\Microsoft.IdentityModel.Protocols.WsFederation.pdb +microsoft.identitymodel.protocols.wsfederation\5.3.0\lib\net461\Microsoft.IdentityModel.Protocols.WsFederation.dll +microsoft.identitymodel.protocols.wsfederation\5.3.0\lib\net461\Microsoft.IdentityModel.Protocols.WsFederation.pdb +microsoft.identitymodel.protocols.wsfederation\5.3.0\lib\netstandard1.4\Microsoft.IdentityModel.Protocols.WsFederation.dll +microsoft.identitymodel.protocols.wsfederation\5.3.0\lib\netstandard1.4\Microsoft.IdentityModel.Protocols.WsFederation.pdb +microsoft.identitymodel.protocols.wsfederation\5.3.0\lib\netstandard2.0\Microsoft.IdentityModel.Protocols.WsFederation.dll +microsoft.identitymodel.protocols.wsfederation\5.3.0\lib\netstandard2.0\Microsoft.IdentityModel.Protocols.WsFederation.pdb +microsoft.identitymodel.protocols.wsfederation\5.3.0\microsoft.identitymodel.protocols.wsfederation.5.3.0.nupkg.sha512 +microsoft.identitymodel.protocols.wsfederation\5.3.0\microsoft.identitymodel.protocols.wsfederation.nuspec +microsoft.identitymodel.protocols\5.3.0\.nupkg.metadata +microsoft.identitymodel.protocols\5.3.0\.signature.p7s +microsoft.identitymodel.protocols\5.3.0\lib\net45\Microsoft.IdentityModel.Protocols.dll +microsoft.identitymodel.protocols\5.3.0\lib\net45\Microsoft.IdentityModel.Protocols.pdb +microsoft.identitymodel.protocols\5.3.0\lib\net451\Microsoft.IdentityModel.Protocols.dll +microsoft.identitymodel.protocols\5.3.0\lib\net451\Microsoft.IdentityModel.Protocols.pdb +microsoft.identitymodel.protocols\5.3.0\lib\net461\Microsoft.IdentityModel.Protocols.dll +microsoft.identitymodel.protocols\5.3.0\lib\net461\Microsoft.IdentityModel.Protocols.pdb +microsoft.identitymodel.protocols\5.3.0\lib\netstandard1.4\Microsoft.IdentityModel.Protocols.dll +microsoft.identitymodel.protocols\5.3.0\lib\netstandard1.4\Microsoft.IdentityModel.Protocols.pdb +microsoft.identitymodel.protocols\5.3.0\lib\netstandard2.0\Microsoft.IdentityModel.Protocols.dll +microsoft.identitymodel.protocols\5.3.0\lib\netstandard2.0\Microsoft.IdentityModel.Protocols.pdb +microsoft.identitymodel.protocols\5.3.0\microsoft.identitymodel.protocols.5.3.0.nupkg.sha512 +microsoft.identitymodel.protocols\5.3.0\microsoft.identitymodel.protocols.nuspec +microsoft.identitymodel.tokens.saml\5.3.0\.nupkg.metadata +microsoft.identitymodel.tokens.saml\5.3.0\.signature.p7s +microsoft.identitymodel.tokens.saml\5.3.0\lib\net45\Microsoft.IdentityModel.Tokens.Saml.dll +microsoft.identitymodel.tokens.saml\5.3.0\lib\net45\Microsoft.IdentityModel.Tokens.Saml.pdb +microsoft.identitymodel.tokens.saml\5.3.0\lib\net451\Microsoft.IdentityModel.Tokens.Saml.dll +microsoft.identitymodel.tokens.saml\5.3.0\lib\net451\Microsoft.IdentityModel.Tokens.Saml.pdb +microsoft.identitymodel.tokens.saml\5.3.0\lib\net461\Microsoft.IdentityModel.Tokens.Saml.dll +microsoft.identitymodel.tokens.saml\5.3.0\lib\net461\Microsoft.IdentityModel.Tokens.Saml.pdb +microsoft.identitymodel.tokens.saml\5.3.0\lib\netstandard1.4\Microsoft.IdentityModel.Tokens.Saml.dll +microsoft.identitymodel.tokens.saml\5.3.0\lib\netstandard1.4\Microsoft.IdentityModel.Tokens.Saml.pdb +microsoft.identitymodel.tokens.saml\5.3.0\lib\netstandard2.0\Microsoft.IdentityModel.Tokens.Saml.dll +microsoft.identitymodel.tokens.saml\5.3.0\lib\netstandard2.0\Microsoft.IdentityModel.Tokens.Saml.pdb +microsoft.identitymodel.tokens.saml\5.3.0\microsoft.identitymodel.tokens.saml.5.3.0.nupkg.sha512 +microsoft.identitymodel.tokens.saml\5.3.0\microsoft.identitymodel.tokens.saml.nuspec +microsoft.identitymodel.tokens\5.3.0\.nupkg.metadata +microsoft.identitymodel.tokens\5.3.0\.signature.p7s +microsoft.identitymodel.tokens\5.3.0\lib\net45\Microsoft.IdentityModel.Tokens.dll +microsoft.identitymodel.tokens\5.3.0\lib\net45\Microsoft.IdentityModel.Tokens.pdb +microsoft.identitymodel.tokens\5.3.0\lib\net451\Microsoft.IdentityModel.Tokens.dll +microsoft.identitymodel.tokens\5.3.0\lib\net451\Microsoft.IdentityModel.Tokens.pdb +microsoft.identitymodel.tokens\5.3.0\lib\net461\Microsoft.IdentityModel.Tokens.dll +microsoft.identitymodel.tokens\5.3.0\lib\net461\Microsoft.IdentityModel.Tokens.pdb +microsoft.identitymodel.tokens\5.3.0\lib\netstandard1.4\Microsoft.IdentityModel.Tokens.dll +microsoft.identitymodel.tokens\5.3.0\lib\netstandard1.4\Microsoft.IdentityModel.Tokens.pdb +microsoft.identitymodel.tokens\5.3.0\lib\netstandard2.0\Microsoft.IdentityModel.Tokens.dll +microsoft.identitymodel.tokens\5.3.0\lib\netstandard2.0\Microsoft.IdentityModel.Tokens.pdb +microsoft.identitymodel.tokens\5.3.0\microsoft.identitymodel.tokens.5.3.0.nupkg.sha512 +microsoft.identitymodel.tokens\5.3.0\microsoft.identitymodel.tokens.nuspec +microsoft.identitymodel.xml\5.3.0\.nupkg.metadata +microsoft.identitymodel.xml\5.3.0\.signature.p7s +microsoft.identitymodel.xml\5.3.0\lib\net45\Microsoft.IdentityModel.Xml.dll +microsoft.identitymodel.xml\5.3.0\lib\net45\Microsoft.IdentityModel.Xml.pdb +microsoft.identitymodel.xml\5.3.0\lib\net451\Microsoft.IdentityModel.Xml.dll +microsoft.identitymodel.xml\5.3.0\lib\net451\Microsoft.IdentityModel.Xml.pdb +microsoft.identitymodel.xml\5.3.0\lib\net461\Microsoft.IdentityModel.Xml.dll +microsoft.identitymodel.xml\5.3.0\lib\net461\Microsoft.IdentityModel.Xml.pdb +microsoft.identitymodel.xml\5.3.0\lib\netstandard1.4\Microsoft.IdentityModel.Xml.dll +microsoft.identitymodel.xml\5.3.0\lib\netstandard1.4\Microsoft.IdentityModel.Xml.pdb +microsoft.identitymodel.xml\5.3.0\lib\netstandard2.0\Microsoft.IdentityModel.Xml.dll +microsoft.identitymodel.xml\5.3.0\lib\netstandard2.0\Microsoft.IdentityModel.Xml.pdb +microsoft.identitymodel.xml\5.3.0\microsoft.identitymodel.xml.5.3.0.nupkg.sha512 +microsoft.identitymodel.xml\5.3.0\microsoft.identitymodel.xml.nuspec +microsoft.net.http.headers\2.2.0\.nupkg.metadata +microsoft.net.http.headers\2.2.0\.signature.p7s +microsoft.net.http.headers\2.2.0\lib\netstandard2.0\Microsoft.Net.Http.Headers.dll +microsoft.net.http.headers\2.2.0\microsoft.net.http.headers.2.2.0.nupkg.sha512 +microsoft.net.http.headers\2.2.0\microsoft.net.http.headers.nuspec +microsoft.netcore.app\2.2.0\.nupkg.metadata +microsoft.netcore.app\2.2.0\.signature.p7s +microsoft.netcore.app\2.2.0\build\netcoreapp2.2\Microsoft.NETCore.App.PlatformManifest.txt +microsoft.netcore.app\2.2.0\build\netcoreapp2.2\Microsoft.NETCore.App.props +microsoft.netcore.app\2.2.0\build\netcoreapp2.2\Microsoft.NETCore.App.targets +microsoft.netcore.app\2.2.0\LICENSE.TXT +microsoft.netcore.app\2.2.0\microsoft.netcore.app.2.2.0.nupkg.sha512 +microsoft.netcore.app\2.2.0\microsoft.netcore.app.nuspec +microsoft.netcore.app\2.2.0\Microsoft.NETCore.App.versions.txt +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\Microsoft.CSharp.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\Microsoft.VisualBasic.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\Microsoft.Win32.Primitives.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\mscorlib.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\netstandard.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.AppContext.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Buffers.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Collections.Concurrent.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Collections.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Collections.Immutable.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Collections.NonGeneric.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Collections.Specialized.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.ComponentModel.Annotations.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.ComponentModel.DataAnnotations.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.ComponentModel.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.ComponentModel.EventBasedAsync.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.ComponentModel.Primitives.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.ComponentModel.TypeConverter.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Configuration.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Console.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Core.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Data.Common.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Data.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Diagnostics.Contracts.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Diagnostics.Debug.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Diagnostics.DiagnosticSource.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Diagnostics.FileVersionInfo.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Diagnostics.Process.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Diagnostics.StackTrace.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Diagnostics.TextWriterTraceListener.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Diagnostics.Tools.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Diagnostics.TraceSource.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Diagnostics.Tracing.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Drawing.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Drawing.Primitives.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Dynamic.Runtime.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Globalization.Calendars.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Globalization.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Globalization.Extensions.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.IO.Compression.Brotli.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.IO.Compression.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.IO.Compression.FileSystem.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.IO.Compression.ZipFile.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.IO.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.IO.FileSystem.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.IO.FileSystem.DriveInfo.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.IO.FileSystem.Primitives.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.IO.FileSystem.Watcher.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.IO.IsolatedStorage.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.IO.MemoryMappedFiles.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.IO.Pipes.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.IO.UnmanagedMemoryStream.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Linq.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Linq.Expressions.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Linq.Parallel.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Linq.Queryable.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Memory.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Net.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Net.Http.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Net.HttpListener.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Net.Mail.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Net.NameResolution.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Net.NetworkInformation.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Net.Ping.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Net.Primitives.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Net.Requests.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Net.Security.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Net.ServicePoint.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Net.Sockets.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Net.WebClient.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Net.WebHeaderCollection.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Net.WebProxy.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Net.WebSockets.Client.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Net.WebSockets.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Numerics.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Numerics.Vectors.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.ObjectModel.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Reflection.DispatchProxy.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Reflection.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Reflection.Emit.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Reflection.Emit.ILGeneration.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Reflection.Emit.Lightweight.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Reflection.Extensions.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Reflection.Metadata.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Reflection.Primitives.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Reflection.TypeExtensions.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Resources.Reader.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Resources.ResourceManager.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Resources.Writer.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Runtime.CompilerServices.VisualC.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Runtime.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Runtime.Extensions.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Runtime.Handles.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Runtime.InteropServices.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Runtime.InteropServices.RuntimeInformation.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Runtime.InteropServices.WindowsRuntime.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Runtime.Loader.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Runtime.Numerics.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Runtime.Serialization.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Runtime.Serialization.Formatters.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Runtime.Serialization.Json.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Runtime.Serialization.Primitives.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Runtime.Serialization.Xml.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Security.Claims.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Security.Cryptography.Algorithms.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Security.Cryptography.Csp.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Security.Cryptography.Encoding.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Security.Cryptography.Primitives.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Security.Cryptography.X509Certificates.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Security.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Security.Principal.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Security.SecureString.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.ServiceModel.Web.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.ServiceProcess.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Text.Encoding.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Text.Encoding.Extensions.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Text.RegularExpressions.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Threading.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Threading.Overlapped.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Threading.Tasks.Dataflow.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Threading.Tasks.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Threading.Tasks.Extensions.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Threading.Tasks.Parallel.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Threading.Thread.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Threading.ThreadPool.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Threading.Timer.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Transactions.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Transactions.Local.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.ValueTuple.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Web.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Web.HttpUtility.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Windows.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Xml.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Xml.Linq.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Xml.ReaderWriter.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Xml.Serialization.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Xml.XDocument.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Xml.XmlDocument.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Xml.XmlSerializer.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Xml.XPath.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\System.Xml.XPath.XDocument.dll +microsoft.netcore.app\2.2.0\ref\netcoreapp2.2\WindowsBase.dll +microsoft.netcore.app\2.2.0\runtime.json +microsoft.netcore.app\2.2.0\THIRD-PARTY-NOTICES.TXT +microsoft.netcore.dotnetapphost\2.2.0\.nupkg.metadata +microsoft.netcore.dotnetapphost\2.2.0\.signature.p7s +microsoft.netcore.dotnetapphost\2.2.0\LICENSE.TXT +microsoft.netcore.dotnetapphost\2.2.0\microsoft.netcore.dotnetapphost.2.2.0.nupkg.sha512 +microsoft.netcore.dotnetapphost\2.2.0\microsoft.netcore.dotnetapphost.nuspec +microsoft.netcore.dotnetapphost\2.2.0\runtime.json +microsoft.netcore.dotnetapphost\2.2.0\THIRD-PARTY-NOTICES.TXT +microsoft.netcore.dotnethostpolicy\2.2.0\.nupkg.metadata +microsoft.netcore.dotnethostpolicy\2.2.0\.signature.p7s +microsoft.netcore.dotnethostpolicy\2.2.0\LICENSE.TXT +microsoft.netcore.dotnethostpolicy\2.2.0\microsoft.netcore.dotnethostpolicy.2.2.0.nupkg.sha512 +microsoft.netcore.dotnethostpolicy\2.2.0\microsoft.netcore.dotnethostpolicy.nuspec +microsoft.netcore.dotnethostpolicy\2.2.0\runtime.json +microsoft.netcore.dotnethostpolicy\2.2.0\THIRD-PARTY-NOTICES.TXT +microsoft.netcore.dotnethostresolver\2.2.0\.nupkg.metadata +microsoft.netcore.dotnethostresolver\2.2.0\.signature.p7s +microsoft.netcore.dotnethostresolver\2.2.0\LICENSE.TXT +microsoft.netcore.dotnethostresolver\2.2.0\microsoft.netcore.dotnethostresolver.2.2.0.nupkg.sha512 +microsoft.netcore.dotnethostresolver\2.2.0\microsoft.netcore.dotnethostresolver.nuspec +microsoft.netcore.dotnethostresolver\2.2.0\runtime.json +microsoft.netcore.dotnethostresolver\2.2.0\THIRD-PARTY-NOTICES.TXT +microsoft.netcore.platforms\1.0.1\.nupkg.metadata +microsoft.netcore.platforms\1.0.1\.signature.p7s +microsoft.netcore.platforms\1.0.2\.nupkg.metadata +microsoft.netcore.platforms\1.0.2\.signature.p7s +microsoft.netcore.platforms\1.1.0\.nupkg.metadata +microsoft.netcore.platforms\1.1.0\.signature.p7s +microsoft.netcore.platforms\2.0.0\.nupkg.metadata +microsoft.netcore.platforms\2.0.0\.signature.p7s +microsoft.netcore.platforms\2.2.0\.nupkg.metadata +microsoft.netcore.platforms\2.2.0\.signature.p7s +microsoft.netcore.platforms\2.2.0\lib\netstandard1.0\_._ +microsoft.netcore.platforms\2.2.0\LICENSE.TXT +microsoft.netcore.platforms\2.2.0\microsoft.netcore.platforms.2.2.0.nupkg.sha512 +microsoft.netcore.platforms\2.2.0\microsoft.netcore.platforms.nuspec +microsoft.netcore.platforms\2.2.0\runtime.json +microsoft.netcore.platforms\2.2.0\THIRD-PARTY-NOTICES.TXT +microsoft.netcore.platforms\2.2.0\useSharedDesignerContext.txt +microsoft.netcore.platforms\2.2.0\version.txt +microsoft.netcore.targets\1.0.1\.nupkg.metadata +microsoft.netcore.targets\1.1.0\.nupkg.metadata +microsoft.netcore.targets\2.0.0\.nupkg.metadata +microsoft.rest.clientruntime.azure\3.3.7\.nupkg.metadata +microsoft.rest.clientruntime.azure\3.3.7\.signature.p7s +microsoft.rest.clientruntime\2.3.8\.nupkg.metadata +microsoft.rest.clientruntime\2.3.8\.signature.p7s +microsoft.visualstudio.web.browserlink\2.2.0\.nupkg.metadata +microsoft.visualstudio.web.browserlink\2.2.0\.signature.p7s +microsoft.visualstudio.web.browserlink\2.2.0\lib\netstandard2.0\Microsoft.VisualStudio.Web.BrowserLink.dll +microsoft.visualstudio.web.browserlink\2.2.0\microsoft.visualstudio.web.browserlink.2.2.0.nupkg.sha512 +microsoft.visualstudio.web.browserlink\2.2.0\microsoft.visualstudio.web.browserlink.nuspec +microsoft.win32.primitives\4.0.1\.nupkg.metadata +microsoft.win32.primitives\4.3.0\.nupkg.metadata +microsoft.win32.registry\4.3.0\.nupkg.metadata +microsoft.win32.registry\4.5.0\.nupkg.metadata +netstandard.library\1.6.0\.nupkg.metadata +netstandard.library\1.6.1\.nupkg.metadata +netstandard.library\2.0.3\.nupkg.metadata +newtonsoft.json.bson\1.0.1\.nupkg.metadata +newtonsoft.json.bson\1.0.1\.signature.p7s +newtonsoft.json\10.0.1\.nupkg.metadata +newtonsoft.json\10.0.1\.signature.p7s +newtonsoft.json\11.0.2\.nupkg.metadata +newtonsoft.json\11.0.2\.signature.p7s +newtonsoft.json\9.0.1\.nupkg.metadata +remotion.linq\2.2.0\.nupkg.metadata +remotion.linq\2.2.0\.signature.p7s +runtime.debian.8-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.fedora.23-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.fedora.24-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.native.system.data.sqlclient.sni\4.5.0\.nupkg.metadata +runtime.native.system.data.sqlclient.sni\4.5.0\.signature.p7s +runtime.native.system.data.sqlclient.sni\4.5.0\LICENSE.TXT +runtime.native.system.data.sqlclient.sni\4.5.0\runtime.native.system.data.sqlclient.sni.4.5.0.nupkg.sha512 +runtime.native.system.data.sqlclient.sni\4.5.0\runtime.native.system.data.sqlclient.sni.nuspec +runtime.native.system.data.sqlclient.sni\4.5.0\THIRD-PARTY-NOTICES.TXT +runtime.native.system.data.sqlclient.sni\4.5.0\useSharedDesignerContext.txt +runtime.native.system.data.sqlclient.sni\4.5.0\version.txt +runtime.native.system.io.compression\4.1.0\.nupkg.metadata +runtime.native.system.io.compression\4.3.0\.nupkg.metadata +runtime.native.system.net.http\4.0.1\.nupkg.metadata +runtime.native.system.net.http\4.3.0\.nupkg.metadata +runtime.native.system.net.security\4.3.0\.nupkg.metadata +runtime.native.system.security.cryptography.apple\4.3.0\.nupkg.metadata +runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.native.system.security.cryptography\4.0.0\.nupkg.metadata +runtime.native.system\4.0.0\.nupkg.metadata +runtime.native.system\4.3.0\.nupkg.metadata +runtime.opensuse.13.2-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.opensuse.42.1-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.osx.10.10-x64.runtime.native.system.security.cryptography.apple\4.3.0\.nupkg.metadata +runtime.osx.10.10-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.rhel.7-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.ubuntu.14.04-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.ubuntu.16.04-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.ubuntu.16.10-x64.runtime.native.system.security.cryptography.openssl\4.3.0\.nupkg.metadata +runtime.win-arm64.runtime.native.system.data.sqlclient.sni\4.4.0\.nupkg.metadata +runtime.win-x64.runtime.native.system.data.sqlclient.sni\4.4.0\.nupkg.metadata +runtime.win-x86.runtime.native.system.data.sqlclient.sni\4.4.0\.nupkg.metadata +sqlitepclraw.bundle_green\1.1.11\.nupkg.metadata +sqlitepclraw.bundle_green\1.1.11\.signature.p7s +sqlitepclraw.core\1.1.11\.nupkg.metadata +sqlitepclraw.core\1.1.11\.signature.p7s +sqlitepclraw.lib.e_sqlite3.linux\1.1.11\.nupkg.metadata +sqlitepclraw.lib.e_sqlite3.linux\1.1.11\.signature.p7s +sqlitepclraw.lib.e_sqlite3.osx\1.1.11\.nupkg.metadata +sqlitepclraw.lib.e_sqlite3.osx\1.1.11\.signature.p7s +sqlitepclraw.lib.e_sqlite3.v110_xp\1.1.11\.nupkg.metadata +sqlitepclraw.lib.e_sqlite3.v110_xp\1.1.11\.signature.p7s +sqlitepclraw.provider.e_sqlite3.netstandard11\1.1.11\.nupkg.metadata +sqlitepclraw.provider.e_sqlite3.netstandard11\1.1.11\.signature.p7s +stackexchange.redis.strongname\1.2.6\.nupkg.metadata +stackexchange.redis.strongname\1.2.6\.signature.p7s +stackexchange.redis.strongname\1.2.6\lib\net45\StackExchange.Redis.StrongName.dll +stackexchange.redis.strongname\1.2.6\lib\net46\StackExchange.Redis.StrongName.dll +stackexchange.redis.strongname\1.2.6\lib\netstandard1.5\StackExchange.Redis.StrongName.dll +stackexchange.redis.strongname\1.2.6\stackexchange.redis.strongname.1.2.6.nupkg.sha512 +stackexchange.redis.strongname\1.2.6\stackexchange.redis.strongname.nuspec +system.appcontext\4.1.0\.nupkg.metadata +system.appcontext\4.3.0\.nupkg.metadata +system.buffers\4.0.0\.nupkg.metadata +system.buffers\4.3.0\.nupkg.metadata +system.buffers\4.5.0\.nupkg.metadata +system.collections.concurrent\4.0.12\.nupkg.metadata +system.collections.concurrent\4.3.0\.nupkg.metadata +system.collections.immutable\1.3.0\.nupkg.metadata +system.collections.immutable\1.3.1\.nupkg.metadata +system.collections.immutable\1.5.0\.nupkg.metadata +system.collections.nongeneric\4.3.0\.nupkg.metadata +system.collections.nongeneric\4.3.0\.signature.p7s +system.collections.specialized\4.3.0\.nupkg.metadata +system.collections\4.0.11\.nupkg.metadata +system.collections\4.3.0\.nupkg.metadata +system.componentmodel.annotations\4.5.0\.nupkg.metadata +system.componentmodel.primitives\4.3.0\.nupkg.metadata +system.componentmodel.typeconverter\4.3.0\.nupkg.metadata +system.componentmodel\4.3.0\.nupkg.metadata +system.console\4.0.0\.nupkg.metadata +system.console\4.3.0\.nupkg.metadata +system.data.sqlclient\4.6.0\.nupkg.metadata +system.data.sqlclient\4.6.0\.signature.p7s +system.data.sqlclient\4.6.0\lib\MonoAndroid10\_._ +system.data.sqlclient\4.6.0\lib\MonoTouch10\_._ +system.data.sqlclient\4.6.0\lib\net451\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\lib\net46\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\lib\net461\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\lib\netcoreapp2.1\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\lib\netstandard1.2\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\lib\netstandard1.3\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\lib\netstandard2.0\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\lib\xamarinios10\_._ +system.data.sqlclient\4.6.0\lib\xamarinmac20\_._ +system.data.sqlclient\4.6.0\lib\xamarintvos10\_._ +system.data.sqlclient\4.6.0\lib\xamarinwatchos10\_._ +system.data.sqlclient\4.6.0\LICENSE.TXT +system.data.sqlclient\4.6.0\ref\MonoAndroid10\_._ +system.data.sqlclient\4.6.0\ref\MonoTouch10\_._ +system.data.sqlclient\4.6.0\ref\net451\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\ref\net46\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\ref\net461\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\ref\netcoreapp2.1\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\ref\netstandard1.2\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\ref\netstandard1.3\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\ref\netstandard2.0\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\ref\xamarinios10\_._ +system.data.sqlclient\4.6.0\ref\xamarinmac20\_._ +system.data.sqlclient\4.6.0\ref\xamarintvos10\_._ +system.data.sqlclient\4.6.0\ref\xamarinwatchos10\_._ +system.data.sqlclient\4.6.0\runtimes\unix\lib\netcoreapp2.1\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\runtimes\unix\lib\netstandard1.3\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\runtimes\unix\lib\netstandard2.0\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\runtimes\win\lib\net451\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\runtimes\win\lib\net46\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\runtimes\win\lib\net461\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\runtimes\win\lib\netcoreapp2.1\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\runtimes\win\lib\netstandard1.3\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\runtimes\win\lib\netstandard2.0\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\runtimes\win\lib\uap10.0.16299\System.Data.SqlClient.dll +system.data.sqlclient\4.6.0\system.data.sqlclient.4.6.0.nupkg.sha512 +system.data.sqlclient\4.6.0\system.data.sqlclient.nuspec +system.data.sqlclient\4.6.0\THIRD-PARTY-NOTICES.TXT +system.data.sqlclient\4.6.0\useSharedDesignerContext.txt +system.data.sqlclient\4.6.0\version.txt +system.diagnostics.contracts\4.3.0\.nupkg.metadata +system.diagnostics.contracts\4.3.0\.signature.p7s +system.diagnostics.debug\4.0.11\.nupkg.metadata +system.diagnostics.debug\4.3.0\.nupkg.metadata +system.diagnostics.diagnosticsource\4.0.0\.nupkg.metadata +system.diagnostics.diagnosticsource\4.3.0\.nupkg.metadata +system.diagnostics.diagnosticsource\4.4.0\.nupkg.metadata +system.diagnostics.diagnosticsource\4.4.0\.signature.p7s +system.diagnostics.diagnosticsource\4.5.0\.nupkg.metadata +system.diagnostics.fileversioninfo\4.3.0\.nupkg.metadata +system.diagnostics.fileversioninfo\4.3.0\.signature.p7s +system.diagnostics.process\4.3.0\.nupkg.metadata +system.diagnostics.stacktrace\4.3.0\.nupkg.metadata +system.diagnostics.tools\4.0.1\.nupkg.metadata +system.diagnostics.tools\4.3.0\.nupkg.metadata +system.diagnostics.tracing\4.1.0\.nupkg.metadata +system.diagnostics.tracing\4.3.0\.nupkg.metadata +system.dynamic.runtime\4.0.11\.nupkg.metadata +system.dynamic.runtime\4.3.0\.nupkg.metadata +system.globalization.calendars\4.0.1\.nupkg.metadata +system.globalization.calendars\4.3.0\.nupkg.metadata +system.globalization.extensions\4.0.1\.nupkg.metadata +system.globalization.extensions\4.3.0\.nupkg.metadata +system.globalization\4.0.11\.nupkg.metadata +system.globalization\4.3.0\.nupkg.metadata +system.identitymodel.tokens.jwt\5.3.0\.nupkg.metadata +system.identitymodel.tokens.jwt\5.3.0\.signature.p7s +system.identitymodel.tokens.jwt\5.3.0\lib\net45\System.IdentityModel.Tokens.Jwt.dll +system.identitymodel.tokens.jwt\5.3.0\lib\net45\System.IdentityModel.Tokens.Jwt.pdb +system.identitymodel.tokens.jwt\5.3.0\lib\net451\System.IdentityModel.Tokens.Jwt.dll +system.identitymodel.tokens.jwt\5.3.0\lib\net451\System.IdentityModel.Tokens.Jwt.pdb +system.identitymodel.tokens.jwt\5.3.0\lib\net461\System.IdentityModel.Tokens.Jwt.dll +system.identitymodel.tokens.jwt\5.3.0\lib\net461\System.IdentityModel.Tokens.Jwt.pdb +system.identitymodel.tokens.jwt\5.3.0\lib\netstandard1.4\System.IdentityModel.Tokens.Jwt.dll +system.identitymodel.tokens.jwt\5.3.0\lib\netstandard1.4\System.IdentityModel.Tokens.Jwt.pdb +system.identitymodel.tokens.jwt\5.3.0\lib\netstandard2.0\System.IdentityModel.Tokens.Jwt.dll +system.identitymodel.tokens.jwt\5.3.0\lib\netstandard2.0\System.IdentityModel.Tokens.Jwt.pdb +system.identitymodel.tokens.jwt\5.3.0\system.identitymodel.tokens.jwt.5.3.0.nupkg.sha512 +system.identitymodel.tokens.jwt\5.3.0\system.identitymodel.tokens.jwt.nuspec +system.interactive.async\3.2.0\.nupkg.metadata +system.interactive.async\3.2.0\.signature.p7s +system.interactive.async\3.2.0\lib\net45\System.Interactive.Async.dll +system.interactive.async\3.2.0\lib\net46\System.Interactive.Async.dll +system.interactive.async\3.2.0\lib\netstandard1.0\System.Interactive.Async.dll +system.interactive.async\3.2.0\lib\netstandard1.3\System.Interactive.Async.dll +system.interactive.async\3.2.0\lib\netstandard2.0\System.Interactive.Async.dll +system.interactive.async\3.2.0\system.interactive.async.3.2.0.nupkg.sha512 +system.interactive.async\3.2.0\system.interactive.async.nuspec +system.io.compression.zipfile\4.0.1\.nupkg.metadata +system.io.compression.zipfile\4.3.0\.nupkg.metadata +system.io.compression\4.1.0\.nupkg.metadata +system.io.compression\4.3.0\.nupkg.metadata +system.io.filesystem.primitives\4.0.1\.nupkg.metadata +system.io.filesystem.primitives\4.3.0\.nupkg.metadata +system.io.filesystem\4.0.1\.nupkg.metadata +system.io.filesystem\4.3.0\.nupkg.metadata +system.io.pipelines\4.5.2\.nupkg.metadata +system.io.pipelines\4.5.2\.signature.p7s +system.io.pipelines\4.5.2\lib\netcoreapp2.1\System.IO.Pipelines.dll +system.io.pipelines\4.5.2\lib\netstandard1.3\System.IO.Pipelines.dll +system.io.pipelines\4.5.2\lib\netstandard2.0\System.IO.Pipelines.dll +system.io.pipelines\4.5.2\LICENSE.TXT +system.io.pipelines\4.5.2\ref\netstandard1.3\System.IO.Pipelines.dll +system.io.pipelines\4.5.2\system.io.pipelines.4.5.2.nupkg.sha512 +system.io.pipelines\4.5.2\system.io.pipelines.nuspec +system.io.pipelines\4.5.2\THIRD-PARTY-NOTICES.TXT +system.io.pipelines\4.5.2\useSharedDesignerContext.txt +system.io.pipelines\4.5.2\version.txt +system.io\4.1.0\.nupkg.metadata +system.io\4.3.0\.nupkg.metadata +system.linq.expressions\4.1.0\.nupkg.metadata +system.linq.expressions\4.3.0\.nupkg.metadata +system.linq.queryable\4.0.1\.nupkg.metadata +system.linq\4.1.0\.nupkg.metadata +system.linq\4.3.0\.nupkg.metadata +system.memory\4.5.1\.nupkg.metadata +system.net.http\4.1.0\.nupkg.metadata +system.net.http\4.1.0\.signature.p7s +system.net.http\4.3.0\.nupkg.metadata +system.net.http\4.3.0\.signature.p7s +system.net.nameresolution\4.3.0\.nupkg.metadata +system.net.primitives\4.0.11\.nupkg.metadata +system.net.primitives\4.3.0\.nupkg.metadata +system.net.security\4.3.0\.nupkg.metadata +system.net.sockets\4.1.0\.nupkg.metadata +system.net.sockets\4.3.0\.nupkg.metadata +system.net.websockets.websocketprotocol\4.5.1\.nupkg.metadata +system.numerics.vectors\4.5.0\.nupkg.metadata +system.objectmodel\4.0.12\.nupkg.metadata +system.objectmodel\4.3.0\.nupkg.metadata +system.private.datacontractserialization\4.1.1\.nupkg.metadata +system.private.datacontractserialization\4.3.0\.nupkg.metadata +system.private.datacontractserialization\4.3.0\.signature.p7s +system.reflection.emit.ilgeneration\4.0.1\.nupkg.metadata +system.reflection.emit.ilgeneration\4.3.0\.nupkg.metadata +system.reflection.emit.lightweight\4.0.1\.nupkg.metadata +system.reflection.emit.lightweight\4.3.0\.nupkg.metadata +system.reflection.emit\4.0.1\.nupkg.metadata +system.reflection.emit\4.3.0\.nupkg.metadata +system.reflection.extensions\4.0.1\.nupkg.metadata +system.reflection.extensions\4.3.0\.nupkg.metadata +system.reflection.metadata\1.4.1\.nupkg.metadata +system.reflection.metadata\1.4.2\.nupkg.metadata +system.reflection.metadata\1.6.0\.nupkg.metadata +system.reflection.primitives\4.0.1\.nupkg.metadata +system.reflection.primitives\4.3.0\.nupkg.metadata +system.reflection.typeextensions\4.1.0\.nupkg.metadata +system.reflection.typeextensions\4.3.0\.nupkg.metadata +system.reflection\4.1.0\.nupkg.metadata +system.reflection\4.3.0\.nupkg.metadata +system.resources.resourcemanager\4.0.1\.nupkg.metadata +system.resources.resourcemanager\4.3.0\.nupkg.metadata +system.runtime.compilerservices.unsafe\4.5.0\.nupkg.metadata +system.runtime.compilerservices.unsafe\4.5.1\.nupkg.metadata +system.runtime.extensions\4.1.0\.nupkg.metadata +system.runtime.extensions\4.3.0\.nupkg.metadata +system.runtime.handles\4.0.1\.nupkg.metadata +system.runtime.handles\4.3.0\.nupkg.metadata +system.runtime.interopservices.runtimeinformation\4.0.0\.nupkg.metadata +system.runtime.interopservices.runtimeinformation\4.3.0\.nupkg.metadata +system.runtime.interopservices\4.1.0\.nupkg.metadata +system.runtime.interopservices\4.3.0\.nupkg.metadata +system.runtime.numerics\4.0.1\.nupkg.metadata +system.runtime.numerics\4.3.0\.nupkg.metadata +system.runtime.serialization.formatters\4.3.0\.nupkg.metadata +system.runtime.serialization.json\4.0.2\.nupkg.metadata +system.runtime.serialization.json\4.3.0\.nupkg.metadata +system.runtime.serialization.json\4.3.0\dotnet_library_license.txt +system.runtime.serialization.json\4.3.0\lib\MonoAndroid10\_._ +system.runtime.serialization.json\4.3.0\lib\MonoTouch10\_._ +system.runtime.serialization.json\4.3.0\lib\net45\_._ +system.runtime.serialization.json\4.3.0\lib\netcore50\System.Runtime.Serialization.Json.dll +system.runtime.serialization.json\4.3.0\lib\netstandard1.3\System.Runtime.Serialization.Json.dll +system.runtime.serialization.json\4.3.0\lib\portable-net45+win8+wp8+wpa81\_._ +system.runtime.serialization.json\4.3.0\lib\win8\_._ +system.runtime.serialization.json\4.3.0\lib\wp80\_._ +system.runtime.serialization.json\4.3.0\lib\wpa81\_._ +system.runtime.serialization.json\4.3.0\lib\xamarinios10\_._ +system.runtime.serialization.json\4.3.0\lib\xamarinmac20\_._ +system.runtime.serialization.json\4.3.0\lib\xamarintvos10\_._ +system.runtime.serialization.json\4.3.0\lib\xamarinwatchos10\_._ +system.runtime.serialization.json\4.3.0\ref\MonoAndroid10\_._ +system.runtime.serialization.json\4.3.0\ref\MonoTouch10\_._ +system.runtime.serialization.json\4.3.0\ref\net45\_._ +system.runtime.serialization.json\4.3.0\ref\netcore50\System.Runtime.Serialization.Json.dll +system.runtime.serialization.json\4.3.0\ref\netstandard1.0\System.Runtime.Serialization.Json.dll +system.runtime.serialization.json\4.3.0\ref\portable-net45+win8+wp8+wpa81\_._ +system.runtime.serialization.json\4.3.0\ref\win8\_._ +system.runtime.serialization.json\4.3.0\ref\wp80\_._ +system.runtime.serialization.json\4.3.0\ref\wpa81\_._ +system.runtime.serialization.json\4.3.0\ref\xamarinios10\_._ +system.runtime.serialization.json\4.3.0\ref\xamarinmac20\_._ +system.runtime.serialization.json\4.3.0\ref\xamarintvos10\_._ +system.runtime.serialization.json\4.3.0\ref\xamarinwatchos10\_._ +system.runtime.serialization.json\4.3.0\system.runtime.serialization.json.4.3.0.nupkg.sha512 +system.runtime.serialization.json\4.3.0\system.runtime.serialization.json.nuspec +system.runtime.serialization.json\4.3.0\ThirdPartyNotices.txt +system.runtime.serialization.primitives\4.1.1\.nupkg.metadata +system.runtime.serialization.primitives\4.3.0\.nupkg.metadata +system.runtime.serialization.xml\4.3.0\.nupkg.metadata +system.runtime.serialization.xml\4.3.0\.signature.p7s +system.runtime\4.1.0\.nupkg.metadata +system.runtime\4.3.0\.nupkg.metadata +system.security.accesscontrol\4.5.0\.nupkg.metadata +system.security.claims\4.3.0\.nupkg.metadata +system.security.cryptography.algorithms\4.2.0\.nupkg.metadata +system.security.cryptography.algorithms\4.3.0\.nupkg.metadata +system.security.cryptography.cng\4.2.0\.nupkg.metadata +system.security.cryptography.cng\4.3.0\.nupkg.metadata +system.security.cryptography.cng\4.5.0\.nupkg.metadata +system.security.cryptography.csp\4.0.0\.nupkg.metadata +system.security.cryptography.csp\4.3.0\.nupkg.metadata +system.security.cryptography.encoding\4.0.0\.nupkg.metadata +system.security.cryptography.encoding\4.3.0\.nupkg.metadata +system.security.cryptography.openssl\4.0.0\.nupkg.metadata +system.security.cryptography.openssl\4.3.0\.nupkg.metadata +system.security.cryptography.pkcs\4.5.0\.nupkg.metadata +system.security.cryptography.primitives\4.0.0\.nupkg.metadata +system.security.cryptography.primitives\4.3.0\.nupkg.metadata +system.security.cryptography.x509certificates\4.1.0\.nupkg.metadata +system.security.cryptography.x509certificates\4.3.0\.nupkg.metadata +system.security.cryptography.xml\4.5.0\.nupkg.metadata +system.security.permissions\4.5.0\.nupkg.metadata +system.security.principal.windows\4.3.0\.nupkg.metadata +system.security.principal.windows\4.5.0\.nupkg.metadata +system.security.principal\4.3.0\.nupkg.metadata +system.spatial\5.8.2\.nupkg.metadata +system.text.encoding.codepages\4.3.0\.nupkg.metadata +system.text.encoding.codepages\4.5.0\.nupkg.metadata +system.text.encoding.extensions\4.0.11\.nupkg.metadata +system.text.encoding.extensions\4.3.0\.nupkg.metadata +system.text.encoding\4.0.11\.nupkg.metadata +system.text.encoding\4.3.0\.nupkg.metadata +system.text.encodings.web\4.3.1\.nupkg.metadata +system.text.encodings.web\4.3.1\.signature.p7s +system.text.encodings.web\4.5.0\.nupkg.metadata +system.text.regularexpressions\4.1.0\.nupkg.metadata +system.text.regularexpressions\4.3.0\.nupkg.metadata +system.threading.channels\4.5.0\.nupkg.metadata +system.threading.tasks.extensions\4.0.0\.nupkg.metadata +system.threading.tasks.extensions\4.3.0\.nupkg.metadata +system.threading.tasks.extensions\4.5.1\.nupkg.metadata +system.threading.tasks.parallel\4.3.0\.nupkg.metadata +system.threading.tasks.parallel\4.3.0\.signature.p7s +system.threading.tasks\4.0.11\.nupkg.metadata +system.threading.tasks\4.3.0\.nupkg.metadata +system.threading.thread\4.3.0\.nupkg.metadata +system.threading.threadpool\4.3.0\.nupkg.metadata +system.threading.timer\4.0.1\.nupkg.metadata +system.threading.timer\4.3.0\.nupkg.metadata +system.threading\4.0.11\.nupkg.metadata +system.threading\4.3.0\.nupkg.metadata +system.valuetuple\4.3.0\.nupkg.metadata +system.valuetuple\4.5.0\.nupkg.metadata +system.xml.readerwriter\4.0.11\.nupkg.metadata +system.xml.readerwriter\4.3.0\.nupkg.metadata +system.xml.xdocument\4.0.11\.nupkg.metadata +system.xml.xdocument\4.3.0\.nupkg.metadata +system.xml.xmldocument\4.0.1\.nupkg.metadata +system.xml.xmldocument\4.3.0\.nupkg.metadata +system.xml.xmldocument\4.3.0\.signature.p7s +system.xml.xmlserializer\4.0.11\.nupkg.metadata +system.xml.xmlserializer\4.3.0\.nupkg.metadata +system.xml.xmlserializer\4.3.0\.signature.p7s +system.xml.xpath.xdocument\4.3.0\.nupkg.metadata +system.xml.xpath\4.3.0\.nupkg.metadata +system.xml.xpath\4.3.0\.signature.p7s +windowsazure.storage\8.1.4\.nupkg.metadata +windowsazure.storage\8.1.4\.signature.p7s diff --git a/src/PackageArchive/ZipManifestGenerator/README.md b/src/PackageArchive/ZipManifestGenerator/README.md index 9922f2e465..6022e996b8 100644 --- a/src/PackageArchive/ZipManifestGenerator/README.md +++ b/src/PackageArchive/ZipManifestGenerator/README.md @@ -1,5 +1,5 @@ ZipManifestGenerator ---------- +-------------------- This console app is used to generate the list of files in a zip archive. @@ -29,3 +29,5 @@ $compatPatchUrl = "https://dotnetfeed.blob.core.windows.net/orchestrated-release dotnet run $compatPatchUrl "../Archive.CiServer.Patch.Compat/ArchiveBaseline.${Version}.txt" ``` + +For convenience, this folder contains [./UpdateBaselines.ps1](./UpdateBaselines.ps1) to run these steps. diff --git a/src/PackageArchive/ZipManifestGenerator/UpdateBaselines.ps1 b/src/PackageArchive/ZipManifestGenerator/UpdateBaselines.ps1 new file mode 100644 index 0000000000..d129443473 --- /dev/null +++ b/src/PackageArchive/ZipManifestGenerator/UpdateBaselines.ps1 @@ -0,0 +1,15 @@ +param( + [Parameter(Mandatory = $true)] + $ProdConBuildId, + [Parameter(Mandatory = $true)] + $ProductVersion, + $FeedContainer = 'orchestrated-release-2-2' +) + +$patchUrl = "https://dotnetfeed.blob.core.windows.net/${FeedContainer}/${ProdconBuildId}/final/assets/aspnetcore/Runtime/${ProductVersion}/nuGetPackagesArchive-ci-server-${ProductVersion}.patch.zip" + +dotnet run $patchUrl "../Archive.CiServer.Patch/ArchiveBaseline.${ProductVersion}.txt" + +$compatPatchUrl = "https://dotnetfeed.blob.core.windows.net/${FeedContainer}/${ProdconBuildId}/final/assets/aspnetcore/Runtime/${ProductVersion}/nuGetPackagesArchive-ci-server-compat-${ProductVersion}.patch.zip" + +dotnet run $compatPatchUrl "../Archive.CiServer.Patch.Compat/ArchiveBaseline.${ProductVersion}.txt" diff --git a/src/SiteExtensions/build/dependencies.props b/src/SiteExtensions/build/dependencies.props index e20e907408..721f8428ed 100644 --- a/src/SiteExtensions/build/dependencies.props +++ b/src/SiteExtensions/build/dependencies.props @@ -4,7 +4,7 @@ - 2.2.0-preview2-20181004.6 + 2.2.1-build-20181114.3 2.1.1-rtm-31076 2.2.0-rtm-35515 15.6.1 diff --git a/src/Tools/Directory.Build.props b/src/Tools/Directory.Build.props new file mode 100644 index 0000000000..6b35802689 --- /dev/null +++ b/src/Tools/Directory.Build.props @@ -0,0 +1,9 @@ + + + + + $(RepositoryRoot)obj\$(MSBuildProjectName)\ + $(RepositoryRoot)bin\$(MSBuildProjectName)\ + + + diff --git a/src/Tools/Directory.Build.targets b/src/Tools/Directory.Build.targets new file mode 100644 index 0000000000..7928d3f6cf --- /dev/null +++ b/src/Tools/Directory.Build.targets @@ -0,0 +1,11 @@ + + + + + true + + + + + + diff --git a/src/Tools/FirstRunCertGenerator/src/CertificateGenerator.cs b/src/Tools/FirstRunCertGenerator/src/CertificateGenerator.cs new file mode 100644 index 0000000000..d3f58eae35 --- /dev/null +++ b/src/Tools/FirstRunCertGenerator/src/CertificateGenerator.cs @@ -0,0 +1,15 @@ +using System; +using Microsoft.AspNetCore.Certificates.Generation; + +namespace Microsoft.AspNetCore.DeveloperCertificates.XPlat +{ + public static class CertificateGenerator + { + public static void GenerateAspNetHttpsCertificate() + { + var manager = new CertificateManager(); + var now = DateTimeOffset.Now; + manager.EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1)); + } + } +} diff --git a/src/Tools/FirstRunCertGenerator/src/Microsoft.AspNetCore.DeveloperCertificates.XPlat.csproj b/src/Tools/FirstRunCertGenerator/src/Microsoft.AspNetCore.DeveloperCertificates.XPlat.csproj new file mode 100644 index 0000000000..c6c9ce517c --- /dev/null +++ b/src/Tools/FirstRunCertGenerator/src/Microsoft.AspNetCore.DeveloperCertificates.XPlat.csproj @@ -0,0 +1,14 @@ + + + + netcoreapp3.0 + Package for the CLI first run experience. + $(DefineConstants);XPLAT + aspnet;cli + + + + + + + diff --git a/src/Tools/README.md b/src/Tools/README.md new file mode 100644 index 0000000000..e13c6ec6e3 --- /dev/null +++ b/src/Tools/README.md @@ -0,0 +1,32 @@ +DotNetTools +=========== + +## Projects + +The folder contains command-line tools for ASP.NET Core that are bundled* in the .NET Core CLI. Follow the links below for more details on each tool. + + - [dotnet-watch](dotnet-watch/README.md) + - [dotnet-user-secrets](dotnet-user-secrets/README.md) + - [dotnet-sql-cache](dotnet-sql-cache/README.md) + - [dotnet-dev-certs](dotnet-dev-certs/README.md) + +*\*This applies to .NET Core CLI 2.1.300-preview2 and up. For earlier versions of the CLI, these tools must be installed separately.* + +*For 2.0 CLI and earlier, see for details.* + +## Usage + +The command line tools can be invoked as a subcommand of `dotnet`. + +```sh +dotnet watch +dotnet user-secrets +dotnet sql-cache +dotnet dev-certs +``` + +Add `--help` to see more details. For example, + +``` +dotnet watch --help +``` diff --git a/src/Tools/dotnet-dev-certs/README.md b/src/Tools/dotnet-dev-certs/README.md new file mode 100644 index 0000000000..e565dbc0e8 --- /dev/null +++ b/src/Tools/dotnet-dev-certs/README.md @@ -0,0 +1,8 @@ +dotnet-dev-certs +================ + +`dotnet-dev-certs` is a command line tool to generate certificates used in ASP.NET Core during development. + +### How To Use + +Run `dotnet dev-certs --help` for more information about usage. diff --git a/src/Tools/dotnet-dev-certs/src/Program.cs b/src/Tools/dotnet-dev-certs/src/Program.cs new file mode 100644 index 0000000000..170e11b09d --- /dev/null +++ b/src/Tools/dotnet-dev-certs/src/Program.cs @@ -0,0 +1,247 @@ +// 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.Runtime.InteropServices; +using System.Security.Cryptography.X509Certificates; +using Microsoft.AspNetCore.Certificates.Generation; +using Microsoft.Extensions.CommandLineUtils; +using Microsoft.Extensions.Tools.Internal; + +namespace Microsoft.AspNetCore.DeveloperCertificates.Tools +{ + internal class Program + { + private const int CriticalError = -1; + private const int Success = 0; + private const int ErrorCreatingTheCertificate = 1; + private const int ErrorSavingTheCertificate = 2; + private const int ErrorExportingTheCertificate = 3; + private const int ErrorTrustingTheCertificate = 4; + private const int ErrorUserCancelledTrustPrompt = 5; + private const int ErrorNoValidCertificateFound = 6; + private const int ErrorCertificateNotTrusted = 7; + private const int ErrorCleaningUpCertificates = 8; + + public static readonly TimeSpan HttpsCertificateValidity = TimeSpan.FromDays(365); + + public static int Main(string[] args) + { + try + { + var app = new CommandLineApplication + { + Name = "dotnet dev-certs" + }; + + app.Command("https", c => + { + var exportPath = c.Option("-ep|--export-path", + "Full path to the exported certificate", + CommandOptionType.SingleValue); + + var password = c.Option("-p|--password", + "Password to use when exporting the certificate with the private key into a pfx file", + CommandOptionType.SingleValue); + + var check = c.Option( + "-c|--check", + "Check for the existence of the certificate but do not perform any action", + CommandOptionType.NoValue); + + var clean = c.Option( + "--clean", + "Cleans all HTTPS development certificates from the machine.", + CommandOptionType.NoValue); + + CommandOption trust = null; + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + trust = c.Option("-t|--trust", + "Trust the certificate on the current platform", + CommandOptionType.NoValue); + } + + var verbose = c.Option("-v|--verbose", + "Display more debug information.", + CommandOptionType.NoValue); + + var quiet = c.Option("-q|--quiet", + "Display warnings and errors only.", + CommandOptionType.NoValue); + + c.HelpOption("-h|--help"); + + c.OnExecute(() => + { + var reporter = new ConsoleReporter(PhysicalConsole.Singleton, verbose.HasValue(), quiet.HasValue()); + if ((clean.HasValue() && (exportPath.HasValue() || password.HasValue() || trust?.HasValue() == true)) || + (check.HasValue() && (exportPath.HasValue() || password.HasValue() || clean.HasValue()))) + { + reporter.Error(@"Incompatible set of flags. Sample usages +'dotnet dev-certs https --clean' +'dotnet dev-certs https --check --trust' +'dotnet dev-certs https -ep ./certificate.pfx -p password --trust'"); + } + + if (check.HasValue()) + { + return CheckHttpsCertificate(trust, reporter); + } + + if (clean.HasValue()) + { + return CleanHttpsCertificates(reporter); + } + + return EnsureHttpsCertificate(exportPath, password, trust, reporter); + }); + }); + + app.HelpOption("-h|--help"); + + app.OnExecute(() => + { + app.ShowHelp(); + return Success; + }); + + return app.Execute(args); + } + catch + { + return CriticalError; + } + } + + private static int CleanHttpsCertificates(IReporter reporter) + { + var manager = new CertificateManager(); + try + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + reporter.Output("Cleaning HTTPS development certificates from the machine. A prompt might get " + + "displayed to confirm the removal of some of the certificates."); + } + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + reporter.Output("Cleaning HTTPS development certificates from the machine. This operation might " + + "require elevated privileges. If that is the case, a prompt for credentials will be displayed."); + } + + manager.CleanupHttpsCertificates(); + reporter.Verbose("HTTPS development certificates successfully removed from the machine."); + return Success; + } + catch(Exception e) + { + reporter.Error("There was an error trying to clean HTTPS development certificates on this machine."); + reporter.Error(e.Message); + + return ErrorCleaningUpCertificates; + } + } + + private static int CheckHttpsCertificate(CommandOption trust, IReporter reporter) + { + var now = DateTimeOffset.Now; + var certificateManager = new CertificateManager(); + var certificates = certificateManager.ListCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, isValid: true); + if (certificates.Count == 0) + { + reporter.Verbose("No valid certificate found."); + return ErrorNoValidCertificateFound; + } + else + { + reporter.Verbose("A valid certificate was found."); + } + + if (trust != null && trust.HasValue()) + { + var store = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? StoreName.My : StoreName.Root; + var trustedCertificates = certificateManager.ListCertificates(CertificatePurpose.HTTPS, store, StoreLocation.CurrentUser, isValid: true); + if (!certificates.Any(c => certificateManager.IsTrusted(c))) + { + reporter.Verbose($@"The following certificates were found, but none of them is trusted: +{string.Join(Environment.NewLine, certificates.Select(c => $"{c.Subject} - {c.Thumbprint}"))}"); + return ErrorCertificateNotTrusted; + } + else + { + reporter.Verbose("A trusted certificate was found."); + } + } + + return Success; + } + + private static int EnsureHttpsCertificate(CommandOption exportPath, CommandOption password, CommandOption trust, IReporter reporter) + { + var now = DateTimeOffset.Now; + var manager = new CertificateManager(); + + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) && trust?.HasValue() == true) + { + reporter.Warn("Trusting the HTTPS development certificate was requested. If the certificate is not " + + "already trusted we will run the following command:" + Environment.NewLine + + "'sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain <>'" + + Environment.NewLine + "This command might prompt you for your password to install the certificate " + + "on the system keychain."); + } + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && trust?.HasValue() == true) + { + reporter.Warn("Trusting the HTTPS development certificate was requested. A confirmation prompt will be displayed " + + "if the certificate was not previously trusted. Click yes on the prompt to trust the certificate."); + } + + var result = manager.EnsureAspNetCoreHttpsDevelopmentCertificate( + now, + now.Add(HttpsCertificateValidity), + exportPath.Value(), + trust == null ? false : trust.HasValue(), + password.HasValue(), + password.Value()); + + switch (result) + { + case EnsureCertificateResult.Succeeded: + reporter.Output("The HTTPS developer certificate was generated successfully."); + if (exportPath.Value() != null) + { + reporter.Verbose($"The certificate was exported to {Path.GetFullPath(exportPath.Value())}"); + } + return Success; + case EnsureCertificateResult.ValidCertificatePresent: + reporter.Output("A valid HTTPS certificate is already present."); + if (exportPath.Value() != null) + { + reporter.Verbose($"The certificate was exported to {Path.GetFullPath(exportPath.Value())}"); + } + return Success; + case EnsureCertificateResult.ErrorCreatingTheCertificate: + reporter.Error("There was an error creating the HTTPS developer certificate."); + return ErrorCreatingTheCertificate; + case EnsureCertificateResult.ErrorSavingTheCertificateIntoTheCurrentUserPersonalStore: + reporter.Error("There was an error saving the HTTPS developer certificate to the current user personal certificate store."); + return ErrorSavingTheCertificate; + case EnsureCertificateResult.ErrorExportingTheCertificate: + reporter.Warn("There was an error exporting HTTPS developer certificate to a file."); + return ErrorExportingTheCertificate; + case EnsureCertificateResult.FailedToTrustTheCertificate: + reporter.Warn("There was an error trusting HTTPS developer certificate."); + return ErrorTrustingTheCertificate; + case EnsureCertificateResult.UserCancelledTrustStep: + reporter.Warn("The user cancelled the trust step."); + return ErrorUserCancelledTrustPrompt; + default: + reporter.Error("Something went wrong. The HTTPS developer certificate could not be created."); + return CriticalError; + } + } + } +} diff --git a/src/Tools/dotnet-dev-certs/src/dotnet-dev-certs.csproj b/src/Tools/dotnet-dev-certs/src/dotnet-dev-certs.csproj new file mode 100644 index 0000000000..8be696049a --- /dev/null +++ b/src/Tools/dotnet-dev-certs/src/dotnet-dev-certs.csproj @@ -0,0 +1,32 @@ + + + + netcoreapp3.0 + exe + Command line tool to generate certificates used in ASP.NET Core during development. + Microsoft.AspNetCore.DeveloperCertificates.Tools + dotnet;developercertificates + true + + win-x64;win-x86 + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Tools/dotnet-sql-cache/README.md b/src/Tools/dotnet-sql-cache/README.md new file mode 100644 index 0000000000..141c1cab65 --- /dev/null +++ b/src/Tools/dotnet-sql-cache/README.md @@ -0,0 +1,8 @@ +dotnet-sql-cache +================ + +`dotnet-sql-cache` is a command line tool that creates table and indexes in Microsoft SQL Server database to be used for distributed caching + +### How To Use + +Run `dotnet sql-cache --help` for more information about usage. diff --git a/src/Tools/dotnet-sql-cache/src/Program.cs b/src/Tools/dotnet-sql-cache/src/Program.cs new file mode 100644 index 0000000000..874244f603 --- /dev/null +++ b/src/Tools/dotnet-sql-cache/src/Program.cs @@ -0,0 +1,173 @@ +// 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.Data; +using System.Data.SqlClient; +using System.Reflection; +using Microsoft.Extensions.CommandLineUtils; +using Microsoft.Extensions.Tools.Internal; + +namespace Microsoft.Extensions.Caching.SqlConfig.Tools +{ + public class Program + { + private string _connectionString = null; + private string _schemaName = null; + private string _tableName = null; + private readonly IConsole _console; + + public Program(IConsole console) + { + Ensure.NotNull(console, nameof(console)); + + _console = console; + } + + public static int Main(string[] args) + { + return new Program(PhysicalConsole.Singleton).Run(args); + } + + public int Run(string[] args) + { + DebugHelper.HandleDebugSwitch(ref args); + + try + { + var app = new CommandLineApplication + { + Name = "dotnet sql-cache", + FullName = "SQL Server Cache Command Line Tool", + Description = + "Creates table and indexes in Microsoft SQL Server database to be used for distributed caching", + }; + + app.HelpOption(); + app.VersionOptionFromAssemblyAttributes(typeof(Program).GetTypeInfo().Assembly); + var verbose = app.VerboseOption(); + + app.Command("create", command => + { + command.Description = app.Description; + + var connectionStringArg = command.Argument( + "[connectionString]", "The connection string to connect to the database."); + + var schemaNameArg = command.Argument( + "[schemaName]", "Name of the table schema."); + + var tableNameArg = command.Argument( + "[tableName]", "Name of the table to be created."); + + command.HelpOption(); + + command.OnExecute(() => + { + var reporter = CreateReporter(verbose.HasValue()); + if (string.IsNullOrEmpty(connectionStringArg.Value) + || string.IsNullOrEmpty(schemaNameArg.Value) + || string.IsNullOrEmpty(tableNameArg.Value)) + { + reporter.Error("Invalid input"); + app.ShowHelp(); + return 2; + } + + _connectionString = connectionStringArg.Value; + _schemaName = schemaNameArg.Value; + _tableName = tableNameArg.Value; + + return CreateTableAndIndexes(reporter); + }); + }); + + // Show help information if no subcommand/option was specified. + app.OnExecute(() => + { + app.ShowHelp(); + return 2; + }); + + return app.Execute(args); + } + catch (Exception exception) + { + CreateReporter(verbose: false).Error($"An error occurred. {exception.Message}"); + return 1; + } + } + + private IReporter CreateReporter(bool verbose) + => new ConsoleReporter(_console, verbose, quiet: false); + private int CreateTableAndIndexes(IReporter reporter) + { + ValidateConnectionString(); + + using (var connection = new SqlConnection(_connectionString)) + { + connection.Open(); + + var sqlQueries = new SqlQueries(_schemaName, _tableName); + var command = new SqlCommand(sqlQueries.TableInfo, connection); + + using (var reader = command.ExecuteReader(CommandBehavior.SingleRow)) + { + if (reader.Read()) + { + reporter.Warn( + $"Table with schema '{_schemaName}' and name '{_tableName}' already exists. " + + "Provide a different table name and try again."); + return 1; + } + } + + using (var transaction = connection.BeginTransaction()) + { + try + { + command = new SqlCommand(sqlQueries.CreateTable, connection, transaction); + + reporter.Verbose($"Executing {command.CommandText}"); + command.ExecuteNonQuery(); + + command = new SqlCommand( + sqlQueries.CreateNonClusteredIndexOnExpirationTime, + connection, + transaction); + + reporter.Verbose($"Executing {command.CommandText}"); + command.ExecuteNonQuery(); + + transaction.Commit(); + + reporter.Output("Table and index were created successfully."); + } + catch (Exception ex) + { + reporter.Error( + $"An error occurred while trying to create the table and index. {ex.Message}"); + transaction.Rollback(); + + return 1; + } + } + } + + return 0; + } + + private void ValidateConnectionString() + { + try + { + new SqlConnectionStringBuilder(_connectionString); + } + catch (Exception ex) + { + throw new ArgumentException( + $"Invalid SQL Server connection string '{_connectionString}'. {ex.Message}", ex); + } + } + } +} diff --git a/src/Tools/dotnet-sql-cache/src/SqlQueries.cs b/src/Tools/dotnet-sql-cache/src/SqlQueries.cs new file mode 100644 index 0000000000..7b9c73a990 --- /dev/null +++ b/src/Tools/dotnet-sql-cache/src/SqlQueries.cs @@ -0,0 +1,67 @@ +// 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.Caching.SqlConfig.Tools +{ + internal class SqlQueries + { + private const string CreateTableFormat = "CREATE TABLE {0}(" + + // Maximum size of primary key column is 900 bytes (898 bytes from key + 2 additional bytes used by the + // Sql Server). In the case where the key is greater than 898 bytes, then it gets truncated. + // - Add collation to the key column to make it case-sensitive + "Id nvarchar(449) COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL, " + + "Value varbinary(MAX) NOT NULL, " + + "ExpiresAtTime datetimeoffset NOT NULL, " + + "SlidingExpirationInSeconds bigint NULL," + + "AbsoluteExpiration datetimeoffset NULL, " + + "PRIMARY KEY (Id))"; + + private const string CreateNonClusteredIndexOnExpirationTimeFormat + = "CREATE NONCLUSTERED INDEX Index_ExpiresAtTime ON {0}(ExpiresAtTime)"; + + private const string TableInfoFormat = + "SELECT TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, TABLE_TYPE " + + "FROM INFORMATION_SCHEMA.TABLES " + + "WHERE TABLE_SCHEMA = '{0}' " + + "AND TABLE_NAME = '{1}'"; + + public SqlQueries(string schemaName, string tableName) + { + if (string.IsNullOrEmpty(schemaName)) + { + throw new ArgumentException("Schema name cannot be empty or null"); + } + if (string.IsNullOrEmpty(tableName)) + { + throw new ArgumentException("Table name cannot be empty or null"); + } + + var tableNameWithSchema = string.Format( + "{0}.{1}", DelimitIdentifier(schemaName), DelimitIdentifier(tableName)); + CreateTable = string.Format(CreateTableFormat, tableNameWithSchema); + CreateNonClusteredIndexOnExpirationTime = string.Format( + CreateNonClusteredIndexOnExpirationTimeFormat, + tableNameWithSchema); + TableInfo = string.Format(TableInfoFormat, EscapeLiteral(schemaName), EscapeLiteral(tableName)); + } + + public string CreateTable { get; } + + public string CreateNonClusteredIndexOnExpirationTime { get; } + + public string TableInfo { get; } + + // From EF's SqlServerQuerySqlGenerator + private string DelimitIdentifier(string identifier) + { + return "[" + identifier.Replace("]", "]]") + "]"; + } + + private string EscapeLiteral(string literal) + { + return literal.Replace("'", "''"); + } + } +} diff --git a/src/Tools/dotnet-sql-cache/src/dotnet-sql-cache.csproj b/src/Tools/dotnet-sql-cache/src/dotnet-sql-cache.csproj new file mode 100644 index 0000000000..d7f9e0c274 --- /dev/null +++ b/src/Tools/dotnet-sql-cache/src/dotnet-sql-cache.csproj @@ -0,0 +1,30 @@ + + + + netcoreapp3.0 + exe + Command line tool to create tables and indexes in a Microsoft SQL Server database for distributed caching. + cache;distributedcache;sqlserver + true + + win-x64;win-x86 + + + + + + + + + + + + + + + + + + + + diff --git a/src/Tools/dotnet-user-secrets/README.md b/src/Tools/dotnet-user-secrets/README.md new file mode 100644 index 0000000000..0d8666cdb6 --- /dev/null +++ b/src/Tools/dotnet-user-secrets/README.md @@ -0,0 +1,8 @@ +dotnet-user-secrets +=================== + +`dotnet-user-secrets` is a command line tool for managing the secrets in a user secret store. + +### How To Use + +Run `dotnet user-secrets --help` for more information about usage. diff --git a/src/Tools/dotnet-user-secrets/src/CommandLineOptions.cs b/src/Tools/dotnet-user-secrets/src/CommandLineOptions.cs new file mode 100644 index 0000000000..8495b6de9d --- /dev/null +++ b/src/Tools/dotnet-user-secrets/src/CommandLineOptions.cs @@ -0,0 +1,73 @@ +// 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; +using Microsoft.Extensions.CommandLineUtils; +using Microsoft.Extensions.SecretManager.Tools.Internal; +using Microsoft.Extensions.Tools.Internal; + +namespace Microsoft.Extensions.SecretManager.Tools +{ + public class CommandLineOptions + { + public ICommand Command { get; set; } + public string Configuration { get; private set; } + public string Id { get; private set; } + public bool IsHelp { get; private set; } + public bool IsVerbose { get; private set; } + public string Project { get; private set; } + + public static CommandLineOptions Parse(string[] args, IConsole console) + { + var app = new CommandLineApplication() + { + Out = console.Out, + Error = console.Error, + Name = "dotnet user-secrets", + FullName = "User Secrets Manager", + Description = "Manages user secrets" + }; + + app.HelpOption(); + app.VersionOptionFromAssemblyAttributes(typeof(Program).GetTypeInfo().Assembly); + + var optionVerbose = app.VerboseOption(); + + var optionProject = app.Option("-p|--project ", "Path to project. Defaults to searching the current directory.", + CommandOptionType.SingleValue, inherited: true); + + var optionConfig = app.Option("-c|--configuration ", $"The project configuration to use. Defaults to 'Debug'.", + CommandOptionType.SingleValue, inherited: true); + + // the escape hatch if project evaluation fails, or if users want to alter a secret store other than the one + // in the current project + var optionId = app.Option("--id", "The user secret ID to use.", + CommandOptionType.SingleValue, inherited: true); + + var options = new CommandLineOptions(); + + app.Command("set", c => SetCommand.Configure(c, options, console)); + app.Command("remove", c => RemoveCommand.Configure(c, options)); + app.Command("list", c => ListCommand.Configure(c, options)); + app.Command("clear", c => ClearCommand.Configure(c, options)); + app.Command("init", c => InitCommandFactory.Configure(c, options)); + + // Show help information if no subcommand/option was specified. + app.OnExecute(() => app.ShowHelp()); + + if (app.Execute(args) != 0) + { + // when command line parsing error in subcommand + return null; + } + + options.Configuration = optionConfig.Value(); + options.Id = optionId.Value(); + options.IsHelp = app.IsShowingInformation; + options.IsVerbose = optionVerbose.HasValue(); + options.Project = optionProject.Value(); + + return options; + } + } +} diff --git a/src/Tools/dotnet-user-secrets/src/Internal/ClearCommand.cs b/src/Tools/dotnet-user-secrets/src/Internal/ClearCommand.cs new file mode 100644 index 0000000000..108fd542d7 --- /dev/null +++ b/src/Tools/dotnet-user-secrets/src/Internal/ClearCommand.cs @@ -0,0 +1,27 @@ +// 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.Extensions.CommandLineUtils; + +namespace Microsoft.Extensions.SecretManager.Tools.Internal +{ + internal class ClearCommand : ICommand + { + public static void Configure(CommandLineApplication command, CommandLineOptions options) + { + command.Description = "Deletes all the application secrets"; + command.HelpOption(); + + command.OnExecute(() => + { + options.Command = new ClearCommand(); + }); + } + + public void Execute(CommandContext context) + { + context.SecretStore.Clear(); + context.SecretStore.Save(); + } + } +} diff --git a/src/Tools/dotnet-user-secrets/src/Internal/CommandContext.cs b/src/Tools/dotnet-user-secrets/src/Internal/CommandContext.cs new file mode 100644 index 0000000000..0ac0ea40fe --- /dev/null +++ b/src/Tools/dotnet-user-secrets/src/Internal/CommandContext.cs @@ -0,0 +1,24 @@ +// 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.Extensions.Tools.Internal; + +namespace Microsoft.Extensions.SecretManager.Tools.Internal +{ + public class CommandContext + { + public CommandContext( + SecretsStore store, + IReporter reporter, + IConsole console) + { + SecretStore = store; + Reporter = reporter; + Console = console; + } + + public IConsole Console { get; } + public IReporter Reporter { get; } + public SecretsStore SecretStore { get; } + } +} \ No newline at end of file diff --git a/src/Tools/dotnet-user-secrets/src/Internal/ICommand.cs b/src/Tools/dotnet-user-secrets/src/Internal/ICommand.cs new file mode 100644 index 0000000000..636c08a07c --- /dev/null +++ b/src/Tools/dotnet-user-secrets/src/Internal/ICommand.cs @@ -0,0 +1,10 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.Extensions.SecretManager.Tools.Internal +{ + public interface ICommand + { + void Execute(CommandContext context); + } +} \ No newline at end of file diff --git a/src/Tools/dotnet-user-secrets/src/Internal/InitCommand.cs b/src/Tools/dotnet-user-secrets/src/Internal/InitCommand.cs new file mode 100644 index 0000000000..670da42c4e --- /dev/null +++ b/src/Tools/dotnet-user-secrets/src/Internal/InitCommand.cs @@ -0,0 +1,126 @@ +// 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.Xml.Linq; +using System.Xml.XPath; +using Microsoft.Extensions.CommandLineUtils; + +namespace Microsoft.Extensions.SecretManager.Tools.Internal +{ + // Workaround used to handle the fact that the options have not been parsed at configuration time + public class InitCommandFactory : ICommand + { + public CommandLineOptions Options { get; } + + internal static void Configure(CommandLineApplication command, CommandLineOptions options) + { + command.Description = "Set a user secrets ID to enable secret storage"; + command.HelpOption(); + + command.OnExecute(() => + { + options.Command = new InitCommandFactory(options); + }); + } + + public InitCommandFactory(CommandLineOptions options) + { + Options = options; + } + + public void Execute(CommandContext context) + { + new InitCommand(Options.Id, Options.Project).Execute(context); + } + + public void Execute(CommandContext context, string workingDirectory) + { + new InitCommand(Options.Id, Options.Project).Execute(context, workingDirectory); + } + } + + public class InitCommand : ICommand + { + public string OverrideId { get; } + public string ProjectPath { get; } + public string WorkingDirectory { get; private set; } = Directory.GetCurrentDirectory(); + + public InitCommand(string id, string project) + { + OverrideId = id; + ProjectPath = project; + } + + public void Execute(CommandContext context, string workingDirectory) + { + WorkingDirectory = workingDirectory; + Execute(context); + } + + public void Execute(CommandContext context) + { + var projectPath = ResolveProjectPath(ProjectPath, WorkingDirectory); + + // Load the project file as XML + var projectDocument = XDocument.Load(projectPath); + + // Accept the `--id` CLI option to the main app + string newSecretsId = string.IsNullOrWhiteSpace(OverrideId) + ? Guid.NewGuid().ToString() + : OverrideId; + + // Confirm secret ID does not contain invalid characters + if (Path.GetInvalidPathChars().Any(invalidChar => newSecretsId.Contains(invalidChar))) + { + throw new ArgumentException(Resources.FormatError_InvalidSecretsId(newSecretsId)); + } + + var existingUserSecretsId = projectDocument.XPathSelectElements("//UserSecretsId").FirstOrDefault(); + + // Check if a UserSecretsId is already set + if (existingUserSecretsId != default) + { + // Only set the UserSecretsId if the user specified an explicit value + if (string.IsNullOrWhiteSpace(OverrideId)) + { + context.Reporter.Output(Resources.FormatMessage_ProjectAlreadyInitialized(projectPath)); + return; + } + + existingUserSecretsId.SetValue(newSecretsId); + } + else + { + // Find the first non-conditional PropertyGroup + var propertyGroup = projectDocument.Root.DescendantNodes() + .FirstOrDefault(node => node is XElement el + && el.Name == "PropertyGroup" + && el.Attributes().All(attr => + attr.Name != "Condition")) as XElement; + + // No valid property group, create a new one + if (propertyGroup == null) + { + propertyGroup = new XElement("PropertyGroup"); + projectDocument.Root.AddFirst(propertyGroup); + } + + // Add UserSecretsId element + propertyGroup.Add(new XElement("UserSecretsId", newSecretsId)); + } + + projectDocument.Save(projectPath); + + context.Reporter.Output(Resources.FormatMessage_SetUserSecretsIdForProject(newSecretsId, projectPath)); + } + + private static string ResolveProjectPath(string name, string path) + { + var finder = new MsBuildProjectFinder(path); + return finder.FindMsBuildProject(name); + } + } +} diff --git a/src/Tools/dotnet-user-secrets/src/Internal/ListCommand.cs b/src/Tools/dotnet-user-secrets/src/Internal/ListCommand.cs new file mode 100644 index 0000000000..bbefab2a13 --- /dev/null +++ b/src/Tools/dotnet-user-secrets/src/Internal/ListCommand.cs @@ -0,0 +1,67 @@ +// 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.Extensions.CommandLineUtils; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace Microsoft.Extensions.SecretManager.Tools.Internal +{ + internal class ListCommand : ICommand + { + private readonly bool _jsonOutput; + + public static void Configure(CommandLineApplication command, CommandLineOptions options) + { + command.Description = "Lists all the application secrets"; + command.HelpOption(); + + var optJson = command.Option("--json", "Use json output. JSON is wrapped by '//BEGIN' and '//END'", + CommandOptionType.NoValue); + + command.OnExecute(() => + { + options.Command = new ListCommand(optJson.HasValue()); + }); + } + + public ListCommand(bool jsonOutput) + { + _jsonOutput = jsonOutput; + } + + public void Execute(CommandContext context) + { + if (_jsonOutput) + { + ReportJson(context); + return; + } + + if (context.SecretStore.Count == 0) + { + context.Reporter.Output(Resources.Error_No_Secrets_Found); + } + else + { + foreach (var secret in context.SecretStore.AsEnumerable()) + { + context.Reporter.Output(Resources.FormatMessage_Secret_Value_Format(secret.Key, secret.Value)); + } + } + } + + private void ReportJson(CommandContext context) + { + var jObject = new JObject(); + foreach(var item in context.SecretStore.AsEnumerable()) + { + jObject[item.Key] = item.Value; + } + + context.Reporter.Output("//BEGIN"); + context.Reporter.Output(jObject.ToString(Formatting.Indented)); + context.Reporter.Output("//END"); + } + } +} diff --git a/src/Tools/dotnet-user-secrets/src/Internal/MsBuildProjectFinder.cs b/src/Tools/dotnet-user-secrets/src/Internal/MsBuildProjectFinder.cs new file mode 100644 index 0000000000..a24843b04d --- /dev/null +++ b/src/Tools/dotnet-user-secrets/src/Internal/MsBuildProjectFinder.cs @@ -0,0 +1,58 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.IO; +using System.Linq; +using Microsoft.Extensions.Tools.Internal; + +namespace Microsoft.Extensions.SecretManager.Tools.Internal +{ + internal class MsBuildProjectFinder + { + private readonly string _directory; + + public MsBuildProjectFinder(string directory) + { + Ensure.NotNullOrEmpty(directory, nameof(directory)); + + _directory = directory; + } + + public string FindMsBuildProject(string project) + { + var projectPath = project ?? _directory; + + if (!Path.IsPathRooted(projectPath)) + { + projectPath = Path.Combine(_directory, projectPath); + } + + if (Directory.Exists(projectPath)) + { + var projects = Directory.EnumerateFileSystemEntries(projectPath, "*.*proj", SearchOption.TopDirectoryOnly) + .Where(f => !".xproj".Equals(Path.GetExtension(f), StringComparison.OrdinalIgnoreCase)) + .ToList(); + + if (projects.Count > 1) + { + throw new FileNotFoundException(Resources.FormatError_MultipleProjectsFound(projectPath)); + } + + if (projects.Count == 0) + { + throw new FileNotFoundException(Resources.FormatError_NoProjectsFound(projectPath)); + } + + return projects[0]; + } + + if (!File.Exists(projectPath)) + { + throw new FileNotFoundException(Resources.FormatError_ProjectPath_NotFound(projectPath)); + } + + return projectPath; + } + } +} \ No newline at end of file diff --git a/src/Tools/dotnet-user-secrets/src/Internal/ProjectIdResolver.cs b/src/Tools/dotnet-user-secrets/src/Internal/ProjectIdResolver.cs new file mode 100644 index 0000000000..da5111ca51 --- /dev/null +++ b/src/Tools/dotnet-user-secrets/src/Internal/ProjectIdResolver.cs @@ -0,0 +1,124 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using Microsoft.Extensions.CommandLineUtils; +using Microsoft.Extensions.Tools.Internal; + +namespace Microsoft.Extensions.SecretManager.Tools.Internal +{ + public class ProjectIdResolver + { + private const string DefaultConfig = "Debug"; + private readonly IReporter _reporter; + private readonly string _targetsFile; + private readonly string _workingDirectory; + + public ProjectIdResolver(IReporter reporter, string workingDirectory) + { + _workingDirectory = workingDirectory; + _reporter = reporter; + _targetsFile = FindTargetsFile(); + } + + public string Resolve(string project, string configuration) + { + var finder = new MsBuildProjectFinder(_workingDirectory); + var projectFile = finder.FindMsBuildProject(project); + + _reporter.Verbose(Resources.FormatMessage_Project_File_Path(projectFile)); + + configuration = !string.IsNullOrEmpty(configuration) + ? configuration + : DefaultConfig; + + var outputFile = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + try + { + var args = new[] + { + "msbuild", + projectFile, + "/nologo", + "/t:_ExtractUserSecretsMetadata", // defined in SecretManager.targets + "/p:_UserSecretsMetadataFile=" + outputFile, + "/p:Configuration=" + configuration, + "/p:CustomAfterMicrosoftCommonTargets=" + _targetsFile, + "/p:CustomAfterMicrosoftCommonCrossTargetingTargets=" + _targetsFile, + }; + var psi = new ProcessStartInfo + { + FileName = DotNetMuxer.MuxerPathOrDefault(), + Arguments = ArgumentEscaper.EscapeAndConcatenate(args), + RedirectStandardOutput = true, + RedirectStandardError = true + }; + +#if DEBUG + _reporter.Verbose($"Invoking '{psi.FileName} {psi.Arguments}'"); +#endif + + var process = Process.Start(psi); + process.WaitForExit(); + + if (process.ExitCode != 0) + { + _reporter.Verbose(process.StandardOutput.ReadToEnd()); + _reporter.Verbose(process.StandardError.ReadToEnd()); + throw new InvalidOperationException(Resources.FormatError_ProjectFailedToLoad(projectFile)); + } + + var id = File.ReadAllText(outputFile)?.Trim(); + if (string.IsNullOrEmpty(id)) + { + throw new InvalidOperationException(Resources.FormatError_ProjectMissingId(projectFile)); + } + return id; + + } + finally + { + TryDelete(outputFile); + } + } + + private string FindTargetsFile() + { + var assemblyDir = Path.GetDirectoryName(typeof(ProjectIdResolver).Assembly.Location); + var searchPaths = new[] + { + Path.Combine(AppContext.BaseDirectory, "assets"), + Path.Combine(assemblyDir, "assets"), + AppContext.BaseDirectory, + assemblyDir, + }; + + var targetPath = searchPaths.Select(p => Path.Combine(p, "SecretManager.targets")).FirstOrDefault(File.Exists); + if (targetPath == null) + { + _reporter.Error("Fatal error: could not find SecretManager.targets"); + return null; + } + return targetPath; + } + + private static void TryDelete(string file) + { + try + { + if (File.Exists(file)) + { + File.Delete(file); + } + } + catch + { + // whatever + } + } + } +} diff --git a/src/Tools/dotnet-user-secrets/src/Internal/ReadableJsonConfigurationSource.cs b/src/Tools/dotnet-user-secrets/src/Internal/ReadableJsonConfigurationSource.cs new file mode 100644 index 0000000000..96d0554aeb --- /dev/null +++ b/src/Tools/dotnet-user-secrets/src/Internal/ReadableJsonConfigurationSource.cs @@ -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. + +using System.Collections.Generic; +using Microsoft.Extensions.Configuration.Json; + +namespace Microsoft.Extensions.SecretManager.Tools.Internal +{ + public class ReadableJsonConfigurationProvider : JsonConfigurationProvider + { + public ReadableJsonConfigurationProvider() + : base(new JsonConfigurationSource()) + { + } + + public IDictionary CurrentData => Data; + } +} \ No newline at end of file diff --git a/src/Tools/dotnet-user-secrets/src/Internal/RemoveCommand.cs b/src/Tools/dotnet-user-secrets/src/Internal/RemoveCommand.cs new file mode 100644 index 0000000000..3bc594b149 --- /dev/null +++ b/src/Tools/dotnet-user-secrets/src/Internal/RemoveCommand.cs @@ -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 Microsoft.Extensions.CommandLineUtils; + +namespace Microsoft.Extensions.SecretManager.Tools.Internal +{ + internal class RemoveCommand : ICommand + { + private readonly string _keyName; + + public static void Configure(CommandLineApplication command, CommandLineOptions options) + { + command.Description = "Removes the specified user secret"; + command.HelpOption(); + + var keyArg = command.Argument("[name]", "Name of the secret"); + command.OnExecute(() => + { + if (keyArg.Value == null) + { + throw new CommandParsingException(command, Resources.FormatError_MissingArgument("name")); + } + + options.Command = new RemoveCommand(keyArg.Value); + }); + } + + + public RemoveCommand(string keyName) + { + _keyName = keyName; + } + + public void Execute(CommandContext context) + { + if (!context.SecretStore.ContainsKey(_keyName)) + { + context.Reporter.Warn(Resources.FormatError_Missing_Secret(_keyName)); + } + else + { + context.SecretStore.Remove(_keyName); + context.SecretStore.Save(); + } + } + } +} diff --git a/src/Tools/dotnet-user-secrets/src/Internal/SecretsStore.cs b/src/Tools/dotnet-user-secrets/src/Internal/SecretsStore.cs new file mode 100644 index 0000000000..93d46242f2 --- /dev/null +++ b/src/Tools/dotnet-user-secrets/src/Internal/SecretsStore.cs @@ -0,0 +1,87 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration.UserSecrets; +using Microsoft.Extensions.Tools.Internal; +using Newtonsoft.Json.Linq; + +namespace Microsoft.Extensions.SecretManager.Tools.Internal +{ + public class SecretsStore + { + private readonly string _secretsFilePath; + private IDictionary _secrets; + + public SecretsStore(string userSecretsId, IReporter reporter) + { + Ensure.NotNull(userSecretsId, nameof(userSecretsId)); + + _secretsFilePath = PathHelper.GetSecretsPathFromSecretsId(userSecretsId); + + // workaround bug in configuration + var secretDir = Path.GetDirectoryName(_secretsFilePath); + Directory.CreateDirectory(secretDir); + + reporter.Verbose(Resources.FormatMessage_Secret_File_Path(_secretsFilePath)); + _secrets = Load(userSecretsId); + } + + public string this[string key] + { + get + { + return _secrets[key]; + } + } + + public int Count => _secrets.Count; + + public bool ContainsKey(string key) => _secrets.ContainsKey(key); + + public IEnumerable> AsEnumerable() => _secrets; + + public void Clear() => _secrets.Clear(); + + public void Set(string key, string value) => _secrets[key] = value; + + public void Remove(string key) + { + if (_secrets.ContainsKey(key)) + { + _secrets.Remove(key); + } + } + + public virtual void Save() + { + Directory.CreateDirectory(Path.GetDirectoryName(_secretsFilePath)); + + var contents = new JObject(); + if (_secrets != null) + { + foreach (var secret in _secrets.AsEnumerable()) + { + contents[secret.Key] = secret.Value; + } + } + + File.WriteAllText(_secretsFilePath, contents.ToString(), Encoding.UTF8); + } + + protected virtual IDictionary Load(string userSecretsId) + { + return new ConfigurationBuilder() + .AddJsonFile(_secretsFilePath, optional: true) + .Build() + .AsEnumerable() + .Where(i => i.Value != null) + .ToDictionary(i => i.Key, i => i.Value, StringComparer.OrdinalIgnoreCase); + } + } +} \ No newline at end of file diff --git a/src/Tools/dotnet-user-secrets/src/Internal/SetCommand.cs b/src/Tools/dotnet-user-secrets/src/Internal/SetCommand.cs new file mode 100644 index 0000000000..fa389ca242 --- /dev/null +++ b/src/Tools/dotnet-user-secrets/src/Internal/SetCommand.cs @@ -0,0 +1,106 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.IO; +using System.Runtime.InteropServices; +using System.Text; +using Microsoft.Extensions.CommandLineUtils; +using Microsoft.Extensions.Tools.Internal; + +namespace Microsoft.Extensions.SecretManager.Tools.Internal +{ + internal class SetCommand + { + public static void Configure(CommandLineApplication command, CommandLineOptions options, IConsole console) + { + command.Description = "Sets the user secret to the specified value"; + command.ExtendedHelpText = @" +Additional Info: + This command will also handle piped input. Piped input is expected to be a valid JSON format. + +Examples: + dotnet user-secrets set ConnStr ""User ID=bob;Password=***"" +"; + + var catCmd = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + ? @"type .\secrets.json" + : "cat ./secrets.json"; + + command.ExtendedHelpText += $@" {catCmd} | dotnet user-secrets set"; + + command.HelpOption(); + + var nameArg = command.Argument("[name]", "Name of the secret"); + var valueArg = command.Argument("[value]", "Value of the secret"); + + command.OnExecute(() => + { + if (console.IsInputRedirected && nameArg.Value == null) + { + options.Command = new FromStdInStrategy(); + } + else + { + if (string.IsNullOrEmpty(nameArg.Value)) + { + throw new CommandParsingException(command, Resources.FormatError_MissingArgument("name")); + } + + if (valueArg.Value == null) + { + throw new CommandParsingException(command, Resources.FormatError_MissingArgument("value")); + } + + options.Command = new ForOneValueStrategy(nameArg.Value, valueArg.Value); + } + }); + } + + public class FromStdInStrategy : ICommand + { + public void Execute(CommandContext context) + { + // parses stdin with the same parser that Microsoft.Extensions.Configuration.Json would use + var provider = new ReadableJsonConfigurationProvider(); + using (var stream = new MemoryStream()) + { + using (var writer = new StreamWriter(stream, Encoding.Unicode, 1024, true)) + { + writer.Write(context.Console.In.ReadToEnd()); // TODO buffer? + } + + stream.Seek(0, SeekOrigin.Begin); + provider.Load(stream); + } + + foreach (var k in provider.CurrentData) + { + context.SecretStore.Set(k.Key, k.Value); + } + + context.Reporter.Output(Resources.FormatMessage_Saved_Secrets(provider.CurrentData.Count)); + + context.SecretStore.Save(); + } + } + + public class ForOneValueStrategy : ICommand + { + private readonly string _keyName; + private readonly string _keyValue; + + public ForOneValueStrategy(string keyName, string keyValue) + { + _keyName = keyName; + _keyValue = keyValue; + } + + public void Execute(CommandContext context) + { + context.SecretStore.Set(_keyName, _keyValue); + context.SecretStore.Save(); + context.Reporter.Output(Resources.FormatMessage_Saved_Secret(_keyName, _keyValue)); + } + } + } +} diff --git a/src/Tools/dotnet-user-secrets/src/Program.cs b/src/Tools/dotnet-user-secrets/src/Program.cs new file mode 100644 index 0000000000..710756eb88 --- /dev/null +++ b/src/Tools/dotnet-user-secrets/src/Program.cs @@ -0,0 +1,111 @@ +// 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 Microsoft.Extensions.CommandLineUtils; +using Microsoft.Extensions.SecretManager.Tools.Internal; +using Microsoft.Extensions.Tools.Internal; + +namespace Microsoft.Extensions.SecretManager.Tools +{ + public class Program + { + private readonly IConsole _console; + private readonly string _workingDirectory; + + public static int Main(string[] args) + { + DebugHelper.HandleDebugSwitch(ref args); + + int rc; + new Program(PhysicalConsole.Singleton, Directory.GetCurrentDirectory()).TryRun(args, out rc); + return rc; + } + + public Program(IConsole console, string workingDirectory) + { + _console = console; + _workingDirectory = workingDirectory; + } + + public bool TryRun(string[] args, out int returnCode) + { + try + { + returnCode = RunInternal(args); + return true; + } + catch (Exception exception) + { + var reporter = CreateReporter(verbose: true); + reporter.Verbose(exception.ToString()); + reporter.Error(Resources.FormatError_Command_Failed(exception.Message)); + returnCode = 1; + return false; + } + } + + internal int RunInternal(params string[] args) + { + CommandLineOptions options; + try + { + options = CommandLineOptions.Parse(args, _console); + } + catch (CommandParsingException ex) + { + CreateReporter(verbose: false).Error(ex.Message); + return 1; + } + + if (options == null) + { + return 1; + } + + if (options.IsHelp) + { + return 2; + } + + var reporter = CreateReporter(options.IsVerbose); + + if (options.Command is InitCommandFactory initCmd) + { + initCmd.Execute(new CommandContext(null, reporter, _console), _workingDirectory); + return 0; + } + + string userSecretsId; + try + { + userSecretsId = ResolveId(options, reporter); + } + catch (Exception ex) when (ex is InvalidOperationException || ex is FileNotFoundException) + { + reporter.Error(ex.Message); + return 1; + } + + var store = new SecretsStore(userSecretsId, reporter); + var context = new Internal.CommandContext(store, reporter, _console); + options.Command.Execute(context); + return 0; + } + + private IReporter CreateReporter(bool verbose) + => new ConsoleReporter(_console, verbose, quiet: false); + + internal string ResolveId(CommandLineOptions options, IReporter reporter) + { + if (!string.IsNullOrEmpty(options.Id)) + { + return options.Id; + } + + var resolver = new ProjectIdResolver(reporter, _workingDirectory); + return resolver.Resolve(options.Project, options.Configuration); + } + } +} diff --git a/src/Tools/dotnet-user-secrets/src/Properties/AssemblyInfo.cs b/src/Tools/dotnet-user-secrets/src/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..ae77d384c1 --- /dev/null +++ b/src/Tools/dotnet-user-secrets/src/Properties/AssemblyInfo.cs @@ -0,0 +1,6 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Microsoft.Extensions.SecretManager.Tools.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] diff --git a/src/Tools/dotnet-user-secrets/src/Properties/Resources.Designer.cs b/src/Tools/dotnet-user-secrets/src/Properties/Resources.Designer.cs new file mode 100644 index 0000000000..8ee2a8f38e --- /dev/null +++ b/src/Tools/dotnet-user-secrets/src/Properties/Resources.Designer.cs @@ -0,0 +1,270 @@ +// +namespace Microsoft.Extensions.SecretManager.Tools +{ + using System.Globalization; + using System.Reflection; + using System.Resources; + + internal static class Resources + { + private static readonly ResourceManager _resourceManager + = new ResourceManager("Microsoft.Extensions.SecretManager.Tools.Resources", typeof(Resources).GetTypeInfo().Assembly); + + /// + /// Command failed : {message} + /// + internal static string Error_Command_Failed + { + get => GetString("Error_Command_Failed"); + } + + /// + /// Command failed : {message} + /// + internal static string FormatError_Command_Failed(object message) + => string.Format(CultureInfo.CurrentCulture, GetString("Error_Command_Failed", "message"), message); + + /// + /// Missing parameter value for '{name}'. + /// Use the '--help' flag to see info. + /// + internal static string Error_MissingArgument + { + get => GetString("Error_MissingArgument"); + } + + /// + /// Missing parameter value for '{name}'. + /// Use the '--help' flag to see info. + /// + internal static string FormatError_MissingArgument(object name) + => string.Format(CultureInfo.CurrentCulture, GetString("Error_MissingArgument", "name"), name); + + /// + /// Cannot find '{key}' in the secret store. + /// + internal static string Error_Missing_Secret + { + get => GetString("Error_Missing_Secret"); + } + + /// + /// Cannot find '{key}' in the secret store. + /// + internal static string FormatError_Missing_Secret(object key) + => string.Format(CultureInfo.CurrentCulture, GetString("Error_Missing_Secret", "key"), key); + + /// + /// Multiple MSBuild project files found in '{projectPath}'. Specify which to use with the --project option. + /// + internal static string Error_MultipleProjectsFound + { + get => GetString("Error_MultipleProjectsFound"); + } + + /// + /// Multiple MSBuild project files found in '{projectPath}'. Specify which to use with the --project option. + /// + internal static string FormatError_MultipleProjectsFound(object projectPath) + => string.Format(CultureInfo.CurrentCulture, GetString("Error_MultipleProjectsFound", "projectPath"), projectPath); + + /// + /// No secrets configured for this application. + /// + internal static string Error_No_Secrets_Found + { + get => GetString("Error_No_Secrets_Found"); + } + + /// + /// No secrets configured for this application. + /// + internal static string FormatError_No_Secrets_Found() + => GetString("Error_No_Secrets_Found"); + + /// + /// Could not find a MSBuild project file in '{projectPath}'. Specify which project to use with the --project option. + /// + internal static string Error_NoProjectsFound + { + get => GetString("Error_NoProjectsFound"); + } + + /// + /// Could not find a MSBuild project file in '{projectPath}'. Specify which project to use with the --project option. + /// + internal static string FormatError_NoProjectsFound(object projectPath) + => string.Format(CultureInfo.CurrentCulture, GetString("Error_NoProjectsFound", "projectPath"), projectPath); + + /// + /// Could not find the global property 'UserSecretsId' in MSBuild project '{project}'. Ensure this property is set in the project or use the '--id' command line option. + /// + internal static string Error_ProjectMissingId + { + get => GetString("Error_ProjectMissingId"); + } + + /// + /// Could not find the global property 'UserSecretsId' in MSBuild project '{project}'. Ensure this property is set in the project or use the '--id' command line option. + /// + internal static string FormatError_ProjectMissingId(object project) + => string.Format(CultureInfo.CurrentCulture, GetString("Error_ProjectMissingId", "project"), project); + + /// + /// The project file '{path}' does not exist. + /// + internal static string Error_ProjectPath_NotFound + { + get => GetString("Error_ProjectPath_NotFound"); + } + + /// + /// The project file '{path}' does not exist. + /// + internal static string FormatError_ProjectPath_NotFound(object path) + => string.Format(CultureInfo.CurrentCulture, GetString("Error_ProjectPath_NotFound", "path"), path); + + /// + /// Could not load the MSBuild project '{project}'. + /// + internal static string Error_ProjectFailedToLoad + { + get => GetString("Error_ProjectFailedToLoad"); + } + + /// + /// Could not load the MSBuild project '{project}'. + /// + internal static string FormatError_ProjectFailedToLoad(object project) + => string.Format(CultureInfo.CurrentCulture, GetString("Error_ProjectFailedToLoad", "project"), project); + + /// + /// Project file path {project}. + /// + internal static string Message_Project_File_Path + { + get => GetString("Message_Project_File_Path"); + } + + /// + /// Project file path {project}. + /// + internal static string FormatMessage_Project_File_Path(object project) + => string.Format(CultureInfo.CurrentCulture, GetString("Message_Project_File_Path", "project"), project); + + /// + /// Successfully saved {key} = {value} to the secret store. + /// + internal static string Message_Saved_Secret + { + get => GetString("Message_Saved_Secret"); + } + + /// + /// Successfully saved {key} = {value} to the secret store. + /// + internal static string FormatMessage_Saved_Secret(object key, object value) + => string.Format(CultureInfo.CurrentCulture, GetString("Message_Saved_Secret", "key", "value"), key, value); + + /// + /// Successfully saved {number} secrets to the secret store. + /// + internal static string Message_Saved_Secrets + { + get => GetString("Message_Saved_Secrets"); + } + + /// + /// Successfully saved {number} secrets to the secret store. + /// + internal static string FormatMessage_Saved_Secrets(object number) + => string.Format(CultureInfo.CurrentCulture, GetString("Message_Saved_Secrets", "number"), number); + + /// + /// Secrets file path {secretsFilePath}. + /// + internal static string Message_Secret_File_Path + { + get => GetString("Message_Secret_File_Path"); + } + + /// + /// Secrets file path {secretsFilePath}. + /// + internal static string FormatMessage_Secret_File_Path(object secretsFilePath) + => string.Format(CultureInfo.CurrentCulture, GetString("Message_Secret_File_Path", "secretsFilePath"), secretsFilePath); + + /// + /// {key} = {value} + /// + internal static string Message_Secret_Value_Format + { + get => GetString("Message_Secret_Value_Format"); + } + + /// + /// {key} = {value} + /// + internal static string FormatMessage_Secret_Value_Format(object key, object value) + => string.Format(CultureInfo.CurrentCulture, GetString("Message_Secret_Value_Format", "key", "value"), key, value); + + /// + /// The UserSecretsId '{userSecretsId}' cannot contain any characters that cannot be used in a file path. + /// + internal static string Error_InvalidSecretsId + { + get => GetString("Error_InvalidSecretsId"); + } + + /// + /// The UserSecretsId '{userSecretsId}' cannot contain any characters that cannot be used in a file path. + /// + internal static string FormatError_InvalidSecretsId(object userSecretsId) + => string.Format(CultureInfo.CurrentCulture, GetString("Error_InvalidSecretsId", "userSecretsId"), userSecretsId); + + /// + /// The MSBuild project '{project}' has already been initialized with a UserSecretsId. + /// + internal static string Message_ProjectAlreadyInitialized + { + get => GetString("Message_ProjectAlreadyInitialized"); + } + + /// + /// The MSBuild project '{project}' has already been initialized with a UserSecretsId. + /// + internal static string FormatMessage_ProjectAlreadyInitialized(object project) + => string.Format(CultureInfo.CurrentCulture, GetString("Message_ProjectAlreadyInitialized", "project"), project); + + /// + /// Set UserSecretsId to '{userSecretsId}' for MSBuild project '{project}'. + /// + internal static string Message_SetUserSecretsIdForProject + { + get => GetString("Message_SetUserSecretsIdForProject"); + } + + /// + /// Set UserSecretsId to '{userSecretsId}' for MSBuild project '{project}'. + /// + internal static string FormatMessage_SetUserSecretsIdForProject(object userSecretsId, object project) + => string.Format(CultureInfo.CurrentCulture, GetString("Message_SetUserSecretsIdForProject", "userSecretsId", "project"), userSecretsId, project); + + 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; + } + } +} diff --git a/src/Tools/dotnet-user-secrets/src/Resources.resx b/src/Tools/dotnet-user-secrets/src/Resources.resx new file mode 100644 index 0000000000..bfcdf99c2a --- /dev/null +++ b/src/Tools/dotnet-user-secrets/src/Resources.resx @@ -0,0 +1,172 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Command failed : {message} + + + Missing parameter value for '{name}'. +Use the '--help' flag to see info. + + + Cannot find '{key}' in the secret store. + + + Multiple MSBuild project files found in '{projectPath}'. Specify which to use with the --project option. + + + No secrets configured for this application. + + + Could not find a MSBuild project file in '{projectPath}'. Specify which project to use with the --project option. + + + Could not find the global property 'UserSecretsId' in MSBuild project '{project}'. Ensure this property is set in the project or use the '--id' command line option. + + + The project file '{path}' does not exist. + + + Could not load the MSBuild project '{project}'. + + + Project file path {project}. + + + Successfully saved {key} = {value} to the secret store. + + + Successfully saved {number} secrets to the secret store. + + + Secrets file path {secretsFilePath}. + + + {key} = {value} + + + The UserSecretsId '{userSecretsId}' cannot contain any characters that cannot be used in a file path. + + + The MSBuild project '{project}' has already been initialized with a UserSecretsId. + + + Set UserSecretsId to '{userSecretsId}' for MSBuild project '{project}'. + + \ No newline at end of file diff --git a/src/Tools/dotnet-user-secrets/src/assets/SecretManager.targets b/src/Tools/dotnet-user-secrets/src/assets/SecretManager.targets new file mode 100644 index 0000000000..8cf63eac00 --- /dev/null +++ b/src/Tools/dotnet-user-secrets/src/assets/SecretManager.targets @@ -0,0 +1,5 @@ + + + + + diff --git a/src/Tools/dotnet-user-secrets/src/dotnet-user-secrets.csproj b/src/Tools/dotnet-user-secrets/src/dotnet-user-secrets.csproj new file mode 100644 index 0000000000..fc5284440b --- /dev/null +++ b/src/Tools/dotnet-user-secrets/src/dotnet-user-secrets.csproj @@ -0,0 +1,42 @@ + + + + netcoreapp3.0 + exe + Command line tool to manage user secrets for Microsoft.Extensions.Configuration. + false + Microsoft.Extensions.SecretManager.Tools + configuration;secrets;usersecrets + true + + win-x64;win-x86 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Tools/dotnet-user-secrets/test/InitCommandTest.cs b/src/Tools/dotnet-user-secrets/test/InitCommandTest.cs new file mode 100644 index 0000000000..d1558e8811 --- /dev/null +++ b/src/Tools/dotnet-user-secrets/test/InitCommandTest.cs @@ -0,0 +1,119 @@ +// 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.Text; +using Microsoft.Extensions.Configuration.UserSecrets.Tests; +using Microsoft.Extensions.SecretManager.Tools.Internal; +using Microsoft.Extensions.Tools.Internal; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.Extensions.SecretManager.Tools.Tests +{ + public class InitCommandTests : IClassFixture + { + private UserSecretsTestFixture _fixture; + private ITestOutputHelper _output; + private TestConsole _console; + private StringBuilder _textOutput; + + public InitCommandTests(UserSecretsTestFixture fixture, ITestOutputHelper output) + { + _fixture = fixture; + _output = output; + _textOutput = new StringBuilder(); + + _console = new TestConsole(output) + { + Error = new StringWriter(_textOutput), + Out = new StringWriter(_textOutput), + }; + } + + private CommandContext MakeCommandContext() => new CommandContext(null, new TestReporter(_output), _console); + + [Fact] + public void AddsSecretIdToProject() + { + var projectDir = _fixture.CreateProject(null); + + new InitCommand(null, null).Execute(MakeCommandContext(), projectDir); + + var idResolver = new ProjectIdResolver(MakeCommandContext().Reporter, projectDir); + + Assert.False(string.IsNullOrWhiteSpace(idResolver.Resolve(null, null))); + } + + [Fact] + public void AddsSpecificSecretIdToProject() + { + const string SecretId = "TestSecretId"; + + var projectDir = _fixture.CreateProject(null); + + new InitCommand(SecretId, null).Execute(MakeCommandContext(), projectDir); + + var idResolver = new ProjectIdResolver(MakeCommandContext().Reporter, projectDir); + + Assert.Equal(SecretId, idResolver.Resolve(null, null)); + } + + [Fact] + public void AddsEscapedSpecificSecretIdToProject() + { + const string SecretId = @"&"; + + var projectDir = _fixture.CreateProject(null); + + new InitCommand(SecretId, null).Execute(MakeCommandContext(), projectDir); + + var idResolver = new ProjectIdResolver(MakeCommandContext().Reporter, projectDir); + + Assert.Equal(SecretId, idResolver.Resolve(null, null)); + } + + [Fact] + public void DoesNotGenerateIdForProjectWithSecretId() + { + const string SecretId = "AlreadyExists"; + + var projectDir = _fixture.CreateProject(SecretId); + + new InitCommand(null, null).Execute(MakeCommandContext(), projectDir); + + var idResolver = new ProjectIdResolver(MakeCommandContext().Reporter, projectDir); + + Assert.Equal(SecretId, idResolver.Resolve(null, null)); + } + + [Fact] + public void OverridesIdForProjectWithSecretId() + { + const string SecretId = "AlreadyExists"; + const string NewId = "TestValue"; + + var projectDir = _fixture.CreateProject(SecretId); + + new InitCommand(NewId, null).Execute(MakeCommandContext(), projectDir); + + var idResolver = new ProjectIdResolver(MakeCommandContext().Reporter, projectDir); + + Assert.Equal(NewId, idResolver.Resolve(null, null)); + } + + [Fact] + public void FailsForInvalidId() + { + string secretId = $"invalid{Path.GetInvalidPathChars()[0]}secret-id"; + + var projectDir = _fixture.CreateProject(null); + + Assert.Throws(() => + { + new InitCommand(secretId, null).Execute(MakeCommandContext(), projectDir); + }); + } + } +} diff --git a/src/Tools/dotnet-user-secrets/test/MsBuildProjectFinderTest.cs b/src/Tools/dotnet-user-secrets/test/MsBuildProjectFinderTest.cs new file mode 100644 index 0000000000..6e7a290834 --- /dev/null +++ b/src/Tools/dotnet-user-secrets/test/MsBuildProjectFinderTest.cs @@ -0,0 +1,85 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.IO; +using Microsoft.Extensions.SecretManager.Tools.Internal; +using Xunit; + +namespace Microsoft.Extensions.SecretManager.Tools.Tests +{ + public class MsBuildProjectFinderTest + { + [Theory] + [InlineData(".csproj")] + [InlineData(".vbproj")] + [InlineData(".fsproj")] + public void FindsSingleProject(string extension) + { + using (var files = new TemporaryFileProvider()) + { + var filename = "TestProject" + extension; + files.Add(filename, ""); + + var finder = new MsBuildProjectFinder(files.Root); + + Assert.Equal(Path.Combine(files.Root, filename), finder.FindMsBuildProject(null)); + } + } + + [Fact] + public void ThrowsWhenNoFile() + { + using (var files = new TemporaryFileProvider()) + { + var finder = new MsBuildProjectFinder(files.Root); + + Assert.Throws(() => finder.FindMsBuildProject(null)); + } + } + + [Fact] + public void DoesNotMatchXproj() + { + using (var files = new TemporaryFileProvider()) + { + var finder = new MsBuildProjectFinder(files.Root); + files.Add("test.xproj", ""); + + Assert.Throws(() => finder.FindMsBuildProject(null)); + } + } + + [Fact] + public void ThrowsWhenMultipleFile() + { + using (var files = new TemporaryFileProvider()) + { + files.Add("Test1.csproj", ""); + files.Add("Test2.csproj", ""); + var finder = new MsBuildProjectFinder(files.Root); + + Assert.Throws(() => finder.FindMsBuildProject(null)); + } + } + + [Fact] + public void ThrowsWhenFileDoesNotExist() + { + using (var files = new TemporaryFileProvider()) + { + var finder = new MsBuildProjectFinder(files.Root); + + Assert.Throws(() => finder.FindMsBuildProject("test.csproj")); + } + } + + [Fact] + public void ThrowsWhenRootDoesNotExist() + { + var files = new TemporaryFileProvider(); + var finder = new MsBuildProjectFinder(files.Root); + files.Dispose(); + Assert.Throws(() => finder.FindMsBuildProject(null)); + } + } +} diff --git a/src/Tools/dotnet-user-secrets/test/SecretManagerTests.cs b/src/Tools/dotnet-user-secrets/test/SecretManagerTests.cs new file mode 100644 index 0000000000..3a390d4439 --- /dev/null +++ b/src/Tools/dotnet-user-secrets/test/SecretManagerTests.cs @@ -0,0 +1,340 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using Microsoft.Extensions.Configuration.UserSecrets; +using Microsoft.Extensions.Configuration.UserSecrets.Tests; +using Microsoft.Extensions.Tools.Internal; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.Extensions.SecretManager.Tools.Tests +{ + public class SecretManagerTests : IClassFixture + { + private readonly TestConsole _console; + private readonly UserSecretsTestFixture _fixture; + private readonly StringBuilder _output = new StringBuilder(); + + public SecretManagerTests(UserSecretsTestFixture fixture, ITestOutputHelper output) + { + _fixture = fixture; + + _console = new TestConsole(output) + { + Error = new StringWriter(_output), + Out = new StringWriter(_output), + }; + } + + private Program CreateProgram() + { + return new Program(_console, Directory.GetCurrentDirectory()); + } + + [Theory] + [InlineData(null)] + [InlineData("")] + public void Error_MissingId(string id) + { + var project = Path.Combine(_fixture.CreateProject(id), "TestProject.csproj"); + var secretManager = CreateProgram(); + + secretManager.RunInternal("list", "-p", project); + Assert.Contains(Resources.FormatError_ProjectMissingId(project), _output.ToString()); + } + + [Fact] + public void Error_InvalidProjectFormat() + { + var project = Path.Combine(_fixture.CreateProject("<"), "TestProject.csproj"); + var secretManager = CreateProgram(); + + secretManager.RunInternal("list", "-p", project); + Assert.Contains(Resources.FormatError_ProjectFailedToLoad(project), _output.ToString()); + } + + [Fact] + public void Error_Project_DoesNotExist() + { + var projectPath = Path.Combine(_fixture.GetTempSecretProject(), "does_not_exist", "TestProject.csproj"); + var secretManager = CreateProgram(); + + secretManager.RunInternal("list", "--project", projectPath); + Assert.Contains(Resources.FormatError_ProjectPath_NotFound(projectPath), _output.ToString()); + } + + [Fact] + public void SupportsRelativePaths() + { + var projectPath = _fixture.GetTempSecretProject(); + var cwd = Path.Combine(projectPath, "nested1"); + Directory.CreateDirectory(cwd); + var secretManager = new Program(_console, cwd); + + secretManager.RunInternal("list", "-p", ".." + Path.DirectorySeparatorChar, "--verbose"); + + Assert.Contains(Resources.FormatMessage_Project_File_Path(Path.Combine(cwd, "..", "TestProject.csproj")), _output.ToString()); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void SetSecrets(bool fromCurrentDirectory) + { + var secrets = new KeyValuePair[] + { + new KeyValuePair("key1", Guid.NewGuid().ToString()), + new KeyValuePair("Facebook:AppId", Guid.NewGuid().ToString()), + new KeyValuePair(@"key-@\/.~123!#$%^&*())-+==", @"key-@\/.~123!#$%^&*())-+=="), + new KeyValuePair("key2", string.Empty) + }; + + var projectPath = _fixture.GetTempSecretProject(); + var dir = fromCurrentDirectory + ? projectPath + : Path.GetTempPath(); + var secretManager = new Program(_console, dir); + + foreach (var secret in secrets) + { + var parameters = fromCurrentDirectory ? + new string[] { "set", secret.Key, secret.Value } : + new string[] { "set", secret.Key, secret.Value, "-p", projectPath }; + secretManager.RunInternal(parameters); + } + + foreach (var keyValue in secrets) + { + Assert.Contains( + string.Format("Successfully saved {0} = {1} to the secret store.", keyValue.Key, keyValue.Value), + _output.ToString()); + } + + _output.Clear(); + var args = fromCurrentDirectory + ? new string[] { "list" } + : new string[] { "list", "-p", projectPath }; + secretManager.RunInternal(args); + foreach (var keyValue in secrets) + { + Assert.Contains( + string.Format("{0} = {1}", keyValue.Key, keyValue.Value), + _output.ToString()); + } + + // Remove secrets. + _output.Clear(); + foreach (var secret in secrets) + { + var parameters = fromCurrentDirectory ? + new string[] { "remove", secret.Key } : + new string[] { "remove", secret.Key, "-p", projectPath }; + secretManager.RunInternal(parameters); + } + + // Verify secrets are removed. + _output.Clear(); + args = fromCurrentDirectory + ? new string[] { "list" } + : new string[] { "list", "-p", projectPath }; + secretManager.RunInternal(args); + Assert.Contains(Resources.Error_No_Secrets_Found, _output.ToString()); + } + + [Fact] + public void SetSecret_Update_Existing_Secret() + { + var projectPath = _fixture.GetTempSecretProject(); + var secretManager = CreateProgram(); + + secretManager.RunInternal("set", "secret1", "value1", "-p", projectPath); + Assert.Contains("Successfully saved secret1 = value1 to the secret store.", _output.ToString()); + secretManager.RunInternal("set", "secret1", "value2", "-p", projectPath); + Assert.Contains("Successfully saved secret1 = value2 to the secret store.", _output.ToString()); + + _output.Clear(); + + secretManager.RunInternal("list", "-p", projectPath); + Assert.Contains("secret1 = value2", _output.ToString()); + } + + [Fact] + public void SetSecret_With_Verbose_Flag() + { + string secretId; + var projectPath = _fixture.GetTempSecretProject(out secretId); + var secretManager = CreateProgram(); + + secretManager.RunInternal("-v", "set", "secret1", "value1", "-p", projectPath); + Assert.Contains(string.Format("Project file path {0}.", Path.Combine(projectPath, "TestProject.csproj")), _output.ToString()); + Assert.Contains(string.Format("Secrets file path {0}.", PathHelper.GetSecretsPathFromSecretsId(secretId)), _output.ToString()); + Assert.Contains("Successfully saved secret1 = value1 to the secret store.", _output.ToString()); + _output.Clear(); + + secretManager.RunInternal("-v", "list", "-p", projectPath); + + Assert.Contains(string.Format("Project file path {0}.", Path.Combine(projectPath, "TestProject.csproj")), _output.ToString()); + Assert.Contains(string.Format("Secrets file path {0}.", PathHelper.GetSecretsPathFromSecretsId(secretId)), _output.ToString()); + Assert.Contains("secret1 = value1", _output.ToString()); + } + + [Fact] + public void Remove_Non_Existing_Secret() + { + var projectPath = _fixture.GetTempSecretProject(); + var secretManager = CreateProgram(); + secretManager.RunInternal("remove", "secret1", "-p", projectPath); + Assert.Contains("Cannot find 'secret1' in the secret store.", _output.ToString()); + } + + [Fact] + public void Remove_Is_Case_Insensitive() + { + var projectPath = _fixture.GetTempSecretProject(); + var secretManager = CreateProgram(); + secretManager.RunInternal("set", "SeCreT1", "value", "-p", projectPath); + secretManager.RunInternal("list", "-p", projectPath); + Assert.Contains("SeCreT1 = value", _output.ToString()); + secretManager.RunInternal("remove", "secret1", "-p", projectPath); + + _output.Clear(); + secretManager.RunInternal("list", "-p", projectPath); + + Assert.Contains(Resources.Error_No_Secrets_Found, _output.ToString()); + } + + [Fact] + public void List_Flattens_Nested_Objects() + { + string secretId; + var projectPath = _fixture.GetTempSecretProject(out secretId); + var secretsFile = PathHelper.GetSecretsPathFromSecretsId(secretId); + Directory.CreateDirectory(Path.GetDirectoryName(secretsFile)); + File.WriteAllText(secretsFile, @"{ ""AzureAd"": { ""ClientSecret"": ""abcd郩˙î""} }", Encoding.UTF8); + var secretManager = CreateProgram(); + secretManager.RunInternal("list", "-p", projectPath); + Assert.Contains("AzureAd:ClientSecret = abcd郩˙î", _output.ToString()); + } + + [Fact] + public void List_Json() + { + string id; + var projectPath = _fixture.GetTempSecretProject(out id); + var secretsFile = PathHelper.GetSecretsPathFromSecretsId(id); + Directory.CreateDirectory(Path.GetDirectoryName(secretsFile)); + File.WriteAllText(secretsFile, @"{ ""AzureAd"": { ""ClientSecret"": ""abcd郩˙î""} }", Encoding.UTF8); + var secretManager = new Program(_console, Path.GetDirectoryName(projectPath)); + secretManager.RunInternal("list", "--id", id, "--json"); + var stdout = _output.ToString(); + Assert.Contains("//BEGIN", stdout); + Assert.Contains(@"""AzureAd:ClientSecret"": ""abcd郩˙î""", stdout); + Assert.Contains("//END", stdout); + } + + [Fact] + public void Set_Flattens_Nested_Objects() + { + string secretId; + var projectPath = _fixture.GetTempSecretProject(out secretId); + var secretsFile = PathHelper.GetSecretsPathFromSecretsId(secretId); + Directory.CreateDirectory(Path.GetDirectoryName(secretsFile)); + File.WriteAllText(secretsFile, @"{ ""AzureAd"": { ""ClientSecret"": ""abcd郩˙î""} }", Encoding.UTF8); + var secretManager = CreateProgram(); + secretManager.RunInternal("set", "AzureAd:ClientSecret", "¡™£¢∞", "-p", projectPath); + secretManager.RunInternal("list", "-p", projectPath); + + Assert.Contains("AzureAd:ClientSecret = ¡™£¢∞", _output.ToString()); + var fileContents = File.ReadAllText(secretsFile, Encoding.UTF8); + Assert.Equal(@"{ + ""AzureAd:ClientSecret"": ""¡™£¢∞"" +}", + fileContents, ignoreLineEndingDifferences: true, ignoreWhiteSpaceDifferences: true); + } + + [Fact] + public void List_Empty_Secrets_File() + { + var projectPath = _fixture.GetTempSecretProject(); + var secretManager = CreateProgram(); + secretManager.RunInternal("list", "-p", projectPath); + Assert.Contains(Resources.Error_No_Secrets_Found, _output.ToString()); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Clear_Secrets(bool fromCurrentDirectory) + { + var projectPath = _fixture.GetTempSecretProject(); + + var dir = fromCurrentDirectory + ? projectPath + : Path.GetTempPath(); + + var secretManager = new Program(_console, dir); + + var secrets = new KeyValuePair[] + { + new KeyValuePair("key1", Guid.NewGuid().ToString()), + new KeyValuePair("Facebook:AppId", Guid.NewGuid().ToString()), + new KeyValuePair(@"key-@\/.~123!#$%^&*())-+==", @"key-@\/.~123!#$%^&*())-+=="), + new KeyValuePair("key2", string.Empty) + }; + + foreach (var secret in secrets) + { + var parameters = fromCurrentDirectory ? + new string[] { "set", secret.Key, secret.Value } : + new string[] { "set", secret.Key, secret.Value, "-p", projectPath }; + secretManager.RunInternal(parameters); + } + + foreach (var keyValue in secrets) + { + Assert.Contains( + string.Format("Successfully saved {0} = {1} to the secret store.", keyValue.Key, keyValue.Value), + _output.ToString()); + } + + // Verify secrets are persisted. + _output.Clear(); + var args = fromCurrentDirectory ? + new string[] { "list" } : + new string[] { "list", "-p", projectPath }; + secretManager.RunInternal(args); + foreach (var keyValue in secrets) + { + Assert.Contains( + string.Format("{0} = {1}", keyValue.Key, keyValue.Value), + _output.ToString()); + } + + // Clear secrets. + _output.Clear(); + args = fromCurrentDirectory ? new string[] { "clear" } : new string[] { "clear", "-p", projectPath }; + secretManager.RunInternal(args); + + args = fromCurrentDirectory ? new string[] { "list" } : new string[] { "list", "-p", projectPath }; + secretManager.RunInternal(args); + Assert.Contains(Resources.Error_No_Secrets_Found, _output.ToString()); + } + + [Fact] + public void Init_When_Project_Has_No_Secrets_Id() + { + var projectPath = _fixture.CreateProject(null); + var project = Path.Combine(projectPath, "TestProject.csproj"); + var secretManager = new Program(_console, projectPath); + + secretManager.RunInternal("init", "-p", project); + + Assert.DoesNotContain(Resources.FormatError_ProjectMissingId(project), _output.ToString()); + Assert.DoesNotContain("--help", _output.ToString()); + } + } +} diff --git a/src/Tools/dotnet-user-secrets/test/SetCommandTest.cs b/src/Tools/dotnet-user-secrets/test/SetCommandTest.cs new file mode 100644 index 0000000000..99941fad91 --- /dev/null +++ b/src/Tools/dotnet-user-secrets/test/SetCommandTest.cs @@ -0,0 +1,106 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.IO; +using System.Collections.Generic; +using Microsoft.Extensions.SecretManager.Tools.Internal; +using Microsoft.Extensions.Tools.Internal; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.Extensions.SecretManager.Tools.Tests +{ + + public class SetCommandTest + { + private readonly ITestOutputHelper _output; + + public SetCommandTest(ITestOutputHelper output) + { + _output = output; + } + + [Fact] + public void SetsFromPipedInput() + { + var input = @" +{ + ""Key1"": ""str value"", +""Key2"": 1234, +""Key3"": false +}"; + var testConsole = new TestConsole(_output) + { + IsInputRedirected = true, + In = new StringReader(input) + }; + var secretStore = new TestSecretsStore(_output); + var command = new SetCommand.FromStdInStrategy(); + + command.Execute(new CommandContext(secretStore, new TestReporter(_output), testConsole)); + + Assert.Equal(3, secretStore.Count); + Assert.Equal("str value", secretStore["Key1"]); + Assert.Equal("1234", secretStore["Key2"]); + Assert.Equal("False", secretStore["Key3"]); + } + + [Fact] + public void ParsesNestedObjects() + { + var input = @" + { + ""Key1"": { + ""nested"" : ""value"" + }, + ""array"": [ 1, 2 ] + }"; + + var testConsole = new TestConsole(_output) + { + IsInputRedirected = true, + In = new StringReader(input) + }; + var secretStore = new TestSecretsStore(_output); + var command = new SetCommand.FromStdInStrategy(); + + command.Execute(new CommandContext(secretStore, new TestReporter(_output), testConsole)); + + Assert.Equal(3, secretStore.Count); + Assert.True(secretStore.ContainsKey("Key1:nested")); + Assert.Equal("value", secretStore["Key1:nested"]); + Assert.Equal("1", secretStore["array:0"]); + Assert.Equal("2", secretStore["array:1"]); + } + + [Fact] + public void OnlyPipesInIfNoArgs() + { + var testConsole = new TestConsole(_output) + { + IsInputRedirected = true, + In = new StringReader("") + }; + var options = CommandLineOptions.Parse(new [] { "set", "key", "value" }, testConsole); + Assert.IsType(options.Command); + } + + private class TestSecretsStore : SecretsStore + { + public TestSecretsStore(ITestOutputHelper output) + : base("xyz", new TestReporter(output)) + { + } + + protected override IDictionary Load(string userSecretsId) + { + return new Dictionary(); + } + + public override void Save() + { + // noop + } + } + } +} diff --git a/src/Tools/dotnet-user-secrets/test/TemporaryFileProvider.cs b/src/Tools/dotnet-user-secrets/test/TemporaryFileProvider.cs new file mode 100644 index 0000000000..34c2e8e2ba --- /dev/null +++ b/src/Tools/dotnet-user-secrets/test/TemporaryFileProvider.cs @@ -0,0 +1,29 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.IO; +using System.Text; + +namespace Microsoft.Extensions.SecretManager.Tools.Tests +{ + internal class TemporaryFileProvider : IDisposable + { + public TemporaryFileProvider() + { + Root = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), "tmpfiles", Guid.NewGuid().ToString())).FullName; + } + + public string Root { get; } + + public void Add(string filename, string contents) + { + File.WriteAllText(Path.Combine(Root, filename), contents, Encoding.UTF8); + } + + public void Dispose() + { + Directory.Delete(Root, recursive: true); + } + } +} diff --git a/src/Tools/dotnet-user-secrets/test/UserSecretsTestFixture.cs b/src/Tools/dotnet-user-secrets/test/UserSecretsTestFixture.cs new file mode 100644 index 0000000000..4c76950548 --- /dev/null +++ b/src/Tools/dotnet-user-secrets/test/UserSecretsTestFixture.cs @@ -0,0 +1,97 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.IO; + +namespace Microsoft.Extensions.Configuration.UserSecrets.Tests +{ + public class UserSecretsTestFixture : IDisposable + { + private Stack _disposables = new Stack(); + + public const string TestSecretsId = "b918174fa80346bbb7f4a386729c0eff"; + + public UserSecretsTestFixture() + { + _disposables.Push(() => TryDelete(Path.GetDirectoryName(PathHelper.GetSecretsPathFromSecretsId(TestSecretsId)))); + } + + public void Dispose() + { + while (_disposables.Count > 0) + { + _disposables.Pop()?.Invoke(); + } + } + + public string GetTempSecretProject() + { + string userSecretsId; + return GetTempSecretProject(out userSecretsId); + } + + private const string ProjectTemplate = @" + + Exe + netcoreapp3.0 + {0} + false + + + + + +"; + + public string GetTempSecretProject(out string userSecretsId) + { + userSecretsId = Guid.NewGuid().ToString(); + return CreateProject(userSecretsId); + } + + public string CreateProject(string userSecretsId) + { + var projectPath = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), "usersecretstest", Guid.NewGuid().ToString())); + var prop = string.IsNullOrEmpty(userSecretsId) + ? string.Empty + : $"{userSecretsId}"; + + File.WriteAllText( + Path.Combine(projectPath.FullName, "TestProject.csproj"), + string.Format(ProjectTemplate, prop)); + + var id = userSecretsId; + _disposables.Push(() => + { + try + { + // may throw if id is bad + var secretsDir = Path.GetDirectoryName(PathHelper.GetSecretsPathFromSecretsId(id)); + TryDelete(secretsDir); + } + catch { } + }); + _disposables.Push(() => TryDelete(projectPath.FullName)); + + return projectPath.FullName; + } + + private static void TryDelete(string directory) + { + try + { + if (Directory.Exists(directory)) + { + Directory.Delete(directory, true); + } + } + catch (Exception) + { + // Ignore failures. + Console.WriteLine("Failed to delete " + directory); + } + } + } +} diff --git a/src/Tools/dotnet-user-secrets/test/dotnet-user-secrets.Tests.csproj b/src/Tools/dotnet-user-secrets/test/dotnet-user-secrets.Tests.csproj new file mode 100644 index 0000000000..1f8f1e4deb --- /dev/null +++ b/src/Tools/dotnet-user-secrets/test/dotnet-user-secrets.Tests.csproj @@ -0,0 +1,21 @@ + + + + netcoreapp3.0 + Microsoft.Extensions.SecretManager.Tools.Tests + + + + + + + + + + + + + + + + diff --git a/src/Tools/dotnet-watch/README.md b/src/Tools/dotnet-watch/README.md new file mode 100644 index 0000000000..ff7102a92e --- /dev/null +++ b/src/Tools/dotnet-watch/README.md @@ -0,0 +1,88 @@ +dotnet-watch +============ +`dotnet-watch` is a file watcher for `dotnet` that restarts the specified application when changes in the source code are detected. + +### How To Use + +The command must be executed in the directory that contains the project to be watched. + + Usage: dotnet watch [options] [[--] ...] + + Options: + -?|-h|--help Show help information + -q|--quiet Suppresses all output except warnings and errors + -v|--verbose Show verbose output + +Add `watch` after `dotnet` and before the command arguments that you want to run: + +| What you want to run | Dotnet watch command | +| ---------------------------------------------- | -------------------------------------------------------- | +| dotnet run | dotnet **watch** run | +| dotnet run --arg1 value1 | dotnet **watch** run --arg1 value | +| dotnet run --framework net451 -- --arg1 value1 | dotnet **watch** run --framework net451 -- --arg1 value1 | +| dotnet test | dotnet **watch** test | + +### Environment variables + +Some configuration options can be passed to `dotnet watch` through environment variables. The available variables are: + +| Variable | Effect | +| ---------------------------------------------- | -------------------------------------------------------- | +| DOTNET_USE_POLLING_FILE_WATCHER | If set to "1" or "true", `dotnet watch` will use a polling file watcher instead of CoreFx's `FileSystemWatcher`. Used when watching files on network shares or Docker mounted volumes. | + +### MSBuild + +dotnet-watch can be configured from the MSBuild project file being watched. + +**Watch items** + +dotnet-watch will watch all items in the **Watch** item group. +By default, this group inclues all items in **Compile** and **EmbeddedResource**. + +More items can be added to watch in a project file by adding items to 'Watch'. + +```xml + + + + +``` + +dotnet-watch will ignore Compile and EmbeddedResource items with the `Watch="false"` attribute. + +Example: + +```xml + + + + + + +``` + +**Project References** + +By default, dotnet-watch will scan the entire graph of project references and watch all files within those projects. + +dotnet-watch will ignore project references with the `Watch="false"` attribute. + +```xml + + + +``` + + +**Advanced configuration** + +dotnet-watch performs a design-time build to find items to watch. +When this build is run, dotnet-watch will set the property `DotNetWatchBuild=true`. + +Example: + +```xml + + + +``` diff --git a/src/Tools/dotnet-watch/src/CommandLineOptions.cs b/src/Tools/dotnet-watch/src/CommandLineOptions.cs new file mode 100644 index 0000000000..5cbaab33e9 --- /dev/null +++ b/src/Tools/dotnet-watch/src/CommandLineOptions.cs @@ -0,0 +1,121 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Reflection; +using Microsoft.DotNet.Watcher.Tools; +using Microsoft.Extensions.CommandLineUtils; +using Microsoft.Extensions.Tools.Internal; + +namespace Microsoft.DotNet.Watcher +{ + internal class CommandLineOptions + { + public string Project { get; private set; } + public bool IsHelp { get; private set; } + public bool IsQuiet { get; private set; } + public bool IsVerbose { get; private set; } + public IList RemainingArguments { get; private set; } + public bool ListFiles { get; private set; } + + public static bool IsPollingEnabled + { + get + { + var envVar = Environment.GetEnvironmentVariable("DOTNET_USE_POLLING_FILE_WATCHER"); + return envVar != null && + (envVar.Equals("1", StringComparison.OrdinalIgnoreCase) || + envVar.Equals("true", StringComparison.OrdinalIgnoreCase)); + } + } + + public static CommandLineOptions Parse(string[] args, IConsole console) + { + Ensure.NotNull(args, nameof(args)); + Ensure.NotNull(console, nameof(console)); + + var app = new CommandLineApplication(throwOnUnexpectedArg: false) + { + Name = "dotnet watch", + FullName = "Microsoft DotNet File Watcher", + Out = console.Out, + Error = console.Error, + AllowArgumentSeparator = true, + ExtendedHelpText = @" +Environment variables: + + DOTNET_USE_POLLING_FILE_WATCHER + When set to '1' or 'true', dotnet-watch will poll the file system for + changes. This is required for some file systems, such as network shares, + Docker mounted volumes, and other virtual file systems. + + DOTNET_WATCH + dotnet-watch sets this variable to '1' on all child processes launched. + + DOTNET_WATCH_ITERATION + dotnet-watch sets this variable to '1' and increments by one each time + a file is changed and the command is restarted. + +Remarks: + The special option '--' is used to delimit the end of the options and + the beginning of arguments that will be passed to the child dotnet process. + Its use is optional. When the special option '--' is not used, + dotnet-watch will use the first unrecognized argument as the beginning + of all arguments passed into the child dotnet process. + + For example: dotnet watch -- --verbose run + + Even though '--verbose' is an option dotnet-watch supports, the use of '--' + indicates that '--verbose' should be treated instead as an argument for + dotnet-run. + +Examples: + dotnet watch run + dotnet watch test +" + }; + + app.HelpOption("-?|-h|--help"); + // TODO multiple shouldn't be too hard to support + var optProjects = app.Option("-p|--project ", "The project to watch", + CommandOptionType.SingleValue); + + var optQuiet = app.Option("-q|--quiet", "Suppresses all output except warnings and errors", + CommandOptionType.NoValue); + var optVerbose = app.VerboseOption(); + + var optList = app.Option("--list", "Lists all discovered files without starting the watcher", + CommandOptionType.NoValue); + + app.VersionOptionFromAssemblyAttributes(typeof(Program).GetTypeInfo().Assembly); + + if (app.Execute(args) != 0) + { + return null; + } + + if (optQuiet.HasValue() && optVerbose.HasValue()) + { + throw new CommandParsingException(app, Resources.Error_QuietAndVerboseSpecified); + } + + if (app.RemainingArguments.Count == 0 + && !app.IsShowingInformation + && !optList.HasValue()) + { + app.ShowHelp(); + } + + return new CommandLineOptions + { + Project = optProjects.Value(), + IsQuiet = optQuiet.HasValue(), + IsVerbose = optVerbose.HasValue(), + RemainingArguments = app.RemainingArguments, + IsHelp = app.IsShowingInformation, + ListFiles = optList.HasValue(), + }; + } + } +} diff --git a/src/Tools/dotnet-watch/src/DotNetWatcher.cs b/src/Tools/dotnet-watch/src/DotNetWatcher.cs new file mode 100644 index 0000000000..8431615c1e --- /dev/null +++ b/src/Tools/dotnet-watch/src/DotNetWatcher.cs @@ -0,0 +1,110 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Globalization; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.DotNet.Watcher.Internal; +using Microsoft.Extensions.CommandLineUtils; +using Microsoft.Extensions.Tools.Internal; + +namespace Microsoft.DotNet.Watcher +{ + public class DotNetWatcher + { + private readonly IReporter _reporter; + private readonly ProcessRunner _processRunner; + + public DotNetWatcher(IReporter reporter) + { + Ensure.NotNull(reporter, nameof(reporter)); + + _reporter = reporter; + _processRunner = new ProcessRunner(reporter); + } + + public async Task WatchAsync(ProcessSpec processSpec, IFileSetFactory fileSetFactory, + CancellationToken cancellationToken) + { + Ensure.NotNull(processSpec, nameof(processSpec)); + + var cancelledTaskSource = new TaskCompletionSource(); + cancellationToken.Register(state => ((TaskCompletionSource) state).TrySetResult(null), + cancelledTaskSource); + + var iteration = 1; + + while (true) + { + processSpec.EnvironmentVariables["DOTNET_WATCH_ITERATION"] = iteration.ToString(CultureInfo.InvariantCulture); + iteration++; + + var fileSet = await fileSetFactory.CreateAsync(cancellationToken); + + if (fileSet == null) + { + _reporter.Error("Failed to find a list of files to watch"); + return; + } + + if (cancellationToken.IsCancellationRequested) + { + return; + } + + using (var currentRunCancellationSource = new CancellationTokenSource()) + using (var combinedCancellationSource = CancellationTokenSource.CreateLinkedTokenSource( + cancellationToken, + currentRunCancellationSource.Token)) + using (var fileSetWatcher = new FileSetWatcher(fileSet, _reporter)) + { + var fileSetTask = fileSetWatcher.GetChangedFileAsync(combinedCancellationSource.Token); + var processTask = _processRunner.RunAsync(processSpec, combinedCancellationSource.Token); + + var args = ArgumentEscaper.EscapeAndConcatenate(processSpec.Arguments); + _reporter.Verbose($"Running {processSpec.ShortDisplayName()} with the following arguments: {args}"); + + _reporter.Output("Started"); + + var finishedTask = await Task.WhenAny(processTask, fileSetTask, cancelledTaskSource.Task); + + // Regardless of the which task finished first, make sure everything is cancelled + // and wait for dotnet to exit. We don't want orphan processes + currentRunCancellationSource.Cancel(); + + await Task.WhenAll(processTask, fileSetTask); + + if (processTask.Result != 0 && finishedTask == processTask && !cancellationToken.IsCancellationRequested) + { + // Only show this error message if the process exited non-zero due to a normal process exit. + // Don't show this if dotnet-watch killed the inner process due to file change or CTRL+C by the user + _reporter.Error($"Exited with error code {processTask.Result}"); + } + else + { + _reporter.Output("Exited"); + } + + if (finishedTask == cancelledTaskSource.Task || cancellationToken.IsCancellationRequested) + { + return; + } + + if (finishedTask == processTask) + { + _reporter.Warn("Waiting for a file to change before restarting dotnet..."); + + // Now wait for a file to change before restarting process + await fileSetWatcher.GetChangedFileAsync(cancellationToken); + } + + if (!string.IsNullOrEmpty(fileSetTask.Result)) + { + _reporter.Output($"File changed: {fileSetTask.Result}"); + } + } + } + } + } +} diff --git a/src/Tools/dotnet-watch/src/IFileSet.cs b/src/Tools/dotnet-watch/src/IFileSet.cs new file mode 100644 index 0000000000..7554d3f542 --- /dev/null +++ b/src/Tools/dotnet-watch/src/IFileSet.cs @@ -0,0 +1,12 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Collections.Generic; + +namespace Microsoft.DotNet.Watcher +{ + public interface IFileSet : IEnumerable + { + bool Contains(string filePath); + } +} diff --git a/src/Tools/dotnet-watch/src/IFileSetFactory.cs b/src/Tools/dotnet-watch/src/IFileSetFactory.cs new file mode 100644 index 0000000000..6a70c06a4c --- /dev/null +++ b/src/Tools/dotnet-watch/src/IFileSetFactory.cs @@ -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. + +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.DotNet.Watcher +{ + public interface IFileSetFactory + { + Task CreateAsync(CancellationToken cancellationToken); + } +} \ No newline at end of file diff --git a/src/Tools/dotnet-watch/src/Internal/FileSet.cs b/src/Tools/dotnet-watch/src/Internal/FileSet.cs new file mode 100644 index 0000000000..736ce43677 --- /dev/null +++ b/src/Tools/dotnet-watch/src/Internal/FileSet.cs @@ -0,0 +1,26 @@ +// 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; + +namespace Microsoft.DotNet.Watcher.Internal +{ + public class FileSet : IFileSet + { + private readonly HashSet _files; + + public FileSet(IEnumerable files) + { + _files = new HashSet(files, StringComparer.OrdinalIgnoreCase); + } + + public bool Contains(string filePath) => _files.Contains(filePath); + + public int Count => _files.Count; + + public IEnumerator GetEnumerator() => _files.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => _files.GetEnumerator(); + } +} diff --git a/src/Tools/dotnet-watch/src/Internal/FileSetWatcher.cs b/src/Tools/dotnet-watch/src/Internal/FileSetWatcher.cs new file mode 100644 index 0000000000..3dc56cc452 --- /dev/null +++ b/src/Tools/dotnet-watch/src/Internal/FileSetWatcher.cs @@ -0,0 +1,55 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Tools.Internal; + +namespace Microsoft.DotNet.Watcher.Internal +{ + public class FileSetWatcher : IDisposable + { + private readonly FileWatcher _fileWatcher; + private readonly IFileSet _fileSet; + + public FileSetWatcher(IFileSet fileSet, IReporter reporter) + { + Ensure.NotNull(fileSet, nameof(fileSet)); + + _fileSet = fileSet; + _fileWatcher = new FileWatcher(reporter); + } + + public async Task GetChangedFileAsync(CancellationToken cancellationToken) + { + foreach (var file in _fileSet) + { + _fileWatcher.WatchDirectory(Path.GetDirectoryName(file)); + } + + var tcs = new TaskCompletionSource(); + cancellationToken.Register(() => tcs.TrySetResult(null)); + + Action callback = path => + { + if (_fileSet.Contains(path)) + { + tcs.TrySetResult(path); + } + }; + + _fileWatcher.OnFileChange += callback; + var changedFile = await tcs.Task; + _fileWatcher.OnFileChange -= callback; + + return changedFile; + } + + public void Dispose() + { + _fileWatcher.Dispose(); + } + } +} diff --git a/src/Tools/dotnet-watch/src/Internal/FileWatcher.cs b/src/Tools/dotnet-watch/src/Internal/FileWatcher.cs new file mode 100644 index 0000000000..65c2ff9285 --- /dev/null +++ b/src/Tools/dotnet-watch/src/Internal/FileWatcher.cs @@ -0,0 +1,143 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Microsoft.Extensions.Tools.Internal; + +namespace Microsoft.DotNet.Watcher.Internal +{ + public class FileWatcher + { + private bool _disposed; + + private readonly IDictionary _watchers; + private readonly IReporter _reporter; + + public FileWatcher() + : this(NullReporter.Singleton) + { } + + public FileWatcher(IReporter reporter) + { + _reporter = reporter ?? throw new ArgumentNullException(nameof(reporter)); + _watchers = new Dictionary(); + } + + public event Action OnFileChange; + + public void WatchDirectory(string directory) + { + EnsureNotDisposed(); + AddDirectoryWatcher(directory); + } + + public void Dispose() + { + if (_disposed) + { + return; + } + + _disposed = true; + + foreach (var watcher in _watchers) + { + watcher.Value.OnFileChange -= WatcherChangedHandler; + watcher.Value.OnError -= WatcherErrorHandler; + watcher.Value.Dispose(); + } + + _watchers.Clear(); + } + + private void AddDirectoryWatcher(string directory) + { + directory = EnsureTrailingSlash(directory); + + var alreadyWatched = _watchers + .Where(d => directory.StartsWith(d.Key)) + .Any(); + + if (alreadyWatched) + { + return; + } + + var redundantWatchers = _watchers + .Where(d => d.Key.StartsWith(directory)) + .Select(d => d.Key) + .ToList(); + + if (redundantWatchers.Any()) + { + foreach (var watcher in redundantWatchers) + { + DisposeWatcher(watcher); + } + } + + var newWatcher = FileWatcherFactory.CreateWatcher(directory); + newWatcher.OnFileChange += WatcherChangedHandler; + newWatcher.OnError += WatcherErrorHandler; + newWatcher.EnableRaisingEvents = true; + + _watchers.Add(directory, newWatcher); + } + + private void WatcherErrorHandler(object sender, Exception error) + { + if (sender is IFileSystemWatcher watcher) + { + _reporter.Warn($"The file watcher observing '{watcher.BasePath}' encountered an error: {error.Message}"); + } + } + + private void WatcherChangedHandler(object sender, string changedPath) + { + NotifyChange(changedPath); + } + + private void NotifyChange(string path) + { + if (OnFileChange != null) + { + OnFileChange(path); + } + } + + private void DisposeWatcher(string directory) + { + var watcher = _watchers[directory]; + _watchers.Remove(directory); + + watcher.EnableRaisingEvents = false; + + watcher.OnFileChange -= WatcherChangedHandler; + watcher.OnError -= WatcherErrorHandler; + + watcher.Dispose(); + } + + private void EnsureNotDisposed() + { + if (_disposed) + { + throw new ObjectDisposedException(nameof(FileWatcher)); + } + } + + private static string EnsureTrailingSlash(string path) + { + if (!string.IsNullOrEmpty(path) && + path[path.Length - 1] != Path.DirectorySeparatorChar) + { + return path + Path.DirectorySeparatorChar; + } + + return path; + } + } +} \ No newline at end of file diff --git a/src/Tools/dotnet-watch/src/Internal/FileWatcher/DotnetFileWatcher.cs b/src/Tools/dotnet-watch/src/Internal/FileWatcher/DotnetFileWatcher.cs new file mode 100644 index 0000000000..0372327819 --- /dev/null +++ b/src/Tools/dotnet-watch/src/Internal/FileWatcher/DotnetFileWatcher.cs @@ -0,0 +1,159 @@ +// 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; +using System.IO; +using Microsoft.Extensions.Tools.Internal; + +namespace Microsoft.DotNet.Watcher.Internal +{ + internal class DotnetFileWatcher : IFileSystemWatcher + { + private volatile bool _disposed; + + private readonly Func _watcherFactory; + + private FileSystemWatcher _fileSystemWatcher; + + private readonly object _createLock = new object(); + + public DotnetFileWatcher(string watchedDirectory) + : this(watchedDirectory, DefaultWatcherFactory) + { + } + + internal DotnetFileWatcher(string watchedDirectory, Func fileSystemWatcherFactory) + { + Ensure.NotNull(fileSystemWatcherFactory, nameof(fileSystemWatcherFactory)); + Ensure.NotNullOrEmpty(watchedDirectory, nameof(watchedDirectory)); + + BasePath = watchedDirectory; + _watcherFactory = fileSystemWatcherFactory; + CreateFileSystemWatcher(); + } + + public event EventHandler OnFileChange; + + public event EventHandler OnError; + + public string BasePath { get; } + + private static FileSystemWatcher DefaultWatcherFactory(string watchedDirectory) + { + Ensure.NotNullOrEmpty(watchedDirectory, nameof(watchedDirectory)); + + return new FileSystemWatcher(watchedDirectory); + } + + private void WatcherErrorHandler(object sender, ErrorEventArgs e) + { + if (_disposed) + { + return; + } + + var exception = e.GetException(); + + // Win32Exception may be triggered when setting EnableRaisingEvents on a file system type + // that is not supported, such as a network share. Don't attempt to recreate the watcher + // in this case as it will cause a StackOverflowException + if (!(exception is Win32Exception)) + { + // Recreate the watcher if it is a recoverable error. + CreateFileSystemWatcher(); + } + + OnError?.Invoke(this, exception); + } + + private void WatcherRenameHandler(object sender, RenamedEventArgs e) + { + if (_disposed) + { + return; + } + + NotifyChange(e.OldFullPath); + NotifyChange(e.FullPath); + + if (Directory.Exists(e.FullPath)) + { + foreach (var newLocation in Directory.EnumerateFileSystemEntries(e.FullPath, "*", SearchOption.AllDirectories)) + { + // Calculated previous path of this moved item. + var oldLocation = Path.Combine(e.OldFullPath, newLocation.Substring(e.FullPath.Length + 1)); + NotifyChange(oldLocation); + NotifyChange(newLocation); + } + } + } + + private void WatcherChangeHandler(object sender, FileSystemEventArgs e) + { + if (_disposed) + { + return; + } + + NotifyChange(e.FullPath); + } + + private void NotifyChange(string fullPath) + { + // Only report file changes + OnFileChange?.Invoke(this, fullPath); + } + + private void CreateFileSystemWatcher() + { + lock (_createLock) + { + bool enableEvents = false; + + if (_fileSystemWatcher != null) + { + enableEvents = _fileSystemWatcher.EnableRaisingEvents; + + DisposeInnerWatcher(); + } + + _fileSystemWatcher = _watcherFactory(BasePath); + _fileSystemWatcher.IncludeSubdirectories = true; + + _fileSystemWatcher.Created += WatcherChangeHandler; + _fileSystemWatcher.Deleted += WatcherChangeHandler; + _fileSystemWatcher.Changed += WatcherChangeHandler; + _fileSystemWatcher.Renamed += WatcherRenameHandler; + _fileSystemWatcher.Error += WatcherErrorHandler; + + _fileSystemWatcher.EnableRaisingEvents = enableEvents; + } + } + + private void DisposeInnerWatcher() + { + _fileSystemWatcher.EnableRaisingEvents = false; + + _fileSystemWatcher.Created -= WatcherChangeHandler; + _fileSystemWatcher.Deleted -= WatcherChangeHandler; + _fileSystemWatcher.Changed -= WatcherChangeHandler; + _fileSystemWatcher.Renamed -= WatcherRenameHandler; + _fileSystemWatcher.Error -= WatcherErrorHandler; + + _fileSystemWatcher.Dispose(); + } + + public bool EnableRaisingEvents + { + get => _fileSystemWatcher.EnableRaisingEvents; + set => _fileSystemWatcher.EnableRaisingEvents = value; + } + + public void Dispose() + { + _disposed = true; + DisposeInnerWatcher(); + } + } +} diff --git a/src/Tools/dotnet-watch/src/Internal/FileWatcher/FileWatcherFactory.cs b/src/Tools/dotnet-watch/src/Internal/FileWatcher/FileWatcherFactory.cs new file mode 100644 index 0000000000..9c91176ec1 --- /dev/null +++ b/src/Tools/dotnet-watch/src/Internal/FileWatcher/FileWatcherFactory.cs @@ -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.DotNet.Watcher.Internal +{ + public static class FileWatcherFactory + { + public static IFileSystemWatcher CreateWatcher(string watchedDirectory) + => CreateWatcher(watchedDirectory, CommandLineOptions.IsPollingEnabled); + + public static IFileSystemWatcher CreateWatcher(string watchedDirectory, bool usePollingWatcher) + { + return usePollingWatcher ? + new PollingFileWatcher(watchedDirectory) : + new DotnetFileWatcher(watchedDirectory) as IFileSystemWatcher; + } + } +} diff --git a/src/Tools/dotnet-watch/src/Internal/FileWatcher/IFileSystemWatcher.cs b/src/Tools/dotnet-watch/src/Internal/FileWatcher/IFileSystemWatcher.cs new file mode 100644 index 0000000000..aaf5773449 --- /dev/null +++ b/src/Tools/dotnet-watch/src/Internal/FileWatcher/IFileSystemWatcher.cs @@ -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. + +using System; + +namespace Microsoft.DotNet.Watcher.Internal +{ + public interface IFileSystemWatcher : IDisposable + { + event EventHandler OnFileChange; + + event EventHandler OnError; + + string BasePath { get; } + + bool EnableRaisingEvents { get; set; } + } +} diff --git a/src/Tools/dotnet-watch/src/Internal/FileWatcher/PollingFileWatcher.cs b/src/Tools/dotnet-watch/src/Internal/FileWatcher/PollingFileWatcher.cs new file mode 100644 index 0000000000..1b503af774 --- /dev/null +++ b/src/Tools/dotnet-watch/src/Internal/FileWatcher/PollingFileWatcher.cs @@ -0,0 +1,247 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Threading; +using Microsoft.Extensions.Tools.Internal; + +namespace Microsoft.DotNet.Watcher.Internal +{ + internal class PollingFileWatcher : IFileSystemWatcher + { + // The minimum interval to rerun the scan + private static readonly TimeSpan _minRunInternal = TimeSpan.FromSeconds(.5); + + private readonly DirectoryInfo _watchedDirectory; + + private Dictionary _knownEntities = new Dictionary(); + private Dictionary _tempDictionary = new Dictionary(); + private HashSet _changes = new HashSet(); + + private Thread _pollingThread; + private bool _raiseEvents; + + private bool _disposed; + + public PollingFileWatcher(string watchedDirectory) + { + Ensure.NotNullOrEmpty(watchedDirectory, nameof(watchedDirectory)); + + _watchedDirectory = new DirectoryInfo(watchedDirectory); + BasePath = _watchedDirectory.FullName; + + _pollingThread = new Thread(new ThreadStart(PollingLoop)); + _pollingThread.IsBackground = true; + _pollingThread.Name = nameof(PollingFileWatcher); + + CreateKnownFilesSnapshot(); + + _pollingThread.Start(); + } + + public event EventHandler OnFileChange; + +#pragma warning disable CS0067 // not used + public event EventHandler OnError; +#pragma warning restore + + public string BasePath { get; } + + public bool EnableRaisingEvents + { + get => _raiseEvents; + set + { + EnsureNotDisposed(); + _raiseEvents = value; + } + } + + private void PollingLoop() + { + var stopwatch = Stopwatch.StartNew(); + stopwatch.Start(); + + while (!_disposed) + { + if (stopwatch.Elapsed < _minRunInternal) + { + // Don't run too often + // The min wait time here can be double + // the value of the variable (FYI) + Thread.Sleep(_minRunInternal); + } + + stopwatch.Reset(); + + if (!_raiseEvents) + { + continue; + } + + CheckForChangedFiles(); + } + + stopwatch.Stop(); + } + + private void CreateKnownFilesSnapshot() + { + _knownEntities.Clear(); + + ForeachEntityInDirectory(_watchedDirectory, f => + { + _knownEntities.Add(f.FullName, new FileMeta(f)); + }); + } + + private void CheckForChangedFiles() + { + _changes.Clear(); + + ForeachEntityInDirectory(_watchedDirectory, f => + { + var fullFilePath = f.FullName; + + if (!_knownEntities.ContainsKey(fullFilePath)) + { + // New file + RecordChange(f); + } + else + { + var fileMeta = _knownEntities[fullFilePath]; + + try + { + if (fileMeta.FileInfo.LastWriteTime != f.LastWriteTime) + { + // File changed + RecordChange(f); + } + + _knownEntities[fullFilePath] = new FileMeta(fileMeta.FileInfo, true); + } + catch (FileNotFoundException) + { + _knownEntities[fullFilePath] = new FileMeta(fileMeta.FileInfo, false); + } + } + + _tempDictionary.Add(f.FullName, new FileMeta(f)); + }); + + foreach (var file in _knownEntities) + { + if (!file.Value.FoundAgain) + { + // File deleted + RecordChange(file.Value.FileInfo); + } + } + + NotifyChanges(); + + // Swap the two dictionaries + var swap = _knownEntities; + _knownEntities = _tempDictionary; + _tempDictionary = swap; + + _tempDictionary.Clear(); + } + + private void RecordChange(FileSystemInfo fileInfo) + { + if (fileInfo == null || + _changes.Contains(fileInfo.FullName) || + fileInfo.FullName.Equals(_watchedDirectory.FullName, StringComparison.Ordinal)) + { + return; + } + + _changes.Add(fileInfo.FullName); + if (fileInfo.FullName != _watchedDirectory.FullName) + { + var file = fileInfo as FileInfo; + if (file != null) + { + RecordChange(file.Directory); + } + else + { + var dir = fileInfo as DirectoryInfo; + if (dir != null) + { + RecordChange(dir.Parent); + } + } + } + } + + private void ForeachEntityInDirectory(DirectoryInfo dirInfo, Action fileAction) + { + if (!dirInfo.Exists) + { + return; + } + + var entities = dirInfo.EnumerateFileSystemInfos("*.*"); + foreach (var entity in entities) + { + fileAction(entity); + + var subdirInfo = entity as DirectoryInfo; + if (subdirInfo != null) + { + ForeachEntityInDirectory(subdirInfo, fileAction); + } + } + } + + private void NotifyChanges() + { + foreach (var path in _changes) + { + if (_disposed || !_raiseEvents) + { + break; + } + + if (OnFileChange != null) + { + OnFileChange(this, path); + } + } + } + + private void EnsureNotDisposed() + { + if (_disposed) + { + throw new ObjectDisposedException(nameof(PollingFileWatcher)); + } + } + + public void Dispose() + { + EnableRaisingEvents = false; + _disposed = true; + } + + private struct FileMeta + { + public FileMeta(FileSystemInfo fileInfo, bool foundAgain = false) + { + FileInfo = fileInfo; + FoundAgain = foundAgain; + } + + public FileSystemInfo FileInfo; + + public bool FoundAgain; + } + } +} diff --git a/src/Tools/dotnet-watch/src/Internal/MsBuildFileSetFactory.cs b/src/Tools/dotnet-watch/src/Internal/MsBuildFileSetFactory.cs new file mode 100644 index 0000000000..3cdf453067 --- /dev/null +++ b/src/Tools/dotnet-watch/src/Internal/MsBuildFileSetFactory.cs @@ -0,0 +1,188 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.CommandLineUtils; +using Microsoft.Extensions.Tools.Internal; + +namespace Microsoft.DotNet.Watcher.Internal +{ + public class MsBuildFileSetFactory : IFileSetFactory + { + private const string TargetName = "GenerateWatchList"; + private const string WatchTargetsFileName = "DotNetWatch.targets"; + private readonly IReporter _reporter; + private readonly string _projectFile; + private readonly OutputSink _outputSink; + private readonly ProcessRunner _processRunner; + private readonly bool _waitOnError; + private readonly IReadOnlyList _buildFlags; + + public MsBuildFileSetFactory(IReporter reporter, + string projectFile, + bool waitOnError, + bool trace) + : this(reporter, projectFile, new OutputSink(), trace) + { + _waitOnError = waitOnError; + } + + // output sink is for testing + internal MsBuildFileSetFactory(IReporter reporter, + string projectFile, + OutputSink outputSink, + bool trace) + { + Ensure.NotNull(reporter, nameof(reporter)); + Ensure.NotNullOrEmpty(projectFile, nameof(projectFile)); + Ensure.NotNull(outputSink, nameof(outputSink)); + + _reporter = reporter; + _projectFile = projectFile; + _outputSink = outputSink; + _processRunner = new ProcessRunner(reporter); + _buildFlags = InitializeArgs(FindTargetsFile(), trace); + } + + public async Task CreateAsync(CancellationToken cancellationToken) + { + var watchList = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + try + { + var projectDir = Path.GetDirectoryName(_projectFile); + + while (true) + { + cancellationToken.ThrowIfCancellationRequested(); + + var capture = _outputSink.StartCapture(); + // TODO adding files doesn't currently work. Need to provide a way to detect new files + // find files + var processSpec = new ProcessSpec + { + Executable = DotNetMuxer.MuxerPathOrDefault(), + WorkingDirectory = projectDir, + Arguments = new[] + { + "msbuild", + _projectFile, + $"/p:_DotNetWatchListFile={watchList}" + }.Concat(_buildFlags), + OutputCapture = capture + }; + + _reporter.Verbose($"Running MSBuild target '{TargetName}' on '{_projectFile}'"); + + var exitCode = await _processRunner.RunAsync(processSpec, cancellationToken); + + if (exitCode == 0 && File.Exists(watchList)) + { + var fileset = new FileSet( + File.ReadAllLines(watchList) + .Select(l => l?.Trim()) + .Where(l => !string.IsNullOrEmpty(l))); + + _reporter.Verbose($"Watching {fileset.Count} file(s) for changes"); +#if DEBUG + + foreach (var file in fileset) + { + _reporter.Verbose($" -> {file}"); + } + + Debug.Assert(fileset.All(Path.IsPathRooted), "All files should be rooted paths"); +#endif + + return fileset; + } + + _reporter.Error($"Error(s) finding watch items project file '{Path.GetFileName(_projectFile)}'"); + + _reporter.Output($"MSBuild output from target '{TargetName}':"); + _reporter.Output(string.Empty); + + foreach (var line in capture.Lines) + { + _reporter.Output($" {line}"); + } + + _reporter.Output(string.Empty); + + if (!_waitOnError) + { + return null; + } + else + { + _reporter.Warn("Fix the error to continue or press Ctrl+C to exit."); + + var fileSet = new FileSet(new[] { _projectFile }); + + using (var watcher = new FileSetWatcher(fileSet, _reporter)) + { + await watcher.GetChangedFileAsync(cancellationToken); + + _reporter.Output($"File changed: {_projectFile}"); + } + } + } + } + finally + { + if (File.Exists(watchList)) + { + File.Delete(watchList); + } + } + } + + private IReadOnlyList InitializeArgs(string watchTargetsFile, bool trace) + { + var args = new List + { + "/nologo", + "/v:n", + "/t:" + TargetName, + "/p:DotNetWatchBuild=true", // extensibility point for users + "/p:DesignTimeBuild=true", // don't do expensive things + "/p:CustomAfterMicrosoftCommonTargets=" + watchTargetsFile, + "/p:CustomAfterMicrosoftCommonCrossTargetingTargets=" + watchTargetsFile, + }; + + if (trace) + { + // enables capturing markers to know which projects have been visited + args.Add("/p:_DotNetWatchTraceOutput=true"); + } + + return args; + } + + private string FindTargetsFile() + { + var assemblyDir = Path.GetDirectoryName(typeof(MsBuildFileSetFactory).Assembly.Location); + var searchPaths = new[] + { + Path.Combine(AppContext.BaseDirectory, "assets"), + Path.Combine(assemblyDir, "assets"), + AppContext.BaseDirectory, + assemblyDir, + }; + + var targetPath = searchPaths.Select(p => Path.Combine(p, WatchTargetsFileName)).FirstOrDefault(File.Exists); + if (targetPath == null) + { + _reporter.Error("Fatal error: could not find DotNetWatch.targets"); + return null; + } + return targetPath; + } + } +} diff --git a/src/Tools/dotnet-watch/src/Internal/MsBuildProjectFinder.cs b/src/Tools/dotnet-watch/src/Internal/MsBuildProjectFinder.cs new file mode 100644 index 0000000000..b6cc515aec --- /dev/null +++ b/src/Tools/dotnet-watch/src/Internal/MsBuildProjectFinder.cs @@ -0,0 +1,57 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.IO; +using System.Linq; +using Microsoft.DotNet.Watcher.Tools; +using Microsoft.Extensions.Tools.Internal; + +namespace Microsoft.DotNet.Watcher.Internal +{ + internal class MsBuildProjectFinder + { + /// + /// Finds a compatible MSBuild project. + /// The base directory to search + /// The filename of the project. Can be null. + /// + public static string FindMsBuildProject(string searchBase, string project) + { + Ensure.NotNullOrEmpty(searchBase, nameof(searchBase)); + + var projectPath = project ?? searchBase; + + if (!Path.IsPathRooted(projectPath)) + { + projectPath = Path.Combine(searchBase, projectPath); + } + + if (Directory.Exists(projectPath)) + { + var projects = Directory.EnumerateFileSystemEntries(projectPath, "*.*proj", SearchOption.TopDirectoryOnly) + .Where(f => !".xproj".Equals(Path.GetExtension(f), StringComparison.OrdinalIgnoreCase)) + .ToList(); + + if (projects.Count > 1) + { + throw new FileNotFoundException(Resources.FormatError_MultipleProjectsFound(projectPath)); + } + + if (projects.Count == 0) + { + throw new FileNotFoundException(Resources.FormatError_NoProjectsFound(projectPath)); + } + + return projects[0]; + } + + if (!File.Exists(projectPath)) + { + throw new FileNotFoundException(Resources.FormatError_ProjectPath_NotFound(projectPath)); + } + + return projectPath; + } + } +} \ No newline at end of file diff --git a/src/Tools/dotnet-watch/src/Internal/OutputCapture.cs b/src/Tools/dotnet-watch/src/Internal/OutputCapture.cs new file mode 100644 index 0000000000..08e051f732 --- /dev/null +++ b/src/Tools/dotnet-watch/src/Internal/OutputCapture.cs @@ -0,0 +1,14 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Collections.Generic; + +namespace Microsoft.DotNet.Watcher.Internal +{ + public class OutputCapture + { + private readonly List _lines = new List(); + public IEnumerable Lines => _lines; + public void AddLine(string line) => _lines.Add(line); + } +} \ No newline at end of file diff --git a/src/Tools/dotnet-watch/src/Internal/OutputSink.cs b/src/Tools/dotnet-watch/src/Internal/OutputSink.cs new file mode 100644 index 0000000000..eb176564ef --- /dev/null +++ b/src/Tools/dotnet-watch/src/Internal/OutputSink.cs @@ -0,0 +1,14 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.DotNet.Watcher.Internal +{ + public class OutputSink + { + public OutputCapture Current { get; private set; } + public OutputCapture StartCapture() + { + return (Current = new OutputCapture()); + } + } +} \ No newline at end of file diff --git a/src/Tools/dotnet-watch/src/Internal/ProcessRunner.cs b/src/Tools/dotnet-watch/src/Internal/ProcessRunner.cs new file mode 100644 index 0000000000..bbded25611 --- /dev/null +++ b/src/Tools/dotnet-watch/src/Internal/ProcessRunner.cs @@ -0,0 +1,174 @@ +// 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.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.CommandLineUtils; +using Microsoft.Extensions.Internal; +using Microsoft.Extensions.Tools.Internal; + +namespace Microsoft.DotNet.Watcher.Internal +{ + public class ProcessRunner + { + private readonly IReporter _reporter; + + public ProcessRunner(IReporter reporter) + { + Ensure.NotNull(reporter, nameof(reporter)); + + _reporter = reporter; + } + + // May not be necessary in the future. See https://github.com/dotnet/corefx/issues/12039 + public async Task RunAsync(ProcessSpec processSpec, CancellationToken cancellationToken) + { + Ensure.NotNull(processSpec, nameof(processSpec)); + + int exitCode; + + var stopwatch = new Stopwatch(); + + using (var process = CreateProcess(processSpec)) + using (var processState = new ProcessState(process, _reporter)) + { + cancellationToken.Register(() => processState.TryKill()); + + stopwatch.Start(); + process.Start(); + _reporter.Verbose($"Started '{processSpec.Executable}' with process id {process.Id}"); + + if (processSpec.IsOutputCaptured) + { + await Task.WhenAll( + processState.Task, + ConsumeStreamAsync(process.StandardOutput, processSpec.OutputCapture.AddLine), + ConsumeStreamAsync(process.StandardError, processSpec.OutputCapture.AddLine) + ); + } + else + { + await processState.Task; + } + + exitCode = process.ExitCode; + stopwatch.Stop(); + _reporter.Verbose($"Process id {process.Id} ran for {stopwatch.ElapsedMilliseconds}ms"); + } + + return exitCode; + } + + private Process CreateProcess(ProcessSpec processSpec) + { + var process = new Process + { + EnableRaisingEvents = true, + StartInfo = + { + FileName = processSpec.Executable, + Arguments = ArgumentEscaper.EscapeAndConcatenate(processSpec.Arguments), + UseShellExecute = false, + WorkingDirectory = processSpec.WorkingDirectory, + RedirectStandardOutput = processSpec.IsOutputCaptured, + RedirectStandardError = processSpec.IsOutputCaptured, + } + }; + + foreach (var env in processSpec.EnvironmentVariables) + { + process.StartInfo.Environment.Add(env.Key, env.Value); + } + + return process; + } + + private static async Task ConsumeStreamAsync(StreamReader reader, Action consume) + { + string line; + while ((line = await reader.ReadLineAsync().ConfigureAwait(false)) != null) + { + consume?.Invoke(line); + } + } + + private class ProcessState : IDisposable + { + private readonly IReporter _reporter; + private readonly Process _process; + private readonly TaskCompletionSource _tcs = new TaskCompletionSource(); + private volatile bool _disposed; + + public ProcessState(Process process, IReporter reporter) + { + _reporter = reporter; + _process = process; + _process.Exited += OnExited; + Task = _tcs.Task.ContinueWith(_ => + { + try + { + // We need to use two WaitForExit calls to ensure that all of the output/events are processed. Previously + // this code used Process.Exited, which could result in us missing some output due to the ordering of + // events. + // + // See the remarks here: https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.process.waitforexit#System_Diagnostics_Process_WaitForExit_System_Int32_ + if (!_process.WaitForExit(Int32.MaxValue)) + { + throw new TimeoutException(); + } + + _process.WaitForExit(); + } + catch (InvalidOperationException) + { + // suppress if this throws if no process is associated with this object anymore. + } + }); + } + + public Task Task { get; } + + public void TryKill() + { + if (_disposed) + { + return; + } + + try + { + if (!_process.HasExited) + { + _reporter.Verbose($"Killing process {_process.Id}"); + _process.KillTree(); + } + } + catch (Exception ex) + { + _reporter.Verbose($"Error while killing process '{_process.StartInfo.FileName} {_process.StartInfo.Arguments}': {ex.Message}"); +#if DEBUG + _reporter.Verbose(ex.ToString()); +#endif + } + } + + private void OnExited(object sender, EventArgs args) + => _tcs.TrySetResult(null); + + public void Dispose() + { + if (!_disposed) + { + TryKill(); + _disposed = true; + _process.Exited -= OnExited; + _process.Dispose(); + } + } + } + } +} diff --git a/src/Tools/dotnet-watch/src/PrefixConsoleReporter.cs b/src/Tools/dotnet-watch/src/PrefixConsoleReporter.cs new file mode 100644 index 0000000000..b2453276ef --- /dev/null +++ b/src/Tools/dotnet-watch/src/PrefixConsoleReporter.cs @@ -0,0 +1,32 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.IO; +using Microsoft.Extensions.Tools.Internal; + +namespace Microsoft.DotNet.Watcher +{ + public class PrefixConsoleReporter : ConsoleReporter + { + private object _lock = new object(); + + public PrefixConsoleReporter(IConsole console, bool verbose, bool quiet) + : base(console, verbose, quiet) + { } + + protected override void WriteLine(TextWriter writer, string message, ConsoleColor? color) + { + const string prefix = "watch : "; + + lock (_lock) + { + Console.ForegroundColor = ConsoleColor.DarkGray; + writer.Write(prefix); + Console.ResetColor(); + + base.WriteLine(writer, message, color); + } + } + } +} diff --git a/src/Tools/dotnet-watch/src/ProcessSpec.cs b/src/Tools/dotnet-watch/src/ProcessSpec.cs new file mode 100644 index 0000000000..ad5eb262b3 --- /dev/null +++ b/src/Tools/dotnet-watch/src/ProcessSpec.cs @@ -0,0 +1,23 @@ +// 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.IO; +using Microsoft.DotNet.Watcher.Internal; + +namespace Microsoft.DotNet.Watcher +{ + public class ProcessSpec + { + public string Executable { get; set; } + public string WorkingDirectory { get; set; } + public IDictionary EnvironmentVariables { get; } = new Dictionary(); + public IEnumerable Arguments { get; set; } + public OutputCapture OutputCapture { get; set; } + + public string ShortDisplayName() + => Path.GetFileNameWithoutExtension(Executable); + + public bool IsOutputCaptured => OutputCapture != null; + } +} diff --git a/src/Tools/dotnet-watch/src/Program.cs b/src/Tools/dotnet-watch/src/Program.cs new file mode 100644 index 0000000000..25317fb6b2 --- /dev/null +++ b/src/Tools/dotnet-watch/src/Program.cs @@ -0,0 +1,216 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.DotNet.Watcher.Internal; +using Microsoft.Extensions.CommandLineUtils; +using Microsoft.Extensions.Tools.Internal; + +namespace Microsoft.DotNet.Watcher +{ + public class Program : IDisposable + { + private readonly IConsole _console; + private readonly string _workingDir; + private readonly CancellationTokenSource _cts; + private IReporter _reporter; + + public Program(IConsole console, string workingDir) + { + Ensure.NotNull(console, nameof(console)); + Ensure.NotNullOrEmpty(workingDir, nameof(workingDir)); + + _console = console; + _workingDir = workingDir; + _cts = new CancellationTokenSource(); + _console.CancelKeyPress += OnCancelKeyPress; + _reporter = CreateReporter(verbose: true, quiet: false, console: _console); + } + + public static async Task Main(string[] args) + { + try + { + DebugHelper.HandleDebugSwitch(ref args); + using (var program = new Program(PhysicalConsole.Singleton, Directory.GetCurrentDirectory())) + { + return await program.RunAsync(args); + } + } + catch (Exception ex) + { + Console.Error.WriteLine("Unexpected error:"); + Console.Error.WriteLine(ex.ToString()); + return 1; + } + } + + public async Task RunAsync(string[] args) + { + CommandLineOptions options; + try + { + options = CommandLineOptions.Parse(args, _console); + } + catch (CommandParsingException ex) + { + _reporter.Error(ex.Message); + return 1; + } + + if (options == null) + { + // invalid args syntax + return 1; + } + + if (options.IsHelp) + { + return 2; + } + + // update reporter as configured by options + _reporter = CreateReporter(options.IsVerbose, options.IsQuiet, _console); + + try + { + if (_cts.IsCancellationRequested) + { + return 1; + } + + if (options.ListFiles) + { + return await ListFilesAsync(_reporter, + options.Project, + _cts.Token); + } + else + { + return await MainInternalAsync(_reporter, + options.Project, + options.RemainingArguments, + _cts.Token); + } + } + catch (Exception ex) + { + if (ex is TaskCanceledException || ex is OperationCanceledException) + { + // swallow when only exception is the CTRL+C forced an exit + return 0; + } + + _reporter.Error(ex.ToString()); + _reporter.Error("An unexpected error occurred"); + return 1; + } + } + + private void OnCancelKeyPress(object sender, ConsoleCancelEventArgs args) + { + // suppress CTRL+C on the first press + args.Cancel = !_cts.IsCancellationRequested; + + if (args.Cancel) + { + _reporter.Output("Shutdown requested. Press Ctrl+C again to force exit."); + } + + _cts.Cancel(); + } + + private async Task MainInternalAsync( + IReporter reporter, + string project, + ICollection args, + CancellationToken cancellationToken) + { + // TODO multiple projects should be easy enough to add here + string projectFile; + try + { + projectFile = MsBuildProjectFinder.FindMsBuildProject(_workingDir, project); + } + catch (FileNotFoundException ex) + { + reporter.Error(ex.Message); + return 1; + } + + var fileSetFactory = new MsBuildFileSetFactory(reporter, + projectFile, + waitOnError: true, + trace: false); + var processInfo = new ProcessSpec + { + Executable = DotNetMuxer.MuxerPathOrDefault(), + WorkingDirectory = Path.GetDirectoryName(projectFile), + Arguments = args, + EnvironmentVariables = + { + ["DOTNET_WATCH"] = "1" + }, + }; + + if (CommandLineOptions.IsPollingEnabled) + { + _reporter.Output("Polling file watcher is enabled"); + } + + await new DotNetWatcher(reporter) + .WatchAsync(processInfo, fileSetFactory, cancellationToken); + + return 0; + } + + private async Task ListFilesAsync( + IReporter reporter, + string project, + CancellationToken cancellationToken) + { + // TODO multiple projects should be easy enough to add here + string projectFile; + try + { + projectFile = MsBuildProjectFinder.FindMsBuildProject(_workingDir, project); + } + catch (FileNotFoundException ex) + { + reporter.Error(ex.Message); + return 1; + } + + var fileSetFactory = new MsBuildFileSetFactory(reporter, + projectFile, + waitOnError: false, + trace: false); + var files = await fileSetFactory.CreateAsync(cancellationToken); + + if (files == null) + { + return 1; + } + + foreach (var file in files) + { + _console.Out.WriteLine(file); + } + + return 0; + } + + private static IReporter CreateReporter(bool verbose, bool quiet, IConsole console) + => new PrefixConsoleReporter(console, verbose || CliContext.IsGlobalVerbose(), quiet); + + public void Dispose() + { + _console.CancelKeyPress -= OnCancelKeyPress; + _cts.Dispose(); + } + } +} diff --git a/src/Tools/dotnet-watch/src/Properties/AssemblyInfo.cs b/src/Tools/dotnet-watch/src/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..70797aee7c --- /dev/null +++ b/src/Tools/dotnet-watch/src/Properties/AssemblyInfo.cs @@ -0,0 +1,6 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Microsoft.DotNet.Watcher.Tools.Tests, PublicKey = 0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] diff --git a/src/Tools/dotnet-watch/src/Properties/Resources.Designer.cs b/src/Tools/dotnet-watch/src/Properties/Resources.Designer.cs new file mode 100644 index 0000000000..ee248b1342 --- /dev/null +++ b/src/Tools/dotnet-watch/src/Properties/Resources.Designer.cs @@ -0,0 +1,94 @@ +// +namespace Microsoft.DotNet.Watcher.Tools +{ + using System.Globalization; + using System.Reflection; + using System.Resources; + + internal static class Resources + { + private static readonly ResourceManager _resourceManager + = new ResourceManager("Microsoft.DotNet.Watcher.Tools.Resources", typeof(Resources).GetTypeInfo().Assembly); + + /// + /// The project file '{path}' does not exist. + /// + internal static string Error_ProjectPath_NotFound + { + get { return GetString("Error_ProjectPath_NotFound"); } + } + + /// + /// The project file '{path}' does not exist. + /// + internal static string FormatError_ProjectPath_NotFound(object path) + { + return string.Format(CultureInfo.CurrentCulture, GetString("Error_ProjectPath_NotFound", "path"), path); + } + + /// + /// Multiple MSBuild project files found in '{projectPath}'. Specify which to use with the --project option. + /// + internal static string Error_MultipleProjectsFound + { + get { return GetString("Error_MultipleProjectsFound"); } + } + + /// + /// Multiple MSBuild project files found in '{projectPath}'. Specify which to use with the --project option. + /// + internal static string FormatError_MultipleProjectsFound(object projectPath) + { + return string.Format(CultureInfo.CurrentCulture, GetString("Error_MultipleProjectsFound", "projectPath"), projectPath); + } + + /// + /// Could not find a MSBuild project file in '{projectPath}'. Specify which project to use with the --project option. + /// + internal static string Error_NoProjectsFound + { + get { return GetString("Error_NoProjectsFound"); } + } + + /// + /// Could not find a MSBuild project file in '{projectPath}'. Specify which project to use with the --project option. + /// + internal static string FormatError_NoProjectsFound(object projectPath) + { + return string.Format(CultureInfo.CurrentCulture, GetString("Error_NoProjectsFound", "projectPath"), projectPath); + } + + /// + /// Cannot specify both '--quiet' and '--verbose' options. + /// + internal static string Error_QuietAndVerboseSpecified + { + get { return GetString("Error_QuietAndVerboseSpecified"); } + } + + /// + /// Cannot specify both '--quiet' and '--verbose' options. + /// + internal static string FormatError_QuietAndVerboseSpecified() + { + return GetString("Error_QuietAndVerboseSpecified"); + } + + 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; + } + } +} diff --git a/src/Tools/dotnet-watch/src/Resources.resx b/src/Tools/dotnet-watch/src/Resources.resx new file mode 100644 index 0000000000..b66821626b --- /dev/null +++ b/src/Tools/dotnet-watch/src/Resources.resx @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + The project file '{path}' does not exist. + + + Multiple MSBuild project files found in '{projectPath}'. Specify which to use with the --project option. + + + Could not find a MSBuild project file in '{projectPath}'. Specify which project to use with the --project option. + + + Cannot specify both '--quiet' and '--verbose' options. + + \ No newline at end of file diff --git a/src/Tools/dotnet-watch/src/assets/DotNetWatch.targets b/src/Tools/dotnet-watch/src/assets/DotNetWatch.targets new file mode 100644 index 0000000000..5ce4f08672 --- /dev/null +++ b/src/Tools/dotnet-watch/src/assets/DotNetWatch.targets @@ -0,0 +1,68 @@ + + + + + + + + + <_CollectWatchItemsDependsOn Condition=" '$(TargetFrameworks)' != '' AND '$(TargetFramework)' == '' "> + _CollectWatchItemsPerFramework; + + <_CollectWatchItemsDependsOn Condition=" '$(TargetFramework)' != '' "> + _CoreCollectWatchItems; + + + + + + + + <_TargetFramework Include="$(TargetFrameworks)" /> + + + + + + + + + + + + + + + + + + <_WatchProjects Include="%(ProjectReference.Identity)" Condition="'%(ProjectReference.Watch)' != 'false'" /> + + + + + + + + diff --git a/src/Tools/dotnet-watch/src/dotnet-watch.csproj b/src/Tools/dotnet-watch/src/dotnet-watch.csproj new file mode 100644 index 0000000000..2e4cb173d1 --- /dev/null +++ b/src/Tools/dotnet-watch/src/dotnet-watch.csproj @@ -0,0 +1,24 @@ + + + + netcoreapp3.0 + exe + Command line tool to watch for source file changes during development and restart the dotnet command. + Microsoft.DotNet.Watcher.Tools + dotnet;watch + true + + win-x64;win-x86 + + + + + + + + + + + + + diff --git a/src/Tools/dotnet-watch/test/AppWithDepsTests.cs b/src/Tools/dotnet-watch/test/AppWithDepsTests.cs new file mode 100644 index 0000000000..8ec43cf3a5 --- /dev/null +++ b/src/Tools/dotnet-watch/test/AppWithDepsTests.cs @@ -0,0 +1,54 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.IO; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Testing; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests +{ + public class AppWithDepsTests : IDisposable + { + private readonly AppWithDeps _app; + + public AppWithDepsTests(ITestOutputHelper logger) + { + _app = new AppWithDeps(logger); + } + + [Fact] + public async Task ChangeFileInDependency() + { + await _app.StartWatcherAsync(); + + var fileToChange = Path.Combine(_app.DependencyFolder, "Foo.cs"); + var programCs = File.ReadAllText(fileToChange); + File.WriteAllText(fileToChange, programCs); + + await _app.HasRestarted(); + } + + public void Dispose() + { + _app.Dispose(); + } + + private class AppWithDeps : WatchableApp + { + private const string Dependency = "Dependency"; + + public AppWithDeps(ITestOutputHelper logger) + : base("AppWithDeps", logger) + { + Scenario.AddTestProjectFolder(Dependency); + + DependencyFolder = Path.Combine(Scenario.WorkFolder, Dependency); + } + + public string DependencyFolder { get; private set; } + } + } +} diff --git a/src/Tools/dotnet-watch/test/AssertEx.cs b/src/Tools/dotnet-watch/test/AssertEx.cs new file mode 100644 index 0000000000..4d897058fd --- /dev/null +++ b/src/Tools/dotnet-watch/test/AssertEx.cs @@ -0,0 +1,35 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Xunit; +using Xunit.Sdk; + +namespace Microsoft.DotNet.Watcher.Tools.Tests +{ + public static class AssertEx + { + public static void EqualFileList(string root, IEnumerable expectedFiles, IEnumerable actualFiles) + { + var expected = expectedFiles.Select(p => Path.Combine(root, p)); + EqualFileList(expected, actualFiles); + } + + public static void EqualFileList(IEnumerable expectedFiles, IEnumerable actualFiles) + { + string normalize(string p) => p.Replace('\\', '/'); + var expected = new HashSet(expectedFiles.Select(normalize)); + var actual = new HashSet(actualFiles.Where(p => !string.IsNullOrEmpty(p)).Select(normalize)); + if (!expected.SetEquals(actual)) + { + throw new AssertActualExpectedException( + expected: "\n" + string.Join("\n", expected), + actual: "\n" + string.Join("\n", actual), + userMessage: "File sets should be equal"); + } + } + } +} diff --git a/src/Tools/dotnet-watch/test/AwaitableProcess.cs b/src/Tools/dotnet-watch/test/AwaitableProcess.cs new file mode 100644 index 0000000000..3e22d53245 --- /dev/null +++ b/src/Tools/dotnet-watch/test/AwaitableProcess.cs @@ -0,0 +1,165 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; +using System.Threading.Tasks.Dataflow; +using Microsoft.Extensions.Internal; +using Microsoft.Extensions.CommandLineUtils; +using Xunit.Abstractions; + +namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests +{ + public class AwaitableProcess : IDisposable + { + private Process _process; + private readonly ProcessSpec _spec; + private readonly List _lines; + private BufferBlock _source; + private ITestOutputHelper _logger; + private TaskCompletionSource _exited; + + public AwaitableProcess(ProcessSpec spec, ITestOutputHelper logger) + { + _spec = spec; + _logger = logger; + _source = new BufferBlock(); + _lines = new List(); + _exited = new TaskCompletionSource(); + } + + public IEnumerable Output => _lines; + + public Task Exited => _exited.Task; + + public int Id => _process.Id; + + public void Start() + { + if (_process != null) + { + throw new InvalidOperationException("Already started"); + } + + _process = new Process + { + EnableRaisingEvents = true, + StartInfo = new ProcessStartInfo + { + UseShellExecute = false, + FileName = _spec.Executable, + WorkingDirectory = _spec.WorkingDirectory, + Arguments = ArgumentEscaper.EscapeAndConcatenate(_spec.Arguments), + RedirectStandardOutput = true, + RedirectStandardError = true, + Environment = + { + ["DOTNET_SKIP_FIRST_TIME_EXPERIENCE"] = "true" + } + } + }; + + foreach (var env in _spec.EnvironmentVariables) + { + _process.StartInfo.EnvironmentVariables[env.Key] = env.Value; + } + + _process.OutputDataReceived += OnData; + _process.ErrorDataReceived += OnData; + _process.Exited += OnExit; + + _process.Start(); + _process.BeginErrorReadLine(); + _process.BeginOutputReadLine(); + _logger.WriteLine($"{DateTime.Now}: process start: '{_process.StartInfo.FileName} {_process.StartInfo.Arguments}'"); + } + + public async Task GetOutputLineAsync(string message, TimeSpan timeout) + { + _logger.WriteLine($"Waiting for output line [msg == '{message}']. Will wait for {timeout.TotalSeconds} sec."); + var cts = new CancellationTokenSource(); + cts.CancelAfter(timeout); + return await GetOutputLineAsync($"[msg == '{message}']", m => string.Equals(m, message, StringComparison.Ordinal), cts.Token); + } + + public async Task GetOutputLineStartsWithAsync(string message, TimeSpan timeout) + { + _logger.WriteLine($"Waiting for output line [msg.StartsWith('{message}')]. Will wait for {timeout.TotalSeconds} sec."); + var cts = new CancellationTokenSource(); + cts.CancelAfter(timeout); + return await GetOutputLineAsync($"[msg.StartsWith('{message}')]", m => m != null && m.StartsWith(message, StringComparison.Ordinal), cts.Token); + } + + private async Task GetOutputLineAsync(string predicateName, Predicate predicate, CancellationToken cancellationToken) + { + while (!_source.Completion.IsCompleted) + { + while (await _source.OutputAvailableAsync(cancellationToken)) + { + var next = await _source.ReceiveAsync(cancellationToken); + _lines.Add(next); + var match = predicate(next); + _logger.WriteLine($"{DateTime.Now}: recv: '{next}'. {(match ? "Matches" : "Does not match")} condition '{predicateName}'."); + if (match) + { + return next; + } + } + } + + return null; + } + + public async Task> GetAllOutputLinesAsync(CancellationToken cancellationToken) + { + var lines = new List(); + while (!_source.Completion.IsCompleted) + { + while (await _source.OutputAvailableAsync(cancellationToken)) + { + var next = await _source.ReceiveAsync(cancellationToken); + _logger.WriteLine($"{DateTime.Now}: recv: '{next}'"); + lines.Add(next); + } + } + return lines; + } + + private void OnData(object sender, DataReceivedEventArgs args) + { + var line = args.Data ?? string.Empty; + _logger.WriteLine($"{DateTime.Now}: post: '{line}'"); + _source.Post(line); + } + + private void OnExit(object sender, EventArgs args) + { + // Wait to ensure the process has exited and all output consumed + _process.WaitForExit(); + _source.Complete(); + _exited.TrySetResult(_process.ExitCode); + _logger.WriteLine($"Process {_process.Id} has exited"); + } + + public void Dispose() + { + _source.Complete(); + + if (_process != null) + { + if (!_process.HasExited) + { + _process.KillTree(); + } + + _process.ErrorDataReceived -= OnData; + _process.OutputDataReceived -= OnData; + _process.Exited -= OnExit; + _process.Dispose(); + } + } + } +} diff --git a/src/Tools/dotnet-watch/test/CommandLineOptionsTests.cs b/src/Tools/dotnet-watch/test/CommandLineOptionsTests.cs new file mode 100644 index 0000000000..129d1219fa --- /dev/null +++ b/src/Tools/dotnet-watch/test/CommandLineOptionsTests.cs @@ -0,0 +1,63 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.IO; +using System.Linq; +using System.Text; +using Microsoft.Extensions.CommandLineUtils; +using Microsoft.Extensions.Tools.Internal; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.DotNet.Watcher.Tools.Tests +{ + public class CommandLineOptionsTests + { + private readonly IConsole _console; + private readonly StringBuilder _stdout = new StringBuilder(); + + public CommandLineOptionsTests(ITestOutputHelper output) + { + _console = new TestConsole(output) + { + Out = new StringWriter(_stdout), + }; + } + + [Theory] + [InlineData(new object[] { new[] { "-h" } })] + [InlineData(new object[] { new[] { "-?" } })] + [InlineData(new object[] { new[] { "--help" } })] + [InlineData(new object[] { new[] { "--help", "--bogus" } })] + [InlineData(new object[] { new[] { "--" } })] + [InlineData(new object[] { new string[0] })] + public void HelpArgs(string[] args) + { + var options = CommandLineOptions.Parse(args, _console); + + Assert.True(options.IsHelp); + Assert.Contains("Usage: dotnet watch ", _stdout.ToString()); + } + + [Theory] + [InlineData(new[] { "run" }, new[] { "run" })] + [InlineData(new[] { "run", "--", "subarg" }, new[] { "run", "--", "subarg" })] + [InlineData(new[] { "--", "run", "--", "subarg" }, new[] { "run", "--", "subarg" })] + [InlineData(new[] { "--unrecognized-arg" }, new[] { "--unrecognized-arg" })] + public void ParsesRemainingArgs(string[] args, string[] expected) + { + var options = CommandLineOptions.Parse(args, _console); + + Assert.Equal(expected, options.RemainingArguments.ToArray()); + Assert.False(options.IsHelp); + Assert.Empty(_stdout.ToString()); + } + + [Fact] + public void CannotHaveQuietAndVerbose() + { + var ex = Assert.Throws(() => CommandLineOptions.Parse(new[] { "--quiet", "--verbose" }, _console)); + Assert.Equal(Resources.Error_QuietAndVerboseSpecified, ex.Message); + } + } +} diff --git a/src/Tools/dotnet-watch/test/ConsoleReporterTests.cs b/src/Tools/dotnet-watch/test/ConsoleReporterTests.cs new file mode 100644 index 0000000000..34cfd42850 --- /dev/null +++ b/src/Tools/dotnet-watch/test/ConsoleReporterTests.cs @@ -0,0 +1,83 @@ +// 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.Text; +using Microsoft.Extensions.Tools.Internal; +using Xunit; + +namespace Microsoft.Extensions.Tools.Tests +{ + public class ReporterTests + { + private static readonly string EOL = Environment.NewLine; + + [Fact] + public void WritesToStandardStreams() + { + var testConsole = new TestConsole(); + var reporter = new ConsoleReporter(testConsole, verbose: true, quiet: false); + + // stdout + reporter.Verbose("verbose"); + Assert.Equal("verbose" + EOL, testConsole.GetOutput()); + testConsole.Clear(); + + reporter.Output("out"); + Assert.Equal("out" + EOL, testConsole.GetOutput()); + testConsole.Clear(); + + reporter.Warn("warn"); + Assert.Equal("warn" + EOL, testConsole.GetOutput()); + testConsole.Clear(); + + // stderr + reporter.Error("error"); + Assert.Equal("error" + EOL, testConsole.GetError()); + testConsole.Clear(); + } + + private class TestConsole : IConsole + { + private readonly StringBuilder _out; + private readonly StringBuilder _error; + + public TestConsole() + { + _out = new StringBuilder(); + _error = new StringBuilder(); + Out = new StringWriter(_out); + Error = new StringWriter(_error); + } + + event ConsoleCancelEventHandler IConsole.CancelKeyPress + { + add { } + remove { } + } + + public string GetOutput() => _out.ToString(); + public string GetError() => _error.ToString(); + + public void Clear() + { + _out.Clear(); + _error.Clear(); + } + + public void ResetColor() + { + ForegroundColor = default(ConsoleColor); + } + + public TextWriter Out { get; } + public TextWriter Error { get; } + public TextReader In { get; } + public bool IsInputRedirected { get; } + public bool IsOutputRedirected { get; } + public bool IsErrorRedirected { get; } + public ConsoleColor ForegroundColor { get; set; } + } + } +} diff --git a/src/Tools/dotnet-watch/test/DotNetWatcherTests.cs b/src/Tools/dotnet-watch/test/DotNetWatcherTests.cs new file mode 100644 index 0000000000..d31f650aa6 --- /dev/null +++ b/src/Tools/dotnet-watch/test/DotNetWatcherTests.cs @@ -0,0 +1,81 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Globalization; +using System.Threading.Tasks; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests +{ + public class DotNetWatcherTests : IDisposable + { + private readonly ITestOutputHelper _logger; + private readonly KitchenSinkApp _app; + + public DotNetWatcherTests(ITestOutputHelper logger) + { + _logger = logger; + _app = new KitchenSinkApp(logger); + } + + [Fact] + public async Task RunsWithDotnetWatchEnvVariable() + { + Assert.True(string.IsNullOrEmpty(Environment.GetEnvironmentVariable("DOTNET_WATCH")), "DOTNET_WATCH cannot be set already when this test is running"); + + await _app.StartWatcherAsync(); + const string messagePrefix = "DOTNET_WATCH = "; + var message = await _app.Process.GetOutputLineStartsWithAsync(messagePrefix, TimeSpan.FromMinutes(2)); + var envValue = message.Substring(messagePrefix.Length); + Assert.Equal("1", envValue); + } + + [Fact] + public async Task RunsWithIterationEnvVariable() + { + await _app.StartWatcherAsync(); + var source = Path.Combine(_app.SourceDirectory, "Program.cs"); + var contents = File.ReadAllText(source); + const string messagePrefix = "DOTNET_WATCH_ITERATION = "; + for (var i = 1; i <= 3; i++) + { + var message = await _app.Process.GetOutputLineStartsWithAsync(messagePrefix, TimeSpan.FromMinutes(2)); + var count = int.Parse(message.Substring(messagePrefix.Length), CultureInfo.InvariantCulture); + Assert.Equal(i, count); + + await _app.IsWaitingForFileChange(); + + try + { + File.SetLastWriteTime(source, DateTime.Now); + await _app.HasRestarted(); + } + catch (Exception ex) + { + _logger.WriteLine("Retrying. First attempt to restart app failed: " + ex.Message); + + // retry + File.SetLastWriteTime(source, DateTime.Now); + await _app.HasRestarted(); + } + } + } + + public void Dispose() + { + _app.Dispose(); + } + + private class KitchenSinkApp : WatchableApp + { + public KitchenSinkApp(ITestOutputHelper logger) + : base("KitchenSink", logger) + { + } + } + } +} diff --git a/src/Tools/dotnet-watch/test/FileWatcherTests.cs b/src/Tools/dotnet-watch/test/FileWatcherTests.cs new file mode 100644 index 0000000000..51c1895e05 --- /dev/null +++ b/src/Tools/dotnet-watch/test/FileWatcherTests.cs @@ -0,0 +1,419 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using Microsoft.DotNet.Watcher.Internal; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests +{ + public class FileWatcherTests + { + public FileWatcherTests(ITestOutputHelper output) + { + _output = output; + } + + private const int DefaultTimeout = 10 * 1000; // 10 sec + private readonly ITestOutputHelper _output; + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void NewFile(bool usePolling) + { + UsingTempDirectory(dir => + { + using (var changedEv = new ManualResetEvent(false)) + using (var watcher = FileWatcherFactory.CreateWatcher(dir, usePolling)) + { + var filesChanged = new HashSet(); + + watcher.OnFileChange += (_, f) => + { + filesChanged.Add(f); + changedEv.Set(); + }; + watcher.EnableRaisingEvents = true; + + var testFileFullPath = Path.Combine(dir, "foo"); + File.WriteAllText(testFileFullPath, string.Empty); + + Assert.True(changedEv.WaitOne(DefaultTimeout)); + Assert.Equal(testFileFullPath, filesChanged.Single()); + } + }); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void ChangeFile(bool usePolling) + { + UsingTempDirectory(dir => + { + var testFileFullPath = Path.Combine(dir, "foo"); + File.WriteAllText(testFileFullPath, string.Empty); + + using (var changedEv = new ManualResetEvent(false)) + using (var watcher = FileWatcherFactory.CreateWatcher(dir, usePolling)) + { + var filesChanged = new HashSet(); + + EventHandler handler = null; + handler = (_, f) => + { + watcher.EnableRaisingEvents = false; + watcher.OnFileChange -= handler; + + filesChanged.Add(f); + changedEv.Set(); + }; + + watcher.OnFileChange += handler; + watcher.EnableRaisingEvents = true; + + // On Unix the file write time is in 1s increments; + // if we don't wait, there's a chance that the polling + // watcher will not detect the change + Thread.Sleep(1000); + File.WriteAllText(testFileFullPath, string.Empty); + + Assert.True(changedEv.WaitOne(DefaultTimeout)); + Assert.Equal(testFileFullPath, filesChanged.Single()); + } + }); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void MoveFile(bool usePolling) + { + UsingTempDirectory(dir => + { + var srcFile = Path.Combine(dir, "foo"); + var dstFile = Path.Combine(dir, "foo2"); + + File.WriteAllText(srcFile, string.Empty); + + using (var changedEv = new ManualResetEvent(false)) + using (var watcher = FileWatcherFactory.CreateWatcher(dir, usePolling)) + { + var filesChanged = new HashSet(); + + EventHandler handler = null; + handler = (_, f) => + { + filesChanged.Add(f); + + if (filesChanged.Count >= 2) + { + watcher.EnableRaisingEvents = false; + watcher.OnFileChange -= handler; + + changedEv.Set(); + } + }; + + watcher.OnFileChange += handler; + watcher.EnableRaisingEvents = true; + + File.Move(srcFile, dstFile); + + Assert.True(changedEv.WaitOne(DefaultTimeout)); + Assert.Contains(srcFile, filesChanged); + Assert.Contains(dstFile, filesChanged); + } + }); + } + + [Fact] + public void FileInSubdirectory() + { + UsingTempDirectory(dir => + { + var subdir = Path.Combine(dir, "subdir"); + Directory.CreateDirectory(subdir); + + var testFileFullPath = Path.Combine(subdir, "foo"); + File.WriteAllText(testFileFullPath, string.Empty); + + using (var changedEv = new ManualResetEvent(false)) + using (var watcher = FileWatcherFactory.CreateWatcher(dir, true)) + { + var filesChanged = new HashSet(); + + EventHandler handler = null; + handler = (_, f) => + { + filesChanged.Add(f); + + if (filesChanged.Count >= 2) + { + watcher.EnableRaisingEvents = false; + watcher.OnFileChange -= handler; + changedEv.Set(); + } + }; + + watcher.OnFileChange += handler; + watcher.EnableRaisingEvents = true; + + // On Unix the file write time is in 1s increments; + // if we don't wait, there's a chance that the polling + // watcher will not detect the change + Thread.Sleep(1000); + File.WriteAllText(testFileFullPath, string.Empty); + + Assert.True(changedEv.WaitOne(DefaultTimeout)); + Assert.Contains(subdir, filesChanged); + Assert.Contains(testFileFullPath, filesChanged); + } + }); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void NoNotificationIfDisabled(bool usePolling) + { + UsingTempDirectory(dir => + { + using (var watcher = FileWatcherFactory.CreateWatcher(dir, usePolling)) + using (var changedEv = new ManualResetEvent(false)) + { + watcher.OnFileChange += (_, f) => changedEv.Set(); + + // Disable + watcher.EnableRaisingEvents = false; + + var testFileFullPath = Path.Combine(dir, "foo"); + + // On Unix the file write time is in 1s increments; + // if we don't wait, there's a chance that the polling + // watcher will not detect the change + Thread.Sleep(1000); + File.WriteAllText(testFileFullPath, string.Empty); + + Assert.False(changedEv.WaitOne(DefaultTimeout / 2)); + } + }); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void DisposedNoEvents(bool usePolling) + { + UsingTempDirectory(dir => + { + using (var changedEv = new ManualResetEvent(false)) + { + using (var watcher = FileWatcherFactory.CreateWatcher(dir, usePolling)) + { + watcher.OnFileChange += (_, f) => changedEv.Set(); + watcher.EnableRaisingEvents = true; + } + + var testFileFullPath = Path.Combine(dir, "foo"); + + // On Unix the file write time is in 1s increments; + // if we don't wait, there's a chance that the polling + // watcher will not detect the change + Thread.Sleep(1000); + File.WriteAllText(testFileFullPath, string.Empty); + + Assert.False(changedEv.WaitOne(DefaultTimeout / 2)); + } + }); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void MultipleFiles(bool usePolling) + { + UsingTempDirectory(dir => + { + File.WriteAllText(Path.Combine(dir, "foo1"), string.Empty); + File.WriteAllText(Path.Combine(dir, "foo2"), string.Empty); + File.WriteAllText(Path.Combine(dir, "foo3"), string.Empty); + File.WriteAllText(Path.Combine(dir, "foo4"), string.Empty); + File.WriteAllText(Path.Combine(dir, "foo4"), string.Empty); + + var testFileFullPath = Path.Combine(dir, "foo3"); + + using (var changedEv = new ManualResetEvent(false)) + using (var watcher = FileWatcherFactory.CreateWatcher(dir, usePolling)) + { + var filesChanged = new HashSet(); + + EventHandler handler = null; + handler = (_, f) => + { + watcher.EnableRaisingEvents = false; + watcher.OnFileChange -= handler; + filesChanged.Add(f); + changedEv.Set(); + }; + + watcher.OnFileChange += handler; + watcher.EnableRaisingEvents = true; + + // On Unix the file write time is in 1s increments; + // if we don't wait, there's a chance that the polling + // watcher will not detect the change + Thread.Sleep(1000); + + File.WriteAllText(testFileFullPath, string.Empty); + + Assert.True(changedEv.WaitOne(DefaultTimeout)); + Assert.Equal(testFileFullPath, filesChanged.Single()); + } + }); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void MultipleTriggers(bool usePolling) + { + var filesChanged = new HashSet(); + + UsingTempDirectory(dir => + { + using (var watcher = FileWatcherFactory.CreateWatcher(dir, usePolling)) + { + watcher.EnableRaisingEvents = true; + + for (var i = 0; i < 5; i++) + { + AssertFileChangeRaisesEvent(dir, watcher); + } + + watcher.EnableRaisingEvents = false; + } + }); + } + + private void AssertFileChangeRaisesEvent(string directory, IFileSystemWatcher watcher) + { + using (var semaphoreSlim = new SemaphoreSlim(0)) + { + var expectedPath = Path.Combine(directory, Path.GetRandomFileName()); + EventHandler handler = (object _, string f) => + { + _output.WriteLine("File changed: " + f); + try + { + if (string.Equals(f, expectedPath, StringComparison.OrdinalIgnoreCase)) + { + semaphoreSlim.Release(); + } + } + catch (ObjectDisposedException) + { + // There's a known race condition here: + // even though we tell the watcher to stop raising events and we unsubscribe the handler + // there might be in-flight events that will still process. Since we dispose the reset + // event, this code will fail if the handler executes after Dispose happens. + } + }; + + File.AppendAllText(expectedPath, " "); + + watcher.OnFileChange += handler; + try + { + // On Unix the file write time is in 1s increments; + // if we don't wait, there's a chance that the polling + // watcher will not detect the change + Thread.Sleep(1000); + File.AppendAllText(expectedPath, " "); + Assert.True(semaphoreSlim.Wait(DefaultTimeout), "Expected a file change event for " + expectedPath); + } + finally + { + watcher.OnFileChange -= handler; + } + } + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void DeleteSubfolder(bool usePolling) + { + UsingTempDirectory(dir => + { + var subdir = Path.Combine(dir, "subdir"); + Directory.CreateDirectory(subdir); + + var f1 = Path.Combine(subdir, "foo1"); + var f2 = Path.Combine(subdir, "foo2"); + var f3 = Path.Combine(subdir, "foo3"); + + File.WriteAllText(f1, string.Empty); + File.WriteAllText(f2, string.Empty); + File.WriteAllText(f3, string.Empty); + + using (var changedEv = new AutoResetEvent(false)) + using (var watcher = FileWatcherFactory.CreateWatcher(dir, usePolling)) + { + var filesChanged = new HashSet(); + + EventHandler handler = null; + handler = (_, f) => + { + filesChanged.Add(f); + + if (filesChanged.Count >= 4) + { + watcher.EnableRaisingEvents = false; + watcher.OnFileChange -= handler; + changedEv.Set(); + } + }; + + watcher.OnFileChange += handler; + watcher.EnableRaisingEvents = true; + + Directory.Delete(subdir, recursive: true); + + Assert.True(changedEv.WaitOne(DefaultTimeout)); + + Assert.Contains(f1, filesChanged); + Assert.Contains(f2, filesChanged); + Assert.Contains(f3, filesChanged); + Assert.Contains(subdir, filesChanged); + } + }); + } + + private static void UsingTempDirectory(Action action) + { + var tempFolder = Path.Combine(Path.GetTempPath(), $"{nameof(FileWatcherTests)}-{Guid.NewGuid().ToString("N")}"); + if (Directory.Exists(tempFolder)) + { + Directory.Delete(tempFolder, recursive: true); + } + + Directory.CreateDirectory(tempFolder); + + try + { + action(tempFolder); + } + finally + { + Directory.Delete(tempFolder, recursive: true); + } + } + } +} diff --git a/src/Tools/dotnet-watch/test/GlobbingAppTests.cs b/src/Tools/dotnet-watch/test/GlobbingAppTests.cs new file mode 100644 index 0000000000..3658261049 --- /dev/null +++ b/src/Tools/dotnet-watch/test/GlobbingAppTests.cs @@ -0,0 +1,140 @@ +// 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.Threading; +using System.Threading.Tasks; +using Microsoft.DotNet.Watcher.Tools.Tests; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests +{ + public class GlobbingAppTests : IDisposable + { + private GlobbingApp _app; + public GlobbingAppTests(ITestOutputHelper logger) + { + _app = new GlobbingApp(logger); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public async Task ChangeCompiledFile(bool usePollingWatcher) + { + _app.UsePollingWatcher = usePollingWatcher; + await _app.StartWatcherAsync(); + + var types = await _app.GetCompiledAppDefinedTypes(); + Assert.Equal(2, types); + + var fileToChange = Path.Combine(_app.SourceDirectory, "include", "Foo.cs"); + var programCs = File.ReadAllText(fileToChange); + File.WriteAllText(fileToChange, programCs); + + await _app.HasRestarted(); + types = await _app.GetCompiledAppDefinedTypes(); + Assert.Equal(2, types); + } + + [Fact] + public async Task DeleteCompiledFile() + { + await _app.StartWatcherAsync(); + + var types = await _app.GetCompiledAppDefinedTypes(); + Assert.Equal(2, types); + + var fileToChange = Path.Combine(_app.SourceDirectory, "include", "Foo.cs"); + File.Delete(fileToChange); + + await _app.HasRestarted(); + types = await _app.GetCompiledAppDefinedTypes(); + Assert.Equal(1, types); + } + + [Fact] + public async Task DeleteSourceFolder() + { + await _app.StartWatcherAsync(); + + var types = await _app.GetCompiledAppDefinedTypes(); + Assert.Equal(2, types); + + var folderToDelete = Path.Combine(_app.SourceDirectory, "include"); + Directory.Delete(folderToDelete, recursive: true); + + await _app.HasRestarted(); + types = await _app.GetCompiledAppDefinedTypes(); + Assert.Equal(1, types); + } + + [Fact] + public async Task RenameCompiledFile() + { + await _app.StartWatcherAsync(); + + var oldFile = Path.Combine(_app.SourceDirectory, "include", "Foo.cs"); + var newFile = Path.Combine(_app.SourceDirectory, "include", "Foo_new.cs"); + File.Move(oldFile, newFile); + + await _app.HasRestarted(); + } + + [Fact] + public async Task ChangeExcludedFile() + { + await _app.StartWatcherAsync(); + + var changedFile = Path.Combine(_app.SourceDirectory, "exclude", "Baz.cs"); + File.WriteAllText(changedFile, ""); + + var restart = _app.HasRestarted(); + var finished = await Task.WhenAny(Task.Delay(TimeSpan.FromSeconds(10)), restart); + Assert.NotSame(restart, finished); + } + + [Fact] + public async Task ListsFiles() + { + await _app.PrepareAsync(); + _app.Start(new [] { "--list" }); + var cts = new CancellationTokenSource(); + cts.CancelAfter(TimeSpan.FromSeconds(30)); + var lines = await _app.Process.GetAllOutputLinesAsync(cts.Token); + var files = lines.Where(l => !l.StartsWith("watch :")); + + AssertEx.EqualFileList( + _app.Scenario.WorkFolder, + new[] + { + "GlobbingApp/Program.cs", + "GlobbingApp/include/Foo.cs", + "GlobbingApp/GlobbingApp.csproj", + }, + files); + } + + public void Dispose() + { + _app.Dispose(); + } + + private class GlobbingApp : WatchableApp + { + public GlobbingApp(ITestOutputHelper logger) + : base("GlobbingApp", logger) + { + } + + public async Task GetCompiledAppDefinedTypes() + { + var definedTypesMessage = await Process.GetOutputLineStartsWithAsync("Defined types = ", TimeSpan.FromSeconds(30)); + return int.Parse(definedTypesMessage.Split('=').Last()); + } + } + } +} diff --git a/src/Tools/dotnet-watch/test/MsBuildFileSetFactoryTest.cs b/src/Tools/dotnet-watch/test/MsBuildFileSetFactoryTest.cs new file mode 100644 index 0000000000..c34111b239 --- /dev/null +++ b/src/Tools/dotnet-watch/test/MsBuildFileSetFactoryTest.cs @@ -0,0 +1,289 @@ +// 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.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Testing; +using Microsoft.DotNet.Watcher.Internal; +using Microsoft.Extensions.Tools.Internal; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.DotNet.Watcher.Tools.Tests +{ + using ItemSpec = TemporaryCSharpProject.ItemSpec; + + public class MsBuildFileSetFactoryTest : IDisposable + { + private readonly IReporter _reporter; + private readonly TemporaryDirectory _tempDir; + public MsBuildFileSetFactoryTest(ITestOutputHelper output) + { + _reporter = new TestReporter(output); + _tempDir = new TemporaryDirectory(); + } + + [Fact] + public async Task FindsCustomWatchItems() + { + _tempDir + .WithCSharpProject("Project1", out var target) + .WithTargetFrameworks("netcoreapp1.0") + .WithItem(new ItemSpec { Name = "Watch", Include = "*.js", Exclude = "gulpfile.js" }) + .Dir() + .WithFile("Program.cs") + .WithFile("app.js") + .WithFile("gulpfile.js"); + + var fileset = await GetFileSet(target); + + AssertEx.EqualFileList( + _tempDir.Root, + new[] + { + "Project1.csproj", + "Program.cs", + "app.js" + }, + fileset + ); + } + + [Fact] + public async Task ExcludesDefaultItemsWithWatchFalseMetadata() + { + _tempDir + .WithCSharpProject("Project1", out var target) + .WithTargetFrameworks("net40") + .WithItem(new ItemSpec { Name = "EmbeddedResource", Update = "*.resx", Watch = false }) + .Dir() + .WithFile("Program.cs") + .WithFile("Strings.resx"); + + var fileset = await GetFileSet(target); + + AssertEx.EqualFileList( + _tempDir.Root, + new[] + { + "Project1.csproj", + "Program.cs", + }, + fileset + ); + } + + [Fact] + public async Task SingleTfm() + { + _tempDir + .SubDir("src") + .SubDir("Project1") + .WithCSharpProject("Project1", out var target) + .WithProperty("BaseIntermediateOutputPath", "obj") + .WithTargetFrameworks("netcoreapp1.0") + .Dir() + .WithFile("Program.cs") + .WithFile("Class1.cs") + .SubDir("obj").WithFile("ignored.cs").Up() + .SubDir("Properties").WithFile("Strings.resx").Up() + .Up() + .Up() + .Create(); + + var fileset = await GetFileSet(target); + + AssertEx.EqualFileList( + _tempDir.Root, + new[] + { + "src/Project1/Project1.csproj", + "src/Project1/Program.cs", + "src/Project1/Class1.cs", + "src/Project1/Properties/Strings.resx", + }, + fileset + ); + } + + [Fact] + public async Task MultiTfm() + { + _tempDir + .SubDir("src") + .SubDir("Project1") + .WithCSharpProject("Project1", out var target) + .WithTargetFrameworks("netcoreapp1.0", "net451") + .WithProperty("EnableDefaultCompileItems", "false") + .WithItem("Compile", "Class1.netcore.cs", "'$(TargetFramework)'=='netcoreapp1.0'") + .WithItem("Compile", "Class1.desktop.cs", "'$(TargetFramework)'=='net451'") + .Dir() + .WithFile("Class1.netcore.cs") + .WithFile("Class1.desktop.cs") + .WithFile("Class1.notincluded.cs"); + + var fileset = await GetFileSet(target); + + AssertEx.EqualFileList( + _tempDir.Root, + new[] + { + "src/Project1/Project1.csproj", + "src/Project1/Class1.netcore.cs", + "src/Project1/Class1.desktop.cs", + }, + fileset + ); + } + + [Fact] + public async Task ProjectReferences_OneLevel() + { + _tempDir + .SubDir("src") + .SubDir("Project2") + .WithCSharpProject("Project2", out var proj2) + .WithTargetFrameworks("netstandard1.1") + .Dir() + .WithFile("Class2.cs") + .Up() + .SubDir("Project1") + .WithCSharpProject("Project1", out var target) + .WithTargetFrameworks("netcoreapp1.0", "net451") + .WithProjectReference(proj2) + .Dir() + .WithFile("Class1.cs"); + + var fileset = await GetFileSet(target); + + AssertEx.EqualFileList( + _tempDir.Root, + new[] + { + "src/Project2/Project2.csproj", + "src/Project2/Class2.cs", + "src/Project1/Project1.csproj", + "src/Project1/Class1.cs", + }, + fileset + ); + } + + [Fact] + public async Task TransitiveProjectReferences_TwoLevels() + { + _tempDir + .SubDir("src") + .SubDir("Project3") + .WithCSharpProject("Project3", out var proj3) + .WithTargetFrameworks("netstandard1.0") + .Dir() + .WithFile("Class3.cs") + .Up() + .SubDir("Project2") + .WithCSharpProject("Project2", out TemporaryCSharpProject proj2) + .WithTargetFrameworks("netstandard1.1") + .WithProjectReference(proj3) + .Dir() + .WithFile("Class2.cs") + .Up() + .SubDir("Project1") + .WithCSharpProject("Project1", out TemporaryCSharpProject target) + .WithTargetFrameworks("netcoreapp1.0", "net451") + .WithProjectReference(proj2) + .Dir() + .WithFile("Class1.cs"); + + var fileset = await GetFileSet(target); + + AssertEx.EqualFileList( + _tempDir.Root, + new[] + { + "src/Project3/Project3.csproj", + "src/Project3/Class3.cs", + "src/Project2/Project2.csproj", + "src/Project2/Class2.cs", + "src/Project1/Project1.csproj", + "src/Project1/Class1.cs", + }, + fileset + ); + } + + [Fact] + public async Task ProjectReferences_Graph() + { + var graph = new TestProjectGraph(_tempDir); + graph.OnCreate(p => p.WithTargetFrameworks("net45")); + var matches = Regex.Matches(@" + A->B B->C C->D D->E + B->E + A->F F->G G->E + F->E + W->U + Y->Z + Y->B + Y->F", + @"(\w)->(\w)"); + + Assert.Equal(13, matches.Count); + foreach (Match m in matches) + { + var target = graph.GetOrCreate(m.Groups[2].Value); + graph.GetOrCreate(m.Groups[1].Value).WithProjectReference(target); + } + + graph.Find("A").WithProjectReference(graph.Find("W"), watch: false); + + var output = new OutputSink(); + var filesetFactory = new MsBuildFileSetFactory(_reporter, graph.GetOrCreate("A").Path, output, trace: true); + + var fileset = await GetFileSet(filesetFactory); + + _reporter.Output(string.Join( + Environment.NewLine, + output.Current.Lines.Select(l => "Sink output: " + l))); + + var includedProjects = new[] { "A", "B", "C", "D", "E", "F", "G" }; + AssertEx.EqualFileList( + _tempDir.Root, + includedProjects + .Select(p => $"{p}/{p}.csproj"), + fileset + ); + + // ensure unreachable projects exist but where not included + Assert.NotNull(graph.Find("W")); + Assert.NotNull(graph.Find("U")); + Assert.NotNull(graph.Find("Y")); + Assert.NotNull(graph.Find("Z")); + + // ensure each project is only visited once for collecting watch items + Assert.All(includedProjects, + projectName => + Assert.Single(output.Current.Lines, + line => line.Contains($"Collecting watch items from '{projectName}'")) + ); + } + + private Task GetFileSet(TemporaryCSharpProject target) + => GetFileSet(new MsBuildFileSetFactory(_reporter, target.Path, waitOnError: false, trace: false)); + + private async Task GetFileSet(MsBuildFileSetFactory filesetFactory) + { + _tempDir.Create(); + return await filesetFactory + .CreateAsync(CancellationToken.None) + .TimeoutAfter(TimeSpan.FromSeconds(30)); + } + + public void Dispose() + { + _tempDir.Dispose(); + } + } +} diff --git a/src/Tools/dotnet-watch/test/NoDepsAppTests.cs b/src/Tools/dotnet-watch/test/NoDepsAppTests.cs new file mode 100644 index 0000000000..812f4ca755 --- /dev/null +++ b/src/Tools/dotnet-watch/test/NoDepsAppTests.cs @@ -0,0 +1,76 @@ +// 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.Threading.Tasks; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests +{ + public class NoDepsAppTests : IDisposable + { + private static readonly TimeSpan DefaultTimeout = TimeSpan.FromSeconds(30); + + private readonly WatchableApp _app; + private readonly ITestOutputHelper _output; + + public NoDepsAppTests(ITestOutputHelper logger) + { + _app = new WatchableApp("NoDepsApp", logger); + _output = logger; + } + + [Fact] + public async Task RestartProcessOnFileChange() + { + await _app.StartWatcherAsync(new[] { "--no-exit" }); + var processIdentifier = await _app.GetProcessIdentifier(); + + // Then wait for it to restart when we change a file + var fileToChange = Path.Combine(_app.SourceDirectory, "Program.cs"); + var programCs = File.ReadAllText(fileToChange); + File.WriteAllText(fileToChange, programCs); + + await _app.HasRestarted(); + Assert.DoesNotContain(_app.Process.Output, l => l.StartsWith("Exited with error code")); + + var processIdentifier2 = await _app.GetProcessIdentifier(); + Assert.NotEqual(processIdentifier, processIdentifier2); + } + + [Fact] + public async Task RestartProcessThatTerminatesAfterFileChange() + { + await _app.StartWatcherAsync(); + var processIdentifier = await _app.GetProcessIdentifier(); + await _app.HasExited(); // process should exit after run + await _app.IsWaitingForFileChange(); + + var fileToChange = Path.Combine(_app.SourceDirectory, "Program.cs"); + + try + { + File.SetLastWriteTime(fileToChange, DateTime.Now); + await _app.HasRestarted(); + } + catch + { + // retry + File.SetLastWriteTime(fileToChange, DateTime.Now); + await _app.HasRestarted(); + } + + var processIdentifier2 = await _app.GetProcessIdentifier(); + Assert.NotEqual(processIdentifier, processIdentifier2); + await _app.HasExited(); // process should exit after run + } + + public void Dispose() + { + _app.Dispose(); + } + } +} diff --git a/src/Tools/dotnet-watch/test/ProgramTests.cs b/src/Tools/dotnet-watch/test/ProgramTests.cs new file mode 100644 index 0000000000..922139a73f --- /dev/null +++ b/src/Tools/dotnet-watch/test/ProgramTests.cs @@ -0,0 +1,57 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.IO; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Testing; +using Microsoft.Extensions.Tools.Internal; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.DotNet.Watcher.Tools.Tests +{ + public class ProgramTests : IDisposable + { + private readonly TemporaryDirectory _tempDir; + private readonly TestConsole _console; + + public ProgramTests(ITestOutputHelper output) + { + _tempDir = new TemporaryDirectory(); + _console = new TestConsole(output); + } + + [Fact] + public async Task ConsoleCancelKey() + { + _tempDir + .WithCSharpProject("testproj") + .WithTargetFrameworks("netcoreapp3.0") + .Dir() + .WithFile("Program.cs") + .Create(); + + var output = new StringBuilder(); + _console.Error = _console.Out = new StringWriter(output); + using (var app = new Program(_console, _tempDir.Root)) + { + var run = app.RunAsync(new[] { "run" }); + + await _console.CancelKeyPressSubscribed.TimeoutAfter(TimeSpan.FromSeconds(30)); + _console.ConsoleCancelKey(); + + var exitCode = await run.TimeoutAfter(TimeSpan.FromSeconds(30)); + + Assert.Contains("Shutdown requested. Press Ctrl+C again to force exit.", output.ToString()); + Assert.Equal(0, exitCode); + } + } + + public void Dispose() + { + _tempDir.Dispose(); + } + } +} diff --git a/src/Tools/dotnet-watch/test/Scenario/ProjectToolScenario.cs b/src/Tools/dotnet-watch/test/Scenario/ProjectToolScenario.cs new file mode 100644 index 0000000000..b5c064563b --- /dev/null +++ b/src/Tools/dotnet-watch/test/Scenario/ProjectToolScenario.cs @@ -0,0 +1,184 @@ +// 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.Linq; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +using System.Xml.Linq; +using Microsoft.Extensions.CommandLineUtils; +using Microsoft.Extensions.Internal; +using Xunit.Abstractions; + +namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests +{ + public class ProjectToolScenario : IDisposable + { + private static readonly string TestProjectSourceRoot = Path.Combine(AppContext.BaseDirectory, "TestProjects"); + private readonly ITestOutputHelper _logger; + + public ProjectToolScenario() + : this(null) + { + } + + public ProjectToolScenario(ITestOutputHelper logger) + { + WorkFolder = Path.Combine(AppContext.BaseDirectory, "tmp", Path.GetRandomFileName()); + DotNetWatchPath = Path.Combine(AppContext.BaseDirectory, "tool", "dotnet-watch.dll"); + + _logger = logger; + _logger?.WriteLine($"The temporary test folder is {WorkFolder}"); + + CreateTestDirectory(); + } + + public string WorkFolder { get; } + + public string DotNetWatchPath { get; } + + public void AddTestProjectFolder(string projectName) + { + var srcFolder = Path.Combine(TestProjectSourceRoot, projectName); + var destinationFolder = Path.Combine(WorkFolder, Path.GetFileName(projectName)); + _logger?.WriteLine($"Copying project {srcFolder} to {destinationFolder}"); + + Directory.CreateDirectory(destinationFolder); + + foreach (var directory in Directory.GetDirectories(srcFolder, "*", SearchOption.AllDirectories)) + { + Directory.CreateDirectory(directory.Replace(srcFolder, destinationFolder)); + } + + foreach (var file in Directory.GetFiles(srcFolder, "*", SearchOption.AllDirectories)) + { + File.Copy(file, file.Replace(srcFolder, destinationFolder), true); + } + } + + public Task RestoreAsync(string project) + { + _logger?.WriteLine($"Restoring msbuild project in {project}"); + return ExecuteCommandAsync(project, TimeSpan.FromSeconds(120), "restore"); + } + + public Task BuildAsync(string project) + { + _logger?.WriteLine($"Building {project}"); + return ExecuteCommandAsync(project, TimeSpan.FromSeconds(60), "build"); + } + + private async Task ExecuteCommandAsync(string project, TimeSpan timeout, params string[] arguments) + { + var tcs = new TaskCompletionSource(); + project = Path.Combine(WorkFolder, project); + _logger?.WriteLine($"Project directory: '{project}'"); + + var process = new Process + { + EnableRaisingEvents = true, + StartInfo = new ProcessStartInfo + { + FileName = DotNetMuxer.MuxerPathOrDefault(), + Arguments = ArgumentEscaper.EscapeAndConcatenate(arguments), + WorkingDirectory = project, + RedirectStandardOutput = true, + RedirectStandardError = true, + Environment = + { + ["DOTNET_SKIP_FIRST_TIME_EXPERIENCE"] = "true" + } + }, + }; + + void OnData(object sender, DataReceivedEventArgs args) + => _logger?.WriteLine(args.Data ?? string.Empty); + + void OnExit(object sender, EventArgs args) + { + _logger?.WriteLine($"Process exited {process.Id}"); + tcs.TrySetResult(null); + } + + process.ErrorDataReceived += OnData; + process.OutputDataReceived += OnData; + process.Exited += OnExit; + + process.Start(); + + process.BeginErrorReadLine(); + process.BeginOutputReadLine(); + + _logger?.WriteLine($"Started process {process.Id}: {process.StartInfo.FileName} {process.StartInfo.Arguments}"); + + var done = await Task.WhenAny(tcs.Task, Task.Delay(timeout)); + process.CancelErrorRead(); + process.CancelOutputRead(); + + process.ErrorDataReceived -= OnData; + process.OutputDataReceived -= OnData; + process.Exited -= OnExit; + + if (!ReferenceEquals(done, tcs.Task)) + { + if (!process.HasExited) + { + _logger?.WriteLine($"Killing process {process.Id}"); + process.KillTree(); + } + + throw new TimeoutException($"Process timed out after {timeout.TotalSeconds} seconds"); + } + + _logger?.WriteLine($"Process exited {process.Id} with code {process.ExitCode}"); + if (process.ExitCode != 0) + { + + throw new InvalidOperationException($"Exit code {process.ExitCode}"); + } + } + + private void CreateTestDirectory() + { + Directory.CreateDirectory(WorkFolder); + + File.WriteAllText(Path.Combine(WorkFolder, "Directory.Build.props"), ""); + + var restoreSources = GetMetadata("TestSettings:RestoreSources"); + var frameworkVersion = GetMetadata("TestSettings:RuntimeFrameworkVersion"); + + var dbTargets = new XDocument( + new XElement("Project", + new XElement("PropertyGroup", + new XElement("RuntimeFrameworkVersion", frameworkVersion), + new XElement("RestoreSources", restoreSources)))); + dbTargets.Save(Path.Combine(WorkFolder, "Directory.Build.targets")); + } + + private string GetMetadata(string key) + { + return typeof(ProjectToolScenario) + .Assembly + .GetCustomAttributes() + .First(a => string.Equals(a.Key, key, StringComparison.Ordinal)) + .Value; + } + + public void Dispose() + { + try + { + Directory.Delete(WorkFolder, recursive: true); + } + catch + { + Console.WriteLine($"Failed to delete {WorkFolder}. Retrying..."); + Thread.Sleep(TimeSpan.FromSeconds(5)); + Directory.Delete(WorkFolder, recursive: true); + } + } + } +} diff --git a/src/Tools/dotnet-watch/test/Scenario/WatchableApp.cs b/src/Tools/dotnet-watch/test/Scenario/WatchableApp.cs new file mode 100644 index 0000000000..c6983a314c --- /dev/null +++ b/src/Tools/dotnet-watch/test/Scenario/WatchableApp.cs @@ -0,0 +1,129 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using Microsoft.Extensions.CommandLineUtils; +using Xunit.Abstractions; + +namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests +{ + public class WatchableApp : IDisposable + { + private static readonly TimeSpan DefaultMessageTimeOut = TimeSpan.FromSeconds(30); + + private const string StartedMessage = "Started"; + private const string ExitingMessage = "Exiting"; + private const string WatchExitedMessage = "watch : Exited"; + private const string WaitingForFileChangeMessage = "watch : Waiting for a file to change"; + + private readonly ITestOutputHelper _logger; + private string _appName; + private bool _prepared; + + + public WatchableApp(string appName, ITestOutputHelper logger) + { + _logger = logger; + _appName = appName; + Scenario = new ProjectToolScenario(logger); + Scenario.AddTestProjectFolder(appName); + SourceDirectory = Path.Combine(Scenario.WorkFolder, appName); + } + + public ProjectToolScenario Scenario { get; } + + public AwaitableProcess Process { get; protected set; } + + public string SourceDirectory { get; } + + public Task HasRestarted() + => Process.GetOutputLineAsync(StartedMessage, DefaultMessageTimeOut); + + public async Task HasExited() + { + await Process.GetOutputLineAsync(ExitingMessage, DefaultMessageTimeOut); + await Process.GetOutputLineStartsWithAsync(WatchExitedMessage, DefaultMessageTimeOut); + } + + public async Task IsWaitingForFileChange() + { + await Process.GetOutputLineStartsWithAsync(WaitingForFileChangeMessage, DefaultMessageTimeOut); + } + + public bool UsePollingWatcher { get; set; } + + public async Task GetProcessIdentifier() + { + // Process ID is insufficient because PID's may be reused. Process identifier also includes other info to distinguish + // between different process instances. + var line = await Process.GetOutputLineStartsWithAsync("Process identifier =", DefaultMessageTimeOut); + return line.Split('=').Last(); + } + + public async Task PrepareAsync() + { + await Scenario.RestoreAsync(_appName); + await Scenario.BuildAsync(_appName); + _prepared = true; + } + + public void Start(IEnumerable arguments, [CallerMemberName] string name = null) + { + if (!_prepared) + { + throw new InvalidOperationException($"Call {nameof(PrepareAsync)} first"); + } + + var args = new List + { + Scenario.DotNetWatchPath, + }; + args.AddRange(arguments); + + var spec = new ProcessSpec + { + Executable = DotNetMuxer.MuxerPathOrDefault(), + Arguments = args, + WorkingDirectory = SourceDirectory, + EnvironmentVariables = + { + ["DOTNET_CLI_CONTEXT_VERBOSE"] = bool.TrueString, + ["DOTNET_USE_POLLING_FILE_WATCHER"] = UsePollingWatcher.ToString(), + }, + }; + + Process = new AwaitableProcess(spec, _logger); + Process.Start(); + } + + public Task StartWatcherAsync([CallerMemberName] string name = null) + => StartWatcherAsync(Array.Empty(), name); + + public async Task StartWatcherAsync(string[] arguments, [CallerMemberName] string name = null) + { + if (!_prepared) + { + await PrepareAsync(); + } + + var args = new[] { "run", "--" }.Concat(arguments); + Start(args, name); + + // Make this timeout long because it depends much on the MSBuild compilation speed. + // Slow machines may take a bit to compile and boot test apps + await Process.GetOutputLineAsync(StartedMessage, TimeSpan.FromMinutes(2)); + } + + public virtual void Dispose() + { + _logger?.WriteLine("Disposing WatchableApp"); + Process?.Dispose(); + Scenario?.Dispose(); + } + } +} diff --git a/src/Tools/dotnet-watch/test/TestProjects/AppWithDeps/AppWithDeps.csproj b/src/Tools/dotnet-watch/test/TestProjects/AppWithDeps/AppWithDeps.csproj new file mode 100644 index 0000000000..656db6ffb9 --- /dev/null +++ b/src/Tools/dotnet-watch/test/TestProjects/AppWithDeps/AppWithDeps.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.0 + exe + true + + + + + + + diff --git a/src/Tools/dotnet-watch/test/TestProjects/AppWithDeps/Program.cs b/src/Tools/dotnet-watch/test/TestProjects/AppWithDeps/Program.cs new file mode 100644 index 0000000000..a96a0bf341 --- /dev/null +++ b/src/Tools/dotnet-watch/test/TestProjects/AppWithDeps/Program.cs @@ -0,0 +1,22 @@ +// 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.Threading; + +namespace ConsoleApplication +{ + public class Program + { + private static readonly int processId = Process.GetCurrentProcess().Id; + + public static void Main(string[] args) + { + Console.WriteLine("Started"); + // Process ID is insufficient because PID's may be reused. + Console.WriteLine($"Process identifier = {Process.GetCurrentProcess().Id}, {Process.GetCurrentProcess().StartTime:hh:mm:ss.FF}"); + Thread.Sleep(Timeout.Infinite); + } + } +} diff --git a/src/Tools/dotnet-watch/test/TestProjects/Dependency/Dependency.csproj b/src/Tools/dotnet-watch/test/TestProjects/Dependency/Dependency.csproj new file mode 100644 index 0000000000..0dbf97b944 --- /dev/null +++ b/src/Tools/dotnet-watch/test/TestProjects/Dependency/Dependency.csproj @@ -0,0 +1,8 @@ + + + + netstandard2.0 + true + + + diff --git a/src/Tools/dotnet-watch/test/TestProjects/Dependency/Foo.cs b/src/Tools/dotnet-watch/test/TestProjects/Dependency/Foo.cs new file mode 100644 index 0000000000..3441304e2f --- /dev/null +++ b/src/Tools/dotnet-watch/test/TestProjects/Dependency/Foo.cs @@ -0,0 +1,9 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Dependency +{ + public class Foo + { + } +} diff --git a/src/Tools/dotnet-watch/test/TestProjects/GlobbingApp/GlobbingApp.csproj b/src/Tools/dotnet-watch/test/TestProjects/GlobbingApp/GlobbingApp.csproj new file mode 100644 index 0000000000..163d37f881 --- /dev/null +++ b/src/Tools/dotnet-watch/test/TestProjects/GlobbingApp/GlobbingApp.csproj @@ -0,0 +1,14 @@ + + + + netcoreapp3.0 + exe + false + true + + + + + + + diff --git a/src/Tools/dotnet-watch/test/TestProjects/GlobbingApp/Program.cs b/src/Tools/dotnet-watch/test/TestProjects/GlobbingApp/Program.cs new file mode 100644 index 0000000000..07c6d0a527 --- /dev/null +++ b/src/Tools/dotnet-watch/test/TestProjects/GlobbingApp/Program.cs @@ -0,0 +1,23 @@ +// 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.Linq; +using System.Reflection; +using System.Threading; + +namespace ConsoleApplication +{ + public class Program + { + public static void Main(string[] args) + { + Console.WriteLine("Started"); + // Process ID is insufficient because PID's may be reused. + Console.WriteLine($"Process identifier = {Process.GetCurrentProcess().Id}, {Process.GetCurrentProcess().StartTime:hh:mm:ss.FF}"); + Console.WriteLine("Defined types = " + typeof(Program).GetTypeInfo().Assembly.DefinedTypes.Count()); + Thread.Sleep(Timeout.Infinite); + } + } +} diff --git a/src/Tools/dotnet-watch/test/TestProjects/GlobbingApp/exclude/Baz.cs b/src/Tools/dotnet-watch/test/TestProjects/GlobbingApp/exclude/Baz.cs new file mode 100644 index 0000000000..fdaebd7201 --- /dev/null +++ b/src/Tools/dotnet-watch/test/TestProjects/GlobbingApp/exclude/Baz.cs @@ -0,0 +1,10 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace GlobbingApp.exclude +{ + public class Baz + { + "THIS FILE SHOULD NOT BE INCLUDED IN COMPILATION" + } +} diff --git a/src/Tools/dotnet-watch/test/TestProjects/GlobbingApp/include/Foo.cs b/src/Tools/dotnet-watch/test/TestProjects/GlobbingApp/include/Foo.cs new file mode 100644 index 0000000000..d1afb658fc --- /dev/null +++ b/src/Tools/dotnet-watch/test/TestProjects/GlobbingApp/include/Foo.cs @@ -0,0 +1,9 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace GlobbingApp.include +{ + public class Foo + { + } +} diff --git a/src/Tools/dotnet-watch/test/TestProjects/KitchenSink/KitchenSink.csproj b/src/Tools/dotnet-watch/test/TestProjects/KitchenSink/KitchenSink.csproj new file mode 100644 index 0000000000..c28f16d91e --- /dev/null +++ b/src/Tools/dotnet-watch/test/TestProjects/KitchenSink/KitchenSink.csproj @@ -0,0 +1,18 @@ + + + + .net/obj + .net/bin + + + + + + Exe + netcoreapp3.0 + true + + + + + diff --git a/src/Tools/dotnet-watch/test/TestProjects/KitchenSink/Program.cs b/src/Tools/dotnet-watch/test/TestProjects/KitchenSink/Program.cs new file mode 100644 index 0000000000..ab2edae7a7 --- /dev/null +++ b/src/Tools/dotnet-watch/test/TestProjects/KitchenSink/Program.cs @@ -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; +using System.Diagnostics; + +namespace KitchenSink +{ + class Program + { + static void Main(string[] args) + { + Console.WriteLine("Started"); + // Process ID is insufficient because PID's may be reused. + Console.WriteLine($"Process identifier = {Process.GetCurrentProcess().Id}, {Process.GetCurrentProcess().StartTime:hh:mm:ss.FF}"); + Console.WriteLine("DOTNET_WATCH = " + Environment.GetEnvironmentVariable("DOTNET_WATCH")); + Console.WriteLine("DOTNET_WATCH_ITERATION = " + Environment.GetEnvironmentVariable("DOTNET_WATCH_ITERATION")); + } + } +} diff --git a/src/Tools/dotnet-watch/test/TestProjects/NoDepsApp/NoDepsApp.csproj b/src/Tools/dotnet-watch/test/TestProjects/NoDepsApp/NoDepsApp.csproj new file mode 100644 index 0000000000..9743820f9b --- /dev/null +++ b/src/Tools/dotnet-watch/test/TestProjects/NoDepsApp/NoDepsApp.csproj @@ -0,0 +1,9 @@ + + + + netcoreapp3.0 + exe + true + + + diff --git a/src/Tools/dotnet-watch/test/TestProjects/NoDepsApp/Program.cs b/src/Tools/dotnet-watch/test/TestProjects/NoDepsApp/Program.cs new file mode 100644 index 0000000000..f3da51ab08 --- /dev/null +++ b/src/Tools/dotnet-watch/test/TestProjects/NoDepsApp/Program.cs @@ -0,0 +1,24 @@ +// 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.Threading; + +namespace ConsoleApplication +{ + public class Program + { + public static void Main(string[] args) + { + Console.WriteLine("Started"); + // Process ID is insufficient because PID's may be reused. + Console.WriteLine($"Process identifier = {Process.GetCurrentProcess().Id}, {Process.GetCurrentProcess().StartTime:hh:mm:ss.FF}"); + if (args.Length > 0 && args[0] == "--no-exit") + { + Thread.Sleep(Timeout.Infinite); + } + Console.WriteLine("Exiting"); + } + } +} diff --git a/src/Tools/dotnet-watch/test/Utilities/TemporaryCSharpProject.cs b/src/Tools/dotnet-watch/test/Utilities/TemporaryCSharpProject.cs new file mode 100644 index 0000000000..7156cf85cf --- /dev/null +++ b/src/Tools/dotnet-watch/test/Utilities/TemporaryCSharpProject.cs @@ -0,0 +1,118 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; + +namespace Microsoft.DotNet.Watcher.Tools.Tests +{ + public class TemporaryCSharpProject + { + private const string Template = + @" + + {0} + Exe + + + {1} + +"; + + private readonly string _filename; + private readonly TemporaryDirectory _directory; + private List _items = new List(); + private List _properties = new List(); + + public TemporaryCSharpProject(string name, TemporaryDirectory directory) + { + Name = name; + _filename = name + ".csproj"; + _directory = directory; + } + + public string Name { get; } + public string Path => System.IO.Path.Combine(_directory.Root, _filename); + + public TemporaryCSharpProject WithTargetFrameworks(params string[] tfms) + { + Debug.Assert(tfms.Length > 0); + var propertySpec = new PropertySpec + { + Value = string.Join(";", tfms) + }; + propertySpec.Name = tfms.Length == 1 + ? "TargetFramework" + : "TargetFrameworks"; + + return WithProperty(propertySpec); + } + + public TemporaryCSharpProject WithProperty(string name, string value) + => WithProperty(new PropertySpec { Name = name, Value = value }); + + public TemporaryCSharpProject WithProperty(PropertySpec property) + { + var sb = new StringBuilder(); + sb.Append('<').Append(property.Name).Append('>') + .Append(property.Value) + .Append("'); + _properties.Add(sb.ToString()); + return this; + } + + public TemporaryCSharpProject WithItem(string itemName, string include, string condition = null) + => WithItem(new ItemSpec { Name = itemName, Include = include, Condition = condition }); + + public TemporaryCSharpProject WithItem(ItemSpec item) + { + var sb = new StringBuilder("<"); + sb.Append(item.Name).Append(" "); + if (item.Include != null) sb.Append(" Include=\"").Append(item.Include).Append('"'); + if (item.Remove != null) sb.Append(" Remove=\"").Append(item.Remove).Append('"'); + if (item.Update != null) sb.Append(" Update=\"").Append(item.Update).Append('"'); + if (item.Exclude != null) sb.Append(" Exclude=\"").Append(item.Exclude).Append('"'); + if (item.Condition != null) sb.Append(" Exclude=\"").Append(item.Condition).Append('"'); + if (!item.Watch) sb.Append(" Watch=\"false\" "); + sb.Append(" />"); + _items.Add(sb.ToString()); + return this; + } + + public TemporaryCSharpProject WithProjectReference(TemporaryCSharpProject reference, bool watch = true) + { + if (ReferenceEquals(this, reference)) + { + throw new InvalidOperationException("Can add project reference to self"); + } + + return WithItem(new ItemSpec { Name = "ProjectReference", Include = reference.Path, Watch = watch }); + } + + public TemporaryDirectory Dir() => _directory; + + public void Create() + { + _directory.CreateFile(_filename, string.Format(Template, string.Join("\r\n", _properties), string.Join("\r\n", _items))); + } + + public class ItemSpec + { + public string Name { get; set; } + public string Include { get; set; } + public string Exclude { get; set; } + public string Update { get; set; } + public string Remove { get; set; } + public bool Watch { get; set; } = true; + public string Condition { get; set; } + } + + public class PropertySpec + { + public string Name { get; set; } + public string Value { get; set; } + } + } +} diff --git a/src/Tools/dotnet-watch/test/Utilities/TemporaryDirectory.cs b/src/Tools/dotnet-watch/test/Utilities/TemporaryDirectory.cs new file mode 100644 index 0000000000..692899817e --- /dev/null +++ b/src/Tools/dotnet-watch/test/Utilities/TemporaryDirectory.cs @@ -0,0 +1,107 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.IO; + +namespace Microsoft.DotNet.Watcher.Tools.Tests +{ + public class TemporaryDirectory : IDisposable + { + private List _projects = new List(); + private List _subdirs = new List(); + private Dictionary _files = new Dictionary(); + private TemporaryDirectory _parent; + + public TemporaryDirectory() + { + Root = Path.Combine(Path.GetTempPath(), "dotnet-watch-tests", Guid.NewGuid().ToString("N")); + } + + private TemporaryDirectory(string path, TemporaryDirectory parent) + { + _parent = parent; + Root = path; + } + + public TemporaryDirectory SubDir(string name) + { + var subdir = new TemporaryDirectory(Path.Combine(Root, name), this); + _subdirs.Add(subdir); + return subdir; + } + + public string Root { get; } + + public TemporaryCSharpProject WithCSharpProject(string name) + { + var project = new TemporaryCSharpProject(name, this); + _projects.Add(project); + return project; + } + + public TemporaryCSharpProject WithCSharpProject(string name, out TemporaryCSharpProject project) + { + project = WithCSharpProject(name); + return project; + } + + public TemporaryDirectory WithFile(string name, string contents = "") + { + _files[name] = contents; + return this; + } + + public TemporaryDirectory Up() + { + if (_parent == null) + { + throw new InvalidOperationException("This is the root directory"); + } + return _parent; + } + + public void Create() + { + Directory.CreateDirectory(Root); + + foreach (var dir in _subdirs) + { + dir.Create(); + } + + foreach (var project in _projects) + { + project.Create(); + } + + foreach (var file in _files) + { + CreateFile(file.Key, file.Value); + } + } + + public void CreateFile(string filename, string contents) + { + File.WriteAllText(Path.Combine(Root, filename), contents); + } + + public void Dispose() + { + if (Root == null || !Directory.Exists(Root) || _parent != null) + { + return; + } + + try + { + Directory.Delete(Root, recursive: true); + } + catch + { + Console.Error.WriteLine($"Test cleanup failed to delete '{Root}'"); + } + } + } +} diff --git a/src/Tools/dotnet-watch/test/Utilities/TestProjectGraph.cs b/src/Tools/dotnet-watch/test/Utilities/TestProjectGraph.cs new file mode 100644 index 0000000000..a8e615d3c9 --- /dev/null +++ b/src/Tools/dotnet-watch/test/Utilities/TestProjectGraph.cs @@ -0,0 +1,41 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; + +namespace Microsoft.DotNet.Watcher.Tools.Tests +{ + public class TestProjectGraph + { + private readonly TemporaryDirectory _directory; + private Action _onCreate; + private Dictionary _projects = new Dictionary(); + public TestProjectGraph(TemporaryDirectory directory) + { + _directory = directory; + } + + public void OnCreate(Action onCreate) + { + _onCreate = onCreate; + } + + public TemporaryCSharpProject Find(string projectName) + => _projects.ContainsKey(projectName) + ? _projects[projectName] + : null; + + public TemporaryCSharpProject GetOrCreate(string projectName) + { + TemporaryCSharpProject sourceProj; + if (!_projects.TryGetValue(projectName, out sourceProj)) + { + sourceProj = _directory.SubDir(projectName).WithCSharpProject(projectName); + _onCreate?.Invoke(sourceProj); + _projects.Add(projectName, sourceProj); + } + return sourceProj; + } + } +} \ No newline at end of file diff --git a/src/Tools/dotnet-watch/test/dotnet-watch.Tests.csproj b/src/Tools/dotnet-watch/test/dotnet-watch.Tests.csproj new file mode 100644 index 0000000000..6deaae84ef --- /dev/null +++ b/src/Tools/dotnet-watch/test/dotnet-watch.Tests.csproj @@ -0,0 +1,39 @@ + + + + netcoreapp3.0 + Microsoft.DotNet.Watcher.Tools.Tests + $(DefaultItemExcludes);TestProjects\**\* + + + + + + + + + + + + + + <_Parameter1>TestSettings:RestoreSources + <_Parameter2>$(RestoreSources) + + + <_Parameter1>TestSettings:RuntimeFrameworkVersion + <_Parameter2>$(RuntimeFrameworkVersion) + + + + + + + + + + + + diff --git a/src/Tools/shared/src/CliContext.cs b/src/Tools/shared/src/CliContext.cs new file mode 100644 index 0000000000..854ea0fef6 --- /dev/null +++ b/src/Tools/shared/src/CliContext.cs @@ -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.Tools.Internal +{ + public static class CliContext + { + /// + /// dotnet -d|--diagnostics subcommand + /// + /// + public static bool IsGlobalVerbose() + { + bool.TryParse(Environment.GetEnvironmentVariable("DOTNET_CLI_CONTEXT_VERBOSE"), out bool globalVerbose); + return globalVerbose; + } + } +} diff --git a/src/Tools/shared/src/CommandLineApplicationExtensions.cs b/src/Tools/shared/src/CommandLineApplicationExtensions.cs new file mode 100644 index 0000000000..6206c861c0 --- /dev/null +++ b/src/Tools/shared/src/CommandLineApplicationExtensions.cs @@ -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 System; +using System.Reflection; + +namespace Microsoft.Extensions.CommandLineUtils +{ + internal static class CommandLineApplicationExtensions + { + public static CommandOption HelpOption(this CommandLineApplication app) + => app.HelpOption("-?|-h|--help"); + + public static CommandOption VerboseOption(this CommandLineApplication app) + => app.Option("-v|--verbose", "Show verbose output", CommandOptionType.NoValue, inherited: true); + + public static void OnExecute(this CommandLineApplication app, Action action) + => app.OnExecute(() => + { + action(); + return 0; + }); + + public static void VersionOptionFromAssemblyAttributes(this CommandLineApplication app, Assembly assembly) + => app.VersionOption("--version", GetInformationalVersion(assembly)); + + private static string GetInformationalVersion(Assembly assembly) + { + var attribute = assembly.GetCustomAttribute(); + + var versionAttribute = attribute == null + ? assembly.GetName().Version.ToString() + : attribute.InformationalVersion; + + return versionAttribute; + } + } +} diff --git a/src/Tools/shared/src/ConsoleReporter.cs b/src/Tools/shared/src/ConsoleReporter.cs new file mode 100644 index 0000000000..ffcd1e8705 --- /dev/null +++ b/src/Tools/shared/src/ConsoleReporter.cs @@ -0,0 +1,72 @@ +// 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; + +namespace Microsoft.Extensions.Tools.Internal +{ + public class ConsoleReporter : IReporter + { + private object _writeLock = new object(); + + public ConsoleReporter(IConsole console) + : this(console, verbose: false, quiet: false) + { } + + public ConsoleReporter(IConsole console, bool verbose, bool quiet) + { + Ensure.NotNull(console, nameof(console)); + + Console = console; + IsVerbose = verbose; + IsQuiet = quiet; + } + + protected IConsole Console { get; } + public bool IsVerbose { get; set; } + public bool IsQuiet { get; set; } + + protected virtual void WriteLine(TextWriter writer, string message, ConsoleColor? color) + { + lock (_writeLock) + { + if (color.HasValue) + { + Console.ForegroundColor = color.Value; + } + + writer.WriteLine(message); + + if (color.HasValue) + { + Console.ResetColor(); + } + } + } + + public virtual void Error(string message) + => WriteLine(Console.Error, message, ConsoleColor.Red); + public virtual void Warn(string message) + => WriteLine(Console.Out, message, ConsoleColor.Yellow); + + public virtual void Output(string message) + { + if (IsQuiet) + { + return; + } + WriteLine(Console.Out, message, color: null); + } + + public virtual void Verbose(string message) + { + if (!IsVerbose) + { + return; + } + + WriteLine(Console.Out, message, ConsoleColor.DarkGray); + } + } +} diff --git a/src/Tools/shared/src/DebugHelper.cs b/src/Tools/shared/src/DebugHelper.cs new file mode 100644 index 0000000000..bb7f966d65 --- /dev/null +++ b/src/Tools/shared/src/DebugHelper.cs @@ -0,0 +1,24 @@ +// 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.Linq; + +namespace Microsoft.Extensions.Tools.Internal +{ + public static class DebugHelper + { + [Conditional("DEBUG")] + public static void HandleDebugSwitch(ref string[] args) + { + if (args.Length > 0 && string.Equals("--debug", args[0], StringComparison.OrdinalIgnoreCase)) + { + args = args.Skip(1).ToArray(); + Console.WriteLine("Waiting for debugger to attach. Press ENTER to continue"); + Console.WriteLine($"Process ID: {Process.GetCurrentProcess().Id}"); + Console.ReadLine(); + } + } + } +} \ No newline at end of file diff --git a/src/Tools/shared/src/Ensure.cs b/src/Tools/shared/src/Ensure.cs new file mode 100644 index 0000000000..5cb8ff7ec7 --- /dev/null +++ b/src/Tools/shared/src/Ensure.cs @@ -0,0 +1,29 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; + +namespace Microsoft.Extensions.Tools.Internal +{ + internal static class Ensure + { + public static T NotNull(T obj, string paramName) + where T : class + { + if (obj == null) + { + throw new ArgumentNullException(paramName); + } + return obj; + } + + public static string NotNullOrEmpty(string obj, string paramName) + { + if (string.IsNullOrEmpty(obj)) + { + throw new ArgumentException("Value cannot be null or an empty string.", paramName); + } + return obj; + } + } +} diff --git a/src/Tools/shared/src/IConsole.cs b/src/Tools/shared/src/IConsole.cs new file mode 100644 index 0000000000..7216c267a0 --- /dev/null +++ b/src/Tools/shared/src/IConsole.cs @@ -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.IO; + +namespace Microsoft.Extensions.Tools.Internal +{ + public interface IConsole + { + event ConsoleCancelEventHandler CancelKeyPress; + TextWriter Out { get; } + TextWriter Error { get; } + TextReader In { get; } + bool IsInputRedirected { get; } + bool IsOutputRedirected { get; } + bool IsErrorRedirected { get; } + ConsoleColor ForegroundColor { get; set; } + void ResetColor(); + } +} diff --git a/src/Tools/shared/src/IReporter.cs b/src/Tools/shared/src/IReporter.cs new file mode 100644 index 0000000000..890dec3f7e --- /dev/null +++ b/src/Tools/shared/src/IReporter.cs @@ -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.Extensions.Tools.Internal +{ + public interface IReporter + { + void Verbose(string message); + void Output(string message); + void Warn(string message); + void Error(string message); + } +} \ No newline at end of file diff --git a/src/Tools/shared/src/NullReporter.cs b/src/Tools/shared/src/NullReporter.cs new file mode 100644 index 0000000000..5d80aeac91 --- /dev/null +++ b/src/Tools/shared/src/NullReporter.cs @@ -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. + +namespace Microsoft.Extensions.Tools.Internal +{ + public class NullReporter : IReporter + { + private NullReporter() + { } + + public static IReporter Singleton { get; } = new NullReporter(); + + public void Verbose(string message) + { } + + public void Output(string message) + { } + + public void Warn(string message) + { } + + public void Error(string message) + { } + } +} diff --git a/src/Tools/shared/src/PhysicalConsole.cs b/src/Tools/shared/src/PhysicalConsole.cs new file mode 100644 index 0000000000..9a93323d5c --- /dev/null +++ b/src/Tools/shared/src/PhysicalConsole.cs @@ -0,0 +1,36 @@ +// 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; + +namespace Microsoft.Extensions.Tools.Internal +{ + public class PhysicalConsole : IConsole + { + private PhysicalConsole() + { + Console.CancelKeyPress += (o, e) => + { + CancelKeyPress?.Invoke(o, e); + }; + } + + public static IConsole Singleton { get; } = new PhysicalConsole(); + + public event ConsoleCancelEventHandler CancelKeyPress; + public TextWriter Error => Console.Error; + public TextReader In => Console.In; + public TextWriter Out => Console.Out; + public bool IsInputRedirected => Console.IsInputRedirected; + public bool IsOutputRedirected => Console.IsOutputRedirected; + public bool IsErrorRedirected => Console.IsErrorRedirected; + public ConsoleColor ForegroundColor + { + get => Console.ForegroundColor; + set => Console.ForegroundColor = value; + } + + public void ResetColor() => Console.ResetColor(); + } +} diff --git a/src/Tools/shared/test/TestConsole.cs b/src/Tools/shared/test/TestConsole.cs new file mode 100644 index 0000000000..b8198238f3 --- /dev/null +++ b/src/Tools/shared/test/TestConsole.cs @@ -0,0 +1,90 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; +using System.Text; +using Xunit.Abstractions; + +namespace Microsoft.Extensions.Tools.Internal +{ + public class TestConsole : IConsole + { + private event ConsoleCancelEventHandler _cancelKeyPress; + private readonly TaskCompletionSource _cancelKeySubscribed = new TaskCompletionSource(); + + public TestConsole(ITestOutputHelper output) + { + var writer = new TestOutputWriter(output); + Error = writer; + Out = writer; + } + + public event ConsoleCancelEventHandler CancelKeyPress + { + add + { + _cancelKeyPress += value; + _cancelKeySubscribed.TrySetResult(true); + } + remove => _cancelKeyPress -= value; + } + + public Task CancelKeyPressSubscribed => _cancelKeySubscribed.Task; + + public TextWriter Error { get; set; } + public TextWriter Out { get; set; } + public TextReader In { get; set; } = new StringReader(string.Empty); + public bool IsInputRedirected { get; set; } = false; + public bool IsOutputRedirected { get; } = false; + public bool IsErrorRedirected { get; } = false; + public ConsoleColor ForegroundColor { get; set; } + + public ConsoleCancelEventArgs ConsoleCancelKey() + { + var ctor = typeof(ConsoleCancelEventArgs) + .GetTypeInfo() + .DeclaredConstructors + .Single(c => c.GetParameters().First().ParameterType == typeof(ConsoleSpecialKey)); + var args = (ConsoleCancelEventArgs)ctor.Invoke(new object[] { ConsoleSpecialKey.ControlC }); + _cancelKeyPress.Invoke(this, args); + return args; + } + + public void ResetColor() + { + } + + private class TestOutputWriter : TextWriter + { + private readonly ITestOutputHelper _output; + private readonly StringBuilder _sb = new StringBuilder(); + + public TestOutputWriter(ITestOutputHelper output) + { + _output = output; + } + + public override Encoding Encoding => Encoding.Unicode; + + public override void Write(char value) + { + if (value == '\r' || value == '\n') + { + if (_sb.Length > 0) + { + _output.WriteLine(_sb.ToString()); + _sb.Clear(); + } + } + else + { + _sb.Append(value); + } + } + } + } +} diff --git a/src/Tools/shared/test/TestReporter.cs b/src/Tools/shared/test/TestReporter.cs new file mode 100644 index 0000000000..e1ed0f5352 --- /dev/null +++ b/src/Tools/shared/test/TestReporter.cs @@ -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 Xunit.Abstractions; + +namespace Microsoft.Extensions.Tools.Internal +{ + public class TestReporter : IReporter + { + private readonly ITestOutputHelper _output; + + public TestReporter(ITestOutputHelper output) + { + _output = output; + } + + public void Verbose(string message) + { + _output.WriteLine("verbose: " + message); + } + + public void Output(string message) + { + _output.WriteLine("output: " + message); + } + + public void Warn(string message) + { + _output.WriteLine("warn: " + message); + } + + public void Error(string message) + { + _output.WriteLine("error: " + message); + } + } +} \ No newline at end of file diff --git a/src/WebSockets/.gitignore b/src/WebSockets/.gitignore deleted file mode 100644 index 0e10f4aa54..0000000000 --- a/src/WebSockets/.gitignore +++ /dev/null @@ -1,31 +0,0 @@ -[Oo]bj/ -[Bb]in/ -TestResults/ -.nuget/ -_ReSharper.*/ -packages/ -artifacts/ -PublishProfiles/ -*.user -*.suo -*.cache -*.docstates -_ReSharper.* -nuget.exe -*net45.csproj -*k10.csproj -*.psess -*.vsp -*.pidb -*.userprefs -*DS_Store -*.ncrunchsolution -*.*sdf -*.ipch -*.sln.ide -/.vs/ -.testPublish/ -.build/ -autobahnreports/ -.vscode/ -global.json diff --git a/src/WebSockets/Directory.Build.props b/src/WebSockets/Directory.Build.props deleted file mode 100644 index 97bc856e11..0000000000 --- a/src/WebSockets/Directory.Build.props +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/WebSockets/NuGetPackageVerifier.json b/src/WebSockets/NuGetPackageVerifier.json deleted file mode 100644 index b153ab1515..0000000000 --- a/src/WebSockets/NuGetPackageVerifier.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "Default": { - "rules": [ - "DefaultCompositeRule" - ] - } -} \ No newline at end of file diff --git a/src/WebSockets/README.md b/src/WebSockets/README.md deleted file mode 100644 index c7c69ee89b..0000000000 --- a/src/WebSockets/README.md +++ /dev/null @@ -1,19 +0,0 @@ -WebSockets -================ - -AppVeyor: [![AppVeyor](https://ci.appveyor.com/api/projects/status/lk5hyg6gki03hdqe/branch/dev?svg=true)](https://ci.appveyor.com/project/aspnetci/WebSockets/branch/dev) - -Travis: [![Travis](https://travis-ci.org/aspnet/WebSockets.svg?branch=dev)](https://travis-ci.org/aspnet/WebSockets) - -Contains a managed implementation of the WebSocket protocol, along with server integration components. - -This project is part of ASP.NET Core. You can find samples, documentation and getting started instructions for ASP.NET Core at the [Home](https://github.com/aspnet/home) repo. - - -## System Requirements - -This repo has a few special system requirements/prerequisites. - -1. Windows IIS Express tests require IIS Express 10 and Windows 8 for WebSockets support -2. HttpListener/ASP.NET 4.6 samples require at least Windows 8 -3. Autobahn Test Suite requires special installation see the README.md in test/AutobahnTestApp diff --git a/src/WebSockets/WebSockets.sln b/src/WebSockets/WebSockets.sln deleted file mode 100644 index 6977d2812e..0000000000 --- a/src/WebSockets/WebSockets.sln +++ /dev/null @@ -1,145 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26730.10 -MinimumVisualStudioVersion = 15.0.26730.03 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{2C7947A5-9FBD-4267-97C1-2D726D7B3BAF}" - ProjectSection(SolutionItems) = preProject - src\Directory.Build.props = src\Directory.Build.props - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{C45106D0-76C8-4776-A140-F7DD83CA2958}" - ProjectSection(SolutionItems) = preProject - test\Directory.Build.props = test\Directory.Build.props - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{9E55FC5B-FD9C-4266-AB24-F3AA649D7C8B}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestServer", "samples\TestServer\TestServer.csproj", "{4E5F5FCC-172C-44D9-BEA0-39098A79CD0B}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "scripts", "scripts", "{19595D64-E42E-46FD-AB2E-BDC870724EE7}" - ProjectSection(SolutionItems) = preProject - scripts\UpdateCoreFxCode.ps1 = scripts\UpdateCoreFxCode.ps1 - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.WebSockets", "src\Microsoft.AspNetCore.WebSockets\Microsoft.AspNetCore.WebSockets.csproj", "{CDE16880-0374-46FA-8896-99F1B90B4B6F}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.WebSockets.Test", "test\Microsoft.AspNetCore.WebSockets.Test\Microsoft.AspNetCore.WebSockets.Test.csproj", "{5AFA74F5-9B1D-4FC5-815F-EF471F5AC1EF}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.WebSockets.ConformanceTest", "test\Microsoft.AspNetCore.WebSockets.ConformanceTest\Microsoft.AspNetCore.WebSockets.ConformanceTest.csproj", "{74F45408-1959-4FEE-9511-25D40F4913FD}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EchoApp", "samples\EchoApp\EchoApp.csproj", "{421954B0-5C6B-4092-8D4D-EACA4CE60AFB}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AutobahnTestApp", "test\AutobahnTestApp\AutobahnTestApp.csproj", "{150DF5A8-87C6-42F7-8886-CE07BFD02FD2}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{92CE12E6-E127-433B-96D3-164C0113EA17}" - ProjectSection(SolutionItems) = preProject - build\dependencies.props = build\dependencies.props - build\Key.snk = build\Key.snk - build\repo.props = build\repo.props - build\repo.targets = build\repo.targets - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7A963B09-471B-4D67-B5C0-6039AF0C39EE}" - ProjectSection(SolutionItems) = preProject - Directory.Build.props = Directory.Build.props - Directory.Build.targets = Directory.Build.targets - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {4E5F5FCC-172C-44D9-BEA0-39098A79CD0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4E5F5FCC-172C-44D9-BEA0-39098A79CD0B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4E5F5FCC-172C-44D9-BEA0-39098A79CD0B}.Debug|x64.ActiveCfg = Debug|Any CPU - {4E5F5FCC-172C-44D9-BEA0-39098A79CD0B}.Debug|x64.Build.0 = Debug|Any CPU - {4E5F5FCC-172C-44D9-BEA0-39098A79CD0B}.Debug|x86.ActiveCfg = Debug|Any CPU - {4E5F5FCC-172C-44D9-BEA0-39098A79CD0B}.Debug|x86.Build.0 = Debug|Any CPU - {4E5F5FCC-172C-44D9-BEA0-39098A79CD0B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4E5F5FCC-172C-44D9-BEA0-39098A79CD0B}.Release|Any CPU.Build.0 = Release|Any CPU - {4E5F5FCC-172C-44D9-BEA0-39098A79CD0B}.Release|x64.ActiveCfg = Release|Any CPU - {4E5F5FCC-172C-44D9-BEA0-39098A79CD0B}.Release|x64.Build.0 = Release|Any CPU - {4E5F5FCC-172C-44D9-BEA0-39098A79CD0B}.Release|x86.ActiveCfg = Release|Any CPU - {4E5F5FCC-172C-44D9-BEA0-39098A79CD0B}.Release|x86.Build.0 = Release|Any CPU - {CDE16880-0374-46FA-8896-99F1B90B4B6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CDE16880-0374-46FA-8896-99F1B90B4B6F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CDE16880-0374-46FA-8896-99F1B90B4B6F}.Debug|x64.ActiveCfg = Debug|Any CPU - {CDE16880-0374-46FA-8896-99F1B90B4B6F}.Debug|x64.Build.0 = Debug|Any CPU - {CDE16880-0374-46FA-8896-99F1B90B4B6F}.Debug|x86.ActiveCfg = Debug|Any CPU - {CDE16880-0374-46FA-8896-99F1B90B4B6F}.Debug|x86.Build.0 = Debug|Any CPU - {CDE16880-0374-46FA-8896-99F1B90B4B6F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CDE16880-0374-46FA-8896-99F1B90B4B6F}.Release|Any CPU.Build.0 = Release|Any CPU - {CDE16880-0374-46FA-8896-99F1B90B4B6F}.Release|x64.ActiveCfg = Release|Any CPU - {CDE16880-0374-46FA-8896-99F1B90B4B6F}.Release|x64.Build.0 = Release|Any CPU - {CDE16880-0374-46FA-8896-99F1B90B4B6F}.Release|x86.ActiveCfg = Release|Any CPU - {CDE16880-0374-46FA-8896-99F1B90B4B6F}.Release|x86.Build.0 = Release|Any CPU - {5AFA74F5-9B1D-4FC5-815F-EF471F5AC1EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5AFA74F5-9B1D-4FC5-815F-EF471F5AC1EF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5AFA74F5-9B1D-4FC5-815F-EF471F5AC1EF}.Debug|x64.ActiveCfg = Debug|Any CPU - {5AFA74F5-9B1D-4FC5-815F-EF471F5AC1EF}.Debug|x64.Build.0 = Debug|Any CPU - {5AFA74F5-9B1D-4FC5-815F-EF471F5AC1EF}.Debug|x86.ActiveCfg = Debug|Any CPU - {5AFA74F5-9B1D-4FC5-815F-EF471F5AC1EF}.Debug|x86.Build.0 = Debug|Any CPU - {5AFA74F5-9B1D-4FC5-815F-EF471F5AC1EF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5AFA74F5-9B1D-4FC5-815F-EF471F5AC1EF}.Release|Any CPU.Build.0 = Release|Any CPU - {5AFA74F5-9B1D-4FC5-815F-EF471F5AC1EF}.Release|x64.ActiveCfg = Release|Any CPU - {5AFA74F5-9B1D-4FC5-815F-EF471F5AC1EF}.Release|x64.Build.0 = Release|Any CPU - {5AFA74F5-9B1D-4FC5-815F-EF471F5AC1EF}.Release|x86.ActiveCfg = Release|Any CPU - {5AFA74F5-9B1D-4FC5-815F-EF471F5AC1EF}.Release|x86.Build.0 = Release|Any CPU - {74F45408-1959-4FEE-9511-25D40F4913FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {74F45408-1959-4FEE-9511-25D40F4913FD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {74F45408-1959-4FEE-9511-25D40F4913FD}.Debug|x64.ActiveCfg = Debug|Any CPU - {74F45408-1959-4FEE-9511-25D40F4913FD}.Debug|x64.Build.0 = Debug|Any CPU - {74F45408-1959-4FEE-9511-25D40F4913FD}.Debug|x86.ActiveCfg = Debug|Any CPU - {74F45408-1959-4FEE-9511-25D40F4913FD}.Debug|x86.Build.0 = Debug|Any CPU - {74F45408-1959-4FEE-9511-25D40F4913FD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {74F45408-1959-4FEE-9511-25D40F4913FD}.Release|Any CPU.Build.0 = Release|Any CPU - {74F45408-1959-4FEE-9511-25D40F4913FD}.Release|x64.ActiveCfg = Release|Any CPU - {74F45408-1959-4FEE-9511-25D40F4913FD}.Release|x64.Build.0 = Release|Any CPU - {74F45408-1959-4FEE-9511-25D40F4913FD}.Release|x86.ActiveCfg = Release|Any CPU - {74F45408-1959-4FEE-9511-25D40F4913FD}.Release|x86.Build.0 = Release|Any CPU - {421954B0-5C6B-4092-8D4D-EACA4CE60AFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {421954B0-5C6B-4092-8D4D-EACA4CE60AFB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {421954B0-5C6B-4092-8D4D-EACA4CE60AFB}.Debug|x64.ActiveCfg = Debug|Any CPU - {421954B0-5C6B-4092-8D4D-EACA4CE60AFB}.Debug|x64.Build.0 = Debug|Any CPU - {421954B0-5C6B-4092-8D4D-EACA4CE60AFB}.Debug|x86.ActiveCfg = Debug|Any CPU - {421954B0-5C6B-4092-8D4D-EACA4CE60AFB}.Debug|x86.Build.0 = Debug|Any CPU - {421954B0-5C6B-4092-8D4D-EACA4CE60AFB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {421954B0-5C6B-4092-8D4D-EACA4CE60AFB}.Release|Any CPU.Build.0 = Release|Any CPU - {421954B0-5C6B-4092-8D4D-EACA4CE60AFB}.Release|x64.ActiveCfg = Release|Any CPU - {421954B0-5C6B-4092-8D4D-EACA4CE60AFB}.Release|x64.Build.0 = Release|Any CPU - {421954B0-5C6B-4092-8D4D-EACA4CE60AFB}.Release|x86.ActiveCfg = Release|Any CPU - {421954B0-5C6B-4092-8D4D-EACA4CE60AFB}.Release|x86.Build.0 = Release|Any CPU - {150DF5A8-87C6-42F7-8886-CE07BFD02FD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {150DF5A8-87C6-42F7-8886-CE07BFD02FD2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {150DF5A8-87C6-42F7-8886-CE07BFD02FD2}.Debug|x64.ActiveCfg = Debug|Any CPU - {150DF5A8-87C6-42F7-8886-CE07BFD02FD2}.Debug|x64.Build.0 = Debug|Any CPU - {150DF5A8-87C6-42F7-8886-CE07BFD02FD2}.Debug|x86.ActiveCfg = Debug|Any CPU - {150DF5A8-87C6-42F7-8886-CE07BFD02FD2}.Debug|x86.Build.0 = Debug|Any CPU - {150DF5A8-87C6-42F7-8886-CE07BFD02FD2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {150DF5A8-87C6-42F7-8886-CE07BFD02FD2}.Release|Any CPU.Build.0 = Release|Any CPU - {150DF5A8-87C6-42F7-8886-CE07BFD02FD2}.Release|x64.ActiveCfg = Release|Any CPU - {150DF5A8-87C6-42F7-8886-CE07BFD02FD2}.Release|x64.Build.0 = Release|Any CPU - {150DF5A8-87C6-42F7-8886-CE07BFD02FD2}.Release|x86.ActiveCfg = Release|Any CPU - {150DF5A8-87C6-42F7-8886-CE07BFD02FD2}.Release|x86.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {4E5F5FCC-172C-44D9-BEA0-39098A79CD0B} = {9E55FC5B-FD9C-4266-AB24-F3AA649D7C8B} - {CDE16880-0374-46FA-8896-99F1B90B4B6F} = {2C7947A5-9FBD-4267-97C1-2D726D7B3BAF} - {5AFA74F5-9B1D-4FC5-815F-EF471F5AC1EF} = {C45106D0-76C8-4776-A140-F7DD83CA2958} - {74F45408-1959-4FEE-9511-25D40F4913FD} = {C45106D0-76C8-4776-A140-F7DD83CA2958} - {421954B0-5C6B-4092-8D4D-EACA4CE60AFB} = {9E55FC5B-FD9C-4266-AB24-F3AA649D7C8B} - {150DF5A8-87C6-42F7-8886-CE07BFD02FD2} = {C45106D0-76C8-4776-A140-F7DD83CA2958} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {D3542868-F8C6-401B-8071-37FE3C981604} - EndGlobalSection -EndGlobal diff --git a/src/WebSockets/build.cmd b/src/WebSockets/build.cmd deleted file mode 100644 index f4169ea5e4..0000000000 --- a/src/WebSockets/build.cmd +++ /dev/null @@ -1,3 +0,0 @@ -@ECHO OFF -SET RepoRoot="%~dp0..\.." -%RepoRoot%\build.cmd -LockFile %RepoRoot%\korebuild-lock.txt -Path %~dp0 %* diff --git a/src/WebSockets/build.sh b/src/WebSockets/build.sh deleted file mode 100755 index d5bb0cf631..0000000000 --- a/src/WebSockets/build.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -repo_root="$DIR/../.." -"$repo_root/build.sh" --path "$DIR" --lockfile "$repo_root/korebuild-lock.txt" "$@" diff --git a/src/WebSockets/build/Key.snk b/src/WebSockets/build/Key.snk deleted file mode 100644 index e10e4889c1..0000000000 Binary files a/src/WebSockets/build/Key.snk and /dev/null differ diff --git a/src/WebSockets/build/repo.props b/src/WebSockets/build/repo.props deleted file mode 100644 index ad95e1570f..0000000000 --- a/src/WebSockets/build/repo.props +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - true - - - - - - diff --git a/src/WebSockets/build/repo.targets b/src/WebSockets/build/repo.targets deleted file mode 100644 index 1767331014..0000000000 --- a/src/WebSockets/build/repo.targets +++ /dev/null @@ -1,9 +0,0 @@ - - - $(ArtifactsDir)autobahnreports\ - - - - - - diff --git a/src/WebSockets/samples/EchoApp/EchoApp.csproj b/src/WebSockets/samples/EchoApp/EchoApp.csproj deleted file mode 100644 index fc19ef1f0c..0000000000 --- a/src/WebSockets/samples/EchoApp/EchoApp.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - netcoreapp2.2;net461 - - - - - - - - - - - - - - - diff --git a/src/WebSockets/src/Directory.Build.props b/src/WebSockets/src/Directory.Build.props deleted file mode 100644 index 1e0980f663..0000000000 --- a/src/WebSockets/src/Directory.Build.props +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/src/WebSockets/src/Microsoft.AspNetCore.WebSockets/Microsoft.AspNetCore.WebSockets.csproj b/src/WebSockets/src/Microsoft.AspNetCore.WebSockets/Microsoft.AspNetCore.WebSockets.csproj deleted file mode 100644 index 277c0cc9fe..0000000000 --- a/src/WebSockets/src/Microsoft.AspNetCore.WebSockets/Microsoft.AspNetCore.WebSockets.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - ASP.NET Core web socket middleware for use on top of opaque servers. - netstandard2.0 - $(NoWarn);CS1591 - true - true - aspnetcore - - - - - - - - - - diff --git a/src/WebSockets/test/Directory.Build.props b/src/WebSockets/test/Directory.Build.props deleted file mode 100644 index a84a332640..0000000000 --- a/src/WebSockets/test/Directory.Build.props +++ /dev/null @@ -1,22 +0,0 @@ - - - - - netcoreapp2.2 - $(DeveloperBuildTestTfms) - - $(StandardTestTfms);net461 - - - - - true - - - - - - diff --git a/src/WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest/Microsoft.AspNetCore.WebSockets.ConformanceTest.csproj b/src/WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest/Microsoft.AspNetCore.WebSockets.ConformanceTest.csproj deleted file mode 100644 index 539a46f002..0000000000 --- a/src/WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest/Microsoft.AspNetCore.WebSockets.ConformanceTest.csproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - netcoreapp2.2 - - - - - - - - - - - - - diff --git a/src/WebSockets/test/Microsoft.AspNetCore.WebSockets.Test/Microsoft.AspNetCore.WebSockets.Test.csproj b/src/WebSockets/test/Microsoft.AspNetCore.WebSockets.Test/Microsoft.AspNetCore.WebSockets.Test.csproj deleted file mode 100644 index 5e7f2eb67e..0000000000 --- a/src/WebSockets/test/Microsoft.AspNetCore.WebSockets.Test/Microsoft.AspNetCore.WebSockets.Test.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - $(StandardTestTfms) - - - - - - - - - - - - - - - - diff --git a/src/WebSockets/version.props b/src/WebSockets/version.props deleted file mode 100644 index bcf920cf80..0000000000 --- a/src/WebSockets/version.props +++ /dev/null @@ -1,12 +0,0 @@ - - - 3.0.0 - alpha1 - $(VersionPrefix) - $(VersionPrefix)-$(VersionSuffix)-final - t000 - a- - $(FeatureBranchVersionPrefix)$(VersionSuffix)-$([System.Text.RegularExpressions.Regex]::Replace('$(FeatureBranchVersionSuffix)', '[^\w-]', '-')) - $(VersionSuffix)-$(BuildNumber) - - diff --git a/version.props b/version.props index 9d6ed6c20d..c3848a6cbd 100644 --- a/version.props +++ b/version.props @@ -11,6 +11,8 @@ $(PreReleaseLabel)-$(BuildNumber) $(PreReleaseBrandingLabel) Build $(BuildNumber) + + true false true @@ -34,6 +36,9 @@ $(VersionSuffix)+$(VersionMetadata) master + + + $(AspNetCoreMajorVersion).$(AspNetCoreMinorVersion).$([MSBuild]::Subtract($(AspNetCorePatchVersion), 1))