From 408759ec991674051d3a09560aff09ce1ad42a29 Mon Sep 17 00:00:00 2001 From: Eilon Lipton Date: Thu, 17 Sep 2015 09:36:36 -0700 Subject: [PATCH 001/471] Update LICENSE.txt --- LICENSE.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 LICENSE.txt diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000000..0bdc1962b6 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,12 @@ +Copyright (c) .NET Foundation. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +these files except in compliance with the License. You may obtain a copy of the +License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed +under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. From b63d1b618710ab5e6064e013c62dc1d51aa5c877 Mon Sep 17 00:00:00 2001 From: Eilon Lipton Date: Thu, 17 Sep 2015 09:36:53 -0700 Subject: [PATCH 002/471] Create CONTRIBUTING.md --- CONTRIBUTING.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000..64ff041d5c --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,4 @@ +Contributing +====== + +Information on contributing to this repo is in the [Contributing Guide](https://github.com/aspnet/Home/blob/dev/CONTRIBUTING.md) in the Home repo. From 98ce82ed72a2c8a02717c615082e3d9a4decef3e Mon Sep 17 00:00:00 2001 From: Eilon Lipton Date: Thu, 17 Sep 2015 09:41:13 -0700 Subject: [PATCH 003/471] Create README.md --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000000..c30d38e62f --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +JsonPatch +=== +AppVeyor: [![AppVeyor](https://ci.appveyor.com/api/projects/status/51gggjks5k3q6pr5/branch/dev?svg=true)](https://ci.appveyor.com/project/aspnetci/JsonPatch/branch/dev) + +Travis: [![Travis](https://travis-ci.org/aspnet/JsonPatch.svg?branch=dev)](https://travis-ci.org/aspnet/JsonPatch) + +This project is part of ASP.NET 5. You can find samples, documentation and getting started instructions for ASP.NET 5 at the [Home](https://github.com/aspnet/home) repo. + + From d3f2b240d752e7eb90f0510d7e0d60e6f51cf625 Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Mon, 21 Sep 2015 10:42:05 -0700 Subject: [PATCH 004/471] Add build-template files --- .gitignore | 36 ++++++++++++++++++++++++++++++++++++ .travis.yml | 13 +++++++++++++ NuGet.config | 7 +++++++ appveyor.yml | 7 +++++++ build.cmd | 39 +++++++++++++++++++++++++++++++++++++++ build.sh | 41 +++++++++++++++++++++++++++++++++++++++++ global.json | 3 +++ makefile.shade | 12 ++++++++++++ 8 files changed, 158 insertions(+) create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 NuGet.config create mode 100644 appveyor.yml create mode 100644 build.cmd create mode 100644 build.sh create mode 100644 global.json create mode 100644 makefile.shade diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..8a9bbc3a43 --- /dev/null +++ b/.gitignore @@ -0,0 +1,36 @@ +[Oo]bj/ +[Bb]in/ +TestResults/ +.nuget/ +*.sln.ide/ +_ReSharper.*/ +packages/ +artifacts/ +PublishProfiles/ +.vs/ +bower_components/ +node_modules/ +**/wwwroot/lib/ +debugSettings.json +project.lock.json +*.user +*.suo +*.cache +*.docstates +_ReSharper.* +nuget.exe +*net45.csproj +*net451.csproj +*k10.csproj +*.psess +*.vsp +*.pidb +*.userprefs +*DS_Store +*.ncrunchsolution +*.*sdf +*.ipch +.settings +*.sln.ide +node_modules +**/[Cc]ompiler/[Rr]esources/**/*.js diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000000..568e2673e9 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,13 @@ +language: csharp +sudo: false +mono: + - beta +env: + - MONO_THREADS_PER_CPU=2000 MONO_MANAGED_WATCHER=disabled +os: + - linux + - osx +before_script: + - if [ $TRAVIS_OS_NAME == "osx" ] ; then sudo sysctl -w kern.maxfiles=64000 ; sudo sysctl -w kern.maxfilesperproc=64000 ; sudo launchctl limit maxfiles 64000 64000 ; fi ; ulimit -n 64000 +script: + - ./build.sh --quiet verify \ No newline at end of file diff --git a/NuGet.config b/NuGet.config new file mode 100644 index 0000000000..52bf414192 --- /dev/null +++ b/NuGet.config @@ -0,0 +1,7 @@ + + + + + + + diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000000..58a3e1bc22 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,7 @@ +init: + - git config --global core.autocrlf true +build_script: + - build.cmd --quiet --parallel verify +clone_depth: 1 +test: off +deploy: off \ No newline at end of file diff --git a/build.cmd b/build.cmd new file mode 100644 index 0000000000..177997c42e --- /dev/null +++ b/build.cmd @@ -0,0 +1,39 @@ +@echo off +cd %~dp0 + +SETLOCAL +SET NUGET_VERSION=latest +SET CACHED_NUGET=%LocalAppData%\NuGet\nuget.%NUGET_VERSION%.exe +SET BUILDCMD_KOREBUILD_VERSION="" +SET BUILDCMD_DNX_VERSION="" + +IF EXIST %CACHED_NUGET% goto copynuget +echo Downloading latest version of NuGet.exe... +IF NOT EXIST %LocalAppData%\NuGet md %LocalAppData%\NuGet +@powershell -NoProfile -ExecutionPolicy unrestricted -Command "$ProgressPreference = 'SilentlyContinue'; Invoke-WebRequest 'https://dist.nuget.org/win-x86-commandline/%NUGET_VERSION%/nuget.exe' -OutFile '%CACHED_NUGET%'" + +:copynuget +IF EXIST .nuget\nuget.exe goto restore +md .nuget +copy %CACHED_NUGET% .nuget\nuget.exe > nul + +:restore +IF EXIST packages\KoreBuild goto run +IF %BUILDCMD_KOREBUILD_VERSION%=="" ( + .nuget\nuget.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre +) ELSE ( + .nuget\nuget.exe install KoreBuild -version %BUILDCMD_KOREBUILD_VERSION% -ExcludeVersion -o packages -nocache -pre +) +.nuget\nuget.exe install Sake -ExcludeVersion -Out packages + +IF "%SKIP_DNX_INSTALL%"=="1" goto run +IF %BUILDCMD_DNX_VERSION%=="" ( + CALL packages\KoreBuild\build\dnvm upgrade -runtime CLR -arch x86 +) ELSE ( + CALL packages\KoreBuild\build\dnvm install %BUILDCMD_DNX_VERSION% -runtime CLR -arch x86 -a default +) +CALL packages\KoreBuild\build\dnvm install default -runtime CoreCLR -arch x86 + +:run +CALL packages\KoreBuild\build\dnvm use default -runtime CLR -arch x86 +packages\Sake\tools\Sake.exe -I packages\KoreBuild\build -f makefile.shade %* \ No newline at end of file diff --git a/build.sh b/build.sh new file mode 100644 index 0000000000..0c66139817 --- /dev/null +++ b/build.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash + +if test `uname` = Darwin; then + cachedir=~/Library/Caches/KBuild +else + if [ -z $XDG_DATA_HOME ]; then + cachedir=$HOME/.local/share + else + cachedir=$XDG_DATA_HOME; + fi +fi +mkdir -p $cachedir +nugetVersion=latest +cachePath=$cachedir/nuget.$nugetVersion.exe + +url=https://dist.nuget.org/win-x86-commandline/$nugetVersion/nuget.exe + +if test ! -f $cachePath; then + wget -O $cachePath $url 2>/dev/null || curl -o $cachePath --location $url /dev/null +fi + +if test ! -e .nuget; then + mkdir .nuget + cp $cachePath .nuget/nuget.exe +fi + +if test ! -d packages/KoreBuild; then + mono .nuget/nuget.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre + mono .nuget/nuget.exe install Sake -ExcludeVersion -Out packages +fi + +if ! type dnvm > /dev/null 2>&1; then + source packages/KoreBuild/build/dnvm.sh +fi + +if ! type dnx > /dev/null 2>&1; then + dnvm upgrade +fi + +mono packages/Sake/tools/Sake.exe -I packages/KoreBuild/build -f makefile.shade "$@" + diff --git a/global.json b/global.json new file mode 100644 index 0000000000..fad3dfeab0 --- /dev/null +++ b/global.json @@ -0,0 +1,3 @@ +{ + "projects": ["src", "test/WebSites", "samples"] +} diff --git a/makefile.shade b/makefile.shade new file mode 100644 index 0000000000..c87524a3ef --- /dev/null +++ b/makefile.shade @@ -0,0 +1,12 @@ + +var VERSION='0.1' +var FULL_VERSION='0.1' +var AUTHORS='Microsoft Open Technologies, Inc.' + +use-standard-lifecycle +k-standard-goals + +#xml-docs-test .clean .build-compile description='Check generated XML documentation files for errors' target='package' + k-xml-docs-test + + From e0ac69c9f79d8486357531f0ea5125bbef3c42fa Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Mon, 21 Sep 2015 11:15:18 -0700 Subject: [PATCH 005/471] Add JsonPatch Moved from https://github.com/aspnet/Mvc --- JsonPatch.sln | 36 + NuGet.config | 2 +- .../Adapters/IObjectAdapter.cs | 19 + .../Adapters/ObjectAdapter.cs | 1105 +++++++++ .../Converters/JsonPatchDocumentConverter.cs | 76 + .../TypedJsonPatchDocumentConverter.cs | 65 + .../Exceptions/JsonPatchException.cs | 38 + .../Helpers/ActualPropertyPathResult.cs | 22 + .../Helpers/ConversionResult.cs | 17 + .../ExpandoObjectDictionaryExtensions.cs | 77 + .../Helpers/ExpressionHelpers.cs | 99 + .../Helpers/GetValueResult.cs | 30 + .../Helpers/JsonPatchProperty.cs | 43 + .../Helpers/ObjectTreeAnalyisResult.cs | 210 ++ .../Helpers/PathHelpers.cs | 31 + .../Helpers/RemovedPropertyTypeResult.cs | 38 + .../IJsonPatchDocument.cs | 16 + .../JsonPatchDocument.cs | 222 ++ .../JsonPatchDocumentOfT.cs | 700 ++++++ .../JsonPatchError.cs | 50 + .../Microsoft.AspNet.JsonPatch.xproj | 17 + .../Operations/Operation.cs | 74 + .../Operations/OperationBase.cs | 57 + .../Operations/OperationOfT.cs | 83 + .../Operations/OperationType.cs | 15 + .../Properties/AssemblyInfo.cs | 8 + .../Properties/Resources.Designer.cs | 270 +++ src/Microsoft.AspNet.JsonPatch/Resources.resx | 165 ++ src/Microsoft.AspNet.JsonPatch/project.json | 25 + .../Dynamic/AddOperationTests.cs | 569 +++++ .../Dynamic/AddTypedOperationTests.cs | 121 + .../Dynamic/CopyOperationTests.cs | 245 ++ .../Dynamic/CopyTypedOperationTests.cs | 268 +++ .../Dynamic/MoveOperationTests.cs | 338 +++ .../Dynamic/MoveTypedOperationTests.cs | 138 ++ .../Dynamic/NestedDTO.cs | 11 + .../Dynamic/PatchDocumentTests.cs | 95 + .../Dynamic/RemoveOperationTests.cs | 302 +++ .../Dynamic/RemoveTypedOperationTests.cs | 244 ++ .../Dynamic/ReplaceOperationTests.cs | 242 ++ .../Dynamic/ReplaceTypedOperationTests.cs | 191 ++ .../Dynamic/SimpleDTO.cs | 21 + .../Dynamic/SimpleDTOWithNestedDTO.cs | 22 + .../Microsoft.AspNet.JsonPatch.Test.xproj | 20 + .../NestedDTO.cs | 10 + .../NestedObjectTests.cs | 2041 +++++++++++++++++ .../ObjectAdapterTests.cs | 1737 ++++++++++++++ .../SimpleDTO.cs | 22 + .../SimpleDTOWithNestedDTO.cs | 27 + .../TestErrorLogger.cs | 15 + .../project.json | 18 + 51 files changed, 10306 insertions(+), 1 deletion(-) create mode 100644 JsonPatch.sln create mode 100644 src/Microsoft.AspNet.JsonPatch/Adapters/IObjectAdapter.cs create mode 100644 src/Microsoft.AspNet.JsonPatch/Adapters/ObjectAdapter.cs create mode 100644 src/Microsoft.AspNet.JsonPatch/Converters/JsonPatchDocumentConverter.cs create mode 100644 src/Microsoft.AspNet.JsonPatch/Converters/TypedJsonPatchDocumentConverter.cs create mode 100644 src/Microsoft.AspNet.JsonPatch/Exceptions/JsonPatchException.cs create mode 100644 src/Microsoft.AspNet.JsonPatch/Helpers/ActualPropertyPathResult.cs create mode 100644 src/Microsoft.AspNet.JsonPatch/Helpers/ConversionResult.cs create mode 100644 src/Microsoft.AspNet.JsonPatch/Helpers/ExpandoObjectDictionaryExtensions.cs create mode 100644 src/Microsoft.AspNet.JsonPatch/Helpers/ExpressionHelpers.cs create mode 100644 src/Microsoft.AspNet.JsonPatch/Helpers/GetValueResult.cs create mode 100644 src/Microsoft.AspNet.JsonPatch/Helpers/JsonPatchProperty.cs create mode 100644 src/Microsoft.AspNet.JsonPatch/Helpers/ObjectTreeAnalyisResult.cs create mode 100644 src/Microsoft.AspNet.JsonPatch/Helpers/PathHelpers.cs create mode 100644 src/Microsoft.AspNet.JsonPatch/Helpers/RemovedPropertyTypeResult.cs create mode 100644 src/Microsoft.AspNet.JsonPatch/IJsonPatchDocument.cs create mode 100644 src/Microsoft.AspNet.JsonPatch/JsonPatchDocument.cs create mode 100644 src/Microsoft.AspNet.JsonPatch/JsonPatchDocumentOfT.cs create mode 100644 src/Microsoft.AspNet.JsonPatch/JsonPatchError.cs create mode 100644 src/Microsoft.AspNet.JsonPatch/Microsoft.AspNet.JsonPatch.xproj create mode 100644 src/Microsoft.AspNet.JsonPatch/Operations/Operation.cs create mode 100644 src/Microsoft.AspNet.JsonPatch/Operations/OperationBase.cs create mode 100644 src/Microsoft.AspNet.JsonPatch/Operations/OperationOfT.cs create mode 100644 src/Microsoft.AspNet.JsonPatch/Operations/OperationType.cs create mode 100644 src/Microsoft.AspNet.JsonPatch/Properties/AssemblyInfo.cs create mode 100644 src/Microsoft.AspNet.JsonPatch/Properties/Resources.Designer.cs create mode 100644 src/Microsoft.AspNet.JsonPatch/Resources.resx create mode 100644 src/Microsoft.AspNet.JsonPatch/project.json create mode 100644 test/Microsoft.AspNet.JsonPatch.Test/Dynamic/AddOperationTests.cs create mode 100644 test/Microsoft.AspNet.JsonPatch.Test/Dynamic/AddTypedOperationTests.cs create mode 100644 test/Microsoft.AspNet.JsonPatch.Test/Dynamic/CopyOperationTests.cs create mode 100644 test/Microsoft.AspNet.JsonPatch.Test/Dynamic/CopyTypedOperationTests.cs create mode 100644 test/Microsoft.AspNet.JsonPatch.Test/Dynamic/MoveOperationTests.cs create mode 100644 test/Microsoft.AspNet.JsonPatch.Test/Dynamic/MoveTypedOperationTests.cs create mode 100644 test/Microsoft.AspNet.JsonPatch.Test/Dynamic/NestedDTO.cs create mode 100644 test/Microsoft.AspNet.JsonPatch.Test/Dynamic/PatchDocumentTests.cs create mode 100644 test/Microsoft.AspNet.JsonPatch.Test/Dynamic/RemoveOperationTests.cs create mode 100644 test/Microsoft.AspNet.JsonPatch.Test/Dynamic/RemoveTypedOperationTests.cs create mode 100644 test/Microsoft.AspNet.JsonPatch.Test/Dynamic/ReplaceOperationTests.cs create mode 100644 test/Microsoft.AspNet.JsonPatch.Test/Dynamic/ReplaceTypedOperationTests.cs create mode 100644 test/Microsoft.AspNet.JsonPatch.Test/Dynamic/SimpleDTO.cs create mode 100644 test/Microsoft.AspNet.JsonPatch.Test/Dynamic/SimpleDTOWithNestedDTO.cs create mode 100644 test/Microsoft.AspNet.JsonPatch.Test/Microsoft.AspNet.JsonPatch.Test.xproj create mode 100644 test/Microsoft.AspNet.JsonPatch.Test/NestedDTO.cs create mode 100644 test/Microsoft.AspNet.JsonPatch.Test/NestedObjectTests.cs create mode 100644 test/Microsoft.AspNet.JsonPatch.Test/ObjectAdapterTests.cs create mode 100644 test/Microsoft.AspNet.JsonPatch.Test/SimpleDTO.cs create mode 100644 test/Microsoft.AspNet.JsonPatch.Test/SimpleDTOWithNestedDTO.cs create mode 100644 test/Microsoft.AspNet.JsonPatch.Test/TestErrorLogger.cs create mode 100644 test/Microsoft.AspNet.JsonPatch.Test/project.json diff --git a/JsonPatch.sln b/JsonPatch.sln new file mode 100644 index 0000000000..01e02f3125 --- /dev/null +++ b/JsonPatch.sln @@ -0,0 +1,36 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.23107.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{430B59ED-F960-4D3A-8FFE-3370008E168D}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{36CD6341-AB44-44EB-B3AA-BF98C89FECDD}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.JsonPatch", "src\Microsoft.AspNet.JsonPatch\Microsoft.AspNet.JsonPatch.xproj", "{4D55F4D8-633B-462F-A5B1-FEB84BD2D534}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.JsonPatch.Test", "test\Microsoft.AspNet.JsonPatch.Test\Microsoft.AspNet.JsonPatch.Test.xproj", "{81C20848-E063-4E12-AC40-0B55A532C16C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4D55F4D8-633B-462F-A5B1-FEB84BD2D534}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4D55F4D8-633B-462F-A5B1-FEB84BD2D534}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4D55F4D8-633B-462F-A5B1-FEB84BD2D534}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4D55F4D8-633B-462F-A5B1-FEB84BD2D534}.Release|Any CPU.Build.0 = Release|Any CPU + {81C20848-E063-4E12-AC40-0B55A532C16C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {81C20848-E063-4E12-AC40-0B55A532C16C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {81C20848-E063-4E12-AC40-0B55A532C16C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {81C20848-E063-4E12-AC40-0B55A532C16C}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {4D55F4D8-633B-462F-A5B1-FEB84BD2D534} = {430B59ED-F960-4D3A-8FFE-3370008E168D} + {81C20848-E063-4E12-AC40-0B55A532C16C} = {36CD6341-AB44-44EB-B3AA-BF98C89FECDD} + EndGlobalSection +EndGlobal diff --git a/NuGet.config b/NuGet.config index 52bf414192..5500f6d507 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,4 +1,4 @@ - + diff --git a/src/Microsoft.AspNet.JsonPatch/Adapters/IObjectAdapter.cs b/src/Microsoft.AspNet.JsonPatch/Adapters/IObjectAdapter.cs new file mode 100644 index 0000000000..724dfe3f79 --- /dev/null +++ b/src/Microsoft.AspNet.JsonPatch/Adapters/IObjectAdapter.cs @@ -0,0 +1,19 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.AspNet.JsonPatch.Operations; + +namespace Microsoft.AspNet.JsonPatch.Adapters +{ + /// + /// Defines the operations that can be performed on a JSON patch document. + /// + public interface IObjectAdapter + { + void Add(Operation operation, object objectToApplyTo); + void Copy(Operation operation, object objectToApplyTo); + void Move(Operation operation, object objectToApplyTo); + void Remove(Operation operation, object objectToApplyTo); + void Replace(Operation operation, object objectToApplyTo); + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.JsonPatch/Adapters/ObjectAdapter.cs b/src/Microsoft.AspNet.JsonPatch/Adapters/ObjectAdapter.cs new file mode 100644 index 0000000000..4640e97039 --- /dev/null +++ b/src/Microsoft.AspNet.JsonPatch/Adapters/ObjectAdapter.cs @@ -0,0 +1,1105 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using Microsoft.AspNet.JsonPatch.Exceptions; +using Microsoft.AspNet.JsonPatch.Helpers; +using Microsoft.AspNet.JsonPatch.Operations; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; + +namespace Microsoft.AspNet.JsonPatch.Adapters +{ + /// + public class ObjectAdapter : IObjectAdapter + { + /// + /// Initializes a new instance of . + /// + /// The . + /// The for logging . + public ObjectAdapter( + IContractResolver contractResolver, + Action logErrorAction) + { + if (contractResolver == null) + { + throw new ArgumentNullException(nameof(contractResolver)); + } + + ContractResolver = contractResolver; + LogErrorAction = logErrorAction; + } + + /// + /// Gets or sets the . + /// + public IContractResolver ContractResolver { get; } + + /// + /// Action for logging . + /// + public Action LogErrorAction { get; } + + /// + /// The "add" operation performs one of the following functions, + /// depending upon what the target location references: + /// + /// o If the target location specifies an array index, a new value is + /// inserted into the array at the specified index. + /// + /// o If the target location specifies an object member that does not + /// already exist, a new member is added to the object. + /// + /// o If the target location specifies an object member that 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" ] } + /// + /// When the operation is applied, the target location MUST reference one + /// of: + /// + /// o The root of the target document - whereupon the specified value + /// becomes the entire content of the target document. + /// + /// o A member to add to an existing object - whereupon the supplied + /// value is added to that object at the indicated location. If the + /// member already exists, it is replaced by the specified value. + /// + /// o An element to add to an existing array - whereupon the supplied + /// value is added to the array at the indicated location. Any + /// elements at or above the specified index are shifted one position + /// to the right. The specified index MUST NOT be greater than the + /// number of elements in the array. If the "-" character is used to + /// index the end of the array (see [RFC6901]), this has the effect of + /// appending the value to the array. + /// + /// Because this operation is designed to add to existing objects and + /// arrays, its target location will often not exist. Although the + /// pointer's error handling algorithm will thus be invoked, this + /// specification defines the error handling behavior for "add" pointers + /// to ignore that error and add the value as specified. + /// + /// However, the object itself or an array containing it does need to + /// exist, and it remains an error for that not to be the case. For + /// example, an "add" with a target location of "/a/b" starting with this + /// document: + /// + /// { "a": { "foo": 1 } } + /// + /// is not an error, because "a" exists, and "b" will be added to its + /// value. It is an error in this document: + /// + /// { "q": { "bar": 2 } } + /// + /// because "a" does not exist. + /// + /// The add operation. + /// Object to apply the operation to. + 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 operationToReport) + { + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + + if (objectToApplyTo == null) + { + throw new ArgumentNullException(nameof(objectToApplyTo)); + } + + if (operationToReport == null) + { + throw new ArgumentNullException(nameof(operationToReport)); + } + + // first up: if the path ends in a numeric value, we're inserting in a list and + // that value represents the position; if the path ends in "-", we're appending + // to the list. + + // get path result + var pathResult = GetActualPropertyPath( + path, + objectToApplyTo, + operationToReport); + if (pathResult == null) + { + return; + } + + var appendList = pathResult.ExecuteAtEnd; + var positionAsInteger = pathResult.NumericEnd; + var actualPathToProperty = pathResult.PathToProperty; + + var treeAnalysisResult = new ObjectTreeAnalysisResult( + objectToApplyTo, + actualPathToProperty, + ContractResolver); + + if (!treeAnalysisResult.IsValidPathForAdd) + { + LogError(new JsonPatchError( + objectToApplyTo, + operationToReport, + Resources.FormatPropertyCannotBeAdded(path))); + return; + } + + if (treeAnalysisResult.UseDynamicLogic) + { + var container = treeAnalysisResult.Container; + if (container.ContainsCaseInsensitiveKey(treeAnalysisResult.PropertyPathInParent)) + { + // Existing property. + // If it's not an array, we need to check if the value fits the property type + // + // If it's an array, we need to check if the value fits in that array type, + // and add it at the correct position (if allowed). + if (appendList || positionAsInteger > -1) + { + // get the actual type + var propertyValue = container.GetValueForCaseInsensitiveKey(treeAnalysisResult.PropertyPathInParent); + var typeOfPathProperty = propertyValue.GetType(); + + if (!IsNonStringArray(typeOfPathProperty)) + { + LogError(new JsonPatchError( + objectToApplyTo, + operationToReport, + Resources.FormatInvalidIndexForArrayProperty(operationToReport.op, path))); + return; + } + + // now, get the generic type of the enumerable + var genericTypeOfArray = GetIListType(typeOfPathProperty); + var conversionResult = ConvertToActualType(genericTypeOfArray, value); + if (!conversionResult.CanBeConverted) + { + LogError(new JsonPatchError( + objectToApplyTo, + operationToReport, + Resources.FormatInvalidValueForProperty(value, path))); + return; + } + + // get value (it can be cast, we just checked that) + var array = treeAnalysisResult.Container.GetValueForCaseInsensitiveKey( + treeAnalysisResult.PropertyPathInParent) as IList; + + if (appendList) + { + array.Add(conversionResult.ConvertedInstance); + treeAnalysisResult.Container.SetValueForCaseInsensitiveKey( + treeAnalysisResult.PropertyPathInParent, array); + } + else + { + // specified index must not be greater than + // the amount of items in the array + if (positionAsInteger > array.Count) + { + LogError(new JsonPatchError( + objectToApplyTo, + operationToReport, + Resources.FormatInvalidIndexForArrayProperty( + operationToReport.op, + path))); + return; + } + + array.Insert(positionAsInteger, conversionResult.ConvertedInstance); + treeAnalysisResult.Container.SetValueForCaseInsensitiveKey( + treeAnalysisResult.PropertyPathInParent, array); + } + } + else + { + // get the actual type + var typeOfPathProperty = treeAnalysisResult.Container + .GetValueForCaseInsensitiveKey(treeAnalysisResult.PropertyPathInParent).GetType(); + + // can the value be converted to the actual type? + var conversionResult = ConvertToActualType(typeOfPathProperty, value); + if (conversionResult.CanBeConverted) + { + treeAnalysisResult.Container.SetValueForCaseInsensitiveKey( + treeAnalysisResult.PropertyPathInParent, + conversionResult.ConvertedInstance); + } + else + { + LogError(new JsonPatchError( + objectToApplyTo, + operationToReport, + Resources.FormatInvalidValueForProperty(conversionResult.ConvertedInstance, path))); + return; + } + } + } + else + { + // New property - add it. + treeAnalysisResult.Container.Add(treeAnalysisResult.PropertyPathInParent, value); + } + } + else + { + // If it's an array, add to that array. If it's not, we replace. + + // is the path an array (but not a string (= char[]))? In this case, + // the path must end with "/position" or "/-", which we already determined before. + + var patchProperty = treeAnalysisResult.JsonPatchProperty; + + if (appendList || positionAsInteger > -1) + { + if (!IsNonStringArray(patchProperty.Property.PropertyType)) + { + LogError(new JsonPatchError( + objectToApplyTo, + operationToReport, + Resources.FormatInvalidIndexForArrayProperty(operationToReport.op, path))); + return; + } + + // now, get the generic type of the IList<> from Property type. + var genericTypeOfArray = GetIListType(patchProperty.Property.PropertyType); + var conversionResult = ConvertToActualType(genericTypeOfArray, value); + if (!conversionResult.CanBeConverted) + { + LogError(new JsonPatchError( + objectToApplyTo, + operationToReport, + Resources.FormatInvalidValueForProperty(conversionResult.ConvertedInstance, path))); + return; + } + + if (!patchProperty.Property.Readable) + { + LogError(new JsonPatchError( + objectToApplyTo, + operationToReport, + Resources.FormatCannotReadProperty(path))); + return; + } + + var array = (IList)patchProperty.Property.ValueProvider.GetValue(patchProperty.Parent); + if (appendList) + { + array.Add(conversionResult.ConvertedInstance); + } + else if (positionAsInteger <= array.Count) + { + array.Insert(positionAsInteger, conversionResult.ConvertedInstance); + } + else + { + LogError(new JsonPatchError( + objectToApplyTo, + operationToReport, + Resources.FormatInvalidIndexForArrayProperty(operationToReport.op, path))); + return; + } + } + else + { + var conversionResultTuple = ConvertToActualType( + patchProperty.Property.PropertyType, + value); + + if (!conversionResultTuple.CanBeConverted) + { + LogError(new JsonPatchError( + objectToApplyTo, + operationToReport, + Resources.FormatInvalidValueForProperty(value, path))); + return; + } + + if (!patchProperty.Property.Writable) + { + LogError(new JsonPatchError( + objectToApplyTo, + operationToReport, + Resources.FormatCannotUpdateProperty(path))); + return; + } + + patchProperty.Property.ValueProvider.SetValue( + patchProperty.Parent, + conversionResultTuple.ConvertedInstance); + } + } + } + + /// + /// The "move" operation removes the value at a specified location and + /// adds it to the target location. + /// + /// The operation object MUST contain a "from" member, which is a string + /// containing a JSON Pointer value that 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" } + /// + /// This operation is functionally identical to a "remove" operation on + /// the "from" location, followed immediately by an "add" operation at + /// the target location with the value that was just removed. + /// + /// The "from" location MUST NOT be a proper prefix of the "path" + /// location; i.e., a location cannot be moved into one of its children. + /// + /// The move operation. + /// Object to apply the operation to. + public void Move(Operation operation, object objectToApplyTo) + { + if (operation == null) + { + throw new ArgumentNullException(nameof(operation)); + } + + if (objectToApplyTo == null) + { + throw new ArgumentNullException(nameof(objectToApplyTo)); + } + + var valueAtFromLocationResult = GetValueAtLocation(operation.from, objectToApplyTo, operation); + + if (valueAtFromLocationResult.HasError) + { + // Error has already been logged in GetValueAtLocation. We + // must return, because remove / add should not be allowed to continue + return; + } + + // remove that value + var removeResult = Remove(operation.from, objectToApplyTo, operation); + + if (removeResult.HasError) + { + // Return => error has already been logged in remove method. We must + // return, because add should not be allowed to continue + return; + } + + // add that value to the path location + Add(operation.path, + valueAtFromLocationResult.PropertyValue, + objectToApplyTo, + operation); + } + + /// + /// The "remove" operation removes the value at the target location. + /// + /// 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. + /// + /// The remove operation. + /// Object to apply the operation to. + 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 RemovedPropertyTypeResult Remove(string path, object objectToApplyTo, Operation operationToReport) + { + // get path result + var pathResult = GetActualPropertyPath( + path, + objectToApplyTo, + operationToReport); + + if (pathResult == null) + { + return new RemovedPropertyTypeResult(null, true); + } + + var removeFromList = pathResult.ExecuteAtEnd; + var positionAsInteger = pathResult.NumericEnd; + var actualPathToProperty = pathResult.PathToProperty; + + var treeAnalysisResult = new ObjectTreeAnalysisResult( + objectToApplyTo, + actualPathToProperty, + ContractResolver); + + if (!treeAnalysisResult.IsValidPathForRemove) + { + LogError(new JsonPatchError( + objectToApplyTo, + operationToReport, + Resources.FormatPropertyCannotBeRemoved(path))); + return new RemovedPropertyTypeResult(null, true); + } + + if (treeAnalysisResult.UseDynamicLogic) + { + // if it's not an array, we can remove the property from + // the dictionary. If it's an array, we need to check the position first. + if (removeFromList || positionAsInteger > -1) + { + var propertyValue = treeAnalysisResult.Container + .GetValueForCaseInsensitiveKey(treeAnalysisResult.PropertyPathInParent); + + // we cannot continue when the value is null, because to be able to + // continue we need to be able to check if the array is a non-string array + if (propertyValue == null) + { + LogError(new JsonPatchError( + objectToApplyTo, + operationToReport, + Resources.FormatCannotDeterminePropertyType(path))); + return new RemovedPropertyTypeResult(null, true); + } + + var typeOfPathProperty = propertyValue.GetType(); + + if (!IsNonStringArray(typeOfPathProperty)) + { + LogError(new JsonPatchError( + objectToApplyTo, + operationToReport, + Resources.FormatInvalidIndexForArrayProperty(operationToReport.op, path))); + return new RemovedPropertyTypeResult(null, true); + } + + // now, get the generic type of the enumerable (we'll return this type) + var genericTypeOfArray = GetIListType(typeOfPathProperty); + + // get the array + var array = (IList)treeAnalysisResult.Container.GetValueForCaseInsensitiveKey( + treeAnalysisResult.PropertyPathInParent); + + if (array.Count == 0) + { + // if the array is empty, we should throw an error + LogError(new JsonPatchError( + objectToApplyTo, + operationToReport, + Resources.FormatInvalidIndexForArrayProperty( + operationToReport.op, + path))); + return new RemovedPropertyTypeResult(null, true); + } + + if (removeFromList) + { + array.RemoveAt(array.Count - 1); + treeAnalysisResult.Container.SetValueForCaseInsensitiveKey( + treeAnalysisResult.PropertyPathInParent, array); + + // return the type of the value that has been removed. + return new RemovedPropertyTypeResult(genericTypeOfArray, false); + } + else + { + if (positionAsInteger >= array.Count) + { + LogError(new JsonPatchError( + objectToApplyTo, + operationToReport, + Resources.FormatInvalidIndexForArrayProperty( + operationToReport.op, + path))); + return new RemovedPropertyTypeResult(null, true); + } + + array.RemoveAt(positionAsInteger); + treeAnalysisResult.Container.SetValueForCaseInsensitiveKey( + treeAnalysisResult.PropertyPathInParent, array); + + // return the type of the value that has been removed. + return new RemovedPropertyTypeResult(genericTypeOfArray, false); + } + } + else + { + // get the property + var getResult = treeAnalysisResult.Container.GetValueForCaseInsensitiveKey( + treeAnalysisResult.PropertyPathInParent); + + // remove the property + treeAnalysisResult.Container.RemoveValueForCaseInsensitiveKey( + treeAnalysisResult.PropertyPathInParent); + + // value is not null, we can determine the type + if (getResult != null) + { + var actualType = getResult.GetType(); + return new RemovedPropertyTypeResult(actualType, false); + } + else + { + return new RemovedPropertyTypeResult(null, false); + } + } + } + else + { + // not dynamic + var patchProperty = treeAnalysisResult.JsonPatchProperty; + + if (removeFromList || positionAsInteger > -1) + { + if (!IsNonStringArray(patchProperty.Property.PropertyType)) + { + LogError(new JsonPatchError( + objectToApplyTo, + operationToReport, + Resources.FormatInvalidIndexForArrayProperty(operationToReport.op, path))); + return new RemovedPropertyTypeResult(null, true); + } + + // now, get the generic type of the IList<> from Property type. + var genericTypeOfArray = GetIListType(patchProperty.Property.PropertyType); + + if (!patchProperty.Property.Readable) + { + LogError(new JsonPatchError( + objectToApplyTo, + operationToReport, + Resources.FormatCannotReadProperty(path))); + return new RemovedPropertyTypeResult(null, true); + } + + var array = (IList)patchProperty.Property.ValueProvider + .GetValue(patchProperty.Parent); + + if (array.Count == 0) + { + // if the array is empty, we should throw an error + LogError(new JsonPatchError( + objectToApplyTo, + operationToReport, + Resources.FormatInvalidIndexForArrayProperty( + operationToReport.op, + path))); + return new RemovedPropertyTypeResult(null, true); + } + + if (removeFromList) + { + array.RemoveAt(array.Count - 1); + + // return the type of the value that has been removed + return new RemovedPropertyTypeResult(genericTypeOfArray, false); + } + else + { + if (positionAsInteger >= array.Count) + { + LogError(new JsonPatchError( + objectToApplyTo, + operationToReport, + Resources.FormatInvalidIndexForArrayProperty( + operationToReport.op, + path))); + return new RemovedPropertyTypeResult(null, true); + } + + array.RemoveAt(positionAsInteger); + + // return the type of the value that has been removed + return new RemovedPropertyTypeResult(genericTypeOfArray, false); + } + } + else + { + if (!patchProperty.Property.Writable) + { + LogError(new JsonPatchError( + objectToApplyTo, + operationToReport, + Resources.FormatCannotUpdateProperty(path))); + return new RemovedPropertyTypeResult(null, true); + } + + // 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 (patchProperty.Property.PropertyType.GetTypeInfo().IsValueType + && Nullable.GetUnderlyingType(patchProperty.Property.PropertyType) == null) + { + value = Activator.CreateInstance(patchProperty.Property.PropertyType); + } + + patchProperty.Property.ValueProvider.SetValue(patchProperty.Parent, value); + return new RemovedPropertyTypeResult(patchProperty.Property.PropertyType, false); + } + } + } + + /// + /// The "replace" operation replaces the value at the target location + /// with a new value. The operation object MUST contain a "value" member + /// whose content 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 } + /// + /// This operation is functionally identical to a "remove" operation for + /// a value, followed immediately by an "add" operation at the same + /// location with the replacement value. + /// + /// Note: even though it's the same functionally, we do not call remove + add + /// for performance reasons (multiple checks of same requirements). + /// + /// The replace operation. + /// Object to apply the operation to. + public void Replace(Operation operation, object objectToApplyTo) + { + if (operation == null) + { + throw new ArgumentNullException(nameof(operation)); + } + + if (objectToApplyTo == null) + { + throw new ArgumentNullException(nameof(objectToApplyTo)); + } + + var removeResult = Remove(operation.path, objectToApplyTo, operation); + + if (removeResult.HasError) + { + // return => error has already been logged in remove method + return; + } + + if (!removeResult.HasError && removeResult.ActualType == null) + { + // the remove operation completed succesfully, but we could not determine the type. + LogError(new JsonPatchError( + objectToApplyTo, + operation, + Resources.FormatCannotDeterminePropertyType(operation.from))); + return; + } + + var conversionResult = ConvertToActualType(removeResult.ActualType, operation.value); + + if (!conversionResult.CanBeConverted) + { + // invalid value for path + LogError(new JsonPatchError( + objectToApplyTo, + operation, + Resources.FormatInvalidValueForProperty(operation.value, operation.path))); + return; + } + + Add(operation.path, conversionResult.ConvertedInstance, objectToApplyTo, operation); + } + + /// + /// The "copy" operation copies the value at a specified location to the + /// target location. + /// + /// The operation object MUST contain a "from" member, which is a string + /// containing a JSON Pointer value that 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" } + /// + /// This operation is functionally identical to an "add" operation at the + /// target location using the value specified in the "from" member. + /// + /// Note: even though it's the same functionally, we do not call add with + /// the value specified in from for performance reasons (multiple checks of same requirements). + /// + /// The copy operation. + /// Object to apply the operation to. + 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 + var valueAtFromLocationResult = GetValueAtLocation(operation.from, objectToApplyTo, operation); + + if (valueAtFromLocationResult.HasError) + { + // Return, error has already been logged in GetValueAtLocation + return; + } + + Add(operation.path, + valueAtFromLocationResult.PropertyValue, + objectToApplyTo, + operation); + } + + /// + /// Method is used by Copy and Move to avoid duplicate code + /// + /// Location where value should be + /// Object to inspect for the desired value + /// Operation to report in case of an error + /// GetValueResult containing value and a bool signifying a possible error + private GetValueResult GetValueAtLocation( + string location, + object objectToGetValueFrom, + Operation operationToReport) + { + if (location == null) + { + throw new ArgumentNullException(nameof(location)); + } + + if (objectToGetValueFrom == null) + { + throw new ArgumentNullException(nameof(objectToGetValueFrom)); + } + + if (operationToReport == null) + { + throw new ArgumentNullException(nameof(operationToReport)); + } + + // get path result + var pathResult = GetActualPropertyPath( + location, + objectToGetValueFrom, + operationToReport); + + if (pathResult == null) + { + return new GetValueResult(null, true); + } + + var getAtEndOfList = pathResult.ExecuteAtEnd; + var positionAsInteger = pathResult.NumericEnd; + var actualPathToProperty = pathResult.PathToProperty; + + var treeAnalysisResult = new ObjectTreeAnalysisResult( + objectToGetValueFrom, + actualPathToProperty, + ContractResolver); + + if (treeAnalysisResult.UseDynamicLogic) + { + // if it's not an array, we can remove the property from + // the dictionary. If it's an array, we need to check the position first. + if (getAtEndOfList || positionAsInteger > -1) + { + var propertyValue = treeAnalysisResult.Container + .GetValueForCaseInsensitiveKey(treeAnalysisResult.PropertyPathInParent); + + // we cannot continue when the value is null, because to be able to + // continue we need to be able to check if the array is a non-string array + if (propertyValue == null) + { + LogError(new JsonPatchError( + objectToGetValueFrom, + operationToReport, + Resources.FormatCannotDeterminePropertyType(location))); + return new GetValueResult(null, true); + } + + var typeOfPathProperty = propertyValue.GetType(); + + if (!IsNonStringArray(typeOfPathProperty)) + { + LogError(new JsonPatchError( + objectToGetValueFrom, + operationToReport, + Resources.FormatInvalidIndexForArrayProperty(operationToReport.op, location))); + return new GetValueResult(null, true); + } + + // get the array + var array = (IList)treeAnalysisResult.Container.GetValueForCaseInsensitiveKey( + treeAnalysisResult.PropertyPathInParent); + + if (positionAsInteger >= array.Count) + { + LogError(new JsonPatchError( + objectToGetValueFrom, + operationToReport, + Resources.FormatInvalidIndexForArrayProperty( + operationToReport.op, + location))); + return new GetValueResult(null, true); + } + + if (getAtEndOfList) + { + return new GetValueResult(array[array.Count - 1], false); + } + else + { + return new GetValueResult(array[positionAsInteger], false); + } + } + else + { + // get the property + var propertyValueAtLocation = treeAnalysisResult.Container.GetValueForCaseInsensitiveKey( + treeAnalysisResult.PropertyPathInParent); + + return new GetValueResult(propertyValueAtLocation, false); + } + } + else + { + // not dynamic + var patchProperty = treeAnalysisResult.JsonPatchProperty; + + if (getAtEndOfList || positionAsInteger > -1) + { + if (!IsNonStringArray(patchProperty.Property.PropertyType)) + { + LogError(new JsonPatchError( + objectToGetValueFrom, + operationToReport, + Resources.FormatInvalidIndexForArrayProperty(operationToReport.op, location))); + return new GetValueResult(null, true); + } + + if (!patchProperty.Property.Readable) + { + LogError(new JsonPatchError( + objectToGetValueFrom, + operationToReport, + Resources.FormatCannotReadProperty(location))); + return new GetValueResult(null, true); + } + + var array = (IList)patchProperty.Property.ValueProvider + .GetValue(patchProperty.Parent); + + if (positionAsInteger >= array.Count) + { + LogError(new JsonPatchError( + objectToGetValueFrom, + operationToReport, + Resources.FormatInvalidIndexForArrayProperty( + operationToReport.op, + location))); + return new GetValueResult(null, true); + } + + if (getAtEndOfList) + { + return new GetValueResult(array[array.Count - 1], false); + } + else + { + return new GetValueResult(array[positionAsInteger], false); + } + } + else + { + if (!patchProperty.Property.Readable) + { + LogError(new JsonPatchError( + objectToGetValueFrom, + operationToReport, + Resources.FormatCannotReadProperty( + location))); + return new GetValueResult(null, true); + } + + var propertyValueAtLocation = patchProperty.Property.ValueProvider + .GetValue(patchProperty.Parent); + + return new GetValueResult(propertyValueAtLocation, false); + } + } + } + + private bool IsNonStringArray(Type type) + { + if (GetIListType(type) != null) + { + return true; + } + + return (!(type == typeof(string)) && typeof(IList).GetTypeInfo().IsAssignableFrom(type.GetTypeInfo())); + } + + private void LogError(JsonPatchError jsonPatchError) + { + if (LogErrorAction != null) + { + LogErrorAction(jsonPatchError); + } + else + { + throw new JsonPatchException(jsonPatchError); + } + } + + private ConversionResult ConvertToActualType(Type propertyType, object value) + { + try + { + var o = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(value), propertyType); + + return new ConversionResult(true, o); + } + catch (Exception) + { + return new ConversionResult(false, null); + } + } + + private Type GetIListType(Type type) + { + if (IsGenericListType(type)) + { + return type.GetGenericArguments()[0]; + } + + foreach (Type interfaceType in type.GetTypeInfo().ImplementedInterfaces) + { + if (IsGenericListType(interfaceType)) + { + return interfaceType.GetGenericArguments()[0]; + } + } + + return null; + } + + private bool IsGenericListType(Type type) + { + if (type.GetTypeInfo().IsGenericType && + type.GetGenericTypeDefinition() == typeof(IList<>)) + { + return true; + } + + return false; + } + + private ActualPropertyPathResult GetActualPropertyPath( + string propertyPath, + object objectToApplyTo, + Operation operationToReport) + { + if (propertyPath == null) + { + throw new ArgumentNullException(nameof(propertyPath)); + } + + if (objectToApplyTo == null) + { + throw new ArgumentNullException(nameof(objectToApplyTo)); + } + + if (operationToReport == null) + { + throw new ArgumentNullException(nameof(operationToReport)); + } + + if (propertyPath.EndsWith("/-")) + { + return new ActualPropertyPathResult(-1, propertyPath.Substring(0, propertyPath.Length - 2), true); + } + else + { + var possibleIndex = propertyPath.Substring(propertyPath.LastIndexOf("/") + 1); + int castedIndex = -1; + if (int.TryParse(possibleIndex, out castedIndex)) + { + // has numeric end. + if (castedIndex > -1) + { + var pathToProperty = propertyPath.Substring( + 0, + propertyPath.LastIndexOf('/' + castedIndex.ToString())); + + return new ActualPropertyPathResult(castedIndex, pathToProperty, false); + } + else + { + // negative position - invalid path + LogError(new JsonPatchError( + objectToApplyTo, + operationToReport, + Resources.FormatNegativeIndexForArrayProperty(operationToReport.op, propertyPath))); + return null; + } + } + + return new ActualPropertyPathResult(-1, propertyPath, false); + } + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.JsonPatch/Converters/JsonPatchDocumentConverter.cs b/src/Microsoft.AspNet.JsonPatch/Converters/JsonPatchDocumentConverter.cs new file mode 100644 index 0000000000..4551f64043 --- /dev/null +++ b/src/Microsoft.AspNet.JsonPatch/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.AspNet.JsonPatch.Exceptions; +using Microsoft.AspNet.JsonPatch.Operations; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Serialization; + +namespace Microsoft.AspNet.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 JsonPatchException(Resources.FormatInvalidJsonPatchDocument(objectType.Name), 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/Microsoft.AspNet.JsonPatch/Converters/TypedJsonPatchDocumentConverter.cs b/src/Microsoft.AspNet.JsonPatch/Converters/TypedJsonPatchDocumentConverter.cs new file mode 100644 index 0000000000..7b6bb77e17 --- /dev/null +++ b/src/Microsoft.AspNet.JsonPatch/Converters/TypedJsonPatchDocumentConverter.cs @@ -0,0 +1,65 @@ +// Copyright (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.AspNet.JsonPatch.Exceptions; +using Microsoft.AspNet.JsonPatch.Operations; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Serialization; + +namespace Microsoft.AspNet.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.GetGenericArguments()[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 JsonPatchException(Resources.FormatInvalidJsonPatchDocument(objectType.Name), ex); + } + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.JsonPatch/Exceptions/JsonPatchException.cs b/src/Microsoft.AspNet.JsonPatch/Exceptions/JsonPatchException.cs new file mode 100644 index 0000000000..ac5222a2bb --- /dev/null +++ b/src/Microsoft.AspNet.JsonPatch/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.AspNet.JsonPatch.Operations; + +namespace Microsoft.AspNet.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/Microsoft.AspNet.JsonPatch/Helpers/ActualPropertyPathResult.cs b/src/Microsoft.AspNet.JsonPatch/Helpers/ActualPropertyPathResult.cs new file mode 100644 index 0000000000..d22d1bf830 --- /dev/null +++ b/src/Microsoft.AspNet.JsonPatch/Helpers/ActualPropertyPathResult.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. + +namespace Microsoft.AspNet.JsonPatch.Helpers +{ + internal class ActualPropertyPathResult + { + public int NumericEnd { get; private set; } + public string PathToProperty { get; set; } + public bool ExecuteAtEnd { get; set; } + + public ActualPropertyPathResult( + int numericEnd, + string pathToProperty, + bool executeAtEnd) + { + NumericEnd = numericEnd; + PathToProperty = pathToProperty; + ExecuteAtEnd = executeAtEnd; + } + } +} diff --git a/src/Microsoft.AspNet.JsonPatch/Helpers/ConversionResult.cs b/src/Microsoft.AspNet.JsonPatch/Helpers/ConversionResult.cs new file mode 100644 index 0000000000..aba4913f2d --- /dev/null +++ b/src/Microsoft.AspNet.JsonPatch/Helpers/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.AspNet.JsonPatch.Helpers +{ + internal class ConversionResult + { + public bool CanBeConverted { get; private set; } + public object ConvertedInstance { get; private set; } + + public ConversionResult(bool canBeConverted, object convertedInstance) + { + CanBeConverted = canBeConverted; + ConvertedInstance = convertedInstance; + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.JsonPatch/Helpers/ExpandoObjectDictionaryExtensions.cs b/src/Microsoft.AspNet.JsonPatch/Helpers/ExpandoObjectDictionaryExtensions.cs new file mode 100644 index 0000000000..a5911dded2 --- /dev/null +++ b/src/Microsoft.AspNet.JsonPatch/Helpers/ExpandoObjectDictionaryExtensions.cs @@ -0,0 +1,77 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; + +namespace Microsoft.AspNet.JsonPatch.Helpers +{ + // Helper methods to allow case-insensitive key search + internal static class ExpandoObjectDictionaryExtensions + { + internal static void SetValueForCaseInsensitiveKey( + this IDictionary propertyDictionary, + string key, + object value) + { + foreach (KeyValuePair kvp in propertyDictionary) + { + if (string.Equals(kvp.Key, key, StringComparison.OrdinalIgnoreCase)) + { + propertyDictionary[kvp.Key] = value; + break; + } + } + } + + internal static void RemoveValueForCaseInsensitiveKey( + this IDictionary propertyDictionary, + string key) + { + string realKey = null; + foreach (KeyValuePair kvp in propertyDictionary) + { + if (string.Equals(kvp.Key, key, StringComparison.OrdinalIgnoreCase)) + { + realKey = kvp.Key; + break; + } + } + + if (realKey != null) + { + propertyDictionary.Remove(realKey); + } + } + + internal static object GetValueForCaseInsensitiveKey( + this IDictionary propertyDictionary, + string key) + { + foreach (KeyValuePair kvp in propertyDictionary) + { + if (string.Equals(kvp.Key, key, StringComparison.OrdinalIgnoreCase)) + { + return kvp.Value; + } + } + + throw new ArgumentException(Resources.FormatDictionaryKeyNotFound(key)); + } + + internal static bool ContainsCaseInsensitiveKey( + this IDictionary propertyDictionary, + string key) + { + foreach (KeyValuePair kvp in propertyDictionary) + { + if (string.Equals(kvp.Key, key, StringComparison.OrdinalIgnoreCase)) + { + return true; + } + } + + return false; + } + } +} diff --git a/src/Microsoft.AspNet.JsonPatch/Helpers/ExpressionHelpers.cs b/src/Microsoft.AspNet.JsonPatch/Helpers/ExpressionHelpers.cs new file mode 100644 index 0000000000..6a0279876c --- /dev/null +++ b/src/Microsoft.AspNet.JsonPatch/Helpers/ExpressionHelpers.cs @@ -0,0 +1,99 @@ +// Copyright (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.Linq.Expressions; + +namespace Microsoft.AspNet.JsonPatch.Helpers +{ + internal static class ExpressionHelpers + { + public static string GetPath(Expression> expr) where TModel : class + { + return "/" + GetPath(expr.Body, true); + } + + private static string GetPath(Expression expr, bool firstTime) + { + switch (expr.NodeType) + { + case ExpressionType.ArrayIndex: + var binaryExpression = (BinaryExpression)expr; + + if (ContinueWithSubPath(binaryExpression.Left.NodeType, false)) + { + var leftFromBinaryExpression = GetPath(binaryExpression.Left, false); + return leftFromBinaryExpression + "/" + binaryExpression.Right.ToString(); + } + else + { + return binaryExpression.Right.ToString(); + } + case ExpressionType.Call: + var methodCallExpression = (MethodCallExpression)expr; + + if (ContinueWithSubPath(methodCallExpression.Object.NodeType, false)) + { + var leftFromMemberCallExpression = GetPath(methodCallExpression.Object, false); + return leftFromMemberCallExpression + "/" + + GetIndexerInvocation(methodCallExpression.Arguments[0]); + } + else + { + return GetIndexerInvocation(methodCallExpression.Arguments[0]); + } + case ExpressionType.Convert: + return GetPath(((UnaryExpression)expr).Operand, false); + case ExpressionType.MemberAccess: + var memberExpression = expr as MemberExpression; + + if (ContinueWithSubPath(memberExpression.Expression.NodeType, false)) + { + var left = GetPath(memberExpression.Expression, false); + return left + "/" + memberExpression.Member.Name; + } + else + { + return memberExpression.Member.Name; + } + case ExpressionType.Parameter: + // Fits "x => x" (the whole document which is "" as JSON pointer) + return firstTime ? string.Empty : null; + default: + return string.Empty; + } + } + + private static bool ContinueWithSubPath(ExpressionType expressionType, bool firstTime) + { + if (firstTime) + { + return (expressionType == ExpressionType.ArrayIndex + || expressionType == ExpressionType.Call + || expressionType == ExpressionType.Convert + || expressionType == ExpressionType.MemberAccess + || expressionType == ExpressionType.Parameter); + } + else + { + return (expressionType == ExpressionType.ArrayIndex + || expressionType == ExpressionType.Call + || expressionType == ExpressionType.Convert + || expressionType == ExpressionType.MemberAccess); + } + } + + private static string GetIndexerInvocation(Expression expression) + { + var converted = Expression.Convert(expression, typeof(object)); + var fakeParameter = Expression.Parameter(typeof(object), null); + var lambda = Expression.Lambda>(converted, fakeParameter); + Func func; + + func = lambda.Compile(); + + return Convert.ToString(func(null), CultureInfo.InvariantCulture); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.JsonPatch/Helpers/GetValueResult.cs b/src/Microsoft.AspNet.JsonPatch/Helpers/GetValueResult.cs new file mode 100644 index 0000000000..89b7c93520 --- /dev/null +++ b/src/Microsoft.AspNet.JsonPatch/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.AspNet.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/Microsoft.AspNet.JsonPatch/Helpers/JsonPatchProperty.cs b/src/Microsoft.AspNet.JsonPatch/Helpers/JsonPatchProperty.cs new file mode 100644 index 0000000000..0539d230a3 --- /dev/null +++ b/src/Microsoft.AspNet.JsonPatch/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.AspNet.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/Microsoft.AspNet.JsonPatch/Helpers/ObjectTreeAnalyisResult.cs b/src/Microsoft.AspNet.JsonPatch/Helpers/ObjectTreeAnalyisResult.cs new file mode 100644 index 0000000000..91d5ee129d --- /dev/null +++ b/src/Microsoft.AspNet.JsonPatch/Helpers/ObjectTreeAnalyisResult.cs @@ -0,0 +1,210 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json.Serialization; + +namespace Microsoft.AspNet.JsonPatch.Helpers +{ + internal class ObjectTreeAnalysisResult + { + // either the property is part of the container dictionary, + // or we have a direct reference to a JsonPatchProperty instance + + public bool UseDynamicLogic { get; private set; } + + public bool IsValidPathForAdd { get; private set; } + + public bool IsValidPathForRemove { get; private set; } + + public IDictionary Container { get; private set; } + + public string PropertyPathInParent { get; private set; } + + public JsonPatchProperty JsonPatchProperty { get; private set; } + + public ObjectTreeAnalysisResult( + object objectToSearch, + string propertyPath, + IContractResolver contractResolver) + { + // construct the analysis result. + + // split the propertypath, and if necessary, remove the first + // empty item (that's the case when it starts with a "/") + var propertyPathTree = propertyPath.Split( + new char[] { '/' }, + StringSplitOptions.RemoveEmptyEntries); + + // we've now got a split up property tree "base/property/otherproperty/..." + int lastPosition = 0; + object targetObject = objectToSearch; + for (int i = 0; i < propertyPathTree.Length; i++) + { + lastPosition = i; + + // if the current target object is an ExpandoObject (IDictionary), + // we cannot use the ContractResolver. + var dictionary = targetObject as IDictionary; + if (dictionary != null) + { + // find the value in the dictionary + if (dictionary.ContainsCaseInsensitiveKey(propertyPathTree[i])) + { + var possibleNewTargetObject = dictionary.GetValueForCaseInsensitiveKey(propertyPathTree[i]); + + // unless we're at the last item, we should set the targetobject + // to the new object. If we're at the last item, we need to stop + if (i != propertyPathTree.Length - 1) + { + targetObject = possibleNewTargetObject; + } + } + else + { + break; + } + } + else + { + // if the current part of the path is numeric, this means we're trying + // to get the propertyInfo of a specific object in an array. To allow + // for this, the previous value (targetObject) must be an IEnumerable, and + // the position must exist. + + int numericValue = -1; + if (int.TryParse(propertyPathTree[i], out numericValue)) + { + var element = GetElementAtFromObject(targetObject, numericValue); + if (element != null) + { + targetObject = element; + } + else + { + break; + } + } + else + { + var jsonContract = (JsonObjectContract)contractResolver.ResolveContract(targetObject.GetType()); + + // does the property exist? + var attemptedProperty = jsonContract + .Properties + .FirstOrDefault(p => string.Equals(p.PropertyName, propertyPathTree[i], StringComparison.OrdinalIgnoreCase)); + + if (attemptedProperty != null) + { + // unless we're at the last item, we should continue searching. + // If we're at the last item, we need to stop + if ((i != propertyPathTree.Length - 1)) + { + targetObject = attemptedProperty.ValueProvider.GetValue(targetObject); + } + } + else + { + // property cannot be found, and we're not working with dynamics. + // Stop, and return invalid path. + break; + } + } + } + } + + if (propertyPathTree.Length - lastPosition != 1) + { + IsValidPathForAdd = false; + IsValidPathForRemove = false; + return; + } + + // two things can happen now. The targetproperty can be an IDictionary - in that + // case, it's valid for add if there's 1 item left in the propertyPathTree. + // + // it can also be a property info. In that case, if there's nothing left in the path + // tree we're at the end, if there's one left we can try and set that. + if (targetObject is IDictionary) + { + UseDynamicLogic = true; + + Container = (IDictionary)targetObject; + IsValidPathForAdd = true; + PropertyPathInParent = propertyPathTree[propertyPathTree.Length - 1]; + + // to be able to remove this property, it must exist + IsValidPathForRemove = Container.ContainsCaseInsensitiveKey(PropertyPathInParent); + } + else if (targetObject is IList) + { + System.Diagnostics.Debugger.Launch(); + UseDynamicLogic = false; + + int index; + if (!Int32.TryParse(propertyPathTree[propertyPathTree.Length - 1], out index)) + { + // We only support indexing into a list + IsValidPathForAdd = false; + IsValidPathForRemove = false; + return; + } + + IsValidPathForAdd = true; + IsValidPathForRemove = ((IList)targetObject).Count > index; + PropertyPathInParent = propertyPathTree[propertyPathTree.Length - 1]; + } + else + { + UseDynamicLogic = false; + + var property = propertyPathTree[propertyPathTree.Length - 1]; + var jsonContract = (JsonObjectContract)contractResolver.ResolveContract(targetObject.GetType()); + var attemptedProperty = jsonContract + .Properties + .FirstOrDefault(p => string.Equals(p.PropertyName, property, StringComparison.OrdinalIgnoreCase)); + + if (attemptedProperty == null) + { + IsValidPathForAdd = false; + IsValidPathForRemove = false; + } + else + { + IsValidPathForAdd = true; + IsValidPathForRemove = true; + JsonPatchProperty = new JsonPatchProperty(attemptedProperty, targetObject); + PropertyPathInParent = property; + } + } + } + + private object GetElementAtFromObject(object targetObject, int numericValue) + { + if (numericValue > -1) + { + // Check if the targetobject is an IEnumerable, + // and if the position is valid. + if (targetObject is IEnumerable) + { + var indexable = ((IEnumerable)targetObject).Cast(); + + if (indexable.Count() >= numericValue) + { + return indexable.ElementAt(numericValue); + } + else { return null; } + } + else { return null; } + } + else + { + return null; + } + } + + } +} diff --git a/src/Microsoft.AspNet.JsonPatch/Helpers/PathHelpers.cs b/src/Microsoft.AspNet.JsonPatch/Helpers/PathHelpers.cs new file mode 100644 index 0000000000..28683e7c98 --- /dev/null +++ b/src/Microsoft.AspNet.JsonPatch/Helpers/PathHelpers.cs @@ -0,0 +1,31 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.AspNet.JsonPatch.Exceptions; + +namespace Microsoft.AspNet.JsonPatch.Helpers +{ + internal static class PathHelpers + { + internal static string NormalizePath(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(".") || path.Contains("//") || path.Contains(" ") || path.Contains("\\")) + { + throw new JsonPatchException(Resources.FormatInvalidValueForPath(path), null); + } + + if (!(path.StartsWith("/"))) + { + return "/" + path; + } + else + { + return path; + } + } + } +} diff --git a/src/Microsoft.AspNet.JsonPatch/Helpers/RemovedPropertyTypeResult.cs b/src/Microsoft.AspNet.JsonPatch/Helpers/RemovedPropertyTypeResult.cs new file mode 100644 index 0000000000..9f5b97a868 --- /dev/null +++ b/src/Microsoft.AspNet.JsonPatch/Helpers/RemovedPropertyTypeResult.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; + +namespace Microsoft.AspNet.JsonPatch.Helpers +{ + /// + /// Return value for Remove operation. The combination tells us what to do next (if this operation + /// is called from inside another operation, eg: Replace, Copy. + /// + /// Possible combo: + /// - ActualType contains type: operation succesfully completed, can continue when called from inside + /// another operation + /// - ActualType null and HasError true: operation not completed succesfully, should not be allowed to continue + /// - ActualType null and HasError false: operation completed succesfully, but we should not be allowed to + /// continue when called from inside another method as we could not verify the type of the removed property. + /// This happens when the value of an item in an ExpandoObject dictionary is null. + /// + internal class RemovedPropertyTypeResult + { + /// + /// The type of the removed property (value) + /// + public Type ActualType { get; private set; } + + /// + /// HasError: true when an error occurred, the operation didn't complete succesfully + /// + public bool HasError { get; set; } + + public RemovedPropertyTypeResult(Type actualType, bool hasError) + { + ActualType = actualType; + HasError = hasError; + } + } +} diff --git a/src/Microsoft.AspNet.JsonPatch/IJsonPatchDocument.cs b/src/Microsoft.AspNet.JsonPatch/IJsonPatchDocument.cs new file mode 100644 index 0000000000..18033e82f0 --- /dev/null +++ b/src/Microsoft.AspNet.JsonPatch/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.AspNet.JsonPatch.Operations; +using System.Collections.Generic; +using Newtonsoft.Json.Serialization; + +namespace Microsoft.AspNet.JsonPatch +{ + public interface IJsonPatchDocument + { + IContractResolver ContractResolver { get; set; } + + IList GetOperations(); + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.JsonPatch/JsonPatchDocument.cs b/src/Microsoft.AspNet.JsonPatch/JsonPatchDocument.cs new file mode 100644 index 0000000000..fc2e73030a --- /dev/null +++ b/src/Microsoft.AspNet.JsonPatch/JsonPatchDocument.cs @@ -0,0 +1,222 @@ +// Copyright (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.AspNet.JsonPatch.Adapters; +using Microsoft.AspNet.JsonPatch.Converters; +using Microsoft.AspNet.JsonPatch.Helpers; +using Microsoft.AspNet.JsonPatch.Operations; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; + +namespace Microsoft.AspNet.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.NormalizePath(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.NormalizePath(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.NormalizePath(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.NormalizePath(path), PathHelpers.NormalizePath(from))); + return this; + } + + /// + /// Copy the value at specified location to the target location. Willr esult 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.NormalizePath(path), PathHelpers.NormalizePath(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, logErrorAction: null)); + } + + /// + /// Apply this JsonPatchDocument + /// + /// Object to apply the JsonPatchDocument to + /// Action to log errors + public void ApplyTo(object objectToApplyTo, Action logErrorAction) + { + if (objectToApplyTo == null) + { + throw new ArgumentNullException(nameof(objectToApplyTo)); + } + + ApplyTo(objectToApplyTo, new ObjectAdapter(ContractResolver, logErrorAction)); + } + + /// + /// 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/Microsoft.AspNet.JsonPatch/JsonPatchDocumentOfT.cs b/src/Microsoft.AspNet.JsonPatch/JsonPatchDocumentOfT.cs new file mode 100644 index 0000000000..7b03f1644c --- /dev/null +++ b/src/Microsoft.AspNet.JsonPatch/JsonPatchDocumentOfT.cs @@ -0,0 +1,700 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using Microsoft.AspNet.JsonPatch.Adapters; +using Microsoft.AspNet.JsonPatch.Converters; +using Microsoft.AspNet.JsonPatch.Helpers; +using Microsoft.AspNet.JsonPatch.Operations; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; + +namespace Microsoft.AspNet.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) + { + 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" ] } + /// + /// 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", + ExpressionHelpers.GetPath(path).ToLowerInvariant(), + 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", + ExpressionHelpers.GetPath(path).ToLowerInvariant() + "/" + position, + from: null, + value: value)); + + return this; + } + + /// + /// At value at end of 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", + ExpressionHelpers.GetPath(path).ToLowerInvariant() + "/-", + 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", ExpressionHelpers.GetPath(path).ToLowerInvariant(), 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", + ExpressionHelpers.GetPath(path).ToLowerInvariant() + "/" + position, + 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", + ExpressionHelpers.GetPath(path).ToLowerInvariant() + "/-", + 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", + ExpressionHelpers.GetPath(path).ToLowerInvariant(), + 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", + ExpressionHelpers.GetPath(path).ToLowerInvariant() + "/" + position, + 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", + ExpressionHelpers.GetPath(path).ToLowerInvariant() + "/-", + 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", + ExpressionHelpers.GetPath(path).ToLowerInvariant(), + ExpressionHelpers.GetPath(from).ToLowerInvariant())); + + 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", + ExpressionHelpers.GetPath(path).ToLowerInvariant(), + ExpressionHelpers.GetPath(from).ToLowerInvariant() + "/" + positionFrom)); + + 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", + ExpressionHelpers.GetPath(path).ToLowerInvariant() + "/" + positionTo, + ExpressionHelpers.GetPath(from).ToLowerInvariant())); + + 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", + ExpressionHelpers.GetPath(path).ToLowerInvariant() + "/" + positionTo, + ExpressionHelpers.GetPath(from).ToLowerInvariant() + "/" + positionFrom)); + + 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", + ExpressionHelpers.GetPath(path).ToLowerInvariant() + "/-", + ExpressionHelpers.GetPath(from).ToLowerInvariant() + "/" + positionFrom)); + + 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", + ExpressionHelpers.GetPath(path).ToLowerInvariant() + "/-", + ExpressionHelpers.GetPath(from).ToLowerInvariant())); + + return this; + } + + /// + /// Copy the value at specified location to the target location. Willr esult 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", + ExpressionHelpers.GetPath(path).ToLowerInvariant() + , ExpressionHelpers.GetPath(from).ToLowerInvariant())); + + 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", + ExpressionHelpers.GetPath(path).ToLowerInvariant(), + ExpressionHelpers.GetPath(from).ToLowerInvariant() + "/" + positionFrom)); + + 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", + ExpressionHelpers.GetPath(path).ToLowerInvariant() + "/" + positionTo, + ExpressionHelpers.GetPath(from).ToLowerInvariant())); + + 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", + ExpressionHelpers.GetPath(path).ToLowerInvariant() + "/" + positionTo, + ExpressionHelpers.GetPath(from).ToLowerInvariant() + "/" + positionFrom)); + + 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", + ExpressionHelpers.GetPath(path).ToLowerInvariant() + "/-", + ExpressionHelpers.GetPath(from).ToLowerInvariant() + "/" + positionFrom)); + + 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", + ExpressionHelpers.GetPath(path).ToLowerInvariant() + "/-", + ExpressionHelpers.GetPath(from).ToLowerInvariant())); + + 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, logErrorAction: null)); + } + + /// + /// Apply this JsonPatchDocument + /// + /// Object to apply the JsonPatchDocument to + /// Action to log errors + public void ApplyTo(TModel objectToApplyTo, Action logErrorAction) + { + if (objectToApplyTo == null) + { + throw new ArgumentNullException(nameof(objectToApplyTo)); + } + + ApplyTo(objectToApplyTo, new ObjectAdapter(ContractResolver, logErrorAction)); + } + + /// + /// 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(); + + untypedOp.op = op.op; + untypedOp.value = op.value; + untypedOp.path = op.path; + untypedOp.from = op.from; + + allOps.Add(untypedOp); + } + } + + return allOps; + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.JsonPatch/JsonPatchError.cs b/src/Microsoft.AspNet.JsonPatch/JsonPatchError.cs new file mode 100644 index 0000000000..a140f0d4c1 --- /dev/null +++ b/src/Microsoft.AspNet.JsonPatch/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.AspNet.JsonPatch.Operations; + +namespace Microsoft.AspNet.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/Microsoft.AspNet.JsonPatch/Microsoft.AspNet.JsonPatch.xproj b/src/Microsoft.AspNet.JsonPatch/Microsoft.AspNet.JsonPatch.xproj new file mode 100644 index 0000000000..f9fb187ecd --- /dev/null +++ b/src/Microsoft.AspNet.JsonPatch/Microsoft.AspNet.JsonPatch.xproj @@ -0,0 +1,17 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 4d55f4d8-633b-462f-a5b1-feb84bd2d534 + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin\$(MSBuildProjectName)\ + + + 2.0 + + + \ No newline at end of file diff --git a/src/Microsoft.AspNet.JsonPatch/Operations/Operation.cs b/src/Microsoft.AspNet.JsonPatch/Operations/Operation.cs new file mode 100644 index 0000000000..7f056f41bf --- /dev/null +++ b/src/Microsoft.AspNet.JsonPatch/Operations/Operation.cs @@ -0,0 +1,74 @@ +// Copyright (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.AspNet.JsonPatch.Adapters; +using Newtonsoft.Json; + +namespace Microsoft.AspNet.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: + 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/Microsoft.AspNet.JsonPatch/Operations/OperationBase.cs b/src/Microsoft.AspNet.JsonPatch/Operations/OperationBase.cs new file mode 100644 index 0000000000..17455f75e8 --- /dev/null +++ b/src/Microsoft.AspNet.JsonPatch/Operations/OperationBase.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 Newtonsoft.Json; + +namespace Microsoft.AspNet.JsonPatch.Operations +{ + public class OperationBase + { + [JsonIgnore] + public OperationType OperationType + { + get + { + return (OperationType)Enum.Parse(typeof(OperationType), op, true); + } + } + + [JsonProperty("path")] + public string path { get; set; } + + [JsonProperty("op")] + public string op { get; set; } + + [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/Microsoft.AspNet.JsonPatch/Operations/OperationOfT.cs b/src/Microsoft.AspNet.JsonPatch/Operations/OperationOfT.cs new file mode 100644 index 0000000000..63663f70d9 --- /dev/null +++ b/src/Microsoft.AspNet.JsonPatch/Operations/OperationOfT.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 Microsoft.AspNet.JsonPatch.Adapters; + +namespace Microsoft.AspNet.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: + throw new NotSupportedException(Resources.TestOperationNotSupported); + default: + break; + } + } + + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.JsonPatch/Operations/OperationType.cs b/src/Microsoft.AspNet.JsonPatch/Operations/OperationType.cs new file mode 100644 index 0000000000..a4d006bc51 --- /dev/null +++ b/src/Microsoft.AspNet.JsonPatch/Operations/OperationType.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.AspNet.JsonPatch.Operations +{ + public enum OperationType + { + Add, + Remove, + Replace, + Move, + Copy, + Test + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.JsonPatch/Properties/AssemblyInfo.cs b/src/Microsoft.AspNet.JsonPatch/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..b2437d9ad6 --- /dev/null +++ b/src/Microsoft.AspNet.JsonPatch/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; + +[assembly: AssemblyMetadata("Serviceable", "True")] +[assembly: NeutralResourcesLanguage("en-us")] \ No newline at end of file diff --git a/src/Microsoft.AspNet.JsonPatch/Properties/Resources.Designer.cs b/src/Microsoft.AspNet.JsonPatch/Properties/Resources.Designer.cs new file mode 100644 index 0000000000..f0ee7f2439 --- /dev/null +++ b/src/Microsoft.AspNet.JsonPatch/Properties/Resources.Designer.cs @@ -0,0 +1,270 @@ +// +namespace Microsoft.AspNet.JsonPatch +{ + using System.Globalization; + using System.Reflection; + using System.Resources; + + internal static class Resources + { + private static readonly ResourceManager _resourceManager + = new ResourceManager("Microsoft.AspNet.JsonPatch.Resources", typeof(Resources).GetTypeInfo().Assembly); + + /// + /// The type of the property at path '{0}' could not be determined. + /// + internal static string CannotDeterminePropertyType + { + get { return GetString("CannotDeterminePropertyType"); } + } + + /// + /// The type of the property at path '{0}' could not be determined. + /// + internal static string FormatCannotDeterminePropertyType(object p0) + { + return string.Format(CultureInfo.CurrentCulture, GetString("CannotDeterminePropertyType"), p0); + } + + /// + /// The property at '{0}' could not be read. + /// + internal static string CannotReadProperty + { + get { return GetString("CannotReadProperty"); } + } + + /// + /// The property at '{0}' could not be read. + /// + internal static string FormatCannotReadProperty(object p0) + { + return string.Format(CultureInfo.CurrentCulture, GetString("CannotReadProperty"), p0); + } + + /// + /// The property at path '{0}' could not be updated. + /// + internal static string CannotUpdateProperty + { + get { return GetString("CannotUpdateProperty"); } + } + + /// + /// The property at path '{0}' could not be updated. + /// + internal static string FormatCannotUpdateProperty(object p0) + { + return string.Format(CultureInfo.CurrentCulture, GetString("CannotUpdateProperty"), p0); + } + + /// + /// The key '{0}' was not found. + /// + internal static string DictionaryKeyNotFound + { + get { return GetString("DictionaryKeyNotFound"); } + } + + /// + /// The key '{0}' was not found. + /// + internal static string FormatDictionaryKeyNotFound(object p0) + { + return string.Format(CultureInfo.CurrentCulture, GetString("DictionaryKeyNotFound"), p0); + } + + /// + /// For operation '{0}' on array property at path '{1}', the index is larger than the array size. + /// + internal static string InvalidIndexForArrayProperty + { + get { return GetString("InvalidIndexForArrayProperty"); } + } + + /// + /// For operation '{0}' on array property at path '{1}', the index is larger than the array size. + /// + internal static string FormatInvalidIndexForArrayProperty(object p0, object p1) + { + return string.Format(CultureInfo.CurrentCulture, GetString("InvalidIndexForArrayProperty"), p0, p1); + } + + /// + /// The type '{0}' was malformed and could not be parsed. + /// + internal static string InvalidJsonPatchDocument + { + get { return GetString("InvalidJsonPatchDocument"); } + } + + /// + /// The type '{0}' was malformed and could not be parsed. + /// + internal static string FormatInvalidJsonPatchDocument(object p0) + { + return string.Format(CultureInfo.CurrentCulture, GetString("InvalidJsonPatchDocument"), p0); + } + + /// + /// For operation '{0}', the provided path is invalid for array property at path '{1}'. + /// + internal static string InvalidPathForArrayProperty + { + get { return GetString("InvalidPathForArrayProperty"); } + } + + /// + /// For operation '{0}', the provided path is invalid for array property at path '{1}'. + /// + internal static string FormatInvalidPathForArrayProperty(object p0, object p1) + { + return string.Format(CultureInfo.CurrentCulture, GetString("InvalidPathForArrayProperty"), p0, p1); + } + + /// + /// The provided string '{0}' is an invalid path. + /// + internal static string InvalidValueForPath + { + get { return GetString("InvalidValueForPath"); } + } + + /// + /// The provided string '{0}' is an invalid path. + /// + internal static string FormatInvalidValueForPath(object p0) + { + return string.Format(CultureInfo.CurrentCulture, GetString("InvalidValueForPath"), p0); + } + + /// + /// The value '{0}' is invalid for property at path '{1}'. + /// + internal static string InvalidValueForProperty + { + get { return GetString("InvalidValueForProperty"); } + } + + /// + /// The value '{0}' is invalid for property at path '{1}'. + /// + internal static string FormatInvalidValueForProperty(object p0, object p1) + { + return string.Format(CultureInfo.CurrentCulture, GetString("InvalidValueForProperty"), p0, p1); + } + + /// + /// For operation '{0}' on array property at path '{1}', the index is negative. + /// + internal static string NegativeIndexForArrayProperty + { + get { return GetString("NegativeIndexForArrayProperty"); } + } + + /// + /// For operation '{0}' on array property at path '{1}', the index is negative. + /// + internal static string FormatNegativeIndexForArrayProperty(object p0, object p1) + { + return string.Format(CultureInfo.CurrentCulture, GetString("NegativeIndexForArrayProperty"), p0, p1); + } + + /// + /// '{0}' must be of type '{1}'. + /// + internal static string ParameterMustMatchType + { + get { return GetString("ParameterMustMatchType"); } + } + + /// + /// '{0}' must be of type '{1}'. + /// + internal static string FormatParameterMustMatchType(object p0, object p1) + { + return string.Format(CultureInfo.CurrentCulture, GetString("ParameterMustMatchType"), p0, p1); + } + + /// + /// The property at path '{0}' could not be added. + /// + internal static string PropertyCannotBeAdded + { + get { return GetString("PropertyCannotBeAdded"); } + } + + /// + /// The property at path '{0}' could not be added. + /// + internal static string FormatPropertyCannotBeAdded(object p0) + { + return string.Format(CultureInfo.CurrentCulture, GetString("PropertyCannotBeAdded"), p0); + } + + /// + /// The property at path '{0}' could not be removed. + /// + internal static string PropertyCannotBeRemoved + { + get { return GetString("PropertyCannotBeRemoved"); } + } + + /// + /// The property at path '{0}' could not be removed. + /// + internal static string FormatPropertyCannotBeRemoved(object p0) + { + return string.Format(CultureInfo.CurrentCulture, GetString("PropertyCannotBeRemoved"), p0); + } + + /// + /// Property does not exist at path '{0}'. + /// + internal static string PropertyDoesNotExist + { + get { return GetString("PropertyDoesNotExist"); } + } + + /// + /// Property does not exist at path '{0}'. + /// + internal static string FormatPropertyDoesNotExist(object p0) + { + return string.Format(CultureInfo.CurrentCulture, GetString("PropertyDoesNotExist"), p0); + } + + /// + /// The test operation is not supported. + /// + internal static string TestOperationNotSupported + { + get { return GetString("TestOperationNotSupported"); } + } + + /// + /// The test operation is not supported. + /// + internal static string FormatTestOperationNotSupported() + { + return GetString("TestOperationNotSupported"); + } + + 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/Microsoft.AspNet.JsonPatch/Resources.resx b/src/Microsoft.AspNet.JsonPatch/Resources.resx new file mode 100644 index 0000000000..59ae2b59c3 --- /dev/null +++ b/src/Microsoft.AspNet.JsonPatch/Resources.resx @@ -0,0 +1,165 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 type of the property at path '{0}' could not be determined. + + + The property at '{0}' could not be read. + + + The property at path '{0}' could not be updated. + + + The key '{0}' was not found. + + + For operation '{0}' on array property at path '{1}', the index is larger than the array size. + + + The type '{0}' was malformed and could not be parsed. + + + For operation '{0}', the provided path is invalid for array property at path '{1}'. + + + The provided string '{0}' is an invalid path. + + + The value '{0}' is invalid for property at path '{1}'. + + + For operation '{0}' on array property at path '{1}', the index is negative. + + + '{0}' must be of type '{1}'. + + + The property at path '{0}' could not be added. + + + The property at path '{0}' could not be removed. + + + Property does not exist at path '{0}'. + + + The test operation is not supported. + + \ No newline at end of file diff --git a/src/Microsoft.AspNet.JsonPatch/project.json b/src/Microsoft.AspNet.JsonPatch/project.json new file mode 100644 index 0000000000..8d67ec1808 --- /dev/null +++ b/src/Microsoft.AspNet.JsonPatch/project.json @@ -0,0 +1,25 @@ +{ + "version": "1.0.0-*", + "repository": { + "type": "git", + "url": "git://github.com/aspnet/mvc" + }, + "dependencies": { + "Newtonsoft.Json": "6.0.6" + }, + "frameworks": { + "dnx451": { }, + "dnxcore50": { + "dependencies": { + "Microsoft.CSharp": "4.0.1-beta-*", + "System.Collections.Concurrent": "4.0.11-beta-*", + "System.ComponentModel.TypeConverter": "4.0.1-beta-*", + "System.Globalization": "4.0.11-beta-*", + "System.Reflection.Extensions": "4.0.1-beta-*", + "System.Resources.ResourceManager": "4.0.1-beta-*", + "System.Runtime.Extensions": "4.0.11-beta-*", + "System.Text.Encoding.Extensions": "4.0.11-beta-*" + } + } + } +} diff --git a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/AddOperationTests.cs b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/AddOperationTests.cs new file mode 100644 index 0000000000..3c2523c5fb --- /dev/null +++ b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/AddOperationTests.cs @@ -0,0 +1,569 @@ +// Copyright (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.AspNet.JsonPatch.Exceptions; +using Newtonsoft.Json; +using Xunit; + +namespace Microsoft.AspNet.JsonPatch.Test.Dynamic +{ + public class AddOperationTests + { + [Fact] + public void AddNewPropertyShouldFailIfRootIsNotAnExpandoObject() + { + dynamic doc = new + { + Test = 1 + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Add("NewInt", 1); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + var exception = Assert.Throws(() => + { + deserialized.ApplyTo(doc); + }); + Assert.Equal( + "The property at path '/NewInt' could not be added.", + exception.Message); + } + + [Fact] + public void AddNewProperty() + { + dynamic obj = new ExpandoObject(); + obj.Test = 1; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Add("NewInt", 1); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(obj); + + Assert.Equal(1, obj.NewInt); + Assert.Equal(1, obj.Test); + } + + [Fact] + public void AddNewPropertyToNestedAnonymousObjectShouldFail() + { + dynamic doc = new + { + Test = 1, + nested = new { } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Add("Nested/NewInt", 1); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + var exception = Assert.Throws(() => + { + deserialized.ApplyTo(doc); + }); + Assert.Equal( + "The property at path '/Nested/NewInt' could not be added.", + exception.Message); + } + + [Fact] + public void AddNewPropertyToTypedObjectShouldFail() + { + dynamic doc = new + { + Test = 1, + nested = new NestedDTO() + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Add("Nested/NewInt", 1); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + var exception = Assert.Throws(() => + { + deserialized.ApplyTo(doc); + }); + Assert.Equal( + "The property at path '/Nested/NewInt' could not be added.", + exception.Message); + } + + [Fact] + public void AddToExistingPropertyOnNestedObject() + { + dynamic doc = new + { + Test = 1, + nested = new NestedDTO() + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Add("Nested/StringProperty", "A"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal("A", doc.nested.StringProperty); + Assert.Equal(1, doc.Test); + } + + [Fact] + public void AddNewPropertyToExpandoOject() + { + dynamic doc = new + { + Test = 1, + nested = new ExpandoObject() + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Add("Nested/NewInt", 1); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(1, doc.nested.NewInt); + Assert.Equal(1, doc.Test); + } + + [Fact] + public void AddNewPropertyToExpandoOjectInTypedObject() + { + var doc = new NestedDTO() + { + DynamicProperty = new ExpandoObject() + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Add("DynamicProperty/NewInt", 1); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(1, doc.DynamicProperty.NewInt); + } + + [Fact] + public void AddNewPropertyToTypedObjectInExpandoObject() + { + dynamic dynamicProperty = new ExpandoObject(); + dynamicProperty.StringProperty = "A"; + + var doc = new NestedDTO() + { + DynamicProperty = dynamicProperty + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Add("DynamicProperty/StringProperty", "B"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal("B", doc.DynamicProperty.StringProperty); + } + + [Fact] + public void AddNewPropertyToAnonymousObjectShouldFail() + { + dynamic doc = new + { + Test = 1 + }; + + dynamic valueToAdd = new { IntValue = 1, StringValue = "test", GuidValue = Guid.NewGuid() }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Add("ComplexProperty", valueToAdd); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + var exception = Assert.Throws(() => + { + deserialized.ApplyTo(doc); + }); + Assert.Equal( + "The property at path '/ComplexProperty' could not be added.", + exception.Message); + } + + [Fact] + public void AddResultsReplaceShouldFailOnAnonymousDueToNoSetter() + { + var doc = new + { + StringProperty = "A" + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Add("StringProperty", "B"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + var exception = Assert.Throws(() => + { + deserialized.ApplyTo(doc); + }); + Assert.Equal( + "The property at path '/StringProperty' could not be updated.", + exception.Message); + } + + [Fact] + public void AddResultsShouldReplace() + { + dynamic doc = new ExpandoObject(); + doc.StringProperty = "A"; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Add("StringProperty", "B"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal("B", doc.StringProperty); + } + + [Fact] + public void AddResultsShouldReplaceInNested() + { + dynamic doc = new ExpandoObject(); + doc.InBetweenFirst = new ExpandoObject(); + doc.InBetweenFirst.InBetweenSecond = new ExpandoObject(); + doc.InBetweenFirst.InBetweenSecond.StringProperty = "A"; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Add("/InBetweenFirst/InBetweenSecond/StringProperty", "B"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal("B", doc.InBetweenFirst.InBetweenSecond.StringProperty); + } + + [Fact] + public void AddResultsShouldReplaceInNestedInDynamic() + { + dynamic doc = new ExpandoObject(); + doc.Nested = new NestedDTO(); + doc.Nested.DynamicProperty = new ExpandoObject(); + doc.Nested.DynamicProperty.InBetweenFirst = new ExpandoObject(); + doc.Nested.DynamicProperty.InBetweenFirst.InBetweenSecond = new ExpandoObject(); + doc.Nested.DynamicProperty.InBetweenFirst.InBetweenSecond.StringProperty = "A"; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Add("/Nested/DynamicProperty/InBetweenFirst/InBetweenSecond/StringProperty", "B"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal("B", doc.Nested.DynamicProperty.InBetweenFirst.InBetweenSecond.StringProperty); + } + + [Fact] + public void ShouldNotBeAbleToAddToNonExistingPropertyThatIsNotTheRoot() + { + //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. + + var doc = new NestedDTO() + { + DynamicProperty = new ExpandoObject() + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Add("DynamicProperty/OtherProperty/IntProperty", 1); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + var exception = Assert.Throws(() => + { + deserialized.ApplyTo(doc); + }); + Assert.Equal( + "The property at path '/DynamicProperty/OtherProperty/IntProperty' could not be added.", + exception.Message); + } + + [Fact] + public void ShouldNotBeAbleToAddToNonExistingPropertyInNestedPropertyThatIsNotTheRoot() + { + //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. + + var doc = new + { + Foo = "bar" + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Add("baz/bat", "qux"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + var exception = Assert.Throws(() => + { + deserialized.ApplyTo(doc); + }); + Assert.Equal( + "The property at path '/baz/bat' could not be added.", + exception.Message); + } + + [Fact] + public void ShouldReplacePropertyWithDifferentCase() + { + dynamic doc = new ExpandoObject(); + doc.StringProperty = "A"; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Add("stringproperty", "B"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal("B", doc.StringProperty); + } + + [Fact] + public void AddToList() + { + var doc = new + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Add("IntegerList/0", 4); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 4, 1, 2, 3 }, doc.IntegerList); + } + + [Fact] + public void AddToListNegativePosition() + { + dynamic doc = new ExpandoObject(); + doc.IntegerList = new List() { 1, 2, 3 }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Add("IntegerList/-1", 4); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + var exception = Assert.Throws(() => + { + deserialized.ApplyTo(doc); + }); + Assert.Equal( + "For operation 'add' on array property at path '/IntegerList/-1', the index is negative.", + exception.Message); + } + + [Fact] + public void ShouldAddToListWithDifferentCase() + { + var doc = new + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Add("integerlist/0", 4); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 4, 1, 2, 3 }, doc.IntegerList); + } + + [Fact] + public void AddToListInvalidPositionTooLarge() + { + var doc = new + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Add("IntegerList/4", 4); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + var exception = Assert.Throws(() => + { + deserialized.ApplyTo(doc); + }); + Assert.Equal( + "For operation 'add' on array property at path '/IntegerList/4', the index is larger than the array size.", + exception.Message); + } + + [Fact] + public void AddToListAtEndWithSerialization() + { + var doc = new + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Add("IntegerList/3", 4); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 1, 2, 3, 4 }, doc.IntegerList); + } + + [Fact] + public void AddToListAtBeginning() + { + var doc = new + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Add("IntegerList/0", 4); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 4, 1, 2, 3 }, doc.IntegerList); + } + + [Fact] + public void AddToListInvalidPositionTooSmall() + { + var doc = new + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Add("IntegerList/-1", 4); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + var exception = Assert.Throws(() => + { + deserialized.ApplyTo(doc); + }); + Assert.Equal( + "For operation 'add' on array property at path '/IntegerList/-1', the index is negative.", + exception.Message); + } + + [Fact] + public void AddToListAppend() + { + var doc = new + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Add("IntegerList/-", 4); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 1, 2, 3, 4 }, doc.IntegerList); + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/AddTypedOperationTests.cs b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/AddTypedOperationTests.cs new file mode 100644 index 0000000000..4d2e8c646d --- /dev/null +++ b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/AddTypedOperationTests.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.Collections.Generic; +using Microsoft.AspNet.JsonPatch.Exceptions; +using Newtonsoft.Json; +using Xunit; + +namespace Microsoft.AspNet.JsonPatch.Test.Dynamic +{ + public class AddTypedOperationTests + { + [Fact] + public void AddToListNegativePosition() + { + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Add("IntegerList/-1", 4); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + var exception = Assert.Throws(() => + { + deserialized.ApplyTo(doc); + }); + Assert.Equal( + "For operation 'add' on array property at path '/IntegerList/-1', the index is negative.", + exception.Message); + } + + [Fact] + public void AddToListInList() + { + var doc = new SimpleDTOWithNestedDTO() + { + ListOfSimpleDTO = new List() + { + new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Add("ListOfSimpleDTO/0/IntegerList/0", 4); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + Assert.Equal(new List() { 4, 1, 2, 3 }, doc.ListOfSimpleDTO[0].IntegerList); + } + + [Fact] + public void AddToListInListInvalidPositionTooSmall() + { + var doc = new SimpleDTOWithNestedDTO() + { + ListOfSimpleDTO = new List() + { + new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Add("ListOfSimpleDTO/-1/IntegerList/0", 4); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + var exception = Assert.Throws(() => + { + deserialized.ApplyTo(doc); + }); + Assert.Equal( + "The property at path '/ListOfSimpleDTO/-1/IntegerList/0' could not be added.", + exception.Message); + } + + [Fact] + public void AddToListInListInvalidPositionTooLarge() + { + var doc = new SimpleDTOWithNestedDTO() + { + ListOfSimpleDTO = new List() + { + new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + } + }; + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Add("ListOfSimpleDTO/20/IntegerList/0", 4); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + var exception = Assert.Throws(() => + { + deserialized.ApplyTo(doc); + }); + Assert.Equal( + "The property at path '/ListOfSimpleDTO/20/IntegerList/0' could not be added.", + exception.Message); + } + } +} diff --git a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/CopyOperationTests.cs b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/CopyOperationTests.cs new file mode 100644 index 0000000000..3fa546faac --- /dev/null +++ b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/CopyOperationTests.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 System.Dynamic; +using Newtonsoft.Json; +using Xunit; + +namespace Microsoft.AspNet.JsonPatch.Test.Dynamic +{ + public class CopyOperationTests + { + [Fact] + public void Copy() + { + dynamic doc = new ExpandoObject(); + + doc.StringProperty = "A"; + doc.AnotherStringProperty = "B"; + + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Copy("StringProperty", "AnotherStringProperty"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + deserialized.ApplyTo(doc); + + Assert.Equal("A", doc.AnotherStringProperty); + } + + [Fact] + public void CopyInList() + { + dynamic doc = new ExpandoObject(); + doc.IntegerList = new List() { 1, 2, 3 }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Copy("IntegerList/0", "IntegerList/1"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 1, 1, 2, 3 }, doc.IntegerList); + } + + [Fact] + public void CopyFromListToEndOfList() + { + dynamic doc = new ExpandoObject(); + doc.IntegerList = new List() { 1, 2, 3 }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Copy("IntegerList/0", "IntegerList/-"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 1, 2, 3, 1 }, doc.IntegerList); + } + + [Fact] + public void CopyFromListToNonList() + { + dynamic doc = new ExpandoObject(); + doc.IntegerList = new List() { 1, 2, 3 }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Copy("IntegerList/0", "IntegerValue"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(1, doc.IntegerValue); + } + + [Fact] + public void CopyFromNonListToList() + { + dynamic doc = new ExpandoObject(); + doc.IntegerValue = 5; + doc.IntegerList = new List() { 1, 2, 3 }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Copy("IntegerValue", "IntegerList/0"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 5, 1, 2, 3 }, doc.IntegerList); + } + + [Fact] + public void CopyToEndOfList() + { + dynamic doc = new ExpandoObject(); + doc.IntegerValue = 5; + doc.IntegerList = new List() { 1, 2, 3 }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Copy("IntegerValue", "IntegerList/-"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 1, 2, 3, 5 }, doc.IntegerList); + } + + [Fact] + public void NestedCopy() + { + dynamic doc = new ExpandoObject(); + doc.SimpleDTO = new SimpleDTO() + { + StringProperty = "A", + AnotherStringProperty = "B" + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Copy("SimpleDTO/StringProperty", "SimpleDTO/AnotherStringProperty"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal("A", doc.SimpleDTO.AnotherStringProperty); + } + + [Fact] + public void NestedCopyInList() + { + dynamic doc = new ExpandoObject(); + doc.SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Copy("SimpleDTO/IntegerList/0", "SimpleDTO/IntegerList/1"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 1, 1, 2, 3 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void NestedCopyFromListToEndOfList() + { + dynamic doc = new ExpandoObject(); + doc.SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Copy("SimpleDTO/IntegerList/0", "SimpleDTO/IntegerList/-"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 1, 2, 3, 1 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void NestedCopyFromListToNonList() + { + dynamic doc = new ExpandoObject(); + doc.SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Copy("SimpleDTO/IntegerList/0", "SimpleDTO/IntegerValue"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + deserialized.ApplyTo(doc); + + Assert.Equal(1, doc.SimpleDTO.IntegerValue); + } + + [Fact] + public void NestedCopyFromNonListToList() + { + dynamic doc = new ExpandoObject(); + doc.SimpleDTO = new SimpleDTO() + { + IntegerValue = 5, + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Copy("SimpleDTO/IntegerValue", "SimpleDTO/IntegerList/0"); + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 5, 1, 2, 3 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void NestedCopyToEndOfList() + { + dynamic doc = new ExpandoObject(); + doc.SimpleDTO = new SimpleDTO() + { + IntegerValue = 5, + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Copy("SimpleDTO/IntegerValue", "SimpleDTO/IntegerList/-"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 1, 2, 3, 5 }, doc.SimpleDTO.IntegerList); + } + } +} diff --git a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/CopyTypedOperationTests.cs b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/CopyTypedOperationTests.cs new file mode 100644 index 0000000000..5b015416ac --- /dev/null +++ b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/CopyTypedOperationTests.cs @@ -0,0 +1,268 @@ +// Copyright (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 Xunit; + +namespace Microsoft.AspNet.JsonPatch.Test.Dynamic +{ + public class CopyTypedOperationTests + { + [Fact] + public void Copy() + { + var doc = new SimpleDTO() + { + StringProperty = "A", + AnotherStringProperty = "B" + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Copy("StringProperty", "AnotherStringProperty"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + deserialized.ApplyTo(doc); + + Assert.Equal("A", doc.AnotherStringProperty); + } + + [Fact] + public void CopyInList() + { + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Copy("IntegerList/0", "IntegerList/1"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 1, 1, 2, 3 }, doc.IntegerList); + } + + [Fact] + public void CopyFromListToEndOfList() + { + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Copy("IntegerList/0", "IntegerList/-"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 1, 2, 3, 1 }, doc.IntegerList); + } + + [Fact] + public void CopyFromListToNonList() + { + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Copy("IntegerList/0", "IntegerValue"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(1, doc.IntegerValue); + } + + [Fact] + public void CopyFromNonListToList() + { + var doc = new SimpleDTO() + { + IntegerValue = 5, + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Copy("IntegerValue", "IntegerList/0"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 5, 1, 2, 3 }, doc.IntegerList); + } + + [Fact] + public void CopyToEndOfList() + { + var doc = new SimpleDTO() + { + IntegerValue = 5, + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Copy("IntegerValue", "IntegerList/-"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 1, 2, 3, 5 }, doc.IntegerList); + } + + [Fact] + public void NestedCopy() + { + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + StringProperty = "A", + AnotherStringProperty = "B" + } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Copy("SimpleDTO/StringProperty", "SimpleDTO/AnotherStringProperty"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal("A", doc.SimpleDTO.AnotherStringProperty); + } + + [Fact] + public void NestedCopyInList() + { + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Copy("SimpleDTO/IntegerList/0", "SimpleDTO/IntegerList/1"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 1, 1, 2, 3 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void NestedCopyFromListToEndOfList() + { + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Copy("SimpleDTO/IntegerList/0", "SimpleDTO/IntegerList/-"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 1, 2, 3, 1 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void NestedCopyFromListToNonList() + { + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Copy("SimpleDTO/IntegerList/0", "SimpleDTO/IntegerValue"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + deserialized.ApplyTo(doc); + + Assert.Equal(1, doc.SimpleDTO.IntegerValue); + } + + [Fact] + public void NestedCopyFromNonListToList() + { + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerValue = 5, + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Copy("SimpleDTO/IntegerValue", "SimpleDTO/IntegerList/0"); + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 5, 1, 2, 3 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void NestedCopyToEndOfList() + { + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerValue = 5, + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Copy("SimpleDTO/IntegerValue", "SimpleDTO/IntegerList/-"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 1, 2, 3, 5 }, doc.SimpleDTO.IntegerList); + } + } +} diff --git a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/MoveOperationTests.cs b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/MoveOperationTests.cs new file mode 100644 index 0000000000..dea2b6ee32 --- /dev/null +++ b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/MoveOperationTests.cs @@ -0,0 +1,338 @@ +// Copyright (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; +using Xunit; + +namespace Microsoft.AspNet.JsonPatch.Test.Dynamic +{ + public class MoveOperationTests + { + [Fact] + public void Move() + { + dynamic doc = new ExpandoObject(); + doc.StringProperty = "A"; + doc.AnotherStringProperty = "B"; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Move("StringProperty", "AnotherStringProperty"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal("A", doc.AnotherStringProperty); + + var cont = doc as IDictionary; + object valueFromDictionary; + cont.TryGetValue("StringProperty", out valueFromDictionary); + Assert.Null(valueFromDictionary); + } + + [Fact] + public void MoveToNonExisting() + { + dynamic doc = new ExpandoObject(); + doc.StringProperty = "A"; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Move("StringProperty", "AnotherStringProperty"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal("A", doc.AnotherStringProperty); + + var cont = doc as IDictionary; + object valueFromDictionary; + cont.TryGetValue("StringProperty", out valueFromDictionary); + Assert.Null(valueFromDictionary); + } + + [Fact] + public void MoveDynamicToTyped() + { + dynamic doc = new ExpandoObject(); + doc.StringProperty = "A"; + doc.SimpleDTO = new SimpleDTO() { AnotherStringProperty = "B" }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Move("StringProperty", "SimpleDTO/AnotherStringProperty"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal("A", doc.SimpleDTO.AnotherStringProperty); + + var cont = doc as IDictionary; + object valueFromDictionary; + cont.TryGetValue("StringProperty", out valueFromDictionary); + Assert.Null(valueFromDictionary); + } + + [Fact] + public void MoveTypedToDynamic() + { + dynamic doc = new ExpandoObject(); + doc.StringProperty = "A"; + doc.SimpleDTO = new SimpleDTO() { AnotherStringProperty = "B" }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Move("SimpleDTO/AnotherStringProperty", "StringProperty"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal("B", doc.StringProperty); + Assert.Equal(null, doc.SimpleDTO.AnotherStringProperty); + } + + [Fact] + public void NestedMove() + { + dynamic doc = new ExpandoObject(); + doc.Nested = new SimpleDTO() + { + StringProperty = "A", + AnotherStringProperty = "B" + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Move("Nested/StringProperty", "Nested/AnotherStringProperty"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal("A", doc.Nested.AnotherStringProperty); + Assert.Equal(null, doc.Nested.StringProperty); + } + + [Fact] + public void MoveInList() + { + dynamic doc = new ExpandoObject(); + doc.IntegerList = new List() { 1, 2, 3 }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Move("IntegerList/0", "IntegerList/1"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 2, 1, 3 }, doc.IntegerList); + } + + [Fact] + public void NestedMoveInList() + { + dynamic doc = new ExpandoObject(); + doc.Nested = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Move("Nested/IntegerList/0", "Nested/IntegerList/1"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 2, 1, 3 }, doc.Nested.IntegerList); + } + + [Fact] + public void MoveFromListToEndOfList() + { + dynamic doc = new ExpandoObject(); + doc.IntegerList = new List() { 1, 2, 3 }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Move("IntegerList/0", "IntegerList/-"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 2, 3, 1 }, doc.IntegerList); + } + + [Fact] + public void NestedMoveFromListToEndOfList() + { + dynamic doc = new ExpandoObject(); + doc.Nested = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Move("Nested/IntegerList/0", "Nested/IntegerList/-"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 2, 3, 1 }, doc.Nested.IntegerList); + } + + [Fact] + public void MoveFomListToNonList() + { + dynamic doc = new ExpandoObject(); + doc.IntegerList = new List() { 1, 2, 3 }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Move("IntegerList/0", "IntegerValue"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 2, 3 }, doc.IntegerList); + Assert.Equal(1, doc.IntegerValue); + } + + [Fact] + public void NestedMoveFomListToNonList() + { + dynamic doc = new ExpandoObject(); + doc.Nested = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Move("Nested/IntegerList/0", "Nested/IntegerValue"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 2, 3 }, doc.Nested.IntegerList); + Assert.Equal(1, doc.Nested.IntegerValue); + } + + [Fact] + public void MoveFromNonListToList() + { + dynamic doc = new ExpandoObject(); + doc.IntegerValue = 5; + doc.IntegerList = new List() { 1, 2, 3 }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Move("IntegerValue", "IntegerList/0"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + var cont = doc as IDictionary; + object valueFromDictionary; + cont.TryGetValue("IntegerValue", out valueFromDictionary); + Assert.Null(valueFromDictionary); + + Assert.Equal(new List() { 5, 1, 2, 3 }, doc.IntegerList); + } + + [Fact] + public void NestedMoveFromNonListToList() + { + dynamic doc = new ExpandoObject(); + doc.Nested = new SimpleDTO() + { + IntegerValue = 5, + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Move("Nested/IntegerValue", "Nested/IntegerList/0"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(0, doc.Nested.IntegerValue); + Assert.Equal(new List() { 5, 1, 2, 3 }, doc.Nested.IntegerList); + } + + [Fact] + public void MoveToEndOfList() + { + dynamic doc = new ExpandoObject(); + doc.IntegerValue = 5; + doc.IntegerList = new List() { 1, 2, 3 }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Move("IntegerValue", "IntegerList/-"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + var cont = doc as IDictionary; + object valueFromDictionary; + cont.TryGetValue("IntegerValue", out valueFromDictionary); + Assert.Null(valueFromDictionary); + + Assert.Equal(new List() { 1, 2, 3, 5 }, doc.IntegerList); + } + + [Fact] + public void NestedMoveToEndOfList() + { + dynamic doc = new ExpandoObject(); + doc.Nested = new SimpleDTO() + { + IntegerValue = 5, + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Move("Nested/IntegerValue", "Nested/IntegerList/-"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(0, doc.Nested.IntegerValue); + Assert.Equal(new List() { 1, 2, 3, 5 }, doc.Nested.IntegerList); + } + } +} diff --git a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/MoveTypedOperationTests.cs b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/MoveTypedOperationTests.cs new file mode 100644 index 0000000000..3d356a3401 --- /dev/null +++ b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/MoveTypedOperationTests.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.Collections.Generic; +using Newtonsoft.Json; +using Xunit; + +namespace Microsoft.AspNet.JsonPatch.Test.Dynamic +{ + public class MoveTypedOperationTests + { + [Fact] + public void Move() + { + var doc = new SimpleDTO() + { + StringProperty = "A", + AnotherStringProperty = "B" + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Move("StringProperty", "AnotherStringProperty"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal("A", doc.AnotherStringProperty); + Assert.Equal(null, doc.StringProperty); + } + + [Fact] + public void MoveInList() + { + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Move("IntegerList/0", "IntegerList/1"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 2, 1, 3 }, doc.IntegerList); + } + + [Fact] + public void MoveFromListToEndOfList() + { + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Move("IntegerList/0", "IntegerList/-"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 2, 3, 1 }, doc.IntegerList); + } + + [Fact] + public void MoveFomListToNonList() + { + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Move("IntegerList/0", "IntegerValue"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 2, 3 }, doc.IntegerList); + Assert.Equal(1, doc.IntegerValue); + } + + [Fact] + public void MoveFromNonListToList() + { + var doc = new SimpleDTO() + { + IntegerValue = 5, + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Move("IntegerValue", "IntegerList/0"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(0, doc.IntegerValue); + Assert.Equal(new List() { 5, 1, 2, 3 }, doc.IntegerList); + } + + [Fact] + public void MoveToEndOfList() + { + var doc = new SimpleDTO() + { + IntegerValue = 5, + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Move("IntegerValue", "IntegerList/-"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(0, doc.IntegerValue); + Assert.Equal(new List() { 1, 2, 3, 5 }, doc.IntegerList); + } + } +} diff --git a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/NestedDTO.cs b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/NestedDTO.cs new file mode 100644 index 0000000000..4d30cf60f2 --- /dev/null +++ b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/NestedDTO.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.AspNet.JsonPatch.Test.Dynamic +{ + public class NestedDTO + { + public string StringProperty { get; set; } + public dynamic DynamicProperty { get; set; } + } +} diff --git a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/PatchDocumentTests.cs b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/PatchDocumentTests.cs new file mode 100644 index 0000000000..e15f85da8e --- /dev/null +++ b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/PatchDocumentTests.cs @@ -0,0 +1,95 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.AspNet.JsonPatch.Exceptions; +using Newtonsoft.Json; +using Xunit; + +namespace Microsoft.AspNet.JsonPatch.Test.Dynamic +{ + public class PatchDocumentTests + { + [Fact] + public void InvalidPathAtBeginningShouldThrowException() + { + JsonPatchDocument patchDoc = new JsonPatchDocument(); + var exception = Assert.Throws(() => + { + patchDoc.Add("//NewInt", 1); + }); + Assert.Equal( + "The provided string '//NewInt' is an invalid path.", + exception.Message); + } + + [Fact] + public void InvalidPathAtEndShouldThrowException() + { + JsonPatchDocument patchDoc = new JsonPatchDocument(); + var exception = Assert.Throws(() => + { + patchDoc.Add("NewInt//", 1); + }); + Assert.Equal( + "The provided string 'NewInt//' is an invalid path.", + exception.Message); + } + + [Fact] + public void InvalidPathWithDotShouldThrowException() + { + JsonPatchDocument patchDoc = new JsonPatchDocument(); + var exception = Assert.Throws(() => + { + patchDoc.Add("NewInt.Test", 1); + }); + Assert.Equal( + "The provided string 'NewInt.Test' is an invalid path.", + exception.Message); + } + + [Fact] + public void NonGenericPatchDocToGenericMustSerialize() + { + var doc = new SimpleDTO() + { + StringProperty = "A", + AnotherStringProperty = "B" + }; + + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Copy("StringProperty", "AnotherStringProperty"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal("A", doc.AnotherStringProperty); + } + + [Fact] + public void GenericPatchDocToNonGenericMustSerialize() + { + var doc = new SimpleDTO() + { + StringProperty = "A", + AnotherStringProperty = "B" + }; + + JsonPatchDocument patchDocTyped = new JsonPatchDocument(); + patchDocTyped.Copy(o => o.StringProperty, o => o.AnotherStringProperty); + + JsonPatchDocument patchDocUntyped = new JsonPatchDocument(); + patchDocUntyped.Copy("StringProperty", "AnotherStringProperty"); + + var serializedTyped = JsonConvert.SerializeObject(patchDocTyped); + var serializedUntyped = JsonConvert.SerializeObject(patchDocUntyped); + var deserialized = JsonConvert.DeserializeObject(serializedTyped); + + deserialized.ApplyTo(doc); + + Assert.Equal("A", doc.AnotherStringProperty); + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/RemoveOperationTests.cs b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/RemoveOperationTests.cs new file mode 100644 index 0000000000..9ef28ad7cc --- /dev/null +++ b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/RemoveOperationTests.cs @@ -0,0 +1,302 @@ +// Copyright (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 Microsoft.AspNet.JsonPatch.Exceptions; +using Newtonsoft.Json; +using Xunit; + +namespace Microsoft.AspNet.JsonPatch.Test.Dynamic +{ + public class RemoveOperationTests + { + [Fact] + public void RemovePropertyShouldFailIfRootIsAnonymous() + { + dynamic doc = new + { + Test = 1 + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Remove("Test"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + var exception = Assert.Throws(() => + { + deserialized.ApplyTo(doc); + }); + Assert.Equal( + "The property at path '/Test' could not be updated.", + exception.Message); + } + + [Fact] + public void RemovePropertyShouldFailIfItDoesntExist() + { + dynamic doc = new ExpandoObject(); + doc.Test = 1; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Remove("NonExisting"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + var exception = Assert.Throws(() => + { + deserialized.ApplyTo(doc); + }); + Assert.Equal( + "The property at path '/NonExisting' could not be removed.", + exception.Message); + } + + [Fact] + public void RemovePropertyFromExpandoObject() + { + dynamic obj = new ExpandoObject(); + obj.Test = 1; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Remove("Test"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(obj); + + var cont = obj as IDictionary; + object valueFromDictionary; + + cont.TryGetValue("Test", out valueFromDictionary); + Assert.Null(valueFromDictionary); + } + + [Fact] + public void RemovePropertyFromExpandoObjectMixedCase() + { + dynamic obj = new ExpandoObject(); + obj.Test = 1; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Remove("test"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(obj); + + var cont = obj as IDictionary; + object valueFromDictionary; + + cont.TryGetValue("Test", out valueFromDictionary); + Assert.Null(valueFromDictionary); + } + + [Fact] + public void RemoveNestedPropertyFromExpandoObject() + { + dynamic obj = new ExpandoObject(); + obj.Test = new ExpandoObject(); + obj.Test.AnotherTest = "A"; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Remove("Test"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(obj); + + var cont = obj as IDictionary; + object valueFromDictionary; + + cont.TryGetValue("Test", out valueFromDictionary); + Assert.Null(valueFromDictionary); + } + + [Fact] + public void RemoveNestedPropertyFromExpandoObjectMixedCase() + { + dynamic obj = new ExpandoObject(); + obj.Test = new ExpandoObject(); + obj.Test.AnotherTest = "A"; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Remove("test"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(obj); + var cont = obj as IDictionary; + + object valueFromDictionary; + cont.TryGetValue("Test", out valueFromDictionary); + Assert.Null(valueFromDictionary); + } + + [Fact] + public void NestedRemove() + { + dynamic doc = new ExpandoObject(); + doc.SimpleDTO = new SimpleDTO() + { + StringProperty = "A" + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Remove("SimpleDTO/StringProperty"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + Assert.Equal(null, doc.SimpleDTO.StringProperty); + } + + [Fact] + public void NestedRemoveMixedCase() + { + dynamic doc = new ExpandoObject(); + doc.SimpleDTO = new SimpleDTO() + { + StringProperty = "A" + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Remove("Simpledto/stringProperty"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(null, doc.SimpleDTO.StringProperty); + } + + [Fact] + public void NestedRemoveFromList() + { + dynamic doc = new ExpandoObject(); + doc.SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Remove("SimpleDTO/IntegerList/2"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 1, 2 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void NestedRemoveFromListMixedCase() + { + dynamic doc = new ExpandoObject(); + doc.SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Remove("SimpleDTO/Integerlist/2"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 1, 2 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void NestedRemoveFromListInvalidPositionTooLarge() + { + dynamic doc = new ExpandoObject(); + doc.SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Remove("SimpleDTO/IntegerList/3"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + var exception = Assert.Throws(() => + { + deserialized.ApplyTo(doc); + }); + Assert.Equal( + "For operation 'remove' on array property at path '/SimpleDTO/IntegerList/3', the index is larger than the array size.", + exception.Message); + } + + [Fact] + public void NestedRemoveFromListInvalidPositionTooSmall() + { + dynamic doc = new ExpandoObject(); + doc.SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Remove("SimpleDTO/IntegerList/-1"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + var exception = Assert.Throws(() => + { + deserialized.ApplyTo(doc); + }); + Assert.Equal( + "For operation 'remove' on array property at path '/SimpleDTO/IntegerList/-1', the index is negative.", + exception.Message); + } + + [Fact] + public void NestedRemoveFromEndOfList() + { + dynamic doc = new ExpandoObject(); + doc.SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Remove("SimpleDTO/IntegerList/-"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + Assert.Equal(new List() { 1, 2 }, doc.SimpleDTO.IntegerList); + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/RemoveTypedOperationTests.cs b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/RemoveTypedOperationTests.cs new file mode 100644 index 0000000000..db5d6502d1 --- /dev/null +++ b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/RemoveTypedOperationTests.cs @@ -0,0 +1,244 @@ +// Copyright (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.AspNet.JsonPatch.Exceptions; +using Newtonsoft.Json; +using Xunit; + +namespace Microsoft.AspNet.JsonPatch.Test.Dynamic +{ + public class RemoveTypedOperationTests + { + [Fact] + public void Remove() + { + var doc = new SimpleDTO() + { + StringProperty = "A" + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Remove("StringProperty"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(null, doc.StringProperty); + } + + [Fact] + public void RemoveFromList() + { + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Remove("IntegerList/2"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 1, 2 }, doc.IntegerList); + } + + [Fact] + public void RemoveFromListInvalidPositionTooLarge() + { + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Remove("IntegerList/3"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + var exception = Assert.Throws(() => + { + deserialized.ApplyTo(doc); + }); + Assert.Equal( + "For operation 'remove' on array property at path '/IntegerList/3', the index is larger than the array size.", + exception.Message); + } + + [Fact] + public void RemoveFromListInvalidPositionTooSmall() + { + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Remove("IntegerList/-1"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + var exception = Assert.Throws(() => + { + deserialized.ApplyTo(doc); + }); + Assert.Equal( + "For operation 'remove' on array property at path '/IntegerList/-1', the index is negative.", + exception.Message); + } + + [Fact] + public void RemoveFromEndOfList() + { + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Remove("IntegerList/-"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 1, 2 }, doc.IntegerList); + } + + [Fact] + public void NestedRemove() + { + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + StringProperty = "A" + } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Remove("SimpleDTO/StringProperty"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(null, doc.SimpleDTO.StringProperty); + } + + [Fact] + public void NestedRemoveFromList() + { + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Remove("SimpleDTO/IntegerList/2"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 1, 2 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void NestedRemoveFromListInvalidPositionTooLarge() + { + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Remove("SimpleDTO/IntegerList/3"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + var exception = Assert.Throws(() => + { + deserialized.ApplyTo(doc); + }); + Assert.Equal( + "For operation 'remove' on array property at path '/SimpleDTO/IntegerList/3', the index is larger than the array size.", + exception.Message); + } + + [Fact] + public void NestedRemoveFromListInvalidPositionTooSmall() + { + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Remove("SimpleDTO/IntegerList/-1"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + var exception = Assert.Throws(() => + { + deserialized.ApplyTo(doc); + }); + Assert.Equal( + "For operation 'remove' on array property at path '/SimpleDTO/IntegerList/-1', the index is negative.", + exception.Message); + } + + [Fact] + public void NestedRemoveFromEndOfList() + { + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Remove("SimpleDTO/IntegerList/-"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 1, 2 }, doc.SimpleDTO.IntegerList); + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/ReplaceOperationTests.cs b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/ReplaceOperationTests.cs new file mode 100644 index 0000000000..c7573c0286 --- /dev/null +++ b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/ReplaceOperationTests.cs @@ -0,0 +1,242 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Dynamic; +using Newtonsoft.Json; +using Xunit; + +namespace Microsoft.AspNet.JsonPatch.Test.Dynamic +{ + public class ReplaceOperationTests + { + [Fact] + public void ReplaceGuidTest() + { + dynamic doc = new SimpleDTO() + { + GuidValue = Guid.NewGuid() + }; + + var newGuid = Guid.NewGuid(); + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Replace("GuidValue", newGuid); + + // serialize & deserialize + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserizalized = JsonConvert.DeserializeObject(serialized); + + deserizalized.ApplyTo(doc); + + Assert.Equal(newGuid, doc.GuidValue); + } + + [Fact] + public void ReplaceGuidTestExpandoObject() + { + dynamic doc = new ExpandoObject(); + doc.GuidValue = Guid.NewGuid(); + + var newGuid = Guid.NewGuid(); + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Replace("GuidValue", newGuid); + + // serialize & deserialize + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserizalized = JsonConvert.DeserializeObject(serialized); + + deserizalized.ApplyTo(doc); + + Assert.Equal(newGuid, doc.GuidValue); + } + + [Fact] + public void ReplaceGuidTestExpandoObjectInAnonymous() + { + dynamic nestedObject = new ExpandoObject(); + nestedObject.GuidValue = Guid.NewGuid(); + + dynamic doc = new + { + NestedObject = nestedObject + }; + + var newGuid = Guid.NewGuid(); + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Replace("nestedobject/GuidValue", newGuid); + + // serialize & deserialize + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserizalized = JsonConvert.DeserializeObject(serialized); + + deserizalized.ApplyTo(doc); + + Assert.Equal(newGuid, doc.NestedObject.GuidValue); + } + + [Fact] + public void ReplaceNestedObjectTest() + { + dynamic doc = new ExpandoObject(); + doc.SimpleDTO = new SimpleDTO() + { + IntegerValue = 5, + IntegerList = new List() { 1, 2, 3 } + }; + + var newDTO = new SimpleDTO() + { + DoubleValue = 1 + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Replace("SimpleDTO", newDTO); + + // serialize & deserialize + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(1, doc.SimpleDTO.DoubleValue); + Assert.Equal(0, doc.SimpleDTO.IntegerValue); + Assert.Equal(null, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void ReplaceInList() + { + dynamic doc = new ExpandoObject(); + doc.IntegerList = new List() { 1, 2, 3 }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Replace("IntegerList/0", 5); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 5, 2, 3 }, doc.IntegerList); + } + + [Fact] + public void ReplaceFullList() + { + dynamic doc = new ExpandoObject(); + doc.IntegerList = new List() { 1, 2, 3 }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Replace("IntegerList", new List() { 4, 5, 6 }); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 4, 5, 6 }, doc.IntegerList); + } + + [Fact] + public void ReplaceInListInList() + { + dynamic doc = new ExpandoObject(); + doc.SimpleDTOList = new List() { + new SimpleDTO() { + IntegerList = new List(){1,2,3} + }}; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Replace("SimpleDTOList/0/IntegerList/0", 4); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(4, doc.SimpleDTOList[0].IntegerList[0]); + } + + [Fact] + public void ReplaceInListInListAtEnd() + { + dynamic doc = new ExpandoObject(); + doc.SimpleDTOList = new List() { + new SimpleDTO() { + IntegerList = new List(){1,2,3} + }}; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Replace("SimpleDTOList/0/IntegerList/-", 4); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(4, doc.SimpleDTOList[0].IntegerList[2]); + } + + [Fact] + public void ReplaceFullListFromEnumerable() + { + dynamic doc = new ExpandoObject(); + doc.IntegerList = new List() { 1, 2, 3 }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Replace("IntegerList", new List() { 4, 5, 6 }); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + Assert.Equal(new List() { 4, 5, 6 }, doc.IntegerList); + } + + [Fact] + public void ReplaceFullListWithCollection() + { + dynamic doc = new ExpandoObject(); + doc.IntegerList = new List() { 1, 2, 3 }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Replace("IntegerList", new Collection() { 4, 5, 6 }); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 4, 5, 6 }, doc.IntegerList); + } + + [Fact] + public void ReplaceAtEndOfList() + { + dynamic doc = new ExpandoObject(); + doc.IntegerList = new List() { 1, 2, 3 }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Replace("IntegerList/-", 5); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 1, 2, 5 }, doc.IntegerList); + } + } +} diff --git a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/ReplaceTypedOperationTests.cs b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/ReplaceTypedOperationTests.cs new file mode 100644 index 0000000000..ccdd86f1a7 --- /dev/null +++ b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/ReplaceTypedOperationTests.cs @@ -0,0 +1,191 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using Newtonsoft.Json; +using Xunit; + +namespace Microsoft.AspNet.JsonPatch.Test.Dynamic +{ + public class ReplaceTypedOperationTests + { + [Fact] + public void ReplaceGuidTest() + { + var doc = new SimpleDTO() + { + GuidValue = Guid.NewGuid() + }; + + var newGuid = Guid.NewGuid(); + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Replace("GuidValue", newGuid); + + // serialize & deserialize + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserizalized = JsonConvert.DeserializeObject(serialized); + + deserizalized.ApplyTo(doc); + + Assert.Equal(newGuid, doc.GuidValue); + } + + [Fact] + public void SerializeAndReplaceNestedObjectTest() + { + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerValue = 5, + IntegerList = new List() { 1, 2, 3 } + } + }; + + var newDTO = new SimpleDTO() + { + DoubleValue = 1 + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Replace("SimpleDTO", newDTO); + + // serialize & deserialize + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(1, doc.SimpleDTO.DoubleValue); + Assert.Equal(0, doc.SimpleDTO.IntegerValue); + Assert.Equal(null, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void ReplaceInList() + { + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Replace("IntegerList/0", 5); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 5, 2, 3 }, doc.IntegerList); + } + + [Fact] + public void ReplaceFullList() + { + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Replace("IntegerList", new List() { 4, 5, 6 }); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 4, 5, 6 }, doc.IntegerList); + } + + [Fact] + public void ReplaceInListInList() + { + var doc = new SimpleDTO() + { + SimpleDTOList = new List() { + new SimpleDTO() { + IntegerList = new List(){1,2,3} + }} + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Replace("SimpleDTOList/0/IntegerList/0", 4); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(4, doc.SimpleDTOList.First().IntegerList.First()); + } + + [Fact] + public void ReplaceFullListFromEnumerable() + { + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Replace("IntegerList", new List() { 4, 5, 6 }); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 4, 5, 6 }, doc.IntegerList); + } + + [Fact] + public void ReplaceFullListWithCollection() + { + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Replace("IntegerList", new Collection() { 4, 5, 6 }); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 4, 5, 6 }, doc.IntegerList); + } + + [Fact] + public void ReplaceAtEndOfList() + { + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + JsonPatchDocument patchDoc = new JsonPatchDocument(); + patchDoc.Replace("IntegerList/-", 5); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject(serialized); + deserialized.ApplyTo(doc); + + Assert.Equal(new List() { 1, 2, 5 }, doc.IntegerList); + } + } +} diff --git a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/SimpleDTO.cs b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/SimpleDTO.cs new file mode 100644 index 0000000000..a6938dd992 --- /dev/null +++ b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/SimpleDTO.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.Collections.Generic; + +namespace Microsoft.AspNet.JsonPatch.Test.Dynamic +{ + public class SimpleDTO + { + public List SimpleDTOList { get; set; } + public List IntegerList { get; set; } + public int IntegerValue { 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; } + } +} diff --git a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/SimpleDTOWithNestedDTO.cs b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/SimpleDTOWithNestedDTO.cs new file mode 100644 index 0000000000..2147fcceb1 --- /dev/null +++ b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/SimpleDTOWithNestedDTO.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.Collections.Generic; + +namespace Microsoft.AspNet.JsonPatch.Test.Dynamic +{ + public class SimpleDTOWithNestedDTO + { + public int IntegerValue { get; set; } + public NestedDTO NestedDTO { get; set; } + public SimpleDTO SimpleDTO { get; set; } + public List ListOfSimpleDTO { get; set; } + + public SimpleDTOWithNestedDTO() + { + NestedDTO = new NestedDTO(); + SimpleDTO = new SimpleDTO(); + ListOfSimpleDTO = new List(); + } + } +} diff --git a/test/Microsoft.AspNet.JsonPatch.Test/Microsoft.AspNet.JsonPatch.Test.xproj b/test/Microsoft.AspNet.JsonPatch.Test/Microsoft.AspNet.JsonPatch.Test.xproj new file mode 100644 index 0000000000..74e0fef687 --- /dev/null +++ b/test/Microsoft.AspNet.JsonPatch.Test/Microsoft.AspNet.JsonPatch.Test.xproj @@ -0,0 +1,20 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 81c20848-e063-4e12-ac40-0b55a532c16c + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin\$(MSBuildProjectName)\ + + + 2.0 + + + + + + \ No newline at end of file diff --git a/test/Microsoft.AspNet.JsonPatch.Test/NestedDTO.cs b/test/Microsoft.AspNet.JsonPatch.Test/NestedDTO.cs new file mode 100644 index 0000000000..6dd5ce8852 --- /dev/null +++ b/test/Microsoft.AspNet.JsonPatch.Test/NestedDTO.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.AspNet.JsonPatch.Test +{ + public class NestedDTO + { + public string StringProperty { get; set; } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.JsonPatch.Test/NestedObjectTests.cs b/test/Microsoft.AspNet.JsonPatch.Test/NestedObjectTests.cs new file mode 100644 index 0000000000..33649b7788 --- /dev/null +++ b/test/Microsoft.AspNet.JsonPatch.Test/NestedObjectTests.cs @@ -0,0 +1,2041 @@ +// Copyright (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.AspNet.JsonPatch.Exceptions; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using Xunit; + +namespace Microsoft.AspNet.JsonPatch.Test +{ + public class NestedObjectTests + { + [Fact] + public void ReplacePropertyInNestedObject() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + IntegerValue = 1 + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.NestedDTO.StringProperty, "B"); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal("B", doc.NestedDTO.StringProperty); + } + + [Fact] + public void ReplacePropertyInNestedObjectWithSerialization() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + IntegerValue = 1 + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.NestedDTO.StringProperty, "B"); + + // serialize & deserialize + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal("B", doc.NestedDTO.StringProperty); + } + + [Fact] + public void ReplaceNestedObject() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + IntegerValue = 1 + }; + + var newNested = new NestedDTO() { StringProperty = "B" }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.NestedDTO, newNested); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal("B", doc.NestedDTO.StringProperty); + } + + [Fact] + public void ReplaceNestedObjectWithSerialization() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + IntegerValue = 1 + }; + + var newNested = new NestedDTO() { StringProperty = "B" }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.NestedDTO, newNested); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal("B", doc.NestedDTO.StringProperty); + } + + [Fact] + public void AddResultsInReplace() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + StringProperty = "A" + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.SimpleDTO.StringProperty, "B"); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal("B", doc.SimpleDTO.StringProperty); + } + + [Fact] + public void AddResultsInReplaceWithSerialization() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + StringProperty = "A" + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.SimpleDTO.StringProperty, "B"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal("B", doc.SimpleDTO.StringProperty); + } + + [Fact] + public void AddToList() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.SimpleDTO.IntegerList, 4, 0); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 4, 1, 2, 3 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void AddToListWithSerialization() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.SimpleDTO.IntegerList, 4, 0); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 4, 1, 2, 3 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void AddToIntegerIList() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerIList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => (List)o.SimpleDTO.IntegerIList, 4, 0); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 4, 1, 2, 3 }, doc.SimpleDTO.IntegerIList); + } + + [Fact] + public void AddToIntegerIListWithSerialization() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerIList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => (List)o.SimpleDTO.IntegerIList, 4, 0); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 4, 1, 2, 3 }, doc.SimpleDTO.IntegerIList); + } + + [Fact] + public void AddToNestedIntegerIList() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTOIList = new List + { + new SimpleDTO + { + IntegerIList = new List() { 1, 2, 3 } + } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => (List)o.SimpleDTOIList[0].IntegerIList, 4, 0); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 4, 1, 2, 3 }, doc.SimpleDTOIList[0].IntegerIList); + } + + [Fact] + public void AddToNestedIntegerIListWithSerialization() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTOIList = new List + { + new SimpleDTO + { + IntegerIList = new List() { 1, 2, 3 } + } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => (List)o.SimpleDTOIList[0].IntegerIList, 4, 0); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 4, 1, 2, 3 }, doc.SimpleDTOIList[0].IntegerIList); + } + + [Fact] + public void AddToComplextTypeListSpecifyIndex() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTOList = new List() + { + new SimpleDTO + { + StringProperty = "String1" + }, + new SimpleDTO + { + StringProperty = "String2" + } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.SimpleDTOList[0].StringProperty, "ChangedString1"); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal("ChangedString1", doc.SimpleDTOList[0].StringProperty); + } + + [Fact] + public void AddToComplextTypeListSpecifyIndexWithSerialization() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTOList = new List() + { + new SimpleDTO + { + StringProperty = "String1" + }, + new SimpleDTO + { + StringProperty = "String2" + } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.SimpleDTOList[0].StringProperty, "ChangedString1"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal("ChangedString1", doc.SimpleDTOList[0].StringProperty); + } + + [Fact] + public void AddToListInvalidPositionTooLarge() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.SimpleDTO.IntegerList, 4, 4); + + // Act & Assert + var exception = Assert.Throws(() => { patchDoc.ApplyTo(doc); }); + Assert.Equal( + "For operation 'add' on array property at path '/simpledto/integerlist/4', the index is " + + "larger than the array size.", + exception.Message); + + } + + [Fact] + public void AddToListInvalidPositionTooLargeWithSerialization() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.SimpleDTO.IntegerList, 4, 4); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act & Assert + var exception = Assert.Throws(() => + { + deserialized.ApplyTo(doc); + }); + Assert.Equal( + "For operation 'add' on array property at path '/simpledto/integerlist/4', the index is " + + "larger than the array size.", + exception.Message); + } + + [Fact] + public void AddToListInvalidPositionTooLarge_LogsError() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.SimpleDTO.IntegerList, 4, 4); + + var logger = new TestErrorLogger(); + + patchDoc.ApplyTo(doc, logger.LogErrorMessage); + + + //Assert + Assert.Equal( + "For operation 'add' on array property at path '/simpledto/integerlist/4', the index is larger than " + + "the array size.", + logger.ErrorMessage); + + } + + [Fact] + public void AddToListInvalidPositionTooSmall() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.SimpleDTO.IntegerList, 4, -1); + + // Act & Assert + var exception = Assert.Throws(() => { patchDoc.ApplyTo(doc); }); + Assert.Equal( + "For operation 'add' on array property at path '/simpledto/integerlist/-1', the index is negative.", + exception.Message); + } + + [Fact] + public void AddToListInvalidPositionTooSmallWithSerialization() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.SimpleDTO.IntegerList, 4, -1); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act & Assert + var exception = Assert.Throws(() => + { + deserialized.ApplyTo(doc); + }); + Assert.Equal( + "For operation 'add' on array property at path '/simpledto/integerlist/-1', the index is negative.", + exception.Message); + } + + [Fact] + public void AddToListInvalidPositionTooSmall_LogsError() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.SimpleDTO.IntegerList, 4, -1); + + var logger = new TestErrorLogger(); + + + patchDoc.ApplyTo(doc, logger.LogErrorMessage); + + + //Assert + Assert.Equal( + "For operation 'add' on array property at path '/simpledto/integerlist/-1', the index is negative.", + logger.ErrorMessage); + } + + [Fact] + public void AddToListAppend() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.SimpleDTO.IntegerList, 4); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 1, 2, 3, 4 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void AddToListAppendWithSerialization() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.SimpleDTO.IntegerList, 4); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 1, 2, 3, 4 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void Remove() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + StringProperty = "A" + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove(o => o.SimpleDTO.StringProperty); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(null, doc.SimpleDTO.StringProperty); + } + + [Fact] + public void RemoveWithSerialization() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + StringProperty = "A" + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove(o => o.SimpleDTO.StringProperty); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(null, doc.SimpleDTO.StringProperty); + } + + [Fact] + public void RemoveFromList() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove(o => o.SimpleDTO.IntegerList, 2); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 1, 2 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void RemoveFromListWithSerialization() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove(o => o.SimpleDTO.IntegerList, 2); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 1, 2 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void RemoveFromListInvalidPositionTooLarge() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove(o => o.SimpleDTO.IntegerList, 3); + + // Act & Assert + var exception = Assert.Throws(() => { patchDoc.ApplyTo(doc); }); + Assert.Equal( + "For operation 'remove' on array property at path '/simpledto/integerlist/3', the index is " + + "larger than the array size.", + exception.Message); + } + + [Fact] + public void RemoveFromListInvalidPositionTooLargeWithSerialization() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove(o => o.SimpleDTO.IntegerList, 3); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act & Assert + var exception = Assert.Throws(() => + { + deserialized.ApplyTo(doc); + }); + Assert.Equal( + "For operation 'remove' on array property at path '/simpledto/integerlist/3', the index is " + + "larger than the array size.", + exception.Message); + } + + [Fact] + public void RemoveFromListInvalidPositionTooLarge_LogsError() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove(o => o.SimpleDTO.IntegerList, 3); + + var logger = new TestErrorLogger(); + + patchDoc.ApplyTo(doc, logger.LogErrorMessage); + + // Assert + Assert.Equal( + "For operation 'remove' on array property at path '/simpledto/integerlist/3', the index is " + + "larger than the array size.", + logger.ErrorMessage); + } + + [Fact] + public void RemoveFromListInvalidPositionTooSmall() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove(o => o.SimpleDTO.IntegerList, -1); + + // Act & Assert + var exception = Assert.Throws(() => { patchDoc.ApplyTo(doc); }); + Assert.Equal("For operation 'remove' on array property at path '/simpledto/integerlist/-1', the index is negative.", exception.Message); + } + + [Fact] + public void RemoveFromListInvalidPositionTooSmallWithSerialization() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove(o => o.SimpleDTO.IntegerList, -1); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act & Assert + var exception = Assert.Throws(() => + { + deserialized.ApplyTo(doc); + }); + Assert.Equal("For operation 'remove' on array property at path '/simpledto/integerlist/-1', the index is negative.", exception.Message); + } + + [Fact] + public void RemoveFromListInvalidPositionTooSmall_LogsError() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove(o => o.SimpleDTO.IntegerList, -1); + + var logger = new TestErrorLogger(); + + + patchDoc.ApplyTo(doc, logger.LogErrorMessage); + + // Assert + Assert.Equal("For operation 'remove' on array property at path '/simpledto/integerlist/-1', the index is negative.", logger.ErrorMessage); + } + + [Fact] + public void RemoveFromEndOfList() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove(o => o.SimpleDTO.IntegerList); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 1, 2 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void RemoveFromEndOfListWithSerialization() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove(o => o.SimpleDTO.IntegerList); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 1, 2 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void Replace() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + StringProperty = "A", + DecimalValue = 10 + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.SimpleDTO.StringProperty, "B"); + patchDoc.Replace(o => o.SimpleDTO.DecimalValue, 12); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal("B", doc.SimpleDTO.StringProperty); + Assert.Equal(12, doc.SimpleDTO.DecimalValue); + } + + [Fact] + public void ReplaceWithSerialization() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + StringProperty = "A", + DecimalValue = 10 + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.SimpleDTO.StringProperty, "B"); + patchDoc.Replace(o => o.SimpleDTO.DecimalValue, 12); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal("B", doc.SimpleDTO.StringProperty); + Assert.Equal(12, doc.SimpleDTO.DecimalValue); + } + + [Fact] + public void SerializationTests() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + StringProperty = "A", + DecimalValue = 10, + DoubleValue = 10, + FloatValue = 10, + IntegerValue = 10 + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.SimpleDTO.StringProperty, "B"); + patchDoc.Replace(o => o.SimpleDTO.DecimalValue, 12); + patchDoc.Replace(o => o.SimpleDTO.DoubleValue, 12); + patchDoc.Replace(o => o.SimpleDTO.FloatValue, 12); + patchDoc.Replace(o => o.SimpleDTO.IntegerValue, 12); + + // serialize & deserialize + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserizalized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserizalized.ApplyTo(doc); + + // Assert + Assert.Equal("B", doc.SimpleDTO.StringProperty); + Assert.Equal(12, doc.SimpleDTO.DecimalValue); + Assert.Equal(12, doc.SimpleDTO.DoubleValue); + Assert.Equal(12, doc.SimpleDTO.FloatValue); + Assert.Equal(12, doc.SimpleDTO.IntegerValue); + } + + [Fact] + public void ReplaceInList() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.SimpleDTO.IntegerList, 5, 0); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 5, 2, 3 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void ReplaceInListWithSerialization() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.SimpleDTO.IntegerList, 5, 0); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 5, 2, 3 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void ReplaceFullList() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace>(o => o.SimpleDTO.IntegerList, new List() { 4, 5, 6 }); + + // Act + patchDoc.ApplyTo(doc); + + // Arrange + Assert.Equal(new List() { 4, 5, 6 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void ReplaceFullListWithSerialiation() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace>(o => o.SimpleDTO.IntegerList, new List() { 4, 5, 6 }); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 4, 5, 6 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void ReplaceFullListFromEnumerable() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace>(o => o.SimpleDTO.IntegerList, new List() { 4, 5, 6 }); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 4, 5, 6 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void ReplaceFullListFromEnumerableWithSerialization() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace>(o => o.SimpleDTO.IntegerList, new List() { 4, 5, 6 }); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 4, 5, 6 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void ReplaceFullListWithCollection() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace>(o => o.SimpleDTO.IntegerList, new Collection() { 4, 5, 6 }); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 4, 5, 6 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void ReplaceFullListWithCollectionWithSerialization() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace>(o => o.SimpleDTO.IntegerList, new Collection() { 4, 5, 6 }); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 4, 5, 6 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void ReplaceAtEndOfList() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.SimpleDTO.IntegerList, 5); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 1, 2, 5 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void ReplaceAtEndOfListWithSerialization() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.SimpleDTO.IntegerList, 5); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 1, 2, 5 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void ReplaceInListInvalidInvalidPositionTooLarge() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.SimpleDTO.IntegerList, 5, 3); + + // Act & Assert + var exception = Assert.Throws(() => { patchDoc.ApplyTo(doc); }); + Assert.Equal( + "For operation 'replace' on array property at path '/simpledto/integerlist/3', the index is " + + "larger than the array size.", + exception.Message); + } + + [Fact] + public void ReplaceInListInvalidInvalidPositionTooLargeWithSerialization() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.SimpleDTO.IntegerList, 5, 3); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act & Assert + var exception = Assert.Throws(() => + { + deserialized.ApplyTo(doc); + }); + Assert.Equal( + "For operation 'replace' on array property at path '/simpledto/integerlist/3', the index is " + + "larger than the array size.", + exception.Message); + } + + [Fact] + public void ReplaceInListInvalid_PositionTooLarge_LogsError() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.SimpleDTO.IntegerList, 5, 3); + + var logger = new TestErrorLogger(); + + + patchDoc.ApplyTo(doc, logger.LogErrorMessage); + + + // Assert + Assert.Equal( + "For operation 'replace' on array property at path '/simpledto/integerlist/3', the index is " + + "larger than the array size.", + logger.ErrorMessage); + } + + [Fact] + public void ReplaceInListInvalidPositionTooSmall() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.SimpleDTO.IntegerList, 5, -1); + + // Act & Assert + var exception = Assert.Throws(() => { patchDoc.ApplyTo(doc); }); + Assert.Equal("For operation 'replace' on array property at path '/simpledto/integerlist/-1', the index is negative.", + exception.Message); + } + + [Fact] + public void ReplaceInListInvalidPositionTooSmallWithSerialization() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.SimpleDTO.IntegerList, 5, -1); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act & Assert + var exception = Assert.Throws(() => { deserialized.ApplyTo(doc); }); + Assert.Equal( + "For operation 'replace' on array property at path '/simpledto/integerlist/-1', the index is negative.", + exception.Message); + } + + [Fact] + public void ReplaceInListInvalidPositionTooSmall_LogsError() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.SimpleDTO.IntegerList, 5, -1); + + var logger = new TestErrorLogger(); + + + patchDoc.ApplyTo(doc, logger.LogErrorMessage); + + + // Assert + Assert.Equal( + "For operation 'replace' on array property at path '/simpledto/integerlist/-1', the index is negative.", + logger.ErrorMessage); + } + + [Fact] + public void Copy() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + StringProperty = "A", + AnotherStringProperty = "B" + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.SimpleDTO.StringProperty, o => o.SimpleDTO.AnotherStringProperty); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal("A", doc.SimpleDTO.AnotherStringProperty); + } + + [Fact] + public void CopyWithSerialization() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + StringProperty = "A", + AnotherStringProperty = "B" + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.SimpleDTO.StringProperty, o => o.SimpleDTO.AnotherStringProperty); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal("A", doc.SimpleDTO.AnotherStringProperty); + } + + [Fact] + public void CopyInList() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.SimpleDTO.IntegerList, 0, o => o.SimpleDTO.IntegerList, 1); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 1, 1, 2, 3 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void CopyInListWithSerialization() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.SimpleDTO.IntegerList, 0, o => o.SimpleDTO.IntegerList, 1); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 1, 1, 2, 3 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void CopyFromListToEndOfList() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.SimpleDTO.IntegerList, 0, o => o.SimpleDTO.IntegerList); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 1, 2, 3, 1 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void CopyFromListToEndOfListWithSerialization() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.SimpleDTO.IntegerList, 0, o => o.SimpleDTO.IntegerList); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 1, 2, 3, 1 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void CopyFromListToNonList() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.SimpleDTO.IntegerList, 0, o => o.SimpleDTO.IntegerValue); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(1, doc.SimpleDTO.IntegerValue); + } + + [Fact] + public void CopyFromListToNonListWithSerialization() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.SimpleDTO.IntegerList, 0, o => o.SimpleDTO.IntegerValue); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(1, doc.SimpleDTO.IntegerValue); + } + + [Fact] + public void CopyFromNonListToList() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerValue = 5, + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.SimpleDTO.IntegerValue, o => o.SimpleDTO.IntegerList, 0); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 5, 1, 2, 3 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void CopyFromNonListToListWithSerialization() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerValue = 5, + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.SimpleDTO.IntegerValue, o => o.SimpleDTO.IntegerList, 0); + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 5, 1, 2, 3 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void CopyToEndOfList() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerValue = 5, + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.SimpleDTO.IntegerValue, o => o.SimpleDTO.IntegerList); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 1, 2, 3, 5 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void CopyToEndOfListWithSerialization() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerValue = 5, + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.SimpleDTO.IntegerValue, o => o.SimpleDTO.IntegerList); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 1, 2, 3, 5 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void Move() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + StringProperty = "A", + AnotherStringProperty = "B" + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.SimpleDTO.StringProperty, o => o.SimpleDTO.AnotherStringProperty); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal("A", doc.SimpleDTO.AnotherStringProperty); + Assert.Equal(null, doc.SimpleDTO.StringProperty); + } + + [Fact] + public void MoveWithSerialization() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + StringProperty = "A", + AnotherStringProperty = "B" + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.SimpleDTO.StringProperty, o => o.SimpleDTO.AnotherStringProperty); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal("A", doc.SimpleDTO.AnotherStringProperty); + Assert.Equal(null, doc.SimpleDTO.StringProperty); + } + + [Fact] + public void MoveInList() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.SimpleDTO.IntegerList, 0, o => o.SimpleDTO.IntegerList, 1); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 2, 1, 3 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void MoveInListWithSerialization() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.SimpleDTO.IntegerList, 0, o => o.SimpleDTO.IntegerList, 1); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 2, 1, 3 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void MoveFromListToEndOfList() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.SimpleDTO.IntegerList, 0, o => o.SimpleDTO.IntegerList); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 2, 3, 1 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void MoveFromListToEndOfListWithSerialization() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.SimpleDTO.IntegerList, 0, o => o.SimpleDTO.IntegerList); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 2, 3, 1 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void MoveFomListToNonList() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.SimpleDTO.IntegerList, 0, o => o.SimpleDTO.IntegerValue); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 2, 3 }, doc.SimpleDTO.IntegerList); + Assert.Equal(1, doc.SimpleDTO.IntegerValue); + } + + [Fact] + public void MoveFomListToNonListWithSerialization() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.SimpleDTO.IntegerList, 0, o => o.SimpleDTO.IntegerValue); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 2, 3 }, doc.SimpleDTO.IntegerList); + Assert.Equal(1, doc.SimpleDTO.IntegerValue); + } + + [Fact] + public void MoveFomListToNonListBetweenHierarchy() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.SimpleDTO.IntegerList, 0, o => o.IntegerValue); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 2, 3 }, doc.SimpleDTO.IntegerList); + Assert.Equal(1, doc.IntegerValue); + } + + [Fact] + public void MoveFomListToNonListBetweenHierarchyWithSerialization() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.SimpleDTO.IntegerList, 0, o => o.IntegerValue); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 2, 3 }, doc.SimpleDTO.IntegerList); + Assert.Equal(1, doc.IntegerValue); + } + + [Fact] + public void MoveFromNonListToList() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerValue = 5, + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.SimpleDTO.IntegerValue, o => o.SimpleDTO.IntegerList, 0); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(0, doc.IntegerValue); + Assert.Equal(new List() { 5, 1, 2, 3 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void MoveFromNonListToListWithSerialization() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerValue = 5, + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.SimpleDTO.IntegerValue, o => o.SimpleDTO.IntegerList, 0); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(0, doc.IntegerValue); + Assert.Equal(new List() { 5, 1, 2, 3 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void MoveToEndOfList() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerValue = 5, + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.SimpleDTO.IntegerValue, o => o.SimpleDTO.IntegerList); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(0, doc.IntegerValue); + Assert.Equal(new List() { 1, 2, 3, 5 }, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void MoveToEndOfListWithSerialization() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerValue = 5, + IntegerList = new List() { 1, 2, 3 } + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.SimpleDTO.IntegerValue, o => o.SimpleDTO.IntegerList); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(0, doc.IntegerValue); + Assert.Equal(new List() { 1, 2, 3, 5 }, doc.SimpleDTO.IntegerList); + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.JsonPatch.Test/ObjectAdapterTests.cs b/test/Microsoft.AspNet.JsonPatch.Test/ObjectAdapterTests.cs new file mode 100644 index 0000000000..0cc97e32c4 --- /dev/null +++ b/test/Microsoft.AspNet.JsonPatch.Test/ObjectAdapterTests.cs @@ -0,0 +1,1737 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using Microsoft.AspNet.JsonPatch.Exceptions; +using Newtonsoft.Json; +using Xunit; + +namespace Microsoft.AspNet.JsonPatch.Test +{ + public class ObjectAdapterTests + { + [Fact] + public void AddResultsShouldReplace() + { + // Arrange + var doc = new SimpleDTO() + { + StringProperty = "A" + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.StringProperty, "B"); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal("B", doc.StringProperty); + } + + [Fact] + public void AddResultsShouldReplaceWithSerialization() + { + // Arrange + var doc = new SimpleDTO() + { + StringProperty = "A" + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.StringProperty, "B"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal("B", doc.StringProperty); + } + + [Fact] + public void AddToList() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.IntegerList, 4, 0); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 4, 1, 2, 3 }, doc.IntegerList); + } + + [Fact] + public void AddToListWithSerialization() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.IntegerList, 4, 0); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 4, 1, 2, 3 }, doc.IntegerList); + } + + [Fact] + public void AddToIntegerIList() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerIList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.IntegerIList, 4, 0); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 4, 1, 2, 3 }, doc.IntegerIList); + } + + [Fact] + public void AddToIntegerIListWithSerialization() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerIList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.IntegerIList, 4, 0); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 4, 1, 2, 3 }, doc.IntegerIList); + } + + [Fact] + public void AddToListInvalidPositionTooLarge() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.IntegerList, 4, 4); + + // Act & Assert + var exception = Assert.Throws(() => { patchDoc.ApplyTo(doc); }); + Assert.Equal( + "For operation 'add' on array property at path '/integerlist/4', the index is " + + "larger than the array size.", + exception.Message); + } + + [Fact] + public void AddToListInvalidPositionTooLargeWithSerialization() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.IntegerList, 4, 4); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act & Assert + var exception = Assert.Throws(() => { deserialized.ApplyTo(doc); }); + Assert.Equal( + "For operation 'add' on array property at path '/integerlist/4', the index is " + + "larger than the array size.", + exception.Message); + } + + [Fact] + public void AddToListInvalidPositionTooLarge_LogsError() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.IntegerList, 4, 4); + + var logger = new TestErrorLogger(); + + patchDoc.ApplyTo(doc, logger.LogErrorMessage); + + + // Assert + Assert.Equal( + "For operation 'add' on array property at path '/integerlist/4', the index is " + + "larger than the array size.", + logger.ErrorMessage); + } + + [Fact] + public void AddToListAtEnd() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.IntegerList, 4, 3); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 1, 2, 3, 4 }, doc.IntegerList); + } + + [Fact] + public void AddToListAtEndWithSerialization() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.IntegerList, 4, 3); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 1, 2, 3, 4 }, doc.IntegerList); + } + + [Fact] + public void AddToListAtBeginning() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.IntegerList, 4, 0); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 4, 1, 2, 3 }, doc.IntegerList); + } + + [Fact] + public void AddToListAtBeginningWithSerialization() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.IntegerList, 4, 0); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 4, 1, 2, 3 }, doc.IntegerList); + } + + [Fact] + public void AddToListInvalidPositionTooSmall() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.IntegerList, 4, -1); + + // Act & Assert + var exception = Assert.Throws(() => { patchDoc.ApplyTo(doc); }); + Assert.Equal( + "For operation 'add' on array property at path '/integerlist/-1', the index is negative.", + exception.Message); + } + + [Fact] + public void AddToListInvalidPositionTooSmallWithSerialization() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.IntegerList, 4, -1); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act & Assert + var exception = Assert.Throws(() => { deserialized.ApplyTo(doc); }); + Assert.Equal( + "For operation 'add' on array property at path '/integerlist/-1', the index is negative.", + exception.Message); + } + + [Fact] + public void AddToListInvalidPositionTooSmall_LogsError() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.IntegerList, 4, -1); + + var logger = new TestErrorLogger(); + + patchDoc.ApplyTo(doc, logger.LogErrorMessage); + + // Assert + Assert.Equal( + "For operation 'add' on array property at path '/integerlist/-1', the index is negative.", + logger.ErrorMessage); + } + + [Fact] + public void AddToListAppend() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.IntegerList, 4); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 1, 2, 3, 4 }, doc.IntegerList); + } + + [Fact] + public void AddToListAppendWithSerialization() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.IntegerList, 4); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 1, 2, 3, 4 }, doc.IntegerList); + } + + [Fact] + public void Remove() + { + // Arrange + var doc = new SimpleDTO() + { + StringProperty = "A" + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove(o => o.StringProperty); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(null, doc.StringProperty); + } + + [Fact] + public void RemoveWithSerialization() + { + // Arrange + var doc = new SimpleDTO() + { + StringProperty = "A" + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove(o => o.StringProperty); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(null, doc.StringProperty); + } + + [Fact] + public void RemoveFromList() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove(o => o.IntegerList, 2); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 1, 2 }, doc.IntegerList); + } + + [Fact] + public void RemoveFromListWithSerialization() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove(o => o.IntegerList, 2); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 1, 2 }, doc.IntegerList); + } + + [Fact] + public void RemoveFromListInvalidPositionTooLarge() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove(o => o.IntegerList, 3); + + // Act & Assert + var exception = Assert.Throws(() => { patchDoc.ApplyTo(doc); }); + Assert.Equal( + "For operation 'remove' on array property at path '/integerlist/3', the index is " + + "larger than the array size.", + exception.Message); + } + + [Fact] + public void RemoveFromListInvalidPositionTooLargeWithSerialization() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove(o => o.IntegerList, 3); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act & Assert + var exception = Assert.Throws(() => { deserialized.ApplyTo(doc); }); + Assert.Equal( + "For operation 'remove' on array property at path '/integerlist/3', the index is " + + "larger than the array size.", + exception.Message); + } + + [Fact] + public void RemoveFromListInvalidPositionTooLarge_LogsError() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove(o => o.IntegerList, 3); + + var logger = new TestErrorLogger(); + + patchDoc.ApplyTo(doc, logger.LogErrorMessage); + + + // Assert + Assert.Equal( + "For operation 'remove' on array property at path '/integerlist/3', the index is " + + "larger than the array size.", + logger.ErrorMessage); + } + + [Fact] + public void RemoveFromListInvalidPositionTooSmall() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove(o => o.IntegerList, -1); + + // Act & Assert + var exception = Assert.Throws(() => { patchDoc.ApplyTo(doc); }); + Assert.Equal("For operation 'remove' on array property at path '/integerlist/-1', the index is negative.", exception.Message); + } + + [Fact] + public void RemoveFromListInvalidPositionTooSmallWithSerialization() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove(o => o.IntegerList, -1); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act & Assert + var exception = Assert.Throws(() => { deserialized.ApplyTo(doc); }); + Assert.Equal("For operation 'remove' on array property at path '/integerlist/-1', the index is negative.", exception.Message); + } + + [Fact] + public void RemoveFromListInvalidPositionTooSmall_LogsError() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove(o => o.IntegerList, -1); + + var logger = new TestErrorLogger(); + + + patchDoc.ApplyTo(doc, logger.LogErrorMessage); + + + // Assert + Assert.Equal("For operation 'remove' on array property at path '/integerlist/-1', the index is negative.", logger.ErrorMessage); + } + + [Fact] + public void RemoveFromEndOfList() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove(o => o.IntegerList); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 1, 2 }, doc.IntegerList); + } + + [Fact] + public void RemoveFromEndOfListWithSerialization() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove(o => o.IntegerList); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 1, 2 }, doc.IntegerList); + } + + [Fact] + public void Replace() + { + // Arrange + var doc = new SimpleDTO() + { + StringProperty = "A", + DecimalValue = 10 + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.StringProperty, "B"); + + patchDoc.Replace(o => o.DecimalValue, 12); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal("B", doc.StringProperty); + Assert.Equal(12, doc.DecimalValue); + } + + [Fact] + public void ReplaceWithSerialization() + { + // Arrange + var doc = new SimpleDTO() + { + StringProperty = "A", + DecimalValue = 10 + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.StringProperty, "B"); + + patchDoc.Replace(o => o.DecimalValue, 12); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal("B", doc.StringProperty); + Assert.Equal(12, doc.DecimalValue); + } + + [Fact] + public void SerializationMustNotIncudeEnvelope() + { + // Arrange + var doc = new SimpleDTO() + { + StringProperty = "A", + DecimalValue = 10, + DoubleValue = 10, + FloatValue = 10, + IntegerValue = 10 + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.StringProperty, "B"); + patchDoc.Replace(o => o.DecimalValue, 12); + patchDoc.Replace(o => o.DoubleValue, 12); + patchDoc.Replace(o => o.FloatValue, 12); + patchDoc.Replace(o => o.IntegerValue, 12); + + // Act + var serialized = JsonConvert.SerializeObject(patchDoc); + + // Assert + Assert.Equal(false, serialized.Contains("operations")); + Assert.Equal(false, serialized.Contains("Operations")); + } + + [Fact] + public void DeserializationMustWorkWithoutEnvelope() + { + // Arrange + var doc = new SimpleDTO() + { + StringProperty = "A", + DecimalValue = 10, + DoubleValue = 10, + FloatValue = 10, + IntegerValue = 10 + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.StringProperty, "B"); + patchDoc.Replace(o => o.DecimalValue, 12); + patchDoc.Replace(o => o.DoubleValue, 12); + patchDoc.Replace(o => o.FloatValue, 12); + patchDoc.Replace(o => o.IntegerValue, 12); + + // default: no envelope + var serialized = JsonConvert.SerializeObject(patchDoc); + + // Act + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Assert + Assert.IsType>(deserialized); + } + + [Fact] + public void DeserializationMustFailWithEnvelope() + { + // Arrange + string serialized = "{\"Operations\": [{ \"op\": \"replace\", \"path\": \"/title\", \"value\": \"New Title\"}]}"; + + // Act & Assert + var exception = Assert.Throws(() => + { + var deserialized + = JsonConvert.DeserializeObject>(serialized); + }); + + Assert.Equal("The type 'JsonPatchDocument`1' was malformed and could not be parsed.", exception.Message); + } + + [Fact] + public void SerializationTests() + { + // Arrange + var doc = new SimpleDTO() + { + StringProperty = "A", + DecimalValue = 10, + DoubleValue = 10, + FloatValue = 10, + IntegerValue = 10 + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.StringProperty, "B"); + patchDoc.Replace(o => o.DecimalValue, 12); + patchDoc.Replace(o => o.DoubleValue, 12); + patchDoc.Replace(o => o.FloatValue, 12); + patchDoc.Replace(o => o.IntegerValue, 12); + + // serialize & deserialize + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserizalized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserizalized.ApplyTo(doc); + + // Assert + Assert.Equal("B", doc.StringProperty); + Assert.Equal(12, doc.DecimalValue); + Assert.Equal(12, doc.DoubleValue); + Assert.Equal(12, doc.FloatValue); + Assert.Equal(12, doc.IntegerValue); + } + + [Fact] + public void SerializeAndReplaceGuidTest() + { + // Arrange + var doc = new SimpleDTO() + { + GuidValue = Guid.NewGuid() + }; + + var newGuid = Guid.NewGuid(); + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.GuidValue, newGuid); + + // serialize & deserialize + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserizalized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserizalized.ApplyTo(doc); + + // Assert + Assert.Equal(newGuid, doc.GuidValue); + } + + [Fact] + public void SerializeAndReplaceNestedObjectTest() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + IntegerValue = 5, + IntegerList = new List() { 1, 2, 3 } + } + }; + + var newDTO = new SimpleDTO() + { + DoubleValue = 1 + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.SimpleDTO, newDTO); + + // serialize & deserialize + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(1, doc.SimpleDTO.DoubleValue); + Assert.Equal(0, doc.SimpleDTO.IntegerValue); + Assert.Equal(null, doc.SimpleDTO.IntegerList); + } + + [Fact] + public void ReplaceInList() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.IntegerList, 5, 0); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 5, 2, 3 }, doc.IntegerList); + } + + [Fact] + public void ReplaceInListWithSerialization() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.IntegerList, 5, 0); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 5, 2, 3 }, doc.IntegerList); + } + + [Fact] + public void ReplaceFullList() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace>(o => o.IntegerList, new List() { 4, 5, 6 }); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 4, 5, 6 }, doc.IntegerList); + } + + [Fact] + public void ReplaceFullListWithSerialization() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace>(o => o.IntegerList, new List() { 4, 5, 6 }); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 4, 5, 6 }, doc.IntegerList); + } + + [Fact] + public void ReplaceFullListFromEnumerable() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace>(o => o.IntegerList, new List() { 4, 5, 6 }); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 4, 5, 6 }, doc.IntegerList); + } + + [Fact] + public void ReplaceFullListFromEnumerableWithSerialization() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace>(o => o.IntegerList, new List() { 4, 5, 6 }); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 4, 5, 6 }, doc.IntegerList); + } + + [Fact] + public void ReplaceFullListWithCollection() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace>(o => o.IntegerList, new Collection() { 4, 5, 6 }); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 4, 5, 6 }, doc.IntegerList); + } + + [Fact] + public void ReplaceFullListWithCollectionWithSerialization() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace>(o => o.IntegerList, new Collection() { 4, 5, 6 }); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 4, 5, 6 }, doc.IntegerList); + } + + [Fact] + public void ReplaceAtEndOfList() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.IntegerList, 5); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 1, 2, 5 }, doc.IntegerList); + } + + [Fact] + public void ReplaceAtEndOfListWithSerialization() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.IntegerList, 5); + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 1, 2, 5 }, doc.IntegerList); + } + + [Fact] + public void ReplaceInListInvalidInvalidPositionTooLarge() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.IntegerList, 5, 3); + + // Act & Assert + var exception = Assert.Throws(() => + { + patchDoc.ApplyTo(doc); + }); + Assert.Equal( + "For operation 'replace' on array property at path '/integerlist/3', the index is " + + "larger than the array size.", + exception.Message); + } + + [Fact] + public void ReplaceInListInvalidInvalidPositionTooLargeWithSerialization() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.IntegerList, 5, 3); + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act & Assert + var exception = Assert.Throws(() => + { + deserialized.ApplyTo(doc); + }); + Assert.Equal( + "For operation 'replace' on array property at path '/integerlist/3', the index is " + + "larger than the array size.", + exception.Message); + } + + [Fact] + public void ReplaceInListInvalidPositionTooSmall() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.IntegerList, 5, -1); + + // Act & Assert + var exception = Assert.Throws(() => + { + patchDoc.ApplyTo(doc); + }); + Assert.Equal("For operation 'replace' on array property at path '/integerlist/-1', the index is negative.", exception.Message); + } + + [Fact] + public void ReplaceInListInvalidPositionTooSmallWithSerialization() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.IntegerList, 5, -1); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act & Assert + var exception = Assert.Throws(() => + { + deserialized.ApplyTo(doc); + }); + Assert.Equal("For operation 'replace' on array property at path '/integerlist/-1', the index is negative.", exception.Message); + } + + [Fact] + public void Copy() + { + // Arrange + var doc = new SimpleDTO() + { + StringProperty = "A", + AnotherStringProperty = "B" + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.StringProperty, o => o.AnotherStringProperty); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal("A", doc.AnotherStringProperty); + } + + [Fact] + public void CopyWithSerialization() + { + // Arrange + var doc = new SimpleDTO() + { + StringProperty = "A", + AnotherStringProperty = "B" + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.StringProperty, o => o.AnotherStringProperty); + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal("A", doc.AnotherStringProperty); + } + + [Fact] + public void CopyInList() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.IntegerList, 0, o => o.IntegerList, 1); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 1, 1, 2, 3 }, doc.IntegerList); + } + + [Fact] + public void CopyInListWithSerialization() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.IntegerList, 0, o => o.IntegerList, 1); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 1, 1, 2, 3 }, doc.IntegerList); + } + + [Fact] + public void CopyFromListToEndOfList() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.IntegerList, 0, o => o.IntegerList); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 1, 2, 3, 1 }, doc.IntegerList); + } + + [Fact] + public void CopyFromListToEndOfListWithSerialization() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.IntegerList, 0, o => o.IntegerList); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 1, 2, 3, 1 }, doc.IntegerList); + } + + [Fact] + public void CopyFromListToNonList() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.IntegerList, 0, o => o.IntegerValue); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(1, doc.IntegerValue); + } + + [Fact] + public void CopyFromListToNonListWithSerialization() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.IntegerList, 0, o => o.IntegerValue); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(1, doc.IntegerValue); + } + + [Fact] + public void CopyFromNonListToList() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerValue = 5, + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.IntegerValue, o => o.IntegerList, 0); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 5, 1, 2, 3 }, doc.IntegerList); + } + + [Fact] + public void CopyFromNonListToListWithSerialization() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerValue = 5, + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.IntegerValue, o => o.IntegerList, 0); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 5, 1, 2, 3 }, doc.IntegerList); + } + + [Fact] + public void CopyToEndOfList() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerValue = 5, + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.IntegerValue, o => o.IntegerList); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 1, 2, 3, 5 }, doc.IntegerList); + } + + [Fact] + public void CopyToEndOfListWithSerialization() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerValue = 5, + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.IntegerValue, o => o.IntegerList); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 1, 2, 3, 5 }, doc.IntegerList); + } + + [Fact] + public void Move() + { + // Arrange + var doc = new SimpleDTO() + { + StringProperty = "A", + AnotherStringProperty = "B" + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.StringProperty, o => o.AnotherStringProperty); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal("A", doc.AnotherStringProperty); + Assert.Equal(null, doc.StringProperty); + } + + [Fact] + public void MoveWithSerialization() + { + // Arrange + var doc = new SimpleDTO() + { + StringProperty = "A", + AnotherStringProperty = "B" + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.StringProperty, o => o.AnotherStringProperty); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal("A", doc.AnotherStringProperty); + Assert.Equal(null, doc.StringProperty); + } + + [Fact] + public void MoveInList() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.IntegerList, 0, o => o.IntegerList, 1); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 2, 1, 3 }, doc.IntegerList); + } + + [Fact] + public void MoveInListWithSerialization() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.IntegerList, 0, o => o.IntegerList, 1); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 2, 1, 3 }, doc.IntegerList); + } + + [Fact] + public void MoveFromListToEndOfList() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.IntegerList, 0, o => o.IntegerList); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 2, 3, 1 }, doc.IntegerList); + } + + [Fact] + public void MoveFromListToEndOfListWithSerialization() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.IntegerList, 0, o => o.IntegerList); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 2, 3, 1 }, doc.IntegerList); + } + + [Fact] + public void MoveFomListToNonList() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.IntegerList, 0, o => o.IntegerValue); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 2, 3 }, doc.IntegerList); + Assert.Equal(1, doc.IntegerValue); + } + + [Fact] + public void MoveFomListToNonListWithSerialization() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.IntegerList, 0, o => o.IntegerValue); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 2, 3 }, doc.IntegerList); + Assert.Equal(1, doc.IntegerValue); + } + + [Fact] + public void MoveFromNonListToList() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerValue = 5, + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.IntegerValue, o => o.IntegerList, 0); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(0, doc.IntegerValue); + Assert.Equal(new List() { 5, 1, 2, 3 }, doc.IntegerList); + } + + [Fact] + public void MoveFromNonListToListWithSerialization() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerValue = 5, + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.IntegerValue, o => o.IntegerList, 0); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(0, doc.IntegerValue); + Assert.Equal(new List() { 5, 1, 2, 3 }, doc.IntegerList); + } + + [Fact] + public void MoveToEndOfList() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerValue = 5, + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.IntegerValue, o => o.IntegerList); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(0, doc.IntegerValue); + Assert.Equal(new List() { 1, 2, 3, 5 }, doc.IntegerList); + } + + [Fact] + public void MoveToEndOfListWithSerialization() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerValue = 5, + IntegerList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.IntegerValue, o => o.IntegerList); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(0, doc.IntegerValue); + Assert.Equal(new List() { 1, 2, 3, 5 }, doc.IntegerList); + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.JsonPatch.Test/SimpleDTO.cs b/test/Microsoft.AspNet.JsonPatch.Test/SimpleDTO.cs new file mode 100644 index 0000000000..0c29a86e83 --- /dev/null +++ b/test/Microsoft.AspNet.JsonPatch.Test/SimpleDTO.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.Collections; +using System.Collections.Generic; + +namespace Microsoft.AspNet.JsonPatch.Test +{ + public class SimpleDTO + { + public List IntegerList { get; set; } + public IList IntegerIList { get; set; } + public int IntegerValue { 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/test/Microsoft.AspNet.JsonPatch.Test/SimpleDTOWithNestedDTO.cs b/test/Microsoft.AspNet.JsonPatch.Test/SimpleDTOWithNestedDTO.cs new file mode 100644 index 0000000000..81aa38e682 --- /dev/null +++ b/test/Microsoft.AspNet.JsonPatch.Test/SimpleDTOWithNestedDTO.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 System.Collections.Generic; + +namespace Microsoft.AspNet.JsonPatch.Test +{ + public class SimpleDTOWithNestedDTO + { + public int IntegerValue { get; set; } + + public NestedDTO NestedDTO { get; set; } + + public SimpleDTO SimpleDTO { get; set; } + + public List SimpleDTOList { get; set; } + + public IList SimpleDTOIList { get; set; } + + public SimpleDTOWithNestedDTO() + { + this.NestedDTO = new NestedDTO(); + this.SimpleDTO = new SimpleDTO(); + this.SimpleDTOList = new List(); + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.JsonPatch.Test/TestErrorLogger.cs b/test/Microsoft.AspNet.JsonPatch.Test/TestErrorLogger.cs new file mode 100644 index 0000000000..c254eab3e3 --- /dev/null +++ b/test/Microsoft.AspNet.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.AspNet.JsonPatch.Test +{ + public class TestErrorLogger where T: class + { + public string ErrorMessage { get; set; } + + public void LogErrorMessage(JsonPatchError patchError) + { + ErrorMessage = patchError.ErrorMessage; + } + } +} diff --git a/test/Microsoft.AspNet.JsonPatch.Test/project.json b/test/Microsoft.AspNet.JsonPatch.Test/project.json new file mode 100644 index 0000000000..629b7a1be3 --- /dev/null +++ b/test/Microsoft.AspNet.JsonPatch.Test/project.json @@ -0,0 +1,18 @@ +{ + "compilationOptions": { + "warningsAsErrors": true + }, + "dependencies": { + "Microsoft.AspNet.JsonPatch": "1.0.0-*", + "Microsoft.AspNet.Testing": "1.0.0-*", + "Moq": "4.2.1312.1622", + "Newtonsoft.Json": "6.0.6", + "xunit.runner.aspnet": "2.0.0-aspnet-*" + }, + "commands": { + "test": "xunit.runner.aspnet" + }, + "frameworks": { + "dnx451": { } + } +} \ No newline at end of file From ae0baac22742650e734a41a26e67f864be859b55 Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Mon, 21 Sep 2015 11:47:54 -0700 Subject: [PATCH 006/471] simplify .travis.yml --- .travis.yml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index 568e2673e9..947bf868ee 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,4 @@ language: csharp sudo: false -mono: - - beta -env: - - MONO_THREADS_PER_CPU=2000 MONO_MANAGED_WATCHER=disabled -os: - - linux - - osx -before_script: - - if [ $TRAVIS_OS_NAME == "osx" ] ; then sudo sysctl -w kern.maxfiles=64000 ; sudo sysctl -w kern.maxfilesperproc=64000 ; sudo launchctl limit maxfiles 64000 64000 ; fi ; ulimit -n 64000 script: - ./build.sh --quiet verify \ No newline at end of file From 22f22c04076c598735469306b291075b7ebfde62 Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Mon, 21 Sep 2015 12:48:21 -0700 Subject: [PATCH 007/471] chmod+x on build.sh --- build.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 build.sh diff --git a/build.sh b/build.sh old mode 100644 new mode 100755 From 7b697e8ec9aa2a7278d834189dc1cfc324eac8f0 Mon Sep 17 00:00:00 2001 From: Ajay Bhargav Baaskaran Date: Tue, 22 Sep 2015 16:06:18 -0700 Subject: [PATCH 008/471] Enabling NuGetPackageVerifier --- NuGetPackageVerifier.json | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 NuGetPackageVerifier.json diff --git a/NuGetPackageVerifier.json b/NuGetPackageVerifier.json new file mode 100644 index 0000000000..a45e74c44d --- /dev/null +++ b/NuGetPackageVerifier.json @@ -0,0 +1,25 @@ +{ + "adx": { // Packages written by the ADX team and that ship on NuGet.org + "rules": [ + "AssemblyHasDocumentFileRule", + "AssemblyHasVersionAttributesRule", + "AssemblyHasServicingAttributeRule", + "AssemblyHasNeutralResourcesLanguageAttributeRule", + "SatellitePackageRule", + "StrictSemanticVersionValidationRule" + ], + "packages": { + "Microsoft.AspNet.JsonPatch": { } + } + }, + "Default": { // Rules to run for packages not listed in any other set. + "rules": [ + "AssemblyHasDocumentFileRule", + "AssemblyHasVersionAttributesRule", + "AssemblyHasServicingAttributeRule", + "AssemblyHasNeutralResourcesLanguageAttributeRule", + "SatellitePackageRule", + "StrictSemanticVersionValidationRule" + ] + } +} \ No newline at end of file From bed133858e92099df6dcb269761d6ceb000c40cf Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 29 Sep 2015 12:39:30 -0700 Subject: [PATCH 009/471] Updating to release NuGet.config --- NuGet.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NuGet.config b/NuGet.config index 5500f6d507..20950d3df6 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,7 @@  - + From 182b7d588c94085f663788a659eb65fd2506e8d0 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Thu, 1 Oct 2015 12:13:37 -0700 Subject: [PATCH 010/471] Update 'build.cmd' alias parameter to use full name. --- build.cmd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.cmd b/build.cmd index 177997c42e..30b3dbba60 100644 --- a/build.cmd +++ b/build.cmd @@ -30,10 +30,10 @@ IF "%SKIP_DNX_INSTALL%"=="1" goto run IF %BUILDCMD_DNX_VERSION%=="" ( CALL packages\KoreBuild\build\dnvm upgrade -runtime CLR -arch x86 ) ELSE ( - CALL packages\KoreBuild\build\dnvm install %BUILDCMD_DNX_VERSION% -runtime CLR -arch x86 -a default + CALL packages\KoreBuild\build\dnvm install %BUILDCMD_DNX_VERSION% -runtime CLR -arch x86 -alias default ) CALL packages\KoreBuild\build\dnvm install default -runtime CoreCLR -arch x86 :run CALL packages\KoreBuild\build\dnvm use default -runtime CLR -arch x86 -packages\Sake\tools\Sake.exe -I packages\KoreBuild\build -f makefile.shade %* \ No newline at end of file +packages\Sake\tools\Sake.exe -I packages\KoreBuild\build -f makefile.shade %* From 21a1c2063c7474cd67c9cae5a2969f18df49a499 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Thu, 8 Oct 2015 19:00:51 -0700 Subject: [PATCH 011/471] React to aspnet/Universe#290 fix --- build.cmd | 23 ++++++++++++----------- build.sh | 12 +++++++----- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/build.cmd b/build.cmd index 30b3dbba60..84dc87e480 100644 --- a/build.cmd +++ b/build.cmd @@ -18,22 +18,23 @@ md .nuget copy %CACHED_NUGET% .nuget\nuget.exe > nul :restore -IF EXIST packages\KoreBuild goto run +IF EXIST packages\Sake goto getdnx IF %BUILDCMD_KOREBUILD_VERSION%=="" ( - .nuget\nuget.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre + .nuget\nuget.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre ) ELSE ( - .nuget\nuget.exe install KoreBuild -version %BUILDCMD_KOREBUILD_VERSION% -ExcludeVersion -o packages -nocache -pre + .nuget\nuget.exe install KoreBuild -version %BUILDCMD_KOREBUILD_VERSION% -ExcludeVersion -o packages -nocache -pre ) -.nuget\nuget.exe install Sake -ExcludeVersion -Out packages +.nuget\NuGet.exe install Sake -ExcludeVersion -Source https://www.nuget.org/api/v2/ -Out packages -IF "%SKIP_DNX_INSTALL%"=="1" goto run -IF %BUILDCMD_DNX_VERSION%=="" ( - CALL packages\KoreBuild\build\dnvm upgrade -runtime CLR -arch x86 +:getdnx +IF "%SKIP_DNX_INSTALL%"=="" ( + IF "%BUILDCMD_DNX_VERSION%"=="" ( + BUILDCMD_DNX_VERSION=latest + ) + CALL packages\KoreBuild\build\dnvm install %BUILDCMD_DNX_VERSION% -runtime CoreCLR -arch x86 -alias default + CALL packages\KoreBuild\build\dnvm install default -runtime CLR -arch x86 -alias default ) ELSE ( - CALL packages\KoreBuild\build\dnvm install %BUILDCMD_DNX_VERSION% -runtime CLR -arch x86 -alias default + CALL packages\KoreBuild\build\dnvm use default -runtime CLR -arch x86 ) -CALL packages\KoreBuild\build\dnvm install default -runtime CoreCLR -arch x86 -:run -CALL packages\KoreBuild\build\dnvm use default -runtime CLR -arch x86 packages\Sake\tools\Sake.exe -I packages\KoreBuild\build -f makefile.shade %* diff --git a/build.sh b/build.sh index 0c66139817..da4e3fcd1c 100755 --- a/build.sh +++ b/build.sh @@ -24,18 +24,20 @@ if test ! -e .nuget; then cp $cachePath .nuget/nuget.exe fi -if test ! -d packages/KoreBuild; then +if test ! -d packages/Sake; then mono .nuget/nuget.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre - mono .nuget/nuget.exe install Sake -ExcludeVersion -Out packages + mono .nuget/nuget.exe install Sake -ExcludeVersion -Source https://www.nuget.org/api/v2/ -Out packages fi if ! type dnvm > /dev/null 2>&1; then source packages/KoreBuild/build/dnvm.sh fi -if ! type dnx > /dev/null 2>&1; then - dnvm upgrade +if ! type dnx > /dev/null 2>&1 || [ -z "$SKIP_DNX_INSTALL" ]; then + dnvm install latest -runtime coreclr -alias default + dnvm install default -runtime mono -alias default +else + dnvm use default -runtime mono fi mono packages/Sake/tools/Sake.exe -I packages/KoreBuild/build -f makefile.shade "$@" - From 62ca4d6a8cbc1951dbda0f585fa0ec6282fb6eb3 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Mon, 12 Oct 2015 12:56:34 -0700 Subject: [PATCH 012/471] Fix local build break --- build.cmd | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build.cmd b/build.cmd index 84dc87e480..553e3929a0 100644 --- a/build.cmd +++ b/build.cmd @@ -4,8 +4,8 @@ cd %~dp0 SETLOCAL SET NUGET_VERSION=latest SET CACHED_NUGET=%LocalAppData%\NuGet\nuget.%NUGET_VERSION%.exe -SET BUILDCMD_KOREBUILD_VERSION="" -SET BUILDCMD_DNX_VERSION="" +SET BUILDCMD_KOREBUILD_VERSION= +SET BUILDCMD_DNX_VERSION= IF EXIST %CACHED_NUGET% goto copynuget echo Downloading latest version of NuGet.exe... @@ -19,7 +19,7 @@ copy %CACHED_NUGET% .nuget\nuget.exe > nul :restore IF EXIST packages\Sake goto getdnx -IF %BUILDCMD_KOREBUILD_VERSION%=="" ( +IF "%BUILDCMD_KOREBUILD_VERSION%"=="" ( .nuget\nuget.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre ) ELSE ( .nuget\nuget.exe install KoreBuild -version %BUILDCMD_KOREBUILD_VERSION% -ExcludeVersion -o packages -nocache -pre @@ -27,10 +27,10 @@ IF %BUILDCMD_KOREBUILD_VERSION%=="" ( .nuget\NuGet.exe install Sake -ExcludeVersion -Source https://www.nuget.org/api/v2/ -Out packages :getdnx +IF "%BUILDCMD_DNX_VERSION%"=="" ( + SET BUILDCMD_DNX_VERSION=latest +) IF "%SKIP_DNX_INSTALL%"=="" ( - IF "%BUILDCMD_DNX_VERSION%"=="" ( - BUILDCMD_DNX_VERSION=latest - ) CALL packages\KoreBuild\build\dnvm install %BUILDCMD_DNX_VERSION% -runtime CoreCLR -arch x86 -alias default CALL packages\KoreBuild\build\dnvm install default -runtime CLR -arch x86 -alias default ) ELSE ( From 127fc1388537e7c9d2f211942511f40d106de716 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 21 Oct 2015 21:24:19 -0700 Subject: [PATCH 013/471] Switching to using generations TFM --- src/Microsoft.AspNet.JsonPatch/project.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.AspNet.JsonPatch/project.json b/src/Microsoft.AspNet.JsonPatch/project.json index 8d67ec1808..c08afdec7e 100644 --- a/src/Microsoft.AspNet.JsonPatch/project.json +++ b/src/Microsoft.AspNet.JsonPatch/project.json @@ -8,8 +8,8 @@ "Newtonsoft.Json": "6.0.6" }, "frameworks": { - "dnx451": { }, - "dnxcore50": { + "net451": {}, + "dotnet5.4": { "dependencies": { "Microsoft.CSharp": "4.0.1-beta-*", "System.Collections.Concurrent": "4.0.11-beta-*", @@ -22,4 +22,4 @@ } } } -} +} \ No newline at end of file From 76346e48a6e2ce577847be0401ac073c7ceda1ee Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 28 Oct 2015 12:43:05 -0700 Subject: [PATCH 014/471] Updating to release NuGet.config. --- NuGet.config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NuGet.config b/NuGet.config index 5500f6d507..71b9724a09 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,7 @@ - + - + From 8a0696602401328e3493ac1ebea67061ce1a692b Mon Sep 17 00:00:00 2001 From: Cesar Blum Silveira Date: Fri, 30 Oct 2015 12:19:00 -0700 Subject: [PATCH 015/471] Strong name Microsoft.AspNet.JsonPatch. --- src/Microsoft.AspNet.JsonPatch/project.json | 4 ++++ tools/Key.snk | Bin 0 -> 596 bytes 2 files changed, 4 insertions(+) create mode 100644 tools/Key.snk diff --git a/src/Microsoft.AspNet.JsonPatch/project.json b/src/Microsoft.AspNet.JsonPatch/project.json index c08afdec7e..d9b41653fb 100644 --- a/src/Microsoft.AspNet.JsonPatch/project.json +++ b/src/Microsoft.AspNet.JsonPatch/project.json @@ -1,5 +1,9 @@ { "version": "1.0.0-*", + "compilationOptions": { + "warningsAsErrors": true, + "keyFile": "../../tools/Key.snk" + }, "repository": { "type": "git", "url": "git://github.com/aspnet/mvc" diff --git a/tools/Key.snk b/tools/Key.snk new file mode 100644 index 0000000000000000000000000000000000000000..e10e4889c125d3120cd9e81582243d70f7cbb806 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098=Iw=HCsnz~#iVhm& zj%TU(_THUee?3yHBjk$37ysB?i5#7WD$={H zV4B!OxRPrb|8)HPg~A}8P>^=#y<)56#=E&NzcjOtPK~<4n6GHt=K$ro*T(lhby_@U zEk(hLzk1H)0yXj{A_5>fk-TgNoP|q6(tP2xo8zt8i%212CWM#AeCd?`hS|4~L({h~Moo(~vy&3Z z1uI}`fd^*>o=rwbAGymj6RM^pZm(*Kfhs+Y1#`-2JPWZMK8@;ZWCk2+9bX4YP);~fj-BU*R zQPvWv$89!{Rl9wM+zR>_TSkn^voYxA?2G iKnV#iZ6Ah`K>b=@=IjYJXrxL124zR(38)nxe+&q_$QXwJ literal 0 HcmV?d00001 From f5477d1748905aab3792efa1c4462d5cca6accb8 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Thu, 12 Nov 2015 12:23:18 -0800 Subject: [PATCH 016/471] Remove System beta tag in project.json for coreclr packages. --- src/Microsoft.AspNet.JsonPatch/project.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Microsoft.AspNet.JsonPatch/project.json b/src/Microsoft.AspNet.JsonPatch/project.json index d9b41653fb..4bbe747d4b 100644 --- a/src/Microsoft.AspNet.JsonPatch/project.json +++ b/src/Microsoft.AspNet.JsonPatch/project.json @@ -15,15 +15,15 @@ "net451": {}, "dotnet5.4": { "dependencies": { - "Microsoft.CSharp": "4.0.1-beta-*", - "System.Collections.Concurrent": "4.0.11-beta-*", - "System.ComponentModel.TypeConverter": "4.0.1-beta-*", - "System.Globalization": "4.0.11-beta-*", - "System.Reflection.Extensions": "4.0.1-beta-*", - "System.Resources.ResourceManager": "4.0.1-beta-*", - "System.Runtime.Extensions": "4.0.11-beta-*", - "System.Text.Encoding.Extensions": "4.0.11-beta-*" + "Microsoft.CSharp": "4.0.1-*", + "System.Collections.Concurrent": "4.0.11-*", + "System.ComponentModel.TypeConverter": "4.0.1-*", + "System.Globalization": "4.0.11-*", + "System.Reflection.Extensions": "4.0.1-*", + "System.Resources.ResourceManager": "4.0.1-*", + "System.Runtime.Extensions": "4.0.11-*", + "System.Text.Encoding.Extensions": "4.0.11-*" } } } -} \ No newline at end of file +} From 02e99e341e91bf72bd7ac210a7c581ef6889c4d2 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Tue, 17 Nov 2015 11:03:11 -0800 Subject: [PATCH 017/471] Explicitly choose Mono 4.0.5 - avoids future problems related to aspnet/External#48 - e.g. when Travis updates default Mono version in `csharp` bundle --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 947bf868ee..dc44c0f660 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,6 @@ language: csharp sudo: false +mono: + - 4.0.5 script: - ./build.sh --quiet verify \ No newline at end of file From b09bdc08f48cbddff43a7ad6045a69b4c8258c11 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Tue, 17 Nov 2015 14:01:02 -0800 Subject: [PATCH 018/471] Move Travis to supported Linux distribution - use Ubuntu 14.04 (Trusty) - Travis support for Trusty is in Beta and currently requires `sudo` - run `dnu restore` with DNX Core since aspnet/External#49 is not fixed in Mono versions we can use - add required dependencies for DNX Core to `.travis.yml` - addresses part of aspnet/Universe#290 --- .travis.yml | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index dc44c0f660..2fc624899f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,18 @@ language: csharp -sudo: false +sudo: required +dist: trusty +addons: + apt: + packages: + - gettext + - libcurl4-openssl-dev + - libicu-dev + - libssl-dev + - libunwind8 + - zlib1g +env: + - KOREBUILD_DNU_RESTORE_CORECLR=true mono: - 4.0.5 script: - - ./build.sh --quiet verify \ No newline at end of file + - ./build.sh --quiet verify From 60f5fd591ef301428347de955c02ee06286732db Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 23 Nov 2015 16:40:15 -0800 Subject: [PATCH 019/471] Updating tests to run on dnxcore50 --- .../Dynamic/AddOperationTests.cs | 36 +++++++-------- .../Dynamic/AddTypedOperationTests.cs | 6 +-- .../Dynamic/PatchDocumentTests.cs | 12 ++--- .../Dynamic/RemoveOperationTests.cs | 46 +++++++++---------- .../Dynamic/RemoveTypedOperationTests.cs | 8 ++-- .../Dynamic/SimpleDTOWithNestedDTO.cs | 2 +- .../NestedObjectTests.cs | 29 ++++++------ .../ObjectAdapterTests.cs | 8 ++-- .../SimpleDTO.cs | 1 - .../TestErrorLogger.cs | 2 +- .../project.json | 36 +++++++++------ 11 files changed, 96 insertions(+), 90 deletions(-) diff --git a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/AddOperationTests.cs b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/AddOperationTests.cs index 3c2523c5fb..f5a3c384ef 100644 --- a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/AddOperationTests.cs +++ b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/AddOperationTests.cs @@ -18,7 +18,7 @@ namespace Microsoft.AspNet.JsonPatch.Test.Dynamic dynamic doc = new { Test = 1 - }; + }; // create patch JsonPatchDocument patchDoc = new JsonPatchDocument(); @@ -33,14 +33,14 @@ namespace Microsoft.AspNet.JsonPatch.Test.Dynamic }); Assert.Equal( "The property at path '/NewInt' could not be added.", - exception.Message); + exception.Message); } [Fact] public void AddNewProperty() { dynamic obj = new ExpandoObject(); - obj.Test = 1; + obj.Test = 1; // create patch JsonPatchDocument patchDoc = new JsonPatchDocument(); @@ -48,7 +48,7 @@ namespace Microsoft.AspNet.JsonPatch.Test.Dynamic var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); - + deserialized.ApplyTo(obj); Assert.Equal(1, obj.NewInt); @@ -104,7 +104,7 @@ namespace Microsoft.AspNet.JsonPatch.Test.Dynamic "The property at path '/Nested/NewInt' could not be added.", exception.Message); } - + [Fact] public void AddToExistingPropertyOnNestedObject() { @@ -120,7 +120,7 @@ namespace Microsoft.AspNet.JsonPatch.Test.Dynamic var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); - + deserialized.ApplyTo(doc); Assert.Equal("A", doc.nested.StringProperty); @@ -142,13 +142,13 @@ namespace Microsoft.AspNet.JsonPatch.Test.Dynamic var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); - + deserialized.ApplyTo(doc); Assert.Equal(1, doc.nested.NewInt); Assert.Equal(1, doc.Test); } - + [Fact] public void AddNewPropertyToExpandoOjectInTypedObject() { @@ -156,7 +156,7 @@ namespace Microsoft.AspNet.JsonPatch.Test.Dynamic { DynamicProperty = new ExpandoObject() }; - + // create patch JsonPatchDocument patchDoc = new JsonPatchDocument(); patchDoc.Add("DynamicProperty/NewInt", 1); @@ -168,9 +168,9 @@ namespace Microsoft.AspNet.JsonPatch.Test.Dynamic Assert.Equal(1, doc.DynamicProperty.NewInt); } - + [Fact] - public void AddNewPropertyToTypedObjectInExpandoObject() + public void AddNewPropertyToTypedObjectInExpandoObject() { dynamic dynamicProperty = new ExpandoObject(); dynamicProperty.StringProperty = "A"; @@ -246,7 +246,7 @@ namespace Microsoft.AspNet.JsonPatch.Test.Dynamic public void AddResultsShouldReplace() { dynamic doc = new ExpandoObject(); - doc.StringProperty = "A"; + doc.StringProperty = "A"; // create patch JsonPatchDocument patchDoc = new JsonPatchDocument(); @@ -289,11 +289,11 @@ namespace Microsoft.AspNet.JsonPatch.Test.Dynamic doc.Nested.DynamicProperty.InBetweenFirst = new ExpandoObject(); doc.Nested.DynamicProperty.InBetweenFirst.InBetweenSecond = new ExpandoObject(); doc.Nested.DynamicProperty.InBetweenFirst.InBetweenSecond.StringProperty = "A"; - + // create patch JsonPatchDocument patchDoc = new JsonPatchDocument(); patchDoc.Add("/Nested/DynamicProperty/InBetweenFirst/InBetweenSecond/StringProperty", "B"); - + var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); @@ -301,7 +301,7 @@ namespace Microsoft.AspNet.JsonPatch.Test.Dynamic Assert.Equal("B", doc.Nested.DynamicProperty.InBetweenFirst.InBetweenSecond.StringProperty); } - + [Fact] public void ShouldNotBeAbleToAddToNonExistingPropertyThatIsNotTheRoot() { @@ -387,7 +387,7 @@ namespace Microsoft.AspNet.JsonPatch.Test.Dynamic // create patch JsonPatchDocument patchDoc = new JsonPatchDocument(); patchDoc.Add("stringproperty", "B"); - + var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); @@ -415,7 +415,7 @@ namespace Microsoft.AspNet.JsonPatch.Test.Dynamic Assert.Equal(new List() { 4, 1, 2, 3 }, doc.IntegerList); } - + [Fact] public void AddToListNegativePosition() { @@ -452,7 +452,7 @@ namespace Microsoft.AspNet.JsonPatch.Test.Dynamic var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); - + deserialized.ApplyTo(doc); Assert.Equal(new List() { 4, 1, 2, 3 }, doc.IntegerList); diff --git a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/AddTypedOperationTests.cs b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/AddTypedOperationTests.cs index 4d2e8c646d..7913541514 100644 --- a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/AddTypedOperationTests.cs +++ b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/AddTypedOperationTests.cs @@ -21,7 +21,7 @@ namespace Microsoft.AspNet.JsonPatch.Test.Dynamic // create patch JsonPatchDocument patchDoc = new JsonPatchDocument(); patchDoc.Add("IntegerList/-1", 4); - + var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); @@ -101,11 +101,11 @@ namespace Microsoft.AspNet.JsonPatch.Test.Dynamic IntegerList = new List() { 1, 2, 3 } } } - }; + }; // create patch JsonPatchDocument patchDoc = new JsonPatchDocument(); patchDoc.Add("ListOfSimpleDTO/20/IntegerList/0", 4); - + var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); diff --git a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/PatchDocumentTests.cs b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/PatchDocumentTests.cs index e15f85da8e..8b14c3448b 100644 --- a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/PatchDocumentTests.cs +++ b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/PatchDocumentTests.cs @@ -8,7 +8,7 @@ using Xunit; namespace Microsoft.AspNet.JsonPatch.Test.Dynamic { public class PatchDocumentTests - { + { [Fact] public void InvalidPathAtBeginningShouldThrowException() { @@ -20,11 +20,11 @@ namespace Microsoft.AspNet.JsonPatch.Test.Dynamic Assert.Equal( "The provided string '//NewInt' is an invalid path.", exception.Message); - } + } [Fact] public void InvalidPathAtEndShouldThrowException() - { + { JsonPatchDocument patchDoc = new JsonPatchDocument(); var exception = Assert.Throws(() => { @@ -33,11 +33,11 @@ namespace Microsoft.AspNet.JsonPatch.Test.Dynamic Assert.Equal( "The provided string 'NewInt//' is an invalid path.", exception.Message); - } + } [Fact] public void InvalidPathWithDotShouldThrowException() - { + { JsonPatchDocument patchDoc = new JsonPatchDocument(); var exception = Assert.Throws(() => { @@ -56,7 +56,7 @@ namespace Microsoft.AspNet.JsonPatch.Test.Dynamic StringProperty = "A", AnotherStringProperty = "B" }; - + JsonPatchDocument patchDoc = new JsonPatchDocument(); patchDoc.Copy("StringProperty", "AnotherStringProperty"); diff --git a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/RemoveOperationTests.cs b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/RemoveOperationTests.cs index 9ef28ad7cc..9ecb520b38 100644 --- a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/RemoveOperationTests.cs +++ b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/RemoveOperationTests.cs @@ -39,7 +39,7 @@ namespace Microsoft.AspNet.JsonPatch.Test.Dynamic public void RemovePropertyShouldFailIfItDoesntExist() { dynamic doc = new ExpandoObject(); - doc.Test = 1; + doc.Test = 1; // create patch JsonPatchDocument patchDoc = new JsonPatchDocument(); @@ -61,7 +61,7 @@ namespace Microsoft.AspNet.JsonPatch.Test.Dynamic public void RemovePropertyFromExpandoObject() { dynamic obj = new ExpandoObject(); - obj.Test = 1; + obj.Test = 1; // create patch JsonPatchDocument patchDoc = new JsonPatchDocument(); @@ -69,13 +69,13 @@ namespace Microsoft.AspNet.JsonPatch.Test.Dynamic var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); - + deserialized.ApplyTo(obj); var cont = obj as IDictionary; object valueFromDictionary; - cont.TryGetValue("Test", out valueFromDictionary); + cont.TryGetValue("Test", out valueFromDictionary); Assert.Null(valueFromDictionary); } @@ -91,7 +91,7 @@ namespace Microsoft.AspNet.JsonPatch.Test.Dynamic var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); - + deserialized.ApplyTo(obj); var cont = obj as IDictionary; @@ -137,7 +137,7 @@ namespace Microsoft.AspNet.JsonPatch.Test.Dynamic var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); - + deserialized.ApplyTo(obj); var cont = obj as IDictionary; @@ -151,9 +151,9 @@ namespace Microsoft.AspNet.JsonPatch.Test.Dynamic { dynamic doc = new ExpandoObject(); doc.SimpleDTO = new SimpleDTO() - { - StringProperty = "A" - }; + { + StringProperty = "A" + }; // create patch JsonPatchDocument patchDoc = new JsonPatchDocument(); @@ -192,10 +192,10 @@ namespace Microsoft.AspNet.JsonPatch.Test.Dynamic { dynamic doc = new ExpandoObject(); doc.SimpleDTO = new SimpleDTO() - { - IntegerList = new List() { 1, 2, 3 } - }; - + { + IntegerList = new List() { 1, 2, 3 } + }; + // create patch JsonPatchDocument patchDoc = new JsonPatchDocument(); patchDoc.Remove("SimpleDTO/IntegerList/2"); @@ -216,7 +216,7 @@ namespace Microsoft.AspNet.JsonPatch.Test.Dynamic { IntegerList = new List() { 1, 2, 3 } }; - + // create patch JsonPatchDocument patchDoc = new JsonPatchDocument(); patchDoc.Remove("SimpleDTO/Integerlist/2"); @@ -234,9 +234,9 @@ namespace Microsoft.AspNet.JsonPatch.Test.Dynamic { dynamic doc = new ExpandoObject(); doc.SimpleDTO = new SimpleDTO() - { - IntegerList = new List() { 1, 2, 3 } - }; + { + IntegerList = new List() { 1, 2, 3 } + }; // create patch JsonPatchDocument patchDoc = new JsonPatchDocument(); @@ -259,9 +259,9 @@ namespace Microsoft.AspNet.JsonPatch.Test.Dynamic { dynamic doc = new ExpandoObject(); doc.SimpleDTO = new SimpleDTO() - { - IntegerList = new List() { 1, 2, 3 } - }; + { + IntegerList = new List() { 1, 2, 3 } + }; // create patch JsonPatchDocument patchDoc = new JsonPatchDocument(); @@ -284,9 +284,9 @@ namespace Microsoft.AspNet.JsonPatch.Test.Dynamic { dynamic doc = new ExpandoObject(); doc.SimpleDTO = new SimpleDTO() - { - IntegerList = new List() { 1, 2, 3 } - }; + { + IntegerList = new List() { 1, 2, 3 } + }; // create patch JsonPatchDocument patchDoc = new JsonPatchDocument(); diff --git a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/RemoveTypedOperationTests.cs b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/RemoveTypedOperationTests.cs index db5d6502d1..802fb27e40 100644 --- a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/RemoveTypedOperationTests.cs +++ b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/RemoveTypedOperationTests.cs @@ -73,7 +73,7 @@ namespace Microsoft.AspNet.JsonPatch.Test.Dynamic "For operation 'remove' on array property at path '/IntegerList/3', the index is larger than the array size.", exception.Message); } - + [Fact] public void RemoveFromListInvalidPositionTooSmall() { @@ -135,7 +135,7 @@ namespace Microsoft.AspNet.JsonPatch.Test.Dynamic var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); - + deserialized.ApplyTo(doc); Assert.Equal(null, doc.SimpleDTO.StringProperty); @@ -190,7 +190,7 @@ namespace Microsoft.AspNet.JsonPatch.Test.Dynamic "For operation 'remove' on array property at path '/SimpleDTO/IntegerList/3', the index is larger than the array size.", exception.Message); } - + [Fact] public void NestedRemoveFromListInvalidPositionTooSmall() { @@ -216,7 +216,7 @@ namespace Microsoft.AspNet.JsonPatch.Test.Dynamic Assert.Equal( "For operation 'remove' on array property at path '/SimpleDTO/IntegerList/-1', the index is negative.", exception.Message); - } + } [Fact] public void NestedRemoveFromEndOfList() diff --git a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/SimpleDTOWithNestedDTO.cs b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/SimpleDTOWithNestedDTO.cs index 2147fcceb1..03c74f8a1b 100644 --- a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/SimpleDTOWithNestedDTO.cs +++ b/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/SimpleDTOWithNestedDTO.cs @@ -11,7 +11,7 @@ namespace Microsoft.AspNet.JsonPatch.Test.Dynamic public NestedDTO NestedDTO { get; set; } public SimpleDTO SimpleDTO { get; set; } public List ListOfSimpleDTO { get; set; } - + public SimpleDTOWithNestedDTO() { NestedDTO = new NestedDTO(); diff --git a/test/Microsoft.AspNet.JsonPatch.Test/NestedObjectTests.cs b/test/Microsoft.AspNet.JsonPatch.Test/NestedObjectTests.cs index 33649b7788..e736373ed8 100644 --- a/test/Microsoft.AspNet.JsonPatch.Test/NestedObjectTests.cs +++ b/test/Microsoft.AspNet.JsonPatch.Test/NestedObjectTests.cs @@ -1,11 +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. -using Microsoft.AspNet.JsonPatch.Exceptions; -using Newtonsoft.Json; -using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using Microsoft.AspNet.JsonPatch.Exceptions; +using Newtonsoft.Json; using Xunit; namespace Microsoft.AspNet.JsonPatch.Test @@ -388,7 +387,7 @@ namespace Microsoft.AspNet.JsonPatch.Test var exception = Assert.Throws(() => { patchDoc.ApplyTo(doc); }); Assert.Equal( "For operation 'add' on array property at path '/simpledto/integerlist/4', the index is " + - "larger than the array size.", + "larger than the array size.", exception.Message); } @@ -442,7 +441,7 @@ namespace Microsoft.AspNet.JsonPatch.Test var logger = new TestErrorLogger(); patchDoc.ApplyTo(doc, logger.LogErrorMessage); - + //Assert Assert.Equal( @@ -524,8 +523,8 @@ namespace Microsoft.AspNet.JsonPatch.Test patchDoc.ApplyTo(doc, logger.LogErrorMessage); - - + + //Assert Assert.Equal( "For operation 'add' on array property at path '/simpledto/integerlist/-1', the index is negative.", @@ -750,9 +749,9 @@ namespace Microsoft.AspNet.JsonPatch.Test patchDoc.Remove(o => o.SimpleDTO.IntegerList, 3); var logger = new TestErrorLogger(); - + patchDoc.ApplyTo(doc, logger.LogErrorMessage); - + // Assert Assert.Equal( "For operation 'remove' on array property at path '/simpledto/integerlist/3', the index is " + @@ -828,7 +827,7 @@ namespace Microsoft.AspNet.JsonPatch.Test patchDoc.ApplyTo(doc, logger.LogErrorMessage); - + // Assert Assert.Equal("For operation 'remove' on array property at path '/simpledto/integerlist/-1', the index is negative.", logger.ErrorMessage); } @@ -1293,9 +1292,9 @@ namespace Microsoft.AspNet.JsonPatch.Test var logger = new TestErrorLogger(); - + patchDoc.ApplyTo(doc, logger.LogErrorMessage); - + // Assert Assert.Equal( @@ -1319,7 +1318,7 @@ namespace Microsoft.AspNet.JsonPatch.Test // create patch var patchDoc = new JsonPatchDocument(); patchDoc.Replace(o => o.SimpleDTO.IntegerList, 5, -1); - + // Act & Assert var exception = Assert.Throws(() => { patchDoc.ApplyTo(doc); }); Assert.Equal("For operation 'replace' on array property at path '/simpledto/integerlist/-1', the index is negative.", @@ -1371,8 +1370,8 @@ namespace Microsoft.AspNet.JsonPatch.Test var logger = new TestErrorLogger(); - patchDoc.ApplyTo(doc, logger.LogErrorMessage); - + patchDoc.ApplyTo(doc, logger.LogErrorMessage); + // Assert Assert.Equal( diff --git a/test/Microsoft.AspNet.JsonPatch.Test/ObjectAdapterTests.cs b/test/Microsoft.AspNet.JsonPatch.Test/ObjectAdapterTests.cs index 0cc97e32c4..85d9404e6d 100644 --- a/test/Microsoft.AspNet.JsonPatch.Test/ObjectAdapterTests.cs +++ b/test/Microsoft.AspNet.JsonPatch.Test/ObjectAdapterTests.cs @@ -202,7 +202,7 @@ namespace Microsoft.AspNet.JsonPatch.Test var logger = new TestErrorLogger(); patchDoc.ApplyTo(doc, logger.LogErrorMessage); - + // Assert Assert.Equal( @@ -356,7 +356,7 @@ namespace Microsoft.AspNet.JsonPatch.Test var logger = new TestErrorLogger(); patchDoc.ApplyTo(doc, logger.LogErrorMessage); - + // Assert Assert.Equal( "For operation 'add' on array property at path '/integerlist/-1', the index is negative.", @@ -553,7 +553,7 @@ namespace Microsoft.AspNet.JsonPatch.Test var logger = new TestErrorLogger(); patchDoc.ApplyTo(doc, logger.LogErrorMessage); - + // Assert Assert.Equal( @@ -618,7 +618,7 @@ namespace Microsoft.AspNet.JsonPatch.Test patchDoc.ApplyTo(doc, logger.LogErrorMessage); - + // Assert Assert.Equal("For operation 'remove' on array property at path '/integerlist/-1', the index is negative.", logger.ErrorMessage); diff --git a/test/Microsoft.AspNet.JsonPatch.Test/SimpleDTO.cs b/test/Microsoft.AspNet.JsonPatch.Test/SimpleDTO.cs index 0c29a86e83..b1177bc5ce 100644 --- a/test/Microsoft.AspNet.JsonPatch.Test/SimpleDTO.cs +++ b/test/Microsoft.AspNet.JsonPatch.Test/SimpleDTO.cs @@ -2,7 +2,6 @@ // 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.AspNet.JsonPatch.Test diff --git a/test/Microsoft.AspNet.JsonPatch.Test/TestErrorLogger.cs b/test/Microsoft.AspNet.JsonPatch.Test/TestErrorLogger.cs index c254eab3e3..525321cfb3 100644 --- a/test/Microsoft.AspNet.JsonPatch.Test/TestErrorLogger.cs +++ b/test/Microsoft.AspNet.JsonPatch.Test/TestErrorLogger.cs @@ -3,7 +3,7 @@ namespace Microsoft.AspNet.JsonPatch.Test { - public class TestErrorLogger where T: class + public class TestErrorLogger where T : class { public string ErrorMessage { get; set; } diff --git a/test/Microsoft.AspNet.JsonPatch.Test/project.json b/test/Microsoft.AspNet.JsonPatch.Test/project.json index 629b7a1be3..8b97af645a 100644 --- a/test/Microsoft.AspNet.JsonPatch.Test/project.json +++ b/test/Microsoft.AspNet.JsonPatch.Test/project.json @@ -1,18 +1,26 @@ { - "compilationOptions": { - "warningsAsErrors": true + "compilationOptions": { + "warningsAsErrors": true + }, + "dependencies": { + "Microsoft.AspNet.JsonPatch": "1.0.0-*", + "Microsoft.AspNet.Testing": "1.0.0-*", + "Newtonsoft.Json": "6.0.6", + "xunit.runner.aspnet": "2.0.0-aspnet-*" + }, + "commands": { + "test": "xunit.runner.aspnet" + }, + "frameworks": { + "dnx451": { + "dependencies": { + "Moq": "4.2.1312.1622" + } }, - "dependencies": { - "Microsoft.AspNet.JsonPatch": "1.0.0-*", - "Microsoft.AspNet.Testing": "1.0.0-*", - "Moq": "4.2.1312.1622", - "Newtonsoft.Json": "6.0.6", - "xunit.runner.aspnet": "2.0.0-aspnet-*" - }, - "commands": { - "test": "xunit.runner.aspnet" - }, - "frameworks": { - "dnx451": { } + "dnxcore50": { + "dependencies": { + "moq.netcore": "4.4.0-beta8" + } } + } } \ No newline at end of file From a2e4c4e13362a54a2b1610b9b878cf60d691bc73 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 1 Dec 2015 11:01:13 -0800 Subject: [PATCH 020/471] Enabling tests on CoreCLR --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2fc624899f..c0befaffcf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ addons: - libunwind8 - zlib1g env: - - KOREBUILD_DNU_RESTORE_CORECLR=true + - KOREBUILD_DNU_RESTORE_CORECLR=true KOREBUILD_TEST_DNXCORE=true mono: - 4.0.5 script: From 48243bbc0cc25e80a84be37b714ae04833814cf1 Mon Sep 17 00:00:00 2001 From: Eilon Lipton Date: Tue, 1 Dec 2015 14:35:51 -0800 Subject: [PATCH 021/471] Create README.md --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000000..add6834eeb --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +HtmlAbstractions +========== + +HTML abstractions such as `IHtmlContent` and related APIs. + +This project is part of ASP.NET 5. You can find samples, documentation and getting started instructions for ASP.NET 5 at the [Home](https://github.com/aspnet/home) repo. From 95ae9483491ce2f12e6d47fd0064132d1c59c065 Mon Sep 17 00:00:00 2001 From: Eilon Lipton Date: Tue, 1 Dec 2015 14:36:15 -0800 Subject: [PATCH 022/471] Create LICENSE.txt --- LICENSE.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 LICENSE.txt diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000000..0bdc1962b6 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,12 @@ +Copyright (c) .NET Foundation. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +these files except in compliance with the License. You may obtain a copy of the +License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed +under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. From b14fa9d990f65c3c07c4e800d1eccfa5479d6a5d Mon Sep 17 00:00:00 2001 From: Eilon Lipton Date: Tue, 1 Dec 2015 14:36:26 -0800 Subject: [PATCH 023/471] Create CONTRIBUTING.md --- CONTRIBUTING.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000..64ff041d5c --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,4 @@ +Contributing +====== + +Information on contributing to this repo is in the [Contributing Guide](https://github.com/aspnet/Home/blob/dev/CONTRIBUTING.md) in the Home repo. From f9661e2bf1b799c68396bb38fa4d942516c9f16a Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 1 Dec 2015 14:58:47 -0800 Subject: [PATCH 024/471] Initial commit --- .gitattributes | 50 ++ .gitignore | 27 ++ .travis.yml | 18 + HtmlAbstractions.sln | 55 +++ NuGet.config | 7 + NuGetPackageVerifier.json | 25 + appveyor.yml | 7 + build.cmd | 40 ++ build.sh | 43 ++ global.json | 3 + makefile.shade | 10 + .../HtmlContentBuilder.cs | 138 ++++++ .../HtmlContentBuilderExtensions.cs | 324 +++++++++++++ .../HtmlEncodedString.cs | 49 ++ src/Microsoft.AspNet.Html/HtmlTextWriter.cs | 49 ++ src/Microsoft.AspNet.Html/IHtmlContent.cs | 22 + .../IHtmlContentBuilder.cs | 40 ++ .../Microsoft.AspNet.Html.xproj | 19 + .../Properties/AssemblyInfo.cs | 10 + src/Microsoft.AspNet.Html/project.json | 29 ++ .../HtmlContentBuilderExtensionsTest.cs | 436 ++++++++++++++++++ .../HtmlContentBuilderTest.cs | 145 ++++++ .../Microsoft.AspNet.Html.Test.xproj | 21 + test/Microsoft.AspNet.Html.Test/project.json | 19 + tools/Key.snk | Bin 0 -> 596 bytes 25 files changed, 1586 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 HtmlAbstractions.sln create mode 100644 NuGet.config create mode 100644 NuGetPackageVerifier.json create mode 100644 appveyor.yml create mode 100644 build.cmd create mode 100755 build.sh create mode 100644 global.json create mode 100644 makefile.shade create mode 100644 src/Microsoft.AspNet.Html/HtmlContentBuilder.cs create mode 100644 src/Microsoft.AspNet.Html/HtmlContentBuilderExtensions.cs create mode 100644 src/Microsoft.AspNet.Html/HtmlEncodedString.cs create mode 100644 src/Microsoft.AspNet.Html/HtmlTextWriter.cs create mode 100644 src/Microsoft.AspNet.Html/IHtmlContent.cs create mode 100644 src/Microsoft.AspNet.Html/IHtmlContentBuilder.cs create mode 100644 src/Microsoft.AspNet.Html/Microsoft.AspNet.Html.xproj create mode 100644 src/Microsoft.AspNet.Html/Properties/AssemblyInfo.cs create mode 100644 src/Microsoft.AspNet.Html/project.json create mode 100644 test/Microsoft.AspNet.Html.Test/HtmlContentBuilderExtensionsTest.cs create mode 100644 test/Microsoft.AspNet.Html.Test/HtmlContentBuilderTest.cs create mode 100644 test/Microsoft.AspNet.Html.Test/Microsoft.AspNet.Html.Test.xproj create mode 100644 test/Microsoft.AspNet.Html.Test/project.json create mode 100644 tools/Key.snk diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..bdaa5ba982 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,50 @@ +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain + +*.jpg binary +*.png binary +*.gif binary + +*.cs text=auto diff=csharp +*.vb text=auto +*.resx text=auto +*.c text=auto +*.cpp text=auto +*.cxx text=auto +*.h text=auto +*.hxx text=auto +*.py text=auto +*.rb text=auto +*.java text=auto +*.html text=auto +*.htm text=auto +*.css text=auto +*.scss text=auto +*.sass text=auto +*.less text=auto +*.js text=auto +*.lisp text=auto +*.clj text=auto +*.sql text=auto +*.php text=auto +*.lua text=auto +*.m text=auto +*.asm text=auto +*.erl text=auto +*.fs text=auto +*.fsx text=auto +*.hs text=auto + +*.csproj text=auto +*.vbproj text=auto +*.fsproj text=auto +*.dbproj text=auto +*.sln text=auto eol=crlf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..ac82da7568 --- /dev/null +++ b/.gitignore @@ -0,0 +1,27 @@ +[Oo]bj/ +[Bb]in/ +TestResults/ +.nuget/ +_ReSharper.*/ +packages/ +artifacts/ +PublishProfiles/ +*.user +*.suo +*.cache +*.docstates +_ReSharper.* +nuget.exe +*net45.csproj +*net451.csproj +*k10.csproj +*.psess +*.vsp +*.pidb +*.userprefs +*DS_Store +*.ncrunchsolution +*.*sdf +*.ipch +*.sln.ide +project.lock.json diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000000..c0befaffcf --- /dev/null +++ b/.travis.yml @@ -0,0 +1,18 @@ +language: csharp +sudo: required +dist: trusty +addons: + apt: + packages: + - gettext + - libcurl4-openssl-dev + - libicu-dev + - libssl-dev + - libunwind8 + - zlib1g +env: + - KOREBUILD_DNU_RESTORE_CORECLR=true KOREBUILD_TEST_DNXCORE=true +mono: + - 4.0.5 +script: + - ./build.sh --quiet verify diff --git a/HtmlAbstractions.sln b/HtmlAbstractions.sln new file mode 100644 index 0000000000..1d1f5118f3 --- /dev/null +++ b/HtmlAbstractions.sln @@ -0,0 +1,55 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.24711.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A5A15F1C-885A-452A-A731-B0173DDBD913}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{F31FF137-390C-49BF-A3BD-7C6ED3597C21}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Html", "src\Microsoft.AspNet.Html.Abstractions\Microsoft.AspNet.Html.xproj", "{68A28E4A-3ADE-4187-9625-4FF185887CB3}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Html.Test", "test\Microsoft.AspNet.Html.Abstractions.Test\Microsoft.AspNet.Html.Test.xproj", "{2D187B88-94BD-4A39-AC97-F8F8B9363301}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {68A28E4A-3ADE-4187-9625-4FF185887CB3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {68A28E4A-3ADE-4187-9625-4FF185887CB3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {68A28E4A-3ADE-4187-9625-4FF185887CB3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {68A28E4A-3ADE-4187-9625-4FF185887CB3}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {68A28E4A-3ADE-4187-9625-4FF185887CB3}.Debug|x86.ActiveCfg = Debug|Any CPU + {68A28E4A-3ADE-4187-9625-4FF185887CB3}.Debug|x86.Build.0 = Debug|Any CPU + {68A28E4A-3ADE-4187-9625-4FF185887CB3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {68A28E4A-3ADE-4187-9625-4FF185887CB3}.Release|Any CPU.Build.0 = Release|Any CPU + {68A28E4A-3ADE-4187-9625-4FF185887CB3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {68A28E4A-3ADE-4187-9625-4FF185887CB3}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {68A28E4A-3ADE-4187-9625-4FF185887CB3}.Release|x86.ActiveCfg = Release|Any CPU + {68A28E4A-3ADE-4187-9625-4FF185887CB3}.Release|x86.Build.0 = Release|Any CPU + {2D187B88-94BD-4A39-AC97-F8F8B9363301}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2D187B88-94BD-4A39-AC97-F8F8B9363301}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2D187B88-94BD-4A39-AC97-F8F8B9363301}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {2D187B88-94BD-4A39-AC97-F8F8B9363301}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {2D187B88-94BD-4A39-AC97-F8F8B9363301}.Debug|x86.ActiveCfg = Debug|Any CPU + {2D187B88-94BD-4A39-AC97-F8F8B9363301}.Debug|x86.Build.0 = Debug|Any CPU + {2D187B88-94BD-4A39-AC97-F8F8B9363301}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2D187B88-94BD-4A39-AC97-F8F8B9363301}.Release|Any CPU.Build.0 = Release|Any CPU + {2D187B88-94BD-4A39-AC97-F8F8B9363301}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {2D187B88-94BD-4A39-AC97-F8F8B9363301}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {2D187B88-94BD-4A39-AC97-F8F8B9363301}.Release|x86.ActiveCfg = Release|Any CPU + {2D187B88-94BD-4A39-AC97-F8F8B9363301}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {68A28E4A-3ADE-4187-9625-4FF185887CB3} = {A5A15F1C-885A-452A-A731-B0173DDBD913} + {2D187B88-94BD-4A39-AC97-F8F8B9363301} = {F31FF137-390C-49BF-A3BD-7C6ED3597C21} + EndGlobalSection +EndGlobal diff --git a/NuGet.config b/NuGet.config new file mode 100644 index 0000000000..03704957e8 --- /dev/null +++ b/NuGet.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/NuGetPackageVerifier.json b/NuGetPackageVerifier.json new file mode 100644 index 0000000000..c57b2afb17 --- /dev/null +++ b/NuGetPackageVerifier.json @@ -0,0 +1,25 @@ +{ + "adx": { // Packages written by the ADX team and that ship on NuGet.org + "rules": [ + "AssemblyHasDocumentFileRule", + "AssemblyHasVersionAttributesRule", + "AssemblyHasServicingAttributeRule", + "AssemblyHasNeutralResourcesLanguageAttributeRule", + "SatellitePackageRule", + "StrictSemanticVersionValidationRule" + ], + "packages": { + "Microsoft.AspNet.Html.Abstractions": { } + } + }, + "Default": { // Rules to run for packages not listed in any other set. + "rules": [ + "AssemblyHasDocumentFileRule", + "AssemblyHasVersionAttributesRule", + "AssemblyHasServicingAttributeRule", + "AssemblyHasNeutralResourcesLanguageAttributeRule", + "SatellitePackageRule", + "StrictSemanticVersionValidationRule" + ] + } +} \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000000..636a7618d3 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,7 @@ +init: + - git config --global core.autocrlf true +build_script: + - build.cmd --quiet verify +clone_depth: 1 +test: off +deploy: off \ No newline at end of file diff --git a/build.cmd b/build.cmd new file mode 100644 index 0000000000..553e3929a0 --- /dev/null +++ b/build.cmd @@ -0,0 +1,40 @@ +@echo off +cd %~dp0 + +SETLOCAL +SET NUGET_VERSION=latest +SET CACHED_NUGET=%LocalAppData%\NuGet\nuget.%NUGET_VERSION%.exe +SET BUILDCMD_KOREBUILD_VERSION= +SET BUILDCMD_DNX_VERSION= + +IF EXIST %CACHED_NUGET% goto copynuget +echo Downloading latest version of NuGet.exe... +IF NOT EXIST %LocalAppData%\NuGet md %LocalAppData%\NuGet +@powershell -NoProfile -ExecutionPolicy unrestricted -Command "$ProgressPreference = 'SilentlyContinue'; Invoke-WebRequest 'https://dist.nuget.org/win-x86-commandline/%NUGET_VERSION%/nuget.exe' -OutFile '%CACHED_NUGET%'" + +:copynuget +IF EXIST .nuget\nuget.exe goto restore +md .nuget +copy %CACHED_NUGET% .nuget\nuget.exe > nul + +:restore +IF EXIST packages\Sake goto getdnx +IF "%BUILDCMD_KOREBUILD_VERSION%"=="" ( + .nuget\nuget.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre +) ELSE ( + .nuget\nuget.exe install KoreBuild -version %BUILDCMD_KOREBUILD_VERSION% -ExcludeVersion -o packages -nocache -pre +) +.nuget\NuGet.exe install Sake -ExcludeVersion -Source https://www.nuget.org/api/v2/ -Out packages + +:getdnx +IF "%BUILDCMD_DNX_VERSION%"=="" ( + SET BUILDCMD_DNX_VERSION=latest +) +IF "%SKIP_DNX_INSTALL%"=="" ( + CALL packages\KoreBuild\build\dnvm install %BUILDCMD_DNX_VERSION% -runtime CoreCLR -arch x86 -alias default + CALL packages\KoreBuild\build\dnvm install default -runtime CLR -arch x86 -alias default +) ELSE ( + CALL packages\KoreBuild\build\dnvm use default -runtime CLR -arch x86 +) + +packages\Sake\tools\Sake.exe -I packages\KoreBuild\build -f makefile.shade %* diff --git a/build.sh b/build.sh new file mode 100755 index 0000000000..da4e3fcd1c --- /dev/null +++ b/build.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash + +if test `uname` = Darwin; then + cachedir=~/Library/Caches/KBuild +else + if [ -z $XDG_DATA_HOME ]; then + cachedir=$HOME/.local/share + else + cachedir=$XDG_DATA_HOME; + fi +fi +mkdir -p $cachedir +nugetVersion=latest +cachePath=$cachedir/nuget.$nugetVersion.exe + +url=https://dist.nuget.org/win-x86-commandline/$nugetVersion/nuget.exe + +if test ! -f $cachePath; then + wget -O $cachePath $url 2>/dev/null || curl -o $cachePath --location $url /dev/null +fi + +if test ! -e .nuget; then + mkdir .nuget + cp $cachePath .nuget/nuget.exe +fi + +if test ! -d packages/Sake; then + mono .nuget/nuget.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre + mono .nuget/nuget.exe install Sake -ExcludeVersion -Source https://www.nuget.org/api/v2/ -Out packages +fi + +if ! type dnvm > /dev/null 2>&1; then + source packages/KoreBuild/build/dnvm.sh +fi + +if ! type dnx > /dev/null 2>&1 || [ -z "$SKIP_DNX_INSTALL" ]; then + dnvm install latest -runtime coreclr -alias default + dnvm install default -runtime mono -alias default +else + dnvm use default -runtime mono +fi + +mono packages/Sake/tools/Sake.exe -I packages/KoreBuild/build -f makefile.shade "$@" diff --git a/global.json b/global.json new file mode 100644 index 0000000000..983ba0401e --- /dev/null +++ b/global.json @@ -0,0 +1,3 @@ +{ + "projects": ["src"] +} diff --git a/makefile.shade b/makefile.shade new file mode 100644 index 0000000000..d5e473d558 --- /dev/null +++ b/makefile.shade @@ -0,0 +1,10 @@ + +var VERSION='0.1' +var FULL_VERSION='0.1' +var AUTHORS='Microsoft Open Technologies, Inc.' + +use-standard-lifecycle +k-standard-goals + +#xml-docs-test .clean .build-compile description='Check generated XML documentation files for errors' target='package' + k-xml-docs-test diff --git a/src/Microsoft.AspNet.Html/HtmlContentBuilder.cs b/src/Microsoft.AspNet.Html/HtmlContentBuilder.cs new file mode 100644 index 0000000000..34e59d3318 --- /dev/null +++ b/src/Microsoft.AspNet.Html/HtmlContentBuilder.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.Collections.Generic; +using System.IO; +using System.Text.Encodings.Web; + +namespace Microsoft.AspNet.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)) + { + } + + /// + /// 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 Append(IHtmlContent htmlContent) + { + if (htmlContent == null) + { + return this; + } + + Entries.Add(htmlContent); + return this; + } + + /// + public IHtmlContentBuilder AppendHtml(string encoded) + { + if (!string.IsNullOrEmpty(encoded)) + { + Entries.Add(new HtmlEncodedString(encoded)); + } + + return this; + } + + /// + public IHtmlContentBuilder Clear() + { + Entries.Clear(); + return this; + } + + /// + 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/Microsoft.AspNet.Html/HtmlContentBuilderExtensions.cs b/src/Microsoft.AspNet.Html/HtmlContentBuilderExtensions.cs new file mode 100644 index 0000000000..eabfafbd12 --- /dev/null +++ b/src/Microsoft.AspNet.Html/HtmlContentBuilderExtensions.cs @@ -0,0 +1,324 @@ +// Copyright (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.AspNet.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.Append(new HtmlFormatString(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.Append(new HtmlFormatString(formatProvider, format, args)); + return builder; + } + + /// + /// Appends an . + /// + /// The . + /// The . + public static IHtmlContentBuilder AppendLine(this IHtmlContentBuilder builder) + { + builder.Append(HtmlEncodedString.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) + { + builder.Append(unencoded); + builder.Append(HtmlEncodedString.NewLine); + return builder; + } + + /// + /// Appends an after appending the value. + /// + /// The . + /// The to append. + /// The . + public static IHtmlContentBuilder AppendLine(this IHtmlContentBuilder builder, IHtmlContent content) + { + builder.Append(content); + builder.Append(HtmlEncodedString.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) + { + builder.AppendHtml(encoded); + builder.Append(HtmlEncodedString.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) + { + builder.Clear(); + builder.Append(unencoded); + return builder; + } + + /// + /// Sets the content to the value. + /// + /// The . + /// The value that replaces the content. + /// The . + public static IHtmlContentBuilder SetContent(this IHtmlContentBuilder builder, IHtmlContent content) + { + builder.Clear(); + builder.Append(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) + { + builder.Clear(); + builder.AppendHtml(encoded); + return builder; + } + + [DebuggerDisplay("{DebuggerToString()}")] + private class HtmlFormatString : IHtmlContent + { + private readonly IFormatProvider _formatProvider; + private readonly string _format; + private readonly object[] _args; + + public HtmlFormatString(string format, object[] args) + : this(null, format, args) + { + } + + public HtmlFormatString(IFormatProvider formatProvider, string format, object[] args) + { + Debug.Assert(format != null); + Debug.Assert(args != null); + + _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; + + 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) + { + // This is the case we need to special case. We trust the IHtmlContent instance to do the + // right thing with encoding. + var htmlContent = arg as IHtmlContent; + if (htmlContent != null) + { + using (var writer = new StringWriter()) + { + htmlContent.WriteTo(writer, _encoder); + return writer.ToString(); + } + } + + // 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/Microsoft.AspNet.Html/HtmlEncodedString.cs b/src/Microsoft.AspNet.Html/HtmlEncodedString.cs new file mode 100644 index 0000000000..348588800f --- /dev/null +++ b/src/Microsoft.AspNet.Html/HtmlEncodedString.cs @@ -0,0 +1,49 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Diagnostics; +using System.IO; +using System.Text.Encodings.Web; + +namespace Microsoft.AspNet.Html +{ + /// + /// An impelementation that wraps an HTML encoded . + /// + [DebuggerDisplay("{DebuggerToString()}")] + public class HtmlEncodedString : IHtmlContent + { + /// + /// An instance for . + /// + public static readonly IHtmlContent NewLine = new HtmlEncodedString(Environment.NewLine); + + private readonly string _value; + + /// + /// Creates a new . + /// + /// The HTML encoded value. + public HtmlEncodedString(string value) + { + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + _value = value; + } + + /// + public void WriteTo(TextWriter writer, HtmlEncoder encoder) + { + writer.Write(_value); + } + + private string DebuggerToString() + { + return _value; + } + } +} diff --git a/src/Microsoft.AspNet.Html/HtmlTextWriter.cs b/src/Microsoft.AspNet.Html/HtmlTextWriter.cs new file mode 100644 index 0000000000..56633f527d --- /dev/null +++ b/src/Microsoft.AspNet.Html/HtmlTextWriter.cs @@ -0,0 +1,49 @@ +// Copyright (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; + +namespace Microsoft.AspNet.Html +{ + /// + /// A which supports special processing of . + /// + public abstract class HtmlTextWriter : TextWriter + { + /// + /// Writes an value. + /// + /// The value. + public abstract void Write(IHtmlContent value); + + /// + public override void Write(object value) + { + var htmlContent = value as IHtmlContent; + if (htmlContent == null) + { + base.Write(value); + } + else + { + Write(htmlContent); + } + } + + /// + public override void WriteLine(object value) + { + var htmlContent = value as IHtmlContent; + if (htmlContent == null) + { + base.Write(value); + } + else + { + Write(htmlContent); + } + + base.WriteLine(); + } + } +} diff --git a/src/Microsoft.AspNet.Html/IHtmlContent.cs b/src/Microsoft.AspNet.Html/IHtmlContent.cs new file mode 100644 index 0000000000..0e21889d54 --- /dev/null +++ b/src/Microsoft.AspNet.Html/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.AspNet.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/Microsoft.AspNet.Html/IHtmlContentBuilder.cs b/src/Microsoft.AspNet.Html/IHtmlContentBuilder.cs new file mode 100644 index 0000000000..de4b9ebd90 --- /dev/null +++ b/src/Microsoft.AspNet.Html/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.AspNet.Html +{ + /// + /// A builder for HTML content. + /// + public interface IHtmlContentBuilder : IHtmlContent + { + /// + /// Appends an instance. + /// + /// The to append. + /// The . + IHtmlContentBuilder Append(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/Microsoft.AspNet.Html/Microsoft.AspNet.Html.xproj b/src/Microsoft.AspNet.Html/Microsoft.AspNet.Html.xproj new file mode 100644 index 0000000000..564c800504 --- /dev/null +++ b/src/Microsoft.AspNet.Html/Microsoft.AspNet.Html.xproj @@ -0,0 +1,19 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 68a28e4a-3ade-4187-9625-4ff185887cb3 + Microsoft.AspNet.Html.Abstractions + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin\$(MSBuildProjectName)\ + + + + 2.0 + + + \ No newline at end of file diff --git a/src/Microsoft.AspNet.Html/Properties/AssemblyInfo.cs b/src/Microsoft.AspNet.Html/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..1951d644af --- /dev/null +++ b/src/Microsoft.AspNet.Html/Properties/AssemblyInfo.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. + +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; + +[assembly: AssemblyMetadata("Serviceable", "True")] +[assembly: NeutralResourcesLanguage("en-us")] +[assembly: InternalsVisibleTo("Microsoft.AspNet.Html.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] \ No newline at end of file diff --git a/src/Microsoft.AspNet.Html/project.json b/src/Microsoft.AspNet.Html/project.json new file mode 100644 index 0000000000..55cc30d9b1 --- /dev/null +++ b/src/Microsoft.AspNet.Html/project.json @@ -0,0 +1,29 @@ +{ + "version": "1.0.0-*", + "description": "ASP.NET 5 HTML content interface.", + "repository": { + "type": "git", + "url": "git://github.com/aspnet/htmlabstractions" + }, + "compilationOptions": { + "warningsAsErrors": true, + "keyFile": "../../tools/Key.snk" + }, + "dependencies": { + "System.Text.Encodings.Web": "4.0.0-*" + }, + "frameworks": { + "net451": { + "frameworkAssemblies": { + "System.IO": "", + "System.Runtime": "" + } + }, + "dotnet5.4": { + "dependencies": { + "System.Collections": "4.0.11-*", + "System.Resources.ResourceManager": "4.0.1-*" + } + } + } +} diff --git a/test/Microsoft.AspNet.Html.Test/HtmlContentBuilderExtensionsTest.cs b/test/Microsoft.AspNet.Html.Test/HtmlContentBuilderExtensionsTest.cs new file mode 100644 index 0000000000..6253bf9be3 --- /dev/null +++ b/test/Microsoft.AspNet.Html.Test/HtmlContentBuilderExtensionsTest.cs @@ -0,0 +1,436 @@ +// Copyright (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.AspNet.Testing; +using Microsoft.Extensions.WebEncoders.Testing; +using Xunit; + +namespace Microsoft.AspNet.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.SetContent(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_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 Append(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 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/test/Microsoft.AspNet.Html.Test/HtmlContentBuilderTest.cs b/test/Microsoft.AspNet.Html.Test/HtmlContentBuilderTest.cs new file mode 100644 index 0000000000..4eee28e219 --- /dev/null +++ b/test/Microsoft.AspNet.Html.Test/HtmlContentBuilderTest.cs @@ -0,0 +1,145 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.IO; +using System.Text.Encodings.Web; +using Microsoft.AspNet.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 + 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.Append(new TestHtmlContent("Hello")); + + // Assert + 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.Append(new TestHtmlContent("hello")); + content.Append("Test"); + + // Assert + Assert.Equal(2, content.Entries.Count); + Assert.Equal("Written from TestHtmlContent: hello", content.Entries[0].ToString()); + Assert.Equal("Test", content.Entries[1]); + } + + [Fact] + public void Clear_DeletesAllItems() + { + // Arrange + var content = new HtmlContentBuilder(); + content.Append(new TestHtmlContent("hello")); + content.Append("Test"); + + // Act + content.Clear(); + + // Assert + Assert.Equal(0, content.Entries.Count); + } + + [Fact] + public void WriteTo_WritesAllItems() + { + // Arrange + var content = new HtmlContentBuilder(); + var writer = new StringWriter(); + content.Append(new TestHtmlContent("Hello")); + content.Append("Test"); + + // Act + content.WriteTo(writer, new HtmlTestEncoder()); + + // Assert + Assert.Equal(2, content.Entries.Count); + Assert.Equal("Written from TestHtmlContent: HelloHtmlEncode[[Test]]", writer.ToString()); + } + + private class TestHtmlContent : IHtmlContent + { + 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; + } + } + } +} diff --git a/test/Microsoft.AspNet.Html.Test/Microsoft.AspNet.Html.Test.xproj b/test/Microsoft.AspNet.Html.Test/Microsoft.AspNet.Html.Test.xproj new file mode 100644 index 0000000000..4a03567677 --- /dev/null +++ b/test/Microsoft.AspNet.Html.Test/Microsoft.AspNet.Html.Test.xproj @@ -0,0 +1,21 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 2d187b88-94bd-4a39-ac97-f8f8b9363301 + Microsoft.AspNet.Html.Abstractions.Test + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin\$(MSBuildProjectName)\ + + + 2.0 + + + + + + \ No newline at end of file diff --git a/test/Microsoft.AspNet.Html.Test/project.json b/test/Microsoft.AspNet.Html.Test/project.json new file mode 100644 index 0000000000..f5ea4ca7e6 --- /dev/null +++ b/test/Microsoft.AspNet.Html.Test/project.json @@ -0,0 +1,19 @@ +{ + "compilationOptions": { + "warningsAsErrors": true, + "keyFile": "../../tools/Key.snk" + }, + "dependencies": { + "Microsoft.AspNet.Html": "1.0.0-*", + "Microsoft.AspNet.Testing": "1.0.0-*", + "Microsoft.Extensions.WebEncoders": "1.0.0-*", + "xunit.runner.aspnet": "2.0.0-aspnet-*" + }, + "commands": { + "test": "xunit.runner.aspnet" + }, + "frameworks": { + "dnx451": { }, + "dnxcore50": { } + } +} diff --git a/tools/Key.snk b/tools/Key.snk new file mode 100644 index 0000000000000000000000000000000000000000..e10e4889c125d3120cd9e81582243d70f7cbb806 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098=Iw=HCsnz~#iVhm& zj%TU(_THUee?3yHBjk$37ysB?i5#7WD$={H zV4B!OxRPrb|8)HPg~A}8P>^=#y<)56#=E&NzcjOtPK~<4n6GHt=K$ro*T(lhby_@U zEk(hLzk1H)0yXj{A_5>fk-TgNoP|q6(tP2xo8zt8i%212CWM#AeCd?`hS|4~L({h~Moo(~vy&3Z z1uI}`fd^*>o=rwbAGymj6RM^pZm(*Kfhs+Y1#`-2JPWZMK8@;ZWCk2+9bX4YP);~fj-BU*R zQPvWv$89!{Rl9wM+zR>_TSkn^voYxA?2G iKnV#iZ6Ah`K>b=@=IjYJXrxL124zR(38)nxe+&q_$QXwJ literal 0 HcmV?d00001 From 1b0e2e50e1860ab663233c607662bdcb8a0c28f6 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Wed, 2 Dec 2015 09:15:16 -0800 Subject: [PATCH 025/471] Restore previous package name: `Microsoft.AspNet.Html.Abstractions` nit: add a couple of solution items --- HtmlAbstractions.sln | 12 +++++++++--- .../HtmlContentBuilder.cs | 0 .../HtmlContentBuilderExtensions.cs | 0 .../HtmlEncodedString.cs | 0 .../HtmlTextWriter.cs | 0 .../IHtmlContent.cs | 0 .../IHtmlContentBuilder.cs | 0 .../Microsoft.AspNet.Html.Abstractions.xproj} | 0 .../Properties/AssemblyInfo.cs | 10 ++++++++++ .../project.json | 0 src/Microsoft.AspNet.Html/Properties/AssemblyInfo.cs | 10 ---------- .../HtmlContentBuilderExtensionsTest.cs | 0 .../HtmlContentBuilderTest.cs | 0 .../Microsoft.AspNet.Html.Abstractions.Test.xproj} | 0 .../project.json | 2 +- 15 files changed, 20 insertions(+), 14 deletions(-) rename src/{Microsoft.AspNet.Html => Microsoft.AspNet.Html.Abstractions}/HtmlContentBuilder.cs (100%) rename src/{Microsoft.AspNet.Html => Microsoft.AspNet.Html.Abstractions}/HtmlContentBuilderExtensions.cs (100%) rename src/{Microsoft.AspNet.Html => Microsoft.AspNet.Html.Abstractions}/HtmlEncodedString.cs (100%) rename src/{Microsoft.AspNet.Html => Microsoft.AspNet.Html.Abstractions}/HtmlTextWriter.cs (100%) rename src/{Microsoft.AspNet.Html => Microsoft.AspNet.Html.Abstractions}/IHtmlContent.cs (100%) rename src/{Microsoft.AspNet.Html => Microsoft.AspNet.Html.Abstractions}/IHtmlContentBuilder.cs (100%) rename src/{Microsoft.AspNet.Html/Microsoft.AspNet.Html.xproj => Microsoft.AspNet.Html.Abstractions/Microsoft.AspNet.Html.Abstractions.xproj} (100%) create mode 100644 src/Microsoft.AspNet.Html.Abstractions/Properties/AssemblyInfo.cs rename src/{Microsoft.AspNet.Html => Microsoft.AspNet.Html.Abstractions}/project.json (100%) delete mode 100644 src/Microsoft.AspNet.Html/Properties/AssemblyInfo.cs rename test/{Microsoft.AspNet.Html.Test => Microsoft.AspNet.Html.Abstractions.Test}/HtmlContentBuilderExtensionsTest.cs (100%) rename test/{Microsoft.AspNet.Html.Test => Microsoft.AspNet.Html.Abstractions.Test}/HtmlContentBuilderTest.cs (100%) rename test/{Microsoft.AspNet.Html.Test/Microsoft.AspNet.Html.Test.xproj => Microsoft.AspNet.Html.Abstractions.Test/Microsoft.AspNet.Html.Abstractions.Test.xproj} (100%) rename test/{Microsoft.AspNet.Html.Test => Microsoft.AspNet.Html.Abstractions.Test}/project.json (87%) diff --git a/HtmlAbstractions.sln b/HtmlAbstractions.sln index 1d1f5118f3..805c4daa7a 100644 --- a/HtmlAbstractions.sln +++ b/HtmlAbstractions.sln @@ -1,14 +1,20 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.24711.0 +VisualStudioVersion = 14.0.24720.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A5A15F1C-885A-452A-A731-B0173DDBD913}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{F31FF137-390C-49BF-A3BD-7C6ED3597C21}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Html", "src\Microsoft.AspNet.Html.Abstractions\Microsoft.AspNet.Html.xproj", "{68A28E4A-3ADE-4187-9625-4FF185887CB3}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Html.Abstractions", "src\Microsoft.AspNet.Html.Abstractions\Microsoft.AspNet.Html.Abstractions.xproj", "{68A28E4A-3ADE-4187-9625-4FF185887CB3}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Html.Test", "test\Microsoft.AspNet.Html.Abstractions.Test\Microsoft.AspNet.Html.Test.xproj", "{2D187B88-94BD-4A39-AC97-F8F8B9363301}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Html.Abstractions.Test", "test\Microsoft.AspNet.Html.Abstractions.Test\Microsoft.AspNet.Html.Abstractions.Test.xproj", "{2D187B88-94BD-4A39-AC97-F8F8B9363301}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B4962A29-BE69-4A18-9B4F-B803EEE31EAA}" + ProjectSection(SolutionItems) = preProject + global.json = global.json + NuGetPackageVerifier.json = NuGetPackageVerifier.json + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/src/Microsoft.AspNet.Html/HtmlContentBuilder.cs b/src/Microsoft.AspNet.Html.Abstractions/HtmlContentBuilder.cs similarity index 100% rename from src/Microsoft.AspNet.Html/HtmlContentBuilder.cs rename to src/Microsoft.AspNet.Html.Abstractions/HtmlContentBuilder.cs diff --git a/src/Microsoft.AspNet.Html/HtmlContentBuilderExtensions.cs b/src/Microsoft.AspNet.Html.Abstractions/HtmlContentBuilderExtensions.cs similarity index 100% rename from src/Microsoft.AspNet.Html/HtmlContentBuilderExtensions.cs rename to src/Microsoft.AspNet.Html.Abstractions/HtmlContentBuilderExtensions.cs diff --git a/src/Microsoft.AspNet.Html/HtmlEncodedString.cs b/src/Microsoft.AspNet.Html.Abstractions/HtmlEncodedString.cs similarity index 100% rename from src/Microsoft.AspNet.Html/HtmlEncodedString.cs rename to src/Microsoft.AspNet.Html.Abstractions/HtmlEncodedString.cs diff --git a/src/Microsoft.AspNet.Html/HtmlTextWriter.cs b/src/Microsoft.AspNet.Html.Abstractions/HtmlTextWriter.cs similarity index 100% rename from src/Microsoft.AspNet.Html/HtmlTextWriter.cs rename to src/Microsoft.AspNet.Html.Abstractions/HtmlTextWriter.cs diff --git a/src/Microsoft.AspNet.Html/IHtmlContent.cs b/src/Microsoft.AspNet.Html.Abstractions/IHtmlContent.cs similarity index 100% rename from src/Microsoft.AspNet.Html/IHtmlContent.cs rename to src/Microsoft.AspNet.Html.Abstractions/IHtmlContent.cs diff --git a/src/Microsoft.AspNet.Html/IHtmlContentBuilder.cs b/src/Microsoft.AspNet.Html.Abstractions/IHtmlContentBuilder.cs similarity index 100% rename from src/Microsoft.AspNet.Html/IHtmlContentBuilder.cs rename to src/Microsoft.AspNet.Html.Abstractions/IHtmlContentBuilder.cs diff --git a/src/Microsoft.AspNet.Html/Microsoft.AspNet.Html.xproj b/src/Microsoft.AspNet.Html.Abstractions/Microsoft.AspNet.Html.Abstractions.xproj similarity index 100% rename from src/Microsoft.AspNet.Html/Microsoft.AspNet.Html.xproj rename to src/Microsoft.AspNet.Html.Abstractions/Microsoft.AspNet.Html.Abstractions.xproj diff --git a/src/Microsoft.AspNet.Html.Abstractions/Properties/AssemblyInfo.cs b/src/Microsoft.AspNet.Html.Abstractions/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..d310306c25 --- /dev/null +++ b/src/Microsoft.AspNet.Html.Abstractions/Properties/AssemblyInfo.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. + +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; + +[assembly: AssemblyMetadata("Serviceable", "True")] +[assembly: NeutralResourcesLanguage("en-us")] +[assembly: InternalsVisibleTo("Microsoft.AspNet.Html.Abstractions.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] \ No newline at end of file diff --git a/src/Microsoft.AspNet.Html/project.json b/src/Microsoft.AspNet.Html.Abstractions/project.json similarity index 100% rename from src/Microsoft.AspNet.Html/project.json rename to src/Microsoft.AspNet.Html.Abstractions/project.json diff --git a/src/Microsoft.AspNet.Html/Properties/AssemblyInfo.cs b/src/Microsoft.AspNet.Html/Properties/AssemblyInfo.cs deleted file mode 100644 index 1951d644af..0000000000 --- a/src/Microsoft.AspNet.Html/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Reflection; -using System.Resources; -using System.Runtime.CompilerServices; - -[assembly: AssemblyMetadata("Serviceable", "True")] -[assembly: NeutralResourcesLanguage("en-us")] -[assembly: InternalsVisibleTo("Microsoft.AspNet.Html.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] \ No newline at end of file diff --git a/test/Microsoft.AspNet.Html.Test/HtmlContentBuilderExtensionsTest.cs b/test/Microsoft.AspNet.Html.Abstractions.Test/HtmlContentBuilderExtensionsTest.cs similarity index 100% rename from test/Microsoft.AspNet.Html.Test/HtmlContentBuilderExtensionsTest.cs rename to test/Microsoft.AspNet.Html.Abstractions.Test/HtmlContentBuilderExtensionsTest.cs diff --git a/test/Microsoft.AspNet.Html.Test/HtmlContentBuilderTest.cs b/test/Microsoft.AspNet.Html.Abstractions.Test/HtmlContentBuilderTest.cs similarity index 100% rename from test/Microsoft.AspNet.Html.Test/HtmlContentBuilderTest.cs rename to test/Microsoft.AspNet.Html.Abstractions.Test/HtmlContentBuilderTest.cs diff --git a/test/Microsoft.AspNet.Html.Test/Microsoft.AspNet.Html.Test.xproj b/test/Microsoft.AspNet.Html.Abstractions.Test/Microsoft.AspNet.Html.Abstractions.Test.xproj similarity index 100% rename from test/Microsoft.AspNet.Html.Test/Microsoft.AspNet.Html.Test.xproj rename to test/Microsoft.AspNet.Html.Abstractions.Test/Microsoft.AspNet.Html.Abstractions.Test.xproj diff --git a/test/Microsoft.AspNet.Html.Test/project.json b/test/Microsoft.AspNet.Html.Abstractions.Test/project.json similarity index 87% rename from test/Microsoft.AspNet.Html.Test/project.json rename to test/Microsoft.AspNet.Html.Abstractions.Test/project.json index f5ea4ca7e6..b8e9656f15 100644 --- a/test/Microsoft.AspNet.Html.Test/project.json +++ b/test/Microsoft.AspNet.Html.Abstractions.Test/project.json @@ -4,7 +4,7 @@ "keyFile": "../../tools/Key.snk" }, "dependencies": { - "Microsoft.AspNet.Html": "1.0.0-*", + "Microsoft.AspNet.Html.Abstractions": "1.0.0-*", "Microsoft.AspNet.Testing": "1.0.0-*", "Microsoft.Extensions.WebEncoders": "1.0.0-*", "xunit.runner.aspnet": "2.0.0-aspnet-*" From 6b7cd4ac18a37956de8ad3647800b6066283b146 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 8 Dec 2015 14:38:35 -0800 Subject: [PATCH 026/471] Adding System.Runtime to resolve build issue --- test/Microsoft.AspNet.Html.Abstractions.Test/project.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/Microsoft.AspNet.Html.Abstractions.Test/project.json b/test/Microsoft.AspNet.Html.Abstractions.Test/project.json index b8e9656f15..e3035cbf59 100644 --- a/test/Microsoft.AspNet.Html.Abstractions.Test/project.json +++ b/test/Microsoft.AspNet.Html.Abstractions.Test/project.json @@ -14,6 +14,10 @@ }, "frameworks": { "dnx451": { }, - "dnxcore50": { } + "dnxcore50": { + "dependencies": { + "System.Runtime": "4.0.21-*" + } + } } } From 4cd2730a39da3f41682243e9d0404cfec90e010c Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 11 Dec 2015 12:22:52 -0800 Subject: [PATCH 027/471] Updating to release NuGet.config. --- NuGet.config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NuGet.config b/NuGet.config index 5500f6d507..71b9724a09 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,7 @@ - + - + From 736f2bcefbd1c1d9bb437bf19d4b0d72593cfb68 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 14 Dec 2015 16:28:23 -0800 Subject: [PATCH 028/471] Adding Travis and AppVeyor badges --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index add6834eeb..799d29e1dc 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ HtmlAbstractions ========== +AppVeyor: [![AppVeyor](https://ci.appveyor.com/api/projects/status/cu9y78vsdp19e5on/branch/dev?svg=true)](https://ci.appveyor.com/project/aspnetci/htmlabstractions/branch/dev) + +Travis: [![Travis](https://travis-ci.org/aspnet/HtmlAbstractions.svg?branch=dev)](https://travis-ci.org/aspnet/HtmlAbstractions) HTML abstractions such as `IHtmlContent` and related APIs. From 234073cf6e4901d68f1b23e7d1127cacff7455e3 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Tue, 15 Dec 2015 15:27:40 -0800 Subject: [PATCH 029/471] Make `HtmlEncodedString` a suitable base for MVC's `HtmlString` - #5 - provide `ToString()` implementation - add missing `null` checks in `WriteTo()`; remove extraneous one in the constructor - special-case `HtmlEncodedString` in `IHtmlContentBuilder.AppendFormat()` extension method nits: - ignore more files - add missing `null` checks in `HtmlContentBuilderExtensions` too --- .gitignore | 12 ++++- .../HtmlContentBuilderExtensions.cs | 45 ++++++++++++++++++- .../HtmlEncodedString.cs | 24 +++++----- .../HtmlContentBuilderExtensionsTest.cs | 13 ++++++ 4 files changed, 81 insertions(+), 13 deletions(-) diff --git a/.gitignore b/.gitignore index ac82da7568..329a307cda 100644 --- a/.gitignore +++ b/.gitignore @@ -2,10 +2,17 @@ [Bb]in/ TestResults/ .nuget/ +*.sln.ide/ _ReSharper.*/ packages/ artifacts/ PublishProfiles/ +.vs/ +bower_components/ +node_modules/ +**/wwwroot/lib/ +debugSettings.json +project.lock.json *.user *.suo *.cache @@ -23,5 +30,8 @@ nuget.exe *.ncrunchsolution *.*sdf *.ipch +.settings *.sln.ide -project.lock.json +node_modules +**/[Cc]ompiler/[Rr]esources/**/*.js +*launchSettings.json diff --git a/src/Microsoft.AspNet.Html.Abstractions/HtmlContentBuilderExtensions.cs b/src/Microsoft.AspNet.Html.Abstractions/HtmlContentBuilderExtensions.cs index eabfafbd12..5d0b82dd5e 100644 --- a/src/Microsoft.AspNet.Html.Abstractions/HtmlContentBuilderExtensions.cs +++ b/src/Microsoft.AspNet.Html.Abstractions/HtmlContentBuilderExtensions.cs @@ -99,6 +99,11 @@ namespace Microsoft.AspNet.Html /// The . public static IHtmlContentBuilder AppendLine(this IHtmlContentBuilder builder) { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + builder.Append(HtmlEncodedString.NewLine); return builder; } @@ -112,6 +117,11 @@ namespace Microsoft.AspNet.Html /// The . public static IHtmlContentBuilder AppendLine(this IHtmlContentBuilder builder, string unencoded) { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + builder.Append(unencoded); builder.Append(HtmlEncodedString.NewLine); return builder; @@ -125,6 +135,11 @@ namespace Microsoft.AspNet.Html /// The . public static IHtmlContentBuilder AppendLine(this IHtmlContentBuilder builder, IHtmlContent content) { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + builder.Append(content); builder.Append(HtmlEncodedString.NewLine); return builder; @@ -139,6 +154,11 @@ namespace Microsoft.AspNet.Html /// The . public static IHtmlContentBuilder AppendHtmlLine(this IHtmlContentBuilder builder, string encoded) { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + builder.AppendHtml(encoded); builder.Append(HtmlEncodedString.NewLine); return builder; @@ -153,6 +173,11 @@ namespace Microsoft.AspNet.Html /// 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; @@ -166,6 +191,11 @@ namespace Microsoft.AspNet.Html /// The . public static IHtmlContentBuilder SetContent(this IHtmlContentBuilder builder, IHtmlContent content) { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + builder.Clear(); builder.Append(content); return builder; @@ -180,6 +210,11 @@ namespace Microsoft.AspNet.Html /// 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; @@ -256,8 +291,14 @@ namespace Microsoft.AspNet.Html public string Format(string format, object arg, IFormatProvider formatProvider) { - // This is the case we need to special case. We trust the IHtmlContent instance to do the - // right thing with encoding. + // These are the cases we need to special case. We trust the HtmlEncodedString or IHtmlContent instance + // to do the right thing with encoding. + var htmlString = arg as HtmlEncodedString; + if (htmlString != null) + { + return htmlString.ToString(); + } + var htmlContent = arg as IHtmlContent; if (htmlContent != null) { diff --git a/src/Microsoft.AspNet.Html.Abstractions/HtmlEncodedString.cs b/src/Microsoft.AspNet.Html.Abstractions/HtmlEncodedString.cs index 348588800f..e5c4ab5003 100644 --- a/src/Microsoft.AspNet.Html.Abstractions/HtmlEncodedString.cs +++ b/src/Microsoft.AspNet.Html.Abstractions/HtmlEncodedString.cs @@ -2,16 +2,14 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Diagnostics; using System.IO; using System.Text.Encodings.Web; namespace Microsoft.AspNet.Html { /// - /// An impelementation that wraps an HTML encoded . + /// An implementation that wraps an HTML encoded . /// - [DebuggerDisplay("{DebuggerToString()}")] public class HtmlEncodedString : IHtmlContent { /// @@ -27,23 +25,29 @@ namespace Microsoft.AspNet.Html /// The HTML encoded value. public HtmlEncodedString(string value) { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - _value = value; } /// 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); } - private string DebuggerToString() + /// + public override string ToString() { - return _value; + return _value ?? string.Empty; } } } diff --git a/test/Microsoft.AspNet.Html.Abstractions.Test/HtmlContentBuilderExtensionsTest.cs b/test/Microsoft.AspNet.Html.Abstractions.Test/HtmlContentBuilderExtensionsTest.cs index 6253bf9be3..9355d507d3 100644 --- a/test/Microsoft.AspNet.Html.Abstractions.Test/HtmlContentBuilderExtensionsTest.cs +++ b/test/Microsoft.AspNet.Html.Abstractions.Test/HtmlContentBuilderExtensionsTest.cs @@ -158,6 +158,19 @@ namespace Microsoft.AspNet.Html.Test HtmlContentToString(builder)); } + [Fact] + public void Builder_AppendFormat_HtmlEncodedString() + { + // Arrange + var builder = new TestHtmlContentBuilder(); + + // Act + builder.AppendFormat("{0}!", new HtmlEncodedString("First")); + + // Assert + Assert.Equal("First!", HtmlContentToString(builder)); + } + [Fact] public void Builder_AppendFormatContent_With1Argument() { From b4239550f3151bcf12211799fdbcbc3dbfec9d1a Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 22 Dec 2015 15:57:35 -0800 Subject: [PATCH 030/471] Move Microsoft.Extensions.WebEncoders to HtmlAbstractions --- HtmlAbstractions.sln | 32 +++++- NuGetPackageVerifier.json | 3 +- .../EncoderServiceCollectionExtensions.cs | 64 +++++++++++ .../EncoderServiceProviderExtensions.cs | 50 +++++++++ .../Microsoft.Extensions.WebEncoders.xproj | 17 +++ .../Properties/AssemblyInfo.cs | 8 ++ .../Testing/HtmlTestEncoder.cs | 104 ++++++++++++++++++ .../Testing/JavaScriptTestEncoder.cs | 104 ++++++++++++++++++ .../Testing/UrlTestEncoder.cs | 104 ++++++++++++++++++ .../WebEncoderOptions.cs | 21 ++++ .../project.json | 27 +++++ ...EncoderServiceCollectionExtensionsTests.cs | 90 +++++++++++++++ .../EncoderServiceProviderExtensionsTests.cs | 103 +++++++++++++++++ .../HtmlTestEncoderTest.cs | 26 +++++ ...crosoft.Extensions.WebEncoders.Tests.xproj | 20 ++++ .../project.json | 24 ++++ 16 files changed, 795 insertions(+), 2 deletions(-) create mode 100644 src/Microsoft.Extensions.WebEncoders/EncoderServiceCollectionExtensions.cs create mode 100644 src/Microsoft.Extensions.WebEncoders/EncoderServiceProviderExtensions.cs create mode 100644 src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.xproj create mode 100644 src/Microsoft.Extensions.WebEncoders/Properties/AssemblyInfo.cs create mode 100644 src/Microsoft.Extensions.WebEncoders/Testing/HtmlTestEncoder.cs create mode 100644 src/Microsoft.Extensions.WebEncoders/Testing/JavaScriptTestEncoder.cs create mode 100644 src/Microsoft.Extensions.WebEncoders/Testing/UrlTestEncoder.cs create mode 100644 src/Microsoft.Extensions.WebEncoders/WebEncoderOptions.cs create mode 100644 src/Microsoft.Extensions.WebEncoders/project.json create mode 100644 test/Microsoft.Extensions.WebEncoders.Tests/EncoderServiceCollectionExtensionsTests.cs create mode 100644 test/Microsoft.Extensions.WebEncoders.Tests/EncoderServiceProviderExtensionsTests.cs create mode 100644 test/Microsoft.Extensions.WebEncoders.Tests/HtmlTestEncoderTest.cs create mode 100644 test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.xproj create mode 100644 test/Microsoft.Extensions.WebEncoders.Tests/project.json diff --git a/HtmlAbstractions.sln b/HtmlAbstractions.sln index 805c4daa7a..a45f34a265 100644 --- a/HtmlAbstractions.sln +++ b/HtmlAbstractions.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.24720.0 +VisualStudioVersion = 14.0.24711.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A5A15F1C-885A-452A-A731-B0173DDBD913}" EndProject @@ -16,6 +16,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution NuGetPackageVerifier.json = NuGetPackageVerifier.json EndProjectSection EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Extensions.WebEncoders", "src\Microsoft.Extensions.WebEncoders\Microsoft.Extensions.WebEncoders.xproj", "{DD2CE416-765E-4000-A03E-C2FF165DA1B6}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Extensions.WebEncoders.Tests", "test\Microsoft.Extensions.WebEncoders.Tests\Microsoft.Extensions.WebEncoders.Tests.xproj", "{7AE2731D-43CD-4CF8-850A-4914DE2CE930}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -50,6 +54,30 @@ Global {2D187B88-94BD-4A39-AC97-F8F8B9363301}.Release|Mixed Platforms.Build.0 = Release|Any CPU {2D187B88-94BD-4A39-AC97-F8F8B9363301}.Release|x86.ActiveCfg = Release|Any CPU {2D187B88-94BD-4A39-AC97-F8F8B9363301}.Release|x86.Build.0 = Release|Any CPU + {DD2CE416-765E-4000-A03E-C2FF165DA1B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DD2CE416-765E-4000-A03E-C2FF165DA1B6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DD2CE416-765E-4000-A03E-C2FF165DA1B6}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {DD2CE416-765E-4000-A03E-C2FF165DA1B6}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {DD2CE416-765E-4000-A03E-C2FF165DA1B6}.Debug|x86.ActiveCfg = Debug|Any CPU + {DD2CE416-765E-4000-A03E-C2FF165DA1B6}.Debug|x86.Build.0 = Debug|Any CPU + {DD2CE416-765E-4000-A03E-C2FF165DA1B6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DD2CE416-765E-4000-A03E-C2FF165DA1B6}.Release|Any CPU.Build.0 = Release|Any CPU + {DD2CE416-765E-4000-A03E-C2FF165DA1B6}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {DD2CE416-765E-4000-A03E-C2FF165DA1B6}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {DD2CE416-765E-4000-A03E-C2FF165DA1B6}.Release|x86.ActiveCfg = Release|Any CPU + {DD2CE416-765E-4000-A03E-C2FF165DA1B6}.Release|x86.Build.0 = Release|Any CPU + {7AE2731D-43CD-4CF8-850A-4914DE2CE930}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7AE2731D-43CD-4CF8-850A-4914DE2CE930}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7AE2731D-43CD-4CF8-850A-4914DE2CE930}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {7AE2731D-43CD-4CF8-850A-4914DE2CE930}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {7AE2731D-43CD-4CF8-850A-4914DE2CE930}.Debug|x86.ActiveCfg = Debug|Any CPU + {7AE2731D-43CD-4CF8-850A-4914DE2CE930}.Debug|x86.Build.0 = Debug|Any CPU + {7AE2731D-43CD-4CF8-850A-4914DE2CE930}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7AE2731D-43CD-4CF8-850A-4914DE2CE930}.Release|Any CPU.Build.0 = Release|Any CPU + {7AE2731D-43CD-4CF8-850A-4914DE2CE930}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {7AE2731D-43CD-4CF8-850A-4914DE2CE930}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {7AE2731D-43CD-4CF8-850A-4914DE2CE930}.Release|x86.ActiveCfg = Release|Any CPU + {7AE2731D-43CD-4CF8-850A-4914DE2CE930}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -57,5 +85,7 @@ Global GlobalSection(NestedProjects) = preSolution {68A28E4A-3ADE-4187-9625-4FF185887CB3} = {A5A15F1C-885A-452A-A731-B0173DDBD913} {2D187B88-94BD-4A39-AC97-F8F8B9363301} = {F31FF137-390C-49BF-A3BD-7C6ED3597C21} + {DD2CE416-765E-4000-A03E-C2FF165DA1B6} = {A5A15F1C-885A-452A-A731-B0173DDBD913} + {7AE2731D-43CD-4CF8-850A-4914DE2CE930} = {F31FF137-390C-49BF-A3BD-7C6ED3597C21} EndGlobalSection EndGlobal diff --git a/NuGetPackageVerifier.json b/NuGetPackageVerifier.json index c57b2afb17..31f9437602 100644 --- a/NuGetPackageVerifier.json +++ b/NuGetPackageVerifier.json @@ -9,7 +9,8 @@ "StrictSemanticVersionValidationRule" ], "packages": { - "Microsoft.AspNet.Html.Abstractions": { } + "Microsoft.AspNet.Html.Abstractions": { }, + "Microsoft.Extensions.WebEncoders": { } } }, "Default": { // Rules to run for packages not listed in any other set. diff --git a/src/Microsoft.Extensions.WebEncoders/EncoderServiceCollectionExtensions.cs b/src/Microsoft.Extensions.WebEncoders/EncoderServiceCollectionExtensions.cs new file mode 100644 index 0000000000..80f1987c17 --- /dev/null +++ b/src/Microsoft.Extensions.WebEncoders/EncoderServiceCollectionExtensions.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.Text.Encodings.Web; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Options; +using Microsoft.Extensions.WebEncoders; + +namespace Microsoft.Extensions.DependencyInjection +{ + public static class EncoderServiceCollectionExtensions + { + public static IServiceCollection AddWebEncoders(this IServiceCollection services) + { + if (services == null) + { + throw new ArgumentNullException(nameof(services)); + } + + return AddWebEncoders(services, configureOptions: null); + } + + public static IServiceCollection AddWebEncoders(this IServiceCollection services, Action configureOptions) + { + if (services == null) + { + throw new ArgumentNullException(nameof(services)); + } + + services.AddOptions(); + + // Register the default encoders + // We want to call the 'Default' property getters lazily since they perform static caching + services.TryAddSingleton( + CreateFactory(() => HtmlEncoder.Default, settings => HtmlEncoder.Create(settings))); + services.TryAddSingleton( + CreateFactory(() => JavaScriptEncoder.Default, settings => JavaScriptEncoder.Create(settings))); + services.TryAddSingleton( + CreateFactory(() => UrlEncoder.Default, settings => UrlEncoder.Create(settings))); + + if (configureOptions != null) + { + services.Configure(configureOptions); + } + + return services; + } + + private static Func CreateFactory( + Func defaultFactory, + Func customSettingsFactory) + { + return serviceProvider => + { + var settings = serviceProvider + ?.GetService>() + ?.Value + ?.TextEncoderSettings; + return (settings != null) ? customSettingsFactory(settings) : defaultFactory(); + }; + } + } +} diff --git a/src/Microsoft.Extensions.WebEncoders/EncoderServiceProviderExtensions.cs b/src/Microsoft.Extensions.WebEncoders/EncoderServiceProviderExtensions.cs new file mode 100644 index 0000000000..8d9d2da4e8 --- /dev/null +++ b/src/Microsoft.Extensions.WebEncoders/EncoderServiceProviderExtensions.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 System.Text.Encodings.Web; + +namespace Microsoft.Extensions.WebEncoders +{ + /// + /// Contains extension methods for fetching encoders from an . + /// + public static class EncoderServiceProviderExtensions + { + /// + /// Retrieves an from an . + /// + /// + /// This method is guaranteed never to return null. + /// It will return a default encoder instance if does not contain one or is null. + /// + public static HtmlEncoder GetHtmlEncoder(this IServiceProvider serviceProvider) + { + return (HtmlEncoder)serviceProvider?.GetService(typeof(HtmlEncoder)) ?? HtmlEncoder.Default; + } + + /// + /// Retrieves an from an . + /// + /// + /// This method is guaranteed never to return null. + /// It will return a default encoder instance if does not contain one or is null. + /// + public static JavaScriptEncoder GetJavaScriptEncoder(this IServiceProvider serviceProvider) + { + return (JavaScriptEncoder)serviceProvider?.GetService(typeof(JavaScriptEncoder)) ?? JavaScriptEncoder.Default; + } + + /// + /// Retrieves an from an . + /// + /// + /// This method is guaranteed never to return null. + /// It will return a default encoder instance if does not contain one or is null. + /// + public static UrlEncoder GetUrlEncoder(this IServiceProvider serviceProvider) + { + return (UrlEncoder)serviceProvider?.GetService(typeof(UrlEncoder)) ?? UrlEncoder.Default; + } + } +} diff --git a/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.xproj b/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.xproj new file mode 100644 index 0000000000..084e7901ea --- /dev/null +++ b/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.xproj @@ -0,0 +1,17 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + dd2ce416-765e-4000-a03e-c2ff165da1b6 + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin\$(MSBuildProjectName)\ + + + 2.0 + + + \ No newline at end of file diff --git a/src/Microsoft.Extensions.WebEncoders/Properties/AssemblyInfo.cs b/src/Microsoft.Extensions.WebEncoders/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..b2437d9ad6 --- /dev/null +++ b/src/Microsoft.Extensions.WebEncoders/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; + +[assembly: AssemblyMetadata("Serviceable", "True")] +[assembly: NeutralResourcesLanguage("en-us")] \ No newline at end of file diff --git a/src/Microsoft.Extensions.WebEncoders/Testing/HtmlTestEncoder.cs b/src/Microsoft.Extensions.WebEncoders/Testing/HtmlTestEncoder.cs new file mode 100644 index 0000000000..162ce4f6c1 --- /dev/null +++ b/src/Microsoft.Extensions.WebEncoders/Testing/HtmlTestEncoder.cs @@ -0,0 +1,104 @@ +// Copyright (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.Extensions.WebEncoders.Testing +{ + /// + /// Encoder used for unit testing. + /// + public sealed class HtmlTestEncoder : HtmlEncoder + { + public override int MaxOutputCharactersPerInputCharacter + { + get { return 1; } + } + + public override string Encode(string value) + { + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + if (value.Length == 0) + { + return string.Empty; + } + + return $"HtmlEncode[[{value}]]"; + } + + public override void Encode(TextWriter output, char[] value, int startIndex, int characterCount) + { + if (output == null) + { + throw new ArgumentNullException(nameof(output)); + } + + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + if (characterCount == 0) + { + return; + } + + output.Write("HtmlEncode[["); + output.Write(value, startIndex, characterCount); + output.Write("]]"); + } + + public override void Encode(TextWriter output, string value, int startIndex, int characterCount) + { + if (output == null) + { + throw new ArgumentNullException(nameof(output)); + } + + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + if (characterCount == 0) + { + return; + } + + output.Write("HtmlEncode[["); + output.Write(value.Substring(startIndex, characterCount)); + output.Write("]]"); + } + + public override bool WillEncode(int unicodeScalar) + { + return false; + } + + public override unsafe int FindFirstCharacterToEncode(char* text, int textLength) + { + return -1; + } + + public override unsafe bool TryEncodeUnicodeScalar( + int unicodeScalar, + char* buffer, + int bufferLength, + out int numberOfCharactersWritten) + { + if (buffer == null) + { + throw new ArgumentNullException(nameof(buffer)); + } + + numberOfCharactersWritten = 0; + return false; + } + } +} \ No newline at end of file diff --git a/src/Microsoft.Extensions.WebEncoders/Testing/JavaScriptTestEncoder.cs b/src/Microsoft.Extensions.WebEncoders/Testing/JavaScriptTestEncoder.cs new file mode 100644 index 0000000000..bef4461676 --- /dev/null +++ b/src/Microsoft.Extensions.WebEncoders/Testing/JavaScriptTestEncoder.cs @@ -0,0 +1,104 @@ +// Copyright (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.Extensions.WebEncoders.Testing +{ + /// + /// Encoder used for unit testing. + /// + public class JavaScriptTestEncoder : JavaScriptEncoder + { + public override int MaxOutputCharactersPerInputCharacter + { + get { return 1; } + } + + public override string Encode(string value) + { + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + if (value.Length == 0) + { + return string.Empty; + } + + return $"JavaScriptEncode[[{value}]]"; + } + + public override void Encode(TextWriter output, char[] value, int startIndex, int characterCount) + { + if (output == null) + { + throw new ArgumentNullException(nameof(output)); + } + + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + if (characterCount == 0) + { + return; + } + + output.Write("JavaScriptEncode[["); + output.Write(value, startIndex, characterCount); + output.Write("]]"); + } + + public override void Encode(TextWriter output, string value, int startIndex, int characterCount) + { + if (output == null) + { + throw new ArgumentNullException(nameof(output)); + } + + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + if (characterCount == 0) + { + return; + } + + output.Write("JavaScriptEncode[["); + output.Write(value.Substring(startIndex, characterCount)); + output.Write("]]"); + } + + public override bool WillEncode(int unicodeScalar) + { + return false; + } + + public override unsafe int FindFirstCharacterToEncode(char* text, int textLength) + { + return -1; + } + + public override unsafe bool TryEncodeUnicodeScalar( + int unicodeScalar, + char* buffer, + int bufferLength, + out int numberOfCharactersWritten) + { + if (buffer == null) + { + throw new ArgumentNullException(nameof(buffer)); + } + + numberOfCharactersWritten = 0; + return false; + } + } +} \ No newline at end of file diff --git a/src/Microsoft.Extensions.WebEncoders/Testing/UrlTestEncoder.cs b/src/Microsoft.Extensions.WebEncoders/Testing/UrlTestEncoder.cs new file mode 100644 index 0000000000..295bda63e8 --- /dev/null +++ b/src/Microsoft.Extensions.WebEncoders/Testing/UrlTestEncoder.cs @@ -0,0 +1,104 @@ +// Copyright (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.Extensions.WebEncoders.Testing +{ + /// + /// Encoder used for unit testing. + /// + public class UrlTestEncoder : UrlEncoder + { + public override int MaxOutputCharactersPerInputCharacter + { + get { return 1; } + } + + public override string Encode(string value) + { + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + if (value.Length == 0) + { + return string.Empty; + } + + return $"UrlEncode[[{value}]]"; + } + + public override void Encode(TextWriter output, char[] value, int startIndex, int characterCount) + { + if (output == null) + { + throw new ArgumentNullException(nameof(output)); + } + + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + if (characterCount == 0) + { + return; + } + + output.Write("UrlEncode[["); + output.Write(value, startIndex, characterCount); + output.Write("]]"); + } + + public override void Encode(TextWriter output, string value, int startIndex, int characterCount) + { + if (output == null) + { + throw new ArgumentNullException(nameof(output)); + } + + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + if (characterCount == 0) + { + return; + } + + output.Write("UrlEncode[["); + output.Write(value.Substring(startIndex, characterCount)); + output.Write("]]"); + } + + public override bool WillEncode(int unicodeScalar) + { + return false; + } + + public override unsafe int FindFirstCharacterToEncode(char* text, int textLength) + { + return -1; + } + + public override unsafe bool TryEncodeUnicodeScalar( + int unicodeScalar, + char* buffer, + int bufferLength, + out int numberOfCharactersWritten) + { + if (buffer == null) + { + throw new ArgumentNullException(nameof(buffer)); + } + + numberOfCharactersWritten = 0; + return false; + } + } +} \ No newline at end of file diff --git a/src/Microsoft.Extensions.WebEncoders/WebEncoderOptions.cs b/src/Microsoft.Extensions.WebEncoders/WebEncoderOptions.cs new file mode 100644 index 0000000000..2f5e770a0c --- /dev/null +++ b/src/Microsoft.Extensions.WebEncoders/WebEncoderOptions.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.Text.Encodings.Web; + +namespace Microsoft.Extensions.WebEncoders +{ + /// + /// Specifies options common to all three encoders (HtmlEncode, JavaScriptEncode, UrlEncode). + /// + public sealed class WebEncoderOptions + { + /// + /// Specifies which code points are allowed to be represented unescaped by the encoders. + /// + /// + /// If this property is null, then the encoders will use their default allow lists. + /// + public TextEncoderSettings TextEncoderSettings { get; set; } + } +} diff --git a/src/Microsoft.Extensions.WebEncoders/project.json b/src/Microsoft.Extensions.WebEncoders/project.json new file mode 100644 index 0000000000..0facfeeb8c --- /dev/null +++ b/src/Microsoft.Extensions.WebEncoders/project.json @@ -0,0 +1,27 @@ +{ + "version": "1.0.0-*", + "description": "Contains registration and configuration APIs for the core framework encoders.", + "repository": { + "type": "git", + "url": "git://github.com/aspnet/httpabstractions" + }, + "compilationOptions": { + "warningsAsErrors": true, + "allowUnsafe": true, + "keyFile": "../../tools/Key.snk" + }, + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "1.0.0-*", + "Microsoft.Extensions.Options": "1.0.0-*", + "System.Text.Encodings.Web": "4.0.0-*" + }, + "frameworks": { + "net451": { + "frameworkAssemblies": { + "System.IO": "", + "System.Runtime": "" + } + }, + "dotnet5.4": {} + } +} diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/EncoderServiceCollectionExtensionsTests.cs b/test/Microsoft.Extensions.WebEncoders.Tests/EncoderServiceCollectionExtensionsTests.cs new file mode 100644 index 0000000000..8e060102bb --- /dev/null +++ b/test/Microsoft.Extensions.WebEncoders.Tests/EncoderServiceCollectionExtensionsTests.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.Text.Encodings.Web; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.WebEncoders.Testing; +using Xunit; + +namespace Microsoft.Extensions.WebEncoders +{ + public class EncoderServiceCollectionExtensionsTests + { + [Fact] + public void AddWebEncoders_WithoutOptions_RegistersDefaultEncoders() + { + // Arrange + var serviceCollection = new ServiceCollection(); + + // Act + serviceCollection.AddWebEncoders(); + + // Assert + var serviceProvider = serviceCollection.BuildServiceProvider(); + Assert.Same(HtmlEncoder.Default, serviceProvider.GetRequiredService()); // default encoder + Assert.Same(HtmlEncoder.Default, serviceProvider.GetRequiredService()); // as singleton instance + Assert.Same(JavaScriptEncoder.Default, serviceProvider.GetRequiredService()); // default encoder + Assert.Same(JavaScriptEncoder.Default, serviceProvider.GetRequiredService()); // as singleton instance + Assert.Same(UrlEncoder.Default, serviceProvider.GetRequiredService()); // default encoder + Assert.Same(UrlEncoder.Default, serviceProvider.GetRequiredService()); // as singleton instance + } + + [Fact] + public void AddWebEncoders_WithOptions_RegistersEncodersWithCustomCodeFilter() + { + // Arrange + var serviceCollection = new ServiceCollection(); + + // Act + serviceCollection.AddWebEncoders(options => + { + options.TextEncoderSettings = new TextEncoderSettings(); + options.TextEncoderSettings.AllowCharacters("ace".ToCharArray()); // only these three chars are allowed + }); + + // Assert + var serviceProvider = serviceCollection.BuildServiceProvider(); + + var htmlEncoder = serviceProvider.GetRequiredService(); + Assert.Equal("abcde", htmlEncoder.Encode("abcde")); + Assert.Same(htmlEncoder, serviceProvider.GetRequiredService()); // as singleton instance + + var javaScriptEncoder = serviceProvider.GetRequiredService(); + Assert.Equal(@"a\u0062c\u0064e", javaScriptEncoder.Encode("abcde")); + Assert.Same(javaScriptEncoder, serviceProvider.GetRequiredService()); // as singleton instance + + var urlEncoder = serviceProvider.GetRequiredService(); + Assert.Equal("a%62c%64e", urlEncoder.Encode("abcde")); + Assert.Same(urlEncoder, serviceProvider.GetRequiredService()); // as singleton instance + } + + [Fact] + public void AddWebEncoders_DoesNotOverrideExistingRegisteredEncoders() + { + // Arrange + var serviceCollection = new ServiceCollection(); + + // Act + serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); + // we don't register an existing URL encoder + serviceCollection.AddWebEncoders(options => + { + options.TextEncoderSettings = new TextEncoderSettings(); + options.TextEncoderSettings.AllowCharacters("ace".ToCharArray()); // only these three chars are allowed + }); + + // Assert + var serviceProvider = serviceCollection.BuildServiceProvider(); + + var htmlEncoder = serviceProvider.GetHtmlEncoder(); + Assert.Equal("HtmlEncode[[abcde]]", htmlEncoder.Encode("abcde")); + + var javaScriptEncoder = serviceProvider.GetJavaScriptEncoder(); + Assert.Equal("JavaScriptEncode[[abcde]]", javaScriptEncoder.Encode("abcde")); + + var urlEncoder = serviceProvider.GetUrlEncoder(); + Assert.Equal("a%62c%64e", urlEncoder.Encode("abcde")); + } + } +} diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/EncoderServiceProviderExtensionsTests.cs b/test/Microsoft.Extensions.WebEncoders.Tests/EncoderServiceProviderExtensionsTests.cs new file mode 100644 index 0000000000..01492e759e --- /dev/null +++ b/test/Microsoft.Extensions.WebEncoders.Tests/EncoderServiceProviderExtensionsTests.cs @@ -0,0 +1,103 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Text.Encodings.Web; +using Xunit; + +namespace Microsoft.Extensions.WebEncoders +{ + public class EncoderServiceProviderExtensionsTests + { + [Fact] + public void GetHtmlEncoder_ServiceProviderDoesNotHaveEncoder_UsesDefault() + { + // Arrange + var serviceProvider = new TestServiceProvider(); + + // Act + var retVal = serviceProvider.GetHtmlEncoder(); + + // Assert + Assert.Same(HtmlEncoder.Default, retVal); + } + + [Fact] + public void GetHtmlEncoder_ServiceProviderHasEncoder_ReturnsRegisteredInstance() + { + // Arrange + var expectedEncoder = HtmlEncoder.Default; + var serviceProvider = new TestServiceProvider() { Service = expectedEncoder }; + + // Act + var retVal = serviceProvider.GetHtmlEncoder(); + + // Assert + Assert.Same(expectedEncoder, retVal); + } + + [Fact] + public void GetJavaScriptEncoder_ServiceProviderDoesNotHaveEncoder_UsesDefault() + { + // Arrange + var serviceProvider = new TestServiceProvider(); + + // Act + var retVal = serviceProvider.GetJavaScriptEncoder(); + + // Assert + Assert.Same(JavaScriptEncoder.Default, retVal); + } + + [Fact] + public void GetJavaScriptEncoder_ServiceProviderHasEncoder_ReturnsRegisteredInstance() + { + // Arrange + var expectedEncoder = JavaScriptEncoder.Default; + var serviceProvider = new TestServiceProvider() { Service = expectedEncoder }; + + // Act + var retVal = serviceProvider.GetJavaScriptEncoder(); + + // Assert + Assert.Same(expectedEncoder, retVal); + } + + [Fact] + public void GetUrlEncoder_ServiceProviderDoesNotHaveEncoder_UsesDefault() + { + // Arrange + var serviceProvider = new TestServiceProvider(); + + // Act + var retVal = serviceProvider.GetUrlEncoder(); + + // Assert + Assert.Same(UrlEncoder.Default, retVal); + } + + [Fact] + public void GetUrlEncoder_ServiceProviderHasEncoder_ReturnsRegisteredInstance() + { + // Arrange + var expectedEncoder = UrlEncoder.Default; + var serviceProvider = new TestServiceProvider() { Service = expectedEncoder }; + + // Act + var retVal = serviceProvider.GetUrlEncoder(); + + // Assert + Assert.Same(expectedEncoder, retVal); + } + + private class TestServiceProvider : IServiceProvider + { + public object Service { get; set; } + + public object GetService(Type serviceType) + { + return Service; + } + } + } +} diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/HtmlTestEncoderTest.cs b/test/Microsoft.Extensions.WebEncoders.Tests/HtmlTestEncoderTest.cs new file mode 100644 index 0000000000..baafedc4de --- /dev/null +++ b/test/Microsoft.Extensions.WebEncoders.Tests/HtmlTestEncoderTest.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 Xunit; + +namespace Microsoft.Extensions.WebEncoders.Testing +{ + public class HtmlTestEncoderTest + { + [Theory] + [InlineData("", "")] + [InlineData("abcd", "HtmlEncode[[abcd]]")] + [InlineData("<<''\"\">>", "HtmlEncode[[<<''\"\">>]]")] + public void StringEncode_EncodesAsExpected(string input, string expectedOutput) + { + // Arrange + var encoder = new HtmlTestEncoder(); + + // Act + var output = encoder.Encode(input); + + // Assert + Assert.Equal(expectedOutput, output); + } + } +} diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.xproj b/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.xproj new file mode 100644 index 0000000000..9b0698e3cc --- /dev/null +++ b/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.xproj @@ -0,0 +1,20 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 7ae2731d-43cd-4cf8-850a-4914de2ce930 + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin\$(MSBuildProjectName)\ + + + 2.0 + + + + + + \ No newline at end of file diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/project.json b/test/Microsoft.Extensions.WebEncoders.Tests/project.json new file mode 100644 index 0000000000..4d81779a7c --- /dev/null +++ b/test/Microsoft.Extensions.WebEncoders.Tests/project.json @@ -0,0 +1,24 @@ +{ + "dependencies": { + "Microsoft.Extensions.DependencyInjection": "1.0.0-*", + "Microsoft.Extensions.WebEncoders": "1.0.0-*", + "Newtonsoft.Json": "6.0.6", + "xunit.runner.aspnet": "2.0.0-aspnet-*" + }, + "commands": { + "test": "xunit.runner.aspnet" + }, + "compilationOptions": { + "allowUnsafe": true, + "warningsAsErrors": true, + "keyFile": "../../tools/Key.snk" + }, + "frameworks": { + "dnx451": { }, + "dnxcore50": { + "dependencies": { + "System.Text.Encoding.Extensions": "4.0.11-*" + } + } + } +} From 46f64dfa208ae29d4e4608343352286f54a6c4a8 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 29 Dec 2015 18:21:07 -0800 Subject: [PATCH 031/471] * Remove EncoderServiceProviderExtensions --- .../EncoderServiceCollectionExtensions.cs | 13 +++ .../EncoderServiceProviderExtensions.cs | 50 --------- ...EncoderServiceCollectionExtensionsTests.cs | 6 +- .../EncoderServiceProviderExtensionsTests.cs | 103 ------------------ .../project.json | 7 +- 5 files changed, 17 insertions(+), 162 deletions(-) delete mode 100644 src/Microsoft.Extensions.WebEncoders/EncoderServiceProviderExtensions.cs delete mode 100644 test/Microsoft.Extensions.WebEncoders.Tests/EncoderServiceProviderExtensionsTests.cs diff --git a/src/Microsoft.Extensions.WebEncoders/EncoderServiceCollectionExtensions.cs b/src/Microsoft.Extensions.WebEncoders/EncoderServiceCollectionExtensions.cs index 80f1987c17..df3946099c 100644 --- a/src/Microsoft.Extensions.WebEncoders/EncoderServiceCollectionExtensions.cs +++ b/src/Microsoft.Extensions.WebEncoders/EncoderServiceCollectionExtensions.cs @@ -11,6 +11,12 @@ namespace Microsoft.Extensions.DependencyInjection { public static class EncoderServiceCollectionExtensions { + /// + /// Adds , and + /// to the specified . + /// + /// The . + /// The instance after the encoders have been added. public static IServiceCollection AddWebEncoders(this IServiceCollection services) { if (services == null) @@ -21,6 +27,13 @@ namespace Microsoft.Extensions.DependencyInjection return AddWebEncoders(services, configureOptions: null); } + /// + /// Adds , and + /// to the specified . + /// + /// The . + /// A callback to configure . + /// The instance after the encoders have been added. public static IServiceCollection AddWebEncoders(this IServiceCollection services, Action configureOptions) { if (services == null) diff --git a/src/Microsoft.Extensions.WebEncoders/EncoderServiceProviderExtensions.cs b/src/Microsoft.Extensions.WebEncoders/EncoderServiceProviderExtensions.cs deleted file mode 100644 index 8d9d2da4e8..0000000000 --- a/src/Microsoft.Extensions.WebEncoders/EncoderServiceProviderExtensions.cs +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Text.Encodings.Web; - -namespace Microsoft.Extensions.WebEncoders -{ - /// - /// Contains extension methods for fetching encoders from an . - /// - public static class EncoderServiceProviderExtensions - { - /// - /// Retrieves an from an . - /// - /// - /// This method is guaranteed never to return null. - /// It will return a default encoder instance if does not contain one or is null. - /// - public static HtmlEncoder GetHtmlEncoder(this IServiceProvider serviceProvider) - { - return (HtmlEncoder)serviceProvider?.GetService(typeof(HtmlEncoder)) ?? HtmlEncoder.Default; - } - - /// - /// Retrieves an from an . - /// - /// - /// This method is guaranteed never to return null. - /// It will return a default encoder instance if does not contain one or is null. - /// - public static JavaScriptEncoder GetJavaScriptEncoder(this IServiceProvider serviceProvider) - { - return (JavaScriptEncoder)serviceProvider?.GetService(typeof(JavaScriptEncoder)) ?? JavaScriptEncoder.Default; - } - - /// - /// Retrieves an from an . - /// - /// - /// This method is guaranteed never to return null. - /// It will return a default encoder instance if does not contain one or is null. - /// - public static UrlEncoder GetUrlEncoder(this IServiceProvider serviceProvider) - { - return (UrlEncoder)serviceProvider?.GetService(typeof(UrlEncoder)) ?? UrlEncoder.Default; - } - } -} diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/EncoderServiceCollectionExtensionsTests.cs b/test/Microsoft.Extensions.WebEncoders.Tests/EncoderServiceCollectionExtensionsTests.cs index 8e060102bb..0178bba2d5 100644 --- a/test/Microsoft.Extensions.WebEncoders.Tests/EncoderServiceCollectionExtensionsTests.cs +++ b/test/Microsoft.Extensions.WebEncoders.Tests/EncoderServiceCollectionExtensionsTests.cs @@ -77,13 +77,13 @@ namespace Microsoft.Extensions.WebEncoders // Assert var serviceProvider = serviceCollection.BuildServiceProvider(); - var htmlEncoder = serviceProvider.GetHtmlEncoder(); + var htmlEncoder = serviceProvider.GetRequiredService(); Assert.Equal("HtmlEncode[[abcde]]", htmlEncoder.Encode("abcde")); - var javaScriptEncoder = serviceProvider.GetJavaScriptEncoder(); + var javaScriptEncoder = serviceProvider.GetRequiredService(); Assert.Equal("JavaScriptEncode[[abcde]]", javaScriptEncoder.Encode("abcde")); - var urlEncoder = serviceProvider.GetUrlEncoder(); + var urlEncoder = serviceProvider.GetRequiredService(); Assert.Equal("a%62c%64e", urlEncoder.Encode("abcde")); } } diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/EncoderServiceProviderExtensionsTests.cs b/test/Microsoft.Extensions.WebEncoders.Tests/EncoderServiceProviderExtensionsTests.cs deleted file mode 100644 index 01492e759e..0000000000 --- a/test/Microsoft.Extensions.WebEncoders.Tests/EncoderServiceProviderExtensionsTests.cs +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Text.Encodings.Web; -using Xunit; - -namespace Microsoft.Extensions.WebEncoders -{ - public class EncoderServiceProviderExtensionsTests - { - [Fact] - public void GetHtmlEncoder_ServiceProviderDoesNotHaveEncoder_UsesDefault() - { - // Arrange - var serviceProvider = new TestServiceProvider(); - - // Act - var retVal = serviceProvider.GetHtmlEncoder(); - - // Assert - Assert.Same(HtmlEncoder.Default, retVal); - } - - [Fact] - public void GetHtmlEncoder_ServiceProviderHasEncoder_ReturnsRegisteredInstance() - { - // Arrange - var expectedEncoder = HtmlEncoder.Default; - var serviceProvider = new TestServiceProvider() { Service = expectedEncoder }; - - // Act - var retVal = serviceProvider.GetHtmlEncoder(); - - // Assert - Assert.Same(expectedEncoder, retVal); - } - - [Fact] - public void GetJavaScriptEncoder_ServiceProviderDoesNotHaveEncoder_UsesDefault() - { - // Arrange - var serviceProvider = new TestServiceProvider(); - - // Act - var retVal = serviceProvider.GetJavaScriptEncoder(); - - // Assert - Assert.Same(JavaScriptEncoder.Default, retVal); - } - - [Fact] - public void GetJavaScriptEncoder_ServiceProviderHasEncoder_ReturnsRegisteredInstance() - { - // Arrange - var expectedEncoder = JavaScriptEncoder.Default; - var serviceProvider = new TestServiceProvider() { Service = expectedEncoder }; - - // Act - var retVal = serviceProvider.GetJavaScriptEncoder(); - - // Assert - Assert.Same(expectedEncoder, retVal); - } - - [Fact] - public void GetUrlEncoder_ServiceProviderDoesNotHaveEncoder_UsesDefault() - { - // Arrange - var serviceProvider = new TestServiceProvider(); - - // Act - var retVal = serviceProvider.GetUrlEncoder(); - - // Assert - Assert.Same(UrlEncoder.Default, retVal); - } - - [Fact] - public void GetUrlEncoder_ServiceProviderHasEncoder_ReturnsRegisteredInstance() - { - // Arrange - var expectedEncoder = UrlEncoder.Default; - var serviceProvider = new TestServiceProvider() { Service = expectedEncoder }; - - // Act - var retVal = serviceProvider.GetUrlEncoder(); - - // Assert - Assert.Same(expectedEncoder, retVal); - } - - private class TestServiceProvider : IServiceProvider - { - public object Service { get; set; } - - public object GetService(Type serviceType) - { - return Service; - } - } - } -} diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/project.json b/test/Microsoft.Extensions.WebEncoders.Tests/project.json index 4d81779a7c..62fb30b458 100644 --- a/test/Microsoft.Extensions.WebEncoders.Tests/project.json +++ b/test/Microsoft.Extensions.WebEncoders.Tests/project.json @@ -2,7 +2,6 @@ "dependencies": { "Microsoft.Extensions.DependencyInjection": "1.0.0-*", "Microsoft.Extensions.WebEncoders": "1.0.0-*", - "Newtonsoft.Json": "6.0.6", "xunit.runner.aspnet": "2.0.0-aspnet-*" }, "commands": { @@ -15,10 +14,6 @@ }, "frameworks": { "dnx451": { }, - "dnxcore50": { - "dependencies": { - "System.Text.Encoding.Extensions": "4.0.11-*" - } - } + "dnxcore50": { } } } From 984fe02eb8a32c3e67592becd024acb527010930 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 31 Dec 2015 10:53:48 -0800 Subject: [PATCH 032/471] Rename IHtmlContentBuilder.Append(IHtmlContent) to IHtmlContentBuilder.AppendHtml(IHtmlContent) Fixes #4 --- .../HtmlContentBuilder.cs | 2 +- .../HtmlContentBuilderExtensions.cs | 16 ++++++++-------- .../IHtmlContentBuilder.cs | 2 +- .../HtmlContentBuilderExtensionsTest.cs | 2 +- .../HtmlContentBuilderTest.cs | 8 ++++---- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/Microsoft.AspNet.Html.Abstractions/HtmlContentBuilder.cs b/src/Microsoft.AspNet.Html.Abstractions/HtmlContentBuilder.cs index 34e59d3318..10a50cb34d 100644 --- a/src/Microsoft.AspNet.Html.Abstractions/HtmlContentBuilder.cs +++ b/src/Microsoft.AspNet.Html.Abstractions/HtmlContentBuilder.cs @@ -67,7 +67,7 @@ namespace Microsoft.AspNet.Html } /// - public IHtmlContentBuilder Append(IHtmlContent htmlContent) + public IHtmlContentBuilder AppendHtml(IHtmlContent htmlContent) { if (htmlContent == null) { diff --git a/src/Microsoft.AspNet.Html.Abstractions/HtmlContentBuilderExtensions.cs b/src/Microsoft.AspNet.Html.Abstractions/HtmlContentBuilderExtensions.cs index 5d0b82dd5e..2ff745cdf3 100644 --- a/src/Microsoft.AspNet.Html.Abstractions/HtmlContentBuilderExtensions.cs +++ b/src/Microsoft.AspNet.Html.Abstractions/HtmlContentBuilderExtensions.cs @@ -48,7 +48,7 @@ namespace Microsoft.AspNet.Html throw new ArgumentNullException(nameof(args)); } - builder.Append(new HtmlFormatString(format, args)); + builder.AppendHtml(new HtmlFormatString(format, args)); return builder; } @@ -88,7 +88,7 @@ namespace Microsoft.AspNet.Html throw new ArgumentNullException(nameof(args)); } - builder.Append(new HtmlFormatString(formatProvider, format, args)); + builder.AppendHtml(new HtmlFormatString(formatProvider, format, args)); return builder; } @@ -104,7 +104,7 @@ namespace Microsoft.AspNet.Html throw new ArgumentNullException(nameof(builder)); } - builder.Append(HtmlEncodedString.NewLine); + builder.AppendHtml(HtmlEncodedString.NewLine); return builder; } @@ -123,7 +123,7 @@ namespace Microsoft.AspNet.Html } builder.Append(unencoded); - builder.Append(HtmlEncodedString.NewLine); + builder.AppendHtml(HtmlEncodedString.NewLine); return builder; } @@ -140,8 +140,8 @@ namespace Microsoft.AspNet.Html throw new ArgumentNullException(nameof(builder)); } - builder.Append(content); - builder.Append(HtmlEncodedString.NewLine); + builder.AppendHtml(content); + builder.AppendHtml(HtmlEncodedString.NewLine); return builder; } @@ -160,7 +160,7 @@ namespace Microsoft.AspNet.Html } builder.AppendHtml(encoded); - builder.Append(HtmlEncodedString.NewLine); + builder.AppendHtml(HtmlEncodedString.NewLine); return builder; } @@ -197,7 +197,7 @@ namespace Microsoft.AspNet.Html } builder.Clear(); - builder.Append(content); + builder.AppendHtml(content); return builder; } diff --git a/src/Microsoft.AspNet.Html.Abstractions/IHtmlContentBuilder.cs b/src/Microsoft.AspNet.Html.Abstractions/IHtmlContentBuilder.cs index de4b9ebd90..6b0a6d6571 100644 --- a/src/Microsoft.AspNet.Html.Abstractions/IHtmlContentBuilder.cs +++ b/src/Microsoft.AspNet.Html.Abstractions/IHtmlContentBuilder.cs @@ -13,7 +13,7 @@ namespace Microsoft.AspNet.Html /// /// The to append. /// The . - IHtmlContentBuilder Append(IHtmlContent content); + IHtmlContentBuilder AppendHtml(IHtmlContent content); /// /// Appends a value. The value is treated as unencoded as-provided, and will be HTML diff --git a/test/Microsoft.AspNet.Html.Abstractions.Test/HtmlContentBuilderExtensionsTest.cs b/test/Microsoft.AspNet.Html.Abstractions.Test/HtmlContentBuilderExtensionsTest.cs index 9355d507d3..ff201b494c 100644 --- a/test/Microsoft.AspNet.Html.Abstractions.Test/HtmlContentBuilderExtensionsTest.cs +++ b/test/Microsoft.AspNet.Html.Abstractions.Test/HtmlContentBuilderExtensionsTest.cs @@ -374,7 +374,7 @@ namespace Microsoft.AspNet.Html.Test return this; } - public IHtmlContentBuilder Append(IHtmlContent content) + public IHtmlContentBuilder AppendHtml(IHtmlContent content) { Entries.Add(content); return this; diff --git a/test/Microsoft.AspNet.Html.Abstractions.Test/HtmlContentBuilderTest.cs b/test/Microsoft.AspNet.Html.Abstractions.Test/HtmlContentBuilderTest.cs index 4eee28e219..c9eda50adc 100644 --- a/test/Microsoft.AspNet.Html.Abstractions.Test/HtmlContentBuilderTest.cs +++ b/test/Microsoft.AspNet.Html.Abstractions.Test/HtmlContentBuilderTest.cs @@ -65,7 +65,7 @@ namespace Microsoft.Extensions.Internal var writer = new StringWriter(); // Act - content.Append(new TestHtmlContent("Hello")); + content.AppendHtml(new TestHtmlContent("Hello")); // Assert var result = Assert.Single(content.Entries); @@ -81,7 +81,7 @@ namespace Microsoft.Extensions.Internal var content = new HtmlContentBuilder(); // Act - content.Append(new TestHtmlContent("hello")); + content.AppendHtml(new TestHtmlContent("hello")); content.Append("Test"); // Assert @@ -95,7 +95,7 @@ namespace Microsoft.Extensions.Internal { // Arrange var content = new HtmlContentBuilder(); - content.Append(new TestHtmlContent("hello")); + content.AppendHtml(new TestHtmlContent("hello")); content.Append("Test"); // Act @@ -111,7 +111,7 @@ namespace Microsoft.Extensions.Internal // Arrange var content = new HtmlContentBuilder(); var writer = new StringWriter(); - content.Append(new TestHtmlContent("Hello")); + content.AppendHtml(new TestHtmlContent("Hello")); content.Append("Test"); // Act From d113f7edc97a23993c1f8324da7bf2577f709100 Mon Sep 17 00:00:00 2001 From: Victor Hurdugaci Date: Wed, 6 Jan 2016 14:49:54 -0800 Subject: [PATCH 033/471] Build with dotnet --- .gitattributes | 1 + .gitignore | 2 + .travis.yml | 8 ++- build.cmd | 68 +++++++++---------- build.sh | 47 +++++++------ .../project.json | 12 +++- .../project.json | 13 +++- 7 files changed, 88 insertions(+), 63 deletions(-) diff --git a/.gitattributes b/.gitattributes index bdaa5ba982..66abdf279e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -48,3 +48,4 @@ *.fsproj text=auto *.dbproj text=auto *.sln text=auto eol=crlf +*.sh eol=lf \ No newline at end of file diff --git a/.gitignore b/.gitignore index 329a307cda..980ee002d9 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,5 @@ nuget.exe node_modules **/[Cc]ompiler/[Rr]esources/**/*.js *launchSettings.json +.build/ +.testPublish/ \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index c0befaffcf..e8f77f0f14 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,9 +10,11 @@ addons: - libssl-dev - libunwind8 - zlib1g -env: - - KOREBUILD_DNU_RESTORE_CORECLR=true KOREBUILD_TEST_DNXCORE=true mono: - 4.0.5 +os: + - linux + - osx +osx_image: xcode7.1 script: - - ./build.sh --quiet verify + - ./build.sh --quiet verify \ No newline at end of file diff --git a/build.cmd b/build.cmd index 553e3929a0..65fb3e3353 100644 --- a/build.cmd +++ b/build.cmd @@ -1,40 +1,40 @@ -@echo off -cd %~dp0 - +@ECHO off SETLOCAL + +SET REPO_FOLDER=%~dp0 +CD "%REPO_FOLDER%" + +SET BUILD_FOLDER=.build +SET KOREBUILD_FOLDER=%BUILD_FOLDER%\KoreBuild-dotnet +SET KOREBUILD_VERSION= + +SET NUGET_PATH=%BUILD_FOLDER%\NuGet.exe SET NUGET_VERSION=latest SET CACHED_NUGET=%LocalAppData%\NuGet\nuget.%NUGET_VERSION%.exe -SET BUILDCMD_KOREBUILD_VERSION= -SET BUILDCMD_DNX_VERSION= -IF EXIST %CACHED_NUGET% goto copynuget -echo Downloading latest version of NuGet.exe... -IF NOT EXIST %LocalAppData%\NuGet md %LocalAppData%\NuGet -@powershell -NoProfile -ExecutionPolicy unrestricted -Command "$ProgressPreference = 'SilentlyContinue'; Invoke-WebRequest 'https://dist.nuget.org/win-x86-commandline/%NUGET_VERSION%/nuget.exe' -OutFile '%CACHED_NUGET%'" - -:copynuget -IF EXIST .nuget\nuget.exe goto restore -md .nuget -copy %CACHED_NUGET% .nuget\nuget.exe > nul - -:restore -IF EXIST packages\Sake goto getdnx -IF "%BUILDCMD_KOREBUILD_VERSION%"=="" ( - .nuget\nuget.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre -) ELSE ( - .nuget\nuget.exe install KoreBuild -version %BUILDCMD_KOREBUILD_VERSION% -ExcludeVersion -o packages -nocache -pre -) -.nuget\NuGet.exe install Sake -ExcludeVersion -Source https://www.nuget.org/api/v2/ -Out packages - -:getdnx -IF "%BUILDCMD_DNX_VERSION%"=="" ( - SET BUILDCMD_DNX_VERSION=latest -) -IF "%SKIP_DNX_INSTALL%"=="" ( - CALL packages\KoreBuild\build\dnvm install %BUILDCMD_DNX_VERSION% -runtime CoreCLR -arch x86 -alias default - CALL packages\KoreBuild\build\dnvm install default -runtime CLR -arch x86 -alias default -) ELSE ( - CALL packages\KoreBuild\build\dnvm use default -runtime CLR -arch x86 +IF NOT EXIST %BUILD_FOLDER% ( + md %BUILD_FOLDER% ) -packages\Sake\tools\Sake.exe -I packages\KoreBuild\build -f makefile.shade %* +IF NOT EXIST %NUGET_PATH% ( + IF NOT EXIST %CACHED_NUGET% ( + echo Downloading latest version of NuGet.exe... + IF NOT EXIST %LocalAppData%\NuGet ( + md %LocalAppData%\NuGet + ) + @powershell -NoProfile -ExecutionPolicy unrestricted -Command "$ProgressPreference = 'SilentlyContinue'; Invoke-WebRequest 'https://dist.nuget.org/win-x86-commandline/%NUGET_VERSION%/nuget.exe' -OutFile '%CACHED_NUGET%'" + ) + + copy %CACHED_NUGET% %NUGET_PATH% > nul +) + +IF NOT EXIST %KOREBUILD_FOLDER% ( + SET KOREBUILD_DOWNLOAD_ARGS= + IF NOT "%KOREBUILD_VERSION%"=="" ( + SET KOREBUILD_DOWNLOAD_ARGS=-version %KOREBUILD_VERSION% + ) + + %BUILD_FOLDER%\nuget.exe install KoreBuild-dotnet -ExcludeVersion -o %BUILD_FOLDER% -nocache -pre %KOREBUILD_DOWNLOAD_ARGS% +) + +"%KOREBUILD_FOLDER%\build\KoreBuild.cmd" %* diff --git a/build.sh b/build.sh index da4e3fcd1c..7b5e25e3a8 100755 --- a/build.sh +++ b/build.sh @@ -1,5 +1,18 @@ #!/usr/bin/env bash +SOURCE="${BASH_SOURCE[0]}" +while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink + DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" + SOURCE="$(readlink "$SOURCE")" + [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located +done +repoFolder="$( cd -P "$( dirname "$SOURCE" )" && pwd )" + +buildFolder=.build +koreBuildFolder=$buildFolder/KoreBuild-dotnet + +nugetPath=$buildFolder/nuget.exe + if test `uname` = Darwin; then cachedir=~/Library/Caches/KBuild else @@ -11,33 +24,25 @@ else fi mkdir -p $cachedir nugetVersion=latest -cachePath=$cachedir/nuget.$nugetVersion.exe +cacheNuget=$cachedir/nuget.$nugetVersion.exe -url=https://dist.nuget.org/win-x86-commandline/$nugetVersion/nuget.exe +nugetUrl=https://dist.nuget.org/win-x86-commandline/$nugetVersion/nuget.exe -if test ! -f $cachePath; then - wget -O $cachePath $url 2>/dev/null || curl -o $cachePath --location $url /dev/null +if test ! -d $buildFolder; then + mkdir $buildFolder fi -if test ! -e .nuget; then - mkdir .nuget - cp $cachePath .nuget/nuget.exe +if test ! -f $nugetPath; then + if test ! -f $cacheNuget; then + wget -O $cacheNuget $nugetUrl 2>/dev/null || curl -o $cacheNuget --location $nugetUrl /dev/null + fi + + cp $cacheNuget $nugetPath fi -if test ! -d packages/Sake; then - mono .nuget/nuget.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre - mono .nuget/nuget.exe install Sake -ExcludeVersion -Source https://www.nuget.org/api/v2/ -Out packages +if test ! -d $koreBuildFolder; then + mono $nugetPath install KoreBuild-dotnet -ExcludeVersion -o $buildFolder -nocache -pre fi -if ! type dnvm > /dev/null 2>&1; then - source packages/KoreBuild/build/dnvm.sh -fi +source $koreBuildFolder/build/KoreBuild.sh -if ! type dnx > /dev/null 2>&1 || [ -z "$SKIP_DNX_INSTALL" ]; then - dnvm install latest -runtime coreclr -alias default - dnvm install default -runtime mono -alias default -else - dnvm use default -runtime mono -fi - -mono packages/Sake/tools/Sake.exe -I packages/KoreBuild/build -f makefile.shade "$@" diff --git a/test/Microsoft.AspNet.Html.Abstractions.Test/project.json b/test/Microsoft.AspNet.Html.Abstractions.Test/project.json index e3035cbf59..8adc45cf51 100644 --- a/test/Microsoft.AspNet.Html.Abstractions.Test/project.json +++ b/test/Microsoft.AspNet.Html.Abstractions.Test/project.json @@ -7,16 +7,22 @@ "Microsoft.AspNet.Html.Abstractions": "1.0.0-*", "Microsoft.AspNet.Testing": "1.0.0-*", "Microsoft.Extensions.WebEncoders": "1.0.0-*", - "xunit.runner.aspnet": "2.0.0-aspnet-*" + "xunit": "2.1.0" }, + "testRunner": "xunit", "commands": { "test": "xunit.runner.aspnet" }, "frameworks": { - "dnx451": { }, + "dnx451": { + "dependencies": { + "xunit.runner.console": "2.1.0" + } + }, "dnxcore50": { "dependencies": { - "System.Runtime": "4.0.21-*" + "System.Runtime": "4.0.21-*", + "xunit.runner.aspnet": "2.0.0-aspnet-*" } } } diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/project.json b/test/Microsoft.Extensions.WebEncoders.Tests/project.json index 62fb30b458..c588c7a29e 100644 --- a/test/Microsoft.Extensions.WebEncoders.Tests/project.json +++ b/test/Microsoft.Extensions.WebEncoders.Tests/project.json @@ -4,6 +4,7 @@ "Microsoft.Extensions.WebEncoders": "1.0.0-*", "xunit.runner.aspnet": "2.0.0-aspnet-*" }, + "testRunner": "xunit", "commands": { "test": "xunit.runner.aspnet" }, @@ -13,7 +14,15 @@ "keyFile": "../../tools/Key.snk" }, "frameworks": { - "dnx451": { }, - "dnxcore50": { } + "dnx451": { + "dependencies": { + "xunit.runner.console": "2.1.0" + } + }, + "dnxcore50": { + "dependencies": { + "xunit.runner.aspnet": "2.0.0-aspnet-*" + } + } } } From 1dba1cc6613faec1fe14a06aa445def8a0611e0b Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 13 Jan 2016 18:25:44 -0800 Subject: [PATCH 034/471] Bumping Json.Net version to 8.0.1 --- src/Microsoft.AspNet.JsonPatch/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.AspNet.JsonPatch/project.json b/src/Microsoft.AspNet.JsonPatch/project.json index 4bbe747d4b..d026fc5266 100644 --- a/src/Microsoft.AspNet.JsonPatch/project.json +++ b/src/Microsoft.AspNet.JsonPatch/project.json @@ -9,7 +9,7 @@ "url": "git://github.com/aspnet/mvc" }, "dependencies": { - "Newtonsoft.Json": "6.0.6" + "Newtonsoft.Json": "8.0.1" }, "frameworks": { "net451": {}, From 9ad62d796332572a5ddc4601b87687b08488c474 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 15 Jan 2016 15:36:29 -0800 Subject: [PATCH 035/471] Updating to Newtonsoft.Json 8.0.2 --- src/Microsoft.AspNet.JsonPatch/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.AspNet.JsonPatch/project.json b/src/Microsoft.AspNet.JsonPatch/project.json index d026fc5266..0b9789d9c2 100644 --- a/src/Microsoft.AspNet.JsonPatch/project.json +++ b/src/Microsoft.AspNet.JsonPatch/project.json @@ -9,7 +9,7 @@ "url": "git://github.com/aspnet/mvc" }, "dependencies": { - "Newtonsoft.Json": "8.0.1" + "Newtonsoft.Json": "8.0.2" }, "frameworks": { "net451": {}, From 40bbad426246962a4715747b641bf24996d204fa Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 20 Jan 2016 20:59:53 -0800 Subject: [PATCH 036/471] Reacting to CoreCLR package version change --- src/Microsoft.AspNet.JsonPatch/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.AspNet.JsonPatch/project.json b/src/Microsoft.AspNet.JsonPatch/project.json index 0b9789d9c2..4d1206eefb 100644 --- a/src/Microsoft.AspNet.JsonPatch/project.json +++ b/src/Microsoft.AspNet.JsonPatch/project.json @@ -21,7 +21,7 @@ "System.Globalization": "4.0.11-*", "System.Reflection.Extensions": "4.0.1-*", "System.Resources.ResourceManager": "4.0.1-*", - "System.Runtime.Extensions": "4.0.11-*", + "System.Runtime.Extensions": "4.1.0-*", "System.Text.Encoding.Extensions": "4.0.11-*" } } From c564dfd20241e5f4eb81367ac5cc8ad494028773 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Fri, 22 Jan 2016 12:19:22 -0800 Subject: [PATCH 037/471] Rename AspNet 5 folders and files. See https://github.com/aspnet/Announcements/issues/144 for more information. --- .../HtmlContentBuilder.cs | 0 .../HtmlContentBuilderExtensions.cs | 0 .../HtmlEncodedString.cs | 0 .../HtmlTextWriter.cs | 0 .../IHtmlContent.cs | 0 .../IHtmlContentBuilder.cs | 0 .../Microsoft.AspNetCore.Html.Abstractions.xproj} | 0 .../Properties/AssemblyInfo.cs | 0 .../project.json | 0 .../HtmlContentBuilderExtensionsTest.cs | 0 .../HtmlContentBuilderTest.cs | 0 .../Microsoft.AspNetCore.Html.Abstractions.Test.xproj} | 0 .../project.json | 0 13 files changed, 0 insertions(+), 0 deletions(-) rename src/{Microsoft.AspNet.Html.Abstractions => Microsoft.AspNetCore.Html.Abstractions}/HtmlContentBuilder.cs (100%) rename src/{Microsoft.AspNet.Html.Abstractions => Microsoft.AspNetCore.Html.Abstractions}/HtmlContentBuilderExtensions.cs (100%) rename src/{Microsoft.AspNet.Html.Abstractions => Microsoft.AspNetCore.Html.Abstractions}/HtmlEncodedString.cs (100%) rename src/{Microsoft.AspNet.Html.Abstractions => Microsoft.AspNetCore.Html.Abstractions}/HtmlTextWriter.cs (100%) rename src/{Microsoft.AspNet.Html.Abstractions => Microsoft.AspNetCore.Html.Abstractions}/IHtmlContent.cs (100%) rename src/{Microsoft.AspNet.Html.Abstractions => Microsoft.AspNetCore.Html.Abstractions}/IHtmlContentBuilder.cs (100%) rename src/{Microsoft.AspNet.Html.Abstractions/Microsoft.AspNet.Html.Abstractions.xproj => Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.xproj} (100%) rename src/{Microsoft.AspNet.Html.Abstractions => Microsoft.AspNetCore.Html.Abstractions}/Properties/AssemblyInfo.cs (100%) rename src/{Microsoft.AspNet.Html.Abstractions => Microsoft.AspNetCore.Html.Abstractions}/project.json (100%) rename test/{Microsoft.AspNet.Html.Abstractions.Test => Microsoft.AspNetCore.Html.Abstractions.Test}/HtmlContentBuilderExtensionsTest.cs (100%) rename test/{Microsoft.AspNet.Html.Abstractions.Test => Microsoft.AspNetCore.Html.Abstractions.Test}/HtmlContentBuilderTest.cs (100%) rename test/{Microsoft.AspNet.Html.Abstractions.Test/Microsoft.AspNet.Html.Abstractions.Test.xproj => Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.xproj} (100%) rename test/{Microsoft.AspNet.Html.Abstractions.Test => Microsoft.AspNetCore.Html.Abstractions.Test}/project.json (100%) diff --git a/src/Microsoft.AspNet.Html.Abstractions/HtmlContentBuilder.cs b/src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilder.cs similarity index 100% rename from src/Microsoft.AspNet.Html.Abstractions/HtmlContentBuilder.cs rename to src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilder.cs diff --git a/src/Microsoft.AspNet.Html.Abstractions/HtmlContentBuilderExtensions.cs b/src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilderExtensions.cs similarity index 100% rename from src/Microsoft.AspNet.Html.Abstractions/HtmlContentBuilderExtensions.cs rename to src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilderExtensions.cs diff --git a/src/Microsoft.AspNet.Html.Abstractions/HtmlEncodedString.cs b/src/Microsoft.AspNetCore.Html.Abstractions/HtmlEncodedString.cs similarity index 100% rename from src/Microsoft.AspNet.Html.Abstractions/HtmlEncodedString.cs rename to src/Microsoft.AspNetCore.Html.Abstractions/HtmlEncodedString.cs diff --git a/src/Microsoft.AspNet.Html.Abstractions/HtmlTextWriter.cs b/src/Microsoft.AspNetCore.Html.Abstractions/HtmlTextWriter.cs similarity index 100% rename from src/Microsoft.AspNet.Html.Abstractions/HtmlTextWriter.cs rename to src/Microsoft.AspNetCore.Html.Abstractions/HtmlTextWriter.cs diff --git a/src/Microsoft.AspNet.Html.Abstractions/IHtmlContent.cs b/src/Microsoft.AspNetCore.Html.Abstractions/IHtmlContent.cs similarity index 100% rename from src/Microsoft.AspNet.Html.Abstractions/IHtmlContent.cs rename to src/Microsoft.AspNetCore.Html.Abstractions/IHtmlContent.cs diff --git a/src/Microsoft.AspNet.Html.Abstractions/IHtmlContentBuilder.cs b/src/Microsoft.AspNetCore.Html.Abstractions/IHtmlContentBuilder.cs similarity index 100% rename from src/Microsoft.AspNet.Html.Abstractions/IHtmlContentBuilder.cs rename to src/Microsoft.AspNetCore.Html.Abstractions/IHtmlContentBuilder.cs diff --git a/src/Microsoft.AspNet.Html.Abstractions/Microsoft.AspNet.Html.Abstractions.xproj b/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.xproj similarity index 100% rename from src/Microsoft.AspNet.Html.Abstractions/Microsoft.AspNet.Html.Abstractions.xproj rename to src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.xproj diff --git a/src/Microsoft.AspNet.Html.Abstractions/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.Html.Abstractions/Properties/AssemblyInfo.cs similarity index 100% rename from src/Microsoft.AspNet.Html.Abstractions/Properties/AssemblyInfo.cs rename to src/Microsoft.AspNetCore.Html.Abstractions/Properties/AssemblyInfo.cs diff --git a/src/Microsoft.AspNet.Html.Abstractions/project.json b/src/Microsoft.AspNetCore.Html.Abstractions/project.json similarity index 100% rename from src/Microsoft.AspNet.Html.Abstractions/project.json rename to src/Microsoft.AspNetCore.Html.Abstractions/project.json diff --git a/test/Microsoft.AspNet.Html.Abstractions.Test/HtmlContentBuilderExtensionsTest.cs b/test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlContentBuilderExtensionsTest.cs similarity index 100% rename from test/Microsoft.AspNet.Html.Abstractions.Test/HtmlContentBuilderExtensionsTest.cs rename to test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlContentBuilderExtensionsTest.cs diff --git a/test/Microsoft.AspNet.Html.Abstractions.Test/HtmlContentBuilderTest.cs b/test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlContentBuilderTest.cs similarity index 100% rename from test/Microsoft.AspNet.Html.Abstractions.Test/HtmlContentBuilderTest.cs rename to test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlContentBuilderTest.cs diff --git a/test/Microsoft.AspNet.Html.Abstractions.Test/Microsoft.AspNet.Html.Abstractions.Test.xproj b/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.xproj similarity index 100% rename from test/Microsoft.AspNet.Html.Abstractions.Test/Microsoft.AspNet.Html.Abstractions.Test.xproj rename to test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.xproj diff --git a/test/Microsoft.AspNet.Html.Abstractions.Test/project.json b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json similarity index 100% rename from test/Microsoft.AspNet.Html.Abstractions.Test/project.json rename to test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json From 79558ae8d3633f1fd9045239bf21286e50159fe4 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Fri, 22 Jan 2016 12:19:23 -0800 Subject: [PATCH 038/471] Rename AspNet 5 file contents. See https://github.com/aspnet/Announcements/issues/144 for more information. --- HtmlAbstractions.sln | 4 ++-- NuGetPackageVerifier.json | 2 +- .../HtmlContentBuilder.cs | 4 ++-- .../HtmlContentBuilderExtensions.cs | 2 +- .../HtmlEncodedString.cs | 4 ++-- src/Microsoft.AspNetCore.Html.Abstractions/HtmlTextWriter.cs | 4 ++-- src/Microsoft.AspNetCore.Html.Abstractions/IHtmlContent.cs | 2 +- .../IHtmlContentBuilder.cs | 4 ++-- .../Microsoft.AspNetCore.Html.Abstractions.xproj | 4 ++-- .../Properties/AssemblyInfo.cs | 2 +- .../HtmlContentBuilderExtensionsTest.cs | 4 ++-- .../HtmlContentBuilderTest.cs | 2 +- .../Microsoft.AspNetCore.Html.Abstractions.Test.xproj | 4 ++-- test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json | 4 ++-- 14 files changed, 23 insertions(+), 23 deletions(-) diff --git a/HtmlAbstractions.sln b/HtmlAbstractions.sln index a45f34a265..81189bb447 100644 --- a/HtmlAbstractions.sln +++ b/HtmlAbstractions.sln @@ -6,9 +6,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A5A15F1C-885 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{F31FF137-390C-49BF-A3BD-7C6ED3597C21}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Html.Abstractions", "src\Microsoft.AspNet.Html.Abstractions\Microsoft.AspNet.Html.Abstractions.xproj", "{68A28E4A-3ADE-4187-9625-4FF185887CB3}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Html.Abstractions", "src\Microsoft.AspNetCore.Html.Abstractions\Microsoft.AspNetCore.Html.Abstractions.xproj", "{68A28E4A-3ADE-4187-9625-4FF185887CB3}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Html.Abstractions.Test", "test\Microsoft.AspNet.Html.Abstractions.Test\Microsoft.AspNet.Html.Abstractions.Test.xproj", "{2D187B88-94BD-4A39-AC97-F8F8B9363301}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Html.Abstractions.Test", "test\Microsoft.AspNetCore.Html.Abstractions.Test\Microsoft.AspNetCore.Html.Abstractions.Test.xproj", "{2D187B88-94BD-4A39-AC97-F8F8B9363301}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B4962A29-BE69-4A18-9B4F-B803EEE31EAA}" ProjectSection(SolutionItems) = preProject diff --git a/NuGetPackageVerifier.json b/NuGetPackageVerifier.json index 31f9437602..d9dea7c8ac 100644 --- a/NuGetPackageVerifier.json +++ b/NuGetPackageVerifier.json @@ -9,7 +9,7 @@ "StrictSemanticVersionValidationRule" ], "packages": { - "Microsoft.AspNet.Html.Abstractions": { }, + "Microsoft.AspNetCore.Html.Abstractions": { }, "Microsoft.Extensions.WebEncoders": { } } }, diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilder.cs b/src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilder.cs index 10a50cb34d..b79e400375 100644 --- a/src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilder.cs +++ b/src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilder.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (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; @@ -6,7 +6,7 @@ using System.Collections.Generic; using System.IO; using System.Text.Encodings.Web; -namespace Microsoft.AspNet.Html +namespace Microsoft.AspNetCore.Html { /// /// An implementation using an in memory list. diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilderExtensions.cs b/src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilderExtensions.cs index 2ff745cdf3..aaba4faefb 100644 --- a/src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilderExtensions.cs @@ -7,7 +7,7 @@ using System.Globalization; using System.IO; using System.Text.Encodings.Web; -namespace Microsoft.AspNet.Html +namespace Microsoft.AspNetCore.Html { /// /// Extension methods for . diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/HtmlEncodedString.cs b/src/Microsoft.AspNetCore.Html.Abstractions/HtmlEncodedString.cs index e5c4ab5003..c50fba890c 100644 --- a/src/Microsoft.AspNetCore.Html.Abstractions/HtmlEncodedString.cs +++ b/src/Microsoft.AspNetCore.Html.Abstractions/HtmlEncodedString.cs @@ -1,11 +1,11 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (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.AspNet.Html +namespace Microsoft.AspNetCore.Html { /// /// An implementation that wraps an HTML encoded . diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/HtmlTextWriter.cs b/src/Microsoft.AspNetCore.Html.Abstractions/HtmlTextWriter.cs index 56633f527d..c9158b49b6 100644 --- a/src/Microsoft.AspNetCore.Html.Abstractions/HtmlTextWriter.cs +++ b/src/Microsoft.AspNetCore.Html.Abstractions/HtmlTextWriter.cs @@ -1,9 +1,9 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (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; -namespace Microsoft.AspNet.Html +namespace Microsoft.AspNetCore.Html { /// /// A which supports special processing of . diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/IHtmlContent.cs b/src/Microsoft.AspNetCore.Html.Abstractions/IHtmlContent.cs index 0e21889d54..2e9a0f19e2 100644 --- a/src/Microsoft.AspNetCore.Html.Abstractions/IHtmlContent.cs +++ b/src/Microsoft.AspNetCore.Html.Abstractions/IHtmlContent.cs @@ -4,7 +4,7 @@ using System.IO; using System.Text.Encodings.Web; -namespace Microsoft.AspNet.Html +namespace Microsoft.AspNetCore.Html { /// /// HTML content which can be written to a TextWriter. diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/IHtmlContentBuilder.cs b/src/Microsoft.AspNetCore.Html.Abstractions/IHtmlContentBuilder.cs index 6b0a6d6571..978fedc03f 100644 --- a/src/Microsoft.AspNetCore.Html.Abstractions/IHtmlContentBuilder.cs +++ b/src/Microsoft.AspNetCore.Html.Abstractions/IHtmlContentBuilder.cs @@ -1,7 +1,7 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (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.AspNet.Html +namespace Microsoft.AspNetCore.Html { /// /// A builder for HTML content. diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.xproj b/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.xproj index 564c800504..df229c75eb 100644 --- a/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.xproj +++ b/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.xproj @@ -1,4 +1,4 @@ - + 14.0 @@ -7,7 +7,7 @@ 68a28e4a-3ade-4187-9625-4ff185887cb3 - Microsoft.AspNet.Html.Abstractions + Microsoft.AspNetCore.Html.Abstractions ..\..\artifacts\obj\$(MSBuildProjectName) ..\..\artifacts\bin\$(MSBuildProjectName)\ diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.Html.Abstractions/Properties/AssemblyInfo.cs index d310306c25..72210dd611 100644 --- a/src/Microsoft.AspNetCore.Html.Abstractions/Properties/AssemblyInfo.cs +++ b/src/Microsoft.AspNetCore.Html.Abstractions/Properties/AssemblyInfo.cs @@ -7,4 +7,4 @@ using System.Runtime.CompilerServices; [assembly: AssemblyMetadata("Serviceable", "True")] [assembly: NeutralResourcesLanguage("en-us")] -[assembly: InternalsVisibleTo("Microsoft.AspNet.Html.Abstractions.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] \ No newline at end of file +[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Html.Abstractions.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlContentBuilderExtensionsTest.cs b/test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlContentBuilderExtensionsTest.cs index ff201b494c..6b4307f690 100644 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlContentBuilderExtensionsTest.cs +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlContentBuilderExtensionsTest.cs @@ -6,11 +6,11 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Text.Encodings.Web; -using Microsoft.AspNet.Testing; +using Microsoft.AspNetCore.Testing; using Microsoft.Extensions.WebEncoders.Testing; using Xunit; -namespace Microsoft.AspNet.Html.Test +namespace Microsoft.AspNetCore.Html.Test { public class HtmlContentBuilderExtensionsTest { diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlContentBuilderTest.cs b/test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlContentBuilderTest.cs index c9eda50adc..901512fdad 100644 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlContentBuilderTest.cs +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlContentBuilderTest.cs @@ -3,7 +3,7 @@ using System.IO; using System.Text.Encodings.Web; -using Microsoft.AspNet.Html; +using Microsoft.AspNetCore.Html; using Microsoft.Extensions.WebEncoders.Testing; using Xunit; diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.xproj b/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.xproj index 4a03567677..f699a1c4dc 100644 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.xproj +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.xproj @@ -1,4 +1,4 @@ - + 14.0 @@ -7,7 +7,7 @@ 2d187b88-94bd-4a39-ac97-f8f8b9363301 - Microsoft.AspNet.Html.Abstractions.Test + Microsoft.AspNetCore.Html.Abstractions.Test ..\..\artifacts\obj\$(MSBuildProjectName) ..\..\artifacts\bin\$(MSBuildProjectName)\ diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json index 8adc45cf51..d796493c0a 100644 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json @@ -4,8 +4,8 @@ "keyFile": "../../tools/Key.snk" }, "dependencies": { - "Microsoft.AspNet.Html.Abstractions": "1.0.0-*", - "Microsoft.AspNet.Testing": "1.0.0-*", + "Microsoft.AspNetCore.Html.Abstractions": "1.0.0-*", + "Microsoft.AspNetCore.Testing": "1.0.0-*", "Microsoft.Extensions.WebEncoders": "1.0.0-*", "xunit": "2.1.0" }, From 582e222c2bf4567d28cb224b78284439a6a34651 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Fri, 22 Jan 2016 12:20:54 -0800 Subject: [PATCH 039/471] Rename AspNet 5 folders and files. See https://github.com/aspnet/Announcements/issues/144 for more information. --- .../Adapters/IObjectAdapter.cs | 0 .../Adapters/ObjectAdapter.cs | 0 .../Converters/JsonPatchDocumentConverter.cs | 0 .../Converters/TypedJsonPatchDocumentConverter.cs | 0 .../Exceptions/JsonPatchException.cs | 0 .../Helpers/ActualPropertyPathResult.cs | 0 .../Helpers/ConversionResult.cs | 0 .../Helpers/ExpandoObjectDictionaryExtensions.cs | 0 .../Helpers/ExpressionHelpers.cs | 0 .../Helpers/GetValueResult.cs | 0 .../Helpers/JsonPatchProperty.cs | 0 .../Helpers/ObjectTreeAnalyisResult.cs | 0 .../Helpers/PathHelpers.cs | 0 .../Helpers/RemovedPropertyTypeResult.cs | 0 .../IJsonPatchDocument.cs | 0 .../JsonPatchDocument.cs | 0 .../JsonPatchDocumentOfT.cs | 0 .../JsonPatchError.cs | 0 .../Microsoft.AspNetCore.JsonPatch.xproj} | 0 .../Operations/Operation.cs | 0 .../Operations/OperationBase.cs | 0 .../Operations/OperationOfT.cs | 0 .../Operations/OperationType.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../Properties/Resources.Designer.cs | 0 .../Resources.resx | 0 .../project.json | 0 .../Dynamic/AddOperationTests.cs | 0 .../Dynamic/AddTypedOperationTests.cs | 0 .../Dynamic/CopyOperationTests.cs | 0 .../Dynamic/CopyTypedOperationTests.cs | 0 .../Dynamic/MoveOperationTests.cs | 0 .../Dynamic/MoveTypedOperationTests.cs | 0 .../Dynamic/NestedDTO.cs | 0 .../Dynamic/PatchDocumentTests.cs | 0 .../Dynamic/RemoveOperationTests.cs | 0 .../Dynamic/RemoveTypedOperationTests.cs | 0 .../Dynamic/ReplaceOperationTests.cs | 0 .../Dynamic/ReplaceTypedOperationTests.cs | 0 .../Dynamic/SimpleDTO.cs | 0 .../Dynamic/SimpleDTOWithNestedDTO.cs | 0 .../Microsoft.AspNetCore.JsonPatch.Test.xproj} | 0 .../NestedDTO.cs | 0 .../NestedObjectTests.cs | 0 .../ObjectAdapterTests.cs | 0 .../SimpleDTO.cs | 0 .../SimpleDTOWithNestedDTO.cs | 0 .../TestErrorLogger.cs | 0 .../project.json | 0 49 files changed, 0 insertions(+), 0 deletions(-) rename src/{Microsoft.AspNet.JsonPatch => Microsoft.AspNetCore.JsonPatch}/Adapters/IObjectAdapter.cs (100%) rename src/{Microsoft.AspNet.JsonPatch => Microsoft.AspNetCore.JsonPatch}/Adapters/ObjectAdapter.cs (100%) rename src/{Microsoft.AspNet.JsonPatch => Microsoft.AspNetCore.JsonPatch}/Converters/JsonPatchDocumentConverter.cs (100%) rename src/{Microsoft.AspNet.JsonPatch => Microsoft.AspNetCore.JsonPatch}/Converters/TypedJsonPatchDocumentConverter.cs (100%) rename src/{Microsoft.AspNet.JsonPatch => Microsoft.AspNetCore.JsonPatch}/Exceptions/JsonPatchException.cs (100%) rename src/{Microsoft.AspNet.JsonPatch => Microsoft.AspNetCore.JsonPatch}/Helpers/ActualPropertyPathResult.cs (100%) rename src/{Microsoft.AspNet.JsonPatch => Microsoft.AspNetCore.JsonPatch}/Helpers/ConversionResult.cs (100%) rename src/{Microsoft.AspNet.JsonPatch => Microsoft.AspNetCore.JsonPatch}/Helpers/ExpandoObjectDictionaryExtensions.cs (100%) rename src/{Microsoft.AspNet.JsonPatch => Microsoft.AspNetCore.JsonPatch}/Helpers/ExpressionHelpers.cs (100%) rename src/{Microsoft.AspNet.JsonPatch => Microsoft.AspNetCore.JsonPatch}/Helpers/GetValueResult.cs (100%) rename src/{Microsoft.AspNet.JsonPatch => Microsoft.AspNetCore.JsonPatch}/Helpers/JsonPatchProperty.cs (100%) rename src/{Microsoft.AspNet.JsonPatch => Microsoft.AspNetCore.JsonPatch}/Helpers/ObjectTreeAnalyisResult.cs (100%) rename src/{Microsoft.AspNet.JsonPatch => Microsoft.AspNetCore.JsonPatch}/Helpers/PathHelpers.cs (100%) rename src/{Microsoft.AspNet.JsonPatch => Microsoft.AspNetCore.JsonPatch}/Helpers/RemovedPropertyTypeResult.cs (100%) rename src/{Microsoft.AspNet.JsonPatch => Microsoft.AspNetCore.JsonPatch}/IJsonPatchDocument.cs (100%) rename src/{Microsoft.AspNet.JsonPatch => Microsoft.AspNetCore.JsonPatch}/JsonPatchDocument.cs (100%) rename src/{Microsoft.AspNet.JsonPatch => Microsoft.AspNetCore.JsonPatch}/JsonPatchDocumentOfT.cs (100%) rename src/{Microsoft.AspNet.JsonPatch => Microsoft.AspNetCore.JsonPatch}/JsonPatchError.cs (100%) rename src/{Microsoft.AspNet.JsonPatch/Microsoft.AspNet.JsonPatch.xproj => Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.xproj} (100%) rename src/{Microsoft.AspNet.JsonPatch => Microsoft.AspNetCore.JsonPatch}/Operations/Operation.cs (100%) rename src/{Microsoft.AspNet.JsonPatch => Microsoft.AspNetCore.JsonPatch}/Operations/OperationBase.cs (100%) rename src/{Microsoft.AspNet.JsonPatch => Microsoft.AspNetCore.JsonPatch}/Operations/OperationOfT.cs (100%) rename src/{Microsoft.AspNet.JsonPatch => Microsoft.AspNetCore.JsonPatch}/Operations/OperationType.cs (100%) rename src/{Microsoft.AspNet.JsonPatch => Microsoft.AspNetCore.JsonPatch}/Properties/AssemblyInfo.cs (100%) rename src/{Microsoft.AspNet.JsonPatch => Microsoft.AspNetCore.JsonPatch}/Properties/Resources.Designer.cs (100%) rename src/{Microsoft.AspNet.JsonPatch => Microsoft.AspNetCore.JsonPatch}/Resources.resx (100%) rename src/{Microsoft.AspNet.JsonPatch => Microsoft.AspNetCore.JsonPatch}/project.json (100%) rename test/{Microsoft.AspNet.JsonPatch.Test => Microsoft.AspNetCore.JsonPatch.Test}/Dynamic/AddOperationTests.cs (100%) rename test/{Microsoft.AspNet.JsonPatch.Test => Microsoft.AspNetCore.JsonPatch.Test}/Dynamic/AddTypedOperationTests.cs (100%) rename test/{Microsoft.AspNet.JsonPatch.Test => Microsoft.AspNetCore.JsonPatch.Test}/Dynamic/CopyOperationTests.cs (100%) rename test/{Microsoft.AspNet.JsonPatch.Test => Microsoft.AspNetCore.JsonPatch.Test}/Dynamic/CopyTypedOperationTests.cs (100%) rename test/{Microsoft.AspNet.JsonPatch.Test => Microsoft.AspNetCore.JsonPatch.Test}/Dynamic/MoveOperationTests.cs (100%) rename test/{Microsoft.AspNet.JsonPatch.Test => Microsoft.AspNetCore.JsonPatch.Test}/Dynamic/MoveTypedOperationTests.cs (100%) rename test/{Microsoft.AspNet.JsonPatch.Test => Microsoft.AspNetCore.JsonPatch.Test}/Dynamic/NestedDTO.cs (100%) rename test/{Microsoft.AspNet.JsonPatch.Test => Microsoft.AspNetCore.JsonPatch.Test}/Dynamic/PatchDocumentTests.cs (100%) rename test/{Microsoft.AspNet.JsonPatch.Test => Microsoft.AspNetCore.JsonPatch.Test}/Dynamic/RemoveOperationTests.cs (100%) rename test/{Microsoft.AspNet.JsonPatch.Test => Microsoft.AspNetCore.JsonPatch.Test}/Dynamic/RemoveTypedOperationTests.cs (100%) rename test/{Microsoft.AspNet.JsonPatch.Test => Microsoft.AspNetCore.JsonPatch.Test}/Dynamic/ReplaceOperationTests.cs (100%) rename test/{Microsoft.AspNet.JsonPatch.Test => Microsoft.AspNetCore.JsonPatch.Test}/Dynamic/ReplaceTypedOperationTests.cs (100%) rename test/{Microsoft.AspNet.JsonPatch.Test => Microsoft.AspNetCore.JsonPatch.Test}/Dynamic/SimpleDTO.cs (100%) rename test/{Microsoft.AspNet.JsonPatch.Test => Microsoft.AspNetCore.JsonPatch.Test}/Dynamic/SimpleDTOWithNestedDTO.cs (100%) rename test/{Microsoft.AspNet.JsonPatch.Test/Microsoft.AspNet.JsonPatch.Test.xproj => Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.xproj} (100%) rename test/{Microsoft.AspNet.JsonPatch.Test => Microsoft.AspNetCore.JsonPatch.Test}/NestedDTO.cs (100%) rename test/{Microsoft.AspNet.JsonPatch.Test => Microsoft.AspNetCore.JsonPatch.Test}/NestedObjectTests.cs (100%) rename test/{Microsoft.AspNet.JsonPatch.Test => Microsoft.AspNetCore.JsonPatch.Test}/ObjectAdapterTests.cs (100%) rename test/{Microsoft.AspNet.JsonPatch.Test => Microsoft.AspNetCore.JsonPatch.Test}/SimpleDTO.cs (100%) rename test/{Microsoft.AspNet.JsonPatch.Test => Microsoft.AspNetCore.JsonPatch.Test}/SimpleDTOWithNestedDTO.cs (100%) rename test/{Microsoft.AspNet.JsonPatch.Test => Microsoft.AspNetCore.JsonPatch.Test}/TestErrorLogger.cs (100%) rename test/{Microsoft.AspNet.JsonPatch.Test => Microsoft.AspNetCore.JsonPatch.Test}/project.json (100%) diff --git a/src/Microsoft.AspNet.JsonPatch/Adapters/IObjectAdapter.cs b/src/Microsoft.AspNetCore.JsonPatch/Adapters/IObjectAdapter.cs similarity index 100% rename from src/Microsoft.AspNet.JsonPatch/Adapters/IObjectAdapter.cs rename to src/Microsoft.AspNetCore.JsonPatch/Adapters/IObjectAdapter.cs diff --git a/src/Microsoft.AspNet.JsonPatch/Adapters/ObjectAdapter.cs b/src/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs similarity index 100% rename from src/Microsoft.AspNet.JsonPatch/Adapters/ObjectAdapter.cs rename to src/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs diff --git a/src/Microsoft.AspNet.JsonPatch/Converters/JsonPatchDocumentConverter.cs b/src/Microsoft.AspNetCore.JsonPatch/Converters/JsonPatchDocumentConverter.cs similarity index 100% rename from src/Microsoft.AspNet.JsonPatch/Converters/JsonPatchDocumentConverter.cs rename to src/Microsoft.AspNetCore.JsonPatch/Converters/JsonPatchDocumentConverter.cs diff --git a/src/Microsoft.AspNet.JsonPatch/Converters/TypedJsonPatchDocumentConverter.cs b/src/Microsoft.AspNetCore.JsonPatch/Converters/TypedJsonPatchDocumentConverter.cs similarity index 100% rename from src/Microsoft.AspNet.JsonPatch/Converters/TypedJsonPatchDocumentConverter.cs rename to src/Microsoft.AspNetCore.JsonPatch/Converters/TypedJsonPatchDocumentConverter.cs diff --git a/src/Microsoft.AspNet.JsonPatch/Exceptions/JsonPatchException.cs b/src/Microsoft.AspNetCore.JsonPatch/Exceptions/JsonPatchException.cs similarity index 100% rename from src/Microsoft.AspNet.JsonPatch/Exceptions/JsonPatchException.cs rename to src/Microsoft.AspNetCore.JsonPatch/Exceptions/JsonPatchException.cs diff --git a/src/Microsoft.AspNet.JsonPatch/Helpers/ActualPropertyPathResult.cs b/src/Microsoft.AspNetCore.JsonPatch/Helpers/ActualPropertyPathResult.cs similarity index 100% rename from src/Microsoft.AspNet.JsonPatch/Helpers/ActualPropertyPathResult.cs rename to src/Microsoft.AspNetCore.JsonPatch/Helpers/ActualPropertyPathResult.cs diff --git a/src/Microsoft.AspNet.JsonPatch/Helpers/ConversionResult.cs b/src/Microsoft.AspNetCore.JsonPatch/Helpers/ConversionResult.cs similarity index 100% rename from src/Microsoft.AspNet.JsonPatch/Helpers/ConversionResult.cs rename to src/Microsoft.AspNetCore.JsonPatch/Helpers/ConversionResult.cs diff --git a/src/Microsoft.AspNet.JsonPatch/Helpers/ExpandoObjectDictionaryExtensions.cs b/src/Microsoft.AspNetCore.JsonPatch/Helpers/ExpandoObjectDictionaryExtensions.cs similarity index 100% rename from src/Microsoft.AspNet.JsonPatch/Helpers/ExpandoObjectDictionaryExtensions.cs rename to src/Microsoft.AspNetCore.JsonPatch/Helpers/ExpandoObjectDictionaryExtensions.cs diff --git a/src/Microsoft.AspNet.JsonPatch/Helpers/ExpressionHelpers.cs b/src/Microsoft.AspNetCore.JsonPatch/Helpers/ExpressionHelpers.cs similarity index 100% rename from src/Microsoft.AspNet.JsonPatch/Helpers/ExpressionHelpers.cs rename to src/Microsoft.AspNetCore.JsonPatch/Helpers/ExpressionHelpers.cs diff --git a/src/Microsoft.AspNet.JsonPatch/Helpers/GetValueResult.cs b/src/Microsoft.AspNetCore.JsonPatch/Helpers/GetValueResult.cs similarity index 100% rename from src/Microsoft.AspNet.JsonPatch/Helpers/GetValueResult.cs rename to src/Microsoft.AspNetCore.JsonPatch/Helpers/GetValueResult.cs diff --git a/src/Microsoft.AspNet.JsonPatch/Helpers/JsonPatchProperty.cs b/src/Microsoft.AspNetCore.JsonPatch/Helpers/JsonPatchProperty.cs similarity index 100% rename from src/Microsoft.AspNet.JsonPatch/Helpers/JsonPatchProperty.cs rename to src/Microsoft.AspNetCore.JsonPatch/Helpers/JsonPatchProperty.cs diff --git a/src/Microsoft.AspNet.JsonPatch/Helpers/ObjectTreeAnalyisResult.cs b/src/Microsoft.AspNetCore.JsonPatch/Helpers/ObjectTreeAnalyisResult.cs similarity index 100% rename from src/Microsoft.AspNet.JsonPatch/Helpers/ObjectTreeAnalyisResult.cs rename to src/Microsoft.AspNetCore.JsonPatch/Helpers/ObjectTreeAnalyisResult.cs diff --git a/src/Microsoft.AspNet.JsonPatch/Helpers/PathHelpers.cs b/src/Microsoft.AspNetCore.JsonPatch/Helpers/PathHelpers.cs similarity index 100% rename from src/Microsoft.AspNet.JsonPatch/Helpers/PathHelpers.cs rename to src/Microsoft.AspNetCore.JsonPatch/Helpers/PathHelpers.cs diff --git a/src/Microsoft.AspNet.JsonPatch/Helpers/RemovedPropertyTypeResult.cs b/src/Microsoft.AspNetCore.JsonPatch/Helpers/RemovedPropertyTypeResult.cs similarity index 100% rename from src/Microsoft.AspNet.JsonPatch/Helpers/RemovedPropertyTypeResult.cs rename to src/Microsoft.AspNetCore.JsonPatch/Helpers/RemovedPropertyTypeResult.cs diff --git a/src/Microsoft.AspNet.JsonPatch/IJsonPatchDocument.cs b/src/Microsoft.AspNetCore.JsonPatch/IJsonPatchDocument.cs similarity index 100% rename from src/Microsoft.AspNet.JsonPatch/IJsonPatchDocument.cs rename to src/Microsoft.AspNetCore.JsonPatch/IJsonPatchDocument.cs diff --git a/src/Microsoft.AspNet.JsonPatch/JsonPatchDocument.cs b/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocument.cs similarity index 100% rename from src/Microsoft.AspNet.JsonPatch/JsonPatchDocument.cs rename to src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocument.cs diff --git a/src/Microsoft.AspNet.JsonPatch/JsonPatchDocumentOfT.cs b/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs similarity index 100% rename from src/Microsoft.AspNet.JsonPatch/JsonPatchDocumentOfT.cs rename to src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs diff --git a/src/Microsoft.AspNet.JsonPatch/JsonPatchError.cs b/src/Microsoft.AspNetCore.JsonPatch/JsonPatchError.cs similarity index 100% rename from src/Microsoft.AspNet.JsonPatch/JsonPatchError.cs rename to src/Microsoft.AspNetCore.JsonPatch/JsonPatchError.cs diff --git a/src/Microsoft.AspNet.JsonPatch/Microsoft.AspNet.JsonPatch.xproj b/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.xproj similarity index 100% rename from src/Microsoft.AspNet.JsonPatch/Microsoft.AspNet.JsonPatch.xproj rename to src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.xproj diff --git a/src/Microsoft.AspNet.JsonPatch/Operations/Operation.cs b/src/Microsoft.AspNetCore.JsonPatch/Operations/Operation.cs similarity index 100% rename from src/Microsoft.AspNet.JsonPatch/Operations/Operation.cs rename to src/Microsoft.AspNetCore.JsonPatch/Operations/Operation.cs diff --git a/src/Microsoft.AspNet.JsonPatch/Operations/OperationBase.cs b/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationBase.cs similarity index 100% rename from src/Microsoft.AspNet.JsonPatch/Operations/OperationBase.cs rename to src/Microsoft.AspNetCore.JsonPatch/Operations/OperationBase.cs diff --git a/src/Microsoft.AspNet.JsonPatch/Operations/OperationOfT.cs b/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationOfT.cs similarity index 100% rename from src/Microsoft.AspNet.JsonPatch/Operations/OperationOfT.cs rename to src/Microsoft.AspNetCore.JsonPatch/Operations/OperationOfT.cs diff --git a/src/Microsoft.AspNet.JsonPatch/Operations/OperationType.cs b/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationType.cs similarity index 100% rename from src/Microsoft.AspNet.JsonPatch/Operations/OperationType.cs rename to src/Microsoft.AspNetCore.JsonPatch/Operations/OperationType.cs diff --git a/src/Microsoft.AspNet.JsonPatch/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.JsonPatch/Properties/AssemblyInfo.cs similarity index 100% rename from src/Microsoft.AspNet.JsonPatch/Properties/AssemblyInfo.cs rename to src/Microsoft.AspNetCore.JsonPatch/Properties/AssemblyInfo.cs diff --git a/src/Microsoft.AspNet.JsonPatch/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs similarity index 100% rename from src/Microsoft.AspNet.JsonPatch/Properties/Resources.Designer.cs rename to src/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs diff --git a/src/Microsoft.AspNet.JsonPatch/Resources.resx b/src/Microsoft.AspNetCore.JsonPatch/Resources.resx similarity index 100% rename from src/Microsoft.AspNet.JsonPatch/Resources.resx rename to src/Microsoft.AspNetCore.JsonPatch/Resources.resx diff --git a/src/Microsoft.AspNet.JsonPatch/project.json b/src/Microsoft.AspNetCore.JsonPatch/project.json similarity index 100% rename from src/Microsoft.AspNet.JsonPatch/project.json rename to src/Microsoft.AspNetCore.JsonPatch/project.json diff --git a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/AddOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddOperationTests.cs similarity index 100% rename from test/Microsoft.AspNet.JsonPatch.Test/Dynamic/AddOperationTests.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddOperationTests.cs diff --git a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/AddTypedOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddTypedOperationTests.cs similarity index 100% rename from test/Microsoft.AspNet.JsonPatch.Test/Dynamic/AddTypedOperationTests.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddTypedOperationTests.cs diff --git a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/CopyOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CopyOperationTests.cs similarity index 100% rename from test/Microsoft.AspNet.JsonPatch.Test/Dynamic/CopyOperationTests.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CopyOperationTests.cs diff --git a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/CopyTypedOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CopyTypedOperationTests.cs similarity index 100% rename from test/Microsoft.AspNet.JsonPatch.Test/Dynamic/CopyTypedOperationTests.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CopyTypedOperationTests.cs diff --git a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/MoveOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveOperationTests.cs similarity index 100% rename from test/Microsoft.AspNet.JsonPatch.Test/Dynamic/MoveOperationTests.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveOperationTests.cs diff --git a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/MoveTypedOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveTypedOperationTests.cs similarity index 100% rename from test/Microsoft.AspNet.JsonPatch.Test/Dynamic/MoveTypedOperationTests.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveTypedOperationTests.cs diff --git a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/NestedDTO.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/NestedDTO.cs similarity index 100% rename from test/Microsoft.AspNet.JsonPatch.Test/Dynamic/NestedDTO.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/NestedDTO.cs diff --git a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/PatchDocumentTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/PatchDocumentTests.cs similarity index 100% rename from test/Microsoft.AspNet.JsonPatch.Test/Dynamic/PatchDocumentTests.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/PatchDocumentTests.cs diff --git a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/RemoveOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveOperationTests.cs similarity index 100% rename from test/Microsoft.AspNet.JsonPatch.Test/Dynamic/RemoveOperationTests.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveOperationTests.cs diff --git a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/RemoveTypedOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveTypedOperationTests.cs similarity index 100% rename from test/Microsoft.AspNet.JsonPatch.Test/Dynamic/RemoveTypedOperationTests.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveTypedOperationTests.cs diff --git a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/ReplaceOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceOperationTests.cs similarity index 100% rename from test/Microsoft.AspNet.JsonPatch.Test/Dynamic/ReplaceOperationTests.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceOperationTests.cs diff --git a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/ReplaceTypedOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceTypedOperationTests.cs similarity index 100% rename from test/Microsoft.AspNet.JsonPatch.Test/Dynamic/ReplaceTypedOperationTests.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceTypedOperationTests.cs diff --git a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/SimpleDTO.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/SimpleDTO.cs similarity index 100% rename from test/Microsoft.AspNet.JsonPatch.Test/Dynamic/SimpleDTO.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/SimpleDTO.cs diff --git a/test/Microsoft.AspNet.JsonPatch.Test/Dynamic/SimpleDTOWithNestedDTO.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/SimpleDTOWithNestedDTO.cs similarity index 100% rename from test/Microsoft.AspNet.JsonPatch.Test/Dynamic/SimpleDTOWithNestedDTO.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/SimpleDTOWithNestedDTO.cs diff --git a/test/Microsoft.AspNet.JsonPatch.Test/Microsoft.AspNet.JsonPatch.Test.xproj b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.xproj similarity index 100% rename from test/Microsoft.AspNet.JsonPatch.Test/Microsoft.AspNet.JsonPatch.Test.xproj rename to test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.xproj diff --git a/test/Microsoft.AspNet.JsonPatch.Test/NestedDTO.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/NestedDTO.cs similarity index 100% rename from test/Microsoft.AspNet.JsonPatch.Test/NestedDTO.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/NestedDTO.cs diff --git a/test/Microsoft.AspNet.JsonPatch.Test/NestedObjectTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/NestedObjectTests.cs similarity index 100% rename from test/Microsoft.AspNet.JsonPatch.Test/NestedObjectTests.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/NestedObjectTests.cs diff --git a/test/Microsoft.AspNet.JsonPatch.Test/ObjectAdapterTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs similarity index 100% rename from test/Microsoft.AspNet.JsonPatch.Test/ObjectAdapterTests.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs diff --git a/test/Microsoft.AspNet.JsonPatch.Test/SimpleDTO.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTO.cs similarity index 100% rename from test/Microsoft.AspNet.JsonPatch.Test/SimpleDTO.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTO.cs diff --git a/test/Microsoft.AspNet.JsonPatch.Test/SimpleDTOWithNestedDTO.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTOWithNestedDTO.cs similarity index 100% rename from test/Microsoft.AspNet.JsonPatch.Test/SimpleDTOWithNestedDTO.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTOWithNestedDTO.cs diff --git a/test/Microsoft.AspNet.JsonPatch.Test/TestErrorLogger.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/TestErrorLogger.cs similarity index 100% rename from test/Microsoft.AspNet.JsonPatch.Test/TestErrorLogger.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/TestErrorLogger.cs diff --git a/test/Microsoft.AspNet.JsonPatch.Test/project.json b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json similarity index 100% rename from test/Microsoft.AspNet.JsonPatch.Test/project.json rename to test/Microsoft.AspNetCore.JsonPatch.Test/project.json From e2801d6c2065acfcb4b997901f13b474a3acbe57 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Fri, 22 Jan 2016 12:20:58 -0800 Subject: [PATCH 040/471] Rename AspNet 5 file contents. See https://github.com/aspnet/Announcements/issues/144 for more information. --- JsonPatch.sln | 6 +++--- NuGetPackageVerifier.json | 2 +- .../Adapters/IObjectAdapter.cs | 4 ++-- .../Adapters/ObjectAdapter.cs | 8 ++++---- .../Converters/JsonPatchDocumentConverter.cs | 8 ++++---- .../Converters/TypedJsonPatchDocumentConverter.cs | 6 +++--- .../Exceptions/JsonPatchException.cs | 4 ++-- .../Helpers/ActualPropertyPathResult.cs | 4 ++-- .../Helpers/ConversionResult.cs | 2 +- .../Helpers/ExpandoObjectDictionaryExtensions.cs | 4 ++-- .../Helpers/ExpressionHelpers.cs | 2 +- .../Helpers/GetValueResult.cs | 4 ++-- .../Helpers/JsonPatchProperty.cs | 2 +- .../Helpers/ObjectTreeAnalyisResult.cs | 4 ++-- .../Helpers/PathHelpers.cs | 6 +++--- .../Helpers/RemovedPropertyTypeResult.cs | 4 ++-- .../IJsonPatchDocument.cs | 4 ++-- .../JsonPatchDocument.cs | 10 +++++----- .../JsonPatchDocumentOfT.cs | 10 +++++----- src/Microsoft.AspNetCore.JsonPatch/JsonPatchError.cs | 4 ++-- .../Operations/Operation.cs | 4 ++-- .../Operations/OperationBase.cs | 2 +- .../Operations/OperationOfT.cs | 4 ++-- .../Operations/OperationType.cs | 2 +- .../Properties/Resources.Designer.cs | 4 ++-- .../Dynamic/AddOperationTests.cs | 6 +++--- .../Dynamic/AddTypedOperationTests.cs | 6 +++--- .../Dynamic/CopyOperationTests.cs | 4 ++-- .../Dynamic/CopyTypedOperationTests.cs | 4 ++-- .../Dynamic/MoveOperationTests.cs | 4 ++-- .../Dynamic/MoveTypedOperationTests.cs | 4 ++-- .../Dynamic/NestedDTO.cs | 4 ++-- .../Dynamic/PatchDocumentTests.cs | 6 +++--- .../Dynamic/RemoveOperationTests.cs | 6 +++--- .../Dynamic/RemoveTypedOperationTests.cs | 6 +++--- .../Dynamic/ReplaceOperationTests.cs | 4 ++-- .../Dynamic/ReplaceTypedOperationTests.cs | 4 ++-- .../Dynamic/SimpleDTO.cs | 4 ++-- .../Dynamic/SimpleDTOWithNestedDTO.cs | 4 ++-- test/Microsoft.AspNetCore.JsonPatch.Test/NestedDTO.cs | 2 +- .../NestedObjectTests.cs | 4 ++-- .../ObjectAdapterTests.cs | 4 ++-- test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTO.cs | 2 +- .../SimpleDTOWithNestedDTO.cs | 2 +- .../TestErrorLogger.cs | 2 +- test/Microsoft.AspNetCore.JsonPatch.Test/project.json | 4 ++-- 46 files changed, 100 insertions(+), 100 deletions(-) diff --git a/JsonPatch.sln b/JsonPatch.sln index 01e02f3125..7149fc4551 100644 --- a/JsonPatch.sln +++ b/JsonPatch.sln @@ -1,4 +1,4 @@ - + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 VisualStudioVersion = 14.0.23107.0 @@ -7,9 +7,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{430B59ED-F96 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{36CD6341-AB44-44EB-B3AA-BF98C89FECDD}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.JsonPatch", "src\Microsoft.AspNet.JsonPatch\Microsoft.AspNet.JsonPatch.xproj", "{4D55F4D8-633B-462F-A5B1-FEB84BD2D534}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.JsonPatch", "src\Microsoft.AspNetCore.JsonPatch\Microsoft.AspNetCore.JsonPatch.xproj", "{4D55F4D8-633B-462F-A5B1-FEB84BD2D534}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.JsonPatch.Test", "test\Microsoft.AspNet.JsonPatch.Test\Microsoft.AspNet.JsonPatch.Test.xproj", "{81C20848-E063-4E12-AC40-0B55A532C16C}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.JsonPatch.Test", "test\Microsoft.AspNetCore.JsonPatch.Test\Microsoft.AspNetCore.JsonPatch.Test.xproj", "{81C20848-E063-4E12-AC40-0B55A532C16C}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/NuGetPackageVerifier.json b/NuGetPackageVerifier.json index a45e74c44d..e95640a3d3 100644 --- a/NuGetPackageVerifier.json +++ b/NuGetPackageVerifier.json @@ -9,7 +9,7 @@ "StrictSemanticVersionValidationRule" ], "packages": { - "Microsoft.AspNet.JsonPatch": { } + "Microsoft.AspNetCore.JsonPatch": { } } }, "Default": { // Rules to run for packages not listed in any other set. diff --git a/src/Microsoft.AspNetCore.JsonPatch/Adapters/IObjectAdapter.cs b/src/Microsoft.AspNetCore.JsonPatch/Adapters/IObjectAdapter.cs index 724dfe3f79..f699755ed4 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Adapters/IObjectAdapter.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Adapters/IObjectAdapter.cs @@ -1,9 +1,9 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using Microsoft.AspNet.JsonPatch.Operations; +using Microsoft.AspNetCore.JsonPatch.Operations; -namespace Microsoft.AspNet.JsonPatch.Adapters +namespace Microsoft.AspNetCore.JsonPatch.Adapters { /// /// Defines the operations that can be performed on a JSON patch document. diff --git a/src/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs b/src/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs index 4640e97039..aeae454fa9 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs @@ -5,13 +5,13 @@ using System; using System.Collections; using System.Collections.Generic; using System.Reflection; -using Microsoft.AspNet.JsonPatch.Exceptions; -using Microsoft.AspNet.JsonPatch.Helpers; -using Microsoft.AspNet.JsonPatch.Operations; +using Microsoft.AspNetCore.JsonPatch.Exceptions; +using Microsoft.AspNetCore.JsonPatch.Helpers; +using Microsoft.AspNetCore.JsonPatch.Operations; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; -namespace Microsoft.AspNet.JsonPatch.Adapters +namespace Microsoft.AspNetCore.JsonPatch.Adapters { /// public class ObjectAdapter : IObjectAdapter diff --git a/src/Microsoft.AspNetCore.JsonPatch/Converters/JsonPatchDocumentConverter.cs b/src/Microsoft.AspNetCore.JsonPatch/Converters/JsonPatchDocumentConverter.cs index 4551f64043..e93e84e12a 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Converters/JsonPatchDocumentConverter.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Converters/JsonPatchDocumentConverter.cs @@ -1,15 +1,15 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (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.AspNet.JsonPatch.Exceptions; -using Microsoft.AspNet.JsonPatch.Operations; +using Microsoft.AspNetCore.JsonPatch.Exceptions; +using Microsoft.AspNetCore.JsonPatch.Operations; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Newtonsoft.Json.Serialization; -namespace Microsoft.AspNet.JsonPatch.Converters +namespace Microsoft.AspNetCore.JsonPatch.Converters { public class JsonPatchDocumentConverter : JsonConverter { diff --git a/src/Microsoft.AspNetCore.JsonPatch/Converters/TypedJsonPatchDocumentConverter.cs b/src/Microsoft.AspNetCore.JsonPatch/Converters/TypedJsonPatchDocumentConverter.cs index 7b6bb77e17..a150bd0478 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Converters/TypedJsonPatchDocumentConverter.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Converters/TypedJsonPatchDocumentConverter.cs @@ -4,13 +4,13 @@ using System; using System.Collections.Generic; using System.Reflection; -using Microsoft.AspNet.JsonPatch.Exceptions; -using Microsoft.AspNet.JsonPatch.Operations; +using Microsoft.AspNetCore.JsonPatch.Exceptions; +using Microsoft.AspNetCore.JsonPatch.Operations; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Newtonsoft.Json.Serialization; -namespace Microsoft.AspNet.JsonPatch.Converters +namespace Microsoft.AspNetCore.JsonPatch.Converters { public class TypedJsonPatchDocumentConverter : JsonPatchDocumentConverter { diff --git a/src/Microsoft.AspNetCore.JsonPatch/Exceptions/JsonPatchException.cs b/src/Microsoft.AspNetCore.JsonPatch/Exceptions/JsonPatchException.cs index ac5222a2bb..90e080575a 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Exceptions/JsonPatchException.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Exceptions/JsonPatchException.cs @@ -2,9 +2,9 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using Microsoft.AspNet.JsonPatch.Operations; +using Microsoft.AspNetCore.JsonPatch.Operations; -namespace Microsoft.AspNet.JsonPatch.Exceptions +namespace Microsoft.AspNetCore.JsonPatch.Exceptions { public class JsonPatchException : Exception { diff --git a/src/Microsoft.AspNetCore.JsonPatch/Helpers/ActualPropertyPathResult.cs b/src/Microsoft.AspNetCore.JsonPatch/Helpers/ActualPropertyPathResult.cs index d22d1bf830..1967bf6d90 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Helpers/ActualPropertyPathResult.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Helpers/ActualPropertyPathResult.cs @@ -1,7 +1,7 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (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.AspNet.JsonPatch.Helpers +namespace Microsoft.AspNetCore.JsonPatch.Helpers { internal class ActualPropertyPathResult { diff --git a/src/Microsoft.AspNetCore.JsonPatch/Helpers/ConversionResult.cs b/src/Microsoft.AspNetCore.JsonPatch/Helpers/ConversionResult.cs index aba4913f2d..00a7513d44 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Helpers/ConversionResult.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Helpers/ConversionResult.cs @@ -1,7 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -namespace Microsoft.AspNet.JsonPatch.Helpers +namespace Microsoft.AspNetCore.JsonPatch.Helpers { internal class ConversionResult { diff --git a/src/Microsoft.AspNetCore.JsonPatch/Helpers/ExpandoObjectDictionaryExtensions.cs b/src/Microsoft.AspNetCore.JsonPatch/Helpers/ExpandoObjectDictionaryExtensions.cs index a5911dded2..aa9fa2158b 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Helpers/ExpandoObjectDictionaryExtensions.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Helpers/ExpandoObjectDictionaryExtensions.cs @@ -1,10 +1,10 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (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.AspNet.JsonPatch.Helpers +namespace Microsoft.AspNetCore.JsonPatch.Helpers { // Helper methods to allow case-insensitive key search internal static class ExpandoObjectDictionaryExtensions diff --git a/src/Microsoft.AspNetCore.JsonPatch/Helpers/ExpressionHelpers.cs b/src/Microsoft.AspNetCore.JsonPatch/Helpers/ExpressionHelpers.cs index 6a0279876c..92880eb0e1 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Helpers/ExpressionHelpers.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Helpers/ExpressionHelpers.cs @@ -5,7 +5,7 @@ using System; using System.Globalization; using System.Linq.Expressions; -namespace Microsoft.AspNet.JsonPatch.Helpers +namespace Microsoft.AspNetCore.JsonPatch.Helpers { internal static class ExpressionHelpers { diff --git a/src/Microsoft.AspNetCore.JsonPatch/Helpers/GetValueResult.cs b/src/Microsoft.AspNetCore.JsonPatch/Helpers/GetValueResult.cs index 89b7c93520..e2e739a027 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Helpers/GetValueResult.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Helpers/GetValueResult.cs @@ -1,7 +1,7 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (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.AspNet.JsonPatch.Helpers +namespace Microsoft.AspNetCore.JsonPatch.Helpers { /// /// Return value for the helper method used by Copy/Move. Needed to ensure we can make a different diff --git a/src/Microsoft.AspNetCore.JsonPatch/Helpers/JsonPatchProperty.cs b/src/Microsoft.AspNetCore.JsonPatch/Helpers/JsonPatchProperty.cs index 0539d230a3..041b0104ac 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Helpers/JsonPatchProperty.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Helpers/JsonPatchProperty.cs @@ -4,7 +4,7 @@ using System; using Newtonsoft.Json.Serialization; -namespace Microsoft.AspNet.JsonPatch +namespace Microsoft.AspNetCore.JsonPatch { /// /// Metadata for JsonProperty. diff --git a/src/Microsoft.AspNetCore.JsonPatch/Helpers/ObjectTreeAnalyisResult.cs b/src/Microsoft.AspNetCore.JsonPatch/Helpers/ObjectTreeAnalyisResult.cs index 91d5ee129d..4d083bd073 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Helpers/ObjectTreeAnalyisResult.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Helpers/ObjectTreeAnalyisResult.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (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; @@ -7,7 +7,7 @@ using System.Collections.Generic; using System.Linq; using Newtonsoft.Json.Serialization; -namespace Microsoft.AspNet.JsonPatch.Helpers +namespace Microsoft.AspNetCore.JsonPatch.Helpers { internal class ObjectTreeAnalysisResult { diff --git a/src/Microsoft.AspNetCore.JsonPatch/Helpers/PathHelpers.cs b/src/Microsoft.AspNetCore.JsonPatch/Helpers/PathHelpers.cs index 28683e7c98..99bb2f1536 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Helpers/PathHelpers.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Helpers/PathHelpers.cs @@ -1,9 +1,9 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (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.AspNet.JsonPatch.Exceptions; +using Microsoft.AspNetCore.JsonPatch.Exceptions; -namespace Microsoft.AspNet.JsonPatch.Helpers +namespace Microsoft.AspNetCore.JsonPatch.Helpers { internal static class PathHelpers { diff --git a/src/Microsoft.AspNetCore.JsonPatch/Helpers/RemovedPropertyTypeResult.cs b/src/Microsoft.AspNetCore.JsonPatch/Helpers/RemovedPropertyTypeResult.cs index 9f5b97a868..c548f55c6e 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Helpers/RemovedPropertyTypeResult.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Helpers/RemovedPropertyTypeResult.cs @@ -1,9 +1,9 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (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.AspNet.JsonPatch.Helpers +namespace Microsoft.AspNetCore.JsonPatch.Helpers { /// /// Return value for Remove operation. The combination tells us what to do next (if this operation diff --git a/src/Microsoft.AspNetCore.JsonPatch/IJsonPatchDocument.cs b/src/Microsoft.AspNetCore.JsonPatch/IJsonPatchDocument.cs index 18033e82f0..fc5f5bd4d1 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/IJsonPatchDocument.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/IJsonPatchDocument.cs @@ -1,11 +1,11 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using Microsoft.AspNet.JsonPatch.Operations; +using Microsoft.AspNetCore.JsonPatch.Operations; using System.Collections.Generic; using Newtonsoft.Json.Serialization; -namespace Microsoft.AspNet.JsonPatch +namespace Microsoft.AspNetCore.JsonPatch { public interface IJsonPatchDocument { diff --git a/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocument.cs b/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocument.cs index fc2e73030a..c9c34459a9 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocument.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocument.cs @@ -3,14 +3,14 @@ using System; using System.Collections.Generic; -using Microsoft.AspNet.JsonPatch.Adapters; -using Microsoft.AspNet.JsonPatch.Converters; -using Microsoft.AspNet.JsonPatch.Helpers; -using Microsoft.AspNet.JsonPatch.Operations; +using Microsoft.AspNetCore.JsonPatch.Adapters; +using Microsoft.AspNetCore.JsonPatch.Converters; +using Microsoft.AspNetCore.JsonPatch.Helpers; +using Microsoft.AspNetCore.JsonPatch.Operations; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; -namespace Microsoft.AspNet.JsonPatch +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 diff --git a/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs b/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs index 7b03f1644c..530b414060 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs @@ -4,14 +4,14 @@ using System; using System.Collections.Generic; using System.Linq.Expressions; -using Microsoft.AspNet.JsonPatch.Adapters; -using Microsoft.AspNet.JsonPatch.Converters; -using Microsoft.AspNet.JsonPatch.Helpers; -using Microsoft.AspNet.JsonPatch.Operations; +using Microsoft.AspNetCore.JsonPatch.Adapters; +using Microsoft.AspNetCore.JsonPatch.Converters; +using Microsoft.AspNetCore.JsonPatch.Helpers; +using Microsoft.AspNetCore.JsonPatch.Operations; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; -namespace Microsoft.AspNet.JsonPatch +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 diff --git a/src/Microsoft.AspNetCore.JsonPatch/JsonPatchError.cs b/src/Microsoft.AspNetCore.JsonPatch/JsonPatchError.cs index a140f0d4c1..a49af7a4e2 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/JsonPatchError.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/JsonPatchError.cs @@ -2,9 +2,9 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using Microsoft.AspNet.JsonPatch.Operations; +using Microsoft.AspNetCore.JsonPatch.Operations; -namespace Microsoft.AspNet.JsonPatch +namespace Microsoft.AspNetCore.JsonPatch { /// /// Captures error message and the related entity and the operation that caused it. diff --git a/src/Microsoft.AspNetCore.JsonPatch/Operations/Operation.cs b/src/Microsoft.AspNetCore.JsonPatch/Operations/Operation.cs index 7f056f41bf..ea81b0c668 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Operations/Operation.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Operations/Operation.cs @@ -2,10 +2,10 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using Microsoft.AspNet.JsonPatch.Adapters; +using Microsoft.AspNetCore.JsonPatch.Adapters; using Newtonsoft.Json; -namespace Microsoft.AspNet.JsonPatch.Operations +namespace Microsoft.AspNetCore.JsonPatch.Operations { public class Operation : OperationBase { diff --git a/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationBase.cs b/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationBase.cs index 17455f75e8..5f421f41c7 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationBase.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationBase.cs @@ -4,7 +4,7 @@ using System; using Newtonsoft.Json; -namespace Microsoft.AspNet.JsonPatch.Operations +namespace Microsoft.AspNetCore.JsonPatch.Operations { public class OperationBase { diff --git a/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationOfT.cs b/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationOfT.cs index 63663f70d9..c41454b7ef 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationOfT.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationOfT.cs @@ -2,9 +2,9 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using Microsoft.AspNet.JsonPatch.Adapters; +using Microsoft.AspNetCore.JsonPatch.Adapters; -namespace Microsoft.AspNet.JsonPatch.Operations +namespace Microsoft.AspNetCore.JsonPatch.Operations { public class Operation : Operation where TModel : class { diff --git a/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationType.cs b/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationType.cs index a4d006bc51..846b07019f 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationType.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationType.cs @@ -1,7 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -namespace Microsoft.AspNet.JsonPatch.Operations +namespace Microsoft.AspNetCore.JsonPatch.Operations { public enum OperationType { diff --git a/src/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs index f0ee7f2439..70f76f1fa3 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs @@ -1,5 +1,5 @@ // -namespace Microsoft.AspNet.JsonPatch +namespace Microsoft.AspNetCore.JsonPatch { using System.Globalization; using System.Reflection; @@ -8,7 +8,7 @@ namespace Microsoft.AspNet.JsonPatch internal static class Resources { private static readonly ResourceManager _resourceManager - = new ResourceManager("Microsoft.AspNet.JsonPatch.Resources", typeof(Resources).GetTypeInfo().Assembly); + = new ResourceManager("Microsoft.AspNetCore.JsonPatch.Resources", typeof(Resources).GetTypeInfo().Assembly); /// /// The type of the property at path '{0}' could not be determined. diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddOperationTests.cs index f5a3c384ef..cb5f090d0f 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddOperationTests.cs @@ -1,14 +1,14 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (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.AspNet.JsonPatch.Exceptions; +using Microsoft.AspNetCore.JsonPatch.Exceptions; using Newtonsoft.Json; using Xunit; -namespace Microsoft.AspNet.JsonPatch.Test.Dynamic +namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic { public class AddOperationTests { diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddTypedOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddTypedOperationTests.cs index 7913541514..098e97d850 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddTypedOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddTypedOperationTests.cs @@ -1,12 +1,12 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (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.AspNet.JsonPatch.Exceptions; +using Microsoft.AspNetCore.JsonPatch.Exceptions; using Newtonsoft.Json; using Xunit; -namespace Microsoft.AspNet.JsonPatch.Test.Dynamic +namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic { public class AddTypedOperationTests { diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CopyOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CopyOperationTests.cs index 3fa546faac..87f221bc15 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CopyOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CopyOperationTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (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; @@ -6,7 +6,7 @@ using System.Dynamic; using Newtonsoft.Json; using Xunit; -namespace Microsoft.AspNet.JsonPatch.Test.Dynamic +namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic { public class CopyOperationTests { diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CopyTypedOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CopyTypedOperationTests.cs index 5b015416ac..3a51556013 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CopyTypedOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CopyTypedOperationTests.cs @@ -1,11 +1,11 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (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 Xunit; -namespace Microsoft.AspNet.JsonPatch.Test.Dynamic +namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic { public class CopyTypedOperationTests { diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveOperationTests.cs index dea2b6ee32..ed367848b7 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveOperationTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (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; @@ -6,7 +6,7 @@ using System.Dynamic; using Newtonsoft.Json; using Xunit; -namespace Microsoft.AspNet.JsonPatch.Test.Dynamic +namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic { public class MoveOperationTests { diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveTypedOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveTypedOperationTests.cs index 3d356a3401..cd4124d564 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveTypedOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveTypedOperationTests.cs @@ -1,11 +1,11 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (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 Xunit; -namespace Microsoft.AspNet.JsonPatch.Test.Dynamic +namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic { public class MoveTypedOperationTests { diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/NestedDTO.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/NestedDTO.cs index 4d30cf60f2..f94ad05d97 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/NestedDTO.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/NestedDTO.cs @@ -1,7 +1,7 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (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.AspNet.JsonPatch.Test.Dynamic +namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic { public class NestedDTO { diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/PatchDocumentTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/PatchDocumentTests.cs index 8b14c3448b..e7e6f665a5 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/PatchDocumentTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/PatchDocumentTests.cs @@ -1,11 +1,11 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (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.AspNet.JsonPatch.Exceptions; +using Microsoft.AspNetCore.JsonPatch.Exceptions; using Newtonsoft.Json; using Xunit; -namespace Microsoft.AspNet.JsonPatch.Test.Dynamic +namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic { public class PatchDocumentTests { diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveOperationTests.cs index 9ecb520b38..b436bb4d23 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveOperationTests.cs @@ -1,13 +1,13 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (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 Microsoft.AspNet.JsonPatch.Exceptions; +using Microsoft.AspNetCore.JsonPatch.Exceptions; using Newtonsoft.Json; using Xunit; -namespace Microsoft.AspNet.JsonPatch.Test.Dynamic +namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic { public class RemoveOperationTests { diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveTypedOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveTypedOperationTests.cs index 802fb27e40..d716dafe9a 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveTypedOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveTypedOperationTests.cs @@ -1,12 +1,12 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (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.AspNet.JsonPatch.Exceptions; +using Microsoft.AspNetCore.JsonPatch.Exceptions; using Newtonsoft.Json; using Xunit; -namespace Microsoft.AspNet.JsonPatch.Test.Dynamic +namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic { public class RemoveTypedOperationTests { diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceOperationTests.cs index c7573c0286..8dff9b6a98 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceOperationTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (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; @@ -8,7 +8,7 @@ using System.Dynamic; using Newtonsoft.Json; using Xunit; -namespace Microsoft.AspNet.JsonPatch.Test.Dynamic +namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic { public class ReplaceOperationTests { diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceTypedOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceTypedOperationTests.cs index ccdd86f1a7..589e86e03a 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceTypedOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceTypedOperationTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (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; @@ -8,7 +8,7 @@ using System.Linq; using Newtonsoft.Json; using Xunit; -namespace Microsoft.AspNet.JsonPatch.Test.Dynamic +namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic { public class ReplaceTypedOperationTests { diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/SimpleDTO.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/SimpleDTO.cs index a6938dd992..d4bf19f75a 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/SimpleDTO.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/SimpleDTO.cs @@ -1,10 +1,10 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (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.AspNet.JsonPatch.Test.Dynamic +namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic { public class SimpleDTO { diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/SimpleDTOWithNestedDTO.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/SimpleDTOWithNestedDTO.cs index 03c74f8a1b..f8af4bb390 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/SimpleDTOWithNestedDTO.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/SimpleDTOWithNestedDTO.cs @@ -1,9 +1,9 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (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.AspNet.JsonPatch.Test.Dynamic +namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic { public class SimpleDTOWithNestedDTO { diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/NestedDTO.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/NestedDTO.cs index 6dd5ce8852..aa767557c3 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/NestedDTO.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/NestedDTO.cs @@ -1,7 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -namespace Microsoft.AspNet.JsonPatch.Test +namespace Microsoft.AspNetCore.JsonPatch.Test { public class NestedDTO { diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/NestedObjectTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/NestedObjectTests.cs index e736373ed8..6215da6bcd 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/NestedObjectTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/NestedObjectTests.cs @@ -3,11 +3,11 @@ using System.Collections.Generic; using System.Collections.ObjectModel; -using Microsoft.AspNet.JsonPatch.Exceptions; +using Microsoft.AspNetCore.JsonPatch.Exceptions; using Newtonsoft.Json; using Xunit; -namespace Microsoft.AspNet.JsonPatch.Test +namespace Microsoft.AspNetCore.JsonPatch.Test { public class NestedObjectTests { diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs index 85d9404e6d..98a72e1bf8 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs @@ -4,11 +4,11 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; -using Microsoft.AspNet.JsonPatch.Exceptions; +using Microsoft.AspNetCore.JsonPatch.Exceptions; using Newtonsoft.Json; using Xunit; -namespace Microsoft.AspNet.JsonPatch.Test +namespace Microsoft.AspNetCore.JsonPatch.Test { public class ObjectAdapterTests { diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTO.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTO.cs index b1177bc5ce..1206cd108f 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTO.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTO.cs @@ -4,7 +4,7 @@ using System; using System.Collections.Generic; -namespace Microsoft.AspNet.JsonPatch.Test +namespace Microsoft.AspNetCore.JsonPatch.Test { public class SimpleDTO { diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTOWithNestedDTO.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTOWithNestedDTO.cs index 81aa38e682..dbded242ee 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTOWithNestedDTO.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTOWithNestedDTO.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; -namespace Microsoft.AspNet.JsonPatch.Test +namespace Microsoft.AspNetCore.JsonPatch.Test { public class SimpleDTOWithNestedDTO { diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/TestErrorLogger.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/TestErrorLogger.cs index 525321cfb3..6db8a42684 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/TestErrorLogger.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/TestErrorLogger.cs @@ -1,7 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -namespace Microsoft.AspNet.JsonPatch.Test +namespace Microsoft.AspNetCore.JsonPatch.Test { public class TestErrorLogger where T : class { diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json index 8b97af645a..7699879f8f 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json @@ -3,8 +3,8 @@ "warningsAsErrors": true }, "dependencies": { - "Microsoft.AspNet.JsonPatch": "1.0.0-*", - "Microsoft.AspNet.Testing": "1.0.0-*", + "Microsoft.AspNetCore.JsonPatch": "1.0.0-*", + "Microsoft.AspNetCore.Testing": "1.0.0-*", "Newtonsoft.Json": "6.0.6", "xunit.runner.aspnet": "2.0.0-aspnet-*" }, From 8d19947ada81d6458e6ddf0a48f2cbb12492c9a1 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 28 Jan 2016 11:03:22 -0800 Subject: [PATCH 041/471] Updating to dotnet-cli build Fixes #9 --- .gitattributes | 52 ++++++++++++++ .gitignore | 15 ++-- .travis.yml | 8 ++- appveyor.yml | 2 +- build.cmd | 68 +++++++++---------- build.sh | 42 ++++++------ .../project.json | 10 +-- 7 files changed, 125 insertions(+), 72 deletions(-) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..d4ee1cb7f3 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,52 @@ +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain + +*.jpg binary +*.png binary +*.gif binary + +*.cs text=auto diff=csharp +*.vb text=auto +*.resx text=auto +*.c text=auto +*.cpp text=auto +*.cxx text=auto +*.h text=auto +*.hxx text=auto +*.py text=auto +*.rb text=auto +*.java text=auto +*.html text=auto +*.htm text=auto +*.css text=auto +*.scss text=auto +*.sass text=auto +*.less text=auto +*.js text=auto +*.lisp text=auto +*.clj text=auto +*.sql text=auto +*.php text=auto +*.lua text=auto +*.m text=auto +*.asm text=auto +*.erl text=auto +*.fs text=auto +*.fsx text=auto +*.hs text=auto + +*.csproj text=auto +*.vbproj text=auto +*.fsproj text=auto +*.dbproj text=auto +*.sln text=auto eol=crlf + +*.sh eol=lf diff --git a/.gitignore b/.gitignore index 8a9bbc3a43..2e4b2d6b5d 100644 --- a/.gitignore +++ b/.gitignore @@ -2,23 +2,21 @@ [Bb]in/ TestResults/ .nuget/ +.build/ +.testPublish/ *.sln.ide/ _ReSharper.*/ packages/ artifacts/ +.build/ PublishProfiles/ -.vs/ -bower_components/ -node_modules/ -**/wwwroot/lib/ -debugSettings.json -project.lock.json *.user *.suo *.cache *.docstates _ReSharper.* nuget.exe +project.lock.json *net45.csproj *net451.csproj *k10.csproj @@ -30,7 +28,4 @@ nuget.exe *.ncrunchsolution *.*sdf *.ipch -.settings -*.sln.ide -node_modules -**/[Cc]ompiler/[Rr]esources/**/*.js +.build/ \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index c0befaffcf..e8f77f0f14 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,9 +10,11 @@ addons: - libssl-dev - libunwind8 - zlib1g -env: - - KOREBUILD_DNU_RESTORE_CORECLR=true KOREBUILD_TEST_DNXCORE=true mono: - 4.0.5 +os: + - linux + - osx +osx_image: xcode7.1 script: - - ./build.sh --quiet verify + - ./build.sh --quiet verify \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml index 58a3e1bc22..636a7618d3 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,7 +1,7 @@ init: - git config --global core.autocrlf true build_script: - - build.cmd --quiet --parallel verify + - build.cmd --quiet verify clone_depth: 1 test: off deploy: off \ No newline at end of file diff --git a/build.cmd b/build.cmd index 553e3929a0..65fb3e3353 100644 --- a/build.cmd +++ b/build.cmd @@ -1,40 +1,40 @@ -@echo off -cd %~dp0 - +@ECHO off SETLOCAL + +SET REPO_FOLDER=%~dp0 +CD "%REPO_FOLDER%" + +SET BUILD_FOLDER=.build +SET KOREBUILD_FOLDER=%BUILD_FOLDER%\KoreBuild-dotnet +SET KOREBUILD_VERSION= + +SET NUGET_PATH=%BUILD_FOLDER%\NuGet.exe SET NUGET_VERSION=latest SET CACHED_NUGET=%LocalAppData%\NuGet\nuget.%NUGET_VERSION%.exe -SET BUILDCMD_KOREBUILD_VERSION= -SET BUILDCMD_DNX_VERSION= -IF EXIST %CACHED_NUGET% goto copynuget -echo Downloading latest version of NuGet.exe... -IF NOT EXIST %LocalAppData%\NuGet md %LocalAppData%\NuGet -@powershell -NoProfile -ExecutionPolicy unrestricted -Command "$ProgressPreference = 'SilentlyContinue'; Invoke-WebRequest 'https://dist.nuget.org/win-x86-commandline/%NUGET_VERSION%/nuget.exe' -OutFile '%CACHED_NUGET%'" - -:copynuget -IF EXIST .nuget\nuget.exe goto restore -md .nuget -copy %CACHED_NUGET% .nuget\nuget.exe > nul - -:restore -IF EXIST packages\Sake goto getdnx -IF "%BUILDCMD_KOREBUILD_VERSION%"=="" ( - .nuget\nuget.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre -) ELSE ( - .nuget\nuget.exe install KoreBuild -version %BUILDCMD_KOREBUILD_VERSION% -ExcludeVersion -o packages -nocache -pre -) -.nuget\NuGet.exe install Sake -ExcludeVersion -Source https://www.nuget.org/api/v2/ -Out packages - -:getdnx -IF "%BUILDCMD_DNX_VERSION%"=="" ( - SET BUILDCMD_DNX_VERSION=latest -) -IF "%SKIP_DNX_INSTALL%"=="" ( - CALL packages\KoreBuild\build\dnvm install %BUILDCMD_DNX_VERSION% -runtime CoreCLR -arch x86 -alias default - CALL packages\KoreBuild\build\dnvm install default -runtime CLR -arch x86 -alias default -) ELSE ( - CALL packages\KoreBuild\build\dnvm use default -runtime CLR -arch x86 +IF NOT EXIST %BUILD_FOLDER% ( + md %BUILD_FOLDER% ) -packages\Sake\tools\Sake.exe -I packages\KoreBuild\build -f makefile.shade %* +IF NOT EXIST %NUGET_PATH% ( + IF NOT EXIST %CACHED_NUGET% ( + echo Downloading latest version of NuGet.exe... + IF NOT EXIST %LocalAppData%\NuGet ( + md %LocalAppData%\NuGet + ) + @powershell -NoProfile -ExecutionPolicy unrestricted -Command "$ProgressPreference = 'SilentlyContinue'; Invoke-WebRequest 'https://dist.nuget.org/win-x86-commandline/%NUGET_VERSION%/nuget.exe' -OutFile '%CACHED_NUGET%'" + ) + + copy %CACHED_NUGET% %NUGET_PATH% > nul +) + +IF NOT EXIST %KOREBUILD_FOLDER% ( + SET KOREBUILD_DOWNLOAD_ARGS= + IF NOT "%KOREBUILD_VERSION%"=="" ( + SET KOREBUILD_DOWNLOAD_ARGS=-version %KOREBUILD_VERSION% + ) + + %BUILD_FOLDER%\nuget.exe install KoreBuild-dotnet -ExcludeVersion -o %BUILD_FOLDER% -nocache -pre %KOREBUILD_DOWNLOAD_ARGS% +) + +"%KOREBUILD_FOLDER%\build\KoreBuild.cmd" %* diff --git a/build.sh b/build.sh index da4e3fcd1c..263fb667a8 100755 --- a/build.sh +++ b/build.sh @@ -1,5 +1,10 @@ #!/usr/bin/env bash +buildFolder=.build +koreBuildFolder=$buildFolder/KoreBuild-dotnet + +nugetPath=$buildFolder/nuget.exe + if test `uname` = Darwin; then cachedir=~/Library/Caches/KBuild else @@ -11,33 +16,30 @@ else fi mkdir -p $cachedir nugetVersion=latest -cachePath=$cachedir/nuget.$nugetVersion.exe +cacheNuget=$cachedir/nuget.$nugetVersion.exe -url=https://dist.nuget.org/win-x86-commandline/$nugetVersion/nuget.exe +nugetUrl=https://dist.nuget.org/win-x86-commandline/$nugetVersion/nuget.exe -if test ! -f $cachePath; then - wget -O $cachePath $url 2>/dev/null || curl -o $cachePath --location $url /dev/null +if test ! -d $buildFolder; then + mkdir $buildFolder fi -if test ! -e .nuget; then - mkdir .nuget - cp $cachePath .nuget/nuget.exe +if test ! -f $nugetPath; then + if test ! -f $cacheNuget; then + wget -O $cacheNuget $nugetUrl 2>/dev/null || curl -o $cacheNuget --location $nugetUrl /dev/null + fi + + cp $cacheNuget $nugetPath fi -if test ! -d packages/Sake; then - mono .nuget/nuget.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre - mono .nuget/nuget.exe install Sake -ExcludeVersion -Source https://www.nuget.org/api/v2/ -Out packages +if test ! -d $koreBuildFolder; then + mono $nugetPath install KoreBuild-dotnet -ExcludeVersion -o $buildFolder -nocache -pre + chmod +x $koreBuildFolder/build/KoreBuild.sh fi -if ! type dnvm > /dev/null 2>&1; then - source packages/KoreBuild/build/dnvm.sh +makeFile=makefile.shade +if [ ! -e $makeFile ]; then + makeFile=$koreBuildFolder/build/makefile.shade fi -if ! type dnx > /dev/null 2>&1 || [ -z "$SKIP_DNX_INSTALL" ]; then - dnvm install latest -runtime coreclr -alias default - dnvm install default -runtime mono -alias default -else - dnvm use default -runtime mono -fi - -mono packages/Sake/tools/Sake.exe -I packages/KoreBuild/build -f makefile.shade "$@" +./$koreBuildFolder/build/KoreBuild.sh -n $nugetPath -m $makeFile "$@" diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json index 7699879f8f..963a3eff63 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json @@ -5,21 +5,23 @@ "dependencies": { "Microsoft.AspNetCore.JsonPatch": "1.0.0-*", "Microsoft.AspNetCore.Testing": "1.0.0-*", - "Newtonsoft.Json": "6.0.6", - "xunit.runner.aspnet": "2.0.0-aspnet-*" + "xunit": "2.1.0" }, "commands": { "test": "xunit.runner.aspnet" }, + "testRunner": "xunit", "frameworks": { "dnx451": { "dependencies": { - "Moq": "4.2.1312.1622" + "Moq": "4.2.1312.1622", + "xunit.runner.console": "2.1.0" } }, "dnxcore50": { "dependencies": { - "moq.netcore": "4.4.0-beta8" + "moq.netcore": "4.4.0-beta8", + "xunit.runner.aspnet": "2.0.0-aspnet-*" } } } From 690c42c199e20ed8f7388a497e8672477a4b8594 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 28 Jan 2016 11:12:36 -0800 Subject: [PATCH 042/471] Add dependency on System.Runtime.Serialization.Primitives to make up for JSON.NET not including it Fixes https://github.com/aspnet/Mvc/issues/3946 --- src/Microsoft.AspNetCore.JsonPatch/project.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Microsoft.AspNetCore.JsonPatch/project.json b/src/Microsoft.AspNetCore.JsonPatch/project.json index 4d1206eefb..e654aecf23 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/project.json +++ b/src/Microsoft.AspNetCore.JsonPatch/project.json @@ -22,6 +22,7 @@ "System.Reflection.Extensions": "4.0.1-*", "System.Resources.ResourceManager": "4.0.1-*", "System.Runtime.Extensions": "4.1.0-*", + "System.Runtime.Serialization.Primitives": "4.1.0-*", "System.Text.Encoding.Extensions": "4.0.11-*" } } From 20ed43fd686f86c9be96d7f456864cdc6fa80762 Mon Sep 17 00:00:00 2001 From: John Luo Date: Mon, 1 Feb 2016 14:48:27 -0800 Subject: [PATCH 043/471] Updating to new CLI --- src/Microsoft.AspNetCore.JsonPatch/project.json | 7 +++++-- test/Microsoft.AspNetCore.JsonPatch.Test/project.json | 6 ++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.AspNetCore.JsonPatch/project.json b/src/Microsoft.AspNetCore.JsonPatch/project.json index e654aecf23..2a3d61af5e 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/project.json +++ b/src/Microsoft.AspNetCore.JsonPatch/project.json @@ -9,7 +9,8 @@ "url": "git://github.com/aspnet/mvc" }, "dependencies": { - "Newtonsoft.Json": "8.0.2" + "Newtonsoft.Json": "8.0.2", + "Microsoft.NETCore.Platforms": "1.0.1-*" }, "frameworks": { "net451": {}, @@ -21,10 +22,12 @@ "System.Globalization": "4.0.11-*", "System.Reflection.Extensions": "4.0.1-*", "System.Resources.ResourceManager": "4.0.1-*", + "System.Runtime": "4.0.21-*", "System.Runtime.Extensions": "4.1.0-*", "System.Runtime.Serialization.Primitives": "4.1.0-*", "System.Text.Encoding.Extensions": "4.0.11-*" - } + }, + "imports": "portable-net451+win8" } } } diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json index 963a3eff63..ff30cfb346 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json @@ -5,7 +5,8 @@ "dependencies": { "Microsoft.AspNetCore.JsonPatch": "1.0.0-*", "Microsoft.AspNetCore.Testing": "1.0.0-*", - "xunit": "2.1.0" + "xunit": "2.1.0", + "Microsoft.NETCore.Platforms": "1.0.1-*" }, "commands": { "test": "xunit.runner.aspnet" @@ -22,7 +23,8 @@ "dependencies": { "moq.netcore": "4.4.0-beta8", "xunit.runner.aspnet": "2.0.0-aspnet-*" - } + }, + "imports": "portable-net451+win8" } } } \ No newline at end of file From 33629c5fc07604227d251e5ddcae55f49ae14219 Mon Sep 17 00:00:00 2001 From: John Luo Date: Mon, 1 Feb 2016 17:04:37 -0800 Subject: [PATCH 044/471] Updating to new CLI --- src/Microsoft.AspNetCore.Html.Abstractions/project.json | 6 ++++-- src/Microsoft.Extensions.WebEncoders/project.json | 5 ++++- .../project.json | 3 ++- test/Microsoft.Extensions.WebEncoders.Tests/project.json | 3 ++- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/project.json b/src/Microsoft.AspNetCore.Html.Abstractions/project.json index 55cc30d9b1..03334e45aa 100644 --- a/src/Microsoft.AspNetCore.Html.Abstractions/project.json +++ b/src/Microsoft.AspNetCore.Html.Abstractions/project.json @@ -10,7 +10,8 @@ "keyFile": "../../tools/Key.snk" }, "dependencies": { - "System.Text.Encodings.Web": "4.0.0-*" + "System.Text.Encodings.Web": "4.0.0-*", + "Microsoft.NETCore.Platforms": "1.0.1-*" }, "frameworks": { "net451": { @@ -23,7 +24,8 @@ "dependencies": { "System.Collections": "4.0.11-*", "System.Resources.ResourceManager": "4.0.1-*" - } + }, + "imports": "portable-net451+win8" } } } diff --git a/src/Microsoft.Extensions.WebEncoders/project.json b/src/Microsoft.Extensions.WebEncoders/project.json index 0facfeeb8c..f56cd3d4b6 100644 --- a/src/Microsoft.Extensions.WebEncoders/project.json +++ b/src/Microsoft.Extensions.WebEncoders/project.json @@ -13,6 +13,7 @@ "dependencies": { "Microsoft.Extensions.DependencyInjection.Abstractions": "1.0.0-*", "Microsoft.Extensions.Options": "1.0.0-*", + "Microsoft.NETCore.Platforms": "1.0.1-*", "System.Text.Encodings.Web": "4.0.0-*" }, "frameworks": { @@ -22,6 +23,8 @@ "System.Runtime": "" } }, - "dotnet5.4": {} + "dotnet5.4": { + "imports": "portable-net451+win8" + } } } diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json index d796493c0a..7e104bae8d 100644 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json @@ -23,7 +23,8 @@ "dependencies": { "System.Runtime": "4.0.21-*", "xunit.runner.aspnet": "2.0.0-aspnet-*" - } + }, + "imports": "portable-net451+win8" } } } diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/project.json b/test/Microsoft.Extensions.WebEncoders.Tests/project.json index c588c7a29e..ebfb18cf96 100644 --- a/test/Microsoft.Extensions.WebEncoders.Tests/project.json +++ b/test/Microsoft.Extensions.WebEncoders.Tests/project.json @@ -22,7 +22,8 @@ "dnxcore50": { "dependencies": { "xunit.runner.aspnet": "2.0.0-aspnet-*" - } + }, + "imports": "portable-net451+win8" } } } From 82e17ce2b69a6bfdcdb631a93b6066a6c74ad47c Mon Sep 17 00:00:00 2001 From: John Luo Date: Mon, 1 Feb 2016 17:58:41 -0800 Subject: [PATCH 045/471] Removing redundant dependencies --- src/Microsoft.AspNetCore.JsonPatch/project.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Microsoft.AspNetCore.JsonPatch/project.json b/src/Microsoft.AspNetCore.JsonPatch/project.json index 2a3d61af5e..072386b843 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/project.json +++ b/src/Microsoft.AspNetCore.JsonPatch/project.json @@ -9,8 +9,7 @@ "url": "git://github.com/aspnet/mvc" }, "dependencies": { - "Newtonsoft.Json": "8.0.2", - "Microsoft.NETCore.Platforms": "1.0.1-*" + "Newtonsoft.Json": "8.0.2" }, "frameworks": { "net451": {}, From 2fd1490c4acb6017e0811bad655e601782575d57 Mon Sep 17 00:00:00 2001 From: John Luo Date: Mon, 1 Feb 2016 18:33:21 -0800 Subject: [PATCH 046/471] Relocating dependencies --- src/Microsoft.AspNetCore.Html.Abstractions/project.json | 6 ++---- src/Microsoft.Extensions.WebEncoders/project.json | 5 +---- .../project.json | 1 + test/Microsoft.Extensions.WebEncoders.Tests/project.json | 1 + 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/project.json b/src/Microsoft.AspNetCore.Html.Abstractions/project.json index 03334e45aa..55cc30d9b1 100644 --- a/src/Microsoft.AspNetCore.Html.Abstractions/project.json +++ b/src/Microsoft.AspNetCore.Html.Abstractions/project.json @@ -10,8 +10,7 @@ "keyFile": "../../tools/Key.snk" }, "dependencies": { - "System.Text.Encodings.Web": "4.0.0-*", - "Microsoft.NETCore.Platforms": "1.0.1-*" + "System.Text.Encodings.Web": "4.0.0-*" }, "frameworks": { "net451": { @@ -24,8 +23,7 @@ "dependencies": { "System.Collections": "4.0.11-*", "System.Resources.ResourceManager": "4.0.1-*" - }, - "imports": "portable-net451+win8" + } } } } diff --git a/src/Microsoft.Extensions.WebEncoders/project.json b/src/Microsoft.Extensions.WebEncoders/project.json index f56cd3d4b6..0facfeeb8c 100644 --- a/src/Microsoft.Extensions.WebEncoders/project.json +++ b/src/Microsoft.Extensions.WebEncoders/project.json @@ -13,7 +13,6 @@ "dependencies": { "Microsoft.Extensions.DependencyInjection.Abstractions": "1.0.0-*", "Microsoft.Extensions.Options": "1.0.0-*", - "Microsoft.NETCore.Platforms": "1.0.1-*", "System.Text.Encodings.Web": "4.0.0-*" }, "frameworks": { @@ -23,8 +22,6 @@ "System.Runtime": "" } }, - "dotnet5.4": { - "imports": "portable-net451+win8" - } + "dotnet5.4": {} } } diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json index 7e104bae8d..2d2e1345d4 100644 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json @@ -7,6 +7,7 @@ "Microsoft.AspNetCore.Html.Abstractions": "1.0.0-*", "Microsoft.AspNetCore.Testing": "1.0.0-*", "Microsoft.Extensions.WebEncoders": "1.0.0-*", + "Microsoft.NETCore.Platforms": "1.0.1-*", "xunit": "2.1.0" }, "testRunner": "xunit", diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/project.json b/test/Microsoft.Extensions.WebEncoders.Tests/project.json index ebfb18cf96..62a6a59ec0 100644 --- a/test/Microsoft.Extensions.WebEncoders.Tests/project.json +++ b/test/Microsoft.Extensions.WebEncoders.Tests/project.json @@ -2,6 +2,7 @@ "dependencies": { "Microsoft.Extensions.DependencyInjection": "1.0.0-*", "Microsoft.Extensions.WebEncoders": "1.0.0-*", + "Microsoft.NETCore.Platforms": "1.0.1-*", "xunit.runner.aspnet": "2.0.0-aspnet-*" }, "testRunner": "xunit", From 9959601c4b07bd5e170975b900293bd3beb13e2a Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Fri, 5 Feb 2016 17:20:53 -0800 Subject: [PATCH 047/471] Update project.json to remove redundant System.Runtime dependency. - This package is pulled in transitively. --- test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json | 1 - 1 file changed, 1 deletion(-) diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json index 2d2e1345d4..f27a4cd094 100644 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json @@ -22,7 +22,6 @@ }, "dnxcore50": { "dependencies": { - "System.Runtime": "4.0.21-*", "xunit.runner.aspnet": "2.0.0-aspnet-*" }, "imports": "portable-net451+win8" From e0fbc6e2c218849a04e16e1792ae472d31952f4c Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Fri, 5 Feb 2016 17:22:05 -0800 Subject: [PATCH 048/471] Update project.json to remove redundant System.Runtime dependency. - This package is pulled in transitively. --- src/Microsoft.AspNetCore.JsonPatch/project.json | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Microsoft.AspNetCore.JsonPatch/project.json b/src/Microsoft.AspNetCore.JsonPatch/project.json index 072386b843..bae136cbbc 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/project.json +++ b/src/Microsoft.AspNetCore.JsonPatch/project.json @@ -21,7 +21,6 @@ "System.Globalization": "4.0.11-*", "System.Reflection.Extensions": "4.0.1-*", "System.Resources.ResourceManager": "4.0.1-*", - "System.Runtime": "4.0.21-*", "System.Runtime.Extensions": "4.1.0-*", "System.Runtime.Serialization.Primitives": "4.1.0-*", "System.Text.Encoding.Extensions": "4.0.11-*" From 76c20aa01032064f8c7a4e6baa92007b1302bf0a Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 8 Feb 2016 09:33:46 -0800 Subject: [PATCH 049/471] Reacting to CoreCLR package version changes --- src/Microsoft.AspNetCore.JsonPatch/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.AspNetCore.JsonPatch/project.json b/src/Microsoft.AspNetCore.JsonPatch/project.json index bae136cbbc..ec303724f5 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/project.json +++ b/src/Microsoft.AspNetCore.JsonPatch/project.json @@ -16,7 +16,7 @@ "dotnet5.4": { "dependencies": { "Microsoft.CSharp": "4.0.1-*", - "System.Collections.Concurrent": "4.0.11-*", + "System.Collections.Concurrent": "4.0.12-*", "System.ComponentModel.TypeConverter": "4.0.1-*", "System.Globalization": "4.0.11-*", "System.Reflection.Extensions": "4.0.1-*", From 3fa76b26c89190d818974b6112b914dd8aae2477 Mon Sep 17 00:00:00 2001 From: Kiran Challa Date: Tue, 9 Feb 2016 22:23:47 -0800 Subject: [PATCH 050/471] Enable tests to run using dotnet xunit runner --- .../project.json | 15 ++++++--------- .../project.json | 17 +++++++---------- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json index f27a4cd094..ff91514fd4 100644 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json @@ -11,20 +11,17 @@ "xunit": "2.1.0" }, "testRunner": "xunit", - "commands": { - "test": "xunit.runner.aspnet" - }, "frameworks": { - "dnx451": { - "dependencies": { - "xunit.runner.console": "2.1.0" - } - }, "dnxcore50": { "dependencies": { - "xunit.runner.aspnet": "2.0.0-aspnet-*" + "dotnet-test-xunit": "1.0.0-dev-*" }, "imports": "portable-net451+win8" + }, + "dnx451": { + "dependencies": { + "xunit.runner.console": "2.1.0" } } } +} \ No newline at end of file diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/project.json b/test/Microsoft.Extensions.WebEncoders.Tests/project.json index 62a6a59ec0..bcd52ff6ee 100644 --- a/test/Microsoft.Extensions.WebEncoders.Tests/project.json +++ b/test/Microsoft.Extensions.WebEncoders.Tests/project.json @@ -6,25 +6,22 @@ "xunit.runner.aspnet": "2.0.0-aspnet-*" }, "testRunner": "xunit", - "commands": { - "test": "xunit.runner.aspnet" - }, "compilationOptions": { "allowUnsafe": true, "warningsAsErrors": true, "keyFile": "../../tools/Key.snk" }, "frameworks": { + "dnxcore50": { + "dependencies": { + "dotnet-test-xunit": "1.0.0-dev-*" + }, + "imports": "portable-net451+win8" + }, "dnx451": { "dependencies": { "xunit.runner.console": "2.1.0" } - }, - "dnxcore50": { - "dependencies": { - "xunit.runner.aspnet": "2.0.0-aspnet-*" - }, - "imports": "portable-net451+win8" } } -} +} \ No newline at end of file From de419e26ce4eadcd0073ae4d74d66d11f2885a25 Mon Sep 17 00:00:00 2001 From: Kiran Challa Date: Tue, 9 Feb 2016 22:27:25 -0800 Subject: [PATCH 051/471] Enable tests to run using dotnet xunit runner --- .../project.json | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json index ff30cfb346..07a2b3511c 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json @@ -8,23 +8,20 @@ "xunit": "2.1.0", "Microsoft.NETCore.Platforms": "1.0.1-*" }, - "commands": { - "test": "xunit.runner.aspnet" - }, "testRunner": "xunit", "frameworks": { + "dnxcore50": { + "dependencies": { + "moq.netcore": "4.4.0-beta8", + "dotnet-test-xunit": "1.0.0-dev-*" + }, + "imports": "portable-net451+win8" + }, "dnx451": { "dependencies": { "Moq": "4.2.1312.1622", "xunit.runner.console": "2.1.0" } - }, - "dnxcore50": { - "dependencies": { - "moq.netcore": "4.4.0-beta8", - "xunit.runner.aspnet": "2.0.0-aspnet-*" - }, - "imports": "portable-net451+win8" } } } \ No newline at end of file From 2bbb7a69e9ba3b98c53d2a8c70b38b43599a7309 Mon Sep 17 00:00:00 2001 From: Brennan Date: Thu, 11 Feb 2016 09:45:54 -0800 Subject: [PATCH 052/471] Update dependencies --- test/Microsoft.AspNetCore.JsonPatch.Test/project.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json index 07a2b3511c..cb87b096e9 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json @@ -18,6 +18,10 @@ "imports": "portable-net451+win8" }, "dnx451": { + "frameworkAssemblies": { + "System.Runtime": "", + "System.Threading.Tasks": "" + }, "dependencies": { "Moq": "4.2.1312.1622", "xunit.runner.console": "2.1.0" From f1e696d865a5b7478b1fe9f6604276fcdfa40f01 Mon Sep 17 00:00:00 2001 From: Ajay Bhargav Baaskaran Date: Thu, 18 Feb 2016 12:39:01 -0800 Subject: [PATCH 053/471] Enabled xml doc generation --- NuGetPackageVerifier.json | 14 ++------------ .../project.json | 4 +++- src/Microsoft.Extensions.WebEncoders/project.json | 4 +++- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/NuGetPackageVerifier.json b/NuGetPackageVerifier.json index d9dea7c8ac..8df495e3e0 100644 --- a/NuGetPackageVerifier.json +++ b/NuGetPackageVerifier.json @@ -1,12 +1,7 @@ { "adx": { // Packages written by the ADX team and that ship on NuGet.org "rules": [ - "AssemblyHasDocumentFileRule", - "AssemblyHasVersionAttributesRule", - "AssemblyHasServicingAttributeRule", - "AssemblyHasNeutralResourcesLanguageAttributeRule", - "SatellitePackageRule", - "StrictSemanticVersionValidationRule" + "AdxVerificationCompositeRule" ], "packages": { "Microsoft.AspNetCore.Html.Abstractions": { }, @@ -15,12 +10,7 @@ }, "Default": { // Rules to run for packages not listed in any other set. "rules": [ - "AssemblyHasDocumentFileRule", - "AssemblyHasVersionAttributesRule", - "AssemblyHasServicingAttributeRule", - "AssemblyHasNeutralResourcesLanguageAttributeRule", - "SatellitePackageRule", - "StrictSemanticVersionValidationRule" + "DefaultCompositeRule" ] } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/project.json b/src/Microsoft.AspNetCore.Html.Abstractions/project.json index 55cc30d9b1..7b5fcb40a1 100644 --- a/src/Microsoft.AspNetCore.Html.Abstractions/project.json +++ b/src/Microsoft.AspNetCore.Html.Abstractions/project.json @@ -7,7 +7,9 @@ }, "compilationOptions": { "warningsAsErrors": true, - "keyFile": "../../tools/Key.snk" + "keyFile": "../../tools/Key.snk", + "nowarn": [ "CS1591" ], + "xmlDoc": true }, "dependencies": { "System.Text.Encodings.Web": "4.0.0-*" diff --git a/src/Microsoft.Extensions.WebEncoders/project.json b/src/Microsoft.Extensions.WebEncoders/project.json index 0facfeeb8c..a777ff4d9b 100644 --- a/src/Microsoft.Extensions.WebEncoders/project.json +++ b/src/Microsoft.Extensions.WebEncoders/project.json @@ -8,7 +8,9 @@ "compilationOptions": { "warningsAsErrors": true, "allowUnsafe": true, - "keyFile": "../../tools/Key.snk" + "keyFile": "../../tools/Key.snk", + "nowarn": [ "CS1591" ], + "xmlDoc": true }, "dependencies": { "Microsoft.Extensions.DependencyInjection.Abstractions": "1.0.0-*", From 4e5e6b3891bd9e6ff22e2cd5a0e435cfad961c57 Mon Sep 17 00:00:00 2001 From: John Luo Date: Thu, 18 Feb 2016 14:46:26 -0800 Subject: [PATCH 054/471] Updating test TFMs for custom test discovery --- test/Microsoft.AspNetCore.JsonPatch.Test/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json index cb87b096e9..cd04e92bb2 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json @@ -17,7 +17,7 @@ }, "imports": "portable-net451+win8" }, - "dnx451": { + "net451": { "frameworkAssemblies": { "System.Runtime": "", "System.Threading.Tasks": "" From 42d913b3ba8a7e82867f1cd4749277338071bca7 Mon Sep 17 00:00:00 2001 From: Ajay Bhargav Baaskaran Date: Thu, 18 Feb 2016 16:20:51 -0800 Subject: [PATCH 055/471] Enabled xml doc generation --- NuGetPackageVerifier.json | 14 ++------------ src/Microsoft.AspNetCore.JsonPatch/project.json | 4 +++- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/NuGetPackageVerifier.json b/NuGetPackageVerifier.json index e95640a3d3..f68002830f 100644 --- a/NuGetPackageVerifier.json +++ b/NuGetPackageVerifier.json @@ -1,12 +1,7 @@ { "adx": { // Packages written by the ADX team and that ship on NuGet.org "rules": [ - "AssemblyHasDocumentFileRule", - "AssemblyHasVersionAttributesRule", - "AssemblyHasServicingAttributeRule", - "AssemblyHasNeutralResourcesLanguageAttributeRule", - "SatellitePackageRule", - "StrictSemanticVersionValidationRule" + "AdxVerificationCompositeRule" ], "packages": { "Microsoft.AspNetCore.JsonPatch": { } @@ -14,12 +9,7 @@ }, "Default": { // Rules to run for packages not listed in any other set. "rules": [ - "AssemblyHasDocumentFileRule", - "AssemblyHasVersionAttributesRule", - "AssemblyHasServicingAttributeRule", - "AssemblyHasNeutralResourcesLanguageAttributeRule", - "SatellitePackageRule", - "StrictSemanticVersionValidationRule" + "DefaultCompositeRule" ] } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.JsonPatch/project.json b/src/Microsoft.AspNetCore.JsonPatch/project.json index ec303724f5..91adf85b87 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/project.json +++ b/src/Microsoft.AspNetCore.JsonPatch/project.json @@ -2,7 +2,9 @@ "version": "1.0.0-*", "compilationOptions": { "warningsAsErrors": true, - "keyFile": "../../tools/Key.snk" + "keyFile": "../../tools/Key.snk", + "nowarn": [ "CS1591" ], + "xmlDoc": true }, "repository": { "type": "git", From 397cda382b24fc1f3ded028dd368a6f091618ed2 Mon Sep 17 00:00:00 2001 From: John Luo Date: Thu, 18 Feb 2016 17:08:28 -0800 Subject: [PATCH 056/471] Updating test TFMs for custom test discovery --- test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json | 4 ++-- test/Microsoft.Extensions.WebEncoders.Tests/project.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json index ff91514fd4..35c576a3c2 100644 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json @@ -18,10 +18,10 @@ }, "imports": "portable-net451+win8" }, - "dnx451": { + "net451": { "dependencies": { "xunit.runner.console": "2.1.0" + } } } -} } \ No newline at end of file diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/project.json b/test/Microsoft.Extensions.WebEncoders.Tests/project.json index bcd52ff6ee..074b939a6d 100644 --- a/test/Microsoft.Extensions.WebEncoders.Tests/project.json +++ b/test/Microsoft.Extensions.WebEncoders.Tests/project.json @@ -3,7 +3,7 @@ "Microsoft.Extensions.DependencyInjection": "1.0.0-*", "Microsoft.Extensions.WebEncoders": "1.0.0-*", "Microsoft.NETCore.Platforms": "1.0.1-*", - "xunit.runner.aspnet": "2.0.0-aspnet-*" + "xunit": "2.1.0" }, "testRunner": "xunit", "compilationOptions": { @@ -18,7 +18,7 @@ }, "imports": "portable-net451+win8" }, - "dnx451": { + "net451": { "dependencies": { "xunit.runner.console": "2.1.0" } From 5de08352fa103ba937c85bdc7c0c3155ae9d2817 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Wed, 24 Feb 2016 09:37:41 -0800 Subject: [PATCH 057/471] Update `build.sh` to match other repos - currently attempts to `source KoreBuild.sh` --- build.sh | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/build.sh b/build.sh index 7b5e25e3a8..263fb667a8 100755 --- a/build.sh +++ b/build.sh @@ -1,13 +1,5 @@ #!/usr/bin/env bash -SOURCE="${BASH_SOURCE[0]}" -while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink - DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" - SOURCE="$(readlink "$SOURCE")" - [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located -done -repoFolder="$( cd -P "$( dirname "$SOURCE" )" && pwd )" - buildFolder=.build koreBuildFolder=$buildFolder/KoreBuild-dotnet @@ -42,7 +34,12 @@ fi if test ! -d $koreBuildFolder; then mono $nugetPath install KoreBuild-dotnet -ExcludeVersion -o $buildFolder -nocache -pre + chmod +x $koreBuildFolder/build/KoreBuild.sh fi -source $koreBuildFolder/build/KoreBuild.sh +makeFile=makefile.shade +if [ ! -e $makeFile ]; then + makeFile=$koreBuildFolder/build/makefile.shade +fi +./$koreBuildFolder/build/KoreBuild.sh -n $nugetPath -m $makeFile "$@" From 05b2b8e7d84a2cf7cd77f070f9aa4091e6a60aaf Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Wed, 24 Feb 2016 12:44:10 -0800 Subject: [PATCH 058/471] Update `build.cmd` to match latest template - aspnet/Universe#347 - `%KOREBUILD_VERSION%` doesn't work without this fix --- build.cmd | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/build.cmd b/build.cmd index 65fb3e3353..95b049cf63 100644 --- a/build.cmd +++ b/build.cmd @@ -28,12 +28,11 @@ IF NOT EXIST %NUGET_PATH% ( copy %CACHED_NUGET% %NUGET_PATH% > nul ) +SET KOREBUILD_DOWNLOAD_ARGS= +IF NOT "%KOREBUILD_VERSION%"=="" ( + SET KOREBUILD_DOWNLOAD_ARGS=-version %KOREBUILD_VERSION% +) IF NOT EXIST %KOREBUILD_FOLDER% ( - SET KOREBUILD_DOWNLOAD_ARGS= - IF NOT "%KOREBUILD_VERSION%"=="" ( - SET KOREBUILD_DOWNLOAD_ARGS=-version %KOREBUILD_VERSION% - ) - %BUILD_FOLDER%\nuget.exe install KoreBuild-dotnet -ExcludeVersion -o %BUILD_FOLDER% -nocache -pre %KOREBUILD_DOWNLOAD_ARGS% ) From 34c0c208518badb6658806ebbb5f9c13895c186b Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Wed, 24 Feb 2016 12:47:22 -0800 Subject: [PATCH 059/471] Update `build.cmd` to match latest template - aspnet/Universe#347 - `%KOREBUILD_VERSION%` doesn't work without this fix --- build.cmd | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/build.cmd b/build.cmd index 65fb3e3353..95b049cf63 100644 --- a/build.cmd +++ b/build.cmd @@ -28,12 +28,11 @@ IF NOT EXIST %NUGET_PATH% ( copy %CACHED_NUGET% %NUGET_PATH% > nul ) +SET KOREBUILD_DOWNLOAD_ARGS= +IF NOT "%KOREBUILD_VERSION%"=="" ( + SET KOREBUILD_DOWNLOAD_ARGS=-version %KOREBUILD_VERSION% +) IF NOT EXIST %KOREBUILD_FOLDER% ( - SET KOREBUILD_DOWNLOAD_ARGS= - IF NOT "%KOREBUILD_VERSION%"=="" ( - SET KOREBUILD_DOWNLOAD_ARGS=-version %KOREBUILD_VERSION% - ) - %BUILD_FOLDER%\nuget.exe install KoreBuild-dotnet -ExcludeVersion -o %BUILD_FOLDER% -nocache -pre %KOREBUILD_DOWNLOAD_ARGS% ) From 2e84cc5aac4d40a24cf56c49e837598271c48da5 Mon Sep 17 00:00:00 2001 From: Victor Hurdugaci Date: Sat, 27 Feb 2016 12:51:06 -0800 Subject: [PATCH 060/471] Update the build scripts --- build.cmd | 41 ++----------------------------------- build.ps1 | 36 +++++++++++++++++++++++++++++++++ build.sh | 60 +++++++++++++++++++++++-------------------------------- 3 files changed, 63 insertions(+), 74 deletions(-) create mode 100644 build.ps1 diff --git a/build.cmd b/build.cmd index 95b049cf63..2fa024b15e 100644 --- a/build.cmd +++ b/build.cmd @@ -1,39 +1,2 @@ -@ECHO off -SETLOCAL - -SET REPO_FOLDER=%~dp0 -CD "%REPO_FOLDER%" - -SET BUILD_FOLDER=.build -SET KOREBUILD_FOLDER=%BUILD_FOLDER%\KoreBuild-dotnet -SET KOREBUILD_VERSION= - -SET NUGET_PATH=%BUILD_FOLDER%\NuGet.exe -SET NUGET_VERSION=latest -SET CACHED_NUGET=%LocalAppData%\NuGet\nuget.%NUGET_VERSION%.exe - -IF NOT EXIST %BUILD_FOLDER% ( - md %BUILD_FOLDER% -) - -IF NOT EXIST %NUGET_PATH% ( - IF NOT EXIST %CACHED_NUGET% ( - echo Downloading latest version of NuGet.exe... - IF NOT EXIST %LocalAppData%\NuGet ( - md %LocalAppData%\NuGet - ) - @powershell -NoProfile -ExecutionPolicy unrestricted -Command "$ProgressPreference = 'SilentlyContinue'; Invoke-WebRequest 'https://dist.nuget.org/win-x86-commandline/%NUGET_VERSION%/nuget.exe' -OutFile '%CACHED_NUGET%'" - ) - - copy %CACHED_NUGET% %NUGET_PATH% > nul -) - -SET KOREBUILD_DOWNLOAD_ARGS= -IF NOT "%KOREBUILD_VERSION%"=="" ( - SET KOREBUILD_DOWNLOAD_ARGS=-version %KOREBUILD_VERSION% -) -IF NOT EXIST %KOREBUILD_FOLDER% ( - %BUILD_FOLDER%\nuget.exe install KoreBuild-dotnet -ExcludeVersion -o %BUILD_FOLDER% -nocache -pre %KOREBUILD_DOWNLOAD_ARGS% -) - -"%KOREBUILD_FOLDER%\build\KoreBuild.cmd" %* +@ECHO OFF +PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0build.ps1' %*" \ No newline at end of file diff --git a/build.ps1 b/build.ps1 new file mode 100644 index 0000000000..4fd24a30d5 --- /dev/null +++ b/build.ps1 @@ -0,0 +1,36 @@ +cd $PSScriptRoot + +$repoFolder = $PSScriptRoot +$env:REPO_FOLDER = $repoFolder + +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +if ($env:KOREBUILD_ZIP) +{ + $koreBuildZip=$env:KOREBUILD_ZIP +} + +$buildFolder = ".build" +$buildFile="$buildFolder\KoreBuild.ps1" + +if (!(Test-Path $buildFolder)) { + Write-Host "Downloading KoreBuild from $koreBuildZip" + + $tempFolder=$env:TEMP + "\KoreBuild-" + [guid]::NewGuid() + New-Item -Path "$tempFolder" -Type directory | Out-Null + + $localZipFile="$tempFolder\korebuild.zip" + + Invoke-WebRequest $koreBuildZip -OutFile $localZipFile + Add-Type -AssemblyName System.IO.Compression.FileSystem + [System.IO.Compression.ZipFile]::ExtractToDirectory($localZipFile, $tempFolder) + + New-Item -Path "$buildFolder" -Type directory | Out-Null + copy-item "$tempFolder\**\build\*" $buildFolder -Recurse + + # Cleanup + if (Test-Path $tempFolder) { + Remove-Item -Recurse -Force $tempFolder + } +} + +&"$buildFile" $args \ No newline at end of file diff --git a/build.sh b/build.sh index 263fb667a8..79638d06b6 100755 --- a/build.sh +++ b/build.sh @@ -1,45 +1,35 @@ #!/usr/bin/env bash +repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +cd $repoFolder -buildFolder=.build -koreBuildFolder=$buildFolder/KoreBuild-dotnet - -nugetPath=$buildFolder/nuget.exe - -if test `uname` = Darwin; then - cachedir=~/Library/Caches/KBuild -else - if [ -z $XDG_DATA_HOME ]; then - cachedir=$HOME/.local/share - else - cachedir=$XDG_DATA_HOME; - fi +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +if [ ! -z $KOREBUILD_ZIP ]; then + koreBuildZip=$KOREBUILD_ZIP fi -mkdir -p $cachedir -nugetVersion=latest -cacheNuget=$cachedir/nuget.$nugetVersion.exe -nugetUrl=https://dist.nuget.org/win-x86-commandline/$nugetVersion/nuget.exe +buildFolder=".build" +buildFile="$buildFolder/KoreBuild.sh" if test ! -d $buildFolder; then + echo "Downloading KoreBuild from $koreBuildZip" + + tempFolder="/tmp/KoreBuild-$(uuidgen)" + mkdir $tempFolder + + localZipFile="$tempFolder/korebuild.zip" + + wget -O $localZipFile $koreBuildZip 2>/dev/null || curl -o $localZipFile --location $koreBuildZip /dev/null + unzip -q -d $tempFolder $localZipFile + mkdir $buildFolder -fi - -if test ! -f $nugetPath; then - if test ! -f $cacheNuget; then - wget -O $cacheNuget $nugetUrl 2>/dev/null || curl -o $cacheNuget --location $nugetUrl /dev/null + cp -r $tempFolder/**/build/** $buildFolder + + chmod +x $buildFile + + # Cleanup + if test ! -d $tempFolder; then + rm -rf $tempFolder fi - - cp $cacheNuget $nugetPath fi -if test ! -d $koreBuildFolder; then - mono $nugetPath install KoreBuild-dotnet -ExcludeVersion -o $buildFolder -nocache -pre - chmod +x $koreBuildFolder/build/KoreBuild.sh -fi - -makeFile=makefile.shade -if [ ! -e $makeFile ]; then - makeFile=$koreBuildFolder/build/makefile.shade -fi - -./$koreBuildFolder/build/KoreBuild.sh -n $nugetPath -m $makeFile "$@" +$buildFile -r $repoFolder "$@" From c6e3cf30d3ab9ba2e1793fcdc42652823ed0614a Mon Sep 17 00:00:00 2001 From: Victor Hurdugaci Date: Sat, 27 Feb 2016 12:51:10 -0800 Subject: [PATCH 061/471] Update the build scripts --- build.cmd | 41 ++----------------------------------- build.ps1 | 36 +++++++++++++++++++++++++++++++++ build.sh | 60 +++++++++++++++++++++++-------------------------------- 3 files changed, 63 insertions(+), 74 deletions(-) create mode 100644 build.ps1 diff --git a/build.cmd b/build.cmd index 95b049cf63..2fa024b15e 100644 --- a/build.cmd +++ b/build.cmd @@ -1,39 +1,2 @@ -@ECHO off -SETLOCAL - -SET REPO_FOLDER=%~dp0 -CD "%REPO_FOLDER%" - -SET BUILD_FOLDER=.build -SET KOREBUILD_FOLDER=%BUILD_FOLDER%\KoreBuild-dotnet -SET KOREBUILD_VERSION= - -SET NUGET_PATH=%BUILD_FOLDER%\NuGet.exe -SET NUGET_VERSION=latest -SET CACHED_NUGET=%LocalAppData%\NuGet\nuget.%NUGET_VERSION%.exe - -IF NOT EXIST %BUILD_FOLDER% ( - md %BUILD_FOLDER% -) - -IF NOT EXIST %NUGET_PATH% ( - IF NOT EXIST %CACHED_NUGET% ( - echo Downloading latest version of NuGet.exe... - IF NOT EXIST %LocalAppData%\NuGet ( - md %LocalAppData%\NuGet - ) - @powershell -NoProfile -ExecutionPolicy unrestricted -Command "$ProgressPreference = 'SilentlyContinue'; Invoke-WebRequest 'https://dist.nuget.org/win-x86-commandline/%NUGET_VERSION%/nuget.exe' -OutFile '%CACHED_NUGET%'" - ) - - copy %CACHED_NUGET% %NUGET_PATH% > nul -) - -SET KOREBUILD_DOWNLOAD_ARGS= -IF NOT "%KOREBUILD_VERSION%"=="" ( - SET KOREBUILD_DOWNLOAD_ARGS=-version %KOREBUILD_VERSION% -) -IF NOT EXIST %KOREBUILD_FOLDER% ( - %BUILD_FOLDER%\nuget.exe install KoreBuild-dotnet -ExcludeVersion -o %BUILD_FOLDER% -nocache -pre %KOREBUILD_DOWNLOAD_ARGS% -) - -"%KOREBUILD_FOLDER%\build\KoreBuild.cmd" %* +@ECHO OFF +PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0build.ps1' %*" \ No newline at end of file diff --git a/build.ps1 b/build.ps1 new file mode 100644 index 0000000000..4fd24a30d5 --- /dev/null +++ b/build.ps1 @@ -0,0 +1,36 @@ +cd $PSScriptRoot + +$repoFolder = $PSScriptRoot +$env:REPO_FOLDER = $repoFolder + +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +if ($env:KOREBUILD_ZIP) +{ + $koreBuildZip=$env:KOREBUILD_ZIP +} + +$buildFolder = ".build" +$buildFile="$buildFolder\KoreBuild.ps1" + +if (!(Test-Path $buildFolder)) { + Write-Host "Downloading KoreBuild from $koreBuildZip" + + $tempFolder=$env:TEMP + "\KoreBuild-" + [guid]::NewGuid() + New-Item -Path "$tempFolder" -Type directory | Out-Null + + $localZipFile="$tempFolder\korebuild.zip" + + Invoke-WebRequest $koreBuildZip -OutFile $localZipFile + Add-Type -AssemblyName System.IO.Compression.FileSystem + [System.IO.Compression.ZipFile]::ExtractToDirectory($localZipFile, $tempFolder) + + New-Item -Path "$buildFolder" -Type directory | Out-Null + copy-item "$tempFolder\**\build\*" $buildFolder -Recurse + + # Cleanup + if (Test-Path $tempFolder) { + Remove-Item -Recurse -Force $tempFolder + } +} + +&"$buildFile" $args \ No newline at end of file diff --git a/build.sh b/build.sh index 263fb667a8..79638d06b6 100755 --- a/build.sh +++ b/build.sh @@ -1,45 +1,35 @@ #!/usr/bin/env bash +repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +cd $repoFolder -buildFolder=.build -koreBuildFolder=$buildFolder/KoreBuild-dotnet - -nugetPath=$buildFolder/nuget.exe - -if test `uname` = Darwin; then - cachedir=~/Library/Caches/KBuild -else - if [ -z $XDG_DATA_HOME ]; then - cachedir=$HOME/.local/share - else - cachedir=$XDG_DATA_HOME; - fi +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +if [ ! -z $KOREBUILD_ZIP ]; then + koreBuildZip=$KOREBUILD_ZIP fi -mkdir -p $cachedir -nugetVersion=latest -cacheNuget=$cachedir/nuget.$nugetVersion.exe -nugetUrl=https://dist.nuget.org/win-x86-commandline/$nugetVersion/nuget.exe +buildFolder=".build" +buildFile="$buildFolder/KoreBuild.sh" if test ! -d $buildFolder; then + echo "Downloading KoreBuild from $koreBuildZip" + + tempFolder="/tmp/KoreBuild-$(uuidgen)" + mkdir $tempFolder + + localZipFile="$tempFolder/korebuild.zip" + + wget -O $localZipFile $koreBuildZip 2>/dev/null || curl -o $localZipFile --location $koreBuildZip /dev/null + unzip -q -d $tempFolder $localZipFile + mkdir $buildFolder -fi - -if test ! -f $nugetPath; then - if test ! -f $cacheNuget; then - wget -O $cacheNuget $nugetUrl 2>/dev/null || curl -o $cacheNuget --location $nugetUrl /dev/null + cp -r $tempFolder/**/build/** $buildFolder + + chmod +x $buildFile + + # Cleanup + if test ! -d $tempFolder; then + rm -rf $tempFolder fi - - cp $cacheNuget $nugetPath fi -if test ! -d $koreBuildFolder; then - mono $nugetPath install KoreBuild-dotnet -ExcludeVersion -o $buildFolder -nocache -pre - chmod +x $koreBuildFolder/build/KoreBuild.sh -fi - -makeFile=makefile.shade -if [ ! -e $makeFile ]; then - makeFile=$koreBuildFolder/build/makefile.shade -fi - -./$koreBuildFolder/build/KoreBuild.sh -n $nugetPath -m $makeFile "$@" +$buildFile -r $repoFolder "$@" From ed2529edced330be83302b97eb70b75aa6068850 Mon Sep 17 00:00:00 2001 From: Victor Hurdugaci Date: Sun, 28 Feb 2016 10:12:09 -0800 Subject: [PATCH 062/471] Return the error code from build.cmd --- build.cmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.cmd b/build.cmd index 2fa024b15e..7d4894cb4a 100644 --- a/build.cmd +++ b/build.cmd @@ -1,2 +1,2 @@ @ECHO OFF -PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0build.ps1' %*" \ No newline at end of file +PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0build.ps1' %*; exit $LASTEXITCODE" \ No newline at end of file From 39af4735ac70102f05fe8b4a895d3fed8f7c6934 Mon Sep 17 00:00:00 2001 From: Victor Hurdugaci Date: Sun, 28 Feb 2016 10:12:13 -0800 Subject: [PATCH 063/471] Return the error code from build.cmd --- build.cmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.cmd b/build.cmd index 2fa024b15e..7d4894cb4a 100644 --- a/build.cmd +++ b/build.cmd @@ -1,2 +1,2 @@ @ECHO OFF -PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0build.ps1' %*" \ No newline at end of file +PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0build.ps1' %*; exit $LASTEXITCODE" \ No newline at end of file From e8f642df19281a3a3059c0ddd51e9eb865519a02 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Tue, 1 Mar 2016 13:29:45 -0800 Subject: [PATCH 064/471] Transition to netstandard. - dotnet5.X => netstandard1.y (where y = x-1). - DNXCore50 => netstandardapp1.5. - Applied the same changes to ifdefs. --- .../project.json | 13 +++++++++---- src/Microsoft.Extensions.WebEncoders/project.json | 12 +++++++++--- .../project.json | 7 +++++-- .../project.json | 7 +++++-- 4 files changed, 28 insertions(+), 11 deletions(-) diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/project.json b/src/Microsoft.AspNetCore.Html.Abstractions/project.json index 7b5fcb40a1..921349d93f 100644 --- a/src/Microsoft.AspNetCore.Html.Abstractions/project.json +++ b/src/Microsoft.AspNetCore.Html.Abstractions/project.json @@ -8,7 +8,9 @@ "compilationOptions": { "warningsAsErrors": true, "keyFile": "../../tools/Key.snk", - "nowarn": [ "CS1591" ], + "nowarn": [ + "CS1591" + ], "xmlDoc": true }, "dependencies": { @@ -21,11 +23,14 @@ "System.Runtime": "" } }, - "dotnet5.4": { + "netstandard1.3": { "dependencies": { "System.Collections": "4.0.11-*", "System.Resources.ResourceManager": "4.0.1-*" - } + }, + "imports": [ + "dotnet5.4" + ] } } -} +} \ No newline at end of file diff --git a/src/Microsoft.Extensions.WebEncoders/project.json b/src/Microsoft.Extensions.WebEncoders/project.json index a777ff4d9b..1c0e609f4c 100644 --- a/src/Microsoft.Extensions.WebEncoders/project.json +++ b/src/Microsoft.Extensions.WebEncoders/project.json @@ -9,7 +9,9 @@ "warningsAsErrors": true, "allowUnsafe": true, "keyFile": "../../tools/Key.snk", - "nowarn": [ "CS1591" ], + "nowarn": [ + "CS1591" + ], "xmlDoc": true }, "dependencies": { @@ -24,6 +26,10 @@ "System.Runtime": "" } }, - "dotnet5.4": {} + "netstandard1.3": { + "imports": [ + "dotnet5.4" + ] + } } -} +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json index 35c576a3c2..a2b85b5cfe 100644 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json @@ -12,11 +12,14 @@ }, "testRunner": "xunit", "frameworks": { - "dnxcore50": { + "netstandardapp1.5": { "dependencies": { "dotnet-test-xunit": "1.0.0-dev-*" }, - "imports": "portable-net451+win8" + "imports": [ + "dnxcore50", + "portable-net451+win8" + ] }, "net451": { "dependencies": { diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/project.json b/test/Microsoft.Extensions.WebEncoders.Tests/project.json index 074b939a6d..0e0c77023b 100644 --- a/test/Microsoft.Extensions.WebEncoders.Tests/project.json +++ b/test/Microsoft.Extensions.WebEncoders.Tests/project.json @@ -12,11 +12,14 @@ "keyFile": "../../tools/Key.snk" }, "frameworks": { - "dnxcore50": { + "netstandardapp1.5": { "dependencies": { "dotnet-test-xunit": "1.0.0-dev-*" }, - "imports": "portable-net451+win8" + "imports": [ + "dnxcore50", + "portable-net451+win8" + ] }, "net451": { "dependencies": { From 8c293934e874addfcdcfc3859592dc1ac3de210d Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Tue, 1 Mar 2016 13:32:25 -0800 Subject: [PATCH 065/471] Transition to netstandard. - dotnet5.X => netstandard1.y (where y = x-1). - DNXCore50 => netstandardapp1.5. - Applied the same changes to ifdefs. --- src/Microsoft.AspNetCore.JsonPatch/project.json | 13 +++++++++---- .../project.json | 7 +++++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/Microsoft.AspNetCore.JsonPatch/project.json b/src/Microsoft.AspNetCore.JsonPatch/project.json index 91adf85b87..6e66884725 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/project.json +++ b/src/Microsoft.AspNetCore.JsonPatch/project.json @@ -3,7 +3,9 @@ "compilationOptions": { "warningsAsErrors": true, "keyFile": "../../tools/Key.snk", - "nowarn": [ "CS1591" ], + "nowarn": [ + "CS1591" + ], "xmlDoc": true }, "repository": { @@ -15,7 +17,7 @@ }, "frameworks": { "net451": {}, - "dotnet5.4": { + "netstandard1.3": { "dependencies": { "Microsoft.CSharp": "4.0.1-*", "System.Collections.Concurrent": "4.0.12-*", @@ -27,7 +29,10 @@ "System.Runtime.Serialization.Primitives": "4.1.0-*", "System.Text.Encoding.Extensions": "4.0.11-*" }, - "imports": "portable-net451+win8" + "imports": [ + "dotnet5.4", + "portable-net451+win8" + ] } } -} +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json index cd04e92bb2..6bfaeafb67 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json @@ -10,12 +10,15 @@ }, "testRunner": "xunit", "frameworks": { - "dnxcore50": { + "netstandardapp1.5": { "dependencies": { "moq.netcore": "4.4.0-beta8", "dotnet-test-xunit": "1.0.0-dev-*" }, - "imports": "portable-net451+win8" + "imports": [ + "dnxcore50", + "portable-net451+win8" + ] }, "net451": { "frameworkAssemblies": { From b2b623816b6c6dabf535e7d924b191e69c091009 Mon Sep 17 00:00:00 2001 From: jacalvar Date: Wed, 24 Feb 2016 23:20:35 -0800 Subject: [PATCH 066/471] Make ServiceCollectionExtensions consistent --- .../EncoderServiceCollectionExtensions.cs | 43 ++++++++++--------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/src/Microsoft.Extensions.WebEncoders/EncoderServiceCollectionExtensions.cs b/src/Microsoft.Extensions.WebEncoders/EncoderServiceCollectionExtensions.cs index df3946099c..317d88f99d 100644 --- a/src/Microsoft.Extensions.WebEncoders/EncoderServiceCollectionExtensions.cs +++ b/src/Microsoft.Extensions.WebEncoders/EncoderServiceCollectionExtensions.cs @@ -9,6 +9,9 @@ using Microsoft.Extensions.WebEncoders; namespace Microsoft.Extensions.DependencyInjection { + /// + /// Extension methods for setting up web encoding services in an . + /// public static class EncoderServiceCollectionExtensions { /// @@ -17,24 +20,7 @@ namespace Microsoft.Extensions.DependencyInjection /// /// The . /// The instance after the encoders have been added. - public static IServiceCollection AddWebEncoders(this IServiceCollection services) - { - if (services == null) - { - throw new ArgumentNullException(nameof(services)); - } - - return AddWebEncoders(services, configureOptions: null); - } - - /// - /// Adds , and - /// to the specified . - /// - /// The . - /// A callback to configure . - /// The instance after the encoders have been added. - public static IServiceCollection AddWebEncoders(this IServiceCollection services, Action configureOptions) + public static void AddWebEncoders(this IServiceCollection services) { if (services == null) { @@ -51,13 +37,28 @@ namespace Microsoft.Extensions.DependencyInjection CreateFactory(() => JavaScriptEncoder.Default, settings => JavaScriptEncoder.Create(settings))); services.TryAddSingleton( CreateFactory(() => UrlEncoder.Default, settings => UrlEncoder.Create(settings))); + } - if (configureOptions != null) + /// + /// Adds , and + /// to the specified . + /// + /// The . + /// An to configure the provided . + public static void AddWebEncoders(this IServiceCollection services, Action setupAction) + { + if (services == null) { - services.Configure(configureOptions); + throw new ArgumentNullException(nameof(services)); } - return services; + if (setupAction == null) + { + throw new ArgumentNullException(nameof(setupAction)); + } + + services.AddWebEncoders(); + services.Configure(setupAction); } private static Func CreateFactory( From 67c1dfc43d14109906d3c2e236d5cdb4d2332b32 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Wed, 2 Mar 2016 18:50:26 -0800 Subject: [PATCH 067/471] Remove project name from output path - aspnet/Coherence-Signed#187 - remove `` settings but maintain other unique aspects e.g. `` - in a few cases, standardize on VS version `14.0` and not something more specific --- .../Microsoft.AspNetCore.Html.Abstractions.xproj | 6 ++---- .../Microsoft.Extensions.WebEncoders.xproj | 2 +- .../Microsoft.AspNetCore.Html.Abstractions.Test.xproj | 5 ++--- .../Microsoft.Extensions.WebEncoders.Tests.xproj | 2 +- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.xproj b/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.xproj index df229c75eb..7a3801b2b1 100644 --- a/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.xproj +++ b/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.xproj @@ -1,4 +1,4 @@ - + 14.0 @@ -7,11 +7,9 @@ 68a28e4a-3ade-4187-9625-4ff185887cb3 - Microsoft.AspNetCore.Html.Abstractions ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\$(MSBuildProjectName)\ + ..\..\artifacts\bin\ - 2.0 diff --git a/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.xproj b/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.xproj index 084e7901ea..0f278d6c98 100644 --- a/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.xproj +++ b/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.xproj @@ -8,7 +8,7 @@ dd2ce416-765e-4000-a03e-c2ff165da1b6 ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\$(MSBuildProjectName)\ + ..\..\artifacts\bin\ 2.0 diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.xproj b/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.xproj index f699a1c4dc..20389ad4bf 100644 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.xproj +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.xproj @@ -1,4 +1,4 @@ - + 14.0 @@ -7,9 +7,8 @@ 2d187b88-94bd-4a39-ac97-f8f8b9363301 - Microsoft.AspNetCore.Html.Abstractions.Test ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\$(MSBuildProjectName)\ + ..\..\artifacts\bin\ 2.0 diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.xproj b/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.xproj index 9b0698e3cc..9ad3cb3d4f 100644 --- a/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.xproj +++ b/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.xproj @@ -8,7 +8,7 @@ 7ae2731d-43cd-4cf8-850a-4914de2ce930 ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\$(MSBuildProjectName)\ + ..\..\artifacts\bin\ 2.0 From 404a3144cf8c2cb609f79c51d94c3053491db04c Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Wed, 2 Mar 2016 18:55:57 -0800 Subject: [PATCH 068/471] Remove project name from output path - aspnet/Coherence-Signed#187 - remove `` settings but maintain other unique aspects e.g. `` - in a few cases, standardize on VS version `14.0` and not something more specific --- .../Microsoft.AspNetCore.JsonPatch.xproj | 2 +- .../Microsoft.AspNetCore.JsonPatch.Test.xproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.xproj b/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.xproj index f9fb187ecd..d11d600744 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.xproj +++ b/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.xproj @@ -8,7 +8,7 @@ 4d55f4d8-633b-462f-a5b1-feb84bd2d534 ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\$(MSBuildProjectName)\ + ..\..\artifacts\bin\ 2.0 diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.xproj b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.xproj index 74e0fef687..0b71c5d301 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.xproj +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.xproj @@ -8,7 +8,7 @@ 81c20848-e063-4e12-ac40-0b55a532c16c ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\$(MSBuildProjectName)\ + ..\..\artifacts\bin\ 2.0 From e95ed5d204956a60a1b8ebe992aa25d4b862181b Mon Sep 17 00:00:00 2001 From: Ajay Bhargav Baaskaran Date: Thu, 3 Mar 2016 17:31:17 -0800 Subject: [PATCH 069/471] Added Company, Copyright and Product attributes to AssemblyInfo --- .../Properties/AssemblyInfo.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.AspNetCore.JsonPatch/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.JsonPatch/Properties/AssemblyInfo.cs index b2437d9ad6..76feceeff0 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Properties/AssemblyInfo.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Properties/AssemblyInfo.cs @@ -5,4 +5,7 @@ using System.Reflection; using System.Resources; [assembly: AssemblyMetadata("Serviceable", "True")] -[assembly: NeutralResourcesLanguage("en-us")] \ No newline at end of file +[assembly: NeutralResourcesLanguage("en-us")] +[assembly: AssemblyCompany("Microsoft Corporation.")] +[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] +[assembly: AssemblyProduct("Microsoft ASP.NET Core")] From b9d2dc89aae71e648b2d19721730d4f023a2f1f5 Mon Sep 17 00:00:00 2001 From: Ajay Bhargav Baaskaran Date: Thu, 3 Mar 2016 17:31:53 -0800 Subject: [PATCH 070/471] Added Company, Copyright and Product attributes to AssemblyInfo --- .../Properties/AssemblyInfo.cs | 5 ++++- .../Properties/AssemblyInfo.cs | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.Html.Abstractions/Properties/AssemblyInfo.cs index 72210dd611..403f0e3c52 100644 --- a/src/Microsoft.AspNetCore.Html.Abstractions/Properties/AssemblyInfo.cs +++ b/src/Microsoft.AspNetCore.Html.Abstractions/Properties/AssemblyInfo.cs @@ -7,4 +7,7 @@ using System.Runtime.CompilerServices; [assembly: AssemblyMetadata("Serviceable", "True")] [assembly: NeutralResourcesLanguage("en-us")] -[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Html.Abstractions.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] \ No newline at end of file +[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Html.Abstractions.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] +[assembly: AssemblyCompany("Microsoft Corporation.")] +[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] +[assembly: AssemblyProduct("Microsoft ASP.NET Core")] diff --git a/src/Microsoft.Extensions.WebEncoders/Properties/AssemblyInfo.cs b/src/Microsoft.Extensions.WebEncoders/Properties/AssemblyInfo.cs index b2437d9ad6..8d8d88195c 100644 --- a/src/Microsoft.Extensions.WebEncoders/Properties/AssemblyInfo.cs +++ b/src/Microsoft.Extensions.WebEncoders/Properties/AssemblyInfo.cs @@ -5,4 +5,7 @@ using System.Reflection; using System.Resources; [assembly: AssemblyMetadata("Serviceable", "True")] -[assembly: NeutralResourcesLanguage("en-us")] \ No newline at end of file +[assembly: NeutralResourcesLanguage("en-us")] +[assembly: AssemblyCompany("Microsoft Corporation.")] +[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] +[assembly: AssemblyProduct("Microsoft .NET Extensions")] From 2705510508b08f6c50007c87e35fd32951208811 Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Fri, 12 Feb 2016 18:11:48 -0800 Subject: [PATCH 071/471] Add Copy/Move for content - Remove HtmlTextWriter Currently we overload the definition of WriteTo on IHtmlContent implementation classes to either represent a "real" write or a "flatten" by checking if the writer inherits HtmlText writer. This overloading is a bit of an odd fit and hides the real semantic we want for flattening. Additionally, we want to gradually make the concept of a pooled backing-buffer for IHtmlContent first-class - using pooled buffers dictates that we support move-semantics to some degree. This change makes the work that we do for flattening into pooled buffers explicit rather than hidden. --- .../HtmlContentBuilder.cs | 64 +++++++++ .../HtmlEncodedString.cs | 13 +- .../HtmlTextWriter.cs | 49 ------- .../IHtmlContentBuilder.cs | 2 +- .../IHtmlContentContainer.cs | 30 +++++ .../HtmlContentBuilderExtensionsTest.cs | 14 ++ .../HtmlContentBuilderTest.cs | 124 +++++++++++++++++- 7 files changed, 240 insertions(+), 56 deletions(-) delete mode 100644 src/Microsoft.AspNetCore.Html.Abstractions/HtmlTextWriter.cs create mode 100644 src/Microsoft.AspNetCore.Html.Abstractions/IHtmlContentContainer.cs diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilder.cs b/src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilder.cs index b79e400375..be218244b0 100644 --- a/src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilder.cs +++ b/src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilder.cs @@ -96,6 +96,70 @@ namespace Microsoft.AspNetCore.Html 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) { diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/HtmlEncodedString.cs b/src/Microsoft.AspNetCore.Html.Abstractions/HtmlEncodedString.cs index c50fba890c..bf38ac3682 100644 --- a/src/Microsoft.AspNetCore.Html.Abstractions/HtmlEncodedString.cs +++ b/src/Microsoft.AspNetCore.Html.Abstractions/HtmlEncodedString.cs @@ -17,17 +17,20 @@ namespace Microsoft.AspNetCore.Html /// public static readonly IHtmlContent NewLine = new HtmlEncodedString(Environment.NewLine); - private readonly string _value; - /// /// Creates a new . /// /// The HTML encoded value. public HtmlEncodedString(string value) { - _value = value; + Value = value; } + /// + /// Gets the HTML encoded value. + /// + public string Value { get; } + /// public void WriteTo(TextWriter writer, HtmlEncoder encoder) { @@ -41,13 +44,13 @@ namespace Microsoft.AspNetCore.Html throw new ArgumentNullException(nameof(encoder)); } - writer.Write(_value); + writer.Write(Value); } /// public override string ToString() { - return _value ?? string.Empty; + return Value ?? string.Empty; } } } diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/HtmlTextWriter.cs b/src/Microsoft.AspNetCore.Html.Abstractions/HtmlTextWriter.cs deleted file mode 100644 index c9158b49b6..0000000000 --- a/src/Microsoft.AspNetCore.Html.Abstractions/HtmlTextWriter.cs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.IO; - -namespace Microsoft.AspNetCore.Html -{ - /// - /// A which supports special processing of . - /// - public abstract class HtmlTextWriter : TextWriter - { - /// - /// Writes an value. - /// - /// The value. - public abstract void Write(IHtmlContent value); - - /// - public override void Write(object value) - { - var htmlContent = value as IHtmlContent; - if (htmlContent == null) - { - base.Write(value); - } - else - { - Write(htmlContent); - } - } - - /// - public override void WriteLine(object value) - { - var htmlContent = value as IHtmlContent; - if (htmlContent == null) - { - base.Write(value); - } - else - { - Write(htmlContent); - } - - base.WriteLine(); - } - } -} diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/IHtmlContentBuilder.cs b/src/Microsoft.AspNetCore.Html.Abstractions/IHtmlContentBuilder.cs index 978fedc03f..912fe442aa 100644 --- a/src/Microsoft.AspNetCore.Html.Abstractions/IHtmlContentBuilder.cs +++ b/src/Microsoft.AspNetCore.Html.Abstractions/IHtmlContentBuilder.cs @@ -6,7 +6,7 @@ namespace Microsoft.AspNetCore.Html /// /// A builder for HTML content. /// - public interface IHtmlContentBuilder : IHtmlContent + public interface IHtmlContentBuilder : IHtmlContentContainer { /// /// Appends an instance. diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/IHtmlContentContainer.cs b/src/Microsoft.AspNetCore.Html.Abstractions/IHtmlContentContainer.cs new file mode 100644 index 0000000000..f17811433c --- /dev/null +++ b/src/Microsoft.AspNetCore.Html.Abstractions/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/test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlContentBuilderExtensionsTest.cs b/test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlContentBuilderExtensionsTest.cs index 6b4307f690..08151b3675 100644 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlContentBuilderExtensionsTest.cs +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlContentBuilderExtensionsTest.cs @@ -392,6 +392,20 @@ namespace Microsoft.AspNetCore.Html.Test 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) diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlContentBuilderTest.cs b/test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlContentBuilderTest.cs index 901512fdad..40219b19f7 100644 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlContentBuilderTest.cs +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlContentBuilderTest.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; using System.IO; using System.Text.Encodings.Web; using Microsoft.AspNetCore.Html; @@ -105,6 +106,106 @@ namespace Microsoft.Extensions.Internal Assert.Equal(0, content.Entries.Count); } + [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.Entries.Count); + Assert.Equal(3, destination.Entries.Count); + + Assert.Equal("some-content", Assert.IsType(destination.Entries[0])); + Assert.Equal(new TestHtmlContent("hello"), Assert.IsType(destination.Entries[1])); + Assert.Equal("Test", Assert.IsType(destination.Entries[2])); + } + + [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.Entries.Count); + Assert.Equal(1, nested.Entries.Count); + Assert.Equal(3, destination.Entries.Count); + + Assert.Equal("some-content", Assert.IsType(destination.Entries[0])); + Assert.Equal(new TestHtmlContent("hello"), Assert.IsType(destination.Entries[1])); + Assert.Equal("Test", Assert.IsType(destination.Entries[2])); + } + + [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.Entries.Count); + Assert.Equal(3, destination.Entries.Count); + + Assert.Equal("some-content", Assert.IsType(destination.Entries[0])); + Assert.Equal(new TestHtmlContent("hello"), Assert.IsType(destination.Entries[1])); + Assert.Equal("Test", Assert.IsType(destination.Entries[2])); + } + + [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.Entries.Count); + Assert.Equal(0, nested.Entries.Count); + Assert.Equal(3, destination.Entries.Count); + + Assert.Equal("some-content", Assert.IsType(destination.Entries[0])); + Assert.Equal(new TestHtmlContent("hello"), Assert.IsType(destination.Entries[1])); + Assert.Equal("Test", Assert.IsType(destination.Entries[2])); + } + [Fact] public void WriteTo_WritesAllItems() { @@ -122,7 +223,7 @@ namespace Microsoft.Extensions.Internal Assert.Equal("Written from TestHtmlContent: HelloHtmlEncode[[Test]]", writer.ToString()); } - private class TestHtmlContent : IHtmlContent + private class TestHtmlContent : IHtmlContent, IEquatable { private string _content; @@ -140,6 +241,27 @@ namespace Microsoft.Extensions.Internal { 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); + } } } } From 8f959b04b18e0b09e01bcd09e48b9524171f5aa8 Mon Sep 17 00:00:00 2001 From: Victor Hurdugaci Date: Mon, 7 Mar 2016 20:54:54 -0800 Subject: [PATCH 072/471] Update the build scripts to the latest version --- build.ps1 | 33 ++++++++++++++++++++++++++++++++- build.sh | 15 +++++++++++++-- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/build.ps1 b/build.ps1 index 4fd24a30d5..8f2f99691a 100644 --- a/build.ps1 +++ b/build.ps1 @@ -1,3 +1,33 @@ +$ErrorActionPreference = "Stop" + +function DownloadWithRetry([string] $url, [string] $downloadLocation, [int] $retries) +{ + while($true) + { + try + { + Invoke-WebRequest $url -OutFile $downloadLocation + break + } + catch + { + $exceptionMessage = $_.Exception.Message + Write-Host "Failed to download '$url': $exceptionMessage" + if ($retries -gt 0) { + $retries-- + Write-Host "Waiting 10 seconds before retrying. Retries left: $retries" + Start-Sleep -Seconds 10 + + } + else + { + $exception = $_.Exception + throw $exception + } + } + } +} + cd $PSScriptRoot $repoFolder = $PSScriptRoot @@ -20,7 +50,8 @@ if (!(Test-Path $buildFolder)) { $localZipFile="$tempFolder\korebuild.zip" - Invoke-WebRequest $koreBuildZip -OutFile $localZipFile + DownloadWithRetry -url $koreBuildZip -downloadLocation $localZipFile -retries 6 + Add-Type -AssemblyName System.IO.Compression.FileSystem [System.IO.Compression.ZipFile]::ExtractToDirectory($localZipFile, $tempFolder) diff --git a/build.sh b/build.sh index 79638d06b6..f4208100eb 100755 --- a/build.sh +++ b/build.sh @@ -18,7 +18,18 @@ if test ! -d $buildFolder; then localZipFile="$tempFolder/korebuild.zip" - wget -O $localZipFile $koreBuildZip 2>/dev/null || curl -o $localZipFile --location $koreBuildZip /dev/null + retries=6 + until (wget -O $localZipFile $koreBuildZip 2>/dev/null || curl -o $localZipFile --location $koreBuildZip 2>/dev/null) + do + echo "Failed to download '$koreBuildZip'" + if [ "$retries" -le 0 ]; then + exit 1 + fi + retries=$((retries - 1)) + echo "Waiting 10 seconds before retrying. Retries left: $retries" + sleep 10s + done + unzip -q -d $tempFolder $localZipFile mkdir $buildFolder @@ -32,4 +43,4 @@ if test ! -d $buildFolder; then fi fi -$buildFile -r $repoFolder "$@" +$buildFile -r $repoFolder "$@" \ No newline at end of file From 5b5655f62808723e2be37b442277b393a813bf48 Mon Sep 17 00:00:00 2001 From: Victor Hurdugaci Date: Mon, 7 Mar 2016 20:54:58 -0800 Subject: [PATCH 073/471] Update the build scripts to the latest version --- build.ps1 | 33 ++++++++++++++++++++++++++++++++- build.sh | 15 +++++++++++++-- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/build.ps1 b/build.ps1 index 4fd24a30d5..8f2f99691a 100644 --- a/build.ps1 +++ b/build.ps1 @@ -1,3 +1,33 @@ +$ErrorActionPreference = "Stop" + +function DownloadWithRetry([string] $url, [string] $downloadLocation, [int] $retries) +{ + while($true) + { + try + { + Invoke-WebRequest $url -OutFile $downloadLocation + break + } + catch + { + $exceptionMessage = $_.Exception.Message + Write-Host "Failed to download '$url': $exceptionMessage" + if ($retries -gt 0) { + $retries-- + Write-Host "Waiting 10 seconds before retrying. Retries left: $retries" + Start-Sleep -Seconds 10 + + } + else + { + $exception = $_.Exception + throw $exception + } + } + } +} + cd $PSScriptRoot $repoFolder = $PSScriptRoot @@ -20,7 +50,8 @@ if (!(Test-Path $buildFolder)) { $localZipFile="$tempFolder\korebuild.zip" - Invoke-WebRequest $koreBuildZip -OutFile $localZipFile + DownloadWithRetry -url $koreBuildZip -downloadLocation $localZipFile -retries 6 + Add-Type -AssemblyName System.IO.Compression.FileSystem [System.IO.Compression.ZipFile]::ExtractToDirectory($localZipFile, $tempFolder) diff --git a/build.sh b/build.sh index 79638d06b6..f4208100eb 100755 --- a/build.sh +++ b/build.sh @@ -18,7 +18,18 @@ if test ! -d $buildFolder; then localZipFile="$tempFolder/korebuild.zip" - wget -O $localZipFile $koreBuildZip 2>/dev/null || curl -o $localZipFile --location $koreBuildZip /dev/null + retries=6 + until (wget -O $localZipFile $koreBuildZip 2>/dev/null || curl -o $localZipFile --location $koreBuildZip 2>/dev/null) + do + echo "Failed to download '$koreBuildZip'" + if [ "$retries" -le 0 ]; then + exit 1 + fi + retries=$((retries - 1)) + echo "Waiting 10 seconds before retrying. Retries left: $retries" + sleep 10s + done + unzip -q -d $tempFolder $localZipFile mkdir $buildFolder @@ -32,4 +43,4 @@ if test ! -d $buildFolder; then fi fi -$buildFile -r $repoFolder "$@" +$buildFile -r $repoFolder "$@" \ No newline at end of file From b7993bd562df1dca3c3f9d5d672f90911c880cf6 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 9 Mar 2016 16:35:07 -0800 Subject: [PATCH 074/471] Limit the branches that build on our public CI. [ci skip] --- .travis.yml | 6 ++++++ appveyor.yml | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/.travis.yml b/.travis.yml index e8f77f0f14..e63d71127a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,5 +16,11 @@ os: - linux - osx osx_image: xcode7.1 +branches: + only: + - master + - release + - dev + - /^(.*\\/)?ci-.*$/ script: - ./build.sh --quiet verify \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml index 636a7618d3..15ffe737a5 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,5 +1,11 @@ init: - git config --global core.autocrlf true +branches: + only: + - master + - release + - dev + - /^(.*\\/)?ci-.*$/ build_script: - build.cmd --quiet verify clone_depth: 1 From e341d1b1e2bebe4f374542a309fb81f949326ac7 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 9 Mar 2016 16:35:10 -0800 Subject: [PATCH 075/471] Limit the branches that build on our public CI. [ci skip] --- .travis.yml | 6 ++++++ appveyor.yml | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/.travis.yml b/.travis.yml index e8f77f0f14..e63d71127a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,5 +16,11 @@ os: - linux - osx osx_image: xcode7.1 +branches: + only: + - master + - release + - dev + - /^(.*\\/)?ci-.*$/ script: - ./build.sh --quiet verify \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml index 636a7618d3..15ffe737a5 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,5 +1,11 @@ init: - git config --global core.autocrlf true +branches: + only: + - master + - release + - dev + - /^(.*\\/)?ci-.*$/ build_script: - build.cmd --quiet verify clone_depth: 1 From 104163e275cce1f95b5b77a6bd6c38abe64061fa Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 9 Mar 2016 17:44:47 -0800 Subject: [PATCH 076/471] Fix backslashes in yml config. [ci skip] --- .travis.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index e63d71127a..304e307169 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,6 +21,6 @@ branches: - master - release - dev - - /^(.*\\/)?ci-.*$/ + - /^(.*\/)?ci-.*$/ script: - ./build.sh --quiet verify \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml index 15ffe737a5..be95b88d6f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -5,7 +5,7 @@ branches: - master - release - dev - - /^(.*\\/)?ci-.*$/ + - /^(.*\/)?ci-.*$/ build_script: - build.cmd --quiet verify clone_depth: 1 From bc560b000353f0e7bf414d3ff812c3691ce0ceb7 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 9 Mar 2016 17:44:48 -0800 Subject: [PATCH 077/471] Fix backslashes in yml config. [ci skip] --- .travis.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index e63d71127a..304e307169 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,6 +21,6 @@ branches: - master - release - dev - - /^(.*\\/)?ci-.*$/ + - /^(.*\/)?ci-.*$/ script: - ./build.sh --quiet verify \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml index 15ffe737a5..be95b88d6f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -5,7 +5,7 @@ branches: - master - release - dev - - /^(.*\\/)?ci-.*$/ + - /^(.*\/)?ci-.*$/ build_script: - build.cmd --quiet verify clone_depth: 1 From b734291b1395d8134b911141c01d8c6aee9ea86e Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 10 Mar 2016 21:46:51 -0800 Subject: [PATCH 078/471] Target minimal TFMs --- .../Adapters/ObjectAdapter.cs | 4 ++-- .../Converters/TypedJsonPatchDocumentConverter.cs | 2 +- .../Helpers/ObjectTreeAnalyisResult.cs | 1 - src/Microsoft.AspNetCore.JsonPatch/project.json | 7 ++++--- test/Microsoft.AspNetCore.JsonPatch.Test/project.json | 5 +++-- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs b/src/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs index aeae454fa9..b70ff697c3 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs @@ -1023,14 +1023,14 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters { if (IsGenericListType(type)) { - return type.GetGenericArguments()[0]; + return type.GetTypeInfo().GenericTypeArguments[0]; } foreach (Type interfaceType in type.GetTypeInfo().ImplementedInterfaces) { if (IsGenericListType(interfaceType)) { - return interfaceType.GetGenericArguments()[0]; + return interfaceType.GetTypeInfo().GenericTypeArguments[0]; } } diff --git a/src/Microsoft.AspNetCore.JsonPatch/Converters/TypedJsonPatchDocumentConverter.cs b/src/Microsoft.AspNetCore.JsonPatch/Converters/TypedJsonPatchDocumentConverter.cs index a150bd0478..292a3be556 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Converters/TypedJsonPatchDocumentConverter.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Converters/TypedJsonPatchDocumentConverter.cs @@ -27,7 +27,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Converters return null; } - var genericType = objectType.GetGenericArguments()[0]; + var genericType = objectType.GetTypeInfo().GenericTypeArguments[0]; // load jObject var jObject = JArray.Load(reader); diff --git a/src/Microsoft.AspNetCore.JsonPatch/Helpers/ObjectTreeAnalyisResult.cs b/src/Microsoft.AspNetCore.JsonPatch/Helpers/ObjectTreeAnalyisResult.cs index 4d083bd073..782859ad5f 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Helpers/ObjectTreeAnalyisResult.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Helpers/ObjectTreeAnalyisResult.cs @@ -141,7 +141,6 @@ namespace Microsoft.AspNetCore.JsonPatch.Helpers } else if (targetObject is IList) { - System.Diagnostics.Debugger.Launch(); UseDynamicLogic = false; int index; diff --git a/src/Microsoft.AspNetCore.JsonPatch/project.json b/src/Microsoft.AspNetCore.JsonPatch/project.json index 6e66884725..abfc19cba3 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/project.json +++ b/src/Microsoft.AspNetCore.JsonPatch/project.json @@ -16,13 +16,14 @@ "Newtonsoft.Json": "8.0.2" }, "frameworks": { - "net451": {}, - "netstandard1.3": { + "netstandard1.1": { "dependencies": { "Microsoft.CSharp": "4.0.1-*", "System.Collections.Concurrent": "4.0.12-*", "System.ComponentModel.TypeConverter": "4.0.1-*", + "System.Diagnostics.Debug": "4.0.11-*", "System.Globalization": "4.0.11-*", + "System.Linq": "4.1.0-*", "System.Reflection.Extensions": "4.0.1-*", "System.Resources.ResourceManager": "4.0.1-*", "System.Runtime.Extensions": "4.1.0-*", @@ -30,7 +31,7 @@ "System.Text.Encoding.Extensions": "4.0.11-*" }, "imports": [ - "dotnet5.4", + "dotnet5.2", "portable-net451+win8" ] } diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json index 6bfaeafb67..c8772f21fb 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json @@ -22,11 +22,12 @@ }, "net451": { "frameworkAssemblies": { - "System.Runtime": "", - "System.Threading.Tasks": "" + "System.Linq.Expressions": {"type": "build"}, + "System.Threading.Tasks": { "type": "build" } }, "dependencies": { "Moq": "4.2.1312.1622", + "System.Runtime": "4.1.0-*", "xunit.runner.console": "2.1.0" } } From 06c818c9e5d5c3b5225a8dfc5771f43a02ae6727 Mon Sep 17 00:00:00 2001 From: Brice Lambson Date: Thu, 10 Mar 2016 10:29:41 -0800 Subject: [PATCH 079/471] Don't reference facades in NuSpec These can be removed entirely after dotnet/cli#164 --- src/Microsoft.AspNetCore.Html.Abstractions/project.json | 4 ++-- src/Microsoft.Extensions.WebEncoders/project.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/project.json b/src/Microsoft.AspNetCore.Html.Abstractions/project.json index 921349d93f..6d2220cabe 100644 --- a/src/Microsoft.AspNetCore.Html.Abstractions/project.json +++ b/src/Microsoft.AspNetCore.Html.Abstractions/project.json @@ -19,8 +19,8 @@ "frameworks": { "net451": { "frameworkAssemblies": { - "System.IO": "", - "System.Runtime": "" + "System.IO": { "type": "build" }, + "System.Runtime": { "type": "build" } } }, "netstandard1.3": { diff --git a/src/Microsoft.Extensions.WebEncoders/project.json b/src/Microsoft.Extensions.WebEncoders/project.json index 1c0e609f4c..1e24e36926 100644 --- a/src/Microsoft.Extensions.WebEncoders/project.json +++ b/src/Microsoft.Extensions.WebEncoders/project.json @@ -22,8 +22,8 @@ "frameworks": { "net451": { "frameworkAssemblies": { - "System.IO": "", - "System.Runtime": "" + "System.IO": { "type": "build" }, + "System.Runtime": { "type": "build" } } }, "netstandard1.3": { From 0e95ce9a8eda8e8ced4f2af169790b09b703f2a8 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Sat, 12 Mar 2016 08:22:32 -0800 Subject: [PATCH 080/471] Target minimal TFMs --- .../project.json | 10 ++-------- src/Microsoft.Extensions.WebEncoders/project.json | 10 ++-------- .../project.json | 5 +++-- .../project.json | 4 ++-- 4 files changed, 9 insertions(+), 20 deletions(-) diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/project.json b/src/Microsoft.AspNetCore.Html.Abstractions/project.json index 6d2220cabe..fc92b6e725 100644 --- a/src/Microsoft.AspNetCore.Html.Abstractions/project.json +++ b/src/Microsoft.AspNetCore.Html.Abstractions/project.json @@ -17,19 +17,13 @@ "System.Text.Encodings.Web": "4.0.0-*" }, "frameworks": { - "net451": { - "frameworkAssemblies": { - "System.IO": { "type": "build" }, - "System.Runtime": { "type": "build" } - } - }, - "netstandard1.3": { + "netstandard1.0": { "dependencies": { "System.Collections": "4.0.11-*", "System.Resources.ResourceManager": "4.0.1-*" }, "imports": [ - "dotnet5.4" + "dotnet5.1" ] } } diff --git a/src/Microsoft.Extensions.WebEncoders/project.json b/src/Microsoft.Extensions.WebEncoders/project.json index 1e24e36926..5b12e9999c 100644 --- a/src/Microsoft.Extensions.WebEncoders/project.json +++ b/src/Microsoft.Extensions.WebEncoders/project.json @@ -20,15 +20,9 @@ "System.Text.Encodings.Web": "4.0.0-*" }, "frameworks": { - "net451": { - "frameworkAssemblies": { - "System.IO": { "type": "build" }, - "System.Runtime": { "type": "build" } - } - }, - "netstandard1.3": { + "netstandard1.0": { "imports": [ - "dotnet5.4" + "dotnet5.1" ] } } diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json index a2b85b5cfe..5115e2741a 100644 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json @@ -22,8 +22,9 @@ ] }, "net451": { - "dependencies": { - "xunit.runner.console": "2.1.0" + "frameworkAssemblies": { + "System.IO": { "type": "build" }, + "System.Runtime": { "type": "build" } } } } diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/project.json b/test/Microsoft.Extensions.WebEncoders.Tests/project.json index 0e0c77023b..24fe63d6b1 100644 --- a/test/Microsoft.Extensions.WebEncoders.Tests/project.json +++ b/test/Microsoft.Extensions.WebEncoders.Tests/project.json @@ -22,8 +22,8 @@ ] }, "net451": { - "dependencies": { - "xunit.runner.console": "2.1.0" + "frameworkAssemblies": { + "System.Runtime": { "type": "build" } } } } From bfe81edbdc29c88a9814fbb939ea465293f960e3 Mon Sep 17 00:00:00 2001 From: Ajay Bhargav Baaskaran Date: Mon, 14 Mar 2016 14:42:18 -0700 Subject: [PATCH 081/471] Updated Json.Net version --- src/Microsoft.AspNetCore.JsonPatch/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.AspNetCore.JsonPatch/project.json b/src/Microsoft.AspNetCore.JsonPatch/project.json index abfc19cba3..f4cc9ede98 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/project.json +++ b/src/Microsoft.AspNetCore.JsonPatch/project.json @@ -13,7 +13,7 @@ "url": "git://github.com/aspnet/mvc" }, "dependencies": { - "Newtonsoft.Json": "8.0.2" + "Newtonsoft.Json": "8.0.3" }, "frameworks": { "netstandard1.1": { From 10c33445dcc7b0f2d45df8fdc803751d762c7e2e Mon Sep 17 00:00:00 2001 From: Cesar Blum Silveira Date: Mon, 14 Mar 2016 21:37:36 -0700 Subject: [PATCH 082/471] ASP.NET 5 -> ASP.NET Core --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c30d38e62f..6c27b76d9d 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,6 @@ AppVeyor: [![AppVeyor](https://ci.appveyor.com/api/projects/status/51gggjks5k3q6 Travis: [![Travis](https://travis-ci.org/aspnet/JsonPatch.svg?branch=dev)](https://travis-ci.org/aspnet/JsonPatch) -This project is part of ASP.NET 5. You can find samples, documentation and getting started instructions for ASP.NET 5 at the [Home](https://github.com/aspnet/home) repo. +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. From 66dccd14eab13387b6b0477f6b0184531dbe7149 Mon Sep 17 00:00:00 2001 From: Cesar Blum Silveira Date: Mon, 14 Mar 2016 21:43:50 -0700 Subject: [PATCH 083/471] ASP.NET 5 -> ASP.NET Core --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 799d29e1dc..c86577af48 100644 --- a/README.md +++ b/README.md @@ -6,4 +6,4 @@ Travis: [![Travis](https://travis-ci.org/aspnet/HtmlAbstractions.svg?branch=de HTML abstractions such as `IHtmlContent` and related APIs. -This project is part of ASP.NET 5. You can find samples, documentation and getting started instructions for ASP.NET 5 at the [Home](https://github.com/aspnet/home) repo. +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. From 4e396b8443bfc0c73651d25e17791fd0296097c9 Mon Sep 17 00:00:00 2001 From: Victor Hurdugaci Date: Thu, 17 Mar 2016 14:27:21 -0700 Subject: [PATCH 084/471] Remove the makefile --- makefile.shade | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 makefile.shade diff --git a/makefile.shade b/makefile.shade deleted file mode 100644 index c87524a3ef..0000000000 --- a/makefile.shade +++ /dev/null @@ -1,12 +0,0 @@ - -var VERSION='0.1' -var FULL_VERSION='0.1' -var AUTHORS='Microsoft Open Technologies, Inc.' - -use-standard-lifecycle -k-standard-goals - -#xml-docs-test .clean .build-compile description='Check generated XML documentation files for errors' target='package' - k-xml-docs-test - - From 7c1c4df3109b5df1583c8cb5ef98750aac9b95c6 Mon Sep 17 00:00:00 2001 From: Victor Hurdugaci Date: Thu, 17 Mar 2016 14:31:32 -0700 Subject: [PATCH 085/471] Remove the makefile --- makefile.shade | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 makefile.shade diff --git a/makefile.shade b/makefile.shade deleted file mode 100644 index d5e473d558..0000000000 --- a/makefile.shade +++ /dev/null @@ -1,10 +0,0 @@ - -var VERSION='0.1' -var FULL_VERSION='0.1' -var AUTHORS='Microsoft Open Technologies, Inc.' - -use-standard-lifecycle -k-standard-goals - -#xml-docs-test .clean .build-compile description='Check generated XML documentation files for errors' target='package' - k-xml-docs-test From 70c0254dc26ec7659b51cf7244324a79f311922f Mon Sep 17 00:00:00 2001 From: David Fowler Date: Fri, 25 Mar 2016 01:48:01 -0700 Subject: [PATCH 086/471] Fixed build --- .../Microsoft.AspNetCore.Html.Abstractions.Test/project.json | 5 +++-- test/Microsoft.Extensions.WebEncoders.Tests/project.json | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json index 5115e2741a..0b423932f0 100644 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json @@ -7,14 +7,15 @@ "Microsoft.AspNetCore.Html.Abstractions": "1.0.0-*", "Microsoft.AspNetCore.Testing": "1.0.0-*", "Microsoft.Extensions.WebEncoders": "1.0.0-*", - "Microsoft.NETCore.Platforms": "1.0.1-*", "xunit": "2.1.0" }, "testRunner": "xunit", "frameworks": { "netstandardapp1.5": { "dependencies": { - "dotnet-test-xunit": "1.0.0-dev-*" + "dotnet-test-xunit": "1.0.0-dev-*", + "NETStandard.Library": "1.5.0-*", + "System.Diagnostics.Process": "4.1.0-*" }, "imports": [ "dnxcore50", diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/project.json b/test/Microsoft.Extensions.WebEncoders.Tests/project.json index 24fe63d6b1..ab7264c378 100644 --- a/test/Microsoft.Extensions.WebEncoders.Tests/project.json +++ b/test/Microsoft.Extensions.WebEncoders.Tests/project.json @@ -2,7 +2,6 @@ "dependencies": { "Microsoft.Extensions.DependencyInjection": "1.0.0-*", "Microsoft.Extensions.WebEncoders": "1.0.0-*", - "Microsoft.NETCore.Platforms": "1.0.1-*", "xunit": "2.1.0" }, "testRunner": "xunit", @@ -14,7 +13,9 @@ "frameworks": { "netstandardapp1.5": { "dependencies": { - "dotnet-test-xunit": "1.0.0-dev-*" + "dotnet-test-xunit": "1.0.0-dev-*", + "NETStandard.Library": "1.5.0-*", + "System.Diagnostics.Process": "4.1.0-*" }, "imports": [ "dnxcore50", From 8965b63ec107fff486b46a03b4de4274be2f83dc Mon Sep 17 00:00:00 2001 From: David Fowler Date: Fri, 25 Mar 2016 02:02:41 -0700 Subject: [PATCH 087/471] Fixed build --- test/Microsoft.AspNetCore.JsonPatch.Test/project.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json index c8772f21fb..72fdfa43b4 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json @@ -5,15 +5,16 @@ "dependencies": { "Microsoft.AspNetCore.JsonPatch": "1.0.0-*", "Microsoft.AspNetCore.Testing": "1.0.0-*", - "xunit": "2.1.0", - "Microsoft.NETCore.Platforms": "1.0.1-*" + "xunit": "2.1.0" }, "testRunner": "xunit", "frameworks": { "netstandardapp1.5": { "dependencies": { "moq.netcore": "4.4.0-beta8", - "dotnet-test-xunit": "1.0.0-dev-*" + "dotnet-test-xunit": "1.0.0-dev-*", + "NETStandard.Library": "1.5.0-*", + "System.Diagnostics.Process": "4.1.0-*" }, "imports": [ "dnxcore50", From 98e2d5d4c729770e5e8e146602ab2b6c5bdc439a Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 24 Mar 2016 12:59:08 -0700 Subject: [PATCH 088/471] Fix dotnet restore warning --- test/Microsoft.AspNetCore.JsonPatch.Test/project.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json index 72fdfa43b4..4dcf2002cf 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json @@ -23,12 +23,12 @@ }, "net451": { "frameworkAssemblies": { - "System.Linq.Expressions": {"type": "build"}, + "System.Linq.Expressions": { "type": "build" }, + "System.Runtime": { "type": "build" }, "System.Threading.Tasks": { "type": "build" } }, "dependencies": { "Moq": "4.2.1312.1622", - "System.Runtime": "4.1.0-*", "xunit.runner.console": "2.1.0" } } From fd10621c1a3e03ae1770a4f381395b452d5c0a24 Mon Sep 17 00:00:00 2001 From: ryanbrandenburg Date: Fri, 25 Mar 2016 11:07:12 -0700 Subject: [PATCH 089/471] SetContent->SetHtmlContent --- .../HtmlContentBuilderExtensions.cs | 2 +- .../HtmlContentBuilderExtensionsTest.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilderExtensions.cs b/src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilderExtensions.cs index aaba4faefb..439b746a55 100644 --- a/src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilderExtensions.cs @@ -189,7 +189,7 @@ namespace Microsoft.AspNetCore.Html /// The . /// The value that replaces the content. /// The . - public static IHtmlContentBuilder SetContent(this IHtmlContentBuilder builder, IHtmlContent content) + public static IHtmlContentBuilder SetHtmlContent(this IHtmlContentBuilder builder, IHtmlContent content) { if (builder == null) { diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlContentBuilderExtensionsTest.cs b/test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlContentBuilderExtensionsTest.cs index 08151b3675..b985c51890 100644 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlContentBuilderExtensionsTest.cs +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlContentBuilderExtensionsTest.cs @@ -104,7 +104,7 @@ namespace Microsoft.AspNetCore.Html.Test var content = new OtherHtmlContent("Hi"); // Act - builder.SetContent(content); + builder.SetHtmlContent(content); // Assert Assert.Collection( From c5d5ef6788a895627ef25e46129c0b2783d97722 Mon Sep 17 00:00:00 2001 From: Eilon Lipton Date: Sat, 26 Mar 2016 15:00:56 -0700 Subject: [PATCH 090/471] Fix package metadata --- README.md | 2 +- src/Microsoft.AspNetCore.Html.Abstractions/project.json | 5 ++++- src/Microsoft.Extensions.WebEncoders/project.json | 5 ++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c86577af48..9939efe5b9 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,6 @@ AppVeyor: [![AppVeyor](https://ci.appveyor.com/api/projects/status/cu9y78vsdp19e Travis: [![Travis](https://travis-ci.org/aspnet/HtmlAbstractions.svg?branch=dev)](https://travis-ci.org/aspnet/HtmlAbstractions) -HTML abstractions such as `IHtmlContent` and related APIs. +HTML abstractions used for building HTML content, including types such as `HtmlEncodedString` and `IHtmlContent`. 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. diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/project.json b/src/Microsoft.AspNetCore.Html.Abstractions/project.json index fc92b6e725..500041c2ed 100644 --- a/src/Microsoft.AspNetCore.Html.Abstractions/project.json +++ b/src/Microsoft.AspNetCore.Html.Abstractions/project.json @@ -1,6 +1,9 @@ { "version": "1.0.0-*", - "description": "ASP.NET 5 HTML content interface.", + "description": "ASP.NET Core HTML abstractions used for building HTML content.\r\nCommonly used types:\r\nMicrosoft.AspNetCore.Html.HtmlEncodedString\r\nMicrosoft.AspNetCore.Html.IHtmlContent", + "tags": [ + "aspnetcore" + ], "repository": { "type": "git", "url": "git://github.com/aspnet/htmlabstractions" diff --git a/src/Microsoft.Extensions.WebEncoders/project.json b/src/Microsoft.Extensions.WebEncoders/project.json index 5b12e9999c..70be4220b9 100644 --- a/src/Microsoft.Extensions.WebEncoders/project.json +++ b/src/Microsoft.Extensions.WebEncoders/project.json @@ -1,6 +1,9 @@ { "version": "1.0.0-*", - "description": "Contains registration and configuration APIs for the core framework encoders.", + "description": "Contains registration and configuration APIs to add the core framework encoders to a dependency injection container.", + "tags": [ + "aspnetcore" + ], "repository": { "type": "git", "url": "git://github.com/aspnet/httpabstractions" From 794d0892ae6975014d3bfb393c9d7646511d81bc Mon Sep 17 00:00:00 2001 From: jacalvar Date: Mon, 28 Mar 2016 15:26:49 -0700 Subject: [PATCH 091/471] Return IServiceCollection from AddWebEncoders extension methods --- .../EncoderServiceCollectionExtensions.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.Extensions.WebEncoders/EncoderServiceCollectionExtensions.cs b/src/Microsoft.Extensions.WebEncoders/EncoderServiceCollectionExtensions.cs index 317d88f99d..72f5e369a1 100644 --- a/src/Microsoft.Extensions.WebEncoders/EncoderServiceCollectionExtensions.cs +++ b/src/Microsoft.Extensions.WebEncoders/EncoderServiceCollectionExtensions.cs @@ -19,8 +19,8 @@ namespace Microsoft.Extensions.DependencyInjection /// to the specified . /// /// The . - /// The instance after the encoders have been added. - public static void AddWebEncoders(this IServiceCollection services) + /// The so that additional calls can be chained. + public static IServiceCollection AddWebEncoders(this IServiceCollection services) { if (services == null) { @@ -37,6 +37,8 @@ namespace Microsoft.Extensions.DependencyInjection CreateFactory(() => JavaScriptEncoder.Default, settings => JavaScriptEncoder.Create(settings))); services.TryAddSingleton( CreateFactory(() => UrlEncoder.Default, settings => UrlEncoder.Create(settings))); + + return services; } /// @@ -45,7 +47,8 @@ namespace Microsoft.Extensions.DependencyInjection /// /// The . /// An to configure the provided . - public static void AddWebEncoders(this IServiceCollection services, Action setupAction) + /// The so that additional calls can be chained. + public static IServiceCollection AddWebEncoders(this IServiceCollection services, Action setupAction) { if (services == null) { @@ -59,6 +62,8 @@ namespace Microsoft.Extensions.DependencyInjection services.AddWebEncoders(); services.Configure(setupAction); + + return services; } private static Func CreateFactory( From 5e2ef6051955e73e2c86c4436e581bc650123d68 Mon Sep 17 00:00:00 2001 From: Victor Hurdugaci Date: Wed, 30 Mar 2016 15:40:25 -0700 Subject: [PATCH 092/471] Webhooks notification --- .travis.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 304e307169..dae036065b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,4 +23,10 @@ branches: - dev - /^(.*\/)?ci-.*$/ script: - - ./build.sh --quiet verify \ No newline at end of file + - ./build.sh --quiet verify +notifications: + webhooks: + secure: "d87o+y2WUx204s8TfSaEuekYudnSyyPaFEXkuzgs3uAyzkKAm/Hx0xcMSuKDqWhYmKaxL7VtgEd2z7mltr2cHZ4oyCrsf6V5v4iI48ojaGykqFXfv8ld6khmLwtdkC32lF2YyuDNL8kUvKNdP9jkrWlpoO/WC6QEqAUxdOuuLo/wLyfrPLbzIvbojwveXbmcwvsfDizLdZdVd88FZSV41h+yBKLnyhpeqRvHG85BTgT/GmVB7Vyjs3yChiS639Aq5DoOP8jBaRdB8Bqs09KibFXzJwDBlKvALIqiwzog3hpd5SVxrgOTCkWbOwqq4TSkahDE425W3vFbmLDANgdfsyAkqgt8daE2BkFTojEHQED+u9CEd8oJVX6FoGnYpuDzge4FVh9iG3HSuKwoVdlONzzew4oJ75iQ+0f67ZNV9oDuScdva/SGb2gYgVUkeJIjDoMxKuaZyhbBT9jRXRBI+LsIjziEhLU/649FjTSmQx0HLpcT7+kaeSmhqT9JffVLidMdvZwhPZsLxPSG9UVBH9G8rdyHXP2e0ZlicHNjjNV6kbDqfDPhHx2/MfZGugsJXjOONKu/5LZduQzmAOysqdLKqkBVkMq2xl7aGV+yVZAtTmZB3nqOWGyKlFC9kLGO+qlJ4tBac26lHCZWTK+4VOAtN5Dag0DkDikgGdZaq78=" + on_success: always + on_failure: always + on_start: always \ No newline at end of file From 7eb34ad25775f0c5d0c4f1055954d2429ad7ef57 Mon Sep 17 00:00:00 2001 From: David Fowler Date: Thu, 31 Mar 2016 12:08:59 -0700 Subject: [PATCH 093/471] Update project.json Fixed System.Runtime.Serialization.Primitives version --- src/Microsoft.AspNetCore.JsonPatch/project.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.AspNetCore.JsonPatch/project.json b/src/Microsoft.AspNetCore.JsonPatch/project.json index f4cc9ede98..9749ef91a1 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/project.json +++ b/src/Microsoft.AspNetCore.JsonPatch/project.json @@ -27,7 +27,7 @@ "System.Reflection.Extensions": "4.0.1-*", "System.Resources.ResourceManager": "4.0.1-*", "System.Runtime.Extensions": "4.1.0-*", - "System.Runtime.Serialization.Primitives": "4.1.0-*", + "System.Runtime.Serialization.Primitives": "4.1.1-*", "System.Text.Encoding.Extensions": "4.0.11-*" }, "imports": [ @@ -36,4 +36,4 @@ ] } } -} \ No newline at end of file +} From 1de783c26bf158d0005a1328c265961f5efcdeb9 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 6 Apr 2016 09:45:27 -0700 Subject: [PATCH 094/471] Updating to release. --- NuGet.config | 4 ++-- build.ps1 | 2 +- build.sh | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/NuGet.config b/NuGet.config index 5500f6d507..71b9724a09 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,7 @@ - + - + diff --git a/build.ps1 b/build.ps1 index 8f2f99691a..cf8bff13bb 100644 --- a/build.ps1 +++ b/build.ps1 @@ -33,7 +33,7 @@ cd $PSScriptRoot $repoFolder = $PSScriptRoot $env:REPO_FOLDER = $repoFolder -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/release.zip" if ($env:KOREBUILD_ZIP) { $koreBuildZip=$env:KOREBUILD_ZIP diff --git a/build.sh b/build.sh index f4208100eb..f88fe4052e 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/release.zip" if [ ! -z $KOREBUILD_ZIP ]; then koreBuildZip=$KOREBUILD_ZIP fi From ffaf2c8b23aa22708c28b58916a179db16883df1 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 6 Apr 2016 09:46:06 -0700 Subject: [PATCH 095/471] Updating to release. --- NuGet.config | 4 ++-- build.ps1 | 2 +- build.sh | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/NuGet.config b/NuGet.config index 03704957e8..9db87a421e 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,7 @@ - + - + \ No newline at end of file diff --git a/build.ps1 b/build.ps1 index 8f2f99691a..cf8bff13bb 100644 --- a/build.ps1 +++ b/build.ps1 @@ -33,7 +33,7 @@ cd $PSScriptRoot $repoFolder = $PSScriptRoot $env:REPO_FOLDER = $repoFolder -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/release.zip" if ($env:KOREBUILD_ZIP) { $koreBuildZip=$env:KOREBUILD_ZIP diff --git a/build.sh b/build.sh index f4208100eb..f88fe4052e 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/release.zip" if [ ! -z $KOREBUILD_ZIP ]; then koreBuildZip=$KOREBUILD_ZIP fi From 89c9c3260b2cbc8fe40c5cceb63a411a7c62b3b8 Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Wed, 6 Apr 2016 13:46:26 -0700 Subject: [PATCH 096/471] Make HtmlFormattableString public We've had this class for a while backing the implementation of the AppendFormat extension method. Making this public so we can use it in MVC in localization. Some updates to the API surface and name to be aligned with System.FormattableString --- .../HtmlContentBuilderExtensions.cs | 146 +----------- .../HtmlFormattableString.cs | 184 +++++++++++++++ .../HtmlFormattableStringTest.cs | 217 ++++++++++++++++++ 3 files changed, 403 insertions(+), 144 deletions(-) create mode 100644 src/Microsoft.AspNetCore.Html.Abstractions/HtmlFormattableString.cs create mode 100644 test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlFormattableStringTest.cs diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilderExtensions.cs b/src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilderExtensions.cs index 439b746a55..f7474ca3f2 100644 --- a/src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilderExtensions.cs @@ -48,7 +48,7 @@ namespace Microsoft.AspNetCore.Html throw new ArgumentNullException(nameof(args)); } - builder.AppendHtml(new HtmlFormatString(format, args)); + builder.AppendHtml(new HtmlFormattableString(format, args)); return builder; } @@ -88,7 +88,7 @@ namespace Microsoft.AspNetCore.Html throw new ArgumentNullException(nameof(args)); } - builder.AppendHtml(new HtmlFormatString(formatProvider, format, args)); + builder.AppendHtml(new HtmlFormattableString(formatProvider, format, args)); return builder; } @@ -219,147 +219,5 @@ namespace Microsoft.AspNetCore.Html builder.AppendHtml(encoded); return builder; } - - [DebuggerDisplay("{DebuggerToString()}")] - private class HtmlFormatString : IHtmlContent - { - private readonly IFormatProvider _formatProvider; - private readonly string _format; - private readonly object[] _args; - - public HtmlFormatString(string format, object[] args) - : this(null, format, args) - { - } - - public HtmlFormatString(IFormatProvider formatProvider, string format, object[] args) - { - Debug.Assert(format != null); - Debug.Assert(args != null); - - _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; - - 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 HtmlEncodedString or IHtmlContent instance - // to do the right thing with encoding. - var htmlString = arg as HtmlEncodedString; - if (htmlString != null) - { - return htmlString.ToString(); - } - - var htmlContent = arg as IHtmlContent; - if (htmlContent != null) - { - using (var writer = new StringWriter()) - { - htmlContent.WriteTo(writer, _encoder); - return writer.ToString(); - } - } - - // 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/Microsoft.AspNetCore.Html.Abstractions/HtmlFormattableString.cs b/src/Microsoft.AspNetCore.Html.Abstractions/HtmlFormattableString.cs new file mode 100644 index 0000000000..82e9b69d98 --- /dev/null +++ b/src/Microsoft.AspNetCore.Html.Abstractions/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 HtmlEncodedString or IHtmlContent instance + // to do the right thing with encoding. + var htmlString = arg as HtmlEncodedString; + 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/test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlFormattableStringTest.cs b/test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlFormattableStringTest.cs new file mode 100644 index 0000000000..6f466e6046 --- /dev/null +++ b/test/Microsoft.AspNetCore.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_WithHtmlEncodedString() + { + // Arrange + var formattableString = new HtmlFormattableString("{0}!", new HtmlEncodedString("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 HtmlEncodedString("Birthday"), + new HtmlContentBuilder().Append("Billy")); + + // Act + var result = HtmlContentToString(formattableString); + + // Assert + Assert.Equal("Happy Birthday, HtmlEncode[[Billy]]!", result); + } + + [Fact] + public void HtmlFormattableString_WithHtmlEncodedString_AndOffset() + { + // Arrange + var formattableString = new HtmlFormattableString("{0, 20}!", new HtmlEncodedString("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(); + } + } + } +} From aeb3939ac8418b072db5a8472f876315b5e975c9 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 7 Apr 2016 15:17:00 -0700 Subject: [PATCH 097/471] Removing imports from src projects --- src/Microsoft.AspNetCore.JsonPatch/project.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Microsoft.AspNetCore.JsonPatch/project.json b/src/Microsoft.AspNetCore.JsonPatch/project.json index 9749ef91a1..1d736bfde3 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/project.json +++ b/src/Microsoft.AspNetCore.JsonPatch/project.json @@ -31,9 +31,8 @@ "System.Text.Encoding.Extensions": "4.0.11-*" }, "imports": [ - "dotnet5.2", "portable-net451+win8" ] } } -} +} \ No newline at end of file From 4d9d196b4a4bbe23e68174c5eac03a88d68a91c9 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 7 Apr 2016 15:27:11 -0700 Subject: [PATCH 098/471] Removing imports from src projects --- src/Microsoft.AspNetCore.Html.Abstractions/project.json | 5 +---- src/Microsoft.Extensions.WebEncoders/project.json | 6 +----- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/project.json b/src/Microsoft.AspNetCore.Html.Abstractions/project.json index 500041c2ed..69b0215834 100644 --- a/src/Microsoft.AspNetCore.Html.Abstractions/project.json +++ b/src/Microsoft.AspNetCore.Html.Abstractions/project.json @@ -24,10 +24,7 @@ "dependencies": { "System.Collections": "4.0.11-*", "System.Resources.ResourceManager": "4.0.1-*" - }, - "imports": [ - "dotnet5.1" - ] + } } } } \ No newline at end of file diff --git a/src/Microsoft.Extensions.WebEncoders/project.json b/src/Microsoft.Extensions.WebEncoders/project.json index 70be4220b9..beeac94efe 100644 --- a/src/Microsoft.Extensions.WebEncoders/project.json +++ b/src/Microsoft.Extensions.WebEncoders/project.json @@ -23,10 +23,6 @@ "System.Text.Encodings.Web": "4.0.0-*" }, "frameworks": { - "netstandard1.0": { - "imports": [ - "dotnet5.1" - ] - } + "netstandard1.0": {} } } \ No newline at end of file From 78d3428eb7494f7f8e53fc15b5ca8e84a892ed55 Mon Sep 17 00:00:00 2001 From: Eilon Lipton Date: Tue, 12 Apr 2016 19:06:55 -0700 Subject: [PATCH 099/471] Fix package metadata --- src/Microsoft.AspNetCore.JsonPatch/project.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.AspNetCore.JsonPatch/project.json b/src/Microsoft.AspNetCore.JsonPatch/project.json index 1d736bfde3..0eeb88f010 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/project.json +++ b/src/Microsoft.AspNetCore.JsonPatch/project.json @@ -1,5 +1,11 @@ { "version": "1.0.0-*", + "description": "ASP.NET Core support for JSON PATCH.", + "tags": [ + "aspnetcore", + "json", + "jsonpatch" + ], "compilationOptions": { "warningsAsErrors": true, "keyFile": "../../tools/Key.snk", @@ -10,7 +16,7 @@ }, "repository": { "type": "git", - "url": "git://github.com/aspnet/mvc" + "url": "git://github.com/aspnet/jsonpatch" }, "dependencies": { "Newtonsoft.Json": "8.0.3" From 98b73cbec5f845cddf1dcffc03ed4cb1d204a7b9 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Thu, 14 Apr 2016 14:01:34 -0700 Subject: [PATCH 100/471] Migrate tests, tools and samples to portable --- .../project.json | 15 +++++++++++---- .../project.json | 11 ++++++++--- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json index 0b423932f0..f05677f95c 100644 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json @@ -11,10 +11,13 @@ }, "testRunner": "xunit", "frameworks": { - "netstandardapp1.5": { + "netcoreapp1.0": { "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.0.0-*", + "type": "platform" + }, "dotnet-test-xunit": "1.0.0-dev-*", - "NETStandard.Library": "1.5.0-*", "System.Diagnostics.Process": "4.1.0-*" }, "imports": [ @@ -24,8 +27,12 @@ }, "net451": { "frameworkAssemblies": { - "System.IO": { "type": "build" }, - "System.Runtime": { "type": "build" } + "System.IO": { + "type": "build" + }, + "System.Runtime": { + "type": "build" + } } } } diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/project.json b/test/Microsoft.Extensions.WebEncoders.Tests/project.json index ab7264c378..63433fa2c6 100644 --- a/test/Microsoft.Extensions.WebEncoders.Tests/project.json +++ b/test/Microsoft.Extensions.WebEncoders.Tests/project.json @@ -11,10 +11,13 @@ "keyFile": "../../tools/Key.snk" }, "frameworks": { - "netstandardapp1.5": { + "netcoreapp1.0": { "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.0.0-*", + "type": "platform" + }, "dotnet-test-xunit": "1.0.0-dev-*", - "NETStandard.Library": "1.5.0-*", "System.Diagnostics.Process": "4.1.0-*" }, "imports": [ @@ -24,7 +27,9 @@ }, "net451": { "frameworkAssemblies": { - "System.Runtime": { "type": "build" } + "System.Runtime": { + "type": "build" + } } } } From 9337f3e48e1d609b3d88e129a5676ec3185b2cb2 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Mon, 18 Apr 2016 16:28:14 -0700 Subject: [PATCH 101/471] Migrate tests, tools and samples to portable --- .../project.json | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json index 4dcf2002cf..9455e29da1 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json @@ -3,18 +3,23 @@ "warningsAsErrors": true }, "dependencies": { + "Microsoft.NETCore.Platforms": "1.0.1-*", "Microsoft.AspNetCore.JsonPatch": "1.0.0-*", "Microsoft.AspNetCore.Testing": "1.0.0-*", "xunit": "2.1.0" }, "testRunner": "xunit", "frameworks": { - "netstandardapp1.5": { + "netcoreapp1.0": { "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.0.0-*", + "type": "platform" + }, "moq.netcore": "4.4.0-beta8", "dotnet-test-xunit": "1.0.0-dev-*", - "NETStandard.Library": "1.5.0-*", - "System.Diagnostics.Process": "4.1.0-*" + "System.Diagnostics.Process": "4.1.0-*", + "System.Diagnostics.TraceSource": "4.0.0-*" }, "imports": [ "dnxcore50", @@ -23,9 +28,15 @@ }, "net451": { "frameworkAssemblies": { - "System.Linq.Expressions": { "type": "build" }, - "System.Runtime": { "type": "build" }, - "System.Threading.Tasks": { "type": "build" } + "System.Linq.Expressions": { + "type": "build" + }, + "System.Runtime": { + "type": "build" + }, + "System.Threading.Tasks": { + "type": "build" + } }, "dependencies": { "Moq": "4.2.1312.1622", From f94faf427623012a3f760ccffb3aba59f004e00e Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Mon, 18 Apr 2016 16:36:54 -0700 Subject: [PATCH 102/471] Bring Microsoft.NETCore.Platforms dependency back --- test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json | 1 + test/Microsoft.Extensions.WebEncoders.Tests/project.json | 1 + 2 files changed, 2 insertions(+) diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json index f05677f95c..6a1156028f 100644 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json @@ -4,6 +4,7 @@ "keyFile": "../../tools/Key.snk" }, "dependencies": { + "Microsoft.NETCore.Platforms": "1.0.1-*", "Microsoft.AspNetCore.Html.Abstractions": "1.0.0-*", "Microsoft.AspNetCore.Testing": "1.0.0-*", "Microsoft.Extensions.WebEncoders": "1.0.0-*", diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/project.json b/test/Microsoft.Extensions.WebEncoders.Tests/project.json index 63433fa2c6..69cdc308b0 100644 --- a/test/Microsoft.Extensions.WebEncoders.Tests/project.json +++ b/test/Microsoft.Extensions.WebEncoders.Tests/project.json @@ -1,5 +1,6 @@ { "dependencies": { + "Microsoft.NETCore.Platforms": "1.0.1-*", "Microsoft.Extensions.DependencyInjection": "1.0.0-*", "Microsoft.Extensions.WebEncoders": "1.0.0-*", "xunit": "2.1.0" From cfc071071b00f51d0fc8f1d8e2f3033b145d7af7 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 19 Apr 2016 14:54:02 -0700 Subject: [PATCH 103/471] Use latest build of dotnet-test-xunit --- test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json | 2 +- test/Microsoft.Extensions.WebEncoders.Tests/project.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json index 6a1156028f..15b3e92d51 100644 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json @@ -18,7 +18,7 @@ "version": "1.0.0-*", "type": "platform" }, - "dotnet-test-xunit": "1.0.0-dev-*", + "dotnet-test-xunit": "1.0.0-*", "System.Diagnostics.Process": "4.1.0-*" }, "imports": [ diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/project.json b/test/Microsoft.Extensions.WebEncoders.Tests/project.json index 69cdc308b0..43836130e5 100644 --- a/test/Microsoft.Extensions.WebEncoders.Tests/project.json +++ b/test/Microsoft.Extensions.WebEncoders.Tests/project.json @@ -18,7 +18,7 @@ "version": "1.0.0-*", "type": "platform" }, - "dotnet-test-xunit": "1.0.0-dev-*", + "dotnet-test-xunit": "1.0.0-*", "System.Diagnostics.Process": "4.1.0-*" }, "imports": [ From 088d8b291ac4beaddebd6ec0a97747ef3dc7ba12 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 19 Apr 2016 14:54:04 -0700 Subject: [PATCH 104/471] Use latest build of dotnet-test-xunit --- test/Microsoft.AspNetCore.JsonPatch.Test/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json index 9455e29da1..8dfb164801 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json @@ -17,7 +17,7 @@ "type": "platform" }, "moq.netcore": "4.4.0-beta8", - "dotnet-test-xunit": "1.0.0-dev-*", + "dotnet-test-xunit": "1.0.0-*", "System.Diagnostics.Process": "4.1.0-*", "System.Diagnostics.TraceSource": "4.0.0-*" }, From a97ac1b23bbbe6e77042f874cc7b79d827632a97 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 2 May 2016 11:27:16 -0700 Subject: [PATCH 105/471] Fix build warnings --- .../project.json | 16 +++++++++------- .../project.json | 16 +++++++++------- .../project.json | 4 ++-- .../project.json | 4 ++-- 4 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/project.json b/src/Microsoft.AspNetCore.Html.Abstractions/project.json index 69b0215834..d117f96abe 100644 --- a/src/Microsoft.AspNetCore.Html.Abstractions/project.json +++ b/src/Microsoft.AspNetCore.Html.Abstractions/project.json @@ -1,14 +1,16 @@ { "version": "1.0.0-*", "description": "ASP.NET Core HTML abstractions used for building HTML content.\r\nCommonly used types:\r\nMicrosoft.AspNetCore.Html.HtmlEncodedString\r\nMicrosoft.AspNetCore.Html.IHtmlContent", - "tags": [ - "aspnetcore" - ], - "repository": { - "type": "git", - "url": "git://github.com/aspnet/htmlabstractions" + "packOptions": { + "repository": { + "type": "git", + "url": "git://github.com/aspnet/htmlabstractions" + }, + "tags": [ + "aspnetcore" + ] }, - "compilationOptions": { + "buildOptions": { "warningsAsErrors": true, "keyFile": "../../tools/Key.snk", "nowarn": [ diff --git a/src/Microsoft.Extensions.WebEncoders/project.json b/src/Microsoft.Extensions.WebEncoders/project.json index beeac94efe..857361e4e4 100644 --- a/src/Microsoft.Extensions.WebEncoders/project.json +++ b/src/Microsoft.Extensions.WebEncoders/project.json @@ -1,14 +1,16 @@ { "version": "1.0.0-*", "description": "Contains registration and configuration APIs to add the core framework encoders to a dependency injection container.", - "tags": [ - "aspnetcore" - ], - "repository": { - "type": "git", - "url": "git://github.com/aspnet/httpabstractions" + "packOptions": { + "repository": { + "type": "git", + "url": "git://github.com/aspnet/httpabstractions" + }, + "tags": [ + "aspnetcore" + ] }, - "compilationOptions": { + "buildOptions": { "warningsAsErrors": true, "allowUnsafe": true, "keyFile": "../../tools/Key.snk", diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json index 15b3e92d51..2efabff127 100644 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json @@ -1,9 +1,10 @@ { - "compilationOptions": { + "buildOptions": { "warningsAsErrors": true, "keyFile": "../../tools/Key.snk" }, "dependencies": { + "dotnet-test-xunit": "1.0.0-*", "Microsoft.NETCore.Platforms": "1.0.1-*", "Microsoft.AspNetCore.Html.Abstractions": "1.0.0-*", "Microsoft.AspNetCore.Testing": "1.0.0-*", @@ -18,7 +19,6 @@ "version": "1.0.0-*", "type": "platform" }, - "dotnet-test-xunit": "1.0.0-*", "System.Diagnostics.Process": "4.1.0-*" }, "imports": [ diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/project.json b/test/Microsoft.Extensions.WebEncoders.Tests/project.json index 43836130e5..2cb866fcc3 100644 --- a/test/Microsoft.Extensions.WebEncoders.Tests/project.json +++ b/test/Microsoft.Extensions.WebEncoders.Tests/project.json @@ -1,12 +1,13 @@ { "dependencies": { + "dotnet-test-xunit": "1.0.0-*", "Microsoft.NETCore.Platforms": "1.0.1-*", "Microsoft.Extensions.DependencyInjection": "1.0.0-*", "Microsoft.Extensions.WebEncoders": "1.0.0-*", "xunit": "2.1.0" }, "testRunner": "xunit", - "compilationOptions": { + "buildOptions": { "allowUnsafe": true, "warningsAsErrors": true, "keyFile": "../../tools/Key.snk" @@ -18,7 +19,6 @@ "version": "1.0.0-*", "type": "platform" }, - "dotnet-test-xunit": "1.0.0-*", "System.Diagnostics.Process": "4.1.0-*" }, "imports": [ From 2cd905dd44caff74332a8dc85b7fbcd253f79387 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 2 May 2016 11:27:18 -0700 Subject: [PATCH 106/471] Fix build warnings --- .../project.json | 20 ++++++++++--------- .../project.json | 4 ++-- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/Microsoft.AspNetCore.JsonPatch/project.json b/src/Microsoft.AspNetCore.JsonPatch/project.json index 0eeb88f010..1860893f6b 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/project.json +++ b/src/Microsoft.AspNetCore.JsonPatch/project.json @@ -1,12 +1,7 @@ { "version": "1.0.0-*", "description": "ASP.NET Core support for JSON PATCH.", - "tags": [ - "aspnetcore", - "json", - "jsonpatch" - ], - "compilationOptions": { + "buildOptions": { "warningsAsErrors": true, "keyFile": "../../tools/Key.snk", "nowarn": [ @@ -14,9 +9,16 @@ ], "xmlDoc": true }, - "repository": { - "type": "git", - "url": "git://github.com/aspnet/jsonpatch" + "packOptions": { + "repository": { + "type": "git", + "url": "git://github.com/aspnet/jsonpatch" + }, + "tags": [ + "aspnetcore", + "json", + "jsonpatch" + ] }, "dependencies": { "Newtonsoft.Json": "8.0.3" diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json index 8dfb164801..dac020cb6c 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json @@ -1,8 +1,9 @@ { - "compilationOptions": { + "buildOptions": { "warningsAsErrors": true }, "dependencies": { + "dotnet-test-xunit": "1.0.0-*", "Microsoft.NETCore.Platforms": "1.0.1-*", "Microsoft.AspNetCore.JsonPatch": "1.0.0-*", "Microsoft.AspNetCore.Testing": "1.0.0-*", @@ -17,7 +18,6 @@ "type": "platform" }, "moq.netcore": "4.4.0-beta8", - "dotnet-test-xunit": "1.0.0-*", "System.Diagnostics.Process": "4.1.0-*", "System.Diagnostics.TraceSource": "4.0.0-*" }, From fe563b1459e9c913b9fb2a0fadf212fb64adf036 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Mon, 16 May 2016 16:06:01 -0700 Subject: [PATCH 107/471] Rename `HtmlEncodedString` => `HtmlString`. - This rename makes the type more consistent with its `HtmlContentBuilder` counterparts (`AppendHtml`). #25 --- README.md | 2 +- .../HtmlContentBuilder.cs | 2 +- .../HtmlContentBuilderExtensions.cs | 8 ++++---- .../HtmlFormattableString.cs | 6 +++--- .../{HtmlEncodedString.cs => HtmlString.cs} | 15 ++++++++++----- .../project.json | 2 +- .../HtmlContentBuilderExtensionsTest.cs | 4 ++-- .../HtmlFormattableStringTest.cs | 10 +++++----- 8 files changed, 27 insertions(+), 22 deletions(-) rename src/Microsoft.AspNetCore.Html.Abstractions/{HtmlEncodedString.cs => HtmlString.cs} (71%) diff --git a/README.md b/README.md index 9939efe5b9..a1e3579e7a 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,6 @@ AppVeyor: [![AppVeyor](https://ci.appveyor.com/api/projects/status/cu9y78vsdp19e Travis: [![Travis](https://travis-ci.org/aspnet/HtmlAbstractions.svg?branch=dev)](https://travis-ci.org/aspnet/HtmlAbstractions) -HTML abstractions used for building HTML content, including types such as `HtmlEncodedString` and `IHtmlContent`. +HTML abstractions used for building HTML content, including types such as `HtmlString` and `IHtmlContent`. 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. diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilder.cs b/src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilder.cs index be218244b0..864f3c8a65 100644 --- a/src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilder.cs +++ b/src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilder.cs @@ -83,7 +83,7 @@ namespace Microsoft.AspNetCore.Html { if (!string.IsNullOrEmpty(encoded)) { - Entries.Add(new HtmlEncodedString(encoded)); + Entries.Add(new HtmlString(encoded)); } return this; diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilderExtensions.cs b/src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilderExtensions.cs index f7474ca3f2..a5a83fdbb3 100644 --- a/src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilderExtensions.cs @@ -104,7 +104,7 @@ namespace Microsoft.AspNetCore.Html throw new ArgumentNullException(nameof(builder)); } - builder.AppendHtml(HtmlEncodedString.NewLine); + builder.AppendHtml(HtmlString.NewLine); return builder; } @@ -123,7 +123,7 @@ namespace Microsoft.AspNetCore.Html } builder.Append(unencoded); - builder.AppendHtml(HtmlEncodedString.NewLine); + builder.AppendHtml(HtmlString.NewLine); return builder; } @@ -141,7 +141,7 @@ namespace Microsoft.AspNetCore.Html } builder.AppendHtml(content); - builder.AppendHtml(HtmlEncodedString.NewLine); + builder.AppendHtml(HtmlString.NewLine); return builder; } @@ -160,7 +160,7 @@ namespace Microsoft.AspNetCore.Html } builder.AppendHtml(encoded); - builder.AppendHtml(HtmlEncodedString.NewLine); + builder.AppendHtml(HtmlString.NewLine); return builder; } diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/HtmlFormattableString.cs b/src/Microsoft.AspNetCore.Html.Abstractions/HtmlFormattableString.cs index 82e9b69d98..24bc7c5e2f 100644 --- a/src/Microsoft.AspNetCore.Html.Abstractions/HtmlFormattableString.cs +++ b/src/Microsoft.AspNetCore.Html.Abstractions/HtmlFormattableString.cs @@ -10,7 +10,7 @@ using System.Text.Encodings.Web; namespace Microsoft.AspNetCore.Html { /// - /// An implementation of composite string formatting + /// An implementation of composite string formatting /// (see https://msdn.microsoft.com/en-us/library/txafckwd(v=vs.110).aspx) which HTML encodes /// formatted arguments. /// @@ -107,9 +107,9 @@ namespace Microsoft.AspNetCore.Html public string Format(string format, object arg, IFormatProvider formatProvider) { - // These are the cases we need to special case. We trust the HtmlEncodedString or IHtmlContent instance + // 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 HtmlEncodedString; + var htmlString = arg as HtmlString; if (htmlString != null) { return htmlString.ToString(); diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/HtmlEncodedString.cs b/src/Microsoft.AspNetCore.Html.Abstractions/HtmlString.cs similarity index 71% rename from src/Microsoft.AspNetCore.Html.Abstractions/HtmlEncodedString.cs rename to src/Microsoft.AspNetCore.Html.Abstractions/HtmlString.cs index bf38ac3682..e7a516bd04 100644 --- a/src/Microsoft.AspNetCore.Html.Abstractions/HtmlEncodedString.cs +++ b/src/Microsoft.AspNetCore.Html.Abstractions/HtmlString.cs @@ -10,18 +10,23 @@ namespace Microsoft.AspNetCore.Html /// /// An implementation that wraps an HTML encoded . /// - public class HtmlEncodedString : IHtmlContent + public class HtmlString : IHtmlContent { /// - /// An instance for . + /// An instance for . /// - public static readonly IHtmlContent NewLine = new HtmlEncodedString(Environment.NewLine); + public static readonly HtmlString NewLine = new HtmlString(Environment.NewLine); /// - /// Creates a new . + /// An instance for . + /// + public static readonly HtmlString Empty = new HtmlString(string.Empty); + + /// + /// Creates a new . /// /// The HTML encoded value. - public HtmlEncodedString(string value) + public HtmlString(string value) { Value = value; } diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/project.json b/src/Microsoft.AspNetCore.Html.Abstractions/project.json index d117f96abe..72763e5b05 100644 --- a/src/Microsoft.AspNetCore.Html.Abstractions/project.json +++ b/src/Microsoft.AspNetCore.Html.Abstractions/project.json @@ -1,6 +1,6 @@ { "version": "1.0.0-*", - "description": "ASP.NET Core HTML abstractions used for building HTML content.\r\nCommonly used types:\r\nMicrosoft.AspNetCore.Html.HtmlEncodedString\r\nMicrosoft.AspNetCore.Html.IHtmlContent", + "description": "ASP.NET Core HTML abstractions used for building HTML content.\r\nCommonly used types:\r\nMicrosoft.AspNetCore.Html.HtmlString\r\nMicrosoft.AspNetCore.Html.IHtmlContent", "packOptions": { "repository": { "type": "git", diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlContentBuilderExtensionsTest.cs b/test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlContentBuilderExtensionsTest.cs index b985c51890..c14daeeebb 100644 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlContentBuilderExtensionsTest.cs +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlContentBuilderExtensionsTest.cs @@ -159,13 +159,13 @@ namespace Microsoft.AspNetCore.Html.Test } [Fact] - public void Builder_AppendFormat_HtmlEncodedString() + public void Builder_AppendFormat_HtmlString() { // Arrange var builder = new TestHtmlContentBuilder(); // Act - builder.AppendFormat("{0}!", new HtmlEncodedString("First")); + builder.AppendFormat("{0}!", new HtmlString("First")); // Assert Assert.Equal("First!", HtmlContentToString(builder)); diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlFormattableStringTest.cs b/test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlFormattableStringTest.cs index 6f466e6046..64e000751e 100644 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlFormattableStringTest.cs +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlFormattableStringTest.cs @@ -54,10 +54,10 @@ namespace Microsoft.AspNetCore.Html } [Fact] - public void HtmlFormattableString_WithHtmlEncodedString() + public void HtmlFormattableString_WithHtmlString() { // Arrange - var formattableString = new HtmlFormattableString("{0}!", new HtmlEncodedString("First")); + var formattableString = new HtmlFormattableString("{0}!", new HtmlString("First")); // Act var result = HtmlContentToString(formattableString); @@ -89,7 +89,7 @@ namespace Microsoft.AspNetCore.Html // Arrange var formattableString = new HtmlFormattableString( "Happy {0}, {1}!", - new HtmlEncodedString("Birthday"), + new HtmlString("Birthday"), new HtmlContentBuilder().Append("Billy")); // Act @@ -100,10 +100,10 @@ namespace Microsoft.AspNetCore.Html } [Fact] - public void HtmlFormattableString_WithHtmlEncodedString_AndOffset() + public void HtmlFormattableString_WithHtmlString_AndOffset() { // Arrange - var formattableString = new HtmlFormattableString("{0, 20}!", new HtmlEncodedString("First")); + var formattableString = new HtmlFormattableString("{0, 20}!", new HtmlString("First")); // Act var result = HtmlContentToString(formattableString); From ca1e53bb34ace9802dd20df8e555d1ce4b1a29d7 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Tue, 17 May 2016 12:28:18 -0700 Subject: [PATCH 108/471] Update minor version of TypeConverter (#22) --- src/Microsoft.AspNetCore.JsonPatch/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.AspNetCore.JsonPatch/project.json b/src/Microsoft.AspNetCore.JsonPatch/project.json index 1860893f6b..d01e21cbb9 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/project.json +++ b/src/Microsoft.AspNetCore.JsonPatch/project.json @@ -28,7 +28,7 @@ "dependencies": { "Microsoft.CSharp": "4.0.1-*", "System.Collections.Concurrent": "4.0.12-*", - "System.ComponentModel.TypeConverter": "4.0.1-*", + "System.ComponentModel.TypeConverter": "4.1.0-*", "System.Diagnostics.Debug": "4.0.11-*", "System.Globalization": "4.0.11-*", "System.Linq": "4.1.0-*", From 47ee8e0cfaa002cce1c57d3f22b40eed9ffd5cb7 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 18 May 2016 09:44:47 -0700 Subject: [PATCH 109/471] Revert "Update minor version of TypeConverter (#22)" This reverts commit ca1e53bb34ace9802dd20df8e555d1ce4b1a29d7. --- src/Microsoft.AspNetCore.JsonPatch/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.AspNetCore.JsonPatch/project.json b/src/Microsoft.AspNetCore.JsonPatch/project.json index d01e21cbb9..1860893f6b 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/project.json +++ b/src/Microsoft.AspNetCore.JsonPatch/project.json @@ -28,7 +28,7 @@ "dependencies": { "Microsoft.CSharp": "4.0.1-*", "System.Collections.Concurrent": "4.0.12-*", - "System.ComponentModel.TypeConverter": "4.1.0-*", + "System.ComponentModel.TypeConverter": "4.0.1-*", "System.Diagnostics.Debug": "4.0.11-*", "System.Globalization": "4.0.11-*", "System.Linq": "4.1.0-*", From a2e3bdf408938bd670ab988c0aad6a08565915d4 Mon Sep 17 00:00:00 2001 From: John Luo Date: Thu, 26 May 2016 18:29:26 -0700 Subject: [PATCH 110/471] React to updated CoreCLR packages https://github.com/aspnet/Coherence/issues/97 --- src/Microsoft.AspNetCore.JsonPatch/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.AspNetCore.JsonPatch/project.json b/src/Microsoft.AspNetCore.JsonPatch/project.json index 1860893f6b..d01e21cbb9 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/project.json +++ b/src/Microsoft.AspNetCore.JsonPatch/project.json @@ -28,7 +28,7 @@ "dependencies": { "Microsoft.CSharp": "4.0.1-*", "System.Collections.Concurrent": "4.0.12-*", - "System.ComponentModel.TypeConverter": "4.0.1-*", + "System.ComponentModel.TypeConverter": "4.1.0-*", "System.Diagnostics.Debug": "4.0.11-*", "System.Globalization": "4.0.11-*", "System.Linq": "4.1.0-*", From 8bd631170328b5bfcbf7b8503487a05ba0b886b7 Mon Sep 17 00:00:00 2001 From: Cesar Blum Silveira Date: Fri, 27 May 2016 11:32:14 -0700 Subject: [PATCH 111/471] Fix OSX build on Travis. --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 304e307169..bb366b178f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,5 +22,7 @@ branches: - release - dev - /^(.*\/)?ci-.*$/ +before_install: + - if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; brew link --force openssl; fi script: - ./build.sh --quiet verify \ No newline at end of file From 45b4960e265ddfc3c4e8d06dc4a22157b0512ea6 Mon Sep 17 00:00:00 2001 From: Cesar Blum Silveira Date: Fri, 27 May 2016 11:53:04 -0700 Subject: [PATCH 112/471] Fix OSX build on Travis. --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index dae036065b..59d308953d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,6 +22,8 @@ branches: - release - dev - /^(.*\/)?ci-.*$/ +before_install: + - if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; brew link --force openssl; fi script: - ./build.sh --quiet verify notifications: From 0f1836c6dd418bbab40520c25ab6a27002691d1b Mon Sep 17 00:00:00 2001 From: jacalvar Date: Fri, 3 Jun 2016 13:08:19 -0700 Subject: [PATCH 113/471] Update Json.NET to 9.0.1-beta1 --- src/Microsoft.AspNetCore.JsonPatch/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.AspNetCore.JsonPatch/project.json b/src/Microsoft.AspNetCore.JsonPatch/project.json index d01e21cbb9..78a4fe8fb2 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/project.json +++ b/src/Microsoft.AspNetCore.JsonPatch/project.json @@ -21,7 +21,7 @@ ] }, "dependencies": { - "Newtonsoft.Json": "8.0.3" + "Newtonsoft.Json": "9.0.1-beta1" }, "frameworks": { "netstandard1.1": { From 4d77dce803855d31c6405bdc81403fbf8ada6e3e Mon Sep 17 00:00:00 2001 From: jacalvar Date: Tue, 7 Jun 2016 22:08:02 -0700 Subject: [PATCH 114/471] Remove unncessary imports --- src/Microsoft.AspNetCore.JsonPatch/project.json | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Microsoft.AspNetCore.JsonPatch/project.json b/src/Microsoft.AspNetCore.JsonPatch/project.json index 78a4fe8fb2..6395f3ecf1 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/project.json +++ b/src/Microsoft.AspNetCore.JsonPatch/project.json @@ -37,10 +37,7 @@ "System.Runtime.Extensions": "4.1.0-*", "System.Runtime.Serialization.Primitives": "4.1.1-*", "System.Text.Encoding.Extensions": "4.0.11-*" - }, - "imports": [ - "portable-net451+win8" - ] + } } } } \ No newline at end of file From af8e9fb4434c0f24f35ea4a15d82b0995d8569c5 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Mon, 13 Jun 2016 15:27:34 -0700 Subject: [PATCH 115/471] Remove direct Microsoft.NETCore.Platforms dependency. - Microsoft.NETCore.App now pulls this package in. aspnet/Coherence-Signed#344 --- test/Microsoft.AspNetCore.JsonPatch.Test/project.json | 1 - 1 file changed, 1 deletion(-) diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json index dac020cb6c..dc9abdb71c 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json @@ -4,7 +4,6 @@ }, "dependencies": { "dotnet-test-xunit": "1.0.0-*", - "Microsoft.NETCore.Platforms": "1.0.1-*", "Microsoft.AspNetCore.JsonPatch": "1.0.0-*", "Microsoft.AspNetCore.Testing": "1.0.0-*", "xunit": "2.1.0" From 0aab6898131d9848728705e146799864bb185be4 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Mon, 13 Jun 2016 15:28:17 -0700 Subject: [PATCH 116/471] Remove direct Microsoft.NETCore.Platforms dependency. - Microsoft.NETCore.App now pulls this package in. aspnet/Coherence-Signed#344 --- test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json | 1 - test/Microsoft.Extensions.WebEncoders.Tests/project.json | 1 - 2 files changed, 2 deletions(-) diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json index 2efabff127..7519592e34 100644 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json @@ -5,7 +5,6 @@ }, "dependencies": { "dotnet-test-xunit": "1.0.0-*", - "Microsoft.NETCore.Platforms": "1.0.1-*", "Microsoft.AspNetCore.Html.Abstractions": "1.0.0-*", "Microsoft.AspNetCore.Testing": "1.0.0-*", "Microsoft.Extensions.WebEncoders": "1.0.0-*", diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/project.json b/test/Microsoft.Extensions.WebEncoders.Tests/project.json index 2cb866fcc3..7e1a202424 100644 --- a/test/Microsoft.Extensions.WebEncoders.Tests/project.json +++ b/test/Microsoft.Extensions.WebEncoders.Tests/project.json @@ -1,7 +1,6 @@ { "dependencies": { "dotnet-test-xunit": "1.0.0-*", - "Microsoft.NETCore.Platforms": "1.0.1-*", "Microsoft.Extensions.DependencyInjection": "1.0.0-*", "Microsoft.Extensions.WebEncoders": "1.0.0-*", "xunit": "2.1.0" From 288810c95ce6f6d2589f4cbbd016e12d48a8e4c3 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 14 Jun 2016 16:21:56 -0700 Subject: [PATCH 117/471] Updating to release. --- NuGet.config | 4 ++-- build.ps1 | 2 +- build.sh | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/NuGet.config b/NuGet.config index 5500f6d507..71b9724a09 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,7 @@ - + - + diff --git a/build.ps1 b/build.ps1 index 8f2f99691a..cf8bff13bb 100644 --- a/build.ps1 +++ b/build.ps1 @@ -33,7 +33,7 @@ cd $PSScriptRoot $repoFolder = $PSScriptRoot $env:REPO_FOLDER = $repoFolder -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/release.zip" if ($env:KOREBUILD_ZIP) { $koreBuildZip=$env:KOREBUILD_ZIP diff --git a/build.sh b/build.sh index f4208100eb..f88fe4052e 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/release.zip" if [ ! -z $KOREBUILD_ZIP ]; then koreBuildZip=$KOREBUILD_ZIP fi From 2fffcb9da7639401f5a197d96bce401175a86c9b Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 14 Jun 2016 16:22:16 -0700 Subject: [PATCH 118/471] Updating to release. --- NuGet.config | 4 ++-- build.ps1 | 2 +- build.sh | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/NuGet.config b/NuGet.config index 03704957e8..9db87a421e 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,7 @@ - + - + \ No newline at end of file diff --git a/build.ps1 b/build.ps1 index 8f2f99691a..cf8bff13bb 100644 --- a/build.ps1 +++ b/build.ps1 @@ -33,7 +33,7 @@ cd $PSScriptRoot $repoFolder = $PSScriptRoot $env:REPO_FOLDER = $repoFolder -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/release.zip" if ($env:KOREBUILD_ZIP) { $koreBuildZip=$env:KOREBUILD_ZIP diff --git a/build.sh b/build.sh index f4208100eb..f88fe4052e 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/release.zip" if [ ! -z $KOREBUILD_ZIP ]; then koreBuildZip=$KOREBUILD_ZIP fi From d7d8af57f6a890360d77e65a68fc54b7cd45d0f6 Mon Sep 17 00:00:00 2001 From: jacalvar Date: Mon, 13 Jun 2016 14:24:30 -0700 Subject: [PATCH 119/471] Update Json.NET to 9.0.1 --- src/Microsoft.AspNetCore.JsonPatch/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.AspNetCore.JsonPatch/project.json b/src/Microsoft.AspNetCore.JsonPatch/project.json index 6395f3ecf1..ac582cbac3 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/project.json +++ b/src/Microsoft.AspNetCore.JsonPatch/project.json @@ -21,7 +21,7 @@ ] }, "dependencies": { - "Newtonsoft.Json": "9.0.1-beta1" + "Newtonsoft.Json": "9.0.1" }, "frameworks": { "netstandard1.1": { From 66518476aff65545f85a3796788f18bf40cfa7e5 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 16 Jun 2016 10:17:56 -0700 Subject: [PATCH 120/471] Updating to dev versions --- src/Microsoft.AspNetCore.Html.Abstractions/project.json | 2 +- src/Microsoft.Extensions.WebEncoders/project.json | 6 +++--- .../project.json | 6 +++--- test/Microsoft.Extensions.WebEncoders.Tests/project.json | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/project.json b/src/Microsoft.AspNetCore.Html.Abstractions/project.json index 72763e5b05..7d42a7746d 100644 --- a/src/Microsoft.AspNetCore.Html.Abstractions/project.json +++ b/src/Microsoft.AspNetCore.Html.Abstractions/project.json @@ -1,5 +1,5 @@ { - "version": "1.0.0-*", + "version": "1.1.0-*", "description": "ASP.NET Core HTML abstractions used for building HTML content.\r\nCommonly used types:\r\nMicrosoft.AspNetCore.Html.HtmlString\r\nMicrosoft.AspNetCore.Html.IHtmlContent", "packOptions": { "repository": { diff --git a/src/Microsoft.Extensions.WebEncoders/project.json b/src/Microsoft.Extensions.WebEncoders/project.json index 857361e4e4..1e765f8b80 100644 --- a/src/Microsoft.Extensions.WebEncoders/project.json +++ b/src/Microsoft.Extensions.WebEncoders/project.json @@ -1,5 +1,5 @@ { - "version": "1.0.0-*", + "version": "1.1.0-*", "description": "Contains registration and configuration APIs to add the core framework encoders to a dependency injection container.", "packOptions": { "repository": { @@ -20,8 +20,8 @@ "xmlDoc": true }, "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "1.0.0-*", - "Microsoft.Extensions.Options": "1.0.0-*", + "Microsoft.Extensions.DependencyInjection.Abstractions": "1.1.0-*", + "Microsoft.Extensions.Options": "1.1.0-*", "System.Text.Encodings.Web": "4.0.0-*" }, "frameworks": { diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json index 7519592e34..cbcb78bf6e 100644 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json @@ -5,9 +5,9 @@ }, "dependencies": { "dotnet-test-xunit": "1.0.0-*", - "Microsoft.AspNetCore.Html.Abstractions": "1.0.0-*", - "Microsoft.AspNetCore.Testing": "1.0.0-*", - "Microsoft.Extensions.WebEncoders": "1.0.0-*", + "Microsoft.AspNetCore.Html.Abstractions": "1.1.0-*", + "Microsoft.AspNetCore.Testing": "1.1.0-*", + "Microsoft.Extensions.WebEncoders": "1.1.0-*", "xunit": "2.1.0" }, "testRunner": "xunit", diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/project.json b/test/Microsoft.Extensions.WebEncoders.Tests/project.json index 7e1a202424..65a29bd9c1 100644 --- a/test/Microsoft.Extensions.WebEncoders.Tests/project.json +++ b/test/Microsoft.Extensions.WebEncoders.Tests/project.json @@ -1,8 +1,8 @@ { "dependencies": { "dotnet-test-xunit": "1.0.0-*", - "Microsoft.Extensions.DependencyInjection": "1.0.0-*", - "Microsoft.Extensions.WebEncoders": "1.0.0-*", + "Microsoft.Extensions.DependencyInjection": "1.1.0-*", + "Microsoft.Extensions.WebEncoders": "1.1.0-*", "xunit": "2.1.0" }, "testRunner": "xunit", From 36e5c0e6fae4d9f547904509b5044678ad559430 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 16 Jun 2016 10:18:06 -0700 Subject: [PATCH 121/471] Updating to dev versions --- src/Microsoft.AspNetCore.JsonPatch/project.json | 2 +- test/Microsoft.AspNetCore.JsonPatch.Test/project.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.AspNetCore.JsonPatch/project.json b/src/Microsoft.AspNetCore.JsonPatch/project.json index ac582cbac3..44daeef0e9 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/project.json +++ b/src/Microsoft.AspNetCore.JsonPatch/project.json @@ -1,5 +1,5 @@ { - "version": "1.0.0-*", + "version": "1.1.0-*", "description": "ASP.NET Core support for JSON PATCH.", "buildOptions": { "warningsAsErrors": true, diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json index dc9abdb71c..4bd3e6450b 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json @@ -4,8 +4,8 @@ }, "dependencies": { "dotnet-test-xunit": "1.0.0-*", - "Microsoft.AspNetCore.JsonPatch": "1.0.0-*", - "Microsoft.AspNetCore.Testing": "1.0.0-*", + "Microsoft.AspNetCore.JsonPatch": "1.1.0-*", + "Microsoft.AspNetCore.Testing": "1.1.0-*", "xunit": "2.1.0" }, "testRunner": "xunit", From 60a66aaa6db5f7d79fab80d84936fb58a443083a Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 30 Jun 2016 14:52:36 -0700 Subject: [PATCH 122/471] Updating to RTM builds of xunit --- .../project.json | 22 ++++--------------- .../project.json | 16 ++++---------- 2 files changed, 8 insertions(+), 30 deletions(-) diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json index cbcb78bf6e..8c2d135d8a 100644 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json @@ -4,11 +4,11 @@ "keyFile": "../../tools/Key.snk" }, "dependencies": { - "dotnet-test-xunit": "1.0.0-*", + "dotnet-test-xunit": "2.2.0-*", "Microsoft.AspNetCore.Html.Abstractions": "1.1.0-*", "Microsoft.AspNetCore.Testing": "1.1.0-*", "Microsoft.Extensions.WebEncoders": "1.1.0-*", - "xunit": "2.1.0" + "xunit": "2.2.0-*" }, "testRunner": "xunit", "frameworks": { @@ -17,23 +17,9 @@ "Microsoft.NETCore.App": { "version": "1.0.0-*", "type": "platform" - }, - "System.Diagnostics.Process": "4.1.0-*" - }, - "imports": [ - "dnxcore50", - "portable-net451+win8" - ] - }, - "net451": { - "frameworkAssemblies": { - "System.IO": { - "type": "build" - }, - "System.Runtime": { - "type": "build" } } - } + }, + "net451": {} } } \ No newline at end of file diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/project.json b/test/Microsoft.Extensions.WebEncoders.Tests/project.json index 65a29bd9c1..6ed331d6ec 100644 --- a/test/Microsoft.Extensions.WebEncoders.Tests/project.json +++ b/test/Microsoft.Extensions.WebEncoders.Tests/project.json @@ -1,13 +1,12 @@ { "dependencies": { - "dotnet-test-xunit": "1.0.0-*", + "dotnet-test-xunit": "2.2.0-*", "Microsoft.Extensions.DependencyInjection": "1.1.0-*", "Microsoft.Extensions.WebEncoders": "1.1.0-*", - "xunit": "2.1.0" + "xunit": "2.2.0-*" }, "testRunner": "xunit", "buildOptions": { - "allowUnsafe": true, "warningsAsErrors": true, "keyFile": "../../tools/Key.snk" }, @@ -17,20 +16,13 @@ "Microsoft.NETCore.App": { "version": "1.0.0-*", "type": "platform" - }, - "System.Diagnostics.Process": "4.1.0-*" + } }, "imports": [ "dnxcore50", "portable-net451+win8" ] }, - "net451": { - "frameworkAssemblies": { - "System.Runtime": { - "type": "build" - } - } - } + "net451": {} } } \ No newline at end of file From 24439bc400ab5c67e9480dfc56ed9d8f361a5f4c Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 30 Jun 2016 15:36:11 -0700 Subject: [PATCH 123/471] Updating to RTM builds of xunit and Moq --- .gitignore | 13 ++++++++--- .../project.json | 22 ++++--------------- 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/.gitignore b/.gitignore index 2e4b2d6b5d..06cfaa0cbe 100644 --- a/.gitignore +++ b/.gitignore @@ -8,15 +8,18 @@ TestResults/ _ReSharper.*/ packages/ artifacts/ -.build/ PublishProfiles/ +.vs/ +bower_components/ +node_modules/ +debugSettings.json +project.lock.json *.user *.suo *.cache *.docstates _ReSharper.* nuget.exe -project.lock.json *net45.csproj *net451.csproj *k10.csproj @@ -28,4 +31,8 @@ project.lock.json *.ncrunchsolution *.*sdf *.ipch -.build/ \ No newline at end of file +.settings +*.sln.ide +node_modules +*launchSettings.json +*.orig \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json index 4bd3e6450b..d6f8f5cbc6 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json @@ -3,10 +3,11 @@ "warningsAsErrors": true }, "dependencies": { - "dotnet-test-xunit": "1.0.0-*", + "dotnet-test-xunit": "2.2.0-*", "Microsoft.AspNetCore.JsonPatch": "1.1.0-*", "Microsoft.AspNetCore.Testing": "1.1.0-*", - "xunit": "2.1.0" + "Moq": "4.6.25-*", + "xunit": "2.2.0-*" }, "testRunner": "xunit", "frameworks": { @@ -16,30 +17,15 @@ "version": "1.0.0-*", "type": "platform" }, - "moq.netcore": "4.4.0-beta8", - "System.Diagnostics.Process": "4.1.0-*", "System.Diagnostics.TraceSource": "4.0.0-*" }, - "imports": [ - "dnxcore50", - "portable-net451+win8" - ] + "imports": "dotnet5.4" }, "net451": { "frameworkAssemblies": { "System.Linq.Expressions": { "type": "build" - }, - "System.Runtime": { - "type": "build" - }, - "System.Threading.Tasks": { - "type": "build" } - }, - "dependencies": { - "Moq": "4.2.1312.1622", - "xunit.runner.console": "2.1.0" } } } From 717e4fe083aee435536ead22c2993278f63f1487 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Thu, 7 Jul 2016 12:00:26 -0700 Subject: [PATCH 124/471] One build to rule them all - well, at least VS and command-line builds will share output - part of aspnet/Coherence-Signed#277 --- .../Microsoft.AspNetCore.Html.Abstractions.xproj | 4 ++-- .../Microsoft.Extensions.WebEncoders.xproj | 4 ++-- .../Microsoft.AspNetCore.Html.Abstractions.Test.xproj | 4 ++-- .../Microsoft.Extensions.WebEncoders.Tests.xproj | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.xproj b/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.xproj index 7a3801b2b1..25d87d97bb 100644 --- a/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.xproj +++ b/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.xproj @@ -7,8 +7,8 @@ 68a28e4a-3ade-4187-9625-4ff185887cb3 - ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\ + .\obj + .\bin\ 2.0 diff --git a/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.xproj b/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.xproj index 0f278d6c98..f458d42cf1 100644 --- a/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.xproj +++ b/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.xproj @@ -7,8 +7,8 @@ dd2ce416-765e-4000-a03e-c2ff165da1b6 - ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\ + .\obj + .\bin\ 2.0 diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.xproj b/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.xproj index 20389ad4bf..3d3d10b2ac 100644 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.xproj +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.xproj @@ -7,8 +7,8 @@ 2d187b88-94bd-4a39-ac97-f8f8b9363301 - ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\ + .\obj + .\bin\ 2.0 diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.xproj b/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.xproj index 9ad3cb3d4f..a7810a9e17 100644 --- a/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.xproj +++ b/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.xproj @@ -7,8 +7,8 @@ 7ae2731d-43cd-4cf8-850a-4914de2ce930 - ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\ + .\obj + .\bin\ 2.0 From 6b08efb12271fd6c81ab60e1c509032cf5ed5e39 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Thu, 7 Jul 2016 12:06:18 -0700 Subject: [PATCH 125/471] One build to rule them all - well, at least VS and command-line builds will share output - part of aspnet/Coherence-Signed#277 --- .../Microsoft.AspNetCore.JsonPatch.xproj | 4 ++-- .../Microsoft.AspNetCore.JsonPatch.Test.xproj | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.xproj b/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.xproj index d11d600744..0ebf789691 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.xproj +++ b/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.xproj @@ -7,8 +7,8 @@ 4d55f4d8-633b-462f-a5b1-feb84bd2d534 - ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\ + .\obj + .\bin\ 2.0 diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.xproj b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.xproj index 0b71c5d301..c8942c121e 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.xproj +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.xproj @@ -7,8 +7,8 @@ 81c20848-e063-4e12-ac40-0b55a532c16c - ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\ + .\obj + .\bin\ 2.0 From c7035517724bc5b0fbdc8cd1b67656f90a953f0a Mon Sep 17 00:00:00 2001 From: BrennanConroy Date: Tue, 2 Aug 2016 13:14:37 -0700 Subject: [PATCH 126/471] Update .travis.yml --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index bb366b178f..631adcf570 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,6 +23,6 @@ branches: - dev - /^(.*\/)?ci-.*$/ before_install: - - if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; brew link --force openssl; fi + - if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/; fi script: - - ./build.sh --quiet verify \ No newline at end of file + - ./build.sh --quiet verify From cbe53312d4b3a41122e334ae38810191363a0486 Mon Sep 17 00:00:00 2001 From: BrennanConroy Date: Tue, 2 Aug 2016 13:15:00 -0700 Subject: [PATCH 127/471] Update .travis.yml --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 59d308953d..1ba51470ba 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,7 +23,7 @@ branches: - dev - /^(.*\/)?ci-.*$/ before_install: - - if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; brew link --force openssl; fi + - if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/; fi script: - ./build.sh --quiet verify notifications: @@ -31,4 +31,4 @@ notifications: secure: "d87o+y2WUx204s8TfSaEuekYudnSyyPaFEXkuzgs3uAyzkKAm/Hx0xcMSuKDqWhYmKaxL7VtgEd2z7mltr2cHZ4oyCrsf6V5v4iI48ojaGykqFXfv8ld6khmLwtdkC32lF2YyuDNL8kUvKNdP9jkrWlpoO/WC6QEqAUxdOuuLo/wLyfrPLbzIvbojwveXbmcwvsfDizLdZdVd88FZSV41h+yBKLnyhpeqRvHG85BTgT/GmVB7Vyjs3yChiS639Aq5DoOP8jBaRdB8Bqs09KibFXzJwDBlKvALIqiwzog3hpd5SVxrgOTCkWbOwqq4TSkahDE425W3vFbmLDANgdfsyAkqgt8daE2BkFTojEHQED+u9CEd8oJVX6FoGnYpuDzge4FVh9iG3HSuKwoVdlONzzew4oJ75iQ+0f67ZNV9oDuScdva/SGb2gYgVUkeJIjDoMxKuaZyhbBT9jRXRBI+LsIjziEhLU/649FjTSmQx0HLpcT7+kaeSmhqT9JffVLidMdvZwhPZsLxPSG9UVBH9G8rdyHXP2e0ZlicHNjjNV6kbDqfDPhHx2/MfZGugsJXjOONKu/5LZduQzmAOysqdLKqkBVkMq2xl7aGV+yVZAtTmZB3nqOWGyKlFC9kLGO+qlJ4tBac26lHCZWTK+4VOAtN5Dag0DkDikgGdZaq78=" on_success: always on_failure: always - on_start: always \ No newline at end of file + on_start: always From e991ebaa4fd6b0011d7492f0e30520f657d02119 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 8 Aug 2016 14:29:46 -0700 Subject: [PATCH 128/471] Updating to Moq \ Castle.Core that does not require imports --- test/Microsoft.AspNetCore.JsonPatch.Test/project.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json index d6f8f5cbc6..acc8390c6d 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json @@ -6,7 +6,7 @@ "dotnet-test-xunit": "2.2.0-*", "Microsoft.AspNetCore.JsonPatch": "1.1.0-*", "Microsoft.AspNetCore.Testing": "1.1.0-*", - "Moq": "4.6.25-*", + "Moq": "4.6.36-*", "xunit": "2.2.0-*" }, "testRunner": "xunit", @@ -18,8 +18,7 @@ "type": "platform" }, "System.Diagnostics.TraceSource": "4.0.0-*" - }, - "imports": "dotnet5.4" + } }, "net451": { "frameworkAssemblies": { From acab75a1bb3c897f9343ae32c5e460bffad786e1 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 9 Aug 2016 15:03:00 -0700 Subject: [PATCH 129/471] Switching to dotnet.myget.org feed --- NuGet.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NuGet.config b/NuGet.config index 03704957e8..826a1f9035 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,7 @@  - + \ No newline at end of file From 2e53d0e55be8fde8f7bf112dd2d814eea8f490a8 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 9 Aug 2016 15:04:20 -0700 Subject: [PATCH 130/471] Switching to dotnet.myget.org feed --- NuGet.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NuGet.config b/NuGet.config index 5500f6d507..0fd623ffdd 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,7 @@  - + From c2690023d8f14f8deb64b9571212ad2da5ff6541 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Sun, 4 Sep 2016 12:44:17 -0700 Subject: [PATCH 131/471] Increase .travis.yml consistency between repos - aspnet/Universe#349 - minimize `dotnet` setup time; no need for caching --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 1ba51470ba..e2abeda7d4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,10 @@ addons: - libssl-dev - libunwind8 - zlib1g +env: + global: + - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + - DOTNET_CLI_TELEMETRY_OPTOUT: 1 mono: - 4.0.5 os: From e72d4b4876ca0599aa1afc685e8d50b50ed6d71b Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Sun, 4 Sep 2016 15:46:35 -0700 Subject: [PATCH 132/471] Increase .travis.yml consistency between repos - aspnet/Universe#349 - minimize `dotnet` setup time; no need for caching --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 631adcf570..d7636fa329 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,10 @@ addons: - libssl-dev - libunwind8 - zlib1g +env: + global: + - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + - DOTNET_CLI_TELEMETRY_OPTOUT: 1 mono: - 4.0.5 os: From c88aa0042a8ae3457bb6731fcbbc6721d4b8c335 Mon Sep 17 00:00:00 2001 From: Kevin Dockx Date: Wed, 28 Sep 2016 18:37:21 +0200 Subject: [PATCH 133/471] Fix for issue #29 (Honor JsonProperty when serializing a JsonPatchDocument) (#35) * Fix for issue #29 (Honor JsonProperty when serializing a JsonPatchDocument) --- .../Helpers/ExpressionHelpers.cs | 26 ++- ...nPatchDocumentJsonPropertyAttributeTest.cs | 148 ++++++++++++++++++ .../JsonPropertyDTO.cs | 13 ++ .../JsonPropertyWithAnotherNameDTO.cs | 10 ++ .../JsonPropertyWithInheritanceDTO.cs | 19 +++ 5 files changed, 214 insertions(+), 2 deletions(-) create mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs create mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyDTO.cs create mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyWithAnotherNameDTO.cs create mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyWithInheritanceDTO.cs diff --git a/src/Microsoft.AspNetCore.JsonPatch/Helpers/ExpressionHelpers.cs b/src/Microsoft.AspNetCore.JsonPatch/Helpers/ExpressionHelpers.cs index 92880eb0e1..d9b516cc0e 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Helpers/ExpressionHelpers.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Helpers/ExpressionHelpers.cs @@ -1,9 +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 Newtonsoft.Json; using System; using System.Globalization; +using System.Linq; using System.Linq.Expressions; +using System.Reflection; namespace Microsoft.AspNetCore.JsonPatch.Helpers { @@ -51,11 +54,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Helpers if (ContinueWithSubPath(memberExpression.Expression.NodeType, false)) { var left = GetPath(memberExpression.Expression, false); - return left + "/" + memberExpression.Member.Name; + // Get property name, respecting JsonProperty attribute + return left + "/" + GetPropertyNameFromMemberExpression(memberExpression); } else { - return memberExpression.Member.Name; + // Get property name, respecting JsonProperty attribute + return GetPropertyNameFromMemberExpression(memberExpression); } case ExpressionType.Parameter: // Fits "x => x" (the whole document which is "" as JSON pointer) @@ -65,6 +70,23 @@ namespace Microsoft.AspNetCore.JsonPatch.Helpers } } + private static string GetPropertyNameFromMemberExpression(MemberExpression memberExpression) + { + // if there's a JsonProperty attribute, we must return the PropertyName + // from the attribute rather than the member name + var jsonPropertyAttribute = + memberExpression.Member.GetCustomAttribute( + typeof(JsonPropertyAttribute), true); + + if (jsonPropertyAttribute == null) + { + return memberExpression.Member.Name; + } + // get value + var castedAttribute = (JsonPropertyAttribute)jsonPropertyAttribute; + return castedAttribute.PropertyName; + } + private static bool ContinueWithSubPath(ExpressionType expressionType, bool firstTime) { if (firstTime) diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs new file mode 100644 index 0000000000..ef7d53c21a --- /dev/null +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs @@ -0,0 +1,148 @@ +// Copyright (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; +using System.Linq; +using Xunit; + +namespace Microsoft.AspNetCore.JsonPatch +{ + public class JsonPatchDocumentJsonPropertyAttributeTest + { + [Fact] + public void Add_WithExpression_RespectsJsonPropertyName_ForModelProperty() + { + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(p => p.Name, "John"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + // serialized value should have "AnotherName" as path + // deserialize to a JsonPatchDocument to check + var deserialized = + JsonConvert.DeserializeObject>(serialized); + + // get path + var pathToCheck = deserialized.Operations.First().path; + Assert.Equal(pathToCheck, "/anothername"); + } + + [Fact] + public void Add_WithExpression_RespectsJsonPropertyName_WhenApplyingToDifferentlyTypedClassWithPropertyMatchingJsonPropertyName() + { + var patchDocToSerialize = new JsonPatchDocument(); + patchDocToSerialize.Add(p => p.Name, "John"); + + // the patchdoc will deserialize to "anothername". We should thus be able to apply + // it to a class that HAS that other property name. + var doc = new JsonPropertyWithAnotherNameDTO() + { + AnotherName = "InitialValue" + }; + + var serialized = JsonConvert.SerializeObject(patchDocToSerialize); + var deserialized = + JsonConvert.DeserializeObject> + (serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(doc.AnotherName, "John"); + } + + [Fact] + public void Add_WithExpression_RespectsJsonPropertyName_WhenApplyingToSameTypedClassWithMatchingJsonPropertyName() + { + var patchDocToSerialize = new JsonPatchDocument(); + patchDocToSerialize.Add(p => p.Name, "John"); + + // the patchdoc will deserialize to "anothername". As JsonPropertyDTO has + // a JsonProperty signifying that "Name" should be deseriallized from "AnotherName", + // we should be able to apply the patchDoc. + + var doc = new JsonPropertyDTO() + { + Name = "InitialValue" + }; + + var serialized = JsonConvert.SerializeObject(patchDocToSerialize); + var deserialized = + JsonConvert.DeserializeObject> + (serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(doc.Name, "John"); + } + + [Fact] + public void Add_OnApplyFromJson_RespectsJsonPropertyNameOnJsonDocument() + { + var doc = new JsonPropertyDTO() + { + Name = "InitialValue" + }; + + // serialization should serialize to "AnotherName" + var serialized = "[{\"value\":\"Kevin\",\"path\":\"/AnotherName\",\"op\":\"add\"}]"; + var deserialized = + JsonConvert.DeserializeObject>(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal("Kevin", doc.Name); + } + + [Fact] + public void Remove_OnApplyFromJson_RespectsJsonPropertyNameOnJsonDocument() + { + var doc = new JsonPropertyDTO() + { + Name = "InitialValue" + }; + + // serialization should serialize to "AnotherName" + var serialized = "[{\"path\":\"/AnotherName\",\"op\":\"remove\"}]"; + var deserialized = + JsonConvert.DeserializeObject>(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal(null, doc.Name); + } + + [Fact] + public void Add_OnApplyFromJson_RespectsInheritedJsonPropertyNameOnJsonDocument() + { + var doc = new JsonPropertyWithInheritanceDTO() + { + Name = "InitialName" + }; + + // serialization should serialize to "AnotherName" + var serialized = "[{\"value\":\"Kevin\",\"path\":\"/AnotherName\",\"op\":\"add\"}]"; + var deserialized = + JsonConvert.DeserializeObject>(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal("Kevin", doc.Name); + } + + [Fact] + public void Add_WithExpression_RespectsJsonPropertyName_ForInheritedModelProperty() + { + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(p => p.Name, "John"); + + var serialized = JsonConvert.SerializeObject(patchDoc); + // serialized value should have "AnotherName" as path + // deserialize to a JsonPatchDocument to check + var deserialized = + JsonConvert.DeserializeObject>(serialized); + + // get path + var pathToCheck = deserialized.Operations.First().path; + Assert.Equal(pathToCheck, "/anothername"); + } + } +} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyDTO.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyDTO.cs new file mode 100644 index 0000000000..c926d9f5fd --- /dev/null +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyDTO.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 Newtonsoft.Json; + +namespace Microsoft.AspNetCore.JsonPatch +{ + public class JsonPropertyDTO + { + [JsonProperty("AnotherName")] + public string Name { get; set; } + } +} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyWithAnotherNameDTO.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyWithAnotherNameDTO.cs new file mode 100644 index 0000000000..9b61e09005 --- /dev/null +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyWithAnotherNameDTO.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 JsonPropertyWithAnotherNameDTO + { + public string AnotherName { get; set; } + } +} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyWithInheritanceDTO.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyWithInheritanceDTO.cs new file mode 100644 index 0000000000..fa69425ea9 --- /dev/null +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyWithInheritanceDTO.cs @@ -0,0 +1,19 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Microsoft.AspNetCore.JsonPatch +{ + public class JsonPropertyWithInheritanceDTO : JsonPropertyWithInheritanceBaseDTO + { + public override string Name { get; set; } + } + + public abstract class JsonPropertyWithInheritanceBaseDTO + { + [JsonProperty("AnotherName")] + public abstract string Name { get; set; } + } +} From c13a8affc0662e32edd3914c290c5c9631dbad96 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 28 Sep 2016 11:50:43 -0700 Subject: [PATCH 134/471] Updating partner package versions --- .../project.json | 10 +++------- src/Microsoft.Extensions.WebEncoders/project.json | 3 ++- .../project.json | 2 +- .../project.json | 2 +- 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/project.json b/src/Microsoft.AspNetCore.Html.Abstractions/project.json index 7d42a7746d..da6f399828 100644 --- a/src/Microsoft.AspNetCore.Html.Abstractions/project.json +++ b/src/Microsoft.AspNetCore.Html.Abstractions/project.json @@ -19,14 +19,10 @@ "xmlDoc": true }, "dependencies": { - "System.Text.Encodings.Web": "4.0.0-*" + "NETStandard.Library": "1.6.1-*", + "System.Text.Encodings.Web": "4.3.0-*" }, "frameworks": { - "netstandard1.0": { - "dependencies": { - "System.Collections": "4.0.11-*", - "System.Resources.ResourceManager": "4.0.1-*" - } - } + "netstandard1.0": {} } } \ No newline at end of file diff --git a/src/Microsoft.Extensions.WebEncoders/project.json b/src/Microsoft.Extensions.WebEncoders/project.json index 1e765f8b80..852787db64 100644 --- a/src/Microsoft.Extensions.WebEncoders/project.json +++ b/src/Microsoft.Extensions.WebEncoders/project.json @@ -22,7 +22,8 @@ "dependencies": { "Microsoft.Extensions.DependencyInjection.Abstractions": "1.1.0-*", "Microsoft.Extensions.Options": "1.1.0-*", - "System.Text.Encodings.Web": "4.0.0-*" + "NETStandard.Library": "1.6.1-*", + "System.Text.Encodings.Web": "4.3.0-*" }, "frameworks": { "netstandard1.0": {} diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json index 8c2d135d8a..8e5e79eeb2 100644 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json @@ -15,7 +15,7 @@ "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.0.0-*", + "version": "1.1.0-*", "type": "platform" } } diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/project.json b/test/Microsoft.Extensions.WebEncoders.Tests/project.json index 6ed331d6ec..4c9ee42471 100644 --- a/test/Microsoft.Extensions.WebEncoders.Tests/project.json +++ b/test/Microsoft.Extensions.WebEncoders.Tests/project.json @@ -14,7 +14,7 @@ "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.0.0-*", + "version": "1.1.0-*", "type": "platform" } }, From 9e8aee24788a48b0d3277a85cebb3a228be8f9dd Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 28 Sep 2016 11:51:01 -0700 Subject: [PATCH 135/471] Updating partner package versions --- src/Microsoft.AspNetCore.JsonPatch/project.json | 15 ++++----------- .../project.json | 4 ++-- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/src/Microsoft.AspNetCore.JsonPatch/project.json b/src/Microsoft.AspNetCore.JsonPatch/project.json index 44daeef0e9..5180ee7e23 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/project.json +++ b/src/Microsoft.AspNetCore.JsonPatch/project.json @@ -21,22 +21,15 @@ ] }, "dependencies": { + "NETStandard.Library": "1.6.1-*", "Newtonsoft.Json": "9.0.1" }, "frameworks": { "netstandard1.1": { "dependencies": { - "Microsoft.CSharp": "4.0.1-*", - "System.Collections.Concurrent": "4.0.12-*", - "System.ComponentModel.TypeConverter": "4.1.0-*", - "System.Diagnostics.Debug": "4.0.11-*", - "System.Globalization": "4.0.11-*", - "System.Linq": "4.1.0-*", - "System.Reflection.Extensions": "4.0.1-*", - "System.Resources.ResourceManager": "4.0.1-*", - "System.Runtime.Extensions": "4.1.0-*", - "System.Runtime.Serialization.Primitives": "4.1.1-*", - "System.Text.Encoding.Extensions": "4.0.11-*" + "Microsoft.CSharp": "4.3.0-*", + "System.ComponentModel.TypeConverter": "4.3.0-*", + "System.Runtime.Serialization.Primitives": "4.3.0-*" } } } diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json index acc8390c6d..9da14bf59e 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json @@ -14,10 +14,10 @@ "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.0.0-*", + "version": "1.1.0-*", "type": "platform" }, - "System.Diagnostics.TraceSource": "4.0.0-*" + "System.Diagnostics.TraceSource": "4.3.0-*" } }, "net451": { From 393c25988ae2a57b6be4235ee4848212c3dcd861 Mon Sep 17 00:00:00 2001 From: Kiran Challa Date: Wed, 21 Sep 2016 22:56:55 -0700 Subject: [PATCH 136/471] [Fixes #33] Dictionary operations fail due to contract issues --- .../Adapters/ObjectAdapter.cs | 853 ++---------------- .../Helpers/ActualPropertyPathResult.cs | 22 - .../ExpandoObjectDictionaryExtensions.cs | 77 -- .../Helpers/ObjectTreeAnalyisResult.cs | 209 ----- .../Helpers/RemovedPropertyTypeResult.cs | 38 - .../{Helpers => Internal}/ConversionResult.cs | 10 +- .../Internal/ConversionResultProvider.cs | 24 + .../Internal/DictionaryAdapter.cs | 111 +++ .../Internal/ExpandoObjectAdapter.cs | 143 +++ .../ExpandoObjectDictionaryExtensions.cs | 26 + .../ExpressionHelpers.cs | 11 +- .../Internal/IAdapter.cs | 44 + .../Internal/ListAdapter.cs | 299 ++++++ .../Internal/ObjectVisitor.cs | 76 ++ .../Internal/ParsedPath.cs | 40 + .../{Helpers => Internal}/PathHelpers.cs | 2 +- .../Internal/PocoAdapter.cs | 205 +++++ .../JsonPatchDocument.cs | 10 +- .../JsonPatchDocumentOfT.cs | 10 +- .../Properties/Resources.Designer.cs | 132 +-- .../Resources.resx | 34 +- .../project.json | 12 +- .../DictionaryAdapterTest.cs | 176 ++++ .../Dynamic/AddOperationTests.cs | 43 +- .../Dynamic/AddTypedOperationTests.cs | 6 +- .../Dynamic/RemoveOperationTests.cs | 10 +- .../Dynamic/RemoveTypedOperationTests.cs | 10 +- .../Dynamic/ReplaceOperationTests.cs | 10 +- .../ListAdapterTest.cs | 302 +++++++ .../NestedDTO.cs | 2 +- .../NestedObjectTests.cs | 54 +- .../ObjectAdapterTests.cs | 667 ++++++++++++-- .../ObjectVisitorTest.cs | 230 +++++ .../ObjectVisitorTest.cs~RF1ad82e13.TMP | 119 +++ .../ObjectVisitorTest.cs~RF1ae034c3.TMP | 131 +++ .../SimpleDTO.cs | 2 +- .../SimpleDTOWithNestedDTO.cs | 2 +- .../TestErrorLogger.cs | 2 +- 38 files changed, 2796 insertions(+), 1358 deletions(-) delete mode 100644 src/Microsoft.AspNetCore.JsonPatch/Helpers/ActualPropertyPathResult.cs delete mode 100644 src/Microsoft.AspNetCore.JsonPatch/Helpers/ExpandoObjectDictionaryExtensions.cs delete mode 100644 src/Microsoft.AspNetCore.JsonPatch/Helpers/ObjectTreeAnalyisResult.cs delete mode 100644 src/Microsoft.AspNetCore.JsonPatch/Helpers/RemovedPropertyTypeResult.cs rename src/Microsoft.AspNetCore.JsonPatch/{Helpers => Internal}/ConversionResult.cs (64%) create mode 100644 src/Microsoft.AspNetCore.JsonPatch/Internal/ConversionResultProvider.cs create mode 100644 src/Microsoft.AspNetCore.JsonPatch/Internal/DictionaryAdapter.cs create mode 100644 src/Microsoft.AspNetCore.JsonPatch/Internal/ExpandoObjectAdapter.cs create mode 100644 src/Microsoft.AspNetCore.JsonPatch/Internal/ExpandoObjectDictionaryExtensions.cs rename src/Microsoft.AspNetCore.JsonPatch/{Helpers => Internal}/ExpressionHelpers.cs (95%) create mode 100644 src/Microsoft.AspNetCore.JsonPatch/Internal/IAdapter.cs create mode 100644 src/Microsoft.AspNetCore.JsonPatch/Internal/ListAdapter.cs create mode 100644 src/Microsoft.AspNetCore.JsonPatch/Internal/ObjectVisitor.cs create mode 100644 src/Microsoft.AspNetCore.JsonPatch/Internal/ParsedPath.cs rename src/Microsoft.AspNetCore.JsonPatch/{Helpers => Internal}/PathHelpers.cs (95%) create mode 100644 src/Microsoft.AspNetCore.JsonPatch/Internal/PocoAdapter.cs create mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/DictionaryAdapterTest.cs create mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/ListAdapterTest.cs create mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/ObjectVisitorTest.cs create mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/ObjectVisitorTest.cs~RF1ad82e13.TMP create mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/ObjectVisitorTest.cs~RF1ae034c3.TMP diff --git a/src/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs b/src/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs index b70ff697c3..ee01fbeba7 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs @@ -1,14 +1,11 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Collections; -using System.Collections.Generic; -using System.Reflection; using Microsoft.AspNetCore.JsonPatch.Exceptions; using Microsoft.AspNetCore.JsonPatch.Helpers; +using Microsoft.AspNetCore.JsonPatch.Internal; using Microsoft.AspNetCore.JsonPatch.Operations; -using Newtonsoft.Json; using Newtonsoft.Json.Serialization; namespace Microsoft.AspNetCore.JsonPatch.Adapters @@ -127,7 +124,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters string path, object value, object objectToApplyTo, - Operation operationToReport) + Operation operation) { if (path == null) { @@ -139,228 +136,30 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters throw new ArgumentNullException(nameof(objectToApplyTo)); } - if (operationToReport == null) + if (operation == null) { - throw new ArgumentNullException(nameof(operationToReport)); + throw new ArgumentNullException(nameof(operation)); } - // first up: if the path ends in a numeric value, we're inserting in a list and - // that value represents the position; if the path ends in "-", we're appending - // to the list. + var parsedPath = new ParsedPath(path); + var visitor = new ObjectVisitor(parsedPath, ContractResolver); - // get path result - var pathResult = GetActualPropertyPath( - path, - objectToApplyTo, - operationToReport); - if (pathResult == null) + IAdapter adapter; + var target = objectToApplyTo; + string errorMessage; + if (!visitor.TryVisit(ref target, out adapter, out errorMessage)) { + var error = CreatePathNotFoundError(objectToApplyTo, path, operation, errorMessage); + ReportError(error); return; } - var appendList = pathResult.ExecuteAtEnd; - var positionAsInteger = pathResult.NumericEnd; - var actualPathToProperty = pathResult.PathToProperty; - - var treeAnalysisResult = new ObjectTreeAnalysisResult( - objectToApplyTo, - actualPathToProperty, - ContractResolver); - - if (!treeAnalysisResult.IsValidPathForAdd) + if (!adapter.TryAdd(target, parsedPath.LastSegment, ContractResolver, value, out errorMessage)) { - LogError(new JsonPatchError( - objectToApplyTo, - operationToReport, - Resources.FormatPropertyCannotBeAdded(path))); + var error = CreateOperationFailedError(objectToApplyTo, path, operation, errorMessage); + ReportError(error); return; } - - if (treeAnalysisResult.UseDynamicLogic) - { - var container = treeAnalysisResult.Container; - if (container.ContainsCaseInsensitiveKey(treeAnalysisResult.PropertyPathInParent)) - { - // Existing property. - // If it's not an array, we need to check if the value fits the property type - // - // If it's an array, we need to check if the value fits in that array type, - // and add it at the correct position (if allowed). - if (appendList || positionAsInteger > -1) - { - // get the actual type - var propertyValue = container.GetValueForCaseInsensitiveKey(treeAnalysisResult.PropertyPathInParent); - var typeOfPathProperty = propertyValue.GetType(); - - if (!IsNonStringArray(typeOfPathProperty)) - { - LogError(new JsonPatchError( - objectToApplyTo, - operationToReport, - Resources.FormatInvalidIndexForArrayProperty(operationToReport.op, path))); - return; - } - - // now, get the generic type of the enumerable - var genericTypeOfArray = GetIListType(typeOfPathProperty); - var conversionResult = ConvertToActualType(genericTypeOfArray, value); - if (!conversionResult.CanBeConverted) - { - LogError(new JsonPatchError( - objectToApplyTo, - operationToReport, - Resources.FormatInvalidValueForProperty(value, path))); - return; - } - - // get value (it can be cast, we just checked that) - var array = treeAnalysisResult.Container.GetValueForCaseInsensitiveKey( - treeAnalysisResult.PropertyPathInParent) as IList; - - if (appendList) - { - array.Add(conversionResult.ConvertedInstance); - treeAnalysisResult.Container.SetValueForCaseInsensitiveKey( - treeAnalysisResult.PropertyPathInParent, array); - } - else - { - // specified index must not be greater than - // the amount of items in the array - if (positionAsInteger > array.Count) - { - LogError(new JsonPatchError( - objectToApplyTo, - operationToReport, - Resources.FormatInvalidIndexForArrayProperty( - operationToReport.op, - path))); - return; - } - - array.Insert(positionAsInteger, conversionResult.ConvertedInstance); - treeAnalysisResult.Container.SetValueForCaseInsensitiveKey( - treeAnalysisResult.PropertyPathInParent, array); - } - } - else - { - // get the actual type - var typeOfPathProperty = treeAnalysisResult.Container - .GetValueForCaseInsensitiveKey(treeAnalysisResult.PropertyPathInParent).GetType(); - - // can the value be converted to the actual type? - var conversionResult = ConvertToActualType(typeOfPathProperty, value); - if (conversionResult.CanBeConverted) - { - treeAnalysisResult.Container.SetValueForCaseInsensitiveKey( - treeAnalysisResult.PropertyPathInParent, - conversionResult.ConvertedInstance); - } - else - { - LogError(new JsonPatchError( - objectToApplyTo, - operationToReport, - Resources.FormatInvalidValueForProperty(conversionResult.ConvertedInstance, path))); - return; - } - } - } - else - { - // New property - add it. - treeAnalysisResult.Container.Add(treeAnalysisResult.PropertyPathInParent, value); - } - } - else - { - // If it's an array, add to that array. If it's not, we replace. - - // is the path an array (but not a string (= char[]))? In this case, - // the path must end with "/position" or "/-", which we already determined before. - - var patchProperty = treeAnalysisResult.JsonPatchProperty; - - if (appendList || positionAsInteger > -1) - { - if (!IsNonStringArray(patchProperty.Property.PropertyType)) - { - LogError(new JsonPatchError( - objectToApplyTo, - operationToReport, - Resources.FormatInvalidIndexForArrayProperty(operationToReport.op, path))); - return; - } - - // now, get the generic type of the IList<> from Property type. - var genericTypeOfArray = GetIListType(patchProperty.Property.PropertyType); - var conversionResult = ConvertToActualType(genericTypeOfArray, value); - if (!conversionResult.CanBeConverted) - { - LogError(new JsonPatchError( - objectToApplyTo, - operationToReport, - Resources.FormatInvalidValueForProperty(conversionResult.ConvertedInstance, path))); - return; - } - - if (!patchProperty.Property.Readable) - { - LogError(new JsonPatchError( - objectToApplyTo, - operationToReport, - Resources.FormatCannotReadProperty(path))); - return; - } - - var array = (IList)patchProperty.Property.ValueProvider.GetValue(patchProperty.Parent); - if (appendList) - { - array.Add(conversionResult.ConvertedInstance); - } - else if (positionAsInteger <= array.Count) - { - array.Insert(positionAsInteger, conversionResult.ConvertedInstance); - } - else - { - LogError(new JsonPatchError( - objectToApplyTo, - operationToReport, - Resources.FormatInvalidIndexForArrayProperty(operationToReport.op, path))); - return; - } - } - else - { - var conversionResultTuple = ConvertToActualType( - patchProperty.Property.PropertyType, - value); - - if (!conversionResultTuple.CanBeConverted) - { - LogError(new JsonPatchError( - objectToApplyTo, - operationToReport, - Resources.FormatInvalidValueForProperty(value, path))); - return; - } - - if (!patchProperty.Property.Writable) - { - LogError(new JsonPatchError( - objectToApplyTo, - operationToReport, - Resources.FormatCannotUpdateProperty(path))); - return; - } - - patchProperty.Property.ValueProvider.SetValue( - patchProperty.Parent, - conversionResultTuple.ConvertedInstance); - } - } } /// @@ -398,30 +197,19 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters throw new ArgumentNullException(nameof(objectToApplyTo)); } - var valueAtFromLocationResult = GetValueAtLocation(operation.from, objectToApplyTo, operation); - - if (valueAtFromLocationResult.HasError) + object propertyValue; + // Get value at 'from' location and add that value to the 'path' location + if (TryGetValue(operation.from, objectToApplyTo, operation, out propertyValue)) { - // Error has already been logged in GetValueAtLocation. We - // must return, because remove / add should not be allowed to continue - return; + // remove that value + Remove(operation.from, objectToApplyTo, operation); + + // add that value to the path location + Add(operation.path, + propertyValue, + objectToApplyTo, + operation); } - - // remove that value - var removeResult = Remove(operation.from, objectToApplyTo, operation); - - if (removeResult.HasError) - { - // Return => error has already been logged in remove method. We must - // return, because add should not be allowed to continue - return; - } - - // add that value to the path location - Add(operation.path, - valueAtFromLocationResult.PropertyValue, - objectToApplyTo, - operation); } /// @@ -453,240 +241,33 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters 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 + /// 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 RemovedPropertyTypeResult Remove(string path, object objectToApplyTo, Operation operationToReport) + private void Remove(string path, object objectToApplyTo, Operation operationToReport) { - // get path result - var pathResult = GetActualPropertyPath( - path, - objectToApplyTo, - operationToReport); + var parsedPath = new ParsedPath(path); + var visitor = new ObjectVisitor(parsedPath, ContractResolver); - if (pathResult == null) + IAdapter adapter; + var target = objectToApplyTo; + string errorMessage; + if (!visitor.TryVisit(ref target, out adapter, out errorMessage)) { - return new RemovedPropertyTypeResult(null, true); + var error = CreatePathNotFoundError(objectToApplyTo, path, operationToReport, errorMessage); + ReportError(error); + return; } - var removeFromList = pathResult.ExecuteAtEnd; - var positionAsInteger = pathResult.NumericEnd; - var actualPathToProperty = pathResult.PathToProperty; - - var treeAnalysisResult = new ObjectTreeAnalysisResult( - objectToApplyTo, - actualPathToProperty, - ContractResolver); - - if (!treeAnalysisResult.IsValidPathForRemove) + if (!adapter.TryRemove(target, parsedPath.LastSegment, ContractResolver, out errorMessage)) { - LogError(new JsonPatchError( - objectToApplyTo, - operationToReport, - Resources.FormatPropertyCannotBeRemoved(path))); - return new RemovedPropertyTypeResult(null, true); - } - - if (treeAnalysisResult.UseDynamicLogic) - { - // if it's not an array, we can remove the property from - // the dictionary. If it's an array, we need to check the position first. - if (removeFromList || positionAsInteger > -1) - { - var propertyValue = treeAnalysisResult.Container - .GetValueForCaseInsensitiveKey(treeAnalysisResult.PropertyPathInParent); - - // we cannot continue when the value is null, because to be able to - // continue we need to be able to check if the array is a non-string array - if (propertyValue == null) - { - LogError(new JsonPatchError( - objectToApplyTo, - operationToReport, - Resources.FormatCannotDeterminePropertyType(path))); - return new RemovedPropertyTypeResult(null, true); - } - - var typeOfPathProperty = propertyValue.GetType(); - - if (!IsNonStringArray(typeOfPathProperty)) - { - LogError(new JsonPatchError( - objectToApplyTo, - operationToReport, - Resources.FormatInvalidIndexForArrayProperty(operationToReport.op, path))); - return new RemovedPropertyTypeResult(null, true); - } - - // now, get the generic type of the enumerable (we'll return this type) - var genericTypeOfArray = GetIListType(typeOfPathProperty); - - // get the array - var array = (IList)treeAnalysisResult.Container.GetValueForCaseInsensitiveKey( - treeAnalysisResult.PropertyPathInParent); - - if (array.Count == 0) - { - // if the array is empty, we should throw an error - LogError(new JsonPatchError( - objectToApplyTo, - operationToReport, - Resources.FormatInvalidIndexForArrayProperty( - operationToReport.op, - path))); - return new RemovedPropertyTypeResult(null, true); - } - - if (removeFromList) - { - array.RemoveAt(array.Count - 1); - treeAnalysisResult.Container.SetValueForCaseInsensitiveKey( - treeAnalysisResult.PropertyPathInParent, array); - - // return the type of the value that has been removed. - return new RemovedPropertyTypeResult(genericTypeOfArray, false); - } - else - { - if (positionAsInteger >= array.Count) - { - LogError(new JsonPatchError( - objectToApplyTo, - operationToReport, - Resources.FormatInvalidIndexForArrayProperty( - operationToReport.op, - path))); - return new RemovedPropertyTypeResult(null, true); - } - - array.RemoveAt(positionAsInteger); - treeAnalysisResult.Container.SetValueForCaseInsensitiveKey( - treeAnalysisResult.PropertyPathInParent, array); - - // return the type of the value that has been removed. - return new RemovedPropertyTypeResult(genericTypeOfArray, false); - } - } - else - { - // get the property - var getResult = treeAnalysisResult.Container.GetValueForCaseInsensitiveKey( - treeAnalysisResult.PropertyPathInParent); - - // remove the property - treeAnalysisResult.Container.RemoveValueForCaseInsensitiveKey( - treeAnalysisResult.PropertyPathInParent); - - // value is not null, we can determine the type - if (getResult != null) - { - var actualType = getResult.GetType(); - return new RemovedPropertyTypeResult(actualType, false); - } - else - { - return new RemovedPropertyTypeResult(null, false); - } - } - } - else - { - // not dynamic - var patchProperty = treeAnalysisResult.JsonPatchProperty; - - if (removeFromList || positionAsInteger > -1) - { - if (!IsNonStringArray(patchProperty.Property.PropertyType)) - { - LogError(new JsonPatchError( - objectToApplyTo, - operationToReport, - Resources.FormatInvalidIndexForArrayProperty(operationToReport.op, path))); - return new RemovedPropertyTypeResult(null, true); - } - - // now, get the generic type of the IList<> from Property type. - var genericTypeOfArray = GetIListType(patchProperty.Property.PropertyType); - - if (!patchProperty.Property.Readable) - { - LogError(new JsonPatchError( - objectToApplyTo, - operationToReport, - Resources.FormatCannotReadProperty(path))); - return new RemovedPropertyTypeResult(null, true); - } - - var array = (IList)patchProperty.Property.ValueProvider - .GetValue(patchProperty.Parent); - - if (array.Count == 0) - { - // if the array is empty, we should throw an error - LogError(new JsonPatchError( - objectToApplyTo, - operationToReport, - Resources.FormatInvalidIndexForArrayProperty( - operationToReport.op, - path))); - return new RemovedPropertyTypeResult(null, true); - } - - if (removeFromList) - { - array.RemoveAt(array.Count - 1); - - // return the type of the value that has been removed - return new RemovedPropertyTypeResult(genericTypeOfArray, false); - } - else - { - if (positionAsInteger >= array.Count) - { - LogError(new JsonPatchError( - objectToApplyTo, - operationToReport, - Resources.FormatInvalidIndexForArrayProperty( - operationToReport.op, - path))); - return new RemovedPropertyTypeResult(null, true); - } - - array.RemoveAt(positionAsInteger); - - // return the type of the value that has been removed - return new RemovedPropertyTypeResult(genericTypeOfArray, false); - } - } - else - { - if (!patchProperty.Property.Writable) - { - LogError(new JsonPatchError( - objectToApplyTo, - operationToReport, - Resources.FormatCannotUpdateProperty(path))); - return new RemovedPropertyTypeResult(null, true); - } - - // 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 (patchProperty.Property.PropertyType.GetTypeInfo().IsValueType - && Nullable.GetUnderlyingType(patchProperty.Property.PropertyType) == null) - { - value = Activator.CreateInstance(patchProperty.Property.PropertyType); - } - - patchProperty.Property.ValueProvider.SetValue(patchProperty.Parent, value); - return new RemovedPropertyTypeResult(patchProperty.Property.PropertyType, false); - } + var error = CreateOperationFailedError(objectToApplyTo, path, operationToReport, errorMessage); + ReportError(error); + return; } } @@ -722,37 +303,25 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters throw new ArgumentNullException(nameof(objectToApplyTo)); } - var removeResult = Remove(operation.path, objectToApplyTo, operation); + var parsedPath = new ParsedPath(operation.path); + var visitor = new ObjectVisitor(parsedPath, ContractResolver); - if (removeResult.HasError) + IAdapter adapter; + var target = objectToApplyTo; + string errorMessage; + if (!visitor.TryVisit(ref target, out adapter, out errorMessage)) { - // return => error has already been logged in remove method + var error = CreatePathNotFoundError(objectToApplyTo, operation.path, operation, errorMessage); + ReportError(error); return; } - if (!removeResult.HasError && removeResult.ActualType == null) + if (!adapter.TryReplace(target, parsedPath.LastSegment, ContractResolver, operation.value, out errorMessage)) { - // the remove operation completed succesfully, but we could not determine the type. - LogError(new JsonPatchError( - objectToApplyTo, - operation, - Resources.FormatCannotDeterminePropertyType(operation.from))); + var error = CreateOperationFailedError(objectToApplyTo, operation.path, operation, errorMessage); + ReportError(error); return; } - - var conversionResult = ConvertToActualType(removeResult.ActualType, operation.value); - - if (!conversionResult.CanBeConverted) - { - // invalid value for path - LogError(new JsonPatchError( - objectToApplyTo, - operation, - Resources.FormatInvalidValueForProperty(operation.value, operation.path))); - return; - } - - Add(operation.path, conversionResult.ConvertedInstance, objectToApplyTo, operation); } /// @@ -789,36 +358,26 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters throw new ArgumentNullException(nameof(objectToApplyTo)); } - // get value at from location and add that value to the path location - var valueAtFromLocationResult = GetValueAtLocation(operation.from, objectToApplyTo, operation); - - if (valueAtFromLocationResult.HasError) + object propertyValue; + // Get value at 'from' location and add that value to the 'path' location + if (TryGetValue(operation.from, objectToApplyTo, operation, out propertyValue)) { - // Return, error has already been logged in GetValueAtLocation - return; + Add(operation.path, + propertyValue, + objectToApplyTo, + operation); } - - Add(operation.path, - valueAtFromLocationResult.PropertyValue, - objectToApplyTo, - operation); } - /// - /// Method is used by Copy and Move to avoid duplicate code - /// - /// Location where value should be - /// Object to inspect for the desired value - /// Operation to report in case of an error - /// GetValueResult containing value and a bool signifying a possible error - private GetValueResult GetValueAtLocation( - string location, + private bool TryGetValue( + string fromLocation, object objectToGetValueFrom, - Operation operationToReport) + Operation operation, + out object propertyValue) { - if (location == null) + if (fromLocation == null) { - throw new ArgumentNullException(nameof(location)); + throw new ArgumentNullException(nameof(fromLocation)); } if (objectToGetValueFrom == null) @@ -826,280 +385,62 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters throw new ArgumentNullException(nameof(objectToGetValueFrom)); } - if (operationToReport == null) + if (operation == null) { - throw new ArgumentNullException(nameof(operationToReport)); + throw new ArgumentNullException(nameof(operation)); } - // get path result - var pathResult = GetActualPropertyPath( - location, - objectToGetValueFrom, - operationToReport); + propertyValue = null; - if (pathResult == null) + var parsedPath = new ParsedPath(fromLocation); + var visitor = new ObjectVisitor(parsedPath, ContractResolver); + + IAdapter adapter; + var target = objectToGetValueFrom; + string errorMessage; + if (!visitor.TryVisit(ref target, out adapter, out errorMessage)) { - return new GetValueResult(null, true); + var error = CreatePathNotFoundError(objectToGetValueFrom, fromLocation, operation, errorMessage); + ReportError(error); + return false; } - var getAtEndOfList = pathResult.ExecuteAtEnd; - var positionAsInteger = pathResult.NumericEnd; - var actualPathToProperty = pathResult.PathToProperty; - - var treeAnalysisResult = new ObjectTreeAnalysisResult( - objectToGetValueFrom, - actualPathToProperty, - ContractResolver); - - if (treeAnalysisResult.UseDynamicLogic) + if (!adapter.TryGet(target, parsedPath.LastSegment, ContractResolver, out propertyValue, out errorMessage)) { - // if it's not an array, we can remove the property from - // the dictionary. If it's an array, we need to check the position first. - if (getAtEndOfList || positionAsInteger > -1) - { - var propertyValue = treeAnalysisResult.Container - .GetValueForCaseInsensitiveKey(treeAnalysisResult.PropertyPathInParent); - - // we cannot continue when the value is null, because to be able to - // continue we need to be able to check if the array is a non-string array - if (propertyValue == null) - { - LogError(new JsonPatchError( - objectToGetValueFrom, - operationToReport, - Resources.FormatCannotDeterminePropertyType(location))); - return new GetValueResult(null, true); - } - - var typeOfPathProperty = propertyValue.GetType(); - - if (!IsNonStringArray(typeOfPathProperty)) - { - LogError(new JsonPatchError( - objectToGetValueFrom, - operationToReport, - Resources.FormatInvalidIndexForArrayProperty(operationToReport.op, location))); - return new GetValueResult(null, true); - } - - // get the array - var array = (IList)treeAnalysisResult.Container.GetValueForCaseInsensitiveKey( - treeAnalysisResult.PropertyPathInParent); - - if (positionAsInteger >= array.Count) - { - LogError(new JsonPatchError( - objectToGetValueFrom, - operationToReport, - Resources.FormatInvalidIndexForArrayProperty( - operationToReport.op, - location))); - return new GetValueResult(null, true); - } - - if (getAtEndOfList) - { - return new GetValueResult(array[array.Count - 1], false); - } - else - { - return new GetValueResult(array[positionAsInteger], false); - } - } - else - { - // get the property - var propertyValueAtLocation = treeAnalysisResult.Container.GetValueForCaseInsensitiveKey( - treeAnalysisResult.PropertyPathInParent); - - return new GetValueResult(propertyValueAtLocation, false); - } + var error = CreateOperationFailedError(objectToGetValueFrom, fromLocation, operation, errorMessage); + ReportError(error); + return false; } - else - { - // not dynamic - var patchProperty = treeAnalysisResult.JsonPatchProperty; - if (getAtEndOfList || positionAsInteger > -1) - { - if (!IsNonStringArray(patchProperty.Property.PropertyType)) - { - LogError(new JsonPatchError( - objectToGetValueFrom, - operationToReport, - Resources.FormatInvalidIndexForArrayProperty(operationToReport.op, location))); - return new GetValueResult(null, true); - } - - if (!patchProperty.Property.Readable) - { - LogError(new JsonPatchError( - objectToGetValueFrom, - operationToReport, - Resources.FormatCannotReadProperty(location))); - return new GetValueResult(null, true); - } - - var array = (IList)patchProperty.Property.ValueProvider - .GetValue(patchProperty.Parent); - - if (positionAsInteger >= array.Count) - { - LogError(new JsonPatchError( - objectToGetValueFrom, - operationToReport, - Resources.FormatInvalidIndexForArrayProperty( - operationToReport.op, - location))); - return new GetValueResult(null, true); - } - - if (getAtEndOfList) - { - return new GetValueResult(array[array.Count - 1], false); - } - else - { - return new GetValueResult(array[positionAsInteger], false); - } - } - else - { - if (!patchProperty.Property.Readable) - { - LogError(new JsonPatchError( - objectToGetValueFrom, - operationToReport, - Resources.FormatCannotReadProperty( - location))); - return new GetValueResult(null, true); - } - - var propertyValueAtLocation = patchProperty.Property.ValueProvider - .GetValue(patchProperty.Parent); - - return new GetValueResult(propertyValueAtLocation, false); - } - } + return true; } - private bool IsNonStringArray(Type type) - { - if (GetIListType(type) != null) - { - return true; - } - - return (!(type == typeof(string)) && typeof(IList).GetTypeInfo().IsAssignableFrom(type.GetTypeInfo())); - } - - private void LogError(JsonPatchError jsonPatchError) + private void ReportError(JsonPatchError error) { if (LogErrorAction != null) { - LogErrorAction(jsonPatchError); + LogErrorAction(error); } else { - throw new JsonPatchException(jsonPatchError); + throw new JsonPatchException(error); } } - private ConversionResult ConvertToActualType(Type propertyType, object value) + private JsonPatchError CreateOperationFailedError(object target, string path, Operation operation, string errorMessage) { - try - { - var o = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(value), propertyType); - - return new ConversionResult(true, o); - } - catch (Exception) - { - return new ConversionResult(false, null); - } + return new JsonPatchError( + target, + operation, + errorMessage ?? Resources.FormatCannotPerformOperation(operation.op, path)); } - private Type GetIListType(Type type) + private JsonPatchError CreatePathNotFoundError(object target, string path, Operation operation, string errorMessage) { - if (IsGenericListType(type)) - { - return type.GetTypeInfo().GenericTypeArguments[0]; - } - - foreach (Type interfaceType in type.GetTypeInfo().ImplementedInterfaces) - { - if (IsGenericListType(interfaceType)) - { - return interfaceType.GetTypeInfo().GenericTypeArguments[0]; - } - } - - return null; - } - - private bool IsGenericListType(Type type) - { - if (type.GetTypeInfo().IsGenericType && - type.GetGenericTypeDefinition() == typeof(IList<>)) - { - return true; - } - - return false; - } - - private ActualPropertyPathResult GetActualPropertyPath( - string propertyPath, - object objectToApplyTo, - Operation operationToReport) - { - if (propertyPath == null) - { - throw new ArgumentNullException(nameof(propertyPath)); - } - - if (objectToApplyTo == null) - { - throw new ArgumentNullException(nameof(objectToApplyTo)); - } - - if (operationToReport == null) - { - throw new ArgumentNullException(nameof(operationToReport)); - } - - if (propertyPath.EndsWith("/-")) - { - return new ActualPropertyPathResult(-1, propertyPath.Substring(0, propertyPath.Length - 2), true); - } - else - { - var possibleIndex = propertyPath.Substring(propertyPath.LastIndexOf("/") + 1); - int castedIndex = -1; - if (int.TryParse(possibleIndex, out castedIndex)) - { - // has numeric end. - if (castedIndex > -1) - { - var pathToProperty = propertyPath.Substring( - 0, - propertyPath.LastIndexOf('/' + castedIndex.ToString())); - - return new ActualPropertyPathResult(castedIndex, pathToProperty, false); - } - else - { - // negative position - invalid path - LogError(new JsonPatchError( - objectToApplyTo, - operationToReport, - Resources.FormatNegativeIndexForArrayProperty(operationToReport.op, propertyPath))); - return null; - } - } - - return new ActualPropertyPathResult(-1, propertyPath, false); - } + return new JsonPatchError( + target, + operation, + errorMessage ?? Resources.FormatTargetLocationNotFound(operation.op, path)); } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.JsonPatch/Helpers/ActualPropertyPathResult.cs b/src/Microsoft.AspNetCore.JsonPatch/Helpers/ActualPropertyPathResult.cs deleted file mode 100644 index 1967bf6d90..0000000000 --- a/src/Microsoft.AspNetCore.JsonPatch/Helpers/ActualPropertyPathResult.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -namespace Microsoft.AspNetCore.JsonPatch.Helpers -{ - internal class ActualPropertyPathResult - { - public int NumericEnd { get; private set; } - public string PathToProperty { get; set; } - public bool ExecuteAtEnd { get; set; } - - public ActualPropertyPathResult( - int numericEnd, - string pathToProperty, - bool executeAtEnd) - { - NumericEnd = numericEnd; - PathToProperty = pathToProperty; - ExecuteAtEnd = executeAtEnd; - } - } -} diff --git a/src/Microsoft.AspNetCore.JsonPatch/Helpers/ExpandoObjectDictionaryExtensions.cs b/src/Microsoft.AspNetCore.JsonPatch/Helpers/ExpandoObjectDictionaryExtensions.cs deleted file mode 100644 index aa9fa2158b..0000000000 --- a/src/Microsoft.AspNetCore.JsonPatch/Helpers/ExpandoObjectDictionaryExtensions.cs +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; - -namespace Microsoft.AspNetCore.JsonPatch.Helpers -{ - // Helper methods to allow case-insensitive key search - internal static class ExpandoObjectDictionaryExtensions - { - internal static void SetValueForCaseInsensitiveKey( - this IDictionary propertyDictionary, - string key, - object value) - { - foreach (KeyValuePair kvp in propertyDictionary) - { - if (string.Equals(kvp.Key, key, StringComparison.OrdinalIgnoreCase)) - { - propertyDictionary[kvp.Key] = value; - break; - } - } - } - - internal static void RemoveValueForCaseInsensitiveKey( - this IDictionary propertyDictionary, - string key) - { - string realKey = null; - foreach (KeyValuePair kvp in propertyDictionary) - { - if (string.Equals(kvp.Key, key, StringComparison.OrdinalIgnoreCase)) - { - realKey = kvp.Key; - break; - } - } - - if (realKey != null) - { - propertyDictionary.Remove(realKey); - } - } - - internal static object GetValueForCaseInsensitiveKey( - this IDictionary propertyDictionary, - string key) - { - foreach (KeyValuePair kvp in propertyDictionary) - { - if (string.Equals(kvp.Key, key, StringComparison.OrdinalIgnoreCase)) - { - return kvp.Value; - } - } - - throw new ArgumentException(Resources.FormatDictionaryKeyNotFound(key)); - } - - internal static bool ContainsCaseInsensitiveKey( - this IDictionary propertyDictionary, - string key) - { - foreach (KeyValuePair kvp in propertyDictionary) - { - if (string.Equals(kvp.Key, key, StringComparison.OrdinalIgnoreCase)) - { - return true; - } - } - - return false; - } - } -} diff --git a/src/Microsoft.AspNetCore.JsonPatch/Helpers/ObjectTreeAnalyisResult.cs b/src/Microsoft.AspNetCore.JsonPatch/Helpers/ObjectTreeAnalyisResult.cs deleted file mode 100644 index 782859ad5f..0000000000 --- a/src/Microsoft.AspNetCore.JsonPatch/Helpers/ObjectTreeAnalyisResult.cs +++ /dev/null @@ -1,209 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using Newtonsoft.Json.Serialization; - -namespace Microsoft.AspNetCore.JsonPatch.Helpers -{ - internal class ObjectTreeAnalysisResult - { - // either the property is part of the container dictionary, - // or we have a direct reference to a JsonPatchProperty instance - - public bool UseDynamicLogic { get; private set; } - - public bool IsValidPathForAdd { get; private set; } - - public bool IsValidPathForRemove { get; private set; } - - public IDictionary Container { get; private set; } - - public string PropertyPathInParent { get; private set; } - - public JsonPatchProperty JsonPatchProperty { get; private set; } - - public ObjectTreeAnalysisResult( - object objectToSearch, - string propertyPath, - IContractResolver contractResolver) - { - // construct the analysis result. - - // split the propertypath, and if necessary, remove the first - // empty item (that's the case when it starts with a "/") - var propertyPathTree = propertyPath.Split( - new char[] { '/' }, - StringSplitOptions.RemoveEmptyEntries); - - // we've now got a split up property tree "base/property/otherproperty/..." - int lastPosition = 0; - object targetObject = objectToSearch; - for (int i = 0; i < propertyPathTree.Length; i++) - { - lastPosition = i; - - // if the current target object is an ExpandoObject (IDictionary), - // we cannot use the ContractResolver. - var dictionary = targetObject as IDictionary; - if (dictionary != null) - { - // find the value in the dictionary - if (dictionary.ContainsCaseInsensitiveKey(propertyPathTree[i])) - { - var possibleNewTargetObject = dictionary.GetValueForCaseInsensitiveKey(propertyPathTree[i]); - - // unless we're at the last item, we should set the targetobject - // to the new object. If we're at the last item, we need to stop - if (i != propertyPathTree.Length - 1) - { - targetObject = possibleNewTargetObject; - } - } - else - { - break; - } - } - else - { - // if the current part of the path is numeric, this means we're trying - // to get the propertyInfo of a specific object in an array. To allow - // for this, the previous value (targetObject) must be an IEnumerable, and - // the position must exist. - - int numericValue = -1; - if (int.TryParse(propertyPathTree[i], out numericValue)) - { - var element = GetElementAtFromObject(targetObject, numericValue); - if (element != null) - { - targetObject = element; - } - else - { - break; - } - } - else - { - var jsonContract = (JsonObjectContract)contractResolver.ResolveContract(targetObject.GetType()); - - // does the property exist? - var attemptedProperty = jsonContract - .Properties - .FirstOrDefault(p => string.Equals(p.PropertyName, propertyPathTree[i], StringComparison.OrdinalIgnoreCase)); - - if (attemptedProperty != null) - { - // unless we're at the last item, we should continue searching. - // If we're at the last item, we need to stop - if ((i != propertyPathTree.Length - 1)) - { - targetObject = attemptedProperty.ValueProvider.GetValue(targetObject); - } - } - else - { - // property cannot be found, and we're not working with dynamics. - // Stop, and return invalid path. - break; - } - } - } - } - - if (propertyPathTree.Length - lastPosition != 1) - { - IsValidPathForAdd = false; - IsValidPathForRemove = false; - return; - } - - // two things can happen now. The targetproperty can be an IDictionary - in that - // case, it's valid for add if there's 1 item left in the propertyPathTree. - // - // it can also be a property info. In that case, if there's nothing left in the path - // tree we're at the end, if there's one left we can try and set that. - if (targetObject is IDictionary) - { - UseDynamicLogic = true; - - Container = (IDictionary)targetObject; - IsValidPathForAdd = true; - PropertyPathInParent = propertyPathTree[propertyPathTree.Length - 1]; - - // to be able to remove this property, it must exist - IsValidPathForRemove = Container.ContainsCaseInsensitiveKey(PropertyPathInParent); - } - else if (targetObject is IList) - { - UseDynamicLogic = false; - - int index; - if (!Int32.TryParse(propertyPathTree[propertyPathTree.Length - 1], out index)) - { - // We only support indexing into a list - IsValidPathForAdd = false; - IsValidPathForRemove = false; - return; - } - - IsValidPathForAdd = true; - IsValidPathForRemove = ((IList)targetObject).Count > index; - PropertyPathInParent = propertyPathTree[propertyPathTree.Length - 1]; - } - else - { - UseDynamicLogic = false; - - var property = propertyPathTree[propertyPathTree.Length - 1]; - var jsonContract = (JsonObjectContract)contractResolver.ResolveContract(targetObject.GetType()); - var attemptedProperty = jsonContract - .Properties - .FirstOrDefault(p => string.Equals(p.PropertyName, property, StringComparison.OrdinalIgnoreCase)); - - if (attemptedProperty == null) - { - IsValidPathForAdd = false; - IsValidPathForRemove = false; - } - else - { - IsValidPathForAdd = true; - IsValidPathForRemove = true; - JsonPatchProperty = new JsonPatchProperty(attemptedProperty, targetObject); - PropertyPathInParent = property; - } - } - } - - private object GetElementAtFromObject(object targetObject, int numericValue) - { - if (numericValue > -1) - { - // Check if the targetobject is an IEnumerable, - // and if the position is valid. - if (targetObject is IEnumerable) - { - var indexable = ((IEnumerable)targetObject).Cast(); - - if (indexable.Count() >= numericValue) - { - return indexable.ElementAt(numericValue); - } - else { return null; } - } - else { return null; } - } - else - { - return null; - } - } - - } -} diff --git a/src/Microsoft.AspNetCore.JsonPatch/Helpers/RemovedPropertyTypeResult.cs b/src/Microsoft.AspNetCore.JsonPatch/Helpers/RemovedPropertyTypeResult.cs deleted file mode 100644 index c548f55c6e..0000000000 --- a/src/Microsoft.AspNetCore.JsonPatch/Helpers/RemovedPropertyTypeResult.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; - -namespace Microsoft.AspNetCore.JsonPatch.Helpers -{ - /// - /// Return value for Remove operation. The combination tells us what to do next (if this operation - /// is called from inside another operation, eg: Replace, Copy. - /// - /// Possible combo: - /// - ActualType contains type: operation succesfully completed, can continue when called from inside - /// another operation - /// - ActualType null and HasError true: operation not completed succesfully, should not be allowed to continue - /// - ActualType null and HasError false: operation completed succesfully, but we should not be allowed to - /// continue when called from inside another method as we could not verify the type of the removed property. - /// This happens when the value of an item in an ExpandoObject dictionary is null. - /// - internal class RemovedPropertyTypeResult - { - /// - /// The type of the removed property (value) - /// - public Type ActualType { get; private set; } - - /// - /// HasError: true when an error occurred, the operation didn't complete succesfully - /// - public bool HasError { get; set; } - - public RemovedPropertyTypeResult(Type actualType, bool hasError) - { - ActualType = actualType; - HasError = hasError; - } - } -} diff --git a/src/Microsoft.AspNetCore.JsonPatch/Helpers/ConversionResult.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/ConversionResult.cs similarity index 64% rename from src/Microsoft.AspNetCore.JsonPatch/Helpers/ConversionResult.cs rename to src/Microsoft.AspNetCore.JsonPatch/Internal/ConversionResult.cs index 00a7513d44..77181eb18d 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Helpers/ConversionResult.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Internal/ConversionResult.cs @@ -1,17 +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.Helpers +namespace Microsoft.AspNetCore.JsonPatch.Internal { - internal class ConversionResult + public class ConversionResult { - public bool CanBeConverted { get; private set; } - public object ConvertedInstance { get; private set; } - 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/Microsoft.AspNetCore.JsonPatch/Internal/ConversionResultProvider.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/ConversionResultProvider.cs new file mode 100644 index 0000000000..bdf4122394 --- /dev/null +++ b/src/Microsoft.AspNetCore.JsonPatch/Internal/ConversionResultProvider.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 Newtonsoft.Json; + +namespace Microsoft.AspNetCore.JsonPatch.Internal +{ + public static class ConversionResultProvider + { + public static ConversionResult ConvertTo(object value, Type typeToConvertTo) + { + try + { + var deserialized = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(value), typeToConvertTo); + return new ConversionResult(true, deserialized); + } + catch + { + return new ConversionResult(canBeConverted: false, convertedInstance: null); + } + } + } +} diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/DictionaryAdapter.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/DictionaryAdapter.cs new file mode 100644 index 0000000000..4c7651e475 --- /dev/null +++ b/src/Microsoft.AspNetCore.JsonPatch/Internal/DictionaryAdapter.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.Collections; +using Newtonsoft.Json.Serialization; + +namespace Microsoft.AspNetCore.JsonPatch.Internal +{ + public class DictionaryAdapter : IAdapter + { + public bool TryAdd( + object target, + string segment, + IContractResolver contractResolver, + object value, + out string errorMessage) + { + var dictionary = (IDictionary)target; + + // As per JsonPatch spec, if a key already exists, adding should replace the existing value + dictionary[segment] = value; + + errorMessage = null; + return true; + } + + public bool TryGet( + object target, + string segment, + IContractResolver contractResolver, + out object value, + out string errorMessage) + { + var dictionary = (IDictionary)target; + + value = dictionary[segment]; + errorMessage = null; + return true; + } + + public bool TryRemove( + object target, + string segment, + IContractResolver contractResolver, + out string errorMessage) + { + var dictionary = (IDictionary)target; + + // As per JsonPatch spec, the target location must exist for remove to be successful + if (!dictionary.Contains(segment)) + { + errorMessage = Resources.FormatTargetLocationAtPathSegmentNotFound(segment); + return false; + } + + dictionary.Remove(segment); + errorMessage = null; + return true; + } + + public bool TryReplace( + object target, + string segment, + IContractResolver contractResolver, + object value, + out string errorMessage) + { + var dictionary = (IDictionary)target; + + // As per JsonPatch spec, the target location must exist for remove to be successful + if (!dictionary.Contains(segment)) + { + errorMessage = Resources.FormatTargetLocationAtPathSegmentNotFound(segment); + return false; + } + + dictionary[segment] = value; + errorMessage = null; + return true; + } + + public bool TryTraverse( + object target, + string segment, + IContractResolver contractResolver, + out object nextTarget, + out string errorMessage) + { + var dictionary = target as IDictionary; + if (dictionary == null) + { + nextTarget = null; + errorMessage = null; + return false; + } + + if (dictionary.Contains(segment)) + { + nextTarget = dictionary[segment]; + errorMessage = null; + return true; + } + else + { + nextTarget = null; + errorMessage = null; + return false; + } + } + } +} diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/ExpandoObjectAdapter.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/ExpandoObjectAdapter.cs new file mode 100644 index 0000000000..681b5309e6 --- /dev/null +++ b/src/Microsoft.AspNetCore.JsonPatch/Internal/ExpandoObjectAdapter.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.Collections.Generic; +using System.Dynamic; +using Newtonsoft.Json.Serialization; + +namespace Microsoft.AspNetCore.JsonPatch.Internal +{ + public class ExpandoObjectAdapter : IAdapter + { + public bool TryAdd( + object target, + string segment, + IContractResolver contractResolver, + object value, + out string errorMessage) + { + var dictionary = (IDictionary)target; + + var key = dictionary.GetKeyUsingCaseInsensitiveSearch(segment); + + // As per JsonPatch spec, if a key already exists, adding should replace the existing value + dictionary[key] = ConvertValue(dictionary, key, value); + + errorMessage = null; + return true; + } + + public bool TryGet( + object target, + string segment, + IContractResolver contractResolver, + out object value, + out string errorMessage) + { + var dictionary = (IDictionary)target; + + var key = dictionary.GetKeyUsingCaseInsensitiveSearch(segment); + value = dictionary[key]; + + errorMessage = null; + return true; + } + + public bool TryRemove( + object target, + string segment, + IContractResolver contractResolver, + out string errorMessage) + { + var dictionary = (IDictionary)target; + + var key = dictionary.GetKeyUsingCaseInsensitiveSearch(segment); + + // As per JsonPatch spec, the target location must exist for remove to be successful + if (!dictionary.ContainsKey(key)) + { + errorMessage = Resources.FormatTargetLocationAtPathSegmentNotFound(segment); + return false; + } + + dictionary.Remove(key); + + errorMessage = null; + return true; + } + + public bool TryReplace( + object target, + string segment, + IContractResolver contractResolver, + object value, + out string errorMessage) + { + var dictionary = (IDictionary)target; + + var key = dictionary.GetKeyUsingCaseInsensitiveSearch(segment); + + // As per JsonPatch spec, the target location must exist for remove to be successful + if (!dictionary.ContainsKey(key)) + { + errorMessage = Resources.FormatTargetLocationAtPathSegmentNotFound(segment); + return false; + } + + dictionary[key] = ConvertValue(dictionary, key, value); + + errorMessage = null; + return true; + } + + public bool TryTraverse( + object target, + string segment, + IContractResolver contractResolver, + out object nextTarget, + out string errorMessage) + { + var expandoObject = target as ExpandoObject; + if (expandoObject == null) + { + errorMessage = null; + nextTarget = null; + return false; + } + + var dictionary = (IDictionary)expandoObject; + + var key = dictionary.GetKeyUsingCaseInsensitiveSearch(segment); + + if (dictionary.ContainsKey(key)) + { + nextTarget = dictionary[key]; + errorMessage = null; + return true; + } + else + { + nextTarget = null; + errorMessage = null; + return false; + } + } + + private object ConvertValue(IDictionary dictionary, string key, object newValue) + { + object existingValue = null; + if (dictionary.TryGetValue(key, out existingValue)) + { + if (existingValue != null) + { + var conversionResult = ConversionResultProvider.ConvertTo(newValue, existingValue.GetType()); + if (conversionResult.CanBeConverted) + { + return conversionResult.ConvertedInstance; + } + } + } + return newValue; + } + } +} diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/ExpandoObjectDictionaryExtensions.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/ExpandoObjectDictionaryExtensions.cs new file mode 100644 index 0000000000..8bb60dd2a7 --- /dev/null +++ b/src/Microsoft.AspNetCore.JsonPatch/Internal/ExpandoObjectDictionaryExtensions.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.Generic; + +namespace Microsoft.AspNetCore.JsonPatch.Internal +{ + // Helper methods to allow case-insensitive key search + public static class ExpandoObjectDictionaryExtensions + { + internal static string GetKeyUsingCaseInsensitiveSearch( + this IDictionary propertyDictionary, + string key) + { + foreach (var keyInDictionary in propertyDictionary.Keys) + { + if (string.Equals(key, keyInDictionary, StringComparison.OrdinalIgnoreCase)) + { + return keyInDictionary; + } + } + return key; + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.JsonPatch/Helpers/ExpressionHelpers.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/ExpressionHelpers.cs similarity index 95% rename from src/Microsoft.AspNetCore.JsonPatch/Helpers/ExpressionHelpers.cs rename to src/Microsoft.AspNetCore.JsonPatch/Internal/ExpressionHelpers.cs index d9b516cc0e..c978330e5c 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Helpers/ExpressionHelpers.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Internal/ExpressionHelpers.cs @@ -1,16 +1,15 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using Newtonsoft.Json; using System; using System.Globalization; -using System.Linq; using System.Linq.Expressions; using System.Reflection; +using Newtonsoft.Json; -namespace Microsoft.AspNetCore.JsonPatch.Helpers +namespace Microsoft.AspNetCore.JsonPatch.Internal { - internal static class ExpressionHelpers + public static class ExpressionHelpers { public static string GetPath(Expression> expr) where TModel : class { @@ -59,7 +58,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Helpers } else { - // Get property name, respecting JsonProperty attribute + // Get property name, respecting JsonProperty attribute return GetPropertyNameFromMemberExpression(memberExpression); } case ExpressionType.Parameter: @@ -73,7 +72,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Helpers private static string GetPropertyNameFromMemberExpression(MemberExpression memberExpression) { // if there's a JsonProperty attribute, we must return the PropertyName - // from the attribute rather than the member name + // from the attribute rather than the member name var jsonPropertyAttribute = memberExpression.Member.GetCustomAttribute( typeof(JsonPropertyAttribute), true); diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/IAdapter.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/IAdapter.cs new file mode 100644 index 0000000000..1866b42ed4 --- /dev/null +++ b/src/Microsoft.AspNetCore.JsonPatch/Internal/IAdapter.cs @@ -0,0 +1,44 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using 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); + } +} diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/ListAdapter.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/ListAdapter.cs new file mode 100644 index 0000000000..c3da14fe5a --- /dev/null +++ b/src/Microsoft.AspNetCore.JsonPatch/Internal/ListAdapter.cs @@ -0,0 +1,299 @@ +// Copyright (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.Serialization; + +namespace Microsoft.AspNetCore.JsonPatch.Internal +{ + public class ListAdapter : IAdapter + { + public bool TryAdd( + object target, + string segment, + IContractResolver contractResolver, + object value, + out string errorMessage) + { + var list = (IList)target; + + Type typeArgument = null; + if (!TryGetListTypeArgument(list, out typeArgument, out errorMessage)) + { + return false; + } + + PositionInfo positionInfo; + if (!TryGetPositionInfo(list, segment, out positionInfo, out errorMessage)) + { + return false; + } + + object convertedValue = null; + if (!TryConvertValue(value, typeArgument, segment, out convertedValue, out errorMessage)) + { + return false; + } + + if (positionInfo.Type == PositionType.EndOfList) + { + list.Add(convertedValue); + } + else + { + list.Insert(positionInfo.Index, convertedValue); + } + + errorMessage = null; + return true; + } + + public bool TryGet( + object target, + string segment, + IContractResolver contractResolver, + out object value, + out string errorMessage) + { + var list = (IList)target; + + Type typeArgument = null; + if (!TryGetListTypeArgument(list, out typeArgument, out errorMessage)) + { + value = null; + return false; + } + + PositionInfo positionInfo; + if (!TryGetPositionInfo(list, segment, out 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 bool TryRemove( + object target, + string segment, + IContractResolver contractResolver, + out string errorMessage) + { + var list = (IList)target; + + Type typeArgument = null; + if (!TryGetListTypeArgument(list, out typeArgument, out errorMessage)) + { + return false; + } + + PositionInfo positionInfo; + if (!TryGetPositionInfo(list, segment, out 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 bool TryReplace( + object target, + string segment, + IContractResolver contractResolver, + object value, + out string errorMessage) + { + var list = (IList)target; + + Type typeArgument = null; + if (!TryGetListTypeArgument(list, out typeArgument, out errorMessage)) + { + return false; + } + + PositionInfo positionInfo; + if (!TryGetPositionInfo(list, segment, out positionInfo, out errorMessage)) + { + return false; + } + + object convertedValue = null; + if (!TryConvertValue(value, typeArgument, segment, out 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 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; + } + + int 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; + } + + private 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; + } + + private 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; + } + } + } + + private bool TryGetPositionInfo(IList list, string segment, out PositionInfo positionInfo, out string errorMessage) + { + if (segment == "-") + { + positionInfo = new PositionInfo(PositionType.EndOfList, -1); + errorMessage = null; + return true; + } + + int position = -1; + if (int.TryParse(segment, out position)) + { + if (position >= 0 && position < list.Count) + { + positionInfo = new PositionInfo(PositionType.Index, position); + errorMessage = null; + return true; + } + else + { + positionInfo = default(PositionInfo); + errorMessage = Resources.FormatIndexOutOfBounds(segment); + return false; + } + } + else + { + positionInfo = default(PositionInfo); + errorMessage = Resources.FormatInvalidIndexValue(segment); + return false; + } + } + + private struct PositionInfo + { + public PositionInfo(PositionType type, int index) + { + Type = type; + Index = index; + } + + public PositionType Type { get; } + public int Index { get; } + } + + private enum PositionType + { + Index, // valid index + EndOfList, // '-' + Invalid, // Ex: not an integer + OutOfBounds + } + } +} diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/ObjectVisitor.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/ObjectVisitor.cs new file mode 100644 index 0000000000..b604f65a17 --- /dev/null +++ b/src/Microsoft.AspNetCore.JsonPatch/Internal/ObjectVisitor.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; +using System.Dynamic; +using Newtonsoft.Json.Serialization; + +namespace Microsoft.AspNetCore.JsonPatch.Internal +{ + public class ObjectVisitor + { + private readonly IContractResolver _contractResolver; + private readonly ParsedPath _path; + + public ObjectVisitor(ParsedPath path, IContractResolver contractResolver) + { + if (contractResolver == null) + { + throw new ArgumentNullException(nameof(contractResolver)); + } + + _path = path; + _contractResolver = contractResolver; + } + + public bool TryVisit(ref object target, out IAdapter adapter, out string errorMessage) + { + if (target == null) + { + adapter = null; + errorMessage = null; + return false; + } + + adapter = SelectAdapater(target); + + // Traverse until the penultimate segment to get the target object and adapter + for (var i = 0; i < _path.Segments.Count - 1; i++) + { + object next; + if (!adapter.TryTraverse(target, _path.Segments[i], _contractResolver, out next, out errorMessage)) + { + adapter = null; + return false; + } + + target = next; + adapter = SelectAdapater(target); + } + + errorMessage = null; + return true; + } + + private IAdapter SelectAdapater(object targetObject) + { + if (targetObject is ExpandoObject) + { + return new ExpandoObjectAdapter(); + } + else if (targetObject is IDictionary) + { + return new DictionaryAdapter(); + } + else if (targetObject is IList) + { + return new ListAdapter(); + } + else + { + return new PocoAdapter(); + } + } + } +} diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/ParsedPath.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/ParsedPath.cs new file mode 100644 index 0000000000..fe786b86c1 --- /dev/null +++ b/src/Microsoft.AspNetCore.JsonPatch/Internal/ParsedPath.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. + +using System; +using System.Collections.Generic; + +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 = path.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries); + } + + public string LastSegment + { + get + { + if (_segments == null || _segments.Length == 0) + { + return null; + } + + return _segments[_segments.Length - 1]; + } + } + + public IReadOnlyList Segments => _segments ?? Empty; + } +} diff --git a/src/Microsoft.AspNetCore.JsonPatch/Helpers/PathHelpers.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/PathHelpers.cs similarity index 95% rename from src/Microsoft.AspNetCore.JsonPatch/Helpers/PathHelpers.cs rename to src/Microsoft.AspNetCore.JsonPatch/Internal/PathHelpers.cs index 99bb2f1536..7ef8fe7baf 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Helpers/PathHelpers.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Internal/PathHelpers.cs @@ -3,7 +3,7 @@ using Microsoft.AspNetCore.JsonPatch.Exceptions; -namespace Microsoft.AspNetCore.JsonPatch.Helpers +namespace Microsoft.AspNetCore.JsonPatch.Internal { internal static class PathHelpers { diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/PocoAdapter.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/PocoAdapter.cs new file mode 100644 index 0000000000..0755e132e1 --- /dev/null +++ b/src/Microsoft.AspNetCore.JsonPatch/Internal/PocoAdapter.cs @@ -0,0 +1,205 @@ +// Copyright (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.Serialization; + +namespace Microsoft.AspNetCore.JsonPatch.Internal +{ + public class PocoAdapter : IAdapter + { + public bool TryAdd( + object target, + string segment, + IContractResolver contractResolver, + object value, + out string errorMessage) + { + JsonProperty jsonProperty = null; + if (!TryGetJsonProperty(target, contractResolver, segment, out jsonProperty)) + { + errorMessage = Resources.FormatTargetLocationAtPathSegmentNotFound(segment); + return false; + } + + if (!jsonProperty.Writable) + { + errorMessage = Resources.FormatCannotUpdateProperty(segment); + return false; + } + + object convertedValue = null; + if (!TryConvertValue(value, jsonProperty.PropertyType, out convertedValue)) + { + errorMessage = Resources.FormatInvalidValueForProperty(value); + return false; + } + + jsonProperty.ValueProvider.SetValue(target, convertedValue); + + errorMessage = null; + return true; + } + + public bool TryGet( + object target, + string segment, + IContractResolver contractResolver, + out object value, + out string errorMessage) + { + JsonProperty jsonProperty = null; + if (!TryGetJsonProperty(target, contractResolver, segment, out 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 bool TryRemove( + object target, + string segment, + IContractResolver contractResolver, + out string errorMessage) + { + JsonProperty jsonProperty = null; + if (!TryGetJsonProperty(target, contractResolver, segment, out 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 bool TryReplace( + object target, + string segment, + IContractResolver + contractResolver, + object value, + out string errorMessage) + { + JsonProperty jsonProperty = null; + if (!TryGetJsonProperty(target, contractResolver, segment, out jsonProperty)) + { + errorMessage = Resources.FormatTargetLocationAtPathSegmentNotFound(segment); + return false; + } + + if (!jsonProperty.Writable) + { + errorMessage = Resources.FormatCannotUpdateProperty(segment); + return false; + } + + object convertedValue = null; + if (!TryConvertValue(value, jsonProperty.PropertyType, out convertedValue)) + { + errorMessage = Resources.FormatInvalidValueForProperty(value); + return false; + } + + jsonProperty.ValueProvider.SetValue(target, convertedValue); + + errorMessage = null; + return true; + } + + public bool TryTraverse( + object target, + string segment, + IContractResolver contractResolver, + out object value, + out string errorMessage) + { + if (target == null) + { + value = null; + errorMessage = null; + return false; + } + + JsonProperty jsonProperty = null; + if (TryGetJsonProperty(target, contractResolver, segment, out jsonProperty)) + { + value = jsonProperty.ValueProvider.GetValue(target); + errorMessage = null; + return true; + } + + value = null; + errorMessage = Resources.FormatTargetLocationAtPathSegmentNotFound(segment); + return false; + } + + private bool TryGetJsonProperty( + object target, + IContractResolver contractResolver, + string segment, + out JsonProperty jsonProperty) + { + var jsonObjectContract = contractResolver.ResolveContract(target.GetType()) as JsonObjectContract; + if (jsonObjectContract != null) + { + var pocoProperty = jsonObjectContract + .Properties + .FirstOrDefault(p => string.Equals(p.PropertyName, segment, StringComparison.OrdinalIgnoreCase)); + + if (pocoProperty != null) + { + jsonProperty = pocoProperty; + return true; + } + } + + jsonProperty = null; + return false; + } + + private 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/Microsoft.AspNetCore.JsonPatch/JsonPatchDocument.cs b/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocument.cs index c9c34459a9..72e93e0302 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocument.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocument.cs @@ -5,7 +5,7 @@ using System; using System.Collections.Generic; using Microsoft.AspNetCore.JsonPatch.Adapters; using Microsoft.AspNetCore.JsonPatch.Converters; -using Microsoft.AspNetCore.JsonPatch.Helpers; +using Microsoft.AspNetCore.JsonPatch.Internal; using Microsoft.AspNetCore.JsonPatch.Operations; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; @@ -13,7 +13,7 @@ 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 + // 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 @@ -145,7 +145,7 @@ namespace Microsoft.AspNetCore.JsonPatch } /// - /// Apply this JsonPatchDocument + /// Apply this JsonPatchDocument /// /// Object to apply the JsonPatchDocument to public void ApplyTo(object objectToApplyTo) @@ -159,7 +159,7 @@ namespace Microsoft.AspNetCore.JsonPatch } /// - /// Apply this JsonPatchDocument + /// Apply this JsonPatchDocument /// /// Object to apply the JsonPatchDocument to /// Action to log errors @@ -174,7 +174,7 @@ namespace Microsoft.AspNetCore.JsonPatch } /// - /// Apply this JsonPatchDocument + /// Apply this JsonPatchDocument /// /// Object to apply the JsonPatchDocument to /// IObjectAdapter instance to use when applying diff --git a/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs b/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs index 530b414060..afb5eb3ff1 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; using System.Linq.Expressions; using Microsoft.AspNetCore.JsonPatch.Adapters; using Microsoft.AspNetCore.JsonPatch.Converters; -using Microsoft.AspNetCore.JsonPatch.Helpers; +using Microsoft.AspNetCore.JsonPatch.Internal; using Microsoft.AspNetCore.JsonPatch.Operations; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; @@ -502,7 +502,7 @@ namespace Microsoft.AspNetCore.JsonPatch /// Copy from a property to a location in a list /// /// - /// source location + /// source location /// target location /// position /// @@ -623,7 +623,7 @@ namespace Microsoft.AspNetCore.JsonPatch } /// - /// Apply this JsonPatchDocument + /// Apply this JsonPatchDocument /// /// Object to apply the JsonPatchDocument to public void ApplyTo(TModel objectToApplyTo) @@ -637,7 +637,7 @@ namespace Microsoft.AspNetCore.JsonPatch } /// - /// Apply this JsonPatchDocument + /// Apply this JsonPatchDocument /// /// Object to apply the JsonPatchDocument to /// Action to log errors @@ -652,7 +652,7 @@ namespace Microsoft.AspNetCore.JsonPatch } /// - /// Apply this JsonPatchDocument + /// Apply this JsonPatchDocument /// /// Object to apply the JsonPatchDocument to /// IObjectAdapter instance to use when applying diff --git a/src/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs index 70f76f1fa3..9e00cc2f00 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs @@ -26,6 +26,22 @@ namespace Microsoft.AspNetCore.JsonPatch return string.Format(CultureInfo.CurrentCulture, GetString("CannotDeterminePropertyType"), p0); } + /// + /// The '{0}' operation at path '{1}' could not be performed. + /// + internal static string CannotPerformOperation + { + get { return GetString("CannotPerformOperation"); } + } + + /// + /// The '{0}' operation at path '{1}' could not be performed. + /// + internal static string FormatCannotPerformOperation(object p0, object p1) + { + return string.Format(CultureInfo.CurrentCulture, GetString("CannotPerformOperation"), p0, p1); + } + /// /// The property at '{0}' could not be read. /// @@ -59,35 +75,35 @@ namespace Microsoft.AspNetCore.JsonPatch } /// - /// The key '{0}' was not found. + /// The index value provided by path segment '{0}' is out of bounds of the array size. /// - internal static string DictionaryKeyNotFound + internal static string IndexOutOfBounds { - get { return GetString("DictionaryKeyNotFound"); } + get { return GetString("IndexOutOfBounds"); } } /// - /// The key '{0}' was not found. + /// The index value provided by path segment '{0}' is out of bounds of the array size. /// - internal static string FormatDictionaryKeyNotFound(object p0) + internal static string FormatIndexOutOfBounds(object p0) { - return string.Format(CultureInfo.CurrentCulture, GetString("DictionaryKeyNotFound"), p0); + return string.Format(CultureInfo.CurrentCulture, GetString("IndexOutOfBounds"), p0); } /// - /// For operation '{0}' on array property at path '{1}', the index is larger than the array size. + /// The path segment '{0}' is invalid for an array index. /// - internal static string InvalidIndexForArrayProperty + internal static string InvalidIndexValue { - get { return GetString("InvalidIndexForArrayProperty"); } + get { return GetString("InvalidIndexValue"); } } /// - /// For operation '{0}' on array property at path '{1}', the index is larger than the array size. + /// The path segment '{0}' is invalid for an array index. /// - internal static string FormatInvalidIndexForArrayProperty(object p0, object p1) + internal static string FormatInvalidIndexValue(object p0) { - return string.Format(CultureInfo.CurrentCulture, GetString("InvalidIndexForArrayProperty"), p0, p1); + return string.Format(CultureInfo.CurrentCulture, GetString("InvalidIndexValue"), p0); } /// @@ -106,22 +122,6 @@ namespace Microsoft.AspNetCore.JsonPatch return string.Format(CultureInfo.CurrentCulture, GetString("InvalidJsonPatchDocument"), p0); } - /// - /// For operation '{0}', the provided path is invalid for array property at path '{1}'. - /// - internal static string InvalidPathForArrayProperty - { - get { return GetString("InvalidPathForArrayProperty"); } - } - - /// - /// For operation '{0}', the provided path is invalid for array property at path '{1}'. - /// - internal static string FormatInvalidPathForArrayProperty(object p0, object p1) - { - return string.Format(CultureInfo.CurrentCulture, GetString("InvalidPathForArrayProperty"), p0, p1); - } - /// /// The provided string '{0}' is an invalid path. /// @@ -139,7 +139,7 @@ namespace Microsoft.AspNetCore.JsonPatch } /// - /// The value '{0}' is invalid for property at path '{1}'. + /// The value '{0}' is invalid for target location. /// internal static string InvalidValueForProperty { @@ -147,27 +147,11 @@ namespace Microsoft.AspNetCore.JsonPatch } /// - /// The value '{0}' is invalid for property at path '{1}'. + /// The value '{0}' is invalid for target location. /// - internal static string FormatInvalidValueForProperty(object p0, object p1) + internal static string FormatInvalidValueForProperty(object p0) { - return string.Format(CultureInfo.CurrentCulture, GetString("InvalidValueForProperty"), p0, p1); - } - - /// - /// For operation '{0}' on array property at path '{1}', the index is negative. - /// - internal static string NegativeIndexForArrayProperty - { - get { return GetString("NegativeIndexForArrayProperty"); } - } - - /// - /// For operation '{0}' on array property at path '{1}', the index is negative. - /// - internal static string FormatNegativeIndexForArrayProperty(object p0, object p1) - { - return string.Format(CultureInfo.CurrentCulture, GetString("NegativeIndexForArrayProperty"), p0, p1); + return string.Format(CultureInfo.CurrentCulture, GetString("InvalidValueForProperty"), p0); } /// @@ -187,51 +171,67 @@ namespace Microsoft.AspNetCore.JsonPatch } /// - /// The property at path '{0}' could not be added. + /// The type '{0}' which is an array is not supported for json patch operations as it has a fixed size. /// - internal static string PropertyCannotBeAdded + internal static string PatchNotSupportedForArrays { - get { return GetString("PropertyCannotBeAdded"); } + get { return GetString("PatchNotSupportedForArrays"); } } /// - /// The property at path '{0}' could not be added. + /// The type '{0}' which is an array is not supported for json patch operations as it has a fixed size. /// - internal static string FormatPropertyCannotBeAdded(object p0) + internal static string FormatPatchNotSupportedForArrays(object p0) { - return string.Format(CultureInfo.CurrentCulture, GetString("PropertyCannotBeAdded"), p0); + return string.Format(CultureInfo.CurrentCulture, GetString("PatchNotSupportedForArrays"), p0); } /// - /// The property at path '{0}' could not be removed. + /// 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 PropertyCannotBeRemoved + internal static string PatchNotSupportedForNonGenericLists { - get { return GetString("PropertyCannotBeRemoved"); } + get { return GetString("PatchNotSupportedForNonGenericLists"); } } /// - /// The property at path '{0}' could not be removed. + /// 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 FormatPropertyCannotBeRemoved(object p0) + internal static string FormatPatchNotSupportedForNonGenericLists(object p0) { - return string.Format(CultureInfo.CurrentCulture, GetString("PropertyCannotBeRemoved"), p0); + return string.Format(CultureInfo.CurrentCulture, GetString("PatchNotSupportedForNonGenericLists"), p0); } /// - /// Property does not exist at path '{0}'. + /// The target location specified by path segment '{0}' was not found. /// - internal static string PropertyDoesNotExist + internal static string TargetLocationAtPathSegmentNotFound { - get { return GetString("PropertyDoesNotExist"); } + get { return GetString("TargetLocationAtPathSegmentNotFound"); } } /// - /// Property does not exist at path '{0}'. + /// The target location specified by path segment '{0}' was not found. /// - internal static string FormatPropertyDoesNotExist(object p0) + internal static string FormatTargetLocationAtPathSegmentNotFound(object p0) { - return string.Format(CultureInfo.CurrentCulture, GetString("PropertyDoesNotExist"), p0); + return 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 { return GetString("TargetLocationNotFound"); } + } + + /// + /// For operation '{0}', the target location specified by path '{1}' was not found. + /// + internal static string FormatTargetLocationNotFound(object p0, object p1) + { + return string.Format(CultureInfo.CurrentCulture, GetString("TargetLocationNotFound"), p0, p1); } /// diff --git a/src/Microsoft.AspNetCore.JsonPatch/Resources.resx b/src/Microsoft.AspNetCore.JsonPatch/Resources.resx index 59ae2b59c3..a7b50520ac 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Resources.resx +++ b/src/Microsoft.AspNetCore.JsonPatch/Resources.resx @@ -120,44 +120,44 @@ 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 key '{0}' was not found. + + The index value provided by path segment '{0}' is out of bounds of the array size. - - For operation '{0}' on array property at path '{1}', the index is larger than the array size. + + The path segment '{0}' is invalid for an array index. The type '{0}' was malformed and could not be parsed. - - For operation '{0}', the provided path is invalid for array property at path '{1}'. - The provided string '{0}' is an invalid path. - The value '{0}' is invalid for property at path '{1}'. - - - For operation '{0}' on array property at path '{1}', the index is negative. + The value '{0}' is invalid for target location. '{0}' must be of type '{1}'. - - The property at path '{0}' could not be added. + + The type '{0}' which is an array is not supported for json patch operations as it has a fixed size. - - The property at path '{0}' could not be removed. + + The type '{0}' which is a non generic list is not supported for json patch operations. Only generic list types are supported. - - Property does not exist at path '{0}'. + + 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. diff --git a/src/Microsoft.AspNetCore.JsonPatch/project.json b/src/Microsoft.AspNetCore.JsonPatch/project.json index 5180ee7e23..c9beba3639 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/project.json +++ b/src/Microsoft.AspNetCore.JsonPatch/project.json @@ -22,14 +22,18 @@ }, "dependencies": { "NETStandard.Library": "1.6.1-*", - "Newtonsoft.Json": "9.0.1" + "Newtonsoft.Json": "9.0.1", + "Microsoft.Extensions.ClosedGenericMatcher.Sources": { + "type": "build", + "version": "1.1.0-*" + } }, "frameworks": { - "netstandard1.1": { + "net451": {}, + "netstandard1.3": { "dependencies": { "Microsoft.CSharp": "4.3.0-*", - "System.ComponentModel.TypeConverter": "4.3.0-*", - "System.Runtime.Serialization.Primitives": "4.3.0-*" + "System.Reflection.TypeExtensions": "4.1.0-*" } } } diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/DictionaryAdapterTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/DictionaryAdapterTest.cs new file mode 100644 index 0000000000..6a88bd6cc7 --- /dev/null +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/DictionaryAdapterTest.cs @@ -0,0 +1,176 @@ +// Copyright (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 Moq; +using Newtonsoft.Json.Serialization; +using Xunit; + +namespace Microsoft.AspNetCore.JsonPatch.Internal +{ + public class DictionaryAdapterTest + { + [Fact] + public void Add_KeyWhichAlreadyExists_ReplacesExistingValue() + { + // Arrange + var nameKey = "Name"; + var dictionary = new Dictionary(StringComparer.Ordinal); + dictionary[nameKey] = "Mike"; + var dictionaryAdapter = new DictionaryAdapter(); + var resolver = new Mock(MockBehavior.Strict); + string message = null; + + // Act + var addStatus = dictionaryAdapter.TryAdd(dictionary, nameKey, resolver.Object, "James", out message); + + // Assert + Assert.True(addStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.Equal(1, dictionary.Count); + Assert.Equal("James", dictionary[nameKey]); + } + + [Fact] + public void Get_UsingCaseSensitiveKey_FailureScenario() + { + // Arrange + var dictionaryAdapter = new DictionaryAdapter(); + var resolver = new Mock(MockBehavior.Strict); + string message = null; + var nameKey = "Name"; + var dictionary = new Dictionary(StringComparer.Ordinal); + + // Act + var addStatus = dictionaryAdapter.TryAdd(dictionary, nameKey, resolver.Object, "James", out message); + + // Assert + Assert.True(addStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.Equal(1, dictionary.Count); + Assert.Equal("James", dictionary[nameKey]); + + // Act + object outValue = null; + addStatus = dictionaryAdapter.TryGet(dictionary, nameKey.ToUpper(), resolver.Object, out outValue, out message); + + // Assert + Assert.True(addStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.Null(outValue); + } + + [Fact] + public void Get_UsingCaseSensitiveKey_SuccessScenario() + { + // Arrange + var dictionaryAdapter = new DictionaryAdapter(); + var resolver = new Mock(MockBehavior.Strict); + string message = null; + var nameKey = "Name"; + var dictionary = new Dictionary(StringComparer.Ordinal); + + // Act + var addStatus = dictionaryAdapter.TryAdd(dictionary, nameKey, resolver.Object, "James", out message); + + // Assert + Assert.True(addStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.Equal(1, dictionary.Count); + Assert.Equal("James", dictionary[nameKey]); + + // Act + object outValue = null; + addStatus = dictionaryAdapter.TryGet(dictionary, nameKey, resolver.Object, out 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 Mock(MockBehavior.Strict); + string message = null; + + // Act + var replaceStatus = dictionaryAdapter.TryReplace(dictionary, nameKey, resolver.Object, "James", out message); + + // Assert + Assert.True(replaceStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.Equal(1, dictionary.Count); + Assert.Equal("James", dictionary[nameKey]); + } + + [Fact] + public void Replace_NonExistingKey_Fails() + { + // Arrange + var nameKey = "Name"; + var dictionary = new Dictionary(StringComparer.Ordinal); + var dictionaryAdapter = new DictionaryAdapter(); + var resolver = new Mock(MockBehavior.Strict); + string message = null; + + // Act + var replaceStatus = dictionaryAdapter.TryReplace(dictionary, nameKey, resolver.Object, "Mike", out message); + + // Assert + Assert.False(replaceStatus); + Assert.Equal( + string.Format("The target location specified by path segment '{0}' was not found.", nameKey), + message); + Assert.Equal(0, dictionary.Count); + } + + [Fact] + public void Remove_NonExistingKey_Fails() + { + // Arrange + var nameKey = "Name"; + var dictionary = new Dictionary(StringComparer.Ordinal); + var dictionaryAdapter = new DictionaryAdapter(); + var resolver = new Mock(MockBehavior.Strict); + string message = null; + + // Act + var removeStatus = dictionaryAdapter.TryRemove(dictionary, nameKey, resolver.Object, out message); + + // Assert + Assert.False(removeStatus); + Assert.Equal( + string.Format("The target location specified by path segment '{0}' was not found.", nameKey), + message); + Assert.Equal(0, dictionary.Count); + } + + [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 Mock(MockBehavior.Strict); + string message = null; + + // Act + var removeStatus = dictionaryAdapter.TryRemove(dictionary, nameKey, resolver.Object, out message); + + //Assert + Assert.True(removeStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.Equal(0, dictionary.Count); + } + } +} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddOperationTests.cs index cb5f090d0f..cbd44a7ef9 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddOperationTests.cs @@ -32,7 +32,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic deserialized.ApplyTo(doc); }); Assert.Equal( - "The property at path '/NewInt' could not be added.", + string.Format("The target location specified by path segment '{0}' was not found.", "NewInt"), exception.Message); } @@ -76,7 +76,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic deserialized.ApplyTo(doc); }); Assert.Equal( - "The property at path '/Nested/NewInt' could not be added.", + string.Format("The target location specified by path segment '{0}' was not found.", "NewInt"), exception.Message); } @@ -101,7 +101,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic deserialized.ApplyTo(doc); }); Assert.Equal( - "The property at path '/Nested/NewInt' could not be added.", + string.Format("The target location specified by path segment '{0}' was not found.", "NewInt"), exception.Message); } @@ -214,7 +214,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic deserialized.ApplyTo(doc); }); Assert.Equal( - "The property at path '/ComplexProperty' could not be added.", + string.Format("The target location specified by path segment '{0}' was not found.", "ComplexProperty"), exception.Message); } @@ -238,7 +238,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic deserialized.ApplyTo(doc); }); Assert.Equal( - "The property at path '/StringProperty' could not be updated.", + string.Format("The property at path '{0}' could not be updated.", "StringProperty"), exception.Message); } @@ -336,7 +336,10 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic deserialized.ApplyTo(doc); }); Assert.Equal( - "The property at path '/DynamicProperty/OtherProperty/IntProperty' could not be added.", + string.Format( + "For operation '{0}', the target location specified by path '{1}' was not found.", + "add", + "/DynamicProperty/OtherProperty/IntProperty"), exception.Message); } @@ -374,7 +377,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic deserialized.ApplyTo(doc); }); Assert.Equal( - "The property at path '/baz/bat' could not be added.", + string.Format("The target location specified by path segment '{0}' was not found.", "baz"), exception.Message); } @@ -434,7 +437,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic deserialized.ApplyTo(doc); }); Assert.Equal( - "For operation 'add' on array property at path '/IntegerList/-1', the index is negative.", + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), exception.Message); } @@ -478,30 +481,10 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic deserialized.ApplyTo(doc); }); Assert.Equal( - "For operation 'add' on array property at path '/IntegerList/4', the index is larger than the array size.", + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "4"), exception.Message); } - [Fact] - public void AddToListAtEndWithSerialization() - { - var doc = new - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); - patchDoc.Add("IntegerList/3", 4); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 1, 2, 3, 4 }, doc.IntegerList); - } - [Fact] public void AddToListAtBeginning() { @@ -542,7 +525,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic deserialized.ApplyTo(doc); }); Assert.Equal( - "For operation 'add' on array property at path '/IntegerList/-1', the index is negative.", + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), exception.Message); } diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddTypedOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddTypedOperationTests.cs index 098e97d850..f28d877ea4 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddTypedOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddTypedOperationTests.cs @@ -30,7 +30,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic deserialized.ApplyTo(doc); }); Assert.Equal( - "For operation 'add' on array property at path '/IntegerList/-1', the index is negative.", + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), exception.Message); } @@ -85,7 +85,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic deserialized.ApplyTo(doc); }); Assert.Equal( - "The property at path '/ListOfSimpleDTO/-1/IntegerList/0' could not be added.", + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), exception.Message); } @@ -114,7 +114,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic deserialized.ApplyTo(doc); }); Assert.Equal( - "The property at path '/ListOfSimpleDTO/20/IntegerList/0' could not be added.", + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "20"), exception.Message); } } diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveOperationTests.cs index b436bb4d23..6e903bf2ec 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveOperationTests.cs @@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic deserialized.ApplyTo(doc); }); Assert.Equal( - "The property at path '/Test' could not be updated.", + string.Format("The property at path '{0}' could not be updated.", "Test"), exception.Message); } @@ -53,7 +53,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic deserialized.ApplyTo(doc); }); Assert.Equal( - "The property at path '/NonExisting' could not be removed.", + string.Format("The target location specified by path segment '{0}' was not found.", "NonExisting"), exception.Message); } @@ -250,7 +250,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic deserialized.ApplyTo(doc); }); Assert.Equal( - "For operation 'remove' on array property at path '/SimpleDTO/IntegerList/3', the index is larger than the array size.", + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "3"), exception.Message); } @@ -275,8 +275,8 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic deserialized.ApplyTo(doc); }); Assert.Equal( - "For operation 'remove' on array property at path '/SimpleDTO/IntegerList/-1', the index is negative.", - exception.Message); + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), + exception.Message); } [Fact] diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveTypedOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveTypedOperationTests.cs index d716dafe9a..126706eef2 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveTypedOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveTypedOperationTests.cs @@ -70,7 +70,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic deserialized.ApplyTo(doc); }); Assert.Equal( - "For operation 'remove' on array property at path '/IntegerList/3', the index is larger than the array size.", + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "3"), exception.Message); } @@ -94,7 +94,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic deserialized.ApplyTo(doc); }); Assert.Equal( - "For operation 'remove' on array property at path '/IntegerList/-1', the index is negative.", + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), exception.Message); } @@ -187,8 +187,8 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic deserialized.ApplyTo(doc); }); Assert.Equal( - "For operation 'remove' on array property at path '/SimpleDTO/IntegerList/3', the index is larger than the array size.", - exception.Message); + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "3"), + exception.Message); } [Fact] @@ -214,7 +214,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic deserialized.ApplyTo(doc); }); Assert.Equal( - "For operation 'remove' on array property at path '/SimpleDTO/IntegerList/-1', the index is negative.", + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), exception.Message); } diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceOperationTests.cs index 8dff9b6a98..b8e7196068 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceOperationTests.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Dynamic; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using Xunit; namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic @@ -25,7 +26,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic JsonPatchDocument patchDoc = new JsonPatchDocument(); patchDoc.Replace("GuidValue", newGuid); - // serialize & deserialize + // serialize & deserialize var serialized = JsonConvert.SerializeObject(patchDoc); var deserizalized = JsonConvert.DeserializeObject(serialized); @@ -45,7 +46,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic JsonPatchDocument patchDoc = new JsonPatchDocument(); patchDoc.Replace("GuidValue", newGuid); - // serialize & deserialize + // serialize & deserialize var serialized = JsonConvert.SerializeObject(patchDoc); var deserizalized = JsonConvert.DeserializeObject(serialized); @@ -70,7 +71,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic JsonPatchDocument patchDoc = new JsonPatchDocument(); patchDoc.Replace("nestedobject/GuidValue", newGuid); - // serialize & deserialize + // serialize & deserialize var serialized = JsonConvert.SerializeObject(patchDoc); var deserizalized = JsonConvert.DeserializeObject(serialized); @@ -98,7 +99,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic JsonPatchDocument patchDoc = new JsonPatchDocument(); patchDoc.Replace("SimpleDTO", newDTO); - // serialize & deserialize + // serialize & deserialize var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); @@ -201,6 +202,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic var deserialized = JsonConvert.DeserializeObject(serialized); deserialized.ApplyTo(doc); + Assert.Equal(new List() { 4, 5, 6 }, doc.IntegerList); } diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/ListAdapterTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/ListAdapterTest.cs new file mode 100644 index 0000000000..ee331a2b30 --- /dev/null +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/ListAdapterTest.cs @@ -0,0 +1,302 @@ +// Copyright (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(); + string message = null; + + // Act + var addStatus = listAdapter.TryAdd(targetObject, "0", resolver.Object, "40", out message); + + // Assert + Assert.False(addStatus); + Assert.Equal( + string.Format( + "The type '{0}' which is an array is not supported for json patch operations as it has a fixed size.", + targetObject.GetType().FullName), + 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(); + string message = null; + + // Act + var addStatus = listAdapter.TryAdd(targetObject, "-", resolver.Object, "40", out message); + + // Assert + Assert.False(addStatus); + Assert.Equal( + string.Format( + "The type '{0}' which is a non generic list is not supported for json patch operations. Only generic list types are supported.", + targetObject.GetType().FullName), + message); + } + + [Theory] + [InlineData("-1")] + [InlineData("-2")] + [InlineData("2")] + [InlineData("3")] + public void Patch_WithOutOfBoundsIndex_Fails(string position) + { + // Arrange + var resolver = new Mock(MockBehavior.Strict); + var targetObject = new List() { "James", "Mike" }; + var listAdapter = new ListAdapter(); + string message = null; + + // Act + var addStatus = listAdapter.TryAdd(targetObject, position, resolver.Object, "40", out message); + + // Assert + Assert.False(addStatus); + Assert.Equal( + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", position), + 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(); + string message = null; + + // Act + var addStatus = listAdapter.TryAdd(targetObject, position, resolver.Object, "40", out message); + + // Assert + Assert.False(addStatus); + Assert.Equal( + string.Format("The path segment '{0}' is invalid for an array index.", position), + 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(); + string message = null; + + // Act + var addStatus = listAdapter.TryAdd(targetObject, "-", resolver.Object, "20", out 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" }; + string message = null; + + // Act + var addStatus = listAdapter.TryAdd(targetObject, "-", resolver.Object, value: null, errorMessage: out 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_NonCompatibleType_Fails() + { + // Arrange + var resolver = new Mock(MockBehavior.Strict); + var targetObject = (new List() { 10, 20 }).AsReadOnly(); + var listAdapter = new ListAdapter(); + string message = null; + + // Act + var addStatus = listAdapter.TryAdd(targetObject, "-", resolver.Object, "James", out message); + + // Assert + Assert.False(addStatus); + Assert.Equal(string.Format("The value '{0}' is invalid for target location.", "James"), 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(); + string message = null; + + // Act + var addStatus = listAdapter.TryAdd(targetObject, position, resolver.Object, value, out 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 Replace_NonCompatibleType_Fails() + { + // Arrange + var resolver = new Mock(MockBehavior.Strict); + var targetObject = (new List() { 10, 20 }).AsReadOnly(); + var listAdapter = new ListAdapter(); + string message = null; + + // Act + var replaceStatus = listAdapter.TryReplace(targetObject, "-", resolver.Object, "James", out message); + + // Assert + Assert.False(replaceStatus); + Assert.Equal( + string.Format("The value '{0}' is invalid for target location.", "James"), + message); + } + + [Fact] + public void Replace_ReplacesValue_AtTheEnd() + { + // Arrange + var resolver = new Mock(MockBehavior.Strict); + var targetObject = new List() { 10, 20 }; + var listAdapter = new ListAdapter(); + string message = null; + + // Act + var replaceStatus = listAdapter.TryReplace(targetObject, "-", resolver.Object, "30", out 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(); + string message = null; + + // Act + var replaceStatus = listAdapter.TryReplace(targetObject, position, resolver.Object, "30", out message); + + // Assert + Assert.True(replaceStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.Equal(expected, targetObject); + } + } +} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/NestedDTO.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/NestedDTO.cs index aa767557c3..90be5152cb 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/NestedDTO.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/NestedDTO.cs @@ -1,7 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -namespace Microsoft.AspNetCore.JsonPatch.Test +namespace Microsoft.AspNetCore.JsonPatch { public class NestedDTO { diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/NestedObjectTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/NestedObjectTests.cs index 6215da6bcd..345ffe2201 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/NestedObjectTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/NestedObjectTests.cs @@ -7,7 +7,7 @@ using Microsoft.AspNetCore.JsonPatch.Exceptions; using Newtonsoft.Json; using Xunit; -namespace Microsoft.AspNetCore.JsonPatch.Test +namespace Microsoft.AspNetCore.JsonPatch { public class NestedObjectTests { @@ -386,8 +386,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test // Act & Assert var exception = Assert.Throws(() => { patchDoc.ApplyTo(doc); }); Assert.Equal( - "For operation 'add' on array property at path '/simpledto/integerlist/4', the index is " + - "larger than the array size.", + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "4"), exception.Message); } @@ -417,8 +416,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test deserialized.ApplyTo(doc); }); Assert.Equal( - "For operation 'add' on array property at path '/simpledto/integerlist/4', the index is " + - "larger than the array size.", + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "4"), exception.Message); } @@ -445,8 +443,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test //Assert Assert.Equal( - "For operation 'add' on array property at path '/simpledto/integerlist/4', the index is larger than " + - "the array size.", + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "4"), logger.ErrorMessage); } @@ -470,7 +467,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test // Act & Assert var exception = Assert.Throws(() => { patchDoc.ApplyTo(doc); }); Assert.Equal( - "For operation 'add' on array property at path '/simpledto/integerlist/-1', the index is negative.", + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), exception.Message); } @@ -499,7 +496,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test deserialized.ApplyTo(doc); }); Assert.Equal( - "For operation 'add' on array property at path '/simpledto/integerlist/-1', the index is negative.", + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), exception.Message); } @@ -527,7 +524,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test //Assert Assert.Equal( - "For operation 'add' on array property at path '/simpledto/integerlist/-1', the index is negative.", + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), logger.ErrorMessage); } @@ -697,8 +694,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test // Act & Assert var exception = Assert.Throws(() => { patchDoc.ApplyTo(doc); }); Assert.Equal( - "For operation 'remove' on array property at path '/simpledto/integerlist/3', the index is " + - "larger than the array size.", + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "3"), exception.Message); } @@ -727,8 +723,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test deserialized.ApplyTo(doc); }); Assert.Equal( - "For operation 'remove' on array property at path '/simpledto/integerlist/3', the index is " + - "larger than the array size.", + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "3"), exception.Message); } @@ -754,8 +749,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test // Assert Assert.Equal( - "For operation 'remove' on array property at path '/simpledto/integerlist/3', the index is " + - "larger than the array size.", + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "3"), logger.ErrorMessage); } @@ -777,7 +771,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Test // Act & Assert var exception = Assert.Throws(() => { patchDoc.ApplyTo(doc); }); - Assert.Equal("For operation 'remove' on array property at path '/simpledto/integerlist/-1', the index is negative.", exception.Message); + Assert.Equal( + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), + exception.Message); } [Fact] @@ -804,7 +800,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Test { deserialized.ApplyTo(doc); }); - Assert.Equal("For operation 'remove' on array property at path '/simpledto/integerlist/-1', the index is negative.", exception.Message); + Assert.Equal( + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), + exception.Message); } [Fact] @@ -829,7 +827,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Test patchDoc.ApplyTo(doc, logger.LogErrorMessage); // Assert - Assert.Equal("For operation 'remove' on array property at path '/simpledto/integerlist/-1', the index is negative.", logger.ErrorMessage); + Assert.Equal( + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), + logger.ErrorMessage); } [Fact] @@ -1239,8 +1239,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test // Act & Assert var exception = Assert.Throws(() => { patchDoc.ApplyTo(doc); }); Assert.Equal( - "For operation 'replace' on array property at path '/simpledto/integerlist/3', the index is " + - "larger than the array size.", + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "3"), exception.Message); } @@ -1269,8 +1268,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test deserialized.ApplyTo(doc); }); Assert.Equal( - "For operation 'replace' on array property at path '/simpledto/integerlist/3', the index is " + - "larger than the array size.", + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "3"), exception.Message); } @@ -1298,8 +1296,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test // Assert Assert.Equal( - "For operation 'replace' on array property at path '/simpledto/integerlist/3', the index is " + - "larger than the array size.", + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "3"), logger.ErrorMessage); } @@ -1321,7 +1318,8 @@ namespace Microsoft.AspNetCore.JsonPatch.Test // Act & Assert var exception = Assert.Throws(() => { patchDoc.ApplyTo(doc); }); - Assert.Equal("For operation 'replace' on array property at path '/simpledto/integerlist/-1', the index is negative.", + Assert.Equal( + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), exception.Message); } @@ -1347,7 +1345,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test // Act & Assert var exception = Assert.Throws(() => { deserialized.ApplyTo(doc); }); Assert.Equal( - "For operation 'replace' on array property at path '/simpledto/integerlist/-1', the index is negative.", + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), exception.Message); } @@ -1375,7 +1373,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test // Assert Assert.Equal( - "For operation 'replace' on array property at path '/simpledto/integerlist/-1', the index is negative.", + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), logger.ErrorMessage); } diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs index 98a72e1bf8..88693fdbd5 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs @@ -8,7 +8,7 @@ using Microsoft.AspNetCore.JsonPatch.Exceptions; using Newtonsoft.Json; using Xunit; -namespace Microsoft.AspNetCore.JsonPatch.Test +namespace Microsoft.AspNetCore.JsonPatch.Adapters { public class ObjectAdapterTests { @@ -157,8 +157,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test // Act & Assert var exception = Assert.Throws(() => { patchDoc.ApplyTo(doc); }); Assert.Equal( - "For operation 'add' on array property at path '/integerlist/4', the index is " + - "larger than the array size.", + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "4"), exception.Message); } @@ -181,8 +180,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test // Act & Assert var exception = Assert.Throws(() => { deserialized.ApplyTo(doc); }); Assert.Equal( - "For operation 'add' on array property at path '/integerlist/4', the index is " + - "larger than the array size.", + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "4"), exception.Message); } @@ -206,54 +204,10 @@ namespace Microsoft.AspNetCore.JsonPatch.Test // Assert Assert.Equal( - "For operation 'add' on array property at path '/integerlist/4', the index is " + - "larger than the array size.", + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "4"), logger.ErrorMessage); } - [Fact] - public void AddToListAtEnd() - { - // Arrange - var doc = new SimpleDTO() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.IntegerList, 4, 3); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 1, 2, 3, 4 }, doc.IntegerList); - } - - [Fact] - public void AddToListAtEndWithSerialization() - { - // Arrange - var doc = new SimpleDTO() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.IntegerList, 4, 3); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 1, 2, 3, 4 }, doc.IntegerList); - } - [Fact] public void AddToListAtBeginning() { @@ -313,7 +267,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test // Act & Assert var exception = Assert.Throws(() => { patchDoc.ApplyTo(doc); }); Assert.Equal( - "For operation 'add' on array property at path '/integerlist/-1', the index is negative.", + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), exception.Message); } @@ -336,7 +290,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test // Act & Assert var exception = Assert.Throws(() => { deserialized.ApplyTo(doc); }); Assert.Equal( - "For operation 'add' on array property at path '/integerlist/-1', the index is negative.", + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), exception.Message); } @@ -359,7 +313,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test // Assert Assert.Equal( - "For operation 'add' on array property at path '/integerlist/-1', the index is negative.", + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), logger.ErrorMessage); } @@ -508,8 +462,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test // Act & Assert var exception = Assert.Throws(() => { patchDoc.ApplyTo(doc); }); Assert.Equal( - "For operation 'remove' on array property at path '/integerlist/3', the index is " + - "larger than the array size.", + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "3"), exception.Message); } @@ -532,8 +485,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test // Act & Assert var exception = Assert.Throws(() => { deserialized.ApplyTo(doc); }); Assert.Equal( - "For operation 'remove' on array property at path '/integerlist/3', the index is " + - "larger than the array size.", + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "3"), exception.Message); } @@ -557,8 +509,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test // Assert Assert.Equal( - "For operation 'remove' on array property at path '/integerlist/3', the index is " + - "larger than the array size.", + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "3"), logger.ErrorMessage); } @@ -577,7 +528,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Test // Act & Assert var exception = Assert.Throws(() => { patchDoc.ApplyTo(doc); }); - Assert.Equal("For operation 'remove' on array property at path '/integerlist/-1', the index is negative.", exception.Message); + Assert.Equal( + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), + exception.Message); } [Fact] @@ -598,7 +551,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Test // Act & Assert var exception = Assert.Throws(() => { deserialized.ApplyTo(doc); }); - Assert.Equal("For operation 'remove' on array property at path '/integerlist/-1', the index is negative.", exception.Message); + Assert.Equal( + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), + exception.Message); } [Fact] @@ -621,7 +576,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Test // Assert - Assert.Equal("For operation 'remove' on array property at path '/integerlist/-1', the index is negative.", logger.ErrorMessage); + Assert.Equal( + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), + logger.ErrorMessage); } [Fact] @@ -1123,8 +1080,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test patchDoc.ApplyTo(doc); }); Assert.Equal( - "For operation 'replace' on array property at path '/integerlist/3', the index is " + - "larger than the array size.", + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "3"), exception.Message); } @@ -1149,8 +1105,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test deserialized.ApplyTo(doc); }); Assert.Equal( - "For operation 'replace' on array property at path '/integerlist/3', the index is " + - "larger than the array size.", + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "3"), exception.Message); } @@ -1172,7 +1127,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Test { patchDoc.ApplyTo(doc); }); - Assert.Equal("For operation 'replace' on array property at path '/integerlist/-1', the index is negative.", exception.Message); + Assert.Equal( + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), + exception.Message); } [Fact] @@ -1196,7 +1153,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Test { deserialized.ApplyTo(doc); }); - Assert.Equal("For operation 'replace' on array property at path '/integerlist/-1', the index is negative.", exception.Message); + Assert.Equal( + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), + exception.Message); } [Fact] @@ -1733,5 +1692,577 @@ namespace Microsoft.AspNetCore.JsonPatch.Test Assert.Equal(0, doc.IntegerValue); Assert.Equal(new List() { 1, 2, 3, 5 }, doc.IntegerList); } + + private class Class6 + { + public IDictionary DictionaryOfStringToInteger { get; } = new Dictionary(); + } + + [Fact] + public void Add_WhenDictionary_ValueIsNonObject_Succeeds() + { + // Arrange + var model = new Class6(); + 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 Remove_WhenDictionary_ValueIsNonObject_Succeeds() + { + // Arrange + var model = new Class6(); + 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 Replace_WhenDictionary_ValueIsNonObject_Succeeds() + { + // Arrange + var model = new Class6(); + 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"]); + } + + private class Customer + { + public string Name { get; set; } + public Address Address { get; set; } + } + + private class Address + { + public string City { get; set; } + } + + private class Class8 + { + public IDictionary DictionaryOfStringToCustomer { get; } = new Dictionary(); + } + + [Fact] + public void Replace_WhenDictionary_ValueAPocoType_Succeeds() + { + // Arrange + var key1 = "key1"; + var value1 = new Customer() { Name = "Jamesss" }; + var key2 = "key2"; + var value2 = new Customer() { Name = "Mike" }; + var model = new Class8(); + 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 Replace_WhenDictionary_ValueAPocoType_Succeeds_WithSerialization() + { + // Arrange + var key1 = "key1"; + var value1 = new Customer() { Name = "Jamesss" }; + var key2 = "key2"; + var value2 = new Customer() { Name = "Mike" }; + var model = new Class8(); + model.DictionaryOfStringToCustomer[key1] = value1; + model.DictionaryOfStringToCustomer[key2] = value2; + var patchDocument = new JsonPatchDocument(); + patchDocument.Replace($"/DictionaryOfStringToCustomer/{key1}/Name", "James"); + var serialized = JsonConvert.SerializeObject(patchDocument); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // 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 Replace_DeepNested_DictionaryValue_Succeeds() + { + // Arrange + var key1 = "key1"; + var value1 = new Customer() { Name = "Jamesss" }; + var key2 = "key2"; + var value2 = new Customer() { Name = "Mike" }; + var model = new Class8(); + 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 Replace_DeepNested_DictionaryValue_Succeeds_WithSerialization() + { + // Arrange + var key1 = "key1"; + var value1 = new Customer() { Name = "James", Address = new Address { City = "Redmond" } }; + var key2 = "key2"; + var value2 = new Customer() { Name = "Mike", Address = new Address { City = "Seattle" } }; + var model = new Class8(); + model.DictionaryOfStringToCustomer[key1] = value1; + model.DictionaryOfStringToCustomer[key2] = value2; + var patchDocument = new JsonPatchDocument(); + patchDocument.Replace($"/DictionaryOfStringToCustomer/{key1}/Address/City", "Bellevue"); + var serialized = JsonConvert.SerializeObject(patchDocument); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + patchDocument.ApplyTo(model); + + // Assert + Assert.Equal(2, model.DictionaryOfStringToCustomer.Count); + var actualValue1 = model.DictionaryOfStringToCustomer[key1]; + Assert.NotNull(actualValue1); + Assert.Equal("James", actualValue1.Name); + var address = actualValue1.Address; + Assert.NotNull(address); + Assert.Equal("Bellevue", address.City); + } + + class Class9 + { + public List StringList { get; set; } = new List(); + } + + [Fact] + public void AddToNonIntegerListAtEnd() + { + // Arrange + var model = new Class9() + { + StringList = new List() + }; + model.StringList.Add("string1"); + model.StringList.Add("string2"); + var patchDoc = new JsonPatchDocument(); + patchDoc.Add("/StringList/0", "string3"); + + // Act + patchDoc.ApplyTo(model); + + // Assert + Assert.Equal(new List() { "string3", "string1", "string2" }, model.StringList); + } + + [Fact] + public void AddMember_OnPOCO_WithNullPropertyValue_ShouldAddPropertyValue() + { + // Arrange + var doc = new SimpleDTO() + { + StringProperty = null + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.StringProperty, "B"); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal("B", doc.StringProperty); + } + + private class Class1 + { + public IDictionary USStates { get; set; } = new Dictionary(); + } + + [Fact] + public void AddMember_OnDictionaryProperty_ShouldAddKeyValueMember() + { + // Arrange + var expected = "Washington"; + var model = new Class1(); + var patchDoc = new JsonPatchDocument(); + patchDoc.Add("/USStates/WA", expected); + + // Act + patchDoc.ApplyTo(model); + + // Assert + Assert.Equal(1, model.USStates.Count); + Assert.Equal(expected, model.USStates["WA"]); + } + + [Fact] + public void AddMember_OnDictionaryProperty_ShouldAddKeyValueMember_WithSerialization() + { + // Arrange + var expected = "Washington"; + var model = new Class1(); + var patchDoc = new JsonPatchDocument(); + patchDoc.Add("/USStates/WA", expected); + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(model); + + // Assert + Assert.Equal(1, model.USStates.Count); + Assert.Equal(expected, model.USStates["WA"]); + } + + private class Class2 + { + public Class1 Class1Property { get; set; } = new Class1(); + } + + [Fact] + public void AddMember_OnDictionaryPropertyDeeplyNested_ShouldAddKeyValueMember() + { + // Arrange + var expected = "Washington"; + var model = new Class2(); + var patchDoc = new JsonPatchDocument(); + patchDoc.Add("/Class1Property/USStates/WA", expected); + + // Act + patchDoc.ApplyTo(model); + + // Assert + Assert.Equal(1, model.Class1Property.USStates.Count); + Assert.Equal(expected, model.Class1Property.USStates["WA"]); + } + + [Fact] + public void AddMember_OnDictionaryPropertyDeeplyNested_ShouldAddKeyValueMember_WithSerialization() + { + // Arrange + var expected = "Washington"; + var model = new Class2(); + var patchDoc = new JsonPatchDocument(); + patchDoc.Add("/Class1Property/USStates/WA", expected); + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(model); + + // Assert + Assert.Equal(1, model.Class1Property.USStates.Count); + Assert.Equal(expected, model.Class1Property.USStates["WA"]); + } + + [Fact] + public void AddMember_OnDictionaryObjectDirectly_ShouldAddKeyValueMember() + { + // Arrange + var expected = "Washington"; + var model = new Dictionary(); + var patchDoc = new JsonPatchDocument(); + patchDoc.Add("/WA", expected); + + // Act + patchDoc.ApplyTo(model); + + // Assert + Assert.Equal(1, model.Count); + Assert.Equal(expected, model["WA"]); + } + + [Fact] + public void AddMember_OnDictionaryObjectDirectly_ShouldAddKeyValueMember_WithSerialization() + { + // Arrange + var expected = "Washington"; + var model = new Dictionary(); + var patchDoc = new JsonPatchDocument(); + patchDoc.Add("/WA", expected); + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>>(serialized); + + // Act + deserialized.ApplyTo(model); + + // Assert + Assert.Equal(1, model.Count); + Assert.Equal(expected, model["WA"]); + } + + [Fact] + public void AddElement_ToListDirectly_ShouldAppendValue() + { + // Arrange + var model = new List() { 1, 2, 3 }; + var patchDoc = new JsonPatchDocument(); + patchDoc.Add("/-", value: 4); + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>>(serialized); + + // Act + deserialized.ApplyTo(model); + + // Assert + Assert.Equal(new List() { 1, 2, 3, 4 }, model); + } + + [Fact] + public void AddElement_ToListDirectly_ShouldAppendValue_WithSerialization() + { + // Arrange + var model = new List() { 1, 2, 3 }; + var patchDoc = new JsonPatchDocument(); + patchDoc.Add("/-", value: 4); + + // Act + patchDoc.ApplyTo(model); + + // Assert + Assert.Equal(new List() { 1, 2, 3, 4 }, model); + } + + [Fact] + public void AddElement_ToListDirectly_ShouldAddValue_AtSuppliedPosition() + { + // Arrange + var model = new List() { 1, 2, 3 }; + var patchDoc = new JsonPatchDocument(); + patchDoc.Add("/0", value: 4); + + // Act + patchDoc.ApplyTo(model); + + // Assert + Assert.Equal(new List() { 4, 1, 2, 3 }, model); + } + + [Fact] + public void AddElement_ToListDirectly_ShouldAddValue_AtSuppliedPosition_WithSerialization() + { + // Arrange + var model = new List() { 1, 2, 3 }; + var patchDoc = new JsonPatchDocument(); + patchDoc.Add("/0", value: 4); + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>>(serialized); + + // Act + deserialized.ApplyTo(model); + + // Assert + Assert.Equal(new List() { 4, 1, 2, 3 }, model); + } + + class ListOnDictionary + { + public IDictionary> NamesAndBadgeIds { get; set; } = new Dictionary>(); + } + + [Fact] + public void AddElement_ToList_OnDictionary_ShouldAddValue_AtSuppliedPosition() + { + // Arrange + var model = new ListOnDictionary(); + model.NamesAndBadgeIds["James"] = new List(); + var patchDoc = new JsonPatchDocument(); + patchDoc.Add("/NamesAndBadgeIds/James/-", 200); + + // Act + patchDoc.ApplyTo(model); + + // Assert + var list = model.NamesAndBadgeIds["James"]; + Assert.NotNull(list); + Assert.Equal(new List() { 200 }, list); + } + + [Fact] + public void AddElement_ToList_OnPOCO_ShouldAddValue_AtSuppliedPosition() + { + // Arrange + var doc = new SimpleDTO() + { + IntegerIList = new List() { 1, 2, 3 } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.IntegerIList, 4, 0); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { 4, 1, 2, 3 }, doc.IntegerIList); + } + + class Class3 + { + public SimpleDTO SimpleDTOProperty { get; set; } = new SimpleDTO(); + } + + [Fact] + public void AddElement_ToDeeplyNestedListProperty_OnPOCO_ShouldAddValue_AtSuppliedPosition() + { + // Arrange + var model = new Class3() + { + SimpleDTOProperty = new SimpleDTO() + { + IntegerIList = new List() { 1, 2, 3 } + } + }; + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.SimpleDTOProperty.IntegerIList, value: 4, position: 0); + + // Act + patchDoc.ApplyTo(model); + + // Assert + Assert.Equal(new List() { 4, 1, 2, 3 }, model.SimpleDTOProperty.IntegerIList); + } + + [Fact] + public void AddElement_ToDeeplyNestedListProperty_OnPOCO_ShouldAddValue_AtSuppliedPosition_WithSerialization() + { + // Arrange + var model = new Class3() + { + SimpleDTOProperty = new SimpleDTO() + { + IntegerIList = new List() { 1, 2, 3 } + } + }; + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.SimpleDTOProperty.IntegerIList, value: 4, position: 0); + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(model); + + // Assert + Assert.Equal(new List() { 4, 1, 2, 3 }, model.SimpleDTOProperty.IntegerIList); + } + + class Class4 + { + public int IntegerProperty { get; set; } + } + + [Fact] + public void Remove_OnNonReferenceType_POCOProperty_ShouldSetDefaultValue() + { + // Arrange + var model = new Class4() + { + IntegerProperty = 10 + }; + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove(o => o.IntegerProperty); + + // Act + patchDoc.ApplyTo(model); + + // Assert + Assert.Equal(0, model.IntegerProperty); + } + + [Fact] + public void Remove_OnNonReferenceType_POCOProperty_ShouldSetDefaultValue_WithSerialization() + { + // Arrange + var doc = new SimpleDTO() + { + StringProperty = "A" + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove(o => o.StringProperty); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal(null, doc.StringProperty); + } + + class ClassWithPrivateProperties + { + public string Name { get; set; } + private int Age { get; set; } = 45; + } + + [Fact] + public void Add_OnPrivateProperties_FailesWithException() + { + // Arrange + var doc = new ClassWithPrivateProperties() + { + Name = "James" + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add("/Age", 30); + + // Act & Assert + var exception = Assert.Throws(() => patchDoc.ApplyTo(doc)); + Assert.Equal( + string.Format("The target location specified by path segment '{0}' was not found.", "Age"), + exception.Message); + } } } \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectVisitorTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectVisitorTest.cs new file mode 100644 index 0000000000..a03b830e02 --- /dev/null +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectVisitorTest.cs @@ -0,0 +1,230 @@ +// Copyright (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()); + IAdapter adapter = null; + string message = null; + + // Act + var visitStatus = visitor.TryVisit(ref targetObject, out adapter, out 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()); + IAdapter adapter = null; + string message = null; + + // Act + var visitStatus = visitor.TryVisit(ref targetObject, out adapter, out message); + + // Assert + Assert.True(visitStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.Same(expectedTargetObject, targetObject); + Assert.IsType(adapter); + } + + public static IEnumerable ReturnsExpandoAdapterData + { + get + { + var model = new Class1(); + yield return new object[] { model, "/Items/Name", model.Items }; + yield return new object[] { model.Items, "/Name", model.Items }; + + 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 visitor = new ObjectVisitor(new ParsedPath(path), new DefaultContractResolver()); + IAdapter adapter = null; + string message = null; + + // Act + var visitStatus = visitor.TryVisit(ref targetObject, out adapter, out message); + + // Assert + Assert.True(visitStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.Same(expectedTargetObject, targetObject); + Assert.IsType(adapter); + } + + 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()); + IAdapter adapter = null; + string message = null; + + // Act + var visitStatus = visitor.TryVisit(ref targetObject, out adapter, out 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; + IAdapter adapter = null; + string message = null; + + // Act + var visitStatus = visitor.TryVisit(ref targetObject, out adapter, out message); + + // Assert + Assert.False(visitStatus); + Assert.Equal( + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", position), + 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; + IAdapter adapter = null; + string message = null; + + // Act + var visitStatus = visitor.TryVisit(ref targetObject, out adapter, out message); + + // Assert + Assert.False(visitStatus); + Assert.Equal(string.Format( + "The path segment '{0}' is invalid for an array index.", position), + message); + } + + // The adapter takes care of the responsibility of validating the final segment + [Fact] + public void Visit_DoesNotValidate_FinalPathSegment() + { + // Arrange + var visitor = new ObjectVisitor(new ParsedPath($"/NonExisting"), new DefaultContractResolver()); + var model = new Class1(); + object targetObject = model; + IAdapter adapter = null; + string message = null; + + // Act + var visitStatus = visitor.TryVisit(ref targetObject, out adapter, out message); + + // Assert + Assert.True(visitStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.IsType(adapter); + } + } +} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectVisitorTest.cs~RF1ad82e13.TMP b/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectVisitorTest.cs~RF1ad82e13.TMP new file mode 100644 index 0000000000..694c33c633 --- /dev/null +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectVisitorTest.cs~RF1ad82e13.TMP @@ -0,0 +1,119 @@ +using System.Collections.Generic; +using Newtonsoft.Json.Serialization; +using Xunit; + +namespace Microsoft.AspNetCore.JsonPatch.Internal +{ + public class ObjectVisitorTest + { + private class Class1 + { + public IList States { get; set; } = new List(); + public IDictionary Countries = new Dictionary(); + } + + [Fact] + public void Visit_ValidPathToArray_ReturnsListAdapter() + { + // Arrange + var visitor = new ObjectVisitor(new ParsedPath("/States/-"), new DefaultContractResolver()); + var model = new Class1(); + object targetObject = model; + IAdapter adapter = null; + string message = null; + + // Act + var visitStatus = visitor.TryVisit(ref targetObject, out adapter, out message); + + // Assert + Assert.True(visitStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.Same(model.States, targetObject); + Assert.IsType(adapter); + } + + [Fact] + public void Visit_ValidPathToDictionary_ReturnsDictionaryAdapter() + { + // Arrange + var visitor = new ObjectVisitor(new ParsedPath("/Countries/USA"), new DefaultContractResolver()); + var model = new Class1(); + object targetObject = model; + IAdapter adapter = null; + string message = null; + + // Act + var visitStatus = visitor.TryVisit(ref targetObject, out adapter, out message); + + // Assert + Assert.True(visitStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.Same(model.Countries, targetObject); + Assert.IsType(adapter); + } + + private class AutomobileDepartment + { + public List Customers { get; set; } = new List(); + } + + [Fact] + public void Visit_ValidPathToArray_ReturnsListAdapter_ForDeepNestedPath() + { + // Arrange + var visitor = new ObjectVisitor(new ParsedPath("/Customers/0/States/-"), new DefaultContractResolver()); + var customer = new Class1(); + var automobileDepartment = new AutomobileDepartment(); + automobileDepartment.Customers.Add(customer); + object targetObject = automobileDepartment; + IAdapter adapter = null; + string message = null; + + // Act + var visitStatus = visitor.TryVisit(ref targetObject, out adapter, out message); + + // Assert + Assert.True(visitStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.Same(customer.States, targetObject); + Assert.IsType(adapter); + } + + [Fact] + public void Visit_InvalidPathToArray_Fails() + { + // Arrange + var invalidIndex = 2; + var visitor = new ObjectVisitor(new ParsedPath($"/Customers/{invalidIndex}/States/-"), new DefaultContractResolver()); + var automobileDepartment = new AutomobileDepartment(); + object targetObject = automobileDepartment; + IAdapter adapter = null; + string message = null; + + // Act + var visitStatus = visitor.TryVisit(ref targetObject, out adapter, out message); + + // Assert + Assert.False(visitStatus); + Assert.Equal(string.Format(ErrorMessageFormats.IndexOutOfBounds, invalidIndex), message); + } + + [Fact] + public void Visit_DoesNotValidate_FinalPathSegment() + { + // Arrange + var visitor = new ObjectVisitor(new ParsedPath($"/NonExisting"), new DefaultContractResolver()); + var model = new Class1(); + object targetObject = model; + IAdapter adapter = null; + string message = null; + + // Act + var visitStatus = visitor.TryVisit(ref targetObject, out adapter, out message); + + // Assert + Assert.False(visitStatus); + Assert.Equal(string.Format(ErrorMessageFormats.TargetLocationAtPathSegmentNotFound, "NonExisting"), message); + } + } +} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectVisitorTest.cs~RF1ae034c3.TMP b/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectVisitorTest.cs~RF1ae034c3.TMP new file mode 100644 index 0000000000..88139198ac --- /dev/null +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectVisitorTest.cs~RF1ae034c3.TMP @@ -0,0 +1,131 @@ +using System.Collections.Generic; +using Newtonsoft.Json.Serialization; +using Xunit; + +namespace Microsoft.AspNetCore.JsonPatch.Internal +{ + public class ObjectVisitorTest + { + private class Class1 + { + public IList States { get; set; } = new List(); + public IDictionary Countries = new Dictionary(); + } + + 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 }; + } + } + + [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()); + IAdapter adapter = null; + string message = null; + + // Act + var visitStatus = visitor.TryVisit(ref targetObject, out adapter, out message); + + // Assert + Assert.True(visitStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.Same(expectedTargetObject, targetObject); + Assert.IsType(adapter); + } + + [Fact] + public void Visit_ValidPathToDictionary_ReturnsDictionaryAdapter() + { + // Arrange + var visitor = new ObjectVisitor(new ParsedPath("/Countries/USA"), new DefaultContractResolver()); + var model = new Class1(); + object targetObject = model; + IAdapter adapter = null; + string message = null; + + // Act + var visitStatus = visitor.TryVisit(ref targetObject, out adapter, out message); + + // Assert + Assert.True(visitStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.Same(model.Countries, targetObject); + Assert.IsType(adapter); + } + + private class AutomobileDepartment + { + public List Customers { get; set; } = new List(); + } + + [Fact] + public void Visit_ValidPathToArray_ReturnsListAdapter_ForDeepNestedPath() + { + // Arrange + var visitor = new ObjectVisitor(new ParsedPath("/Customers/0/States/-"), new DefaultContractResolver()); + var customer = new Class1(); + var automobileDepartment = new AutomobileDepartment(); + automobileDepartment.Customers.Add(customer); + object targetObject = automobileDepartment; + IAdapter adapter = null; + string message = null; + + // Act + var visitStatus = visitor.TryVisit(ref targetObject, out adapter, out message); + + // Assert + Assert.True(visitStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.Same(customer.States, targetObject); + Assert.IsType(adapter); + } + + [Fact] + public void Visit_InvalidPathToArray_Fails() + { + // Arrange + var invalidIndex = 2; + var visitor = new ObjectVisitor(new ParsedPath($"/Customers/{invalidIndex}/States/-"), new DefaultContractResolver()); + var automobileDepartment = new AutomobileDepartment(); + object targetObject = automobileDepartment; + IAdapter adapter = null; + string message = null; + + // Act + var visitStatus = visitor.TryVisit(ref targetObject, out adapter, out message); + + // Assert + Assert.False(visitStatus); + Assert.Equal(string.Format(ErrorMessageFormats.IndexOutOfBounds, invalidIndex), message); + } + + // The adapter takes care of the responsibility of validating the final segment + [Fact] + public void Visit_DoesNotValidate_FinalPathSegment() + { + // Arrange + var visitor = new ObjectVisitor(new ParsedPath($"/NonExisting"), new DefaultContractResolver()); + var model = new Class1(); + object targetObject = model; + IAdapter adapter = null; + string message = null; + + // Act + var visitStatus = visitor.TryVisit(ref targetObject, out adapter, out message); + + // Assert + Assert.True(visitStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.IsType(adapter); + } + } +} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTO.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTO.cs index 1206cd108f..6dc1f173de 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTO.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTO.cs @@ -4,7 +4,7 @@ using System; using System.Collections.Generic; -namespace Microsoft.AspNetCore.JsonPatch.Test +namespace Microsoft.AspNetCore.JsonPatch { public class SimpleDTO { diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTOWithNestedDTO.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTOWithNestedDTO.cs index dbded242ee..879d820277 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTOWithNestedDTO.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTOWithNestedDTO.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; -namespace Microsoft.AspNetCore.JsonPatch.Test +namespace Microsoft.AspNetCore.JsonPatch { public class SimpleDTOWithNestedDTO { diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/TestErrorLogger.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/TestErrorLogger.cs index 6db8a42684..2cd6a4453e 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/TestErrorLogger.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/TestErrorLogger.cs @@ -1,7 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -namespace Microsoft.AspNetCore.JsonPatch.Test +namespace Microsoft.AspNetCore.JsonPatch { public class TestErrorLogger where T : class { From 3b7f9b4043c978e1ce1d1d9d974be36f05b8e985 Mon Sep 17 00:00:00 2001 From: Kiran Challa Date: Fri, 7 Oct 2016 11:28:07 -0700 Subject: [PATCH 137/471] Fixed version of System.Reflection.TypeExtensions package --- src/Microsoft.AspNetCore.JsonPatch/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.AspNetCore.JsonPatch/project.json b/src/Microsoft.AspNetCore.JsonPatch/project.json index c9beba3639..5b998272ff 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/project.json +++ b/src/Microsoft.AspNetCore.JsonPatch/project.json @@ -33,7 +33,7 @@ "netstandard1.3": { "dependencies": { "Microsoft.CSharp": "4.3.0-*", - "System.Reflection.TypeExtensions": "4.1.0-*" + "System.Reflection.TypeExtensions": "4.3.0-*" } } } From 08332a96b718ce5b0a192385a196dbcb62f77e21 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 12 Oct 2016 13:45:26 -0700 Subject: [PATCH 138/471] Updating to netcoreapp1.1 --- test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json | 2 +- test/Microsoft.Extensions.WebEncoders.Tests/project.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json index 8e5e79eeb2..754cf25670 100644 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json @@ -12,7 +12,7 @@ }, "testRunner": "xunit", "frameworks": { - "netcoreapp1.0": { + "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/project.json b/test/Microsoft.Extensions.WebEncoders.Tests/project.json index 4c9ee42471..9171910c7c 100644 --- a/test/Microsoft.Extensions.WebEncoders.Tests/project.json +++ b/test/Microsoft.Extensions.WebEncoders.Tests/project.json @@ -11,7 +11,7 @@ "keyFile": "../../tools/Key.snk" }, "frameworks": { - "netcoreapp1.0": { + "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", From ddcee4774dc3d316498c8a177d9b765eabe8bc33 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 12 Oct 2016 13:45:39 -0700 Subject: [PATCH 139/471] Updating to netcoreapp1.1 --- test/Microsoft.AspNetCore.JsonPatch.Test/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json index 9da14bf59e..9e95ee86e0 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json @@ -11,7 +11,7 @@ }, "testRunner": "xunit", "frameworks": { - "netcoreapp1.0": { + "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", From 2b86005a855d724873ec02b2434b1872c5646b79 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 12 Oct 2016 16:08:44 -0700 Subject: [PATCH 140/471] Revert "Updating to netcoreapp1.1" This reverts commit 08332a96b718ce5b0a192385a196dbcb62f77e21. --- test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json | 2 +- test/Microsoft.Extensions.WebEncoders.Tests/project.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json index 754cf25670..8e5e79eeb2 100644 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json @@ -12,7 +12,7 @@ }, "testRunner": "xunit", "frameworks": { - "netcoreapp1.1": { + "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/project.json b/test/Microsoft.Extensions.WebEncoders.Tests/project.json index 9171910c7c..4c9ee42471 100644 --- a/test/Microsoft.Extensions.WebEncoders.Tests/project.json +++ b/test/Microsoft.Extensions.WebEncoders.Tests/project.json @@ -11,7 +11,7 @@ "keyFile": "../../tools/Key.snk" }, "frameworks": { - "netcoreapp1.1": { + "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", From 681812d0f40cb9c4281215413e8b3c0feca30509 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 12 Oct 2016 16:08:53 -0700 Subject: [PATCH 141/471] Revert "Updating to netcoreapp1.1" This reverts commit ddcee4774dc3d316498c8a177d9b765eabe8bc33. --- test/Microsoft.AspNetCore.JsonPatch.Test/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json index 9e95ee86e0..9da14bf59e 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json @@ -11,7 +11,7 @@ }, "testRunner": "xunit", "frameworks": { - "netcoreapp1.1": { + "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", From 58d5c2f7d4420b095faeece77c580acfbc4f78ca Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 13 Oct 2016 11:17:57 -0700 Subject: [PATCH 142/471] Updating to netcoreapp1.1 --- test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json | 2 +- test/Microsoft.Extensions.WebEncoders.Tests/project.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json index 8e5e79eeb2..754cf25670 100644 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json @@ -12,7 +12,7 @@ }, "testRunner": "xunit", "frameworks": { - "netcoreapp1.0": { + "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/project.json b/test/Microsoft.Extensions.WebEncoders.Tests/project.json index 4c9ee42471..9171910c7c 100644 --- a/test/Microsoft.Extensions.WebEncoders.Tests/project.json +++ b/test/Microsoft.Extensions.WebEncoders.Tests/project.json @@ -11,7 +11,7 @@ "keyFile": "../../tools/Key.snk" }, "frameworks": { - "netcoreapp1.0": { + "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", From 17a4e83babc7e4a6882d1e80b68a5e4fb4a1e5f1 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 13 Oct 2016 11:19:06 -0700 Subject: [PATCH 143/471] Updating to netcoreapp1.1 --- test/Microsoft.AspNetCore.JsonPatch.Test/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json index 9da14bf59e..9e95ee86e0 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json @@ -11,7 +11,7 @@ }, "testRunner": "xunit", "frameworks": { - "netcoreapp1.0": { + "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", From f280d5ff434257ca679ab9b135f9a7d4235c047b Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 17 Oct 2016 09:49:10 -0700 Subject: [PATCH 144/471] Branching for 1.1.0-preview1 --- NuGet.config | 4 ++-- build.ps1 | 2 +- build.sh | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/NuGet.config b/NuGet.config index 826a1f9035..6197c93176 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,7 @@ - + - + \ No newline at end of file diff --git a/build.ps1 b/build.ps1 index 8f2f99691a..787f63ac02 100644 --- a/build.ps1 +++ b/build.ps1 @@ -33,7 +33,7 @@ cd $PSScriptRoot $repoFolder = $PSScriptRoot $env:REPO_FOLDER = $repoFolder -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/1.1.0-preview1.zip" if ($env:KOREBUILD_ZIP) { $koreBuildZip=$env:KOREBUILD_ZIP diff --git a/build.sh b/build.sh index f4208100eb..355c682856 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/1.1.0-preview1.zip" if [ ! -z $KOREBUILD_ZIP ]; then koreBuildZip=$KOREBUILD_ZIP fi From ad17eb8b562c4e0971bd1faa2bb95c1392ebca8d Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 17 Oct 2016 09:49:16 -0700 Subject: [PATCH 145/471] Branching for 1.1.0-preview1 --- NuGet.config | 4 ++-- build.ps1 | 2 +- build.sh | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/NuGet.config b/NuGet.config index 0fd623ffdd..ad973186eb 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,7 @@ - + - + diff --git a/build.ps1 b/build.ps1 index 8f2f99691a..787f63ac02 100644 --- a/build.ps1 +++ b/build.ps1 @@ -33,7 +33,7 @@ cd $PSScriptRoot $repoFolder = $PSScriptRoot $env:REPO_FOLDER = $repoFolder -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/1.1.0-preview1.zip" if ($env:KOREBUILD_ZIP) { $koreBuildZip=$env:KOREBUILD_ZIP diff --git a/build.sh b/build.sh index f4208100eb..355c682856 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/1.1.0-preview1.zip" if [ ! -z $KOREBUILD_ZIP ]; then koreBuildZip=$KOREBUILD_ZIP fi From 0781b5a87cb9eb8b48044b74cb8e6602650a3b63 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Mon, 10 Oct 2016 21:42:33 -0700 Subject: [PATCH 146/471] Add `HtmlContentBuilder.Count` - precursor to PR aspnet/Mvc#5378 for issue aspnet/Mvc#3918 --- .../HtmlContentBuilder.cs | 5 ++ .../HtmlContentBuilderTest.cs | 71 +++++++++++-------- 2 files changed, 45 insertions(+), 31 deletions(-) diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilder.cs b/src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilder.cs index 864f3c8a65..e61d9f7dc8 100644 --- a/src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilder.cs +++ b/src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilder.cs @@ -30,6 +30,11 @@ namespace Microsoft.AspNetCore.Html { } + /// + /// Gets the number of elements in the . + /// + public int Count => Entries.Count; + /// /// Creates a new with the given list of entries. /// diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlContentBuilderTest.cs b/test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlContentBuilderTest.cs index 40219b19f7..c3cb7d1954 100644 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlContentBuilderTest.cs +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlContentBuilderTest.cs @@ -22,6 +22,7 @@ namespace Microsoft.Extensions.Internal content.Append("Hello"); // Assert + Assert.Equal(1, content.Count); var result = Assert.Single(content.Entries); Assert.IsType(result); } @@ -69,6 +70,7 @@ namespace Microsoft.Extensions.Internal 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()); @@ -86,9 +88,11 @@ namespace Microsoft.Extensions.Internal content.Append("Test"); // Assert - Assert.Equal(2, content.Entries.Count); - Assert.Equal("Written from TestHtmlContent: hello", content.Entries[0].ToString()); - Assert.Equal("Test", content.Entries[1]); + Assert.Equal(2, content.Count); + Assert.Collection( + content.Entries, + entry => Assert.Equal("Written from TestHtmlContent: hello", entry.ToString()), + entry => Assert.Equal("Test", entry)); } [Fact] @@ -103,7 +107,8 @@ namespace Microsoft.Extensions.Internal content.Clear(); // Assert - Assert.Equal(0, content.Entries.Count); + Assert.Equal(0, content.Count); + Assert.Empty(content.Entries); } [Fact] @@ -121,12 +126,13 @@ namespace Microsoft.Extensions.Internal source.CopyTo(destination); // Assert - Assert.Equal(2, source.Entries.Count); - Assert.Equal(3, destination.Entries.Count); - - Assert.Equal("some-content", Assert.IsType(destination.Entries[0])); - Assert.Equal(new TestHtmlContent("hello"), Assert.IsType(destination.Entries[1])); - Assert.Equal("Test", Assert.IsType(destination.Entries[2])); + 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] @@ -147,13 +153,14 @@ namespace Microsoft.Extensions.Internal source.CopyTo(destination); // Assert - Assert.Equal(2, source.Entries.Count); - Assert.Equal(1, nested.Entries.Count); - Assert.Equal(3, destination.Entries.Count); - - Assert.Equal("some-content", Assert.IsType(destination.Entries[0])); - Assert.Equal(new TestHtmlContent("hello"), Assert.IsType(destination.Entries[1])); - Assert.Equal("Test", Assert.IsType(destination.Entries[2])); + 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] @@ -171,12 +178,13 @@ namespace Microsoft.Extensions.Internal source.MoveTo(destination); // Assert - Assert.Equal(0, source.Entries.Count); - Assert.Equal(3, destination.Entries.Count); - - Assert.Equal("some-content", Assert.IsType(destination.Entries[0])); - Assert.Equal(new TestHtmlContent("hello"), Assert.IsType(destination.Entries[1])); - Assert.Equal("Test", Assert.IsType(destination.Entries[2])); + 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] @@ -197,13 +205,14 @@ namespace Microsoft.Extensions.Internal source.MoveTo(destination); // Assert - Assert.Equal(0, source.Entries.Count); - Assert.Equal(0, nested.Entries.Count); - Assert.Equal(3, destination.Entries.Count); - - Assert.Equal("some-content", Assert.IsType(destination.Entries[0])); - Assert.Equal(new TestHtmlContent("hello"), Assert.IsType(destination.Entries[1])); - Assert.Equal("Test", Assert.IsType(destination.Entries[2])); + 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] @@ -219,7 +228,7 @@ namespace Microsoft.Extensions.Internal content.WriteTo(writer, new HtmlTestEncoder()); // Assert - Assert.Equal(2, content.Entries.Count); + Assert.Equal(2, content.Count); Assert.Equal("Written from TestHtmlContent: HelloHtmlEncode[[Test]]", writer.ToString()); } From 81931e75d48370cf9163254523b1f6c4bcc92acb Mon Sep 17 00:00:00 2001 From: Kiran Challa Date: Mon, 31 Oct 2016 15:06:25 -0700 Subject: [PATCH 147/471] Handle exceptions for invalid operation types Related to https://github.com/aspnet/Mvc/issues/5463 --- .../Adapters/ObjectAdapter.cs | 26 +++--- .../Internal/ErrorReporter.cs | 16 ++++ .../JsonPatchDocument.cs | 18 +++- .../JsonPatchDocumentOfT.cs | 18 +++- .../Operations/OperationBase.cs | 10 +- .../Operations/OperationOfT.cs | 3 +- .../Properties/Resources.Designer.cs | 16 ++++ .../Resources.resx | 3 + .../JsonPatchDocumentTest.cs | 91 +++++++++++++++++++ 9 files changed, 182 insertions(+), 19 deletions(-) create mode 100644 src/Microsoft.AspNetCore.JsonPatch/Internal/ErrorReporter.cs create mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentTest.cs diff --git a/src/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs b/src/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs index ee01fbeba7..0ac2ebbe56 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs @@ -150,14 +150,14 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters if (!visitor.TryVisit(ref target, out adapter, out errorMessage)) { var error = CreatePathNotFoundError(objectToApplyTo, path, operation, errorMessage); - ReportError(error); + ErrorReporter(error); return; } if (!adapter.TryAdd(target, parsedPath.LastSegment, ContractResolver, value, out errorMessage)) { var error = CreateOperationFailedError(objectToApplyTo, path, operation, errorMessage); - ReportError(error); + ErrorReporter(error); return; } } @@ -259,14 +259,14 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters if (!visitor.TryVisit(ref target, out adapter, out errorMessage)) { var error = CreatePathNotFoundError(objectToApplyTo, path, operationToReport, errorMessage); - ReportError(error); + ErrorReporter(error); return; } if (!adapter.TryRemove(target, parsedPath.LastSegment, ContractResolver, out errorMessage)) { var error = CreateOperationFailedError(objectToApplyTo, path, operationToReport, errorMessage); - ReportError(error); + ErrorReporter(error); return; } } @@ -312,14 +312,14 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters if (!visitor.TryVisit(ref target, out adapter, out errorMessage)) { var error = CreatePathNotFoundError(objectToApplyTo, operation.path, operation, errorMessage); - ReportError(error); + ErrorReporter(error); return; } if (!adapter.TryReplace(target, parsedPath.LastSegment, ContractResolver, operation.value, out errorMessage)) { var error = CreateOperationFailedError(objectToApplyTo, operation.path, operation, errorMessage); - ReportError(error); + ErrorReporter(error); return; } } @@ -401,29 +401,25 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters if (!visitor.TryVisit(ref target, out adapter, out errorMessage)) { var error = CreatePathNotFoundError(objectToGetValueFrom, fromLocation, operation, errorMessage); - ReportError(error); + ErrorReporter(error); return false; } if (!adapter.TryGet(target, parsedPath.LastSegment, ContractResolver, out propertyValue, out errorMessage)) { var error = CreateOperationFailedError(objectToGetValueFrom, fromLocation, operation, errorMessage); - ReportError(error); + ErrorReporter(error); return false; } return true; } - private void ReportError(JsonPatchError error) + private Action ErrorReporter { - if (LogErrorAction != null) + get { - LogErrorAction(error); - } - else - { - throw new JsonPatchException(error); + return LogErrorAction ?? Internal.ErrorReporter.Default; } } diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/ErrorReporter.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/ErrorReporter.cs new file mode 100644 index 0000000000..76b55a6144 --- /dev/null +++ b/src/Microsoft.AspNetCore.JsonPatch/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/Microsoft.AspNetCore.JsonPatch/JsonPatchDocument.cs b/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocument.cs index 72e93e0302..875134ed9d 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocument.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocument.cs @@ -5,6 +5,7 @@ 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; @@ -170,7 +171,22 @@ namespace Microsoft.AspNetCore.JsonPatch throw new ArgumentNullException(nameof(objectToApplyTo)); } - ApplyTo(objectToApplyTo, new ObjectAdapter(ContractResolver, logErrorAction)); + var adapter = new ObjectAdapter(ContractResolver, logErrorAction); + 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; + } + } } /// diff --git a/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs b/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs index afb5eb3ff1..fc660b2b45 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; 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; @@ -648,7 +649,22 @@ namespace Microsoft.AspNetCore.JsonPatch throw new ArgumentNullException(nameof(objectToApplyTo)); } - ApplyTo(objectToApplyTo, new ObjectAdapter(ContractResolver, logErrorAction)); + var adapter = new ObjectAdapter(ContractResolver, logErrorAction); + 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; + } + } } /// diff --git a/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationBase.cs b/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationBase.cs index 5f421f41c7..eb35fa7e9d 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationBase.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationBase.cs @@ -2,6 +2,7 @@ // 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; using Newtonsoft.Json; namespace Microsoft.AspNetCore.JsonPatch.Operations @@ -13,7 +14,14 @@ namespace Microsoft.AspNetCore.JsonPatch.Operations { get { - return (OperationType)Enum.Parse(typeof(OperationType), op, true); + OperationType result; + if (!Enum.TryParse(op, ignoreCase: true, result: out result)) + { + throw new JsonPatchException( + Resources.FormatInvalidJsonPatchOperation(op), + innerException: null); + } + return result; } } diff --git a/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationOfT.cs b/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationOfT.cs index c41454b7ef..5af4f5d3f9 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationOfT.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationOfT.cs @@ -3,6 +3,7 @@ using System; using Microsoft.AspNetCore.JsonPatch.Adapters; +using Microsoft.AspNetCore.JsonPatch.Exceptions; namespace Microsoft.AspNetCore.JsonPatch.Operations { @@ -73,7 +74,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Operations adapter.Copy(this, objectToApplyTo); break; case OperationType.Test: - throw new NotSupportedException(Resources.TestOperationNotSupported); + throw new JsonPatchException(new JsonPatchError(objectToApplyTo, this, Resources.TestOperationNotSupported)); default: break; } diff --git a/src/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs index 9e00cc2f00..ed567cf003 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs @@ -122,6 +122,22 @@ namespace Microsoft.AspNetCore.JsonPatch return string.Format(CultureInfo.CurrentCulture, GetString("InvalidJsonPatchDocument"), p0); } + /// + /// Invalid JsonPatch operation '{0}'. + /// + internal static string InvalidJsonPatchOperation + { + get { return GetString("InvalidJsonPatchOperation"); } + } + + /// + /// Invalid JsonPatch operation '{0}'. + /// + internal static string FormatInvalidJsonPatchOperation(object p0) + { + return string.Format(CultureInfo.CurrentCulture, GetString("InvalidJsonPatchOperation"), p0); + } + /// /// The provided string '{0}' is an invalid path. /// diff --git a/src/Microsoft.AspNetCore.JsonPatch/Resources.resx b/src/Microsoft.AspNetCore.JsonPatch/Resources.resx index a7b50520ac..7381ad02fc 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Resources.resx +++ b/src/Microsoft.AspNetCore.JsonPatch/Resources.resx @@ -138,6 +138,9 @@ The type '{0}' was malformed and could not be parsed. + + Invalid JsonPatch operation '{0}'. + The provided string '{0}' is an invalid path. diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentTest.cs new file mode 100644 index 0000000000..723ef15b64 --- /dev/null +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentTest.cs @@ -0,0 +1,91 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.AspNetCore.JsonPatch.Exceptions; +using Newtonsoft.Json; +using Xunit; + +namespace Microsoft.AspNetCore.JsonPatch.Test +{ + public class JsonPatchDocumentTest + { + [Fact] + public void TestOperation_ThrowsException_CallsIntoLogErrorAction() + { + // Arrange + var serialized = "[{\"value\":\"John\",\"path\":\"/Name\",\"op\":\"test\"}]"; + var jsonPatchDocument = JsonConvert.DeserializeObject>(serialized); + var model = new Customer(); + var expectedErrorMessage = "The test operation is not supported."; + string actualErrorMessage = null; + + // Act + jsonPatchDocument.ApplyTo(model, (jsonPatchError) => + { + actualErrorMessage = jsonPatchError.ErrorMessage; + }); + + // Assert + Assert.Equal(expectedErrorMessage, actualErrorMessage); + } + + [Fact] + public void TestOperation_NoLogErrorAction_ThrowsJsonPatchException() + { + // Arrange + var serialized = "[{\"value\":\"John\",\"path\":\"/Name\",\"op\":\"test\"}]"; + var jsonPatchDocument = JsonConvert.DeserializeObject>(serialized); + var model = new Customer(); + var expectedErrorMessage = "The test operation is not supported."; + + // Act + var jsonPatchException = Assert.Throws(() => jsonPatchDocument.ApplyTo(model)); + + // Assert + Assert.Equal(expectedErrorMessage, jsonPatchException.Message); + } + + [Fact] + public void InvalidOperation_ThrowsException_CallsIntoLogErrorAction() + { + // Arrange + var operationName = "foo"; + var serialized = "[{\"value\":\"John\",\"path\":\"/Name\",\"op\":\"" + operationName + "\"}]"; + var jsonPatchDocument = JsonConvert.DeserializeObject>(serialized); + var model = new Customer(); + var expectedErrorMessage = $"Invalid JsonPatch operation '{operationName}'."; + string actualErrorMessage = null; + + // Act + jsonPatchDocument.ApplyTo(model, (jsonPatchError) => + { + actualErrorMessage = jsonPatchError.ErrorMessage; + }); + + // Assert + Assert.Equal(expectedErrorMessage, actualErrorMessage); + } + + [Fact] + public void InvalidOperation_NoLogErrorAction_ThrowsJsonPatchException() + { + // Arrange + var operationName = "foo"; + var serialized = "[{\"value\":\"John\",\"path\":\"/Name\",\"op\":\"" + operationName + "\"}]"; + var jsonPatchDocument = JsonConvert.DeserializeObject>(serialized); + var model = new Customer(); + var expectedErrorMessage = $"Invalid JsonPatch operation '{operationName}'."; + + // Act + var jsonPatchException = Assert.Throws(() => jsonPatchDocument.ApplyTo(model)); + + // Assert + Assert.Equal(expectedErrorMessage, jsonPatchException.Message); + } + + private class Customer + { + public string Name { get; set; } + } + } +} From 80cdeceb0b7127ec9be2da2bfbfbba4824978751 Mon Sep 17 00:00:00 2001 From: jacalvar Date: Fri, 4 Nov 2016 15:28:07 -0700 Subject: [PATCH 148/471] Created public API baselines --- .../baseline.netcore.json | 618 ++++++++++++++++++ .../baseline.netcore.json | 564 ++++++++++++++++ 2 files changed, 1182 insertions(+) create mode 100644 src/Microsoft.AspNetCore.Html.Abstractions/baseline.netcore.json create mode 100644 src/Microsoft.Extensions.WebEncoders/baseline.netcore.json diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/baseline.netcore.json b/src/Microsoft.AspNetCore.Html.Abstractions/baseline.netcore.json new file mode 100644 index 0000000000..7e3a4d0d00 --- /dev/null +++ b/src/Microsoft.AspNetCore.Html.Abstractions/baseline.netcore.json @@ -0,0 +1,618 @@ +{ + "AssemblyIdentity": "Microsoft.AspNetCore.Html.Abstractions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "Types": [ + { + "Name": "Microsoft.AspNetCore.Html.HtmlContentBuilder", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.Html.IHtmlContentBuilder" + ], + "Members": [ + { + "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": "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": "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/Microsoft.Extensions.WebEncoders/baseline.netcore.json b/src/Microsoft.Extensions.WebEncoders/baseline.netcore.json new file mode 100644 index 0000000000..db16203ed1 --- /dev/null +++ b/src/Microsoft.Extensions.WebEncoders/baseline.netcore.json @@ -0,0 +1,564 @@ +{ + "AssemblyIdentity": "Microsoft.Extensions.WebEncoders, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "Types": [ + { + "Name": "Microsoft.Extensions.WebEncoders.WebEncoderOptions", + "Visibility": "Public", + "Kind": "Class", + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_TextEncoderSettings", + "Parameters": [], + "ReturnType": "System.Text.Encodings.Web.TextEncoderSettings", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_TextEncoderSettings", + "Parameters": [ + { + "Name": "value", + "Type": "System.Text.Encodings.Web.TextEncoderSettings" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.Extensions.WebEncoders.Testing.HtmlTestEncoder", + "Visibility": "Public", + "Kind": "Class", + "Sealed": true, + "BaseType": "System.Text.Encodings.Web.HtmlEncoder", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_MaxOutputCharactersPerInputCharacter", + "Parameters": [], + "ReturnType": "System.Int32", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Encode", + "Parameters": [ + { + "Name": "value", + "Type": "System.String" + } + ], + "ReturnType": "System.String", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Encode", + "Parameters": [ + { + "Name": "output", + "Type": "System.IO.TextWriter" + }, + { + "Name": "value", + "Type": "System.Char[]" + }, + { + "Name": "startIndex", + "Type": "System.Int32" + }, + { + "Name": "characterCount", + "Type": "System.Int32" + } + ], + "ReturnType": "System.Void", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Encode", + "Parameters": [ + { + "Name": "output", + "Type": "System.IO.TextWriter" + }, + { + "Name": "value", + "Type": "System.String" + }, + { + "Name": "startIndex", + "Type": "System.Int32" + }, + { + "Name": "characterCount", + "Type": "System.Int32" + } + ], + "ReturnType": "System.Void", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "WillEncode", + "Parameters": [ + { + "Name": "unicodeScalar", + "Type": "System.Int32" + } + ], + "ReturnType": "System.Boolean", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "FindFirstCharacterToEncode", + "Parameters": [ + { + "Name": "text", + "Type": "System.Char*" + }, + { + "Name": "textLength", + "Type": "System.Int32" + } + ], + "ReturnType": "System.Int32", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "TryEncodeUnicodeScalar", + "Parameters": [ + { + "Name": "unicodeScalar", + "Type": "System.Int32" + }, + { + "Name": "buffer", + "Type": "System.Char*" + }, + { + "Name": "bufferLength", + "Type": "System.Int32" + }, + { + "Name": "numberOfCharactersWritten", + "Type": "System.Int32", + "Direction": "Out" + } + ], + "ReturnType": "System.Boolean", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.Extensions.WebEncoders.Testing.JavaScriptTestEncoder", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "System.Text.Encodings.Web.JavaScriptEncoder", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_MaxOutputCharactersPerInputCharacter", + "Parameters": [], + "ReturnType": "System.Int32", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Encode", + "Parameters": [ + { + "Name": "value", + "Type": "System.String" + } + ], + "ReturnType": "System.String", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Encode", + "Parameters": [ + { + "Name": "output", + "Type": "System.IO.TextWriter" + }, + { + "Name": "value", + "Type": "System.Char[]" + }, + { + "Name": "startIndex", + "Type": "System.Int32" + }, + { + "Name": "characterCount", + "Type": "System.Int32" + } + ], + "ReturnType": "System.Void", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Encode", + "Parameters": [ + { + "Name": "output", + "Type": "System.IO.TextWriter" + }, + { + "Name": "value", + "Type": "System.String" + }, + { + "Name": "startIndex", + "Type": "System.Int32" + }, + { + "Name": "characterCount", + "Type": "System.Int32" + } + ], + "ReturnType": "System.Void", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "WillEncode", + "Parameters": [ + { + "Name": "unicodeScalar", + "Type": "System.Int32" + } + ], + "ReturnType": "System.Boolean", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "FindFirstCharacterToEncode", + "Parameters": [ + { + "Name": "text", + "Type": "System.Char*" + }, + { + "Name": "textLength", + "Type": "System.Int32" + } + ], + "ReturnType": "System.Int32", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "TryEncodeUnicodeScalar", + "Parameters": [ + { + "Name": "unicodeScalar", + "Type": "System.Int32" + }, + { + "Name": "buffer", + "Type": "System.Char*" + }, + { + "Name": "bufferLength", + "Type": "System.Int32" + }, + { + "Name": "numberOfCharactersWritten", + "Type": "System.Int32", + "Direction": "Out" + } + ], + "ReturnType": "System.Boolean", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.Extensions.WebEncoders.Testing.UrlTestEncoder", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "System.Text.Encodings.Web.UrlEncoder", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_MaxOutputCharactersPerInputCharacter", + "Parameters": [], + "ReturnType": "System.Int32", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Encode", + "Parameters": [ + { + "Name": "value", + "Type": "System.String" + } + ], + "ReturnType": "System.String", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Encode", + "Parameters": [ + { + "Name": "output", + "Type": "System.IO.TextWriter" + }, + { + "Name": "value", + "Type": "System.Char[]" + }, + { + "Name": "startIndex", + "Type": "System.Int32" + }, + { + "Name": "characterCount", + "Type": "System.Int32" + } + ], + "ReturnType": "System.Void", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Encode", + "Parameters": [ + { + "Name": "output", + "Type": "System.IO.TextWriter" + }, + { + "Name": "value", + "Type": "System.String" + }, + { + "Name": "startIndex", + "Type": "System.Int32" + }, + { + "Name": "characterCount", + "Type": "System.Int32" + } + ], + "ReturnType": "System.Void", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "WillEncode", + "Parameters": [ + { + "Name": "unicodeScalar", + "Type": "System.Int32" + } + ], + "ReturnType": "System.Boolean", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "FindFirstCharacterToEncode", + "Parameters": [ + { + "Name": "text", + "Type": "System.Char*" + }, + { + "Name": "textLength", + "Type": "System.Int32" + } + ], + "ReturnType": "System.Int32", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "TryEncodeUnicodeScalar", + "Parameters": [ + { + "Name": "unicodeScalar", + "Type": "System.Int32" + }, + { + "Name": "buffer", + "Type": "System.Char*" + }, + { + "Name": "bufferLength", + "Type": "System.Int32" + }, + { + "Name": "numberOfCharactersWritten", + "Type": "System.Int32", + "Direction": "Out" + } + ], + "ReturnType": "System.Boolean", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.Extensions.DependencyInjection.EncoderServiceCollectionExtensions", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "AddWebEncoders", + "Parameters": [ + { + "Name": "services", + "Type": "Microsoft.Extensions.DependencyInjection.IServiceCollection" + } + ], + "ReturnType": "Microsoft.Extensions.DependencyInjection.IServiceCollection", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AddWebEncoders", + "Parameters": [ + { + "Name": "services", + "Type": "Microsoft.Extensions.DependencyInjection.IServiceCollection" + }, + { + "Name": "setupAction", + "Type": "System.Action" + } + ], + "ReturnType": "Microsoft.Extensions.DependencyInjection.IServiceCollection", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + } + ] +} \ No newline at end of file From 373097e0dd772d947603c2e1a316fe323f50a288 Mon Sep 17 00:00:00 2001 From: jacalvar Date: Fri, 4 Nov 2016 17:05:29 -0700 Subject: [PATCH 149/471] Created public API baselines --- .../baseline.netcore.json | 1840 +++++++++++++++++ 1 file changed, 1840 insertions(+) create mode 100644 src/Microsoft.AspNetCore.JsonPatch/baseline.netcore.json diff --git a/src/Microsoft.AspNetCore.JsonPatch/baseline.netcore.json b/src/Microsoft.AspNetCore.JsonPatch/baseline.netcore.json new file mode 100644 index 0000000000..c84771a03c --- /dev/null +++ b/src/Microsoft.AspNetCore.JsonPatch/baseline.netcore.json @@ -0,0 +1,1840 @@ +{ + "AssemblyIdentity": "Microsoft.AspNetCore.JsonPatch, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "Types": [ + { + "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": "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": "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.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.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" + } + ], + "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.ObjectAdapter", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.JsonPatch.Adapters.IObjectAdapter" + ], + "Members": [ + { + "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": "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": "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": "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": "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 From fe2453b93abe4f0bfbfade7abcb737fe10ed4040 Mon Sep 17 00:00:00 2001 From: Cyprien Autexier Date: Sat, 8 Oct 2016 04:43:22 -0700 Subject: [PATCH 150/471] Escaping support for JSON pointers --- .../Internal/ParsedPath.cs | 54 ++++++++++++++++++- ...nPatchDocumentJsonPropertyAttributeTest.cs | 23 ++++++++ .../JsonPropertyComplexNameDTO.cs | 16 ++++++ .../ObjectAdapterTests.cs | 27 ++++++++++ .../ParsedPathTests.cs | 39 ++++++++++++++ 5 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyComplexNameDTO.cs create mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/ParsedPathTests.cs diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/ParsedPath.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/ParsedPath.cs index fe786b86c1..8d0e69aa4d 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Internal/ParsedPath.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Internal/ParsedPath.cs @@ -1,8 +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. +using Microsoft.AspNetCore.JsonPatch.Exceptions; using System; using System.Collections.Generic; +using System.Text; namespace Microsoft.AspNetCore.JsonPatch.Internal { @@ -19,7 +21,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal throw new ArgumentNullException(nameof(path)); } - _segments = path.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries); + _segments = ParsePath(path); } public string LastSegment @@ -36,5 +38,55 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal } 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/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs index ef7d53c21a..0ec0c18afd 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs @@ -144,5 +144,28 @@ namespace Microsoft.AspNetCore.JsonPatch var pathToCheck = deserialized.Operations.First().path; Assert.Equal(pathToCheck, "/anothername"); } + + [Fact] + public void Add_OnApplyFromJson_EscapingHandledOnComplexJsonPropertyNameOnJsonDocument() + { + var doc = new JsonPropertyComplexNameDTO() + { + FooSlashBars = "InitialName", + FooSlashTilde = new SimpleDTO + { + StringProperty = "Initial Value" + } + }; + + // serialization should serialize to "AnotherName" + var serialized = "[{\"value\":\"Kevin\",\"path\":\"/foo~1bar~0\",\"op\":\"add\"},{\"value\":\"Final Value\",\"path\":\"/foo~1~0/StringProperty\",\"op\":\"replace\"}]"; + var deserialized = + JsonConvert.DeserializeObject>(serialized); + + deserialized.ApplyTo(doc); + + Assert.Equal("Kevin", doc.FooSlashBars); + Assert.Equal("Final Value", doc.FooSlashTilde.StringProperty); + } } } diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyComplexNameDTO.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyComplexNameDTO.cs new file mode 100644 index 0000000000..7ff66481ad --- /dev/null +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyComplexNameDTO.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 Newtonsoft.Json; + +namespace Microsoft.AspNetCore.JsonPatch +{ + public class JsonPropertyComplexNameDTO + { + [JsonProperty("foo/bar~")] + public string FooSlashBars { get; set; } + + [JsonProperty("foo/~")] + public SimpleDTO FooSlashTilde { get; set; } + } +} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs index 88693fdbd5..5898311044 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs @@ -1821,6 +1821,33 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters Assert.Equal("James", actualValue1.Name); } + [Fact] + public void Replace_WhenDictionary_ValueAPocoType_WithEscaping_Succeeds() + { + // Arrange + var key1 = "Foo/Name"; + var value1 = new Customer() { Name = "Jamesss" }; + var key2 = "Foo"; + var value2 = new Customer() { Name = "Mike" }; + var model = new Class8(); + model.DictionaryOfStringToCustomer[key1] = value1; + model.DictionaryOfStringToCustomer[key2] = value2; + var patchDocument = new JsonPatchDocument(); + patchDocument.Replace($"/DictionaryOfStringToCustomer/Foo~1Name/Name", "James"); + + // Act + patchDocument.ApplyTo(model); + + // Assert + Assert.Equal(2, model.DictionaryOfStringToCustomer.Count); + var actualValue1 = model.DictionaryOfStringToCustomer[key1]; + var actualValue2 = model.DictionaryOfStringToCustomer[key2]; + Assert.NotNull(actualValue1); + Assert.Equal("James", actualValue1.Name); + Assert.Equal("Mike", actualValue2.Name); + + } + [Fact] public void Replace_DeepNested_DictionaryValue_Succeeds() { diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/ParsedPathTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/ParsedPathTests.cs new file mode 100644 index 0000000000..6b7c2e69cb --- /dev/null +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/ParsedPathTests.cs @@ -0,0 +1,39 @@ +// Copyright (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 Microsoft.AspNetCore.JsonPatch.Internal; +using Xunit; + +namespace Microsoft.AspNetCore.JsonPatch.Test +{ + 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) + { + var parsedPath = new ParsedPath(path); + Assert.Equal(expected, parsedPath.Segments); + } + + [Theory] + [InlineData("foo/bar~")] + [InlineData("~")] + [InlineData("~2")] + [InlineData("foo~3bar")] + public void PathWithInvalidEscapeSequenceShouldFail(string path) + { + Assert.Throws(() => + { + var parsedPath = new ParsedPath(path); + }); + } + } +} From 86508f3c44468326384c90b139b1bd4e7328e832 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 9 Nov 2016 11:31:01 -0800 Subject: [PATCH 151/471] Branching for 1.1.0 --- NuGet.config | 4 ++-- build.ps1 | 2 +- build.sh | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/NuGet.config b/NuGet.config index 826a1f9035..6197c93176 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,7 @@ - + - + \ No newline at end of file diff --git a/build.ps1 b/build.ps1 index 8f2f99691a..24ca167cf6 100644 --- a/build.ps1 +++ b/build.ps1 @@ -33,7 +33,7 @@ cd $PSScriptRoot $repoFolder = $PSScriptRoot $env:REPO_FOLDER = $repoFolder -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/1.1.0.zip" if ($env:KOREBUILD_ZIP) { $koreBuildZip=$env:KOREBUILD_ZIP diff --git a/build.sh b/build.sh index f4208100eb..fea9ac64ad 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/1.1.0.zip" if [ ! -z $KOREBUILD_ZIP ]; then koreBuildZip=$KOREBUILD_ZIP fi From fd2aec9d343ac0794f4acb27b2bf26ace3242c50 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 9 Nov 2016 11:31:27 -0800 Subject: [PATCH 152/471] Branching for 1.1.0 --- NuGet.config | 4 ++-- build.ps1 | 2 +- build.sh | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/NuGet.config b/NuGet.config index 0fd623ffdd..ad973186eb 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,7 @@ - + - + diff --git a/build.ps1 b/build.ps1 index 8f2f99691a..24ca167cf6 100644 --- a/build.ps1 +++ b/build.ps1 @@ -33,7 +33,7 @@ cd $PSScriptRoot $repoFolder = $PSScriptRoot $env:REPO_FOLDER = $repoFolder -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/1.1.0.zip" if ($env:KOREBUILD_ZIP) { $koreBuildZip=$env:KOREBUILD_ZIP diff --git a/build.sh b/build.sh index f4208100eb..fea9ac64ad 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/1.1.0.zip" if [ ! -z $KOREBUILD_ZIP ]; then koreBuildZip=$KOREBUILD_ZIP fi From 9cdb55b59cee496d3b65913c42fff4724ac2e52f Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 9 Nov 2016 14:17:51 -0800 Subject: [PATCH 153/471] Updating versions to 1.2.0-* --- src/Microsoft.AspNetCore.Html.Abstractions/project.json | 2 +- src/Microsoft.Extensions.WebEncoders/project.json | 6 +++--- .../project.json | 6 +++--- test/Microsoft.Extensions.WebEncoders.Tests/project.json | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/project.json b/src/Microsoft.AspNetCore.Html.Abstractions/project.json index da6f399828..8c64893f22 100644 --- a/src/Microsoft.AspNetCore.Html.Abstractions/project.json +++ b/src/Microsoft.AspNetCore.Html.Abstractions/project.json @@ -1,5 +1,5 @@ { - "version": "1.1.0-*", + "version": "1.2.0-*", "description": "ASP.NET Core HTML abstractions used for building HTML content.\r\nCommonly used types:\r\nMicrosoft.AspNetCore.Html.HtmlString\r\nMicrosoft.AspNetCore.Html.IHtmlContent", "packOptions": { "repository": { diff --git a/src/Microsoft.Extensions.WebEncoders/project.json b/src/Microsoft.Extensions.WebEncoders/project.json index 852787db64..f7ded704b5 100644 --- a/src/Microsoft.Extensions.WebEncoders/project.json +++ b/src/Microsoft.Extensions.WebEncoders/project.json @@ -1,5 +1,5 @@ { - "version": "1.1.0-*", + "version": "1.2.0-*", "description": "Contains registration and configuration APIs to add the core framework encoders to a dependency injection container.", "packOptions": { "repository": { @@ -20,8 +20,8 @@ "xmlDoc": true }, "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "1.1.0-*", - "Microsoft.Extensions.Options": "1.1.0-*", + "Microsoft.Extensions.DependencyInjection.Abstractions": "1.2.0-*", + "Microsoft.Extensions.Options": "1.2.0-*", "NETStandard.Library": "1.6.1-*", "System.Text.Encodings.Web": "4.3.0-*" }, diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json index 754cf25670..a1e50970d0 100644 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json @@ -5,9 +5,9 @@ }, "dependencies": { "dotnet-test-xunit": "2.2.0-*", - "Microsoft.AspNetCore.Html.Abstractions": "1.1.0-*", - "Microsoft.AspNetCore.Testing": "1.1.0-*", - "Microsoft.Extensions.WebEncoders": "1.1.0-*", + "Microsoft.AspNetCore.Html.Abstractions": "1.2.0-*", + "Microsoft.AspNetCore.Testing": "1.2.0-*", + "Microsoft.Extensions.WebEncoders": "1.2.0-*", "xunit": "2.2.0-*" }, "testRunner": "xunit", diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/project.json b/test/Microsoft.Extensions.WebEncoders.Tests/project.json index 9171910c7c..462b1cebfd 100644 --- a/test/Microsoft.Extensions.WebEncoders.Tests/project.json +++ b/test/Microsoft.Extensions.WebEncoders.Tests/project.json @@ -1,8 +1,8 @@ { "dependencies": { "dotnet-test-xunit": "2.2.0-*", - "Microsoft.Extensions.DependencyInjection": "1.1.0-*", - "Microsoft.Extensions.WebEncoders": "1.1.0-*", + "Microsoft.Extensions.DependencyInjection": "1.2.0-*", + "Microsoft.Extensions.WebEncoders": "1.2.0-*", "xunit": "2.2.0-*" }, "testRunner": "xunit", From 6ee6220e06131584a56d7225e1dcdb5fe4b7a867 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 9 Nov 2016 14:18:11 -0800 Subject: [PATCH 154/471] Updating versions to 1.2.0-* --- src/Microsoft.AspNetCore.JsonPatch/project.json | 4 ++-- test/Microsoft.AspNetCore.JsonPatch.Test/project.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.AspNetCore.JsonPatch/project.json b/src/Microsoft.AspNetCore.JsonPatch/project.json index 5b998272ff..a2015980e1 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/project.json +++ b/src/Microsoft.AspNetCore.JsonPatch/project.json @@ -1,5 +1,5 @@ { - "version": "1.1.0-*", + "version": "1.2.0-*", "description": "ASP.NET Core support for JSON PATCH.", "buildOptions": { "warningsAsErrors": true, @@ -25,7 +25,7 @@ "Newtonsoft.Json": "9.0.1", "Microsoft.Extensions.ClosedGenericMatcher.Sources": { "type": "build", - "version": "1.1.0-*" + "version": "1.2.0-*" } }, "frameworks": { diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json index 9e95ee86e0..158192b281 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json @@ -4,8 +4,8 @@ }, "dependencies": { "dotnet-test-xunit": "2.2.0-*", - "Microsoft.AspNetCore.JsonPatch": "1.1.0-*", - "Microsoft.AspNetCore.Testing": "1.1.0-*", + "Microsoft.AspNetCore.JsonPatch": "1.2.0-*", + "Microsoft.AspNetCore.Testing": "1.2.0-*", "Moq": "4.6.36-*", "xunit": "2.2.0-*" }, From 758f35835c1a9257fefa8692431d662ed5d53824 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Fri, 18 Nov 2016 10:56:54 -0800 Subject: [PATCH 155/471] Clean tmp folder after unzipping KoreBuild --- build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sh b/build.sh index f4208100eb..4fd7ede788 100755 --- a/build.sh +++ b/build.sh @@ -38,7 +38,7 @@ if test ! -d $buildFolder; then chmod +x $buildFile # Cleanup - if test ! -d $tempFolder; then + if test -d $tempFolder; then rm -rf $tempFolder fi fi From 6259fd3fb37712fb670e33326c68279c8df3c9b0 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Fri, 18 Nov 2016 10:57:00 -0800 Subject: [PATCH 156/471] Clean tmp folder after unzipping KoreBuild --- build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sh b/build.sh index f4208100eb..4fd7ede788 100755 --- a/build.sh +++ b/build.sh @@ -38,7 +38,7 @@ if test ! -d $buildFolder; then chmod +x $buildFile # Cleanup - if test ! -d $tempFolder; then + if test -d $tempFolder; then rm -rf $tempFolder fi fi From 4faf89030c47e5ee5c7193a26d810a50862a3cf4 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 18 Nov 2016 12:12:17 -0800 Subject: [PATCH 157/471] Pinning versions for 1.1.0 release --- NuGet.config | 7 ++++--- src/Microsoft.AspNetCore.JsonPatch/project.json | 14 +++++++------- .../project.json | 8 ++++---- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/NuGet.config b/NuGet.config index ad973186eb..feaadcda87 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,8 @@ - + - - + + + diff --git a/src/Microsoft.AspNetCore.JsonPatch/project.json b/src/Microsoft.AspNetCore.JsonPatch/project.json index 5b998272ff..6d2ccde5cc 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/project.json +++ b/src/Microsoft.AspNetCore.JsonPatch/project.json @@ -1,5 +1,5 @@ { - "version": "1.1.0-*", + "version": "1.1.0", "description": "ASP.NET Core support for JSON PATCH.", "buildOptions": { "warningsAsErrors": true, @@ -21,19 +21,19 @@ ] }, "dependencies": { - "NETStandard.Library": "1.6.1-*", - "Newtonsoft.Json": "9.0.1", "Microsoft.Extensions.ClosedGenericMatcher.Sources": { "type": "build", - "version": "1.1.0-*" - } + "version": "1.1.0-rtm-22752" + }, + "NETStandard.Library": "1.6.1", + "Newtonsoft.Json": "9.0.1" }, "frameworks": { "net451": {}, "netstandard1.3": { "dependencies": { - "Microsoft.CSharp": "4.3.0-*", - "System.Reflection.TypeExtensions": "4.3.0-*" + "Microsoft.CSharp": "4.3.0", + "System.Reflection.TypeExtensions": "4.3.0" } } } diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json index 9e95ee86e0..196dbcac08 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json @@ -4,8 +4,8 @@ }, "dependencies": { "dotnet-test-xunit": "2.2.0-*", - "Microsoft.AspNetCore.JsonPatch": "1.1.0-*", - "Microsoft.AspNetCore.Testing": "1.1.0-*", + "Microsoft.AspNetCore.JsonPatch": "1.1.0", + "Microsoft.AspNetCore.Testing": "1.1.0-rtm-22752", "Moq": "4.6.36-*", "xunit": "2.2.0-*" }, @@ -14,10 +14,10 @@ "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.1.0-*", + "version": "1.1.0", "type": "platform" }, - "System.Diagnostics.TraceSource": "4.3.0-*" + "System.Diagnostics.TraceSource": "4.3.0" } }, "net451": { From 4dea3e7512a5ebf0d502c4a01ec0a69650af8270 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Wed, 23 Nov 2016 15:57:04 -0800 Subject: [PATCH 158/471] Pin global.json SDK to 1.0.0-preview2-1-003177. --- global.json | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/global.json b/global.json index fad3dfeab0..e04bdfc390 100644 --- a/global.json +++ b/global.json @@ -1,3 +1,10 @@ { - "projects": ["src", "test/WebSites", "samples"] -} + "projects": [ + "src", + "test/WebSites", + "samples" + ], + "sdk": { + "version": "1.0.0-preview2-1-003177" + } +} \ No newline at end of file From fe4527d54399bb98c43e0f75633b6d4ea3d812ab Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Wed, 23 Nov 2016 15:57:55 -0800 Subject: [PATCH 159/471] Pin global.json SDK to 1.0.0-preview2-1-003177. --- global.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/global.json b/global.json index 983ba0401e..f45e8cc925 100644 --- a/global.json +++ b/global.json @@ -1,3 +1,8 @@ { - "projects": ["src"] -} + "projects": [ + "src" + ], + "sdk": { + "version": "1.0.0-preview2-1-003177" + } +} \ No newline at end of file From 5d8be62037127a1ac102a63e7a9ac7c21c3d8e88 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Thu, 8 Dec 2016 10:01:52 -0800 Subject: [PATCH 160/471] Update .travis.yml osx image to xcode7.3. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d7636fa329..a0be886892 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,7 +19,7 @@ mono: os: - linux - osx -osx_image: xcode7.1 +osx_image: xcode7.3 branches: only: - master From 9c90925f81b59a637b86f015d6fbba930c0d56d0 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Thu, 8 Dec 2016 10:02:30 -0800 Subject: [PATCH 161/471] Update .travis.yml osx image to xcode7.3. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e2abeda7d4..67d9a88786 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,7 +19,7 @@ mono: os: - linux - osx -osx_image: xcode7.1 +osx_image: xcode7.3 branches: only: - master From 9bf8486fe58017b0a0cb586f8a9ca04e9ada8728 Mon Sep 17 00:00:00 2001 From: Ajay Bhargav Baaskaran Date: Mon, 12 Dec 2016 00:42:23 -0800 Subject: [PATCH 162/471] Removed packages list in NuGetPackageVerifier.json --- NuGetPackageVerifier.json | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/NuGetPackageVerifier.json b/NuGetPackageVerifier.json index f68002830f..b153ab1515 100644 --- a/NuGetPackageVerifier.json +++ b/NuGetPackageVerifier.json @@ -1,13 +1,5 @@ { - "adx": { // Packages written by the ADX team and that ship on NuGet.org - "rules": [ - "AdxVerificationCompositeRule" - ], - "packages": { - "Microsoft.AspNetCore.JsonPatch": { } - } - }, - "Default": { // Rules to run for packages not listed in any other set. + "Default": { "rules": [ "DefaultCompositeRule" ] From 3a9dff9c1c3884e3919ffa99a64b78485836ede9 Mon Sep 17 00:00:00 2001 From: Ajay Bhargav Baaskaran Date: Mon, 12 Dec 2016 00:42:29 -0800 Subject: [PATCH 163/471] Removed packages list in NuGetPackageVerifier.json --- NuGetPackageVerifier.json | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/NuGetPackageVerifier.json b/NuGetPackageVerifier.json index 8df495e3e0..b153ab1515 100644 --- a/NuGetPackageVerifier.json +++ b/NuGetPackageVerifier.json @@ -1,14 +1,5 @@ { - "adx": { // Packages written by the ADX team and that ship on NuGet.org - "rules": [ - "AdxVerificationCompositeRule" - ], - "packages": { - "Microsoft.AspNetCore.Html.Abstractions": { }, - "Microsoft.Extensions.WebEncoders": { } - } - }, - "Default": { // Rules to run for packages not listed in any other set. + "Default": { "rules": [ "DefaultCompositeRule" ] From c8c2dfaad97d1e21eacb8ba0bbd1b65a9cc6993f Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 5 Dec 2016 09:02:54 -0800 Subject: [PATCH 164/471] Updating to 4.4 CoreFx packages --- global.json | 2 +- src/Microsoft.AspNetCore.JsonPatch/project.json | 6 +++--- test/Microsoft.AspNetCore.JsonPatch.Test/project.json | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/global.json b/global.json index e04bdfc390..a5c02fe221 100644 --- a/global.json +++ b/global.json @@ -5,6 +5,6 @@ "samples" ], "sdk": { - "version": "1.0.0-preview2-1-003177" + "version": "1.0.0-preview2-1-003180" } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.JsonPatch/project.json b/src/Microsoft.AspNetCore.JsonPatch/project.json index a2015980e1..7214cde411 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/project.json +++ b/src/Microsoft.AspNetCore.JsonPatch/project.json @@ -21,7 +21,7 @@ ] }, "dependencies": { - "NETStandard.Library": "1.6.1-*", + "NETStandard.Library": "1.6.2-*", "Newtonsoft.Json": "9.0.1", "Microsoft.Extensions.ClosedGenericMatcher.Sources": { "type": "build", @@ -32,8 +32,8 @@ "net451": {}, "netstandard1.3": { "dependencies": { - "Microsoft.CSharp": "4.3.0-*", - "System.Reflection.TypeExtensions": "4.3.0-*" + "Microsoft.CSharp": "4.4.0-*", + "System.Reflection.TypeExtensions": "4.4.0-*" } } } diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json index 158192b281..4790217eba 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json @@ -14,10 +14,10 @@ "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.1.0-*", + "version": "1.2.0-*", "type": "platform" }, - "System.Diagnostics.TraceSource": "4.3.0-*" + "System.Diagnostics.TraceSource": "4.4.0-*" } }, "net451": { From f6eb86be7838e030173d2c6e7614bccd18d1dec7 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 5 Dec 2016 09:02:41 -0800 Subject: [PATCH 165/471] Updating to 4.4 CoreFx packages --- global.json | 2 +- src/Microsoft.AspNetCore.Html.Abstractions/project.json | 4 ++-- src/Microsoft.Extensions.WebEncoders/project.json | 4 ++-- test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json | 2 +- test/Microsoft.Extensions.WebEncoders.Tests/project.json | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/global.json b/global.json index f45e8cc925..0ad1995dd2 100644 --- a/global.json +++ b/global.json @@ -3,6 +3,6 @@ "src" ], "sdk": { - "version": "1.0.0-preview2-1-003177" + "version": "1.0.0-preview2-1-003180" } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/project.json b/src/Microsoft.AspNetCore.Html.Abstractions/project.json index 8c64893f22..4e640d584b 100644 --- a/src/Microsoft.AspNetCore.Html.Abstractions/project.json +++ b/src/Microsoft.AspNetCore.Html.Abstractions/project.json @@ -19,8 +19,8 @@ "xmlDoc": true }, "dependencies": { - "NETStandard.Library": "1.6.1-*", - "System.Text.Encodings.Web": "4.3.0-*" + "NETStandard.Library": "1.6.2-*", + "System.Text.Encodings.Web": "4.4.0-*" }, "frameworks": { "netstandard1.0": {} diff --git a/src/Microsoft.Extensions.WebEncoders/project.json b/src/Microsoft.Extensions.WebEncoders/project.json index f7ded704b5..b3fe422893 100644 --- a/src/Microsoft.Extensions.WebEncoders/project.json +++ b/src/Microsoft.Extensions.WebEncoders/project.json @@ -22,8 +22,8 @@ "dependencies": { "Microsoft.Extensions.DependencyInjection.Abstractions": "1.2.0-*", "Microsoft.Extensions.Options": "1.2.0-*", - "NETStandard.Library": "1.6.1-*", - "System.Text.Encodings.Web": "4.3.0-*" + "NETStandard.Library": "1.6.2-*", + "System.Text.Encodings.Web": "4.4.0-*" }, "frameworks": { "netstandard1.0": {} diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json index a1e50970d0..0e46d9c52c 100644 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json @@ -15,7 +15,7 @@ "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.1.0-*", + "version": "1.2.0-*", "type": "platform" } } diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/project.json b/test/Microsoft.Extensions.WebEncoders.Tests/project.json index 462b1cebfd..d06fb5b18b 100644 --- a/test/Microsoft.Extensions.WebEncoders.Tests/project.json +++ b/test/Microsoft.Extensions.WebEncoders.Tests/project.json @@ -14,7 +14,7 @@ "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.1.0-*", + "version": "1.2.0-*", "type": "platform" } }, From 5966024d01278bccb4cf2581fdd93575e87da9d8 Mon Sep 17 00:00:00 2001 From: David Rovani Date: Fri, 23 Dec 2016 09:33:39 -0600 Subject: [PATCH 166/471] Fixed minor spelling error in comments. --- src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocument.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocument.cs b/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocument.cs index 875134ed9d..4da2bdbe1e 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocument.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocument.cs @@ -123,7 +123,7 @@ namespace Microsoft.AspNetCore.JsonPatch } /// - /// Copy the value at specified location to the target location. Willr esult in, for example: + /// 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 From e8452821b9a7689853e36c9a10ad4b8c6281817c Mon Sep 17 00:00:00 2001 From: Kiran Challa Date: Wed, 28 Dec 2016 13:35:15 -0800 Subject: [PATCH 167/471] [Fixes #50] JsonPatchDocument.Replace() yields invalid path when [JsonProperty] is used (1.1.0) --- .../Internal/ExpressionHelpers.cs | 120 ------------- .../JsonPatchDocumentOfT.cs | 170 ++++++++++++++---- ...nPatchDocumentJsonPropertyAttributeTest.cs | 113 +++++++++++- 3 files changed, 245 insertions(+), 158 deletions(-) delete mode 100644 src/Microsoft.AspNetCore.JsonPatch/Internal/ExpressionHelpers.cs diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/ExpressionHelpers.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/ExpressionHelpers.cs deleted file mode 100644 index c978330e5c..0000000000 --- a/src/Microsoft.AspNetCore.JsonPatch/Internal/ExpressionHelpers.cs +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Globalization; -using System.Linq.Expressions; -using System.Reflection; -using Newtonsoft.Json; - -namespace Microsoft.AspNetCore.JsonPatch.Internal -{ - public static class ExpressionHelpers - { - public static string GetPath(Expression> expr) where TModel : class - { - return "/" + GetPath(expr.Body, true); - } - - private static string GetPath(Expression expr, bool firstTime) - { - switch (expr.NodeType) - { - case ExpressionType.ArrayIndex: - var binaryExpression = (BinaryExpression)expr; - - if (ContinueWithSubPath(binaryExpression.Left.NodeType, false)) - { - var leftFromBinaryExpression = GetPath(binaryExpression.Left, false); - return leftFromBinaryExpression + "/" + binaryExpression.Right.ToString(); - } - else - { - return binaryExpression.Right.ToString(); - } - case ExpressionType.Call: - var methodCallExpression = (MethodCallExpression)expr; - - if (ContinueWithSubPath(methodCallExpression.Object.NodeType, false)) - { - var leftFromMemberCallExpression = GetPath(methodCallExpression.Object, false); - return leftFromMemberCallExpression + "/" + - GetIndexerInvocation(methodCallExpression.Arguments[0]); - } - else - { - return GetIndexerInvocation(methodCallExpression.Arguments[0]); - } - case ExpressionType.Convert: - return GetPath(((UnaryExpression)expr).Operand, false); - case ExpressionType.MemberAccess: - var memberExpression = expr as MemberExpression; - - if (ContinueWithSubPath(memberExpression.Expression.NodeType, false)) - { - var left = GetPath(memberExpression.Expression, false); - // Get property name, respecting JsonProperty attribute - return left + "/" + GetPropertyNameFromMemberExpression(memberExpression); - } - else - { - // Get property name, respecting JsonProperty attribute - return GetPropertyNameFromMemberExpression(memberExpression); - } - case ExpressionType.Parameter: - // Fits "x => x" (the whole document which is "" as JSON pointer) - return firstTime ? string.Empty : null; - default: - return string.Empty; - } - } - - private static string GetPropertyNameFromMemberExpression(MemberExpression memberExpression) - { - // if there's a JsonProperty attribute, we must return the PropertyName - // from the attribute rather than the member name - var jsonPropertyAttribute = - memberExpression.Member.GetCustomAttribute( - typeof(JsonPropertyAttribute), true); - - if (jsonPropertyAttribute == null) - { - return memberExpression.Member.Name; - } - // get value - var castedAttribute = (JsonPropertyAttribute)jsonPropertyAttribute; - return castedAttribute.PropertyName; - } - - private static bool ContinueWithSubPath(ExpressionType expressionType, bool firstTime) - { - if (firstTime) - { - return (expressionType == ExpressionType.ArrayIndex - || expressionType == ExpressionType.Call - || expressionType == ExpressionType.Convert - || expressionType == ExpressionType.MemberAccess - || expressionType == ExpressionType.Parameter); - } - else - { - return (expressionType == ExpressionType.ArrayIndex - || expressionType == ExpressionType.Call - || expressionType == ExpressionType.Convert - || expressionType == ExpressionType.MemberAccess); - } - } - - private static string GetIndexerInvocation(Expression expression) - { - var converted = Expression.Convert(expression, typeof(object)); - var fakeParameter = Expression.Parameter(typeof(object), null); - var lambda = Expression.Lambda>(converted, fakeParameter); - Func func; - - func = lambda.Compile(); - - return Convert.ToString(func(null), CultureInfo.InvariantCulture); - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs b/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs index fc660b2b45..c81c4e4d6c 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs @@ -2,7 +2,9 @@ // 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; @@ -66,7 +68,7 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "add", - ExpressionHelpers.GetPath(path).ToLowerInvariant(), + GetPath(path), from: null, value: value)); @@ -93,7 +95,7 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "add", - ExpressionHelpers.GetPath(path).ToLowerInvariant() + "/" + position, + GetPath(path) + "/" + position, from: null, value: value)); @@ -116,7 +118,7 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "add", - ExpressionHelpers.GetPath(path).ToLowerInvariant() + "/-", + GetPath(path) + "/-", from: null, value: value)); @@ -136,7 +138,7 @@ namespace Microsoft.AspNetCore.JsonPatch throw new ArgumentNullException(nameof(path)); } - Operations.Add(new Operation("remove", ExpressionHelpers.GetPath(path).ToLowerInvariant(), from: null)); + Operations.Add(new Operation("remove", GetPath(path), from: null)); return this; } @@ -157,7 +159,7 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "remove", - ExpressionHelpers.GetPath(path).ToLowerInvariant() + "/" + position, + GetPath(path) + "/" + position, from: null)); return this; @@ -178,7 +180,7 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "remove", - ExpressionHelpers.GetPath(path).ToLowerInvariant() + "/-", + GetPath(path) + "/-", from: null)); return this; @@ -200,7 +202,7 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "replace", - ExpressionHelpers.GetPath(path).ToLowerInvariant(), + GetPath(path), from: null, value: value)); @@ -225,7 +227,7 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "replace", - ExpressionHelpers.GetPath(path).ToLowerInvariant() + "/" + position, + GetPath(path) + "/" + position, from: null, value: value)); @@ -248,7 +250,7 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "replace", - ExpressionHelpers.GetPath(path).ToLowerInvariant() + "/-", + GetPath(path) + "/-", from: null, value: value)); @@ -278,8 +280,8 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "move", - ExpressionHelpers.GetPath(path).ToLowerInvariant(), - ExpressionHelpers.GetPath(from).ToLowerInvariant())); + GetPath(path), + GetPath(from))); return this; } @@ -309,8 +311,8 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "move", - ExpressionHelpers.GetPath(path).ToLowerInvariant(), - ExpressionHelpers.GetPath(from).ToLowerInvariant() + "/" + positionFrom)); + GetPath(path), + GetPath(from) + "/" + positionFrom)); return this; } @@ -340,8 +342,8 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "move", - ExpressionHelpers.GetPath(path).ToLowerInvariant() + "/" + positionTo, - ExpressionHelpers.GetPath(from).ToLowerInvariant())); + GetPath(path) + "/" + positionTo, + GetPath(from))); return this; } @@ -373,8 +375,8 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "move", - ExpressionHelpers.GetPath(path).ToLowerInvariant() + "/" + positionTo, - ExpressionHelpers.GetPath(from).ToLowerInvariant() + "/" + positionFrom)); + GetPath(path) + "/" + positionTo, + GetPath(from) + "/" + positionFrom)); return this; } @@ -404,8 +406,8 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "move", - ExpressionHelpers.GetPath(path).ToLowerInvariant() + "/-", - ExpressionHelpers.GetPath(from).ToLowerInvariant() + "/" + positionFrom)); + GetPath(path) + "/-", + GetPath(from) + "/" + positionFrom)); return this; } @@ -433,8 +435,8 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "move", - ExpressionHelpers.GetPath(path).ToLowerInvariant() + "/-", - ExpressionHelpers.GetPath(from).ToLowerInvariant())); + GetPath(path) + "/-", + GetPath(from))); return this; } @@ -462,8 +464,8 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "copy", - ExpressionHelpers.GetPath(path).ToLowerInvariant() - , ExpressionHelpers.GetPath(from).ToLowerInvariant())); + GetPath(path) + , GetPath(from))); return this; } @@ -493,8 +495,8 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "copy", - ExpressionHelpers.GetPath(path).ToLowerInvariant(), - ExpressionHelpers.GetPath(from).ToLowerInvariant() + "/" + positionFrom)); + GetPath(path), + GetPath(from) + "/" + positionFrom)); return this; } @@ -524,8 +526,8 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "copy", - ExpressionHelpers.GetPath(path).ToLowerInvariant() + "/" + positionTo, - ExpressionHelpers.GetPath(from).ToLowerInvariant())); + GetPath(path) + "/" + positionTo, + GetPath(from))); return this; } @@ -557,8 +559,8 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "copy", - ExpressionHelpers.GetPath(path).ToLowerInvariant() + "/" + positionTo, - ExpressionHelpers.GetPath(from).ToLowerInvariant() + "/" + positionFrom)); + GetPath(path) + "/" + positionTo, + GetPath(from) + "/" + positionFrom)); return this; } @@ -588,8 +590,8 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "copy", - ExpressionHelpers.GetPath(path).ToLowerInvariant() + "/-", - ExpressionHelpers.GetPath(from).ToLowerInvariant() + "/" + positionFrom)); + GetPath(path) + "/-", + GetPath(from) + "/" + positionFrom)); return this; } @@ -617,8 +619,8 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "copy", - ExpressionHelpers.GetPath(path).ToLowerInvariant() + "/-", - ExpressionHelpers.GetPath(from).ToLowerInvariant())); + GetPath(path) + "/-", + GetPath(from))); return this; } @@ -712,5 +714,107 @@ namespace Microsoft.AspNetCore.JsonPatch return allOps; } + + private string GetPath(Expression> expr) + { + return "/" + GetPath(expr.Body, true).ToLowerInvariant(); + } + + private string GetPath(Expression expr, bool firstTime) + { + switch (expr.NodeType) + { + case ExpressionType.ArrayIndex: + var binaryExpression = (BinaryExpression)expr; + + if (ContinueWithSubPath(binaryExpression.Left.NodeType, false)) + { + var leftFromBinaryExpression = GetPath(binaryExpression.Left, false); + return leftFromBinaryExpression + "/" + binaryExpression.Right.ToString(); + } + else + { + return binaryExpression.Right.ToString(); + } + case ExpressionType.Call: + var methodCallExpression = (MethodCallExpression)expr; + + if (ContinueWithSubPath(methodCallExpression.Object.NodeType, false)) + { + var leftFromMemberCallExpression = GetPath(methodCallExpression.Object, false); + return leftFromMemberCallExpression + "/" + + GetIndexerInvocation(methodCallExpression.Arguments[0]); + } + else + { + return GetIndexerInvocation(methodCallExpression.Arguments[0]); + } + case ExpressionType.Convert: + return GetPath(((UnaryExpression)expr).Operand, false); + case ExpressionType.MemberAccess: + var memberExpression = expr as MemberExpression; + + if (ContinueWithSubPath(memberExpression.Expression.NodeType, false)) + { + var left = GetPath(memberExpression.Expression, false); + // Get property name, respecting JsonProperty attribute + return left + "/" + GetPropertyNameFromMemberExpression(memberExpression); + } + else + { + // Get property name, respecting JsonProperty attribute + return GetPropertyNameFromMemberExpression(memberExpression); + } + case ExpressionType.Parameter: + // Fits "x => x" (the whole document which is "" as JSON pointer) + return firstTime ? string.Empty : null; + default: + return string.Empty; + } + } + + 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, bool firstTime) + { + if (firstTime) + { + return (expressionType == ExpressionType.ArrayIndex + || expressionType == ExpressionType.Call + || expressionType == ExpressionType.Convert + || expressionType == ExpressionType.MemberAccess + || expressionType == ExpressionType.Parameter); + } + else + { + return (expressionType == ExpressionType.ArrayIndex + || expressionType == ExpressionType.Call + || expressionType == ExpressionType.Convert + || expressionType == ExpressionType.MemberAccess); + } + } + + private static string GetIndexerInvocation(Expression expression) + { + var converted = Expression.Convert(expression, typeof(object)); + var fakeParameter = Expression.Parameter(typeof(object), null); + var lambda = Expression.Lambda>(converted, fakeParameter); + Func func; + + func = lambda.Compile(); + + return Convert.ToString(func(null), CultureInfo.InvariantCulture); + } } } \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs index 0ec0c18afd..182cf1cd6d 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs @@ -1,8 +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. -using Newtonsoft.Json; using System.Linq; +using System.Reflection; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; using Xunit; namespace Microsoft.AspNetCore.JsonPatch @@ -26,13 +28,47 @@ namespace Microsoft.AspNetCore.JsonPatch Assert.Equal(pathToCheck, "/anothername"); } + [Fact] + public void Add_WithExpressionOnStringProperty_FallsbackToPropertyName_WhenJsonPropertyName_IsEmpty() + { + // Arrange + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(m => m.StringProperty, "Test"); + var serialized = JsonConvert.SerializeObject(patchDoc); + + // Act + var deserialized = + JsonConvert.DeserializeObject>(serialized); + + // Assert + var pathToCheck = deserialized.Operations.First().path; + Assert.Equal("/stringproperty", pathToCheck); + } + + [Fact] + public void Add_WithExpressionOnArrayProperty_FallsbackToPropertyName_WhenJsonPropertyName_IsEmpty() + { + // Arrange + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(m => m.ArrayProperty, "James"); + var serialized = JsonConvert.SerializeObject(patchDoc); + + // Act + var deserialized = + JsonConvert.DeserializeObject>(serialized); + + // Assert + var pathToCheck = deserialized.Operations.First().path; + Assert.Equal("/arrayproperty/-", pathToCheck); + } + [Fact] public void Add_WithExpression_RespectsJsonPropertyName_WhenApplyingToDifferentlyTypedClassWithPropertyMatchingJsonPropertyName() { var patchDocToSerialize = new JsonPatchDocument(); patchDocToSerialize.Add(p => p.Name, "John"); - // the patchdoc will deserialize to "anothername". We should thus be able to apply + // the patchdoc will deserialize to "anothername". We should thus be able to apply // it to a class that HAS that other property name. var doc = new JsonPropertyWithAnotherNameDTO() { @@ -81,7 +117,7 @@ namespace Microsoft.AspNetCore.JsonPatch { Name = "InitialValue" }; - + // serialization should serialize to "AnotherName" var serialized = "[{\"value\":\"Kevin\",\"path\":\"/AnotherName\",\"op\":\"add\"}]"; var deserialized = @@ -151,9 +187,9 @@ namespace Microsoft.AspNetCore.JsonPatch var doc = new JsonPropertyComplexNameDTO() { FooSlashBars = "InitialName", - FooSlashTilde = new SimpleDTO + FooSlashTilde = new SimpleDTO { - StringProperty = "Initial Value" + StringProperty = "Initial Value" } }; @@ -167,5 +203,72 @@ namespace Microsoft.AspNetCore.JsonPatch Assert.Equal("Kevin", doc.FooSlashBars); Assert.Equal("Final Value", doc.FooSlashTilde.StringProperty); } + + [Fact] + public void Move_WithExpression_FallsbackToPropertyName_WhenJsonPropertyName_IsEmpty() + { + // Arrange + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(m => m.StringProperty, m => m.StringProperty2); + var serialized = JsonConvert.SerializeObject(patchDoc); + + // Act + var deserialized = + JsonConvert.DeserializeObject>(serialized); + + // Assert + var fromPath = deserialized.Operations.First().from; + Assert.Equal("/stringproperty", fromPath); + var toPath = deserialized.Operations.First().path; + Assert.Equal("/stringproperty2", toPath); + } + + [Fact] + public void Add_WithExpression_AndCustomContractResolver_UsesPropertyName_SetByContractResolver() + { + // Arrange + var patchDoc = new JsonPatchDocument(); + patchDoc.ContractResolver = new CustomContractResolver(); + patchDoc.Add(m => m.SSN, "123-45-6789"); + var serialized = JsonConvert.SerializeObject(patchDoc); + + // Act + var deserialized = + JsonConvert.DeserializeObject>(serialized); + + // Assert + var path = deserialized.Operations.First().path; + Assert.Equal("/socialsecuritynumber", path); + } + + 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; } + } + + private class CustomContractResolver : DefaultContractResolver + { + protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) + { + var jsonProperty = base.CreateProperty(member, memberSerialization); + + if (jsonProperty.PropertyName == "SSN") + { + jsonProperty.PropertyName = "SocialSecurityNumber"; + } + + return jsonProperty; + } + } } } From 0795ec1d9afdbac6c85990f7beb414bf7241fb3e Mon Sep 17 00:00:00 2001 From: Jass Bagga Date: Thu, 26 Jan 2017 11:28:35 -0800 Subject: [PATCH 168/471] Add tests for Replace operation with null checks for property (#56) See #32 --- .../NestedObjectTests.cs | 23 ++++++++++++++ .../ObjectAdapterTests.cs | 20 +++++++++++++ .../SimpleDTOWithNestedDTOWithNullCheck.cs | 15 ++++++++++ .../SimpleDTOWithNullCheck.cs | 30 +++++++++++++++++++ 4 files changed, 88 insertions(+) create mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTOWithNestedDTOWithNullCheck.cs create mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTOWithNullCheck.cs diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/NestedObjectTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/NestedObjectTests.cs index 345ffe2201..cc2e990997 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/NestedObjectTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/NestedObjectTests.cs @@ -907,6 +907,29 @@ namespace Microsoft.AspNetCore.JsonPatch Assert.Equal(12, doc.SimpleDTO.DecimalValue); } + [Fact] + public void Replace_DTOWithNullCheck() + { + // Arrange + var doc = new SimpleDTOWithNestedDTOWithNullCheck() + { + SimpleDTOWithNullCheck = new SimpleDTOWithNullCheck() + { + StringProperty = "A" + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.SimpleDTOWithNullCheck.StringProperty, "B"); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal("B", doc.SimpleDTOWithNullCheck.StringProperty); + } + [Fact] public void ReplaceWithSerialization() { diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs index 5898311044..d14daadbff 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs @@ -648,6 +648,26 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters Assert.Equal(12, doc.DecimalValue); } + [Fact] + public void Replace_DTOWithNullCheck() + { + // Arrange + var doc = new SimpleDTOWithNullCheck() + { + StringProperty = "A", + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.StringProperty, "B"); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal("B", doc.StringProperty); + } + [Fact] public void ReplaceWithSerialization() { diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTOWithNestedDTOWithNullCheck.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTOWithNestedDTOWithNullCheck.cs new file mode 100644 index 0000000000..308f23b470 --- /dev/null +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTOWithNestedDTOWithNullCheck.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 SimpleDTOWithNestedDTOWithNullCheck + { + public SimpleDTOWithNullCheck SimpleDTOWithNullCheck { get; set; } + + public SimpleDTOWithNestedDTOWithNullCheck() + { + SimpleDTOWithNullCheck = new SimpleDTOWithNullCheck(); + } + } +} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTOWithNullCheck.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTOWithNullCheck.cs new file mode 100644 index 0000000000..d2a5fe51a4 --- /dev/null +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTOWithNullCheck.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; + +namespace Microsoft.AspNetCore.JsonPatch +{ + public class SimpleDTOWithNullCheck + { + private string stringProperty; + + public string StringProperty + { + get + { + return stringProperty; + } + + set + { + if (value == null) + { + throw new ArgumentNullException(); + } + + stringProperty = value; + } + } + } +} From 7a487a880a6525ced73b2e3d658c8e20b6578afb Mon Sep 17 00:00:00 2001 From: Kiran Challa Date: Mon, 23 Jan 2017 12:00:42 -0800 Subject: [PATCH 169/471] [Fixes #48] Regression: List add must support adding items where index is same as count of elements --- .../Internal/ListAdapter.cs | 35 ++++-- .../ListAdapterTest.cs | 110 +++++++++++++++++- 2 files changed, 136 insertions(+), 9 deletions(-) diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/ListAdapter.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/ListAdapter.cs index c3da14fe5a..343712690a 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Internal/ListAdapter.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Internal/ListAdapter.cs @@ -27,7 +27,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal } PositionInfo positionInfo; - if (!TryGetPositionInfo(list, segment, out positionInfo, out errorMessage)) + if (!TryGetPositionInfo(list, segment, OperationType.Add, out positionInfo, out errorMessage)) { return false; } @@ -68,7 +68,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal } PositionInfo positionInfo; - if (!TryGetPositionInfo(list, segment, out positionInfo, out errorMessage)) + if (!TryGetPositionInfo(list, segment, OperationType.Get, out positionInfo, out errorMessage)) { value = null; return false; @@ -102,7 +102,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal } PositionInfo positionInfo; - if (!TryGetPositionInfo(list, segment, out positionInfo, out errorMessage)) + if (!TryGetPositionInfo(list, segment, OperationType.Remove, out positionInfo, out errorMessage)) { return false; } @@ -136,7 +136,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal } PositionInfo positionInfo; - if (!TryGetPositionInfo(list, segment, out positionInfo, out errorMessage)) + if (!TryGetPositionInfo(list, segment, OperationType.Replace, out positionInfo, out errorMessage)) { return false; } @@ -243,7 +243,12 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal } } - private bool TryGetPositionInfo(IList list, string segment, out PositionInfo positionInfo, out string errorMessage) + private bool TryGetPositionInfo( + IList list, + string segment, + OperationType operationType, + out PositionInfo positionInfo, + out string errorMessage) { if (segment == "-") { @@ -261,16 +266,24 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal 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 = default(PositionInfo); + positionInfo = new PositionInfo(PositionType.OutOfBounds, position); errorMessage = Resources.FormatIndexOutOfBounds(segment); return false; } } else { - positionInfo = default(PositionInfo); + positionInfo = new PositionInfo(PositionType.Invalid, -1); errorMessage = Resources.FormatInvalidIndexValue(segment); return false; } @@ -295,5 +308,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal Invalid, // Ex: not an integer OutOfBounds } + + private enum OperationType + { + Add, + Remove, + Get, + Replace + } } } diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/ListAdapterTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/ListAdapterTest.cs index ee331a2b30..799f6e9e89 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/ListAdapterTest.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/ListAdapterTest.cs @@ -55,12 +55,31 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal message); } + [Fact] + public void Add_WithIndexSameAsNumberOfElements_Works() + { + // Arrange + var resolver = new Mock(MockBehavior.Strict); + var targetObject = new List() { "James", "Mike" }; + var listAdapter = new ListAdapter(); + string message = null; + var position = targetObject.Count.ToString(); + + // Act + var addStatus = listAdapter.TryAdd(targetObject, position, resolver.Object, "Rob", out 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("2")] [InlineData("3")] - public void Patch_WithOutOfBoundsIndex_Fails(string position) + public void Add_WithOutOfBoundsIndex_Fails(string position) { // Arrange var resolver = new Mock(MockBehavior.Strict); @@ -225,6 +244,93 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal 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(); + string message = null; + object value = null; + + // Act + var getStatus = listAdapter.TryGet(targetObject, position, resolver.Object, out value, out message); + + // Assert + Assert.False(getStatus); + Assert.Equal( + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", position), + 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(); + string message = null; + object value = null; + + // Act + var getStatus = listAdapter.TryGet(targetObject, position, resolver.Object, out value, out 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(); + string message = null; + + // Act + var removeStatus = listAdapter.TryRemove(targetObject, position, resolver.Object, out message); + + // Assert + Assert.False(removeStatus); + Assert.Equal( + string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", position), + 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(); + string message = null; + + // Act + var removeStatus = listAdapter.TryRemove(targetObject, position, resolver.Object, out message); + + // Assert + Assert.True(removeStatus); + Assert.Equal(new List(expected), targetObject); + } + [Fact] public void Replace_NonCompatibleType_Fails() { From 48ab68bd2a47d87b1660bdf264898e4bc32aed24 Mon Sep 17 00:00:00 2001 From: Jass Bagga Date: Mon, 30 Jan 2017 15:58:19 -0800 Subject: [PATCH 170/471] Upgrade to msbuild Addresses #57 --- JsonPatch.sln | 20 ++- NuGet.config | 1 + appveyor.yml | 4 +- build.ps1 | 2 +- build.sh | 2 +- build/Key.snk | Bin 0 -> 596 bytes build/common.props | 25 ++++ global.json | 10 -- .../Microsoft.AspNetCore.JsonPatch.csproj | 22 +++ .../Microsoft.AspNetCore.JsonPatch.xproj | 17 --- .../Properties/AssemblyInfo.cs | 11 -- .../project.json | 40 ------ ...Microsoft.AspNetCore.JsonPatch.Test.csproj | 25 ++++ .../Microsoft.AspNetCore.JsonPatch.Test.xproj | 20 --- .../ObjectVisitorTest.cs~RF1ad82e13.TMP | 119 ---------------- .../ObjectVisitorTest.cs~RF1ae034c3.TMP | 131 ------------------ .../project.json | 31 ----- version.props | 7 + 18 files changed, 101 insertions(+), 386 deletions(-) create mode 100644 build/Key.snk create mode 100644 build/common.props delete mode 100644 global.json create mode 100644 src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj delete mode 100644 src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.xproj delete mode 100644 src/Microsoft.AspNetCore.JsonPatch/Properties/AssemblyInfo.cs delete mode 100644 src/Microsoft.AspNetCore.JsonPatch/project.json create mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj delete mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.xproj delete mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/ObjectVisitorTest.cs~RF1ad82e13.TMP delete mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/ObjectVisitorTest.cs~RF1ae034c3.TMP delete mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/project.json create mode 100644 version.props diff --git a/JsonPatch.sln b/JsonPatch.sln index 7149fc4551..ae03b680d3 100644 --- a/JsonPatch.sln +++ b/JsonPatch.sln @@ -1,15 +1,27 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.23107.0 +# Visual Studio 15 +VisualStudioVersion = 15.0.26123.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{430B59ED-F960-4D3A-8FFE-3370008E168D}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{36CD6341-AB44-44EB-B3AA-BF98C89FECDD}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.JsonPatch", "src\Microsoft.AspNetCore.JsonPatch\Microsoft.AspNetCore.JsonPatch.xproj", "{4D55F4D8-633B-462F-A5B1-FEB84BD2D534}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.JsonPatch", "src\Microsoft.AspNetCore.JsonPatch\Microsoft.AspNetCore.JsonPatch.csproj", "{4D55F4D8-633B-462F-A5B1-FEB84BD2D534}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.JsonPatch.Test", "test\Microsoft.AspNetCore.JsonPatch.Test\Microsoft.AspNetCore.JsonPatch.Test.xproj", "{81C20848-E063-4E12-AC40-0B55A532C16C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.JsonPatch.Test", "test\Microsoft.AspNetCore.JsonPatch.Test\Microsoft.AspNetCore.JsonPatch.Test.csproj", "{81C20848-E063-4E12-AC40-0B55A532C16C}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C430C499-382D-47BD-B351-CF8F89C08CD2}" + ProjectSection(SolutionItems) = preProject + NuGet.config = NuGet.config + EndProjectSection +EndProject + +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{6DC6B416-C8C4-4BFA-8C1E-A55A6D7EFD08}" + ProjectSection(SolutionItems) = preProject + build\common.props = build\common.props + build\Key.snk = build\Key.snk + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/NuGet.config b/NuGet.config index 0fd623ffdd..93f1ac47df 100644 --- a/NuGet.config +++ b/NuGet.config @@ -2,6 +2,7 @@ + diff --git a/appveyor.yml b/appveyor.yml index be95b88d6f..06545db9f6 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -10,4 +10,6 @@ build_script: - build.cmd --quiet verify clone_depth: 1 test: off -deploy: off \ No newline at end of file +deploy: off +# Required for dotnet-test to work +os: Visual Studio 2015 \ No newline at end of file diff --git a/build.ps1 b/build.ps1 index 8f2f99691a..0605b59c01 100644 --- a/build.ps1 +++ b/build.ps1 @@ -33,7 +33,7 @@ cd $PSScriptRoot $repoFolder = $PSScriptRoot $env:REPO_FOLDER = $repoFolder -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/feature/msbuild.zip" if ($env:KOREBUILD_ZIP) { $koreBuildZip=$env:KOREBUILD_ZIP diff --git a/build.sh b/build.sh index 4fd7ede788..07997d6c83 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/feature/msbuild.zip" if [ ! -z $KOREBUILD_ZIP ]; then koreBuildZip=$KOREBUILD_ZIP fi diff --git a/build/Key.snk b/build/Key.snk new file mode 100644 index 0000000000000000000000000000000000000000..e10e4889c125d3120cd9e81582243d70f7cbb806 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098=Iw=HCsnz~#iVhm& zj%TU(_THUee?3yHBjk$37ysB?i5#7WD$={H zV4B!OxRPrb|8)HPg~A}8P>^=#y<)56#=E&NzcjOtPK~<4n6GHt=K$ro*T(lhby_@U zEk(hLzk1H)0yXj{A_5>fk-TgNoP|q6(tP2xo8zt8i%212CWM#AeCd?`hS|4~L({h~Moo(~vy&3Z z1uI}`fd^*>o=rwbAGymj6RM^pZm(*Kfhs+Y1#`-2JPWZMK8@;ZWCk2+9bX4YP);~fj-BU*R zQPvWv$89!{Rl9wM+zR>_TSkn^voYxA?2G iKnV#iZ6Ah`K>b=@=IjYJXrxL124zR(38)nxe+&q_$QXwJ literal 0 HcmV?d00001 diff --git a/build/common.props b/build/common.props new file mode 100644 index 0000000000..813c202b7f --- /dev/null +++ b/build/common.props @@ -0,0 +1,25 @@ + + + + + + Microsoft ASP.NET Core + https://github.com/aspnet/JsonPatch + git + $(MSBuildThisFileDirectory)Key.snk + true + true + 1.2.0-* + 1.6.2-* + $(VersionSuffix)-$(BuildNumber) + + + + + + + + + + + \ No newline at end of file diff --git a/global.json b/global.json deleted file mode 100644 index a5c02fe221..0000000000 --- a/global.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "projects": [ - "src", - "test/WebSites", - "samples" - ], - "sdk": { - "version": "1.0.0-preview2-1-003180" - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj b/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj new file mode 100644 index 0000000000..5bf2f0f74e --- /dev/null +++ b/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj @@ -0,0 +1,22 @@ + + + + + ASP.NET Core support for JSON PATCH. + net451;netstandard1.3 + $(NoWarn);CS1591 + true + aspnetcore;json;jsonpatch + + + + + + + + + + + + + diff --git a/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.xproj b/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.xproj deleted file mode 100644 index 0ebf789691..0000000000 --- a/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.xproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 4d55f4d8-633b-462f-a5b1-feb84bd2d534 - .\obj - .\bin\ - - - 2.0 - - - \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.JsonPatch/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.JsonPatch/Properties/AssemblyInfo.cs deleted file mode 100644 index 76feceeff0..0000000000 --- a/src/Microsoft.AspNetCore.JsonPatch/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Reflection; -using System.Resources; - -[assembly: AssemblyMetadata("Serviceable", "True")] -[assembly: NeutralResourcesLanguage("en-us")] -[assembly: AssemblyCompany("Microsoft Corporation.")] -[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] -[assembly: AssemblyProduct("Microsoft ASP.NET Core")] diff --git a/src/Microsoft.AspNetCore.JsonPatch/project.json b/src/Microsoft.AspNetCore.JsonPatch/project.json deleted file mode 100644 index 7214cde411..0000000000 --- a/src/Microsoft.AspNetCore.JsonPatch/project.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "version": "1.2.0-*", - "description": "ASP.NET Core support for JSON PATCH.", - "buildOptions": { - "warningsAsErrors": true, - "keyFile": "../../tools/Key.snk", - "nowarn": [ - "CS1591" - ], - "xmlDoc": true - }, - "packOptions": { - "repository": { - "type": "git", - "url": "git://github.com/aspnet/jsonpatch" - }, - "tags": [ - "aspnetcore", - "json", - "jsonpatch" - ] - }, - "dependencies": { - "NETStandard.Library": "1.6.2-*", - "Newtonsoft.Json": "9.0.1", - "Microsoft.Extensions.ClosedGenericMatcher.Sources": { - "type": "build", - "version": "1.2.0-*" - } - }, - "frameworks": { - "net451": {}, - "netstandard1.3": { - "dependencies": { - "Microsoft.CSharp": "4.4.0-*", - "System.Reflection.TypeExtensions": "4.4.0-*" - } - } - } -} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj new file mode 100644 index 0000000000..6715989b4e --- /dev/null +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj @@ -0,0 +1,25 @@ + + + + netcoreapp1.1;net451 + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.xproj b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.xproj deleted file mode 100644 index c8942c121e..0000000000 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.xproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 81c20848-e063-4e12-ac40-0b55a532c16c - .\obj - .\bin\ - - - 2.0 - - - - - - \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectVisitorTest.cs~RF1ad82e13.TMP b/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectVisitorTest.cs~RF1ad82e13.TMP deleted file mode 100644 index 694c33c633..0000000000 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectVisitorTest.cs~RF1ad82e13.TMP +++ /dev/null @@ -1,119 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json.Serialization; -using Xunit; - -namespace Microsoft.AspNetCore.JsonPatch.Internal -{ - public class ObjectVisitorTest - { - private class Class1 - { - public IList States { get; set; } = new List(); - public IDictionary Countries = new Dictionary(); - } - - [Fact] - public void Visit_ValidPathToArray_ReturnsListAdapter() - { - // Arrange - var visitor = new ObjectVisitor(new ParsedPath("/States/-"), new DefaultContractResolver()); - var model = new Class1(); - object targetObject = model; - IAdapter adapter = null; - string message = null; - - // Act - var visitStatus = visitor.TryVisit(ref targetObject, out adapter, out message); - - // Assert - Assert.True(visitStatus); - Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); - Assert.Same(model.States, targetObject); - Assert.IsType(adapter); - } - - [Fact] - public void Visit_ValidPathToDictionary_ReturnsDictionaryAdapter() - { - // Arrange - var visitor = new ObjectVisitor(new ParsedPath("/Countries/USA"), new DefaultContractResolver()); - var model = new Class1(); - object targetObject = model; - IAdapter adapter = null; - string message = null; - - // Act - var visitStatus = visitor.TryVisit(ref targetObject, out adapter, out message); - - // Assert - Assert.True(visitStatus); - Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); - Assert.Same(model.Countries, targetObject); - Assert.IsType(adapter); - } - - private class AutomobileDepartment - { - public List Customers { get; set; } = new List(); - } - - [Fact] - public void Visit_ValidPathToArray_ReturnsListAdapter_ForDeepNestedPath() - { - // Arrange - var visitor = new ObjectVisitor(new ParsedPath("/Customers/0/States/-"), new DefaultContractResolver()); - var customer = new Class1(); - var automobileDepartment = new AutomobileDepartment(); - automobileDepartment.Customers.Add(customer); - object targetObject = automobileDepartment; - IAdapter adapter = null; - string message = null; - - // Act - var visitStatus = visitor.TryVisit(ref targetObject, out adapter, out message); - - // Assert - Assert.True(visitStatus); - Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); - Assert.Same(customer.States, targetObject); - Assert.IsType(adapter); - } - - [Fact] - public void Visit_InvalidPathToArray_Fails() - { - // Arrange - var invalidIndex = 2; - var visitor = new ObjectVisitor(new ParsedPath($"/Customers/{invalidIndex}/States/-"), new DefaultContractResolver()); - var automobileDepartment = new AutomobileDepartment(); - object targetObject = automobileDepartment; - IAdapter adapter = null; - string message = null; - - // Act - var visitStatus = visitor.TryVisit(ref targetObject, out adapter, out message); - - // Assert - Assert.False(visitStatus); - Assert.Equal(string.Format(ErrorMessageFormats.IndexOutOfBounds, invalidIndex), message); - } - - [Fact] - public void Visit_DoesNotValidate_FinalPathSegment() - { - // Arrange - var visitor = new ObjectVisitor(new ParsedPath($"/NonExisting"), new DefaultContractResolver()); - var model = new Class1(); - object targetObject = model; - IAdapter adapter = null; - string message = null; - - // Act - var visitStatus = visitor.TryVisit(ref targetObject, out adapter, out message); - - // Assert - Assert.False(visitStatus); - Assert.Equal(string.Format(ErrorMessageFormats.TargetLocationAtPathSegmentNotFound, "NonExisting"), message); - } - } -} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectVisitorTest.cs~RF1ae034c3.TMP b/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectVisitorTest.cs~RF1ae034c3.TMP deleted file mode 100644 index 88139198ac..0000000000 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectVisitorTest.cs~RF1ae034c3.TMP +++ /dev/null @@ -1,131 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json.Serialization; -using Xunit; - -namespace Microsoft.AspNetCore.JsonPatch.Internal -{ - public class ObjectVisitorTest - { - private class Class1 - { - public IList States { get; set; } = new List(); - public IDictionary Countries = new Dictionary(); - } - - 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 }; - } - } - - [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()); - IAdapter adapter = null; - string message = null; - - // Act - var visitStatus = visitor.TryVisit(ref targetObject, out adapter, out message); - - // Assert - Assert.True(visitStatus); - Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); - Assert.Same(expectedTargetObject, targetObject); - Assert.IsType(adapter); - } - - [Fact] - public void Visit_ValidPathToDictionary_ReturnsDictionaryAdapter() - { - // Arrange - var visitor = new ObjectVisitor(new ParsedPath("/Countries/USA"), new DefaultContractResolver()); - var model = new Class1(); - object targetObject = model; - IAdapter adapter = null; - string message = null; - - // Act - var visitStatus = visitor.TryVisit(ref targetObject, out adapter, out message); - - // Assert - Assert.True(visitStatus); - Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); - Assert.Same(model.Countries, targetObject); - Assert.IsType(adapter); - } - - private class AutomobileDepartment - { - public List Customers { get; set; } = new List(); - } - - [Fact] - public void Visit_ValidPathToArray_ReturnsListAdapter_ForDeepNestedPath() - { - // Arrange - var visitor = new ObjectVisitor(new ParsedPath("/Customers/0/States/-"), new DefaultContractResolver()); - var customer = new Class1(); - var automobileDepartment = new AutomobileDepartment(); - automobileDepartment.Customers.Add(customer); - object targetObject = automobileDepartment; - IAdapter adapter = null; - string message = null; - - // Act - var visitStatus = visitor.TryVisit(ref targetObject, out adapter, out message); - - // Assert - Assert.True(visitStatus); - Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); - Assert.Same(customer.States, targetObject); - Assert.IsType(adapter); - } - - [Fact] - public void Visit_InvalidPathToArray_Fails() - { - // Arrange - var invalidIndex = 2; - var visitor = new ObjectVisitor(new ParsedPath($"/Customers/{invalidIndex}/States/-"), new DefaultContractResolver()); - var automobileDepartment = new AutomobileDepartment(); - object targetObject = automobileDepartment; - IAdapter adapter = null; - string message = null; - - // Act - var visitStatus = visitor.TryVisit(ref targetObject, out adapter, out message); - - // Assert - Assert.False(visitStatus); - Assert.Equal(string.Format(ErrorMessageFormats.IndexOutOfBounds, invalidIndex), message); - } - - // The adapter takes care of the responsibility of validating the final segment - [Fact] - public void Visit_DoesNotValidate_FinalPathSegment() - { - // Arrange - var visitor = new ObjectVisitor(new ParsedPath($"/NonExisting"), new DefaultContractResolver()); - var model = new Class1(); - object targetObject = model; - IAdapter adapter = null; - string message = null; - - // Act - var visitStatus = visitor.TryVisit(ref targetObject, out adapter, out message); - - // Assert - Assert.True(visitStatus); - Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); - Assert.IsType(adapter); - } - } -} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json b/test/Microsoft.AspNetCore.JsonPatch.Test/project.json deleted file mode 100644 index 4790217eba..0000000000 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/project.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "buildOptions": { - "warningsAsErrors": true - }, - "dependencies": { - "dotnet-test-xunit": "2.2.0-*", - "Microsoft.AspNetCore.JsonPatch": "1.2.0-*", - "Microsoft.AspNetCore.Testing": "1.2.0-*", - "Moq": "4.6.36-*", - "xunit": "2.2.0-*" - }, - "testRunner": "xunit", - "frameworks": { - "netcoreapp1.1": { - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.2.0-*", - "type": "platform" - }, - "System.Diagnostics.TraceSource": "4.4.0-*" - } - }, - "net451": { - "frameworkAssemblies": { - "System.Linq.Expressions": { - "type": "build" - } - } - } - } -} \ No newline at end of file diff --git a/version.props b/version.props new file mode 100644 index 0000000000..e77c8d9c38 --- /dev/null +++ b/version.props @@ -0,0 +1,7 @@ + + + + 1.2.0 + preview1 + + \ No newline at end of file From 81acef9238622249c95229ce2d6205a48b85d514 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 1 Feb 2017 13:24:34 -0800 Subject: [PATCH 171/471] Upgrade to VS 2017 --- HtmlAbstractions.sln | 13 ++++---- NuGet.config | 5 +-- appveyor.yml | 3 +- build.ps1 | 2 +- build.sh | 2 +- {tools => build}/Key.snk | Bin build/common.props | 19 +++++++++++ global.json | 8 ----- ...rosoft.AspNetCore.Html.Abstractions.csproj | 21 ++++++++++++ ...crosoft.AspNetCore.Html.Abstractions.xproj | 17 ---------- .../Properties/AssemblyInfo.cs | 5 --- .../project.json | 28 ---------------- .../Microsoft.Extensions.WebEncoders.csproj | 21 ++++++++++++ .../Microsoft.Extensions.WebEncoders.xproj | 17 ---------- .../Properties/AssemblyInfo.cs | 11 ------- .../project.json | 31 ------------------ ...t.AspNetCore.Html.Abstractions.Test.csproj | 18 ++++++++++ ...ft.AspNetCore.Html.Abstractions.Test.xproj | 20 ----------- .../project.json | 25 -------------- ...rosoft.Extensions.WebEncoders.Tests.csproj | 18 ++++++++++ ...crosoft.Extensions.WebEncoders.Tests.xproj | 20 ----------- .../project.json | 28 ---------------- version.props | 7 ++++ 23 files changed, 117 insertions(+), 222 deletions(-) rename {tools => build}/Key.snk (100%) create mode 100644 build/common.props delete mode 100644 global.json create mode 100755 src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.csproj delete mode 100644 src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.xproj delete mode 100644 src/Microsoft.AspNetCore.Html.Abstractions/project.json create mode 100755 src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.csproj delete mode 100644 src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.xproj delete mode 100644 src/Microsoft.Extensions.WebEncoders/Properties/AssemblyInfo.cs delete mode 100644 src/Microsoft.Extensions.WebEncoders/project.json create mode 100755 test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.csproj delete mode 100644 test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.xproj delete mode 100644 test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json create mode 100755 test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj delete mode 100644 test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.xproj delete mode 100644 test/Microsoft.Extensions.WebEncoders.Tests/project.json create mode 100644 version.props diff --git a/HtmlAbstractions.sln b/HtmlAbstractions.sln index 81189bb447..5b6b09416f 100644 --- a/HtmlAbstractions.sln +++ b/HtmlAbstractions.sln @@ -1,24 +1,23 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.24711.0 +# Visual Studio 15 +VisualStudioVersion = 15.0.26127.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A5A15F1C-885A-452A-A731-B0173DDBD913}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{F31FF137-390C-49BF-A3BD-7C6ED3597C21}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Html.Abstractions", "src\Microsoft.AspNetCore.Html.Abstractions\Microsoft.AspNetCore.Html.Abstractions.xproj", "{68A28E4A-3ADE-4187-9625-4FF185887CB3}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.Html.Abstractions", "src\Microsoft.AspNetCore.Html.Abstractions\Microsoft.AspNetCore.Html.Abstractions.csproj", "{68A28E4A-3ADE-4187-9625-4FF185887CB3}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Html.Abstractions.Test", "test\Microsoft.AspNetCore.Html.Abstractions.Test\Microsoft.AspNetCore.Html.Abstractions.Test.xproj", "{2D187B88-94BD-4A39-AC97-F8F8B9363301}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.Html.Abstractions.Test", "test\Microsoft.AspNetCore.Html.Abstractions.Test\Microsoft.AspNetCore.Html.Abstractions.Test.csproj", "{2D187B88-94BD-4A39-AC97-F8F8B9363301}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B4962A29-BE69-4A18-9B4F-B803EEE31EAA}" ProjectSection(SolutionItems) = preProject - global.json = global.json NuGetPackageVerifier.json = NuGetPackageVerifier.json EndProjectSection EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Extensions.WebEncoders", "src\Microsoft.Extensions.WebEncoders\Microsoft.Extensions.WebEncoders.xproj", "{DD2CE416-765E-4000-A03E-C2FF165DA1B6}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Extensions.WebEncoders", "src\Microsoft.Extensions.WebEncoders\Microsoft.Extensions.WebEncoders.csproj", "{DD2CE416-765E-4000-A03E-C2FF165DA1B6}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Extensions.WebEncoders.Tests", "test\Microsoft.Extensions.WebEncoders.Tests\Microsoft.Extensions.WebEncoders.Tests.xproj", "{7AE2731D-43CD-4CF8-850A-4914DE2CE930}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Extensions.WebEncoders.Tests", "test\Microsoft.Extensions.WebEncoders.Tests\Microsoft.Extensions.WebEncoders.Tests.csproj", "{7AE2731D-43CD-4CF8-850A-4914DE2CE930}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/NuGet.config b/NuGet.config index 826a1f9035..8e65695611 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,8 @@ - + + - \ No newline at end of file + diff --git a/appveyor.yml b/appveyor.yml index be95b88d6f..13c0650228 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -10,4 +10,5 @@ build_script: - build.cmd --quiet verify clone_depth: 1 test: off -deploy: off \ No newline at end of file +deploy: off +os: Visual Studio 2017 RC diff --git a/build.ps1 b/build.ps1 index 8f2f99691a..0605b59c01 100644 --- a/build.ps1 +++ b/build.ps1 @@ -33,7 +33,7 @@ cd $PSScriptRoot $repoFolder = $PSScriptRoot $env:REPO_FOLDER = $repoFolder -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/feature/msbuild.zip" if ($env:KOREBUILD_ZIP) { $koreBuildZip=$env:KOREBUILD_ZIP diff --git a/build.sh b/build.sh index 4fd7ede788..07997d6c83 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/feature/msbuild.zip" if [ ! -z $KOREBUILD_ZIP ]; then koreBuildZip=$KOREBUILD_ZIP fi diff --git a/tools/Key.snk b/build/Key.snk similarity index 100% rename from tools/Key.snk rename to build/Key.snk diff --git a/build/common.props b/build/common.props new file mode 100644 index 0000000000..c39a1694c3 --- /dev/null +++ b/build/common.props @@ -0,0 +1,19 @@ + + + + + https://github.com/aspnet/HtmlAbstractions + git + $(MSBuildThisFileDirectory)Key.snk + true + true + 1.2.0-* + 1.6.2-* + $(VersionSuffix)-$(BuildNumber) + + + + + + + diff --git a/global.json b/global.json deleted file mode 100644 index 0ad1995dd2..0000000000 --- a/global.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "projects": [ - "src" - ], - "sdk": { - "version": "1.0.0-preview2-1-003180" - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.csproj b/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.csproj new file mode 100755 index 0000000000..3baa9641ae --- /dev/null +++ b/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.csproj @@ -0,0 +1,21 @@ + + + + + + Microsoft ASP.NET Core + ASP.NET Core HTML abstractions used for building HTML content. +Commonly used types: +Microsoft.AspNetCore.Html.HtmlString +Microsoft.AspNetCore.Html.IHtmlContent + netstandard1.0 + $(NoWarn);CS1591 + true + aspnetcore + + + + + + + diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.xproj b/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.xproj deleted file mode 100644 index 25d87d97bb..0000000000 --- a/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.xproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 68a28e4a-3ade-4187-9625-4ff185887cb3 - .\obj - .\bin\ - - - 2.0 - - - \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.Html.Abstractions/Properties/AssemblyInfo.cs index 403f0e3c52..bde0132dbb 100644 --- a/src/Microsoft.AspNetCore.Html.Abstractions/Properties/AssemblyInfo.cs +++ b/src/Microsoft.AspNetCore.Html.Abstractions/Properties/AssemblyInfo.cs @@ -5,9 +5,4 @@ using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; -[assembly: AssemblyMetadata("Serviceable", "True")] -[assembly: NeutralResourcesLanguage("en-us")] [assembly: InternalsVisibleTo("Microsoft.AspNetCore.Html.Abstractions.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] -[assembly: AssemblyCompany("Microsoft Corporation.")] -[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] -[assembly: AssemblyProduct("Microsoft ASP.NET Core")] diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/project.json b/src/Microsoft.AspNetCore.Html.Abstractions/project.json deleted file mode 100644 index 4e640d584b..0000000000 --- a/src/Microsoft.AspNetCore.Html.Abstractions/project.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "version": "1.2.0-*", - "description": "ASP.NET Core HTML abstractions used for building HTML content.\r\nCommonly used types:\r\nMicrosoft.AspNetCore.Html.HtmlString\r\nMicrosoft.AspNetCore.Html.IHtmlContent", - "packOptions": { - "repository": { - "type": "git", - "url": "git://github.com/aspnet/htmlabstractions" - }, - "tags": [ - "aspnetcore" - ] - }, - "buildOptions": { - "warningsAsErrors": true, - "keyFile": "../../tools/Key.snk", - "nowarn": [ - "CS1591" - ], - "xmlDoc": true - }, - "dependencies": { - "NETStandard.Library": "1.6.2-*", - "System.Text.Encodings.Web": "4.4.0-*" - }, - "frameworks": { - "netstandard1.0": {} - } -} \ No newline at end of file diff --git a/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.csproj b/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.csproj new file mode 100755 index 0000000000..231359c110 --- /dev/null +++ b/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.csproj @@ -0,0 +1,21 @@ + + + + + + Microsoft .NET Extensions + Contains registration and configuration APIs to add the core framework encoders to a dependency injection container. + netstandard1.0 + $(NoWarn);CS1591 + true + true + aspnetcore + + + + + + + + + diff --git a/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.xproj b/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.xproj deleted file mode 100644 index f458d42cf1..0000000000 --- a/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.xproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - dd2ce416-765e-4000-a03e-c2ff165da1b6 - .\obj - .\bin\ - - - 2.0 - - - \ No newline at end of file diff --git a/src/Microsoft.Extensions.WebEncoders/Properties/AssemblyInfo.cs b/src/Microsoft.Extensions.WebEncoders/Properties/AssemblyInfo.cs deleted file mode 100644 index 8d8d88195c..0000000000 --- a/src/Microsoft.Extensions.WebEncoders/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Reflection; -using System.Resources; - -[assembly: AssemblyMetadata("Serviceable", "True")] -[assembly: NeutralResourcesLanguage("en-us")] -[assembly: AssemblyCompany("Microsoft Corporation.")] -[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] -[assembly: AssemblyProduct("Microsoft .NET Extensions")] diff --git a/src/Microsoft.Extensions.WebEncoders/project.json b/src/Microsoft.Extensions.WebEncoders/project.json deleted file mode 100644 index b3fe422893..0000000000 --- a/src/Microsoft.Extensions.WebEncoders/project.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "version": "1.2.0-*", - "description": "Contains registration and configuration APIs to add the core framework encoders to a dependency injection container.", - "packOptions": { - "repository": { - "type": "git", - "url": "git://github.com/aspnet/httpabstractions" - }, - "tags": [ - "aspnetcore" - ] - }, - "buildOptions": { - "warningsAsErrors": true, - "allowUnsafe": true, - "keyFile": "../../tools/Key.snk", - "nowarn": [ - "CS1591" - ], - "xmlDoc": true - }, - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "1.2.0-*", - "Microsoft.Extensions.Options": "1.2.0-*", - "NETStandard.Library": "1.6.2-*", - "System.Text.Encodings.Web": "4.4.0-*" - }, - "frameworks": { - "netstandard1.0": {} - } -} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.csproj b/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.csproj new file mode 100755 index 0000000000..160e0ab478 --- /dev/null +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.csproj @@ -0,0 +1,18 @@ + + + + + + netcoreapp1.1;net451 + + + + + + + + + + + + diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.xproj b/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.xproj deleted file mode 100644 index 3d3d10b2ac..0000000000 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.xproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 2d187b88-94bd-4a39-ac97-f8f8b9363301 - .\obj - .\bin\ - - - 2.0 - - - - - - \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json b/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json deleted file mode 100644 index 0e46d9c52c..0000000000 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/project.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "buildOptions": { - "warningsAsErrors": true, - "keyFile": "../../tools/Key.snk" - }, - "dependencies": { - "dotnet-test-xunit": "2.2.0-*", - "Microsoft.AspNetCore.Html.Abstractions": "1.2.0-*", - "Microsoft.AspNetCore.Testing": "1.2.0-*", - "Microsoft.Extensions.WebEncoders": "1.2.0-*", - "xunit": "2.2.0-*" - }, - "testRunner": "xunit", - "frameworks": { - "netcoreapp1.1": { - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.2.0-*", - "type": "platform" - } - } - }, - "net451": {} - } -} \ No newline at end of file diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj b/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj new file mode 100755 index 0000000000..9ad4edbc0b --- /dev/null +++ b/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj @@ -0,0 +1,18 @@ + + + + + + netcoreapp1.1;net451 + $(PackageTargetFallback);dnxcore50;portable-net451+win8 + + + + + + + + + + + diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.xproj b/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.xproj deleted file mode 100644 index a7810a9e17..0000000000 --- a/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.xproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 7ae2731d-43cd-4cf8-850a-4914de2ce930 - .\obj - .\bin\ - - - 2.0 - - - - - - \ No newline at end of file diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/project.json b/test/Microsoft.Extensions.WebEncoders.Tests/project.json deleted file mode 100644 index d06fb5b18b..0000000000 --- a/test/Microsoft.Extensions.WebEncoders.Tests/project.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "dependencies": { - "dotnet-test-xunit": "2.2.0-*", - "Microsoft.Extensions.DependencyInjection": "1.2.0-*", - "Microsoft.Extensions.WebEncoders": "1.2.0-*", - "xunit": "2.2.0-*" - }, - "testRunner": "xunit", - "buildOptions": { - "warningsAsErrors": true, - "keyFile": "../../tools/Key.snk" - }, - "frameworks": { - "netcoreapp1.1": { - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.2.0-*", - "type": "platform" - } - }, - "imports": [ - "dnxcore50", - "portable-net451+win8" - ] - }, - "net451": {} - } -} \ No newline at end of file diff --git a/version.props b/version.props new file mode 100644 index 0000000000..17fd5ac36d --- /dev/null +++ b/version.props @@ -0,0 +1,7 @@ + + + + 1.2.0 + preview1 + + From 50abb557fc31b6803897cc4b9a8ce03e2e6efbec Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Mon, 13 Feb 2017 11:13:17 -0800 Subject: [PATCH 172/471] Bump test projects up to .NET 4.5.2 - aspnet/Testing#248 - xUnit no longer supports .NET 4.5.1 - build tests for desktop .NET only on Windows --- .../Microsoft.AspNetCore.JsonPatch.Test.csproj | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj index 6715989b4e..0825a33ba9 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj @@ -1,7 +1,8 @@  - netcoreapp1.1;net451 + netcoreapp1.1;net452 + netcoreapp1.1 @@ -14,7 +15,7 @@ - + From 859aad081e3ce334b7b604bf2175beb1b6a91496 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Tue, 14 Feb 2017 08:31:52 -0800 Subject: [PATCH 173/471] Bump test projects up to .NET 4.5.2 - aspnet/Testing#248 - xUnit no longer supports .NET 4.5.1 - build tests for desktop .NET only on Windows --- .../Microsoft.AspNetCore.Html.Abstractions.Test.csproj | 3 ++- .../Microsoft.Extensions.WebEncoders.Tests.csproj | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.csproj b/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.csproj index 160e0ab478..1fe9581c45 100755 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.csproj +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.csproj @@ -3,7 +3,8 @@ - netcoreapp1.1;net451 + netcoreapp1.1;net452 + netcoreapp1.1 diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj b/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj index 9ad4edbc0b..77b807e9dd 100755 --- a/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj +++ b/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj @@ -3,7 +3,8 @@ - netcoreapp1.1;net451 + netcoreapp1.1;net452 + netcoreapp1.1 $(PackageTargetFallback);dnxcore50;portable-net451+win8 From 0c714cf61b908e5e39c8d06a0109aa2305b7e9b0 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 14 Feb 2017 16:03:53 -0800 Subject: [PATCH 174/471] Downgrade to stable packages --- build/common.props | 3 +-- build/dependencies.props | 6 ++++++ .../Microsoft.AspNetCore.Html.Abstractions.csproj | 2 +- .../Microsoft.Extensions.WebEncoders.csproj | 2 +- 4 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 build/dependencies.props diff --git a/build/common.props b/build/common.props index c39a1694c3..de08271afe 100644 --- a/build/common.props +++ b/build/common.props @@ -1,4 +1,5 @@ + @@ -7,8 +8,6 @@ $(MSBuildThisFileDirectory)Key.snk true true - 1.2.0-* - 1.6.2-* $(VersionSuffix)-$(BuildNumber) diff --git a/build/dependencies.props b/build/dependencies.props new file mode 100644 index 0000000000..e704edaec0 --- /dev/null +++ b/build/dependencies.props @@ -0,0 +1,6 @@ + + + 1.6.1 + 4.3.0 + + diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.csproj b/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.csproj index 3baa9641ae..85948d6df7 100755 --- a/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.csproj +++ b/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.csproj @@ -15,7 +15,7 @@ Microsoft.AspNetCore.Html.IHtmlContent - + diff --git a/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.csproj b/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.csproj index 231359c110..70766d649f 100755 --- a/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.csproj +++ b/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.csproj @@ -15,7 +15,7 @@ - + From 8051f3671b273fd1b8118563b2022e2e2078f4f0 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 14 Feb 2017 16:03:53 -0800 Subject: [PATCH 175/471] Downgrade to stable packages --- build/common.props | 7 +++---- build/dependencies.props | 6 ++++++ .../Microsoft.AspNetCore.JsonPatch.csproj | 6 +++--- .../Microsoft.AspNetCore.JsonPatch.Test.csproj | 6 +----- 4 files changed, 13 insertions(+), 12 deletions(-) create mode 100644 build/dependencies.props diff --git a/build/common.props b/build/common.props index 813c202b7f..17a0ccb4d8 100644 --- a/build/common.props +++ b/build/common.props @@ -1,5 +1,6 @@ - + + @@ -9,8 +10,6 @@ $(MSBuildThisFileDirectory)Key.snk true true - 1.2.0-* - 1.6.2-* $(VersionSuffix)-$(BuildNumber) @@ -22,4 +21,4 @@ - \ No newline at end of file + diff --git a/build/dependencies.props b/build/dependencies.props new file mode 100644 index 0000000000..e704edaec0 --- /dev/null +++ b/build/dependencies.props @@ -0,0 +1,6 @@ + + + 1.6.1 + 4.3.0 + + diff --git a/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj b/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj index 5bf2f0f74e..d3d5b01a89 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj +++ b/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj @@ -13,10 +13,10 @@ - + - - + + diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj index 0825a33ba9..e939e5d62c 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj @@ -12,15 +12,11 @@ - - - - - \ No newline at end of file + From b312a84ff488d7acd06d8e9510961bce86ffbfee Mon Sep 17 00:00:00 2001 From: Kiran Challa Date: Fri, 24 Feb 2017 15:55:59 -0800 Subject: [PATCH 176/471] Fixed solution file --- JsonPatch.sln | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/JsonPatch.sln b/JsonPatch.sln index ae03b680d3..b75721a487 100644 --- a/JsonPatch.sln +++ b/JsonPatch.sln @@ -1,7 +1,6 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26123.0 +VisualStudioVersion = 15.0.26222.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{430B59ED-F960-4D3A-8FFE-3370008E168D}" EndProject @@ -12,16 +11,9 @@ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.JsonPatch.Test", "test\Microsoft.AspNetCore.JsonPatch.Test\Microsoft.AspNetCore.JsonPatch.Test.csproj", "{81C20848-E063-4E12-AC40-0B55A532C16C}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C430C499-382D-47BD-B351-CF8F89C08CD2}" - ProjectSection(SolutionItems) = preProject - NuGet.config = NuGet.config - EndProjectSection -EndProject - -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{6DC6B416-C8C4-4BFA-8C1E-A55A6D7EFD08}" ProjectSection(SolutionItems) = preProject - build\common.props = build\common.props - build\Key.snk = build\Key.snk - EndProjectSection + NuGet.config = NuGet.config + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution From 1f74ceca1b670c249f8118415e16afc4ba3f6ef7 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 1 Mar 2017 18:14:13 -0800 Subject: [PATCH 177/471] Change korebuild branch and fix argument forwarding in bootstrapper --- build.ps1 | 16 ++++++++-------- build.sh | 22 +++++++++++----------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/build.ps1 b/build.ps1 index 0605b59c01..5bf0e2c113 100644 --- a/build.ps1 +++ b/build.ps1 @@ -1,6 +1,6 @@ $ErrorActionPreference = "Stop" -function DownloadWithRetry([string] $url, [string] $downloadLocation, [int] $retries) +function DownloadWithRetry([string] $url, [string] $downloadLocation, [int] $retries) { while($true) { @@ -19,7 +19,7 @@ function DownloadWithRetry([string] $url, [string] $downloadLocation, [int] $ret Start-Sleep -Seconds 10 } - else + else { $exception = $_.Exception throw $exception @@ -33,7 +33,7 @@ cd $PSScriptRoot $repoFolder = $PSScriptRoot $env:REPO_FOLDER = $repoFolder -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/feature/msbuild.zip" +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" if ($env:KOREBUILD_ZIP) { $koreBuildZip=$env:KOREBUILD_ZIP @@ -43,18 +43,18 @@ $buildFolder = ".build" $buildFile="$buildFolder\KoreBuild.ps1" if (!(Test-Path $buildFolder)) { - Write-Host "Downloading KoreBuild from $koreBuildZip" - + Write-Host "Downloading KoreBuild from $koreBuildZip" + $tempFolder=$env:TEMP + "\KoreBuild-" + [guid]::NewGuid() New-Item -Path "$tempFolder" -Type directory | Out-Null $localZipFile="$tempFolder\korebuild.zip" - + DownloadWithRetry -url $koreBuildZip -downloadLocation $localZipFile -retries 6 Add-Type -AssemblyName System.IO.Compression.FileSystem [System.IO.Compression.ZipFile]::ExtractToDirectory($localZipFile, $tempFolder) - + New-Item -Path "$buildFolder" -Type directory | Out-Null copy-item "$tempFolder\**\build\*" $buildFolder -Recurse @@ -64,4 +64,4 @@ if (!(Test-Path $buildFolder)) { } } -&"$buildFile" $args \ No newline at end of file +&"$buildFile" @args diff --git a/build.sh b/build.sh index 07997d6c83..b0bcadb579 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/feature/msbuild.zip" +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" if [ ! -z $KOREBUILD_ZIP ]; then koreBuildZip=$KOREBUILD_ZIP fi @@ -12,12 +12,12 @@ buildFile="$buildFolder/KoreBuild.sh" if test ! -d $buildFolder; then echo "Downloading KoreBuild from $koreBuildZip" - - tempFolder="/tmp/KoreBuild-$(uuidgen)" + + tempFolder="/tmp/KoreBuild-$(uuidgen)" mkdir $tempFolder - + localZipFile="$tempFolder/korebuild.zip" - + retries=6 until (wget -O $localZipFile $koreBuildZip 2>/dev/null || curl -o $localZipFile --location $koreBuildZip 2>/dev/null) do @@ -29,18 +29,18 @@ if test ! -d $buildFolder; then echo "Waiting 10 seconds before retrying. Retries left: $retries" sleep 10s done - + unzip -q -d $tempFolder $localZipFile - + mkdir $buildFolder cp -r $tempFolder/**/build/** $buildFolder - + chmod +x $buildFile - + # Cleanup if test -d $tempFolder; then - rm -rf $tempFolder + rm -rf $tempFolder fi fi -$buildFile -r $repoFolder "$@" \ No newline at end of file +$buildFile -r $repoFolder "$@" From fbb2360f872437247a55cb47bfdc4c2bcc7c75d4 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 1 Mar 2017 18:14:13 -0800 Subject: [PATCH 178/471] Change korebuild branch and fix argument forwarding in bootstrapper --- build.ps1 | 16 ++++++++-------- build.sh | 22 +++++++++++----------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/build.ps1 b/build.ps1 index 0605b59c01..5bf0e2c113 100644 --- a/build.ps1 +++ b/build.ps1 @@ -1,6 +1,6 @@ $ErrorActionPreference = "Stop" -function DownloadWithRetry([string] $url, [string] $downloadLocation, [int] $retries) +function DownloadWithRetry([string] $url, [string] $downloadLocation, [int] $retries) { while($true) { @@ -19,7 +19,7 @@ function DownloadWithRetry([string] $url, [string] $downloadLocation, [int] $ret Start-Sleep -Seconds 10 } - else + else { $exception = $_.Exception throw $exception @@ -33,7 +33,7 @@ cd $PSScriptRoot $repoFolder = $PSScriptRoot $env:REPO_FOLDER = $repoFolder -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/feature/msbuild.zip" +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" if ($env:KOREBUILD_ZIP) { $koreBuildZip=$env:KOREBUILD_ZIP @@ -43,18 +43,18 @@ $buildFolder = ".build" $buildFile="$buildFolder\KoreBuild.ps1" if (!(Test-Path $buildFolder)) { - Write-Host "Downloading KoreBuild from $koreBuildZip" - + Write-Host "Downloading KoreBuild from $koreBuildZip" + $tempFolder=$env:TEMP + "\KoreBuild-" + [guid]::NewGuid() New-Item -Path "$tempFolder" -Type directory | Out-Null $localZipFile="$tempFolder\korebuild.zip" - + DownloadWithRetry -url $koreBuildZip -downloadLocation $localZipFile -retries 6 Add-Type -AssemblyName System.IO.Compression.FileSystem [System.IO.Compression.ZipFile]::ExtractToDirectory($localZipFile, $tempFolder) - + New-Item -Path "$buildFolder" -Type directory | Out-Null copy-item "$tempFolder\**\build\*" $buildFolder -Recurse @@ -64,4 +64,4 @@ if (!(Test-Path $buildFolder)) { } } -&"$buildFile" $args \ No newline at end of file +&"$buildFile" @args diff --git a/build.sh b/build.sh index 07997d6c83..b0bcadb579 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/feature/msbuild.zip" +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" if [ ! -z $KOREBUILD_ZIP ]; then koreBuildZip=$KOREBUILD_ZIP fi @@ -12,12 +12,12 @@ buildFile="$buildFolder/KoreBuild.sh" if test ! -d $buildFolder; then echo "Downloading KoreBuild from $koreBuildZip" - - tempFolder="/tmp/KoreBuild-$(uuidgen)" + + tempFolder="/tmp/KoreBuild-$(uuidgen)" mkdir $tempFolder - + localZipFile="$tempFolder/korebuild.zip" - + retries=6 until (wget -O $localZipFile $koreBuildZip 2>/dev/null || curl -o $localZipFile --location $koreBuildZip 2>/dev/null) do @@ -29,18 +29,18 @@ if test ! -d $buildFolder; then echo "Waiting 10 seconds before retrying. Retries left: $retries" sleep 10s done - + unzip -q -d $tempFolder $localZipFile - + mkdir $buildFolder cp -r $tempFolder/**/build/** $buildFolder - + chmod +x $buildFile - + # Cleanup if test -d $tempFolder; then - rm -rf $tempFolder + rm -rf $tempFolder fi fi -$buildFile -r $repoFolder "$@" \ No newline at end of file +$buildFile -r $repoFolder "$@" From dcfbbab005c1fe59e131a0795fff05abf64f76d9 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 1 Mar 2017 18:25:39 -0800 Subject: [PATCH 179/471] Update AppVeyor and Travis settings --- .travis.yml | 2 +- appveyor.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index a0be886892..af659e9ae9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,4 +29,4 @@ branches: before_install: - if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/; fi script: - - ./build.sh --quiet verify + - ./build.sh diff --git a/appveyor.yml b/appveyor.yml index 06545db9f6..944c23c8ba 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,9 +7,9 @@ branches: - dev - /^(.*\/)?ci-.*$/ build_script: - - build.cmd --quiet verify + - ps: .\build.ps1 clone_depth: 1 test: off deploy: off # Required for dotnet-test to work -os: Visual Studio 2015 \ No newline at end of file +os: Visual Studio 2015 From 35ab125ba64ae21a581f051d986c75c0f2919391 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 1 Mar 2017 18:25:51 -0800 Subject: [PATCH 180/471] Update AppVeyor and Travis settings --- .travis.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 67d9a88786..d9285f178d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,7 +29,7 @@ branches: before_install: - if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/; fi script: - - ./build.sh --quiet verify + - ./build.sh notifications: webhooks: secure: "d87o+y2WUx204s8TfSaEuekYudnSyyPaFEXkuzgs3uAyzkKAm/Hx0xcMSuKDqWhYmKaxL7VtgEd2z7mltr2cHZ4oyCrsf6V5v4iI48ojaGykqFXfv8ld6khmLwtdkC32lF2YyuDNL8kUvKNdP9jkrWlpoO/WC6QEqAUxdOuuLo/wLyfrPLbzIvbojwveXbmcwvsfDizLdZdVd88FZSV41h+yBKLnyhpeqRvHG85BTgT/GmVB7Vyjs3yChiS639Aq5DoOP8jBaRdB8Bqs09KibFXzJwDBlKvALIqiwzog3hpd5SVxrgOTCkWbOwqq4TSkahDE425W3vFbmLDANgdfsyAkqgt8daE2BkFTojEHQED+u9CEd8oJVX6FoGnYpuDzge4FVh9iG3HSuKwoVdlONzzew4oJ75iQ+0f67ZNV9oDuScdva/SGb2gYgVUkeJIjDoMxKuaZyhbBT9jRXRBI+LsIjziEhLU/649FjTSmQx0HLpcT7+kaeSmhqT9JffVLidMdvZwhPZsLxPSG9UVBH9G8rdyHXP2e0ZlicHNjjNV6kbDqfDPhHx2/MfZGugsJXjOONKu/5LZduQzmAOysqdLKqkBVkMq2xl7aGV+yVZAtTmZB3nqOWGyKlFC9kLGO+qlJ4tBac26lHCZWTK+4VOAtN5Dag0DkDikgGdZaq78=" diff --git a/appveyor.yml b/appveyor.yml index 13c0650228..3f828ce38e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,7 +7,7 @@ branches: - dev - /^(.*\/)?ci-.*$/ build_script: - - build.cmd --quiet verify + - ps: .\build.ps1 clone_depth: 1 test: off deploy: off From 42d0d40b36df498f6367326810852ac546c81352 Mon Sep 17 00:00:00 2001 From: Thierry Fleury Date: Tue, 7 Feb 2017 14:20:42 -0800 Subject: [PATCH 181/471] [Fixes #61] Move must keep object reference --- .../Adapters/ObjectAdapter.cs | 19 +- .../Internal/ConversionResultProvider.cs | 53 ++++- .../Properties/Resources.Designer.cs | 16 ++ .../Resources.resx | 3 + .../InheritedDTO.cs | 10 + .../ListAdapterTest.cs | 75 +++++++ .../NestedObjectTests.cs | 211 ++++++++++++++++++ .../SimpleDTOWithNestedDTO.cs | 3 + 8 files changed, 385 insertions(+), 5 deletions(-) create mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/InheritedDTO.cs diff --git a/src/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs b/src/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs index 0ac2ebbe56..b1a487f088 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs @@ -362,10 +362,21 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters // Get value at 'from' location and add that value to the 'path' location if (TryGetValue(operation.from, objectToApplyTo, operation, out propertyValue)) { - Add(operation.path, - propertyValue, - objectToApplyTo, - operation); + // 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; + } } } diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/ConversionResultProvider.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/ConversionResultProvider.cs index bdf4122394..71af0d27fc 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Internal/ConversionResultProvider.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Internal/ConversionResultProvider.cs @@ -2,6 +2,7 @@ // 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 @@ -10,9 +11,44 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal { 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(IsNullableType(typeToConvertTo), null); + } + else if (typeToConvertTo.IsAssignableFrom(value.GetType())) + { + // Keep original type + targetType = value.GetType(); + } try { - var deserialized = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(value), typeToConvertTo); + var deserialized = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(value), targetType); return new ConversionResult(true, deserialized); } catch @@ -20,5 +56,20 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal 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/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs index ed567cf003..97c98c2b05 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs @@ -26,6 +26,22 @@ namespace Microsoft.AspNetCore.JsonPatch return string.Format(CultureInfo.CurrentCulture, GetString("CannotDeterminePropertyType"), p0); } + /// + /// The property at '{0}' could not be copied. + /// + internal static string CannotCannotCopyProperty + { + get { return GetString("CannotCannotCopyProperty"); } + } + + /// + /// The property at '{0}' could not be copied. + /// + internal static string FormatCannotCopyProperty(object p0) + { + return string.Format(CultureInfo.CurrentCulture, GetString("CannotCannotCopyProperty"), p0); + } + /// /// The '{0}' operation at path '{1}' could not be performed. /// diff --git a/src/Microsoft.AspNetCore.JsonPatch/Resources.resx b/src/Microsoft.AspNetCore.JsonPatch/Resources.resx index 7381ad02fc..87ed5c0a17 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Resources.resx +++ b/src/Microsoft.AspNetCore.JsonPatch/Resources.resx @@ -117,6 +117,9 @@ 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. diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/InheritedDTO.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/InheritedDTO.cs new file mode 100644 index 0000000000..a784a6304b --- /dev/null +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/InheritedDTO.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 InheritedDTO : SimpleDTO + { + public string AdditionalStringProperty { get; set; } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/ListAdapterTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/ListAdapterTest.cs index 799f6e9e89..077a179a40 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/ListAdapterTest.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/ListAdapterTest.cs @@ -174,6 +174,27 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal Assert.Equal(new List() { "James", "Mike", null }, targetObject); } + [Fact] + public void Add_CompatibleTypeWorks() + { + // Arrange + var sDto = new SimpleDTO(); + var iDto = new InheritedDTO(); + var resolver = new Mock(MockBehavior.Strict); + var targetObject = (new List() { sDto }); + var listAdapter = new ListAdapter(); + string message = null; + + // Act + var addStatus = listAdapter.TryAdd(targetObject, "-", resolver.Object, iDto, out 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() { @@ -244,6 +265,60 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal Assert.Equal(expected, targetObject); } + public static TheoryData AddingKeepsObjectReferenceData { + get { + var sDto1 = new SimpleDTO(); + var sDto2 = new SimpleDTO(); + var sDto3 = new SimpleDTO(); + 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(); + string message = null; + + // Act + var addStatus = listAdapter.TryAdd(targetObject, position, resolver.Object, value, out 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")] diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/NestedObjectTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/NestedObjectTests.cs index cc2e990997..ece1a6e3d6 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/NestedObjectTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/NestedObjectTests.cs @@ -1699,6 +1699,81 @@ namespace Microsoft.AspNetCore.JsonPatch Assert.Equal(new List() { 1, 2, 3, 5 }, doc.SimpleDTO.IntegerList); } + [Fact] + public void Copy_DeepClonesObject() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO() + { + StringProperty = "A", + AnotherStringProperty = "B" + }, + InheritedDTO = new InheritedDTO() + { + StringProperty = "C", + AnotherStringProperty = "D" + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.InheritedDTO, o => o.SimpleDTO); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal("C", doc.SimpleDTO.StringProperty); + Assert.Equal("D", doc.SimpleDTO.AnotherStringProperty); + Assert.Equal("C", doc.InheritedDTO.StringProperty); + Assert.Equal("D", doc.InheritedDTO.AnotherStringProperty); + Assert.NotSame(doc.SimpleDTO.StringProperty, doc.InheritedDTO.StringProperty); + } + + [Fact] + public void Copy_KeepsObjectType() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO(), + InheritedDTO = new InheritedDTO() + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.InheritedDTO, o => o.SimpleDTO); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(typeof(InheritedDTO), doc.SimpleDTO.GetType()); + } + + [Fact] + public void Copy_BreaksObjectReference() + { + // Arrange + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = new SimpleDTO(), + InheritedDTO = new InheritedDTO() + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.InheritedDTO, o => o.SimpleDTO); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.NotSame(doc.SimpleDTO, doc.InheritedDTO); + } + [Fact] public void Move() { @@ -1752,6 +1827,77 @@ namespace Microsoft.AspNetCore.JsonPatch Assert.Equal(null, doc.SimpleDTO.StringProperty); } + [Fact] + public void Move_KeepsObjectReference() + { + // Arrange + var sDto = new SimpleDTO() + { + StringProperty = "A", + AnotherStringProperty = "B" + }; + var iDto = new InheritedDTO() + { + StringProperty = "C", + AnotherStringProperty = "D" + }; + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = sDto, + InheritedDTO = iDto + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.InheritedDTO, o => o.SimpleDTO); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal("C", doc.SimpleDTO.StringProperty); + Assert.Equal("D", doc.SimpleDTO.AnotherStringProperty); + Assert.Same(iDto, doc.SimpleDTO); + Assert.Equal(null, doc.InheritedDTO); + } + + [Fact] + public void Move_KeepsObjectReferenceWithSerialization() + { + // Arrange + var sDto = new SimpleDTO() + { + StringProperty = "A", + AnotherStringProperty = "B" + }; + var iDto = new InheritedDTO() + { + StringProperty = "C", + AnotherStringProperty = "D" + }; + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTO = sDto, + InheritedDTO = iDto + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.InheritedDTO, o => o.SimpleDTO); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + deserialized.ApplyTo(doc); + + // Assert + Assert.Equal("C", doc.SimpleDTO.StringProperty); + Assert.Equal("D", doc.SimpleDTO.AnotherStringProperty); + Assert.Same(iDto, doc.SimpleDTO); + Assert.Equal(null, doc.InheritedDTO); + } + [Fact] public void MoveInList() { @@ -1801,6 +1947,71 @@ namespace Microsoft.AspNetCore.JsonPatch Assert.Equal(new List() { 2, 1, 3 }, doc.SimpleDTO.IntegerList); } + [Fact] + public void Move_KeepsObjectReferenceInList() + { + // Arrange + var sDto1 = new SimpleDTO() { IntegerValue = 1 }; + var sDto2 = new SimpleDTO() { IntegerValue = 2 }; + var sDto3 = new SimpleDTO() { IntegerValue = 3 }; + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTOList = new List() { + sDto1, + sDto2, + sDto3 + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.SimpleDTOList, 0, o => o.SimpleDTOList, 1); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { sDto2, sDto1, sDto3 }, doc.SimpleDTOList); + Assert.Equal(2, doc.SimpleDTOList[0].IntegerValue); + Assert.Equal(1, doc.SimpleDTOList[1].IntegerValue); + Assert.Same(sDto2, doc.SimpleDTOList[0]); + Assert.Same(sDto1, doc.SimpleDTOList[1]); + } + + [Fact] + public void Move_KeepsObjectReferenceInListWithSerialization() + { + // Arrange + var sDto1 = new SimpleDTO() { IntegerValue = 1 }; + var sDto2 = new SimpleDTO() { IntegerValue = 2 }; + var sDto3 = new SimpleDTO() { IntegerValue = 3 }; + var doc = new SimpleDTOWithNestedDTO() + { + SimpleDTOList = new List() { + sDto1, + sDto2, + sDto3 + } + }; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.SimpleDTOList, 0, o => o.SimpleDTOList, 1); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = JsonConvert.DeserializeObject>(serialized); + + // Act + patchDoc.ApplyTo(doc); + + // Assert + Assert.Equal(new List() { sDto2, sDto1, sDto3 }, doc.SimpleDTOList); + Assert.Equal(2, doc.SimpleDTOList[0].IntegerValue); + Assert.Equal(1, doc.SimpleDTOList[1].IntegerValue); + Assert.Same(sDto2, doc.SimpleDTOList[0]); + Assert.Same(sDto1, doc.SimpleDTOList[1]); + } + [Fact] public void MoveFromListToEndOfList() { diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTOWithNestedDTO.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTOWithNestedDTO.cs index 879d820277..de089eb25f 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTOWithNestedDTO.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTOWithNestedDTO.cs @@ -13,6 +13,8 @@ namespace Microsoft.AspNetCore.JsonPatch public SimpleDTO SimpleDTO { get; set; } + public InheritedDTO InheritedDTO { get; set; } + public List SimpleDTOList { get; set; } public IList SimpleDTOIList { get; set; } @@ -21,6 +23,7 @@ namespace Microsoft.AspNetCore.JsonPatch { this.NestedDTO = new NestedDTO(); this.SimpleDTO = new SimpleDTO(); + this.InheritedDTO = new InheritedDTO(); this.SimpleDTOList = new List(); } } From d3a09ca9e879507fb7b7c5a8825da59b3bfa63ef Mon Sep 17 00:00:00 2001 From: Thierry Fleury Date: Tue, 7 Feb 2017 13:38:10 -0800 Subject: [PATCH 182/471] Correct ListAdapter tests Modifying a ReadOnlyCollection will always fail --- test/Microsoft.AspNetCore.JsonPatch.Test/ListAdapterTest.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/ListAdapterTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/ListAdapterTest.cs index 077a179a40..6a087edd8f 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/ListAdapterTest.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/ListAdapterTest.cs @@ -181,7 +181,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal var sDto = new SimpleDTO(); var iDto = new InheritedDTO(); var resolver = new Mock(MockBehavior.Strict); - var targetObject = (new List() { sDto }); + var targetObject = new List() { sDto }; var listAdapter = new ListAdapter(); string message = null; @@ -200,7 +200,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal { // Arrange var resolver = new Mock(MockBehavior.Strict); - var targetObject = (new List() { 10, 20 }).AsReadOnly(); + var targetObject = new List() { 10, 20 }; var listAdapter = new ListAdapter(); string message = null; @@ -411,7 +411,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal { // Arrange var resolver = new Mock(MockBehavior.Strict); - var targetObject = (new List() { 10, 20 }).AsReadOnly(); + var targetObject = new List() { 10, 20 }; var listAdapter = new ListAdapter(); string message = null; From 9c618c8600b1748146f5454cf4e25ad3cbb1980c Mon Sep 17 00:00:00 2001 From: David Fowler Date: Wed, 8 Mar 2017 20:00:41 -0800 Subject: [PATCH 183/471] Update .travis.yml --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index af659e9ae9..b8f60ce2e5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,8 +14,7 @@ env: global: - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true - DOTNET_CLI_TELEMETRY_OPTOUT: 1 -mono: - - 4.0.5 +mono: none os: - linux - osx From 533373d6365be73c72ee8fe003dcb09cb6fbc23e Mon Sep 17 00:00:00 2001 From: David Fowler Date: Wed, 8 Mar 2017 20:32:33 -0800 Subject: [PATCH 184/471] Update .travis.yml --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index d9285f178d..4f28213da4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,8 +14,7 @@ env: global: - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true - DOTNET_CLI_TELEMETRY_OPTOUT: 1 -mono: - - 4.0.5 +mono: none os: - linux - osx From ba0926736b86703c64044983f6e74a10c640ead9 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 14 Mar 2017 13:40:24 -0700 Subject: [PATCH 185/471] Update appveyor and travis settings --- .travis.yml | 1 - appveyor.yml | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4f28213da4..56f3837d7e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,6 @@ mono: none os: - linux - osx -osx_image: xcode7.3 branches: only: - master diff --git a/appveyor.yml b/appveyor.yml index 3f828ce38e..1041615c68 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -11,4 +11,4 @@ build_script: clone_depth: 1 test: off deploy: off -os: Visual Studio 2017 RC +os: Visual Studio 2017 From d01f81eeb84d5edbcf6d52de4863e2eceaf8d8ab Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 14 Mar 2017 13:40:42 -0700 Subject: [PATCH 186/471] Update appveyor and travis settings --- .travis.yml | 1 - appveyor.yml | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index b8f60ce2e5..e4c69a2a09 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,6 @@ mono: none os: - linux - osx -osx_image: xcode7.3 branches: only: - master diff --git a/appveyor.yml b/appveyor.yml index 944c23c8ba..1041615c68 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -11,5 +11,4 @@ build_script: clone_depth: 1 test: off deploy: off -# Required for dotnet-test to work -os: Visual Studio 2015 +os: Visual Studio 2017 From e3ca1d1a2cd8d1471f5d82103c7bddf95b71a8b8 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 15 Mar 2017 13:47:45 -0700 Subject: [PATCH 187/471] Unify dependency versions to one file and remove workarounds --- build/dependencies.props | 5 ++++- .../Microsoft.Extensions.WebEncoders.csproj | 4 ++-- ...icrosoft.AspNetCore.Html.Abstractions.Test.csproj | 11 +++++++---- .../Microsoft.Extensions.WebEncoders.Tests.csproj | 12 +++++++----- 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index e704edaec0..5a4c06ce33 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,6 +1,9 @@ - 1.6.1 + 1.2.0-* 4.3.0 + 1.6.1 + 15.0.0 + 2.2.0 diff --git a/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.csproj b/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.csproj index 70766d649f..d80a4bbcc6 100755 --- a/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.csproj +++ b/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.csproj @@ -13,8 +13,8 @@ - - + + diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.csproj b/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.csproj index 1fe9581c45..8f5f62fd36 100755 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.csproj +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.csproj @@ -10,10 +10,13 @@ - - - - + + + + + + + diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj b/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj index 77b807e9dd..f090acc59c 100755 --- a/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj +++ b/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj @@ -5,15 +5,17 @@ netcoreapp1.1;net452 netcoreapp1.1 - $(PackageTargetFallback);dnxcore50;portable-net451+win8 - - - - + + + + + + + From 832cbdcee8df72ba74d6892542e16312c5d0ef38 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 15 Mar 2017 15:11:25 -0700 Subject: [PATCH 188/471] Unify dependency versions to one file --- build/common.props | 1 - build/dependencies.props | 7 ++++++- .../Microsoft.AspNetCore.JsonPatch.csproj | 4 ++-- ...Microsoft.AspNetCore.JsonPatch.Test.csproj | 19 +++++++++++++----- tools/Key.snk | Bin 596 -> 0 bytes 5 files changed, 22 insertions(+), 9 deletions(-) delete mode 100644 tools/Key.snk diff --git a/build/common.props b/build/common.props index 17a0ccb4d8..1d3e64007b 100644 --- a/build/common.props +++ b/build/common.props @@ -1,5 +1,4 @@ - diff --git a/build/dependencies.props b/build/dependencies.props index e704edaec0..4fe028e673 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,6 +1,11 @@ - 1.6.1 + 1.2.0-* 4.3.0 + 9.0.1 + 4.7.1 + 1.6.1 + 15.0.0 + 2.2.0 diff --git a/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj b/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj index d3d5b01a89..f68aae1aaa 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj +++ b/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj @@ -10,8 +10,8 @@ - - + + diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj index e939e5d62c..6f5575c5ee 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj @@ -1,22 +1,31 @@  + + netcoreapp1.1;net452 netcoreapp1.1 + - - - - - + + + + + + + + + + + diff --git a/tools/Key.snk b/tools/Key.snk deleted file mode 100644 index e10e4889c125d3120cd9e81582243d70f7cbb806..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098=Iw=HCsnz~#iVhm& zj%TU(_THUee?3yHBjk$37ysB?i5#7WD$={H zV4B!OxRPrb|8)HPg~A}8P>^=#y<)56#=E&NzcjOtPK~<4n6GHt=K$ro*T(lhby_@U zEk(hLzk1H)0yXj{A_5>fk-TgNoP|q6(tP2xo8zt8i%212CWM#AeCd?`hS|4~L({h~Moo(~vy&3Z z1uI}`fd^*>o=rwbAGymj6RM^pZm(*Kfhs+Y1#`-2JPWZMK8@;ZWCk2+9bX4YP);~fj-BU*R zQPvWv$89!{Rl9wM+zR>_TSkn^voYxA?2G iKnV#iZ6Ah`K>b=@=IjYJXrxL124zR(38)nxe+&q_$QXwJ From 616f7dcfe74d809543125558af6dc984dfb1315c Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 21 Mar 2017 11:46:29 -0700 Subject: [PATCH 189/471] Update Travis to macOS Sierra [skip appveyor] --- .travis.yml | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index e4c69a2a09..2a46104677 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,15 +1,6 @@ language: csharp -sudo: required +sudo: false dist: trusty -addons: - apt: - packages: - - gettext - - libcurl4-openssl-dev - - libicu-dev - - libssl-dev - - libunwind8 - - zlib1g env: global: - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true @@ -18,6 +9,7 @@ mono: none os: - linux - osx +osx_image: xcode8.2 branches: only: - master From ebd8f61dcbe5909926162d06033a48fae3463123 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 21 Mar 2017 12:14:12 -0700 Subject: [PATCH 190/471] Update Travis to macOS Sierra [skip appveyor] --- .travis.yml | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/.travis.yml b/.travis.yml index 56f3837d7e..2a46104677 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,15 +1,6 @@ language: csharp -sudo: required +sudo: false dist: trusty -addons: - apt: - packages: - - gettext - - libcurl4-openssl-dev - - libicu-dev - - libssl-dev - - libunwind8 - - zlib1g env: global: - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true @@ -18,6 +9,7 @@ mono: none os: - linux - osx +osx_image: xcode8.2 branches: only: - master @@ -28,9 +20,3 @@ before_install: - if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/; fi script: - ./build.sh -notifications: - webhooks: - secure: "d87o+y2WUx204s8TfSaEuekYudnSyyPaFEXkuzgs3uAyzkKAm/Hx0xcMSuKDqWhYmKaxL7VtgEd2z7mltr2cHZ4oyCrsf6V5v4iI48ojaGykqFXfv8ld6khmLwtdkC32lF2YyuDNL8kUvKNdP9jkrWlpoO/WC6QEqAUxdOuuLo/wLyfrPLbzIvbojwveXbmcwvsfDizLdZdVd88FZSV41h+yBKLnyhpeqRvHG85BTgT/GmVB7Vyjs3yChiS639Aq5DoOP8jBaRdB8Bqs09KibFXzJwDBlKvALIqiwzog3hpd5SVxrgOTCkWbOwqq4TSkahDE425W3vFbmLDANgdfsyAkqgt8daE2BkFTojEHQED+u9CEd8oJVX6FoGnYpuDzge4FVh9iG3HSuKwoVdlONzzew4oJ75iQ+0f67ZNV9oDuScdva/SGb2gYgVUkeJIjDoMxKuaZyhbBT9jRXRBI+LsIjziEhLU/649FjTSmQx0HLpcT7+kaeSmhqT9JffVLidMdvZwhPZsLxPSG9UVBH9G8rdyHXP2e0ZlicHNjjNV6kbDqfDPhHx2/MfZGugsJXjOONKu/5LZduQzmAOysqdLKqkBVkMq2xl7aGV+yVZAtTmZB3nqOWGyKlFC9kLGO+qlJ4tBac26lHCZWTK+4VOAtN5Dag0DkDikgGdZaq78=" - on_success: always - on_failure: always - on_start: always From bac161fdd6f193c5a63584db5a2a5bc8c4729135 Mon Sep 17 00:00:00 2001 From: Kiran Challa Date: Tue, 21 Mar 2017 15:41:08 -0700 Subject: [PATCH 191/471] Converted test projects to run on netcoreapp2.0 --- build/dependencies.props | 1 + .../Microsoft.AspNetCore.Html.Abstractions.Test.csproj | 4 ++-- .../Microsoft.Extensions.WebEncoders.Tests.csproj | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 5a4c06ce33..12a50aa67f 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,6 +3,7 @@ 1.2.0-* 4.3.0 1.6.1 + 2.0.0-* 15.0.0 2.2.0 diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.csproj b/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.csproj index 8f5f62fd36..3e6fcd27cb 100755 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.csproj +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.csproj @@ -3,8 +3,8 @@ - netcoreapp1.1;net452 - netcoreapp1.1 + netcoreapp2.0;net452 + netcoreapp2.0 diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj b/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj index f090acc59c..35a8477927 100755 --- a/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj +++ b/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj @@ -3,8 +3,8 @@ - netcoreapp1.1;net452 - netcoreapp1.1 + netcoreapp2.0;net452 + netcoreapp2.0 From d2be921ca461505e93a5bae957ea345d1b1b1379 Mon Sep 17 00:00:00 2001 From: Kiran Challa Date: Mon, 13 Mar 2017 17:20:01 -0700 Subject: [PATCH 192/471] Converted test project to run on netcoreapp2.0 --- build/dependencies.props | 1 + .../Microsoft.AspNetCore.JsonPatch.Test.csproj | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 4fe028e673..b810d63d6e 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -5,6 +5,7 @@ 9.0.1 4.7.1 1.6.1 + 2.0.0-* 15.0.0 2.2.0 diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj index 6f5575c5ee..bb67d98fb1 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj @@ -3,8 +3,8 @@ - netcoreapp1.1;net452 - netcoreapp1.1 + netcoreapp2.0;net452 + netcoreapp2.0 From 9a7abcd902358017bdcfafa4cc5371360758551c Mon Sep 17 00:00:00 2001 From: Pranav K Date: Sun, 12 Mar 2017 15:02:51 -0700 Subject: [PATCH 193/471] Remove net451 as a cross-compile target --- .gitignore | 3 ++- .../Microsoft.AspNetCore.Html.Abstractions.Test.csproj | 2 +- .../Microsoft.Extensions.WebEncoders.Tests.csproj | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 980ee002d9..6da3c6a3e9 100644 --- a/.gitignore +++ b/.gitignore @@ -36,4 +36,5 @@ node_modules **/[Cc]ompiler/[Rr]esources/**/*.js *launchSettings.json .build/ -.testPublish/ \ No newline at end of file +.testPublish/ +global.json diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.csproj b/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.csproj index 3e6fcd27cb..ac305ecf01 100755 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.csproj +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.csproj @@ -3,7 +3,7 @@ - netcoreapp2.0;net452 + netcoreapp2.0;net46 netcoreapp2.0 diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj b/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj index 35a8477927..94bc15926e 100755 --- a/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj +++ b/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj @@ -3,7 +3,7 @@ - netcoreapp2.0;net452 + netcoreapp2.0;net46 netcoreapp2.0 From f66753cc3c0ec85ea806970a50271acba16b982f Mon Sep 17 00:00:00 2001 From: Pranav K Date: Sun, 12 Mar 2017 15:50:01 -0700 Subject: [PATCH 194/471] Remove net451 as a cross-compile target --- .gitignore | 3 ++- .../Microsoft.AspNetCore.JsonPatch.csproj | 7 ++----- .../Microsoft.AspNetCore.JsonPatch.Test.csproj | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 06cfaa0cbe..2e8ec28064 100644 --- a/.gitignore +++ b/.gitignore @@ -35,4 +35,5 @@ nuget.exe *.sln.ide node_modules *launchSettings.json -*.orig \ No newline at end of file +*.orig +global.json diff --git a/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj b/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj index f68aae1aaa..073f7f170f 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj +++ b/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj @@ -3,7 +3,7 @@ ASP.NET Core support for JSON PATCH. - net451;netstandard1.3 + netstandard1.3 $(NoWarn);CS1591 true aspnetcore;json;jsonpatch @@ -11,11 +11,8 @@ - - - - + diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj index bb67d98fb1..d8ef8158e3 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj @@ -3,7 +3,7 @@ - netcoreapp2.0;net452 + netcoreapp2.0;net46 netcoreapp2.0 From ab6e74f4b4eb19c02156ed85934a29000b4d008f Mon Sep 17 00:00:00 2001 From: Kiran Challa Date: Mon, 27 Mar 2017 18:14:22 -0700 Subject: [PATCH 195/471] Upgraded Json.NET version to 10.0.1 --- build/dependencies.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/dependencies.props b/build/dependencies.props index b810d63d6e..8aa0110742 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -2,7 +2,7 @@ 1.2.0-* 4.3.0 - 9.0.1 + 10.0.1 4.7.1 1.6.1 2.0.0-* From 2e3c35b863ab242a2c948911225537965483740c Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 29 Mar 2017 11:30:33 -0700 Subject: [PATCH 196/471] Updating to 2.0.0 Internal.AspNetCore.Sdk --- build/common.props | 2 +- build/dependencies.props | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/build/common.props b/build/common.props index de08271afe..647ef2d1e9 100644 --- a/build/common.props +++ b/build/common.props @@ -12,7 +12,7 @@ - + diff --git a/build/dependencies.props b/build/dependencies.props index 12a50aa67f..8c81df7f34 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -2,9 +2,10 @@ 1.2.0-* 4.3.0 + 2.0.0-* 1.6.1 2.0.0-* 15.0.0 2.2.0 - + \ No newline at end of file From 99ff496e7128b3b51968c0971459143df1321205 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 29 Mar 2017 11:30:34 -0700 Subject: [PATCH 197/471] Updating to 2.0.0 Internal.AspNetCore.Sdk --- build/common.props | 2 +- build/dependencies.props | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/build/common.props b/build/common.props index 1d3e64007b..ffe4d99846 100644 --- a/build/common.props +++ b/build/common.props @@ -13,7 +13,7 @@ - + diff --git a/build/dependencies.props b/build/dependencies.props index 8aa0110742..72d6874ffd 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -2,6 +2,7 @@ 1.2.0-* 4.3.0 + 2.0.0-* 10.0.1 4.7.1 1.6.1 @@ -9,4 +10,4 @@ 15.0.0 2.2.0 - + \ No newline at end of file From 0e6db5af0f82d85273b800660045d2696e6302e1 Mon Sep 17 00:00:00 2001 From: Hao Kung Date: Wed, 29 Mar 2017 14:32:35 -0700 Subject: [PATCH 198/471] Bump to netstandard1.1 for options --- .../Microsoft.Extensions.WebEncoders.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.csproj b/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.csproj index d80a4bbcc6..773011fef5 100755 --- a/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.csproj +++ b/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.csproj @@ -5,7 +5,7 @@ Microsoft .NET Extensions Contains registration and configuration APIs to add the core framework encoders to a dependency injection container. - netstandard1.0 + netstandard1.1 $(NoWarn);CS1591 true true From ebc2c99aaf71e820d3acef6f89986b2e854279d1 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 3 Apr 2017 21:41:10 -0700 Subject: [PATCH 199/471] Updating versions to 2.0.0-preview1 --- build/dependencies.props | 2 +- version.props | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 8c81df7f34..1973fc186f 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,6 +1,6 @@ - 1.2.0-* + 2.0.0-* 4.3.0 2.0.0-* 1.6.1 diff --git a/version.props b/version.props index 17fd5ac36d..c7150e64f4 100644 --- a/version.props +++ b/version.props @@ -1,7 +1,7 @@ - 1.2.0 + 2.0.0 preview1 From 290fd0a28da2b4edebb74709fed71517cfcc6778 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 3 Apr 2017 21:41:10 -0700 Subject: [PATCH 200/471] Updating versions to 2.0.0-preview1 --- build/dependencies.props | 2 +- version.props | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 72d6874ffd..5f6c92189c 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,6 +1,6 @@ - 1.2.0-* + 2.0.0-* 4.3.0 2.0.0-* 10.0.1 diff --git a/version.props b/version.props index e77c8d9c38..44cb2290b9 100644 --- a/version.props +++ b/version.props @@ -1,7 +1,7 @@ - 1.2.0 + 2.0.0 preview1 \ No newline at end of file From 2c2992b465fbd929891086bf1614139e4f5c438e Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 25 Apr 2017 11:04:08 -0700 Subject: [PATCH 201/471] Use Bundled NETStandard.Library \ NETCoreApp versions instead of explicitly specifying one --- build/dependencies.props | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 1973fc186f..01387147a4 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,9 +3,7 @@ 2.0.0-* 4.3.0 2.0.0-* - 1.6.1 - 2.0.0-* 15.0.0 2.2.0 - \ No newline at end of file + From e61f7a591ce3d5c05ef3246dfd2ea45662dbb277 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 25 Apr 2017 11:04:08 -0700 Subject: [PATCH 202/471] Use Bundled NETStandard.Library \ NETCoreApp versions instead of explicitly specifying one --- build/common.props | 2 +- build/dependencies.props | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/build/common.props b/build/common.props index ffe4d99846..a2698f3553 100644 --- a/build/common.props +++ b/build/common.props @@ -17,7 +17,7 @@ - + diff --git a/build/dependencies.props b/build/dependencies.props index 5f6c92189c..ac44ce3323 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -5,9 +5,7 @@ 2.0.0-* 10.0.1 4.7.1 - 1.6.1 - 2.0.0-* 15.0.0 2.2.0 - \ No newline at end of file + From 755bba2c623035bc9bf1b55ebb05c1756834b5d2 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 25 Apr 2017 22:02:36 -0700 Subject: [PATCH 203/471] Branching for 2.0.0-preview1 --- NuGet.config | 2 +- build.ps1 | 2 +- build.sh | 2 +- build/dependencies.props | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/NuGet.config b/NuGet.config index 8e65695611..fa4304af9c 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,7 @@ - + diff --git a/build.ps1 b/build.ps1 index 5bf0e2c113..225b1fe450 100644 --- a/build.ps1 +++ b/build.ps1 @@ -33,7 +33,7 @@ cd $PSScriptRoot $repoFolder = $PSScriptRoot $env:REPO_FOLDER = $repoFolder -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/2.0.0-preview1.zip" if ($env:KOREBUILD_ZIP) { $koreBuildZip=$env:KOREBUILD_ZIP diff --git a/build.sh b/build.sh index b0bcadb579..702b25c636 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/2.0.0-preview1.zip" if [ ! -z $KOREBUILD_ZIP ]; then koreBuildZip=$KOREBUILD_ZIP fi diff --git a/build/dependencies.props b/build/dependencies.props index 01387147a4..c7741b724b 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,6 +1,6 @@ - 2.0.0-* + 2.0.0-preview1-* 4.3.0 2.0.0-* 15.0.0 From c4dbc8d31592bb3ca191e77a6aeecffbbeb964df Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 25 Apr 2017 22:03:21 -0700 Subject: [PATCH 204/471] Branching for 2.0.0-preview1 --- NuGet.config | 4 ++-- build.ps1 | 2 +- build.sh | 2 +- build/dependencies.props | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/NuGet.config b/NuGet.config index 93f1ac47df..fa4304af9c 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,7 @@ - + - + diff --git a/build.ps1 b/build.ps1 index 5bf0e2c113..225b1fe450 100644 --- a/build.ps1 +++ b/build.ps1 @@ -33,7 +33,7 @@ cd $PSScriptRoot $repoFolder = $PSScriptRoot $env:REPO_FOLDER = $repoFolder -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/2.0.0-preview1.zip" if ($env:KOREBUILD_ZIP) { $koreBuildZip=$env:KOREBUILD_ZIP diff --git a/build.sh b/build.sh index b0bcadb579..702b25c636 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/2.0.0-preview1.zip" if [ ! -z $KOREBUILD_ZIP ]; then koreBuildZip=$KOREBUILD_ZIP fi diff --git a/build/dependencies.props b/build/dependencies.props index ac44ce3323..dddf01f9f0 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,6 +1,6 @@ - 2.0.0-* + 2.0.0-preview1-* 4.3.0 2.0.0-* 10.0.1 From 36a11404acfa0991ece671128da4cc26a720fe0d Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 26 Apr 2017 07:12:58 -0700 Subject: [PATCH 205/471] Updating package version to preview2 --- version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.props b/version.props index c7150e64f4..6af4f81de2 100644 --- a/version.props +++ b/version.props @@ -2,6 +2,6 @@ 2.0.0 - preview1 + preview2 From d0e7b6b7cdd23c352cb06b721707fb10de605524 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 26 Apr 2017 07:13:08 -0700 Subject: [PATCH 206/471] Updating package version to preview2 --- version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.props b/version.props index 44cb2290b9..0b2b8e0010 100644 --- a/version.props +++ b/version.props @@ -2,6 +2,6 @@ 2.0.0 - preview1 + preview2 \ No newline at end of file From aa4bef0f546c1c8544bd09af1e86e0ad6ea8f0b2 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 1 May 2017 12:39:26 -0700 Subject: [PATCH 207/471] Use the bundled NETStandard.Library package in netstandard targeting libraries --- build/dependencies.props | 1 + 1 file changed, 1 insertion(+) diff --git a/build/dependencies.props b/build/dependencies.props index c7741b724b..3db1eba0a2 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,6 +3,7 @@ 2.0.0-preview1-* 4.3.0 2.0.0-* + $(BundledNETStandardPackageVersion) 15.0.0 2.2.0 From 4628a2ff4e3097dd7e3c14e5e0d74d9c3d50371c Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 1 May 2017 12:39:39 -0700 Subject: [PATCH 208/471] Use the bundled NETStandard.Library package in netstandard targeting libraries --- build/dependencies.props | 1 + 1 file changed, 1 insertion(+) diff --git a/build/dependencies.props b/build/dependencies.props index dddf01f9f0..8dce2099b3 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -5,6 +5,7 @@ 2.0.0-* 10.0.1 4.7.1 + $(BundledNETStandardPackageVersion) 15.0.0 2.2.0 From 0eca2200697f16f987788a8f1e3dbae765ac3c84 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Fri, 5 May 2017 10:22:33 -0700 Subject: [PATCH 209/471] Update InternalAspNetCoreSdkVersion --- build/dependencies.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/dependencies.props b/build/dependencies.props index 3db1eba0a2..f66ecf394c 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -2,7 +2,7 @@ 2.0.0-preview1-* 4.3.0 - 2.0.0-* + 2.1.0-* $(BundledNETStandardPackageVersion) 15.0.0 2.2.0 From 8a0a8a781ec03d19a030db3b737b0d27c28f2497 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Fri, 5 May 2017 10:23:47 -0700 Subject: [PATCH 210/471] Update InternalAspNetCoreSdkVersion --- build/dependencies.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/dependencies.props b/build/dependencies.props index 8dce2099b3..40945df373 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -2,7 +2,7 @@ 2.0.0-preview1-* 4.3.0 - 2.0.0-* + 2.1.0-* 10.0.1 4.7.1 $(BundledNETStandardPackageVersion) From 378136f794017ed847d4ed0f3273d19bd89eb125 Mon Sep 17 00:00:00 2001 From: Jass Bagga Date: Fri, 5 May 2017 16:12:46 -0700 Subject: [PATCH 211/471] Change TFM to netcoreapp2.0 (#78) --- .../Microsoft.AspNetCore.JsonPatch.csproj | 2 +- .../Microsoft.AspNetCore.JsonPatch.Test.csproj | 8 +------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj b/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj index 073f7f170f..f31e8b9f82 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj +++ b/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj @@ -3,7 +3,7 @@ ASP.NET Core support for JSON PATCH. - netstandard1.3 + netcoreapp2.0 $(NoWarn);CS1591 true aspnetcore;json;jsonpatch diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj index d8ef8158e3..8f007862cd 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj @@ -3,8 +3,7 @@ - netcoreapp2.0;net46 - netcoreapp2.0 + netcoreapp2.0 @@ -19,11 +18,6 @@ - - - - - From ec0ce4b63855275c18b40ae9d1ff1e085bd9cea0 Mon Sep 17 00:00:00 2001 From: Jass Bagga Date: Fri, 5 May 2017 16:17:15 -0700 Subject: [PATCH 212/471] Change TFM to netcoreapp2.0 (#78) --- .../Microsoft.AspNetCore.JsonPatch.csproj | 2 +- .../Microsoft.AspNetCore.JsonPatch.Test.csproj | 8 +------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj b/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj index 073f7f170f..f31e8b9f82 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj +++ b/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj @@ -3,7 +3,7 @@ ASP.NET Core support for JSON PATCH. - netstandard1.3 + netcoreapp2.0 $(NoWarn);CS1591 true aspnetcore;json;jsonpatch diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj index d8ef8158e3..8f007862cd 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj @@ -3,8 +3,7 @@ - netcoreapp2.0;net46 - netcoreapp2.0 + netcoreapp2.0 @@ -19,11 +18,6 @@ - - - - - From 7a7dc711643858fb18e69cad296d30233ddcf847 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Wed, 10 May 2017 11:45:31 -0700 Subject: [PATCH 213/471] Remove unnecessary package references (#79) --- build/dependencies.props | 1 - .../Microsoft.AspNetCore.JsonPatch.csproj | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index ce45e95994..28b5745a79 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,7 +1,6 @@ 2.0.0-* - 4.3.0 2.1.0-* 10.0.1 4.7.1 diff --git a/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj b/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj index f31e8b9f82..f9c60761bf 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj +++ b/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj @@ -1,4 +1,4 @@ - + @@ -11,9 +11,7 @@ - - From 225c482c375fb1ffebcd6ad2d8334d6494c1f56f Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Mon, 15 May 2017 15:39:13 -0700 Subject: [PATCH 214/471] Upgrade test framework versions --- build/dependencies.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 09cfb1fe04..ed2c89867f 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,7 +4,7 @@ 4.3.0 2.1.0-* $(BundledNETStandardPackageVersion) - 15.0.0 - 2.2.0 + 15.3.0-* + 2.3.0-beta2-* From a7524e189d7f0c0099ea9d0b2a53ae440a8df605 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Mon, 15 May 2017 16:14:55 -0700 Subject: [PATCH 215/471] Upgrade test framework versions and fix test issues --- build/dependencies.props | 4 ++-- .../Dynamic/MoveOperationTests.cs | 4 ++-- .../Dynamic/MoveTypedOperationTests.cs | 2 +- .../Dynamic/RemoveOperationTests.cs | 6 ++--- .../Dynamic/RemoveTypedOperationTests.cs | 6 ++--- .../Dynamic/ReplaceOperationTests.cs | 2 +- .../Dynamic/ReplaceTypedOperationTests.cs | 6 ++--- ...nPatchDocumentJsonPropertyAttributeTest.cs | 10 ++++----- ...Microsoft.AspNetCore.JsonPatch.Test.csproj | 4 ---- .../NestedObjectTests.cs | 14 ++++++------ .../ObjectAdapterTests.cs | 22 +++++++++---------- 11 files changed, 38 insertions(+), 42 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 28b5745a79..3abab6008e 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -5,7 +5,7 @@ 10.0.1 4.7.1 $(BundledNETStandardPackageVersion) - 15.0.0 - 2.2.0 + 15.3.0-* + 2.3.0-beta2-* diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveOperationTests.cs index ed367848b7..5e2f7ae814 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveOperationTests.cs @@ -98,7 +98,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic deserialized.ApplyTo(doc); Assert.Equal("B", doc.StringProperty); - Assert.Equal(null, doc.SimpleDTO.AnotherStringProperty); + Assert.Null(doc.SimpleDTO.AnotherStringProperty); } [Fact] @@ -121,7 +121,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic deserialized.ApplyTo(doc); Assert.Equal("A", doc.Nested.AnotherStringProperty); - Assert.Equal(null, doc.Nested.StringProperty); + Assert.Null(doc.Nested.StringProperty); } [Fact] diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveTypedOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveTypedOperationTests.cs index cd4124d564..f57ad3d11c 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveTypedOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveTypedOperationTests.cs @@ -28,7 +28,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic deserialized.ApplyTo(doc); Assert.Equal("A", doc.AnotherStringProperty); - Assert.Equal(null, doc.StringProperty); + Assert.Null(doc.StringProperty); } [Fact] diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveOperationTests.cs index 6e903bf2ec..f0164765ee 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveOperationTests.cs @@ -163,7 +163,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic var deserialized = JsonConvert.DeserializeObject(serialized); deserialized.ApplyTo(doc); - Assert.Equal(null, doc.SimpleDTO.StringProperty); + Assert.Null(doc.SimpleDTO.StringProperty); } [Fact] @@ -184,7 +184,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic deserialized.ApplyTo(doc); - Assert.Equal(null, doc.SimpleDTO.StringProperty); + Assert.Null(doc.SimpleDTO.StringProperty); } [Fact] @@ -299,4 +299,4 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic Assert.Equal(new List() { 1, 2 }, doc.SimpleDTO.IntegerList); } } -} \ No newline at end of file +} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveTypedOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveTypedOperationTests.cs index 126706eef2..50ae6e8d5d 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveTypedOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveTypedOperationTests.cs @@ -27,7 +27,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic deserialized.ApplyTo(doc); - Assert.Equal(null, doc.StringProperty); + Assert.Null(doc.StringProperty); } [Fact] @@ -138,7 +138,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic deserialized.ApplyTo(doc); - Assert.Equal(null, doc.SimpleDTO.StringProperty); + Assert.Null(doc.SimpleDTO.StringProperty); } [Fact] @@ -241,4 +241,4 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic Assert.Equal(new List() { 1, 2 }, doc.SimpleDTO.IntegerList); } } -} \ No newline at end of file +} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceOperationTests.cs index b8e7196068..c5936ec1b0 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceOperationTests.cs @@ -107,7 +107,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic Assert.Equal(1, doc.SimpleDTO.DoubleValue); Assert.Equal(0, doc.SimpleDTO.IntegerValue); - Assert.Equal(null, doc.SimpleDTO.IntegerList); + Assert.Null(doc.SimpleDTO.IntegerList); } [Fact] diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceTypedOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceTypedOperationTests.cs index 589e86e03a..d0bf23f487 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceTypedOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceTypedOperationTests.cs @@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic JsonPatchDocument patchDoc = new JsonPatchDocument(); patchDoc.Replace("GuidValue", newGuid); - // serialize & deserialize + // serialize & deserialize var serialized = JsonConvert.SerializeObject(patchDoc); var deserizalized = JsonConvert.DeserializeObject(serialized); @@ -55,7 +55,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic JsonPatchDocument patchDoc = new JsonPatchDocument(); patchDoc.Replace("SimpleDTO", newDTO); - // serialize & deserialize + // serialize & deserialize var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); @@ -63,7 +63,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic Assert.Equal(1, doc.SimpleDTO.DoubleValue); Assert.Equal(0, doc.SimpleDTO.IntegerValue); - Assert.Equal(null, doc.SimpleDTO.IntegerList); + Assert.Null(doc.SimpleDTO.IntegerList); } [Fact] diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs index 182cf1cd6d..efc780b388 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs @@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.JsonPatch // get path var pathToCheck = deserialized.Operations.First().path; - Assert.Equal(pathToCheck, "/anothername"); + Assert.Equal("/anothername", pathToCheck); } [Fact] @@ -82,7 +82,7 @@ namespace Microsoft.AspNetCore.JsonPatch deserialized.ApplyTo(doc); - Assert.Equal(doc.AnotherName, "John"); + Assert.Equal("John", doc.AnotherName); } [Fact] @@ -107,7 +107,7 @@ namespace Microsoft.AspNetCore.JsonPatch deserialized.ApplyTo(doc); - Assert.Equal(doc.Name, "John"); + Assert.Equal("John", doc.Name); } [Fact] @@ -143,7 +143,7 @@ namespace Microsoft.AspNetCore.JsonPatch deserialized.ApplyTo(doc); - Assert.Equal(null, doc.Name); + Assert.Null(doc.Name); } [Fact] @@ -178,7 +178,7 @@ namespace Microsoft.AspNetCore.JsonPatch // get path var pathToCheck = deserialized.Operations.First().path; - Assert.Equal(pathToCheck, "/anothername"); + Assert.Equal("/anothername", pathToCheck); } [Fact] diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj index 8f007862cd..29a1f7dbed 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj @@ -18,8 +18,4 @@ - - - - diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/NestedObjectTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/NestedObjectTests.cs index ece1a6e3d6..4aa25a3af1 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/NestedObjectTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/NestedObjectTests.cs @@ -597,7 +597,7 @@ namespace Microsoft.AspNetCore.JsonPatch patchDoc.ApplyTo(doc); // Assert - Assert.Equal(null, doc.SimpleDTO.StringProperty); + Assert.Null(doc.SimpleDTO.StringProperty); } [Fact] @@ -623,7 +623,7 @@ namespace Microsoft.AspNetCore.JsonPatch deserialized.ApplyTo(doc); // Assert - Assert.Equal(null, doc.SimpleDTO.StringProperty); + Assert.Null(doc.SimpleDTO.StringProperty); } [Fact] @@ -1796,7 +1796,7 @@ namespace Microsoft.AspNetCore.JsonPatch // Assert Assert.Equal("A", doc.SimpleDTO.AnotherStringProperty); - Assert.Equal(null, doc.SimpleDTO.StringProperty); + Assert.Null(doc.SimpleDTO.StringProperty); } [Fact] @@ -1824,7 +1824,7 @@ namespace Microsoft.AspNetCore.JsonPatch // Assert Assert.Equal("A", doc.SimpleDTO.AnotherStringProperty); - Assert.Equal(null, doc.SimpleDTO.StringProperty); + Assert.Null(doc.SimpleDTO.StringProperty); } [Fact] @@ -1858,7 +1858,7 @@ namespace Microsoft.AspNetCore.JsonPatch Assert.Equal("C", doc.SimpleDTO.StringProperty); Assert.Equal("D", doc.SimpleDTO.AnotherStringProperty); Assert.Same(iDto, doc.SimpleDTO); - Assert.Equal(null, doc.InheritedDTO); + Assert.Null(doc.InheritedDTO); } [Fact] @@ -1895,7 +1895,7 @@ namespace Microsoft.AspNetCore.JsonPatch Assert.Equal("C", doc.SimpleDTO.StringProperty); Assert.Equal("D", doc.SimpleDTO.AnotherStringProperty); Assert.Same(iDto, doc.SimpleDTO); - Assert.Equal(null, doc.InheritedDTO); + Assert.Null(doc.InheritedDTO); } [Fact] @@ -2269,4 +2269,4 @@ namespace Microsoft.AspNetCore.JsonPatch Assert.Equal(new List() { 1, 2, 3, 5 }, doc.SimpleDTO.IntegerList); } } -} \ No newline at end of file +} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs index d14daadbff..56b25d22be 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs @@ -377,7 +377,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters patchDoc.ApplyTo(doc); // Assert - Assert.Equal(null, doc.StringProperty); + Assert.Null(doc.StringProperty); } [Fact] @@ -400,7 +400,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters deserialized.ApplyTo(doc); // Assert - Assert.Equal(null, doc.StringProperty); + Assert.Null(doc.StringProperty); } [Fact] @@ -654,7 +654,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters // Arrange var doc = new SimpleDTOWithNullCheck() { - StringProperty = "A", + StringProperty = "A", }; // create patch @@ -720,8 +720,8 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters var serialized = JsonConvert.SerializeObject(patchDoc); // Assert - Assert.Equal(false, serialized.Contains("operations")); - Assert.Equal(false, serialized.Contains("Operations")); + Assert.False(serialized.Contains("operations")); + Assert.False(serialized.Contains("Operations")); } [Fact] @@ -864,7 +864,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters // Assert Assert.Equal(1, doc.SimpleDTO.DoubleValue); Assert.Equal(0, doc.SimpleDTO.IntegerValue); - Assert.Equal(null, doc.SimpleDTO.IntegerList); + Assert.Null(doc.SimpleDTO.IntegerList); } [Fact] @@ -1460,7 +1460,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters // Assert Assert.Equal("A", doc.AnotherStringProperty); - Assert.Equal(null, doc.StringProperty); + Assert.Null(doc.StringProperty); } [Fact] @@ -1485,7 +1485,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters // Assert Assert.Equal("A", doc.AnotherStringProperty); - Assert.Equal(null, doc.StringProperty); + Assert.Null(doc.StringProperty); } [Fact] @@ -2283,7 +2283,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters deserialized.ApplyTo(doc); // Assert - Assert.Equal(null, doc.StringProperty); + Assert.Null(doc.StringProperty); } class ClassWithPrivateProperties @@ -2308,8 +2308,8 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters // Act & Assert var exception = Assert.Throws(() => patchDoc.ApplyTo(doc)); Assert.Equal( - string.Format("The target location specified by path segment '{0}' was not found.", "Age"), + string.Format("The target location specified by path segment '{0}' was not found.", "Age"), exception.Message); } } -} \ No newline at end of file +} From e3114dc6a41be48dfeff17306fad428670c0f550 Mon Sep 17 00:00:00 2001 From: Kiran Challa Date: Fri, 19 May 2017 13:44:15 -0700 Subject: [PATCH 216/471] Temporarily change tfm to netstandard1.3 Ideally we want to target netstandard2.0 but this conversion is blocked on the issue: https://github.com/dotnet/sdk/issues/1219 --- build/dependencies.props | 1 + .../Microsoft.AspNetCore.JsonPatch.csproj | 4 +++- .../Microsoft.AspNetCore.JsonPatch.Test.csproj | 3 ++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 3abab6008e..0011678b86 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,6 +1,7 @@ 2.0.0-* + 4.3.0 2.1.0-* 10.0.1 4.7.1 diff --git a/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj b/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj index f9c60761bf..3e275fe102 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj +++ b/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj @@ -3,13 +3,15 @@ ASP.NET Core support for JSON PATCH. - netcoreapp2.0 + netstandard1.3 $(NoWarn);CS1591 true aspnetcore;json;jsonpatch + + diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj index 29a1f7dbed..f5b8c8268a 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj @@ -3,7 +3,8 @@ - netcoreapp2.0 + netcoreapp2.0;net461 + netcoreapp2.0 From 46dd25fcac69c32ddce56931ebc082b5dc0a7897 Mon Sep 17 00:00:00 2001 From: Kiran Challa Date: Fri, 26 May 2017 12:40:38 -0700 Subject: [PATCH 217/471] Updated to use the latest shared runtime --- build/dependencies.props | 1 + 1 file changed, 1 insertion(+) diff --git a/build/dependencies.props b/build/dependencies.props index ed2c89867f..e9ed2ba5bf 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,6 +4,7 @@ 4.3.0 2.1.0-* $(BundledNETStandardPackageVersion) + 2.0.0-* 15.3.0-* 2.3.0-beta2-* From 758006d17f7d6accea730627d451a8d0c6b731cf Mon Sep 17 00:00:00 2001 From: Kiran Challa Date: Fri, 26 May 2017 12:41:43 -0700 Subject: [PATCH 218/471] Updated to use the latest shared runtime --- build/dependencies.props | 1 + 1 file changed, 1 insertion(+) diff --git a/build/dependencies.props b/build/dependencies.props index 0011678b86..55f77f78f3 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -6,6 +6,7 @@ 10.0.1 4.7.1 $(BundledNETStandardPackageVersion) + 2.0.0-* 15.3.0-* 2.3.0-beta2-* From 3cae8795d4aca9a03d37a41a13f484dd96c79ab4 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 31 May 2017 19:36:37 -0700 Subject: [PATCH 219/471] Branching for rel/2.0.0-preview2 --- NuGet.config | 7 ++++--- build/dependencies.props | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/NuGet.config b/NuGet.config index 8e65695611..c4bc056c4d 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,8 +1,9 @@ - + - + + - + \ No newline at end of file diff --git a/build/dependencies.props b/build/dependencies.props index e9ed2ba5bf..fa6f8711f8 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,6 +1,6 @@ - 2.0.0-* + 2.0.0-preview2-* 4.3.0 2.1.0-* $(BundledNETStandardPackageVersion) From 14c35c1faef0d2afe1e5d2a93b888ff66100769d Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 31 May 2017 19:36:49 -0700 Subject: [PATCH 220/471] Branching for rel/2.0.0-preview2 --- NuGet.config | 5 +++-- build/dependencies.props | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/NuGet.config b/NuGet.config index 93f1ac47df..c4bc056c4d 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,8 +1,9 @@  - + + - + \ No newline at end of file diff --git a/build/dependencies.props b/build/dependencies.props index 55f77f78f3..2b3acda9ac 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,6 +1,6 @@ - 2.0.0-* + 2.0.0-preview2-* 4.3.0 2.1.0-* 10.0.1 From 7e436ef3ce5e12eedf75b1638509d5629da7325a Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 31 May 2017 19:53:20 -0700 Subject: [PATCH 221/471] Updating build scripts to point to 2.0.0-preview2 KoreBuild --- build.ps1 | 2 +- build.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.ps1 b/build.ps1 index 5bf0e2c113..3a2476b2b4 100644 --- a/build.ps1 +++ b/build.ps1 @@ -33,7 +33,7 @@ cd $PSScriptRoot $repoFolder = $PSScriptRoot $env:REPO_FOLDER = $repoFolder -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/2.0.0-preview2.zip" if ($env:KOREBUILD_ZIP) { $koreBuildZip=$env:KOREBUILD_ZIP diff --git a/build.sh b/build.sh index b0bcadb579..a40bdb87b1 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/2.0.0-preview2.zip" if [ ! -z $KOREBUILD_ZIP ]; then koreBuildZip=$KOREBUILD_ZIP fi From b647c68176a5a6e71906c16fc5c5e9f741fb1f87 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 31 May 2017 19:53:23 -0700 Subject: [PATCH 222/471] Updating build scripts to point to 2.0.0-preview2 KoreBuild --- build.ps1 | 2 +- build.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.ps1 b/build.ps1 index 5bf0e2c113..3a2476b2b4 100644 --- a/build.ps1 +++ b/build.ps1 @@ -33,7 +33,7 @@ cd $PSScriptRoot $repoFolder = $PSScriptRoot $env:REPO_FOLDER = $repoFolder -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/2.0.0-preview2.zip" if ($env:KOREBUILD_ZIP) { $koreBuildZip=$env:KOREBUILD_ZIP diff --git a/build.sh b/build.sh index b0bcadb579..a40bdb87b1 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/2.0.0-preview2.zip" if [ ! -z $KOREBUILD_ZIP ]; then koreBuildZip=$KOREBUILD_ZIP fi From b52a081f1998d58791b7efbf874aa46e199db410 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 1 Jun 2017 10:47:02 -0700 Subject: [PATCH 223/471] Updating versions to preview3 --- NuGet.config | 3 ++- version.props | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/NuGet.config b/NuGet.config index 8e65695611..4e8a1f6de1 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,6 +1,7 @@ - + + diff --git a/version.props b/version.props index 6af4f81de2..193a5999d8 100644 --- a/version.props +++ b/version.props @@ -2,6 +2,6 @@ 2.0.0 - preview2 + preview3 From f66166f6bc4165b01ba1d7fb3682ca99feb488a7 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 1 Jun 2017 10:47:14 -0700 Subject: [PATCH 224/471] Updating versions to preview3 --- NuGet.config | 1 + version.props | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/NuGet.config b/NuGet.config index 93f1ac47df..4e8a1f6de1 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,6 +1,7 @@  + diff --git a/version.props b/version.props index 0b2b8e0010..90a2f5b5cc 100644 --- a/version.props +++ b/version.props @@ -2,6 +2,6 @@ 2.0.0 - preview2 + preview3 \ No newline at end of file From d9531031a869cab74d412ecfb396ce1b0797c301 Mon Sep 17 00:00:00 2001 From: Kiran Challa Date: Tue, 6 Jun 2017 10:28:19 -0700 Subject: [PATCH 225/471] Updated to netstandard2.0 --- build/dependencies.props | 3 ++- .../Microsoft.AspNetCore.JsonPatch.csproj | 3 +-- .../Microsoft.AspNetCore.JsonPatch.Test.csproj | 4 ++++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 2b3acda9ac..9a1d9569a2 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,10 +1,11 @@ 2.0.0-preview2-* - 4.3.0 + 4.4.0-* 2.1.0-* 10.0.1 4.7.1 + 2.0.0-* $(BundledNETStandardPackageVersion) 2.0.0-* 15.3.0-* diff --git a/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj b/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj index 3e275fe102..e9732e8621 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj +++ b/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj @@ -3,7 +3,7 @@ ASP.NET Core support for JSON PATCH. - netstandard1.3 + netstandard2.0 $(NoWarn);CS1591 true aspnetcore;json;jsonpatch @@ -11,7 +11,6 @@ - diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj index f5b8c8268a..d5bb8d950f 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj @@ -7,6 +7,10 @@ netcoreapp2.0 + + + + From ccef6b261b94394aa34a68aa5faf2a8c533ca2fe Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 7 Jun 2017 09:41:23 -0700 Subject: [PATCH 226/471] Lift Microsoft.Extensions.WebEncoders to target .NET Standard 2.0 --- build/common.props | 4 ++++ build/dependencies.props | 3 ++- .../Microsoft.AspNetCore.Html.Abstractions.csproj | 1 - .../Microsoft.Extensions.WebEncoders.csproj | 2 +- .../Microsoft.AspNetCore.Html.Abstractions.Test.csproj | 2 +- .../Microsoft.Extensions.WebEncoders.Tests.csproj | 2 +- 6 files changed, 9 insertions(+), 5 deletions(-) diff --git a/build/common.props b/build/common.props index 647ef2d1e9..da05c181bb 100644 --- a/build/common.props +++ b/build/common.props @@ -15,4 +15,8 @@ + + + + diff --git a/build/dependencies.props b/build/dependencies.props index e9ed2ba5bf..583adadec1 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,9 +1,10 @@ 2.0.0-* - 4.3.0 + 4.4.0-* 2.1.0-* $(BundledNETStandardPackageVersion) + 2.0.0-* 2.0.0-* 15.3.0-* 2.3.0-beta2-* diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.csproj b/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.csproj index 85948d6df7..246b2515a2 100755 --- a/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.csproj +++ b/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.csproj @@ -9,7 +9,6 @@ Commonly used types: Microsoft.AspNetCore.Html.HtmlString Microsoft.AspNetCore.Html.IHtmlContent netstandard1.0 - $(NoWarn);CS1591 true aspnetcore diff --git a/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.csproj b/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.csproj index 773011fef5..de62d482f9 100755 --- a/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.csproj +++ b/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.csproj @@ -5,7 +5,7 @@ Microsoft .NET Extensions Contains registration and configuration APIs to add the core framework encoders to a dependency injection container. - netstandard1.1 + netstandard2.0 $(NoWarn);CS1591 true true diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.csproj b/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.csproj index ac305ecf01..5030f90ad5 100755 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.csproj +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.csproj @@ -3,7 +3,7 @@ - netcoreapp2.0;net46 + netcoreapp2.0;net461 netcoreapp2.0 diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj b/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj index 94bc15926e..19406979f2 100755 --- a/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj +++ b/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj @@ -3,7 +3,7 @@ - netcoreapp2.0;net46 + netcoreapp2.0;net461 netcoreapp2.0 From f12054dfa7b38a7cccc7a63ad298f0e00d359365 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Thu, 8 Jun 2017 12:58:50 -0700 Subject: [PATCH 227/471] Update Microsoft.AspNetCore.HtmlAbstractions to .NET Standard 2.0 --- build/dependencies.props | 2 +- .../Microsoft.AspNetCore.Html.Abstractions.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 583adadec1..c81696f7f4 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,7 +3,7 @@ 2.0.0-* 4.4.0-* 2.1.0-* - $(BundledNETStandardPackageVersion) + 2.0.0-* 2.0.0-* 2.0.0-* 15.3.0-* diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.csproj b/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.csproj index 246b2515a2..c26d590912 100755 --- a/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.csproj +++ b/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.csproj @@ -8,7 +8,7 @@ Commonly used types: Microsoft.AspNetCore.Html.HtmlString Microsoft.AspNetCore.Html.IHtmlContent - netstandard1.0 + netstandard2.0 true aspnetcore From cfb7ae413f811e54ade3db99fb468b8629676a81 Mon Sep 17 00:00:00 2001 From: Kiran Challa Date: Thu, 15 Jun 2017 05:07:52 -0700 Subject: [PATCH 228/471] Updated NETStandardImplicitPackageVersion to 2.0.0-* from BundledNETStandardPackageVersion --- NuGet.config | 1 + build/common.props | 2 +- build/dependencies.props | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/NuGet.config b/NuGet.config index 4e8a1f6de1..42f3f72326 100644 --- a/NuGet.config +++ b/NuGet.config @@ -3,6 +3,7 @@ + diff --git a/build/common.props b/build/common.props index a2698f3553..9f0faa97ad 100644 --- a/build/common.props +++ b/build/common.props @@ -17,7 +17,7 @@ - + diff --git a/build/dependencies.props b/build/dependencies.props index 5e815355d7..33e05e9df0 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -6,7 +6,7 @@ 10.0.1 4.7.1 2.0.0-* - $(BundledNETStandardPackageVersion) + 2.0.0-* 2.0.0-* 15.3.0-* 2.3.0-beta2-* From a8b6fa757a3ae49bfe02e0c75bb30006eb404d10 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 16 Jun 2017 08:19:31 -0700 Subject: [PATCH 229/471] Remove dotnet-core feed from NuGet.config --- NuGet.config | 1 - 1 file changed, 1 deletion(-) diff --git a/NuGet.config b/NuGet.config index 42f3f72326..4e8a1f6de1 100644 --- a/NuGet.config +++ b/NuGet.config @@ -3,7 +3,6 @@ - From c816bce13a1f6eb0fc529a56dd1801d3221faafb Mon Sep 17 00:00:00 2001 From: Jass Bagga Date: Wed, 21 Jun 2017 12:35:31 -0700 Subject: [PATCH 230/471] Refactor invalid operation exception handling (#87) Addresses part of #80 --- .../Operations/OperationBase.cs | 31 +++++++++----- .../Operations/OperationOfT.cs | 3 ++ .../Operations/OperationType.cs | 3 +- .../OperationBaseTests.cs | 41 +++++++++++++++++++ 4 files changed, 67 insertions(+), 11 deletions(-) create mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/OperationBaseTests.cs diff --git a/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationBase.cs b/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationBase.cs index eb35fa7e9d..e629e2308d 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationBase.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationBase.cs @@ -2,26 +2,21 @@ // 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; using Newtonsoft.Json; namespace Microsoft.AspNetCore.JsonPatch.Operations { public class OperationBase { + private string _op; + private OperationType _operationType; + [JsonIgnore] public OperationType OperationType { get { - OperationType result; - if (!Enum.TryParse(op, ignoreCase: true, result: out result)) - { - throw new JsonPatchException( - Resources.FormatInvalidJsonPatchOperation(op), - innerException: null); - } - return result; + return _operationType; } } @@ -29,7 +24,23 @@ namespace Microsoft.AspNetCore.JsonPatch.Operations public string path { get; set; } [JsonProperty("op")] - public string op { get; set; } + 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; } diff --git a/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationOfT.cs b/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationOfT.cs index 5af4f5d3f9..7189cf8210 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationOfT.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationOfT.cs @@ -75,6 +75,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Operations break; case OperationType.Test: throw new JsonPatchException(new JsonPatchError(objectToApplyTo, this, Resources.TestOperationNotSupported)); + case OperationType.Invalid: + throw new JsonPatchException( + Resources.FormatInvalidJsonPatchOperation(op), innerException: null); default: break; } diff --git a/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationType.cs b/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationType.cs index 846b07019f..725646df3a 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationType.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationType.cs @@ -10,6 +10,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Operations Replace, Move, Copy, - Test + Test, + Invalid } } \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/OperationBaseTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/OperationBaseTests.cs new file mode 100644 index 0000000000..955344404f --- /dev/null +++ b/test/Microsoft.AspNetCore.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); + } + } +} From 16b9c59ac364950cb74a9bb49b14d25aa5126fb2 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Mon, 26 Jun 2017 09:37:33 -0700 Subject: [PATCH 231/471] Adding libunwind8 to .travis.yml [skip appveyor] --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 2a46104677..b10be14215 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,10 @@ os: - linux - osx osx_image: xcode8.2 +addons: + apt: + packages: + - libunwind8 branches: only: - master From 877e458da066c42ab84f067de49e9fbddd849238 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Mon, 26 Jun 2017 09:38:31 -0700 Subject: [PATCH 232/471] Adding libunwind8 to .travis.yml [skip appveyor] --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 2a46104677..b10be14215 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,10 @@ os: - linux - osx osx_image: xcode8.2 +addons: + apt: + packages: + - libunwind8 branches: only: - master From d7bdf1d4e4f2415c9ea3f50c06679b35522d4bf4 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 29 Jun 2017 08:18:18 -0700 Subject: [PATCH 233/471] Update dependencies.props * Update Moq to 4.7.49. * Add NETStandardImplicitPackageVersion --- build/dependencies.props | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 33e05e9df0..22b77634a0 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,10 +1,11 @@ - + 2.0.0-* 4.4.0-* 2.1.0-* 10.0.1 - 4.7.1 + 4.7.49 + 2.0.0-* 2.0.0-* 2.0.0-* 2.0.0-* From 0704198e554cb0b4407063a1c4c578b48ba32c71 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 3 Jul 2017 14:05:58 -0700 Subject: [PATCH 234/471] Update LICENSE.txt text --- LICENSE.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/LICENSE.txt b/LICENSE.txt index 0bdc1962b6..7b2956ecee 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,10 +1,12 @@ -Copyright (c) .NET Foundation. All rights reserved. +Copyright (c) .NET Foundation and Contributors + +All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use -these files except in compliance with the License. You may obtain a copy of the +this file except in compliance with the License. You may obtain a copy of the License at -http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR From fbfdbf4fe905898d18d119b2729bb5f25d8788b8 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 3 Jul 2017 14:06:32 -0700 Subject: [PATCH 235/471] Update LICENSE.txt text --- LICENSE.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/LICENSE.txt b/LICENSE.txt index 0bdc1962b6..7b2956ecee 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,10 +1,12 @@ -Copyright (c) .NET Foundation. All rights reserved. +Copyright (c) .NET Foundation and Contributors + +All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use -these files except in compliance with the License. You may obtain a copy of the +this file except in compliance with the License. You may obtain a copy of the License at -http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR From 6849a49905ce6febe8699f831514e926a88c11d9 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Thu, 6 Jul 2017 10:37:33 -0700 Subject: [PATCH 236/471] React to aspnet/BuildTools#293 [ci skip] --- build/dependencies.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/dependencies.props b/build/dependencies.props index c81696f7f4..b4bc781894 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -2,7 +2,7 @@ 2.0.0-* 4.4.0-* - 2.1.0-* + 2.0.1-* 2.0.0-* 2.0.0-* 2.0.0-* From 4d87a52f6e6b7d360e1fa4fd950a8bc127e59cff Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Thu, 6 Jul 2017 10:38:05 -0700 Subject: [PATCH 237/471] React to aspnet/BuildTools#293 [ci skip] --- build/dependencies.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/dependencies.props b/build/dependencies.props index 22b77634a0..624ea78685 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -2,7 +2,7 @@ 2.0.0-* 4.4.0-* - 2.1.0-* + 2.0.1-* 10.0.1 4.7.49 2.0.0-* From bcbfe745f4c649f1a7b3cda62eb0d75dec661ca6 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Thu, 6 Jul 2017 12:12:21 -0700 Subject: [PATCH 238/471] Set "TreatWarningsAsErrors" before NuGet restore * Ensures our build stays clean of NuGet warnings --- build/common.props | 1 + 1 file changed, 1 insertion(+) diff --git a/build/common.props b/build/common.props index da05c181bb..7abb374f12 100644 --- a/build/common.props +++ b/build/common.props @@ -9,6 +9,7 @@ true true $(VersionSuffix)-$(BuildNumber) + true From 2a2326dec94d569e27c839de7a79e3d2a1412714 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Thu, 6 Jul 2017 12:16:57 -0700 Subject: [PATCH 239/471] Set "TreatWarningsAsErrors" before NuGet restore * Ensures our build stays clean of NuGet warnings --- build/common.props | 1 + 1 file changed, 1 insertion(+) diff --git a/build/common.props b/build/common.props index 9f0faa97ad..c00767473e 100644 --- a/build/common.props +++ b/build/common.props @@ -10,6 +10,7 @@ true true $(VersionSuffix)-$(BuildNumber) + true From 3d92b581e710b61c2d95c0826eb0f1a0090b1ccf Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 6 Jul 2017 15:08:18 -0700 Subject: [PATCH 240/471] Update version suffix for 2.0.0 RTM release --- version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.props b/version.props index 193a5999d8..eba6b16756 100644 --- a/version.props +++ b/version.props @@ -2,6 +2,6 @@ 2.0.0 - preview3 + rtm From bd90271c85460f93fb3a067cd1c55315fc71618b Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 6 Jul 2017 15:08:27 -0700 Subject: [PATCH 241/471] Update version suffix for 2.0.0 RTM release --- version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.props b/version.props index 90a2f5b5cc..b94223e008 100644 --- a/version.props +++ b/version.props @@ -2,6 +2,6 @@ 2.0.0 - preview3 + rtm \ No newline at end of file From e4f3b9d624d8cf3fff8edd281defdb610a33b7f2 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Thu, 6 Jul 2017 15:28:29 -0700 Subject: [PATCH 242/471] Remove NETSTandard.Library.NETFramework --- .../Microsoft.AspNetCore.JsonPatch.Test.csproj | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj index d5bb8d950f..f5b8c8268a 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj @@ -7,10 +7,6 @@ netcoreapp2.0 - - - - From 615f9d1743db0839ae027047efbcdeef438f0445 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Thu, 6 Jul 2017 15:51:42 -0700 Subject: [PATCH 243/471] Remove NETStandard.Library.NETFramework --- build/common.props | 4 ---- 1 file changed, 4 deletions(-) diff --git a/build/common.props b/build/common.props index 7abb374f12..83647293aa 100644 --- a/build/common.props +++ b/build/common.props @@ -16,8 +16,4 @@ - - - - From b4afc95b281d8f2bee775ee58bf4b028e9a0c009 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 10 Jul 2017 11:42:52 -0700 Subject: [PATCH 244/471] Branching for 2.0.0 rtm --- NuGet.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NuGet.config b/NuGet.config index 4e8a1f6de1..37f0d27ea0 100644 --- a/NuGet.config +++ b/NuGet.config @@ -2,7 +2,7 @@ - + From 28801a17e7786daabd31cd27665cb988495a772d Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 10 Jul 2017 11:43:45 -0700 Subject: [PATCH 245/471] Branching for 2.0.0 rtm --- NuGet.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NuGet.config b/NuGet.config index 4e8a1f6de1..37f0d27ea0 100644 --- a/NuGet.config +++ b/NuGet.config @@ -2,7 +2,7 @@ - + From 1fbbf5e72ff21df8418224b2d4ecd07ff3fcbefd Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 10 Jul 2017 11:57:57 -0700 Subject: [PATCH 246/471] Updating KoreBuild branch --- build.ps1 | 2 +- build.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.ps1 b/build.ps1 index 5bf0e2c113..1785334385 100644 --- a/build.ps1 +++ b/build.ps1 @@ -33,7 +33,7 @@ cd $PSScriptRoot $repoFolder = $PSScriptRoot $env:REPO_FOLDER = $repoFolder -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/2.0.0.zip" if ($env:KOREBUILD_ZIP) { $koreBuildZip=$env:KOREBUILD_ZIP diff --git a/build.sh b/build.sh index b0bcadb579..5e27ed8efb 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/2.0.0.zip" if [ ! -z $KOREBUILD_ZIP ]; then koreBuildZip=$KOREBUILD_ZIP fi From 1481037d6ec436fd6d290bef5deeb115099d96e1 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 10 Jul 2017 11:57:58 -0700 Subject: [PATCH 247/471] Updating KoreBuild branch --- build.ps1 | 2 +- build.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.ps1 b/build.ps1 index 5bf0e2c113..1785334385 100644 --- a/build.ps1 +++ b/build.ps1 @@ -33,7 +33,7 @@ cd $PSScriptRoot $repoFolder = $PSScriptRoot $env:REPO_FOLDER = $repoFolder -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/2.0.0.zip" if ($env:KOREBUILD_ZIP) { $koreBuildZip=$env:KOREBUILD_ZIP diff --git a/build.sh b/build.sh index b0bcadb579..5e27ed8efb 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/2.0.0.zip" if [ ! -z $KOREBUILD_ZIP ]; then koreBuildZip=$KOREBUILD_ZIP fi From 8f13caf33f263f76f72d2ab0f356e9c30bc09905 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Fri, 7 Jul 2017 14:56:16 -0700 Subject: [PATCH 248/471] Skip first time experience on Appveyor --- appveyor.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 1041615c68..31efd8196f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -init: +init: - git config --global core.autocrlf true branches: only: @@ -9,6 +9,10 @@ branches: build_script: - ps: .\build.ps1 clone_depth: 1 +environment: + global: + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + DOTNET_CLI_TELEMETRY_OPTOUT: 1 test: off deploy: off os: Visual Studio 2017 From e9d7403c6f8f5d1cb3172d5ebcbc0eb498cdae65 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Fri, 7 Jul 2017 14:55:40 -0700 Subject: [PATCH 249/471] Skip first time experience on Appveyor --- appveyor.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 1041615c68..31efd8196f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -init: +init: - git config --global core.autocrlf true branches: only: @@ -9,6 +9,10 @@ branches: build_script: - ps: .\build.ps1 clone_depth: 1 +environment: + global: + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + DOTNET_CLI_TELEMETRY_OPTOUT: 1 test: off deploy: off os: Visual Studio 2017 From 465f09b3364a551771b6a3d5a22c344ec650dd0e Mon Sep 17 00:00:00 2001 From: Mike Harder Date: Wed, 19 Jul 2017 09:38:17 -0700 Subject: [PATCH 250/471] Remove duplicate NETStandardImplicitPackageVersion (#95) --- build/dependencies.props | 1 - 1 file changed, 1 deletion(-) diff --git a/build/dependencies.props b/build/dependencies.props index 624ea78685..f04855911e 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -7,7 +7,6 @@ 4.7.49 2.0.0-* 2.0.0-* - 2.0.0-* 2.0.0-* 15.3.0-* 2.3.0-beta2-* From de5d7de12469c312992cf2e9867314ee91a2622e Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Fri, 21 Jul 2017 12:59:18 -0700 Subject: [PATCH 251/471] 2.0.0-rtm to 2.1.0-preview1 --- version.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.props b/version.props index eba6b16756..1ea46af42a 100644 --- a/version.props +++ b/version.props @@ -1,7 +1,7 @@ - 2.0.0 - rtm + 2.1.0 + preview1 From 7f2a1def984a685f1ed39a70cf47c6cc868f0914 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Fri, 21 Jul 2017 13:00:17 -0700 Subject: [PATCH 252/471] 2.0.0-rtm to 2.1.0-preview1 --- version.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.props b/version.props index b94223e008..cb77b43933 100644 --- a/version.props +++ b/version.props @@ -1,7 +1,7 @@ - 2.0.0 - rtm + 2.1.0 + preview1 \ No newline at end of file From 2ac5f3617e9bd157e08d701429abb8b5943fe720 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Mon, 24 Jul 2017 17:56:12 -0700 Subject: [PATCH 253/471] Set AspNetCoreVersion --- build/dependencies.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/dependencies.props b/build/dependencies.props index b4bc781894..833d909a0d 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,6 +1,6 @@ - 2.0.0-* + 2.1.0-* 4.4.0-* 2.0.1-* 2.0.0-* From db9eee83b78e20d32232e60c382cea006265aa9c Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Mon, 24 Jul 2017 17:56:54 -0700 Subject: [PATCH 254/471] Set AspNetCoreVersion --- build/dependencies.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index f04855911e..0071bd6d24 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,6 +1,6 @@ - + - 2.0.0-* + 2.1.0-* 4.4.0-* 2.0.1-* 10.0.1 From 7d5f3511d1e837a8760a5916c3ce657964cd9e53 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 25 Jul 2017 15:13:18 -0700 Subject: [PATCH 255/471] Updating to InternalAspNetCoreSdkVersion 2.1.1-* --- build/dependencies.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/dependencies.props b/build/dependencies.props index 833d909a0d..3c71bd378d 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -2,7 +2,7 @@ 2.1.0-* 4.4.0-* - 2.0.1-* + 2.1.1-* 2.0.0-* 2.0.0-* 2.0.0-* From eaefe914eace7fa16e8deb497f07d313fbc0b366 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 25 Jul 2017 15:13:44 -0700 Subject: [PATCH 256/471] Updating to InternalAspNetCoreSdkVersion 2.1.1-* --- build/dependencies.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/dependencies.props b/build/dependencies.props index 0071bd6d24..f2fb071ace 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -2,7 +2,7 @@ 2.1.0-* 4.4.0-* - 2.0.1-* + 2.1.1-* 10.0.1 4.7.49 2.0.0-* From 4b747a75bded9ef1e8648f98f640d0096b631044 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 25 Jul 2017 16:32:07 -0700 Subject: [PATCH 257/471] Update bootstrappers to use the compiled version of KoreBuild [ci skip] --- .gitignore | 1 + build.cmd | 2 +- build.ps1 | 218 +++++++++++++++++++++++++--------- build.sh | 224 +++++++++++++++++++++++++++++------ build/common.props | 2 +- version.props => version.xml | 3 +- 6 files changed, 356 insertions(+), 94 deletions(-) rename version.props => version.xml (55%) diff --git a/.gitignore b/.gitignore index 6da3c6a3e9..a7fdfd773b 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,4 @@ node_modules .build/ .testPublish/ global.json +korebuild-lock.txt diff --git a/build.cmd b/build.cmd index 7d4894cb4a..b6c8d24864 100644 --- a/build.cmd +++ b/build.cmd @@ -1,2 +1,2 @@ @ECHO OFF -PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0build.ps1' %*; exit $LASTEXITCODE" \ No newline at end of file +PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0build.ps1' %*; exit $LASTEXITCODE" diff --git a/build.ps1 b/build.ps1 index 5bf0e2c113..d5eb4d5cf2 100644 --- a/build.ps1 +++ b/build.ps1 @@ -1,67 +1,177 @@ -$ErrorActionPreference = "Stop" +#!/usr/bin/env powershell +#requires -version 4 -function DownloadWithRetry([string] $url, [string] $downloadLocation, [int] $retries) -{ - while($true) - { - try - { - Invoke-WebRequest $url -OutFile $downloadLocation - break - } - catch - { - $exceptionMessage = $_.Exception.Message - Write-Host "Failed to download '$url': $exceptionMessage" - if ($retries -gt 0) { - $retries-- - Write-Host "Waiting 10 seconds before retrying. Retries left: $retries" - Start-Sleep -Seconds 10 +<# +.SYNOPSIS +Build this repository +.DESCRIPTION +Downloads korebuild if required. Then builds the repository. + +.PARAMETER Path +The folder to build. Defaults to the folder containing this script. + +.PARAMETER Channel +The channel of KoreBuild to download. Overrides the value from the config file. + +.PARAMETER DotNetHome +The directory where .NET Core tools will be stored. + +.PARAMETER ToolsSource +The base url where build tools can be downloaded. Overrides the value from the config file. + +.PARAMETER Update +Updates KoreBuild to the latest version even if a lock file is present. + +.PARAMETER ConfigFile +The path to the configuration file that stores values. Defaults to version.xml. + +.PARAMETER MSBuildArgs +Arguments to be passed to MSBuild + +.NOTES +This function will create a file $PSScriptRoot/korebuild-lock.txt. This lock file can be committed to source, but does not have to be. +When the lockfile is not present, KoreBuild will create one using latest available version from $Channel. + +The $ConfigFile is expected to be an XML file. It is optional, and the configuration values in it are optional as well. + +.EXAMPLE +Example config file: +```xml + + + + dev + https://aspnetcore.blob.core.windows.net/buildtools + + +``` +#> +[CmdletBinding(PositionalBinding = $false)] +param( + [string]$Path = $PSScriptRoot, + [Alias('c')] + [string]$Channel, + [Alias('d')] + [string]$DotNetHome, + [Alias('s')] + [string]$ToolsSource, + [Alias('u')] + [switch]$Update, + [string]$ConfigFile = (Join-Path $PSScriptRoot 'version.xml'), + [Parameter(ValueFromRemainingArguments = $true)] + [string[]]$MSBuildArgs +) + +Set-StrictMode -Version 2 +$ErrorActionPreference = 'Stop' + +# +# Functions +# + +function Get-KoreBuild { + + $lockFile = Join-Path $Path 'korebuild-lock.txt' + + if (!(Test-Path $lockFile) -or $Update) { + Get-RemoteFile "$ToolsSource/korebuild/channels/$Channel/latest.txt" $lockFile + } + + $version = Get-Content $lockFile | Where-Object { $_ -like 'version:*' } | Select-Object -first 1 + if (!$version) { + Write-Error "Failed to parse version from $lockFile. Expected a line that begins with 'version:'" + } + $version = $version.TrimStart('version:').Trim() + $korebuildPath = Join-Paths $DotNetHome ('buildtools', 'korebuild', $version) + + if (!(Test-Path $korebuildPath)) { + Write-Host -ForegroundColor Magenta "Downloading KoreBuild $version" + New-Item -ItemType Directory -Path $korebuildPath | Out-Null + $remotePath = "$ToolsSource/korebuild/artifacts/$version/korebuild.$version.zip" + + try { + $tmpfile = Join-Path ([IO.Path]::GetTempPath()) "KoreBuild-$([guid]::NewGuid()).zip" + Get-RemoteFile $remotePath $tmpfile + if (Get-Command -Name 'Expand-Archive' -ErrorAction Ignore) { + # Use built-in commands where possible as they are cross-plat compatible + Expand-Archive -Path $tmpfile -DestinationPath $korebuildPath } - else - { - $exception = $_.Exception - throw $exception + else { + # Fallback to old approach for old installations of PowerShell + Add-Type -AssemblyName System.IO.Compression.FileSystem + [System.IO.Compression.ZipFile]::ExtractToDirectory($tmpfile, $korebuildPath) } } + catch { + Remove-Item -Recurse -Force $korebuildPath -ErrorAction Ignore + throw + } + finally { + Remove-Item $tmpfile -ErrorAction Ignore + } } + + return $korebuildPath } -cd $PSScriptRoot - -$repoFolder = $PSScriptRoot -$env:REPO_FOLDER = $repoFolder - -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" -if ($env:KOREBUILD_ZIP) -{ - $koreBuildZip=$env:KOREBUILD_ZIP +function Join-Paths([string]$path, [string[]]$childPaths) { + $childPaths | ForEach-Object { $path = Join-Path $path $_ } + return $path } -$buildFolder = ".build" -$buildFile="$buildFolder\KoreBuild.ps1" - -if (!(Test-Path $buildFolder)) { - Write-Host "Downloading KoreBuild from $koreBuildZip" - - $tempFolder=$env:TEMP + "\KoreBuild-" + [guid]::NewGuid() - New-Item -Path "$tempFolder" -Type directory | Out-Null - - $localZipFile="$tempFolder\korebuild.zip" - - DownloadWithRetry -url $koreBuildZip -downloadLocation $localZipFile -retries 6 - - Add-Type -AssemblyName System.IO.Compression.FileSystem - [System.IO.Compression.ZipFile]::ExtractToDirectory($localZipFile, $tempFolder) - - New-Item -Path "$buildFolder" -Type directory | Out-Null - copy-item "$tempFolder\**\build\*" $buildFolder -Recurse - - # Cleanup - if (Test-Path $tempFolder) { - Remove-Item -Recurse -Force $tempFolder +function Get-RemoteFile([string]$RemotePath, [string]$LocalPath) { + if ($RemotePath -notlike 'http*') { + Copy-Item $RemotePath $LocalPath + return } + + $retries = 10 + while ($retries -gt 0) { + $retries -= 1 + try { + Invoke-WebRequest -UseBasicParsing -Uri $RemotePath -OutFile $LocalPath + return + } + catch { + Write-Verbose "Request failed. $retries retries remaining" + } + } + + Write-Error "Download failed: '$RemotePath'." } -&"$buildFile" @args +# +# Main +# + +# Load configuration or set defaults + +if (Test-Path $ConfigFile) { + [xml] $config = Get-Content $ConfigFile + if (!($Channel)) { [string] $Channel = Select-Xml -Xml $config -XPath '/Project/PropertyGroup/KoreBuildChannel' } + if (!($ToolsSource)) { [string] $ToolsSource = Select-Xml -Xml $config -XPath '/Project/PropertyGroup/KoreBuildToolsSource' } +} + +if (!$DotNetHome) { + $DotNetHome = if ($env:DOTNET_HOME) { $env:DOTNET_HOME } ` + elseif ($env:USERPROFILE) { Join-Path $env:USERPROFILE '.dotnet'} ` + elseif ($env:HOME) {Join-Path $env:HOME '.dotnet'}` + else { Join-Path $PSScriptRoot '.dotnet'} +} + +if (!$Channel) { $Channel = 'dev' } +if (!$ToolsSource) { $ToolsSource = 'https://aspnetcore.blob.core.windows.net/buildtools' } + +# Execute + +$korebuildPath = Get-KoreBuild +Import-Module -Force -Scope Local (Join-Path $korebuildPath 'KoreBuild.psd1') + +try { + Install-Tools $ToolsSource $DotNetHome + Invoke-RepositoryBuild $Path @MSBuildArgs +} +finally { + Remove-Module 'KoreBuild' -ErrorAction Ignore +} diff --git a/build.sh b/build.sh index b0bcadb579..ab590e62f1 100755 --- a/build.sh +++ b/build.sh @@ -1,46 +1,196 @@ #!/usr/bin/env bash -repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" -if [ ! -z $KOREBUILD_ZIP ]; then - koreBuildZip=$KOREBUILD_ZIP -fi +set -euo pipefail -buildFolder=".build" -buildFile="$buildFolder/KoreBuild.sh" +# +# variables +# -if test ! -d $buildFolder; then - echo "Downloading KoreBuild from $koreBuildZip" +RESET="\033[0m" +RED="\033[0;31m" +MAGENTA="\033[0;95m" +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +[ -z "${DOTNET_HOME:-}"] && DOTNET_HOME="$HOME/.dotnet" +config_file="$DIR/version.xml" +verbose=false +update=false +repo_path="$DIR" +channel='' +tools_source='' - tempFolder="/tmp/KoreBuild-$(uuidgen)" - mkdir $tempFolder +# +# Functions +# +__usage() { + echo "Usage: $(basename ${BASH_SOURCE[0]}) [options] [[--] ...]" + echo "" + echo "Arguments:" + echo " ... Arguments passed to MSBuild. Variable number of arguments allowed." + echo "" + echo "Options:" + echo " --verbose Show verbose output." + echo " -c|--channel The channel of KoreBuild to download. Overrides the value from the config file.." + echo " --config-file TThe path to the configuration file that stores values. Defaults to version.xml." + echo " -d|--dotnet-home The directory where .NET Core tools will be stored. Defaults to '\$DOTNET_HOME' or '\$HOME/.dotnet." + echo " --path The directory to build. Defaults to the directory containing the script." + echo " -s|--tools-source The base url where build tools can be downloaded. Overrides the value from the config file." + echo " -u|--update Update to the latest KoreBuild even if the lock file is present." + echo "" + echo "Description:" + echo " This function will create a file \$DIR/korebuild-lock.txt. This lock file can be committed to source, but does not have to be." + echo " When the lockfile is not present, KoreBuild will create one using latest available version from \$channel." - localZipFile="$tempFolder/korebuild.zip" - - retries=6 - until (wget -O $localZipFile $koreBuildZip 2>/dev/null || curl -o $localZipFile --location $koreBuildZip 2>/dev/null) - do - echo "Failed to download '$koreBuildZip'" - if [ "$retries" -le 0 ]; then - exit 1 - fi - retries=$((retries - 1)) - echo "Waiting 10 seconds before retrying. Retries left: $retries" - sleep 10s - done - - unzip -q -d $tempFolder $localZipFile - - mkdir $buildFolder - cp -r $tempFolder/**/build/** $buildFolder - - chmod +x $buildFile - - # Cleanup - if test -d $tempFolder; then - rm -rf $tempFolder + if [[ "${1:-}" != '--no-exit' ]]; then + exit 2 fi +} + +get_korebuild() { + local lock_file="$repo_path/korebuild-lock.txt" + if [ ! -f $lock_file ] || [ "$update" = true ]; then + __get_remote_file "$tools_source/korebuild/channels/$channel/latest.txt" $lock_file + fi + local version="$(grep 'version:*' -m 1 $lock_file)" + if [[ "$version" == '' ]]; then + __error "Failed to parse version from $lock_file. Expected a line that begins with 'version:'" + return 1 + fi + version="$(echo ${version#version:} | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" + local korebuild_path="$DOTNET_HOME/buildtools/korebuild/$version" + + { + if [ ! -d "$korebuild_path" ]; then + mkdir -p "$korebuild_path" + local remote_path="$tools_source/korebuild/artifacts/$version/korebuild.$version.zip" + tmpfile="$(mktemp)" + echo -e "${MAGENTA}Downloading KoreBuild ${version}${RESET}" + if __get_remote_file $remote_path $tmpfile; then + unzip -q -d "$korebuild_path" $tmpfile + fi + rm $tmpfile || true + fi + + source "$korebuild_path/KoreBuild.sh" + } || { + if [ -d "$korebuild_path" ]; then + echo "Cleaning up after failed installation" + rm -rf "$korebuild_path" || true + fi + return 1 + } +} + +__error() { + echo -e "${RED}$@${RESET}" 1>&2 +} + +__machine_has() { + hash "$1" > /dev/null 2>&1 + return $? +} + +__get_remote_file() { + local remote_path=$1 + local local_path=$2 + + if [[ "$remote_path" != 'http'* ]]; then + cp $remote_path $local_path + return 0 + fi + + failed=false + if __machine_has wget; then + wget --tries 10 --quiet -O $local_path $remote_path || failed=true + fi + + if [ "$failed" = true ] && __machine_has curl; then + failed=false + curl --retry 10 -sSL -f --create-dirs -o $local_path $remote_path || failed=true + fi + + if [ "$failed" = true ]; then + __error "Download failed: $remote_path" 1>&2 + return 1 + fi +} + +__read_dom () { local IFS=\> ; read -d \< ENTITY CONTENT ;} + +# +# main +# + +while [[ $# > 0 ]]; do + case $1 in + -\?|-h|--help) + __usage --no-exit + exit 0 + ;; + -c|--channel|-Channel) + shift + channel=${1:-} + [ -z "$channel" ] && __usage + ;; + --config-file|-ConfigFile) + shift + config_file="${1:-}" + [ -z "$config_file" ] && __usage + ;; + -d|--dotnet-home|-DotNetHome) + shift + DOTNET_HOME=${1:-} + [ -z "$DOTNET_HOME" ] && __usage + ;; + --path|-Path) + shift + repo_path="${1:-}" + [ -z "$repo_path" ] && __usage + ;; + -s|--tools-source|-ToolsSource) + shift + tools_source="${1:-}" + [ -z "$tools_source" ] && __usage + ;; + -u|--update|-Update) + update=true + ;; + --verbose|-Verbose) + verbose=true + ;; + --) + shift + break + ;; + *) + break + ;; + esac + shift +done + +if ! __machine_has unzip; then + __error 'Missing required command: unzip' + exit 1 fi -$buildFile -r $repoFolder "$@" +if ! __machine_has curl && ! __machine_has wget; then + __error 'Missing required command. Either wget or curl is required.' + exit 1 +fi + +if [ -f $config_file ]; then + comment=false + while __read_dom; do + if [ "$comment" = true ]; then [[ $CONTENT == *'-->'* ]] && comment=false ; continue; fi + if [[ $ENTITY == '!--'* ]]; then comment=true; continue; fi + if [ -z "$channel" ] && [[ $ENTITY == "KoreBuildChannel" ]]; then channel=$CONTENT; fi + if [ -z "$tools_source" ] && [[ $ENTITY == "KoreBuildToolsSource" ]]; then tools_source=$CONTENT; fi + done < $config_file +fi + +[ -z "$channel" ] && channel='dev' +[ -z "$tools_source" ] && tools_source='https://aspnetcore.blob.core.windows.net/buildtools' + +get_korebuild +install_tools "$tools_source" "$DOTNET_HOME" +invoke_repository_build "$repo_path" $@ diff --git a/build/common.props b/build/common.props index 83647293aa..c03e5c1314 100644 --- a/build/common.props +++ b/build/common.props @@ -1,6 +1,6 @@ - + https://github.com/aspnet/HtmlAbstractions diff --git a/version.props b/version.xml similarity index 55% rename from version.props rename to version.xml index 1ea46af42a..3c05022b7d 100644 --- a/version.props +++ b/version.xml @@ -1,6 +1,7 @@ - + + dev 2.1.0 preview1 From b52b1d700ecd22b3437411e6e29d2cba9cca611f Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 25 Jul 2017 16:32:53 -0700 Subject: [PATCH 258/471] Update bootstrappers to use the compiled version of KoreBuild [ci skip] --- .gitignore | 1 + build.cmd | 2 +- build.ps1 | 218 ++++++++++++++++++++++++++++++++----------- build.sh | 224 +++++++++++++++++++++++++++++++++++++-------- build/common.props | 2 +- version.props | 7 -- version.xml | 8 ++ 7 files changed, 362 insertions(+), 100 deletions(-) delete mode 100644 version.props create mode 100644 version.xml diff --git a/.gitignore b/.gitignore index 2e8ec28064..24d990294f 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,4 @@ node_modules *launchSettings.json *.orig global.json +korebuild-lock.txt diff --git a/build.cmd b/build.cmd index 7d4894cb4a..b6c8d24864 100644 --- a/build.cmd +++ b/build.cmd @@ -1,2 +1,2 @@ @ECHO OFF -PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0build.ps1' %*; exit $LASTEXITCODE" \ No newline at end of file +PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0build.ps1' %*; exit $LASTEXITCODE" diff --git a/build.ps1 b/build.ps1 index 5bf0e2c113..d5eb4d5cf2 100644 --- a/build.ps1 +++ b/build.ps1 @@ -1,67 +1,177 @@ -$ErrorActionPreference = "Stop" +#!/usr/bin/env powershell +#requires -version 4 -function DownloadWithRetry([string] $url, [string] $downloadLocation, [int] $retries) -{ - while($true) - { - try - { - Invoke-WebRequest $url -OutFile $downloadLocation - break - } - catch - { - $exceptionMessage = $_.Exception.Message - Write-Host "Failed to download '$url': $exceptionMessage" - if ($retries -gt 0) { - $retries-- - Write-Host "Waiting 10 seconds before retrying. Retries left: $retries" - Start-Sleep -Seconds 10 +<# +.SYNOPSIS +Build this repository +.DESCRIPTION +Downloads korebuild if required. Then builds the repository. + +.PARAMETER Path +The folder to build. Defaults to the folder containing this script. + +.PARAMETER Channel +The channel of KoreBuild to download. Overrides the value from the config file. + +.PARAMETER DotNetHome +The directory where .NET Core tools will be stored. + +.PARAMETER ToolsSource +The base url where build tools can be downloaded. Overrides the value from the config file. + +.PARAMETER Update +Updates KoreBuild to the latest version even if a lock file is present. + +.PARAMETER ConfigFile +The path to the configuration file that stores values. Defaults to version.xml. + +.PARAMETER MSBuildArgs +Arguments to be passed to MSBuild + +.NOTES +This function will create a file $PSScriptRoot/korebuild-lock.txt. This lock file can be committed to source, but does not have to be. +When the lockfile is not present, KoreBuild will create one using latest available version from $Channel. + +The $ConfigFile is expected to be an XML file. It is optional, and the configuration values in it are optional as well. + +.EXAMPLE +Example config file: +```xml + + + + dev + https://aspnetcore.blob.core.windows.net/buildtools + + +``` +#> +[CmdletBinding(PositionalBinding = $false)] +param( + [string]$Path = $PSScriptRoot, + [Alias('c')] + [string]$Channel, + [Alias('d')] + [string]$DotNetHome, + [Alias('s')] + [string]$ToolsSource, + [Alias('u')] + [switch]$Update, + [string]$ConfigFile = (Join-Path $PSScriptRoot 'version.xml'), + [Parameter(ValueFromRemainingArguments = $true)] + [string[]]$MSBuildArgs +) + +Set-StrictMode -Version 2 +$ErrorActionPreference = 'Stop' + +# +# Functions +# + +function Get-KoreBuild { + + $lockFile = Join-Path $Path 'korebuild-lock.txt' + + if (!(Test-Path $lockFile) -or $Update) { + Get-RemoteFile "$ToolsSource/korebuild/channels/$Channel/latest.txt" $lockFile + } + + $version = Get-Content $lockFile | Where-Object { $_ -like 'version:*' } | Select-Object -first 1 + if (!$version) { + Write-Error "Failed to parse version from $lockFile. Expected a line that begins with 'version:'" + } + $version = $version.TrimStart('version:').Trim() + $korebuildPath = Join-Paths $DotNetHome ('buildtools', 'korebuild', $version) + + if (!(Test-Path $korebuildPath)) { + Write-Host -ForegroundColor Magenta "Downloading KoreBuild $version" + New-Item -ItemType Directory -Path $korebuildPath | Out-Null + $remotePath = "$ToolsSource/korebuild/artifacts/$version/korebuild.$version.zip" + + try { + $tmpfile = Join-Path ([IO.Path]::GetTempPath()) "KoreBuild-$([guid]::NewGuid()).zip" + Get-RemoteFile $remotePath $tmpfile + if (Get-Command -Name 'Expand-Archive' -ErrorAction Ignore) { + # Use built-in commands where possible as they are cross-plat compatible + Expand-Archive -Path $tmpfile -DestinationPath $korebuildPath } - else - { - $exception = $_.Exception - throw $exception + else { + # Fallback to old approach for old installations of PowerShell + Add-Type -AssemblyName System.IO.Compression.FileSystem + [System.IO.Compression.ZipFile]::ExtractToDirectory($tmpfile, $korebuildPath) } } + catch { + Remove-Item -Recurse -Force $korebuildPath -ErrorAction Ignore + throw + } + finally { + Remove-Item $tmpfile -ErrorAction Ignore + } } + + return $korebuildPath } -cd $PSScriptRoot - -$repoFolder = $PSScriptRoot -$env:REPO_FOLDER = $repoFolder - -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" -if ($env:KOREBUILD_ZIP) -{ - $koreBuildZip=$env:KOREBUILD_ZIP +function Join-Paths([string]$path, [string[]]$childPaths) { + $childPaths | ForEach-Object { $path = Join-Path $path $_ } + return $path } -$buildFolder = ".build" -$buildFile="$buildFolder\KoreBuild.ps1" - -if (!(Test-Path $buildFolder)) { - Write-Host "Downloading KoreBuild from $koreBuildZip" - - $tempFolder=$env:TEMP + "\KoreBuild-" + [guid]::NewGuid() - New-Item -Path "$tempFolder" -Type directory | Out-Null - - $localZipFile="$tempFolder\korebuild.zip" - - DownloadWithRetry -url $koreBuildZip -downloadLocation $localZipFile -retries 6 - - Add-Type -AssemblyName System.IO.Compression.FileSystem - [System.IO.Compression.ZipFile]::ExtractToDirectory($localZipFile, $tempFolder) - - New-Item -Path "$buildFolder" -Type directory | Out-Null - copy-item "$tempFolder\**\build\*" $buildFolder -Recurse - - # Cleanup - if (Test-Path $tempFolder) { - Remove-Item -Recurse -Force $tempFolder +function Get-RemoteFile([string]$RemotePath, [string]$LocalPath) { + if ($RemotePath -notlike 'http*') { + Copy-Item $RemotePath $LocalPath + return } + + $retries = 10 + while ($retries -gt 0) { + $retries -= 1 + try { + Invoke-WebRequest -UseBasicParsing -Uri $RemotePath -OutFile $LocalPath + return + } + catch { + Write-Verbose "Request failed. $retries retries remaining" + } + } + + Write-Error "Download failed: '$RemotePath'." } -&"$buildFile" @args +# +# Main +# + +# Load configuration or set defaults + +if (Test-Path $ConfigFile) { + [xml] $config = Get-Content $ConfigFile + if (!($Channel)) { [string] $Channel = Select-Xml -Xml $config -XPath '/Project/PropertyGroup/KoreBuildChannel' } + if (!($ToolsSource)) { [string] $ToolsSource = Select-Xml -Xml $config -XPath '/Project/PropertyGroup/KoreBuildToolsSource' } +} + +if (!$DotNetHome) { + $DotNetHome = if ($env:DOTNET_HOME) { $env:DOTNET_HOME } ` + elseif ($env:USERPROFILE) { Join-Path $env:USERPROFILE '.dotnet'} ` + elseif ($env:HOME) {Join-Path $env:HOME '.dotnet'}` + else { Join-Path $PSScriptRoot '.dotnet'} +} + +if (!$Channel) { $Channel = 'dev' } +if (!$ToolsSource) { $ToolsSource = 'https://aspnetcore.blob.core.windows.net/buildtools' } + +# Execute + +$korebuildPath = Get-KoreBuild +Import-Module -Force -Scope Local (Join-Path $korebuildPath 'KoreBuild.psd1') + +try { + Install-Tools $ToolsSource $DotNetHome + Invoke-RepositoryBuild $Path @MSBuildArgs +} +finally { + Remove-Module 'KoreBuild' -ErrorAction Ignore +} diff --git a/build.sh b/build.sh index b0bcadb579..ab590e62f1 100755 --- a/build.sh +++ b/build.sh @@ -1,46 +1,196 @@ #!/usr/bin/env bash -repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" -if [ ! -z $KOREBUILD_ZIP ]; then - koreBuildZip=$KOREBUILD_ZIP -fi +set -euo pipefail -buildFolder=".build" -buildFile="$buildFolder/KoreBuild.sh" +# +# variables +# -if test ! -d $buildFolder; then - echo "Downloading KoreBuild from $koreBuildZip" +RESET="\033[0m" +RED="\033[0;31m" +MAGENTA="\033[0;95m" +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +[ -z "${DOTNET_HOME:-}"] && DOTNET_HOME="$HOME/.dotnet" +config_file="$DIR/version.xml" +verbose=false +update=false +repo_path="$DIR" +channel='' +tools_source='' - tempFolder="/tmp/KoreBuild-$(uuidgen)" - mkdir $tempFolder +# +# Functions +# +__usage() { + echo "Usage: $(basename ${BASH_SOURCE[0]}) [options] [[--] ...]" + echo "" + echo "Arguments:" + echo " ... Arguments passed to MSBuild. Variable number of arguments allowed." + echo "" + echo "Options:" + echo " --verbose Show verbose output." + echo " -c|--channel The channel of KoreBuild to download. Overrides the value from the config file.." + echo " --config-file TThe path to the configuration file that stores values. Defaults to version.xml." + echo " -d|--dotnet-home The directory where .NET Core tools will be stored. Defaults to '\$DOTNET_HOME' or '\$HOME/.dotnet." + echo " --path The directory to build. Defaults to the directory containing the script." + echo " -s|--tools-source The base url where build tools can be downloaded. Overrides the value from the config file." + echo " -u|--update Update to the latest KoreBuild even if the lock file is present." + echo "" + echo "Description:" + echo " This function will create a file \$DIR/korebuild-lock.txt. This lock file can be committed to source, but does not have to be." + echo " When the lockfile is not present, KoreBuild will create one using latest available version from \$channel." - localZipFile="$tempFolder/korebuild.zip" - - retries=6 - until (wget -O $localZipFile $koreBuildZip 2>/dev/null || curl -o $localZipFile --location $koreBuildZip 2>/dev/null) - do - echo "Failed to download '$koreBuildZip'" - if [ "$retries" -le 0 ]; then - exit 1 - fi - retries=$((retries - 1)) - echo "Waiting 10 seconds before retrying. Retries left: $retries" - sleep 10s - done - - unzip -q -d $tempFolder $localZipFile - - mkdir $buildFolder - cp -r $tempFolder/**/build/** $buildFolder - - chmod +x $buildFile - - # Cleanup - if test -d $tempFolder; then - rm -rf $tempFolder + if [[ "${1:-}" != '--no-exit' ]]; then + exit 2 fi +} + +get_korebuild() { + local lock_file="$repo_path/korebuild-lock.txt" + if [ ! -f $lock_file ] || [ "$update" = true ]; then + __get_remote_file "$tools_source/korebuild/channels/$channel/latest.txt" $lock_file + fi + local version="$(grep 'version:*' -m 1 $lock_file)" + if [[ "$version" == '' ]]; then + __error "Failed to parse version from $lock_file. Expected a line that begins with 'version:'" + return 1 + fi + version="$(echo ${version#version:} | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" + local korebuild_path="$DOTNET_HOME/buildtools/korebuild/$version" + + { + if [ ! -d "$korebuild_path" ]; then + mkdir -p "$korebuild_path" + local remote_path="$tools_source/korebuild/artifacts/$version/korebuild.$version.zip" + tmpfile="$(mktemp)" + echo -e "${MAGENTA}Downloading KoreBuild ${version}${RESET}" + if __get_remote_file $remote_path $tmpfile; then + unzip -q -d "$korebuild_path" $tmpfile + fi + rm $tmpfile || true + fi + + source "$korebuild_path/KoreBuild.sh" + } || { + if [ -d "$korebuild_path" ]; then + echo "Cleaning up after failed installation" + rm -rf "$korebuild_path" || true + fi + return 1 + } +} + +__error() { + echo -e "${RED}$@${RESET}" 1>&2 +} + +__machine_has() { + hash "$1" > /dev/null 2>&1 + return $? +} + +__get_remote_file() { + local remote_path=$1 + local local_path=$2 + + if [[ "$remote_path" != 'http'* ]]; then + cp $remote_path $local_path + return 0 + fi + + failed=false + if __machine_has wget; then + wget --tries 10 --quiet -O $local_path $remote_path || failed=true + fi + + if [ "$failed" = true ] && __machine_has curl; then + failed=false + curl --retry 10 -sSL -f --create-dirs -o $local_path $remote_path || failed=true + fi + + if [ "$failed" = true ]; then + __error "Download failed: $remote_path" 1>&2 + return 1 + fi +} + +__read_dom () { local IFS=\> ; read -d \< ENTITY CONTENT ;} + +# +# main +# + +while [[ $# > 0 ]]; do + case $1 in + -\?|-h|--help) + __usage --no-exit + exit 0 + ;; + -c|--channel|-Channel) + shift + channel=${1:-} + [ -z "$channel" ] && __usage + ;; + --config-file|-ConfigFile) + shift + config_file="${1:-}" + [ -z "$config_file" ] && __usage + ;; + -d|--dotnet-home|-DotNetHome) + shift + DOTNET_HOME=${1:-} + [ -z "$DOTNET_HOME" ] && __usage + ;; + --path|-Path) + shift + repo_path="${1:-}" + [ -z "$repo_path" ] && __usage + ;; + -s|--tools-source|-ToolsSource) + shift + tools_source="${1:-}" + [ -z "$tools_source" ] && __usage + ;; + -u|--update|-Update) + update=true + ;; + --verbose|-Verbose) + verbose=true + ;; + --) + shift + break + ;; + *) + break + ;; + esac + shift +done + +if ! __machine_has unzip; then + __error 'Missing required command: unzip' + exit 1 fi -$buildFile -r $repoFolder "$@" +if ! __machine_has curl && ! __machine_has wget; then + __error 'Missing required command. Either wget or curl is required.' + exit 1 +fi + +if [ -f $config_file ]; then + comment=false + while __read_dom; do + if [ "$comment" = true ]; then [[ $CONTENT == *'-->'* ]] && comment=false ; continue; fi + if [[ $ENTITY == '!--'* ]]; then comment=true; continue; fi + if [ -z "$channel" ] && [[ $ENTITY == "KoreBuildChannel" ]]; then channel=$CONTENT; fi + if [ -z "$tools_source" ] && [[ $ENTITY == "KoreBuildToolsSource" ]]; then tools_source=$CONTENT; fi + done < $config_file +fi + +[ -z "$channel" ] && channel='dev' +[ -z "$tools_source" ] && tools_source='https://aspnetcore.blob.core.windows.net/buildtools' + +get_korebuild +install_tools "$tools_source" "$DOTNET_HOME" +invoke_repository_build "$repo_path" $@ diff --git a/build/common.props b/build/common.props index c00767473e..b749c350f1 100644 --- a/build/common.props +++ b/build/common.props @@ -1,6 +1,6 @@ - + Microsoft ASP.NET Core diff --git a/version.props b/version.props deleted file mode 100644 index cb77b43933..0000000000 --- a/version.props +++ /dev/null @@ -1,7 +0,0 @@ - - - - 2.1.0 - preview1 - - \ No newline at end of file diff --git a/version.xml b/version.xml new file mode 100644 index 0000000000..3c05022b7d --- /dev/null +++ b/version.xml @@ -0,0 +1,8 @@ + + + + dev + 2.1.0 + preview1 + + From 9c3d4543f550e9ca985887f72627a2b0d021fe12 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 26 Jul 2017 10:27:33 -0700 Subject: [PATCH 259/471] Fix syntax warning when running build.sh on older versions of bash [ci skip] --- build.sh | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/build.sh b/build.sh index ab590e62f1..5568c6182a 100755 --- a/build.sh +++ b/build.sh @@ -10,7 +10,7 @@ RESET="\033[0m" RED="\033[0;31m" MAGENTA="\033[0;95m" DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -[ -z "${DOTNET_HOME:-}"] && DOTNET_HOME="$HOME/.dotnet" +[ -z "${DOTNET_HOME:-}" ] && DOTNET_HOME="$HOME/.dotnet" config_file="$DIR/version.xml" verbose=false update=false @@ -22,7 +22,7 @@ tools_source='' # Functions # __usage() { - echo "Usage: $(basename ${BASH_SOURCE[0]}) [options] [[--] ...]" + echo "Usage: $(basename "${BASH_SOURCE[0]}") [options] [[--] ...]" echo "" echo "Arguments:" echo " ... Arguments passed to MSBuild. Variable number of arguments allowed." @@ -46,16 +46,17 @@ __usage() { } get_korebuild() { + local version local lock_file="$repo_path/korebuild-lock.txt" - if [ ! -f $lock_file ] || [ "$update" = true ]; then - __get_remote_file "$tools_source/korebuild/channels/$channel/latest.txt" $lock_file + if [ ! -f "$lock_file" ] || [ "$update" = true ]; then + __get_remote_file "$tools_source/korebuild/channels/$channel/latest.txt" "$lock_file" fi - local version="$(grep 'version:*' -m 1 $lock_file)" + version="$(grep 'version:*' -m 1 "$lock_file")" if [[ "$version" == '' ]]; then __error "Failed to parse version from $lock_file. Expected a line that begins with 'version:'" return 1 fi - version="$(echo ${version#version:} | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" + version="$(echo "${version#version:}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" local korebuild_path="$DOTNET_HOME/buildtools/korebuild/$version" { @@ -64,10 +65,10 @@ get_korebuild() { local remote_path="$tools_source/korebuild/artifacts/$version/korebuild.$version.zip" tmpfile="$(mktemp)" echo -e "${MAGENTA}Downloading KoreBuild ${version}${RESET}" - if __get_remote_file $remote_path $tmpfile; then - unzip -q -d "$korebuild_path" $tmpfile + if __get_remote_file "$remote_path" "$tmpfile"; then + unzip -q -d "$korebuild_path" "$tmpfile" fi - rm $tmpfile || true + rm "$tmpfile" || true fi source "$korebuild_path/KoreBuild.sh" @@ -81,7 +82,7 @@ get_korebuild() { } __error() { - echo -e "${RED}$@${RESET}" 1>&2 + echo -e "${RED}$*${RESET}" 1>&2 } __machine_has() { @@ -94,18 +95,18 @@ __get_remote_file() { local local_path=$2 if [[ "$remote_path" != 'http'* ]]; then - cp $remote_path $local_path + cp "$remote_path" "$local_path" return 0 fi failed=false if __machine_has wget; then - wget --tries 10 --quiet -O $local_path $remote_path || failed=true + wget --tries 10 --quiet -O "$local_path" "$remote_path" || failed=true fi if [ "$failed" = true ] && __machine_has curl; then failed=false - curl --retry 10 -sSL -f --create-dirs -o $local_path $remote_path || failed=true + curl --retry 10 -sSL -f --create-dirs -o "$local_path" "$remote_path" || failed=true fi if [ "$failed" = true ]; then @@ -114,13 +115,13 @@ __get_remote_file() { fi } -__read_dom () { local IFS=\> ; read -d \< ENTITY CONTENT ;} +__read_dom () { local IFS=\> ; read -r -d \< ENTITY CONTENT ;} # # main # -while [[ $# > 0 ]]; do +while [[ $# -gt 0 ]]; do case $1 in -\?|-h|--help) __usage --no-exit @@ -128,7 +129,7 @@ while [[ $# > 0 ]]; do ;; -c|--channel|-Channel) shift - channel=${1:-} + channel="${1:-}" [ -z "$channel" ] && __usage ;; --config-file|-ConfigFile) @@ -138,7 +139,7 @@ while [[ $# > 0 ]]; do ;; -d|--dotnet-home|-DotNetHome) shift - DOTNET_HOME=${1:-} + DOTNET_HOME="${1:-}" [ -z "$DOTNET_HOME" ] && __usage ;; --path|-Path) @@ -178,14 +179,14 @@ if ! __machine_has curl && ! __machine_has wget; then exit 1 fi -if [ -f $config_file ]; then +if [ -f "$config_file" ]; then comment=false while __read_dom; do if [ "$comment" = true ]; then [[ $CONTENT == *'-->'* ]] && comment=false ; continue; fi if [[ $ENTITY == '!--'* ]]; then comment=true; continue; fi if [ -z "$channel" ] && [[ $ENTITY == "KoreBuildChannel" ]]; then channel=$CONTENT; fi if [ -z "$tools_source" ] && [[ $ENTITY == "KoreBuildToolsSource" ]]; then tools_source=$CONTENT; fi - done < $config_file + done < "$config_file" fi [ -z "$channel" ] && channel='dev' @@ -193,4 +194,4 @@ fi get_korebuild install_tools "$tools_source" "$DOTNET_HOME" -invoke_repository_build "$repo_path" $@ +invoke_repository_build "$repo_path" "$@" From 6a20337254dc0fcc5227e2243fdc3f52c88e58da Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 26 Jul 2017 10:27:59 -0700 Subject: [PATCH 260/471] Fix syntax warning when running build.sh on older versions of bash [ci skip] --- build.sh | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/build.sh b/build.sh index ab590e62f1..5568c6182a 100755 --- a/build.sh +++ b/build.sh @@ -10,7 +10,7 @@ RESET="\033[0m" RED="\033[0;31m" MAGENTA="\033[0;95m" DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -[ -z "${DOTNET_HOME:-}"] && DOTNET_HOME="$HOME/.dotnet" +[ -z "${DOTNET_HOME:-}" ] && DOTNET_HOME="$HOME/.dotnet" config_file="$DIR/version.xml" verbose=false update=false @@ -22,7 +22,7 @@ tools_source='' # Functions # __usage() { - echo "Usage: $(basename ${BASH_SOURCE[0]}) [options] [[--] ...]" + echo "Usage: $(basename "${BASH_SOURCE[0]}") [options] [[--] ...]" echo "" echo "Arguments:" echo " ... Arguments passed to MSBuild. Variable number of arguments allowed." @@ -46,16 +46,17 @@ __usage() { } get_korebuild() { + local version local lock_file="$repo_path/korebuild-lock.txt" - if [ ! -f $lock_file ] || [ "$update" = true ]; then - __get_remote_file "$tools_source/korebuild/channels/$channel/latest.txt" $lock_file + if [ ! -f "$lock_file" ] || [ "$update" = true ]; then + __get_remote_file "$tools_source/korebuild/channels/$channel/latest.txt" "$lock_file" fi - local version="$(grep 'version:*' -m 1 $lock_file)" + version="$(grep 'version:*' -m 1 "$lock_file")" if [[ "$version" == '' ]]; then __error "Failed to parse version from $lock_file. Expected a line that begins with 'version:'" return 1 fi - version="$(echo ${version#version:} | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" + version="$(echo "${version#version:}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" local korebuild_path="$DOTNET_HOME/buildtools/korebuild/$version" { @@ -64,10 +65,10 @@ get_korebuild() { local remote_path="$tools_source/korebuild/artifacts/$version/korebuild.$version.zip" tmpfile="$(mktemp)" echo -e "${MAGENTA}Downloading KoreBuild ${version}${RESET}" - if __get_remote_file $remote_path $tmpfile; then - unzip -q -d "$korebuild_path" $tmpfile + if __get_remote_file "$remote_path" "$tmpfile"; then + unzip -q -d "$korebuild_path" "$tmpfile" fi - rm $tmpfile || true + rm "$tmpfile" || true fi source "$korebuild_path/KoreBuild.sh" @@ -81,7 +82,7 @@ get_korebuild() { } __error() { - echo -e "${RED}$@${RESET}" 1>&2 + echo -e "${RED}$*${RESET}" 1>&2 } __machine_has() { @@ -94,18 +95,18 @@ __get_remote_file() { local local_path=$2 if [[ "$remote_path" != 'http'* ]]; then - cp $remote_path $local_path + cp "$remote_path" "$local_path" return 0 fi failed=false if __machine_has wget; then - wget --tries 10 --quiet -O $local_path $remote_path || failed=true + wget --tries 10 --quiet -O "$local_path" "$remote_path" || failed=true fi if [ "$failed" = true ] && __machine_has curl; then failed=false - curl --retry 10 -sSL -f --create-dirs -o $local_path $remote_path || failed=true + curl --retry 10 -sSL -f --create-dirs -o "$local_path" "$remote_path" || failed=true fi if [ "$failed" = true ]; then @@ -114,13 +115,13 @@ __get_remote_file() { fi } -__read_dom () { local IFS=\> ; read -d \< ENTITY CONTENT ;} +__read_dom () { local IFS=\> ; read -r -d \< ENTITY CONTENT ;} # # main # -while [[ $# > 0 ]]; do +while [[ $# -gt 0 ]]; do case $1 in -\?|-h|--help) __usage --no-exit @@ -128,7 +129,7 @@ while [[ $# > 0 ]]; do ;; -c|--channel|-Channel) shift - channel=${1:-} + channel="${1:-}" [ -z "$channel" ] && __usage ;; --config-file|-ConfigFile) @@ -138,7 +139,7 @@ while [[ $# > 0 ]]; do ;; -d|--dotnet-home|-DotNetHome) shift - DOTNET_HOME=${1:-} + DOTNET_HOME="${1:-}" [ -z "$DOTNET_HOME" ] && __usage ;; --path|-Path) @@ -178,14 +179,14 @@ if ! __machine_has curl && ! __machine_has wget; then exit 1 fi -if [ -f $config_file ]; then +if [ -f "$config_file" ]; then comment=false while __read_dom; do if [ "$comment" = true ]; then [[ $CONTENT == *'-->'* ]] && comment=false ; continue; fi if [[ $ENTITY == '!--'* ]]; then comment=true; continue; fi if [ -z "$channel" ] && [[ $ENTITY == "KoreBuildChannel" ]]; then channel=$CONTENT; fi if [ -z "$tools_source" ] && [[ $ENTITY == "KoreBuildToolsSource" ]]; then tools_source=$CONTENT; fi - done < $config_file + done < "$config_file" fi [ -z "$channel" ] && channel='dev' @@ -193,4 +194,4 @@ fi get_korebuild install_tools "$tools_source" "$DOTNET_HOME" -invoke_repository_build "$repo_path" $@ +invoke_repository_build "$repo_path" "$@" From dce16d26ecc51fc89912b86eb7c2199679bcb87b Mon Sep 17 00:00:00 2001 From: John Luo Date: Wed, 2 Aug 2017 12:44:45 -0700 Subject: [PATCH 261/471] Update __get_remote_file logic --- build.sh | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/build.sh b/build.sh index 5568c6182a..8eace4c20d 100755 --- a/build.sh +++ b/build.sh @@ -99,17 +99,16 @@ __get_remote_file() { return 0 fi - failed=false + local succeeded=false if __machine_has wget; then - wget --tries 10 --quiet -O "$local_path" "$remote_path" || failed=true + wget --tries 10 --quiet -O "$local_path" "$remote_path" && succeeded=true fi - if [ "$failed" = true ] && __machine_has curl; then - failed=false - curl --retry 10 -sSL -f --create-dirs -o "$local_path" "$remote_path" || failed=true + if [ "$succeeded" = false ] && __machine_has curl; then + curl --retry 10 -sSL -f --create-dirs -o "$local_path" "$remote_path" && succeeded=true fi - if [ "$failed" = true ]; then + if [ "$succeeded" = false ]; then __error "Download failed: $remote_path" 1>&2 return 1 fi From 90d9b8d5131bffe2e16a19aeb964066b59b0aca1 Mon Sep 17 00:00:00 2001 From: John Luo Date: Wed, 2 Aug 2017 12:44:46 -0700 Subject: [PATCH 262/471] Update __get_remote_file logic --- build.sh | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/build.sh b/build.sh index 5568c6182a..8eace4c20d 100755 --- a/build.sh +++ b/build.sh @@ -99,17 +99,16 @@ __get_remote_file() { return 0 fi - failed=false + local succeeded=false if __machine_has wget; then - wget --tries 10 --quiet -O "$local_path" "$remote_path" || failed=true + wget --tries 10 --quiet -O "$local_path" "$remote_path" && succeeded=true fi - if [ "$failed" = true ] && __machine_has curl; then - failed=false - curl --retry 10 -sSL -f --create-dirs -o "$local_path" "$remote_path" || failed=true + if [ "$succeeded" = false ] && __machine_has curl; then + curl --retry 10 -sSL -f --create-dirs -o "$local_path" "$remote_path" && succeeded=true fi - if [ "$failed" = true ]; then + if [ "$succeeded" = false ]; then __error "Download failed: $remote_path" 1>&2 return 1 fi From aa2c30688236abf8037b4dd9e47971eddae858e2 Mon Sep 17 00:00:00 2001 From: John Luo Date: Wed, 2 Aug 2017 14:31:53 -0700 Subject: [PATCH 263/471] Ensure fallback to curl after failed wget --- build.sh | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/build.sh b/build.sh index 8eace4c20d..11cdbe5504 100755 --- a/build.sh +++ b/build.sh @@ -99,16 +99,19 @@ __get_remote_file() { return 0 fi - local succeeded=false + local failed=false if __machine_has wget; then - wget --tries 10 --quiet -O "$local_path" "$remote_path" && succeeded=true + wget --tries 10 --quiet -O "$local_path" "$remote_path" || failed=true + else + failed=true fi - if [ "$succeeded" = false ] && __machine_has curl; then - curl --retry 10 -sSL -f --create-dirs -o "$local_path" "$remote_path" && succeeded=true + if [ "$failed" = true ] && __machine_has curl; then + failed=false + curl --retry 10 -sSL -f --create-dirs -o "$local_path" "$remote_path" || failed=true fi - if [ "$succeeded" = false ]; then + if [ "$failed" = true ]; then __error "Download failed: $remote_path" 1>&2 return 1 fi From 13754ed0c7dc7db53fa1ee6d79b714d0882a8ac5 Mon Sep 17 00:00:00 2001 From: John Luo Date: Wed, 2 Aug 2017 14:32:27 -0700 Subject: [PATCH 264/471] Ensure fallback to curl after failed wget --- build.sh | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/build.sh b/build.sh index 8eace4c20d..11cdbe5504 100755 --- a/build.sh +++ b/build.sh @@ -99,16 +99,19 @@ __get_remote_file() { return 0 fi - local succeeded=false + local failed=false if __machine_has wget; then - wget --tries 10 --quiet -O "$local_path" "$remote_path" && succeeded=true + wget --tries 10 --quiet -O "$local_path" "$remote_path" || failed=true + else + failed=true fi - if [ "$succeeded" = false ] && __machine_has curl; then - curl --retry 10 -sSL -f --create-dirs -o "$local_path" "$remote_path" && succeeded=true + if [ "$failed" = true ] && __machine_has curl; then + failed=false + curl --retry 10 -sSL -f --create-dirs -o "$local_path" "$remote_path" || failed=true fi - if [ "$succeeded" = false ]; then + if [ "$failed" = true ]; then __error "Download failed: $remote_path" 1>&2 return 1 fi From a2c0410e39a05bf646d1a042ec2284af37847b1b Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Thu, 17 Aug 2017 16:15:42 -0700 Subject: [PATCH 265/471] Use PackageLineup to manage package versions --- appveyor.yml => .appveyor.yml | 0 Directory.Build.props | 14 +++++++++++ Directory.Build.targets | 14 +++++++++++ JsonPatch.sln | 25 ++++++++++++++++++- build/common.props | 24 ------------------ build/dependencies.props | 14 ----------- build/repo.props | 6 +++++ src/Directory.Build.props | 7 ++++++ .../Microsoft.AspNetCore.JsonPatch.csproj | 7 +++--- test/Directory.Build.props | 11 ++++++++ .../DictionaryAdapterTest.cs | 14 +++++------ ...Microsoft.AspNetCore.JsonPatch.Test.csproj | 9 ++----- .../ObjectAdapterTests.cs | 8 +++--- 13 files changed, 92 insertions(+), 61 deletions(-) rename appveyor.yml => .appveyor.yml (100%) create mode 100644 Directory.Build.props create mode 100644 Directory.Build.targets delete mode 100644 build/common.props delete mode 100644 build/dependencies.props create mode 100644 build/repo.props create mode 100644 src/Directory.Build.props create mode 100644 test/Directory.Build.props diff --git a/appveyor.yml b/.appveyor.yml similarity index 100% rename from appveyor.yml rename to .appveyor.yml diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 0000000000..57d9ef7e6a --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,14 @@ + + + + + Microsoft ASP.NET Core + https://github.com/aspnet/JsonPatch + git + $(MSBuildThisFileDirectory)build\Key.snk + true + true + $(VersionSuffix)-$(BuildNumber) + true + + diff --git a/Directory.Build.targets b/Directory.Build.targets new file mode 100644 index 0000000000..9989b1046b --- /dev/null +++ b/Directory.Build.targets @@ -0,0 +1,14 @@ + + + + <_BootstrapperFile Condition=" $([MSBuild]::IsOSUnixLike()) ">build.sh + <_BootstrapperFile Condition="! $([MSBuild]::IsOSUnixLike()) ">build.cmd + <_BootstrapperError> + Package references have not been pinned. Run './$(_BootstrapperFile) /t:Pin'. + Also, you can run './$(_BootstrapperFile) /t:Restore' which will pin *and* restore packages. '$(_BootstrapperFile)' can be found in '$(MSBuildThisFileDirectory)'. + + + + + + diff --git a/JsonPatch.sln b/JsonPatch.sln index b75721a487..87b48a8ea1 100644 --- a/JsonPatch.sln +++ b/JsonPatch.sln @@ -1,10 +1,16 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26222.1 +VisualStudioVersion = 15.0.26815.3 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{430B59ED-F960-4D3A-8FFE-3370008E168D}" + ProjectSection(SolutionItems) = preProject + src\Directory.Build.props = src\Directory.Build.props + EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{36CD6341-AB44-44EB-B3AA-BF98C89FECDD}" + ProjectSection(SolutionItems) = preProject + test\Directory.Build.props = test\Directory.Build.props + EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.JsonPatch", "src\Microsoft.AspNetCore.JsonPatch\Microsoft.AspNetCore.JsonPatch.csproj", "{4D55F4D8-633B-462F-A5B1-FEB84BD2D534}" EndProject @@ -12,7 +18,21 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.JsonPa EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C430C499-382D-47BD-B351-CF8F89C08CD2}" ProjectSection(SolutionItems) = preProject + .appveyor.yml = .appveyor.yml + .gitattributes = .gitattributes + .gitignore = .gitignore + .travis.yml = .travis.yml + build.cmd = build.cmd + build.ps1 = build.ps1 + build.sh = build.sh + CONTRIBUTING.md = CONTRIBUTING.md + Directory.Build.props = Directory.Build.props + Directory.Build.targets = Directory.Build.targets + LICENSE.txt = LICENSE.txt NuGet.config = NuGet.config + NuGetPackageVerifier.json = NuGetPackageVerifier.json + README.md = README.md + version.xml = version.xml EndProjectSection EndProject Global @@ -37,4 +57,7 @@ Global {4D55F4D8-633B-462F-A5B1-FEB84BD2D534} = {430B59ED-F960-4D3A-8FFE-3370008E168D} {81C20848-E063-4E12-AC40-0B55A532C16C} = {36CD6341-AB44-44EB-B3AA-BF98C89FECDD} EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {9FFA3EB9-8740-4434-BC8C-F3D595161B59} + EndGlobalSection EndGlobal diff --git a/build/common.props b/build/common.props deleted file mode 100644 index b749c350f1..0000000000 --- a/build/common.props +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - Microsoft ASP.NET Core - https://github.com/aspnet/JsonPatch - git - $(MSBuildThisFileDirectory)Key.snk - true - true - $(VersionSuffix)-$(BuildNumber) - true - - - - - - - - - - - diff --git a/build/dependencies.props b/build/dependencies.props deleted file mode 100644 index f2fb071ace..0000000000 --- a/build/dependencies.props +++ /dev/null @@ -1,14 +0,0 @@ - - - 2.1.0-* - 4.4.0-* - 2.1.1-* - 10.0.1 - 4.7.49 - 2.0.0-* - 2.0.0-* - 2.0.0-* - 15.3.0-* - 2.3.0-beta2-* - - diff --git a/build/repo.props b/build/repo.props new file mode 100644 index 0000000000..c5d91e8a2c --- /dev/null +++ b/build/repo.props @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/Directory.Build.props b/src/Directory.Build.props new file mode 100644 index 0000000000..5236edee58 --- /dev/null +++ b/src/Directory.Build.props @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj b/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj index e9732e8621..a364de22ef 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj +++ b/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj @@ -1,5 +1,4 @@ - ASP.NET Core support for JSON PATCH. @@ -10,9 +9,9 @@ - - - + + + diff --git a/test/Directory.Build.props b/test/Directory.Build.props new file mode 100644 index 0000000000..31ed7dd07c --- /dev/null +++ b/test/Directory.Build.props @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/DictionaryAdapterTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/DictionaryAdapterTest.cs index 6a88bd6cc7..bc50b872a2 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/DictionaryAdapterTest.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/DictionaryAdapterTest.cs @@ -28,7 +28,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal // Assert Assert.True(addStatus); Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); - Assert.Equal(1, dictionary.Count); + Assert.Single(dictionary); Assert.Equal("James", dictionary[nameKey]); } @@ -48,7 +48,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal // Assert Assert.True(addStatus); Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); - Assert.Equal(1, dictionary.Count); + Assert.Single(dictionary); Assert.Equal("James", dictionary[nameKey]); // Act @@ -77,7 +77,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal // Assert Assert.True(addStatus); Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); - Assert.Equal(1, dictionary.Count); + Assert.Single(dictionary); Assert.Equal("James", dictionary[nameKey]); // Act @@ -107,7 +107,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal // Assert Assert.True(replaceStatus); Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); - Assert.Equal(1, dictionary.Count); + Assert.Single(dictionary); Assert.Equal("James", dictionary[nameKey]); } @@ -129,7 +129,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal Assert.Equal( string.Format("The target location specified by path segment '{0}' was not found.", nameKey), message); - Assert.Equal(0, dictionary.Count); + Assert.Empty(dictionary); } [Fact] @@ -150,7 +150,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal Assert.Equal( string.Format("The target location specified by path segment '{0}' was not found.", nameKey), message); - Assert.Equal(0, dictionary.Count); + Assert.Empty(dictionary); } [Fact] @@ -170,7 +170,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal //Assert Assert.True(removeStatus); Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); - Assert.Equal(0, dictionary.Count); + Assert.Empty(dictionary); } } } diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj index f5b8c8268a..2e4f68b538 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj @@ -1,7 +1,5 @@  - - netcoreapp2.0;net461 netcoreapp2.0 @@ -12,11 +10,8 @@ - - - - - + + diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs index 56b25d22be..34a8c97b67 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs @@ -720,8 +720,8 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters var serialized = JsonConvert.SerializeObject(patchDoc); // Assert - Assert.False(serialized.Contains("operations")); - Assert.False(serialized.Contains("Operations")); + Assert.DoesNotContain("operations", serialized); + Assert.DoesNotContain("Operations", serialized); } [Fact] @@ -2061,7 +2061,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters patchDoc.ApplyTo(model); // Assert - Assert.Equal(1, model.Count); + Assert.Single(model); Assert.Equal(expected, model["WA"]); } @@ -2080,7 +2080,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters deserialized.ApplyTo(model); // Assert - Assert.Equal(1, model.Count); + Assert.Single(model); Assert.Equal(expected, model["WA"]); } From 01bf47170fdb848f4ced623b1fad7450c8848d64 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Fri, 18 Aug 2017 10:43:19 -0700 Subject: [PATCH 266/471] Revert lineups change until we work out issues with PackageLineup This reverts commit a2c0410e39a05bf646d1a042ec2284af37847b1b. --- Directory.Build.props | 14 ----------- Directory.Build.targets | 14 ----------- JsonPatch.sln | 25 +------------------ .appveyor.yml => appveyor.yml | 0 build/common.props | 24 ++++++++++++++++++ build/dependencies.props | 14 +++++++++++ build/repo.props | 6 ----- src/Directory.Build.props | 7 ------ .../Microsoft.AspNetCore.JsonPatch.csproj | 7 +++--- test/Directory.Build.props | 11 -------- .../DictionaryAdapterTest.cs | 14 +++++------ ...Microsoft.AspNetCore.JsonPatch.Test.csproj | 9 +++++-- .../ObjectAdapterTests.cs | 8 +++--- 13 files changed, 61 insertions(+), 92 deletions(-) delete mode 100644 Directory.Build.props delete mode 100644 Directory.Build.targets rename .appveyor.yml => appveyor.yml (100%) create mode 100644 build/common.props create mode 100644 build/dependencies.props delete mode 100644 build/repo.props delete mode 100644 src/Directory.Build.props delete mode 100644 test/Directory.Build.props diff --git a/Directory.Build.props b/Directory.Build.props deleted file mode 100644 index 57d9ef7e6a..0000000000 --- a/Directory.Build.props +++ /dev/null @@ -1,14 +0,0 @@ - - - - - Microsoft ASP.NET Core - https://github.com/aspnet/JsonPatch - git - $(MSBuildThisFileDirectory)build\Key.snk - true - true - $(VersionSuffix)-$(BuildNumber) - true - - diff --git a/Directory.Build.targets b/Directory.Build.targets deleted file mode 100644 index 9989b1046b..0000000000 --- a/Directory.Build.targets +++ /dev/null @@ -1,14 +0,0 @@ - - - - <_BootstrapperFile Condition=" $([MSBuild]::IsOSUnixLike()) ">build.sh - <_BootstrapperFile Condition="! $([MSBuild]::IsOSUnixLike()) ">build.cmd - <_BootstrapperError> - Package references have not been pinned. Run './$(_BootstrapperFile) /t:Pin'. - Also, you can run './$(_BootstrapperFile) /t:Restore' which will pin *and* restore packages. '$(_BootstrapperFile)' can be found in '$(MSBuildThisFileDirectory)'. - - - - - - diff --git a/JsonPatch.sln b/JsonPatch.sln index 87b48a8ea1..b75721a487 100644 --- a/JsonPatch.sln +++ b/JsonPatch.sln @@ -1,16 +1,10 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26815.3 +VisualStudioVersion = 15.0.26222.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{430B59ED-F960-4D3A-8FFE-3370008E168D}" - ProjectSection(SolutionItems) = preProject - src\Directory.Build.props = src\Directory.Build.props - EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{36CD6341-AB44-44EB-B3AA-BF98C89FECDD}" - ProjectSection(SolutionItems) = preProject - test\Directory.Build.props = test\Directory.Build.props - EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.JsonPatch", "src\Microsoft.AspNetCore.JsonPatch\Microsoft.AspNetCore.JsonPatch.csproj", "{4D55F4D8-633B-462F-A5B1-FEB84BD2D534}" EndProject @@ -18,21 +12,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.JsonPa EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C430C499-382D-47BD-B351-CF8F89C08CD2}" ProjectSection(SolutionItems) = preProject - .appveyor.yml = .appveyor.yml - .gitattributes = .gitattributes - .gitignore = .gitignore - .travis.yml = .travis.yml - build.cmd = build.cmd - build.ps1 = build.ps1 - build.sh = build.sh - CONTRIBUTING.md = CONTRIBUTING.md - Directory.Build.props = Directory.Build.props - Directory.Build.targets = Directory.Build.targets - LICENSE.txt = LICENSE.txt NuGet.config = NuGet.config - NuGetPackageVerifier.json = NuGetPackageVerifier.json - README.md = README.md - version.xml = version.xml EndProjectSection EndProject Global @@ -57,7 +37,4 @@ Global {4D55F4D8-633B-462F-A5B1-FEB84BD2D534} = {430B59ED-F960-4D3A-8FFE-3370008E168D} {81C20848-E063-4E12-AC40-0B55A532C16C} = {36CD6341-AB44-44EB-B3AA-BF98C89FECDD} EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {9FFA3EB9-8740-4434-BC8C-F3D595161B59} - EndGlobalSection EndGlobal diff --git a/.appveyor.yml b/appveyor.yml similarity index 100% rename from .appveyor.yml rename to appveyor.yml diff --git a/build/common.props b/build/common.props new file mode 100644 index 0000000000..b749c350f1 --- /dev/null +++ b/build/common.props @@ -0,0 +1,24 @@ + + + + + + Microsoft ASP.NET Core + https://github.com/aspnet/JsonPatch + git + $(MSBuildThisFileDirectory)Key.snk + true + true + $(VersionSuffix)-$(BuildNumber) + true + + + + + + + + + + + diff --git a/build/dependencies.props b/build/dependencies.props new file mode 100644 index 0000000000..f2fb071ace --- /dev/null +++ b/build/dependencies.props @@ -0,0 +1,14 @@ + + + 2.1.0-* + 4.4.0-* + 2.1.1-* + 10.0.1 + 4.7.49 + 2.0.0-* + 2.0.0-* + 2.0.0-* + 15.3.0-* + 2.3.0-beta2-* + + diff --git a/build/repo.props b/build/repo.props deleted file mode 100644 index c5d91e8a2c..0000000000 --- a/build/repo.props +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/src/Directory.Build.props b/src/Directory.Build.props deleted file mode 100644 index 5236edee58..0000000000 --- a/src/Directory.Build.props +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj b/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj index a364de22ef..e9732e8621 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj +++ b/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj @@ -1,4 +1,5 @@ + ASP.NET Core support for JSON PATCH. @@ -9,9 +10,9 @@ - - - + + + diff --git a/test/Directory.Build.props b/test/Directory.Build.props deleted file mode 100644 index 31ed7dd07c..0000000000 --- a/test/Directory.Build.props +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/DictionaryAdapterTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/DictionaryAdapterTest.cs index bc50b872a2..6a88bd6cc7 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/DictionaryAdapterTest.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/DictionaryAdapterTest.cs @@ -28,7 +28,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal // Assert Assert.True(addStatus); Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); - Assert.Single(dictionary); + Assert.Equal(1, dictionary.Count); Assert.Equal("James", dictionary[nameKey]); } @@ -48,7 +48,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal // Assert Assert.True(addStatus); Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); - Assert.Single(dictionary); + Assert.Equal(1, dictionary.Count); Assert.Equal("James", dictionary[nameKey]); // Act @@ -77,7 +77,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal // Assert Assert.True(addStatus); Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); - Assert.Single(dictionary); + Assert.Equal(1, dictionary.Count); Assert.Equal("James", dictionary[nameKey]); // Act @@ -107,7 +107,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal // Assert Assert.True(replaceStatus); Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); - Assert.Single(dictionary); + Assert.Equal(1, dictionary.Count); Assert.Equal("James", dictionary[nameKey]); } @@ -129,7 +129,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal Assert.Equal( string.Format("The target location specified by path segment '{0}' was not found.", nameKey), message); - Assert.Empty(dictionary); + Assert.Equal(0, dictionary.Count); } [Fact] @@ -150,7 +150,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal Assert.Equal( string.Format("The target location specified by path segment '{0}' was not found.", nameKey), message); - Assert.Empty(dictionary); + Assert.Equal(0, dictionary.Count); } [Fact] @@ -170,7 +170,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal //Assert Assert.True(removeStatus); Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); - Assert.Empty(dictionary); + Assert.Equal(0, dictionary.Count); } } } diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj index 2e4f68b538..f5b8c8268a 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj @@ -1,5 +1,7 @@  + + netcoreapp2.0;net461 netcoreapp2.0 @@ -10,8 +12,11 @@ - - + + + + + diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs index 34a8c97b67..56b25d22be 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs @@ -720,8 +720,8 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters var serialized = JsonConvert.SerializeObject(patchDoc); // Assert - Assert.DoesNotContain("operations", serialized); - Assert.DoesNotContain("Operations", serialized); + Assert.False(serialized.Contains("operations")); + Assert.False(serialized.Contains("Operations")); } [Fact] @@ -2061,7 +2061,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters patchDoc.ApplyTo(model); // Assert - Assert.Single(model); + Assert.Equal(1, model.Count); Assert.Equal(expected, model["WA"]); } @@ -2080,7 +2080,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters deserialized.ApplyTo(model); // Assert - Assert.Single(model); + Assert.Equal(1, model.Count); Assert.Equal(expected, model["WA"]); } From a993c2a5ff3d4f21a50c3a424cb42201944c4b19 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Fri, 18 Aug 2017 16:31:06 -0700 Subject: [PATCH 267/471] Use PackageLineup to manage versions (revert revert) We resolved the issues with PackageLineup and partial graph builds. This reverts commit 01bf47170fdb848f4ced623b1fad7450c8848d64. --- appveyor.yml => .appveyor.yml | 0 Directory.Build.props | 14 +++++++++++ Directory.Build.targets | 14 +++++++++++ JsonPatch.sln | 25 ++++++++++++++++++- build/common.props | 24 ------------------ build/dependencies.props | 14 ----------- build/repo.props | 6 +++++ src/Directory.Build.props | 7 ++++++ .../Microsoft.AspNetCore.JsonPatch.csproj | 7 +++--- test/Directory.Build.props | 11 ++++++++ .../DictionaryAdapterTest.cs | 14 +++++------ ...Microsoft.AspNetCore.JsonPatch.Test.csproj | 9 ++----- .../ObjectAdapterTests.cs | 8 +++--- 13 files changed, 92 insertions(+), 61 deletions(-) rename appveyor.yml => .appveyor.yml (100%) create mode 100644 Directory.Build.props create mode 100644 Directory.Build.targets delete mode 100644 build/common.props delete mode 100644 build/dependencies.props create mode 100644 build/repo.props create mode 100644 src/Directory.Build.props create mode 100644 test/Directory.Build.props diff --git a/appveyor.yml b/.appveyor.yml similarity index 100% rename from appveyor.yml rename to .appveyor.yml diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 0000000000..57d9ef7e6a --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,14 @@ + + + + + Microsoft ASP.NET Core + https://github.com/aspnet/JsonPatch + git + $(MSBuildThisFileDirectory)build\Key.snk + true + true + $(VersionSuffix)-$(BuildNumber) + true + + diff --git a/Directory.Build.targets b/Directory.Build.targets new file mode 100644 index 0000000000..9989b1046b --- /dev/null +++ b/Directory.Build.targets @@ -0,0 +1,14 @@ + + + + <_BootstrapperFile Condition=" $([MSBuild]::IsOSUnixLike()) ">build.sh + <_BootstrapperFile Condition="! $([MSBuild]::IsOSUnixLike()) ">build.cmd + <_BootstrapperError> + Package references have not been pinned. Run './$(_BootstrapperFile) /t:Pin'. + Also, you can run './$(_BootstrapperFile) /t:Restore' which will pin *and* restore packages. '$(_BootstrapperFile)' can be found in '$(MSBuildThisFileDirectory)'. + + + + + + diff --git a/JsonPatch.sln b/JsonPatch.sln index b75721a487..87b48a8ea1 100644 --- a/JsonPatch.sln +++ b/JsonPatch.sln @@ -1,10 +1,16 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26222.1 +VisualStudioVersion = 15.0.26815.3 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{430B59ED-F960-4D3A-8FFE-3370008E168D}" + ProjectSection(SolutionItems) = preProject + src\Directory.Build.props = src\Directory.Build.props + EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{36CD6341-AB44-44EB-B3AA-BF98C89FECDD}" + ProjectSection(SolutionItems) = preProject + test\Directory.Build.props = test\Directory.Build.props + EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.JsonPatch", "src\Microsoft.AspNetCore.JsonPatch\Microsoft.AspNetCore.JsonPatch.csproj", "{4D55F4D8-633B-462F-A5B1-FEB84BD2D534}" EndProject @@ -12,7 +18,21 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.JsonPa EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C430C499-382D-47BD-B351-CF8F89C08CD2}" ProjectSection(SolutionItems) = preProject + .appveyor.yml = .appveyor.yml + .gitattributes = .gitattributes + .gitignore = .gitignore + .travis.yml = .travis.yml + build.cmd = build.cmd + build.ps1 = build.ps1 + build.sh = build.sh + CONTRIBUTING.md = CONTRIBUTING.md + Directory.Build.props = Directory.Build.props + Directory.Build.targets = Directory.Build.targets + LICENSE.txt = LICENSE.txt NuGet.config = NuGet.config + NuGetPackageVerifier.json = NuGetPackageVerifier.json + README.md = README.md + version.xml = version.xml EndProjectSection EndProject Global @@ -37,4 +57,7 @@ Global {4D55F4D8-633B-462F-A5B1-FEB84BD2D534} = {430B59ED-F960-4D3A-8FFE-3370008E168D} {81C20848-E063-4E12-AC40-0B55A532C16C} = {36CD6341-AB44-44EB-B3AA-BF98C89FECDD} EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {9FFA3EB9-8740-4434-BC8C-F3D595161B59} + EndGlobalSection EndGlobal diff --git a/build/common.props b/build/common.props deleted file mode 100644 index b749c350f1..0000000000 --- a/build/common.props +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - Microsoft ASP.NET Core - https://github.com/aspnet/JsonPatch - git - $(MSBuildThisFileDirectory)Key.snk - true - true - $(VersionSuffix)-$(BuildNumber) - true - - - - - - - - - - - diff --git a/build/dependencies.props b/build/dependencies.props deleted file mode 100644 index f2fb071ace..0000000000 --- a/build/dependencies.props +++ /dev/null @@ -1,14 +0,0 @@ - - - 2.1.0-* - 4.4.0-* - 2.1.1-* - 10.0.1 - 4.7.49 - 2.0.0-* - 2.0.0-* - 2.0.0-* - 15.3.0-* - 2.3.0-beta2-* - - diff --git a/build/repo.props b/build/repo.props new file mode 100644 index 0000000000..c5d91e8a2c --- /dev/null +++ b/build/repo.props @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/Directory.Build.props b/src/Directory.Build.props new file mode 100644 index 0000000000..5236edee58 --- /dev/null +++ b/src/Directory.Build.props @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj b/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj index e9732e8621..a364de22ef 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj +++ b/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj @@ -1,5 +1,4 @@ - ASP.NET Core support for JSON PATCH. @@ -10,9 +9,9 @@ - - - + + + diff --git a/test/Directory.Build.props b/test/Directory.Build.props new file mode 100644 index 0000000000..31ed7dd07c --- /dev/null +++ b/test/Directory.Build.props @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/DictionaryAdapterTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/DictionaryAdapterTest.cs index 6a88bd6cc7..bc50b872a2 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/DictionaryAdapterTest.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/DictionaryAdapterTest.cs @@ -28,7 +28,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal // Assert Assert.True(addStatus); Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); - Assert.Equal(1, dictionary.Count); + Assert.Single(dictionary); Assert.Equal("James", dictionary[nameKey]); } @@ -48,7 +48,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal // Assert Assert.True(addStatus); Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); - Assert.Equal(1, dictionary.Count); + Assert.Single(dictionary); Assert.Equal("James", dictionary[nameKey]); // Act @@ -77,7 +77,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal // Assert Assert.True(addStatus); Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); - Assert.Equal(1, dictionary.Count); + Assert.Single(dictionary); Assert.Equal("James", dictionary[nameKey]); // Act @@ -107,7 +107,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal // Assert Assert.True(replaceStatus); Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); - Assert.Equal(1, dictionary.Count); + Assert.Single(dictionary); Assert.Equal("James", dictionary[nameKey]); } @@ -129,7 +129,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal Assert.Equal( string.Format("The target location specified by path segment '{0}' was not found.", nameKey), message); - Assert.Equal(0, dictionary.Count); + Assert.Empty(dictionary); } [Fact] @@ -150,7 +150,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal Assert.Equal( string.Format("The target location specified by path segment '{0}' was not found.", nameKey), message); - Assert.Equal(0, dictionary.Count); + Assert.Empty(dictionary); } [Fact] @@ -170,7 +170,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal //Assert Assert.True(removeStatus); Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); - Assert.Equal(0, dictionary.Count); + Assert.Empty(dictionary); } } } diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj index f5b8c8268a..2e4f68b538 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj @@ -1,7 +1,5 @@  - - netcoreapp2.0;net461 netcoreapp2.0 @@ -12,11 +10,8 @@ - - - - - + + diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs index 56b25d22be..34a8c97b67 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs @@ -720,8 +720,8 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters var serialized = JsonConvert.SerializeObject(patchDoc); // Assert - Assert.False(serialized.Contains("operations")); - Assert.False(serialized.Contains("Operations")); + Assert.DoesNotContain("operations", serialized); + Assert.DoesNotContain("Operations", serialized); } [Fact] @@ -2061,7 +2061,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters patchDoc.ApplyTo(model); // Assert - Assert.Equal(1, model.Count); + Assert.Single(model); Assert.Equal(expected, model["WA"]); } @@ -2080,7 +2080,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters deserialized.ApplyTo(model); // Assert - Assert.Equal(1, model.Count); + Assert.Single(model); Assert.Equal(expected, model["WA"]); } From 68a6e8d367b27d00e00ae00b4bacd764dc6fb503 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 22 Aug 2017 15:19:42 -0700 Subject: [PATCH 268/471] Upgrade to xunit 2.3.0-beta4 --- build/dependencies.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 3c71bd378d..1235e00530 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -6,7 +6,7 @@ 2.0.0-* 2.0.0-* 2.0.0-* - 15.3.0-* - 2.3.0-beta2-* + 15.3.0 + 2.3.0-beta4-build3742 From d4b64af0e60a319d8240837d3174fac9b04e271b Mon Sep 17 00:00:00 2001 From: Jass Bagga Date: Wed, 23 Aug 2017 10:30:11 -0700 Subject: [PATCH 269/471] Use DictionaryKeyResolver for ExpandoObjectAdapter (#100) Addresses #102 --- .../Adapters/ObjectAdapter.cs | 31 +--- .../Internal/ExpandoObjectAdapter.cs | 22 +-- .../ExpandoObjectDictionaryExtensions.cs | 26 --- .../Internal/ListAdapter.cs | 34 ++-- .../Internal/PocoAdapter.cs | 24 +-- .../Dynamic/AddOperationTests.cs | 51 +++--- .../Dynamic/AddTypedOperationTests.cs | 8 +- .../Dynamic/CopyOperationTests.cs | 24 +-- .../Dynamic/CopyTypedOperationTests.cs | 24 +-- .../Dynamic/CustomNamingStrategyTests.cs | 154 ++++++++++++++++++ .../Dynamic/MoveOperationTests.cs | 45 +++-- .../Dynamic/MoveTypedOperationTests.cs | 12 +- .../Dynamic/PatchDocumentTests.cs | 12 +- .../Dynamic/RemoveOperationTests.cs | 80 ++++----- .../Dynamic/RemoveTypedOperationTests.cs | 20 +-- .../ObjectVisitorTest.cs | 4 - 16 files changed, 330 insertions(+), 241 deletions(-) delete mode 100644 src/Microsoft.AspNetCore.JsonPatch/Internal/ExpandoObjectDictionaryExtensions.cs create mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CustomNamingStrategyTests.cs diff --git a/src/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs b/src/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs index b1a487f088..a30343868a 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs @@ -2,8 +2,6 @@ // 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; -using Microsoft.AspNetCore.JsonPatch.Helpers; using Microsoft.AspNetCore.JsonPatch.Internal; using Microsoft.AspNetCore.JsonPatch.Operations; using Newtonsoft.Json.Serialization; @@ -22,12 +20,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters IContractResolver contractResolver, Action logErrorAction) { - if (contractResolver == null) - { - throw new ArgumentNullException(nameof(contractResolver)); - } - - ContractResolver = contractResolver; + ContractResolver = contractResolver ?? throw new ArgumentNullException(nameof(contractResolver)); LogErrorAction = logErrorAction; } @@ -144,10 +137,8 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters var parsedPath = new ParsedPath(path); var visitor = new ObjectVisitor(parsedPath, ContractResolver); - IAdapter adapter; var target = objectToApplyTo; - string errorMessage; - if (!visitor.TryVisit(ref target, out adapter, out errorMessage)) + if (!visitor.TryVisit(ref target, out var adapter, out var errorMessage)) { var error = CreatePathNotFoundError(objectToApplyTo, path, operation, errorMessage); ErrorReporter(error); @@ -197,9 +188,8 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters throw new ArgumentNullException(nameof(objectToApplyTo)); } - object propertyValue; // Get value at 'from' location and add that value to the 'path' location - if (TryGetValue(operation.from, objectToApplyTo, operation, out propertyValue)) + if (TryGetValue(operation.from, objectToApplyTo, operation, out var propertyValue)) { // remove that value Remove(operation.from, objectToApplyTo, operation); @@ -253,10 +243,8 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters var parsedPath = new ParsedPath(path); var visitor = new ObjectVisitor(parsedPath, ContractResolver); - IAdapter adapter; var target = objectToApplyTo; - string errorMessage; - if (!visitor.TryVisit(ref target, out adapter, out errorMessage)) + if (!visitor.TryVisit(ref target, out var adapter, out var errorMessage)) { var error = CreatePathNotFoundError(objectToApplyTo, path, operationToReport, errorMessage); ErrorReporter(error); @@ -306,10 +294,8 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters var parsedPath = new ParsedPath(operation.path); var visitor = new ObjectVisitor(parsedPath, ContractResolver); - IAdapter adapter; var target = objectToApplyTo; - string errorMessage; - if (!visitor.TryVisit(ref target, out adapter, out errorMessage)) + if (!visitor.TryVisit(ref target, out var adapter, out var errorMessage)) { var error = CreatePathNotFoundError(objectToApplyTo, operation.path, operation, errorMessage); ErrorReporter(error); @@ -358,9 +344,8 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters throw new ArgumentNullException(nameof(objectToApplyTo)); } - object propertyValue; // Get value at 'from' location and add that value to the 'path' location - if (TryGetValue(operation.from, objectToApplyTo, operation, out propertyValue)) + if (TryGetValue(operation.from, objectToApplyTo, operation, out var propertyValue)) { // Create deep copy var copyResult = ConversionResultProvider.CopyTo(propertyValue, propertyValue.GetType()); @@ -406,10 +391,8 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters var parsedPath = new ParsedPath(fromLocation); var visitor = new ObjectVisitor(parsedPath, ContractResolver); - IAdapter adapter; var target = objectToGetValueFrom; - string errorMessage; - if (!visitor.TryVisit(ref target, out adapter, out errorMessage)) + if (!visitor.TryVisit(ref target, out var adapter, out var errorMessage)) { var error = CreatePathNotFoundError(objectToGetValueFrom, fromLocation, operation, errorMessage); ErrorReporter(error); diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/ExpandoObjectAdapter.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/ExpandoObjectAdapter.cs index 681b5309e6..c35d1b702c 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Internal/ExpandoObjectAdapter.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Internal/ExpandoObjectAdapter.cs @@ -16,10 +16,10 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal object value, out string errorMessage) { + var contract = (JsonDictionaryContract)contractResolver.ResolveContract(target.GetType()); + var key = contract.DictionaryKeyResolver(segment); var dictionary = (IDictionary)target; - var key = dictionary.GetKeyUsingCaseInsensitiveSearch(segment); - // As per JsonPatch spec, if a key already exists, adding should replace the existing value dictionary[key] = ConvertValue(dictionary, key, value); @@ -34,9 +34,10 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal out object value, out string errorMessage) { + var contract = (JsonDictionaryContract)contractResolver.ResolveContract(target.GetType()); + var key = contract.DictionaryKeyResolver(segment); var dictionary = (IDictionary)target; - var key = dictionary.GetKeyUsingCaseInsensitiveSearch(segment); value = dictionary[key]; errorMessage = null; @@ -49,10 +50,10 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal IContractResolver contractResolver, out string errorMessage) { + var contract = (JsonDictionaryContract)contractResolver.ResolveContract(target.GetType()); + var key = contract.DictionaryKeyResolver(segment); var dictionary = (IDictionary)target; - var key = dictionary.GetKeyUsingCaseInsensitiveSearch(segment); - // As per JsonPatch spec, the target location must exist for remove to be successful if (!dictionary.ContainsKey(key)) { @@ -73,10 +74,10 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal object value, out string errorMessage) { + var contract = (JsonDictionaryContract)contractResolver.ResolveContract(target.GetType()); + var key = contract.DictionaryKeyResolver(segment); var dictionary = (IDictionary)target; - var key = dictionary.GetKeyUsingCaseInsensitiveSearch(segment); - // As per JsonPatch spec, the target location must exist for remove to be successful if (!dictionary.ContainsKey(key)) { @@ -105,10 +106,10 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal return false; } + var contract = (JsonDictionaryContract)contractResolver.ResolveContract(target.GetType()); + var key = contract.DictionaryKeyResolver(segment); var dictionary = (IDictionary)expandoObject; - var key = dictionary.GetKeyUsingCaseInsensitiveSearch(segment); - if (dictionary.ContainsKey(key)) { nextTarget = dictionary[key]; @@ -125,8 +126,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal private object ConvertValue(IDictionary dictionary, string key, object newValue) { - object existingValue = null; - if (dictionary.TryGetValue(key, out existingValue)) + if (dictionary.TryGetValue(key, out var existingValue)) { if (existingValue != null) { diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/ExpandoObjectDictionaryExtensions.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/ExpandoObjectDictionaryExtensions.cs deleted file mode 100644 index 8bb60dd2a7..0000000000 --- a/src/Microsoft.AspNetCore.JsonPatch/Internal/ExpandoObjectDictionaryExtensions.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; - -namespace Microsoft.AspNetCore.JsonPatch.Internal -{ - // Helper methods to allow case-insensitive key search - public static class ExpandoObjectDictionaryExtensions - { - internal static string GetKeyUsingCaseInsensitiveSearch( - this IDictionary propertyDictionary, - string key) - { - foreach (var keyInDictionary in propertyDictionary.Keys) - { - if (string.Equals(key, keyInDictionary, StringComparison.OrdinalIgnoreCase)) - { - return keyInDictionary; - } - } - return key; - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/ListAdapter.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/ListAdapter.cs index 343712690a..a1c0498e47 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Internal/ListAdapter.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Internal/ListAdapter.cs @@ -20,20 +20,17 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal { var list = (IList)target; - Type typeArgument = null; - if (!TryGetListTypeArgument(list, out typeArgument, out errorMessage)) + if (!TryGetListTypeArgument(list, out var typeArgument, out errorMessage)) { return false; } - PositionInfo positionInfo; - if (!TryGetPositionInfo(list, segment, OperationType.Add, out positionInfo, out errorMessage)) + if (!TryGetPositionInfo(list, segment, OperationType.Add, out var positionInfo, out errorMessage)) { return false; } - object convertedValue = null; - if (!TryConvertValue(value, typeArgument, segment, out convertedValue, out errorMessage)) + if (!TryConvertValue(value, typeArgument, segment, out var convertedValue, out errorMessage)) { return false; } @@ -60,15 +57,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal { var list = (IList)target; - Type typeArgument = null; - if (!TryGetListTypeArgument(list, out typeArgument, out errorMessage)) + if (!TryGetListTypeArgument(list, out var typeArgument, out errorMessage)) { value = null; return false; } - PositionInfo positionInfo; - if (!TryGetPositionInfo(list, segment, OperationType.Get, out positionInfo, out errorMessage)) + if (!TryGetPositionInfo(list, segment, OperationType.Get, out var positionInfo, out errorMessage)) { value = null; return false; @@ -95,14 +90,12 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal { var list = (IList)target; - Type typeArgument = null; - if (!TryGetListTypeArgument(list, out typeArgument, out errorMessage)) + if (!TryGetListTypeArgument(list, out var typeArgument, out errorMessage)) { return false; } - PositionInfo positionInfo; - if (!TryGetPositionInfo(list, segment, OperationType.Remove, out positionInfo, out errorMessage)) + if (!TryGetPositionInfo(list, segment, OperationType.Remove, out var positionInfo, out errorMessage)) { return false; } @@ -129,20 +122,17 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal { var list = (IList)target; - Type typeArgument = null; - if (!TryGetListTypeArgument(list, out typeArgument, out errorMessage)) + if (!TryGetListTypeArgument(list, out var typeArgument, out errorMessage)) { return false; } - PositionInfo positionInfo; - if (!TryGetPositionInfo(list, segment, OperationType.Replace, out positionInfo, out errorMessage)) + if (!TryGetPositionInfo(list, segment, OperationType.Replace, out var positionInfo, out errorMessage)) { return false; } - object convertedValue = null; - if (!TryConvertValue(value, typeArgument, segment, out convertedValue, out errorMessage)) + if (!TryConvertValue(value, typeArgument, segment, out var convertedValue, out errorMessage)) { return false; } @@ -175,7 +165,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal return false; } - int index = -1; + var index = -1; if (!int.TryParse(segment, out index)) { value = null; @@ -257,7 +247,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal return true; } - int position = -1; + var position = -1; if (int.TryParse(segment, out position)) { if (position >= 0 && position < list.Count) diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/PocoAdapter.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/PocoAdapter.cs index 0755e132e1..eab16a3035 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Internal/PocoAdapter.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Internal/PocoAdapter.cs @@ -17,8 +17,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal object value, out string errorMessage) { - JsonProperty jsonProperty = null; - if (!TryGetJsonProperty(target, contractResolver, segment, out jsonProperty)) + if (!TryGetJsonProperty(target, contractResolver, segment, out var jsonProperty)) { errorMessage = Resources.FormatTargetLocationAtPathSegmentNotFound(segment); return false; @@ -30,8 +29,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal return false; } - object convertedValue = null; - if (!TryConvertValue(value, jsonProperty.PropertyType, out convertedValue)) + if (!TryConvertValue(value, jsonProperty.PropertyType, out var convertedValue)) { errorMessage = Resources.FormatInvalidValueForProperty(value); return false; @@ -50,8 +48,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal out object value, out string errorMessage) { - JsonProperty jsonProperty = null; - if (!TryGetJsonProperty(target, contractResolver, segment, out jsonProperty)) + if (!TryGetJsonProperty(target, contractResolver, segment, out var jsonProperty)) { errorMessage = Resources.FormatTargetLocationAtPathSegmentNotFound(segment); value = null; @@ -76,8 +73,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal IContractResolver contractResolver, out string errorMessage) { - JsonProperty jsonProperty = null; - if (!TryGetJsonProperty(target, contractResolver, segment, out jsonProperty)) + if (!TryGetJsonProperty(target, contractResolver, segment, out var jsonProperty)) { errorMessage = Resources.FormatTargetLocationAtPathSegmentNotFound(segment); return false; @@ -112,8 +108,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal object value, out string errorMessage) { - JsonProperty jsonProperty = null; - if (!TryGetJsonProperty(target, contractResolver, segment, out jsonProperty)) + if (!TryGetJsonProperty(target, contractResolver, segment, out var jsonProperty)) { errorMessage = Resources.FormatTargetLocationAtPathSegmentNotFound(segment); return false; @@ -125,8 +120,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal return false; } - object convertedValue = null; - if (!TryConvertValue(value, jsonProperty.PropertyType, out convertedValue)) + if (!TryConvertValue(value, jsonProperty.PropertyType, out var convertedValue)) { errorMessage = Resources.FormatInvalidValueForProperty(value); return false; @@ -152,8 +146,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal return false; } - JsonProperty jsonProperty = null; - if (TryGetJsonProperty(target, contractResolver, segment, out jsonProperty)) + if (TryGetJsonProperty(target, contractResolver, segment, out var jsonProperty)) { value = jsonProperty.ValueProvider.GetValue(target); errorMessage = null; @@ -171,8 +164,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal string segment, out JsonProperty jsonProperty) { - var jsonObjectContract = contractResolver.ResolveContract(target.GetType()) as JsonObjectContract; - if (jsonObjectContract != null) + if (contractResolver.ResolveContract(target.GetType()) is JsonObjectContract jsonObjectContract) { var pocoProperty = jsonObjectContract .Properties diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddOperationTests.cs index cbd44a7ef9..e1cdb21df2 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddOperationTests.cs @@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add("NewInt", 1); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -43,7 +43,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic obj.Test = 1; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add("NewInt", 1); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -65,7 +65,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add("Nested/NewInt", 1); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -90,7 +90,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add("Nested/NewInt", 1); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -115,7 +115,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add("Nested/StringProperty", "A"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -137,7 +137,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add("Nested/NewInt", 1); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -158,7 +158,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add("DynamicProperty/NewInt", 1); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -181,7 +181,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add("DynamicProperty/StringProperty", "B"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -203,7 +203,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic dynamic valueToAdd = new { IntValue = 1, StringValue = "test", GuidValue = Guid.NewGuid() }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add("ComplexProperty", valueToAdd); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -227,7 +227,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add("StringProperty", "B"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -249,7 +249,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic doc.StringProperty = "A"; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add("StringProperty", "B"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -269,7 +269,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic doc.InBetweenFirst.InBetweenSecond.StringProperty = "A"; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add("/InBetweenFirst/InBetweenSecond/StringProperty", "B"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -291,7 +291,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic doc.Nested.DynamicProperty.InBetweenFirst.InBetweenSecond.StringProperty = "A"; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add("/Nested/DynamicProperty/InBetweenFirst/InBetweenSecond/StringProperty", "B"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -325,7 +325,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add("DynamicProperty/OtherProperty/IntProperty", 1); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -366,7 +366,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add("baz/bat", "qux"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -382,13 +382,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic } [Fact] - public void ShouldReplacePropertyWithDifferentCase() + public void ShouldNotReplacePropertyWithDifferentCase() { dynamic doc = new ExpandoObject(); doc.StringProperty = "A"; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add("stringproperty", "B"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -396,7 +396,8 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic deserialized.ApplyTo(doc); - Assert.Equal("B", doc.StringProperty); + Assert.Equal("A", doc.StringProperty); + Assert.Equal("B", doc.stringproperty); } [Fact] @@ -408,7 +409,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add("IntegerList/0", 4); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -426,7 +427,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic doc.IntegerList = new List() { 1, 2, 3 }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add("IntegerList/-1", 4); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -450,7 +451,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add("integerlist/0", 4); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -470,7 +471,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add("IntegerList/4", 4); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -494,7 +495,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add("IntegerList/0", 4); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -514,7 +515,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add("IntegerList/-1", 4); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -538,7 +539,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add("IntegerList/-", 4); var serialized = JsonConvert.SerializeObject(patchDoc); diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddTypedOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddTypedOperationTests.cs index f28d877ea4..bbf5118962 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddTypedOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddTypedOperationTests.cs @@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add("IntegerList/-1", 4); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -49,7 +49,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add("ListOfSimpleDTO/0/IntegerList/0", 4); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -74,7 +74,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add("ListOfSimpleDTO/-1/IntegerList/0", 4); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -103,7 +103,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic } }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add("ListOfSimpleDTO/20/IntegerList/0", 4); var serialized = JsonConvert.SerializeObject(patchDoc); diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CopyOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CopyOperationTests.cs index 87f221bc15..42dd0072c4 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CopyOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CopyOperationTests.cs @@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic doc.StringProperty = "A"; doc.AnotherStringProperty = "B"; - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Copy("StringProperty", "AnotherStringProperty"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -35,7 +35,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic doc.IntegerList = new List() { 1, 2, 3 }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Copy("IntegerList/0", "IntegerList/1"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -53,7 +53,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic doc.IntegerList = new List() { 1, 2, 3 }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Copy("IntegerList/0", "IntegerList/-"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -70,7 +70,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic doc.IntegerList = new List() { 1, 2, 3 }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Copy("IntegerList/0", "IntegerValue"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -89,7 +89,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic doc.IntegerList = new List() { 1, 2, 3 }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Copy("IntegerValue", "IntegerList/0"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -107,7 +107,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic doc.IntegerList = new List() { 1, 2, 3 }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Copy("IntegerValue", "IntegerList/-"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -129,7 +129,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Copy("SimpleDTO/StringProperty", "SimpleDTO/AnotherStringProperty"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -150,7 +150,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Copy("SimpleDTO/IntegerList/0", "SimpleDTO/IntegerList/1"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -170,7 +170,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Copy("SimpleDTO/IntegerList/0", "SimpleDTO/IntegerList/-"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -191,7 +191,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Copy("SimpleDTO/IntegerList/0", "SimpleDTO/IntegerValue"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -212,7 +212,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Copy("SimpleDTO/IntegerValue", "SimpleDTO/IntegerList/0"); var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); @@ -232,7 +232,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Copy("SimpleDTO/IntegerValue", "SimpleDTO/IntegerList/-"); var serialized = JsonConvert.SerializeObject(patchDoc); diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CopyTypedOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CopyTypedOperationTests.cs index 3a51556013..0ea602da03 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CopyTypedOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CopyTypedOperationTests.cs @@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Copy("StringProperty", "AnotherStringProperty"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -38,7 +38,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Copy("IntegerList/0", "IntegerList/1"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -58,7 +58,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Copy("IntegerList/0", "IntegerList/-"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -77,7 +77,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Copy("IntegerList/0", "IntegerValue"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -98,7 +98,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Copy("IntegerValue", "IntegerList/0"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -118,7 +118,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Copy("IntegerValue", "IntegerList/-"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -142,7 +142,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Copy("SimpleDTO/StringProperty", "SimpleDTO/AnotherStringProperty"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -165,7 +165,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Copy("SimpleDTO/IntegerList/0", "SimpleDTO/IntegerList/1"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -187,7 +187,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Copy("SimpleDTO/IntegerList/0", "SimpleDTO/IntegerList/-"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -210,7 +210,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Copy("SimpleDTO/IntegerList/0", "SimpleDTO/IntegerValue"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -233,7 +233,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Copy("SimpleDTO/IntegerValue", "SimpleDTO/IntegerList/0"); var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); @@ -255,7 +255,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Copy("SimpleDTO/IntegerValue", "SimpleDTO/IntegerList/-"); var serialized = JsonConvert.SerializeObject(patchDoc); diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CustomNamingStrategyTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CustomNamingStrategyTests.cs new file mode 100644 index 0000000000..b829b81902 --- /dev/null +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CustomNamingStrategyTests.cs @@ -0,0 +1,154 @@ +// Copyright (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.Test.Dynamic +{ + public class CustomNamingStrategyTests + { + [Fact] + public void AddProperty_ToExpandoObject_WithCustomNamingStrategy() + { + // Arrange + var contractResolver = new DefaultContractResolver + { + NamingStrategy = new TestNamingStrategy() + }; + + dynamic obj = new ExpandoObject(); + obj.Test = 1; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Add("NewInt", 1); + patchDoc.ContractResolver = contractResolver; + + // Act + patchDoc.ApplyTo(obj); + + // Assert + Assert.Equal(1, obj.customNewInt); + Assert.Equal(1, obj.Test); + } + + [Fact] + public void CopyPropertyValue_ForExpandoObject_WithCustomNamingStrategy() + { + // Arrange + var contractResolver = new DefaultContractResolver + { + NamingStrategy = new TestNamingStrategy() + }; + + dynamic obj = new ExpandoObject(); + obj.customStringProperty = "A"; + obj.customAnotherStringProperty = "B"; + + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy("StringProperty", "AnotherStringProperty"); + patchDoc.ContractResolver = contractResolver; + + // Act + patchDoc.ApplyTo(obj); + + // Assert + Assert.Equal("A", obj.customAnotherStringProperty); + } + + [Fact] + public void MovePropertyValue_ForExpandoObject_WithCustomNamingStrategy() + { + // Arrange + var contractResolver = new DefaultContractResolver + { + NamingStrategy = new TestNamingStrategy() + }; + + dynamic obj = new ExpandoObject(); + obj.customStringProperty = "A"; + obj.customAnotherStringProperty = "B"; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Move("StringProperty", "AnotherStringProperty"); + patchDoc.ContractResolver = contractResolver; + + // Act + patchDoc.ApplyTo(obj); + var cont = obj as IDictionary; + cont.TryGetValue("customStringProperty", out var valueFromDictionary); + + // Assert + Assert.Equal("A", obj.customAnotherStringProperty); + Assert.Null(valueFromDictionary); + } + + [Fact] + public void RemoveProperty_FromExpandoObject_WithCustomNamingStrategy() + { + // Arrange + var contractResolver = new DefaultContractResolver + { + NamingStrategy = new TestNamingStrategy() + }; + + dynamic obj = new ExpandoObject(); + obj.customTest = 1; + + // create patch + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove("Test"); + patchDoc.ContractResolver = contractResolver; + + // Act + patchDoc.ApplyTo(obj); + var cont = obj as IDictionary; + cont.TryGetValue("customTest", out var valueFromDictionary); + + // Assert + Assert.Null(valueFromDictionary); + } + + [Fact] + public void ReplacePropertyValue_ForExpandoObject_WithCustomNamingStrategy() + { + // Arrange + var contractResolver = new DefaultContractResolver + { + NamingStrategy = new TestNamingStrategy() + }; + + dynamic obj = new ExpandoObject(); + obj.customTest = 1; + + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace("Test", 2); + patchDoc.ContractResolver = contractResolver; + + // Act + patchDoc.ApplyTo(obj); + + // Assert + Assert.Equal(2, obj.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/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveOperationTests.cs index 5e2f7ae814..0e3ea2cea0 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveOperationTests.cs @@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic doc.AnotherStringProperty = "B"; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Move("StringProperty", "AnotherStringProperty"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -29,8 +29,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic Assert.Equal("A", doc.AnotherStringProperty); var cont = doc as IDictionary; - object valueFromDictionary; - cont.TryGetValue("StringProperty", out valueFromDictionary); + cont.TryGetValue("StringProperty", out var valueFromDictionary); Assert.Null(valueFromDictionary); } @@ -41,7 +40,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic doc.StringProperty = "A"; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Move("StringProperty", "AnotherStringProperty"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -52,8 +51,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic Assert.Equal("A", doc.AnotherStringProperty); var cont = doc as IDictionary; - object valueFromDictionary; - cont.TryGetValue("StringProperty", out valueFromDictionary); + cont.TryGetValue("StringProperty", out var valueFromDictionary); Assert.Null(valueFromDictionary); } @@ -65,7 +63,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic doc.SimpleDTO = new SimpleDTO() { AnotherStringProperty = "B" }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Move("StringProperty", "SimpleDTO/AnotherStringProperty"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -76,8 +74,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic Assert.Equal("A", doc.SimpleDTO.AnotherStringProperty); var cont = doc as IDictionary; - object valueFromDictionary; - cont.TryGetValue("StringProperty", out valueFromDictionary); + cont.TryGetValue("StringProperty", out var valueFromDictionary); Assert.Null(valueFromDictionary); } @@ -89,7 +86,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic doc.SimpleDTO = new SimpleDTO() { AnotherStringProperty = "B" }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Move("SimpleDTO/AnotherStringProperty", "StringProperty"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -112,7 +109,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Move("Nested/StringProperty", "Nested/AnotherStringProperty"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -131,7 +128,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic doc.IntegerList = new List() { 1, 2, 3 }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Move("IntegerList/0", "IntegerList/1"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -152,7 +149,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Move("Nested/IntegerList/0", "Nested/IntegerList/1"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -170,7 +167,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic doc.IntegerList = new List() { 1, 2, 3 }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Move("IntegerList/0", "IntegerList/-"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -190,7 +187,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Move("Nested/IntegerList/0", "Nested/IntegerList/-"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -207,7 +204,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic doc.IntegerList = new List() { 1, 2, 3 }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Move("IntegerList/0", "IntegerValue"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -229,7 +226,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Move("Nested/IntegerList/0", "Nested/IntegerValue"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -249,7 +246,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic doc.IntegerList = new List() { 1, 2, 3 }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Move("IntegerValue", "IntegerList/0"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -258,8 +255,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic deserialized.ApplyTo(doc); var cont = doc as IDictionary; - object valueFromDictionary; - cont.TryGetValue("IntegerValue", out valueFromDictionary); + cont.TryGetValue("IntegerValue", out var valueFromDictionary); Assert.Null(valueFromDictionary); Assert.Equal(new List() { 5, 1, 2, 3 }, doc.IntegerList); @@ -276,7 +272,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Move("Nested/IntegerValue", "Nested/IntegerList/0"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -296,7 +292,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic doc.IntegerList = new List() { 1, 2, 3 }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Move("IntegerValue", "IntegerList/-"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -305,8 +301,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic deserialized.ApplyTo(doc); var cont = doc as IDictionary; - object valueFromDictionary; - cont.TryGetValue("IntegerValue", out valueFromDictionary); + cont.TryGetValue("IntegerValue", out var valueFromDictionary); Assert.Null(valueFromDictionary); Assert.Equal(new List() { 1, 2, 3, 5 }, doc.IntegerList); @@ -323,7 +318,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Move("Nested/IntegerValue", "Nested/IntegerList/-"); var serialized = JsonConvert.SerializeObject(patchDoc); diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveTypedOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveTypedOperationTests.cs index f57ad3d11c..bfd79a0ea2 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveTypedOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveTypedOperationTests.cs @@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Move("StringProperty", "AnotherStringProperty"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -40,7 +40,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Move("IntegerList/0", "IntegerList/1"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -60,7 +60,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Move("IntegerList/0", "IntegerList/-"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -79,7 +79,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Move("IntegerList/0", "IntegerValue"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -101,7 +101,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Move("IntegerValue", "IntegerList/0"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -123,7 +123,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Move("IntegerValue", "IntegerList/-"); var serialized = JsonConvert.SerializeObject(patchDoc); diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/PatchDocumentTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/PatchDocumentTests.cs index e7e6f665a5..e86dc8acbd 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/PatchDocumentTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/PatchDocumentTests.cs @@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic [Fact] public void InvalidPathAtBeginningShouldThrowException() { - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); var exception = Assert.Throws(() => { patchDoc.Add("//NewInt", 1); @@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic [Fact] public void InvalidPathAtEndShouldThrowException() { - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); var exception = Assert.Throws(() => { patchDoc.Add("NewInt//", 1); @@ -38,7 +38,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic [Fact] public void InvalidPathWithDotShouldThrowException() { - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); var exception = Assert.Throws(() => { patchDoc.Add("NewInt.Test", 1); @@ -57,7 +57,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic AnotherStringProperty = "B" }; - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Copy("StringProperty", "AnotherStringProperty"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -77,10 +77,10 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic AnotherStringProperty = "B" }; - JsonPatchDocument patchDocTyped = new JsonPatchDocument(); + var patchDocTyped = new JsonPatchDocument(); patchDocTyped.Copy(o => o.StringProperty, o => o.AnotherStringProperty); - JsonPatchDocument patchDocUntyped = new JsonPatchDocument(); + var patchDocUntyped = new JsonPatchDocument(); patchDocUntyped.Copy("StringProperty", "AnotherStringProperty"); var serializedTyped = JsonConvert.SerializeObject(patchDocTyped); diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveOperationTests.cs index f0164765ee..c8985e3a86 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveOperationTests.cs @@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Remove("Test"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -42,7 +42,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic doc.Test = 1; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Remove("NonExisting"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -64,7 +64,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic obj.Test = 1; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Remove("Test"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -73,32 +73,31 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic deserialized.ApplyTo(obj); var cont = obj as IDictionary; - object valueFromDictionary; - - cont.TryGetValue("Test", out valueFromDictionary); + cont.TryGetValue("Test", out var valueFromDictionary); Assert.Null(valueFromDictionary); } [Fact] - public void RemovePropertyFromExpandoObjectMixedCase() + public void RemoveProperty_FromExpandoObject_MixedCase_ThrowsPathNotFoundException() { dynamic obj = new ExpandoObject(); obj.Test = 1; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Remove("test"); var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); - deserialized.ApplyTo(obj); - - var cont = obj as IDictionary; - object valueFromDictionary; - - cont.TryGetValue("Test", out valueFromDictionary); - Assert.Null(valueFromDictionary); + var exception = Assert.Throws(() => + { + deserialized.ApplyTo(obj); + }); + Assert.Equal( + string.Format("The target location specified by path segment '{0}' was not found.", + "test"), + exception.Message); } [Fact] @@ -109,7 +108,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic obj.Test.AnotherTest = "A"; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Remove("Test"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -118,32 +117,31 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic deserialized.ApplyTo(obj); var cont = obj as IDictionary; - object valueFromDictionary; - - cont.TryGetValue("Test", out valueFromDictionary); + cont.TryGetValue("Test", out var valueFromDictionary); Assert.Null(valueFromDictionary); } [Fact] - public void RemoveNestedPropertyFromExpandoObjectMixedCase() + public void RemoveNestedProperty_FromExpandoObject_MixedCase_ThrowsPathNotFoundException() { dynamic obj = new ExpandoObject(); obj.Test = new ExpandoObject(); obj.Test.AnotherTest = "A"; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Remove("test"); var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); - deserialized.ApplyTo(obj); - var cont = obj as IDictionary; - - object valueFromDictionary; - cont.TryGetValue("Test", out valueFromDictionary); - Assert.Null(valueFromDictionary); + var exception = Assert.Throws(() => + { + deserialized.ApplyTo(obj); + }); + Assert.Equal( + string.Format("The target location specified by path segment '{0}' was not found.", "test"), + exception.Message); } [Fact] @@ -156,7 +154,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Remove("SimpleDTO/StringProperty"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -167,7 +165,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic } [Fact] - public void NestedRemoveMixedCase() + public void NestedRemove_MixedCase_ThrowsPathNotFoundException() { dynamic doc = new ExpandoObject(); doc.SimpleDTO = new SimpleDTO() @@ -176,15 +174,21 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Remove("Simpledto/stringProperty"); var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); - deserialized.ApplyTo(doc); - - Assert.Null(doc.SimpleDTO.StringProperty); + var exception = Assert.Throws(() => + { + deserialized.ApplyTo(doc); + }); + Assert.Equal( + string.Format("For operation '{0}', the target location specified by path '{1}' was not found.", + "remove", + "/Simpledto/stringProperty"), + exception.Message); } [Fact] @@ -197,7 +201,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Remove("SimpleDTO/IntegerList/2"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -218,7 +222,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Remove("SimpleDTO/Integerlist/2"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -239,7 +243,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Remove("SimpleDTO/IntegerList/3"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -264,7 +268,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Remove("SimpleDTO/IntegerList/-1"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -289,7 +293,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Remove("SimpleDTO/IntegerList/-"); var serialized = JsonConvert.SerializeObject(patchDoc); diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveTypedOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveTypedOperationTests.cs index 50ae6e8d5d..f65b2e6342 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveTypedOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveTypedOperationTests.cs @@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Remove("StringProperty"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -39,7 +39,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Remove("IntegerList/2"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -59,7 +59,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Remove("IntegerList/3"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -83,7 +83,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Remove("IntegerList/-1"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -107,7 +107,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Remove("IntegerList/-"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -130,7 +130,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Remove("SimpleDTO/StringProperty"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -153,7 +153,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Remove("SimpleDTO/IntegerList/2"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -176,7 +176,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Remove("SimpleDTO/IntegerList/3"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -203,7 +203,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Remove("SimpleDTO/IntegerList/-1"); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -230,7 +230,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Remove("SimpleDTO/IntegerList/-"); var serialized = JsonConvert.SerializeObject(patchDoc); diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectVisitorTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectVisitorTest.cs index a03b830e02..391b5ebe2c 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectVisitorTest.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectVisitorTest.cs @@ -98,10 +98,6 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal { get { - var model = new Class1(); - yield return new object[] { model, "/Items/Name", model.Items }; - yield return new object[] { model.Items, "/Name", model.Items }; - var nestedModel = new Class1Nested(); nestedModel.Customers.Add(new Class1()); yield return new object[] { nestedModel, "/Customers/0/Items/Name", nestedModel.Customers[0].Items }; From 3d6a8615de85a8d25f78db2abe2cc511be46592c Mon Sep 17 00:00:00 2001 From: Jass Bagga Date: Thu, 24 Aug 2017 15:11:01 -0700 Subject: [PATCH 270/471] Support DynamicObject types (#99) Addresses #38 --- .../Internal/DynamicObjectAdapter.cs | 211 ++++ .../Internal/ObjectVisitor.cs | 14 +- .../Properties/Resources.Designer.cs | 124 +- .../DictionaryAdapterTest.cs | 27 +- .../Dynamic/AddOperationTests.cs | 14 +- .../Dynamic/AddTypedOperationTests.cs | 30 +- .../Dynamic/CopyOperationTests.cs | 38 +- .../Dynamic/CopyTypedOperationTests.cs | 62 +- .../Dynamic/InheritedObject.cs | 10 + .../Dynamic/MoveOperationTests.cs | 24 +- .../Dynamic/MoveTypedOperationTests.cs | 14 +- .../Dynamic/{NestedDTO.cs => NestedObject.cs} | 4 +- .../Dynamic/PatchDocumentTests.cs | 12 +- .../Dynamic/RemoveOperationTests.cs | 43 +- .../Dynamic/RemoveTypedOperationTests.cs | 48 +- .../Dynamic/ReplaceOperationTests.cs | 38 +- .../Dynamic/ReplaceTypedOperationTests.cs | 54 +- .../Dynamic/SimpleDTOWithNestedDTO.cs | 22 - .../Dynamic/{SimpleDTO.cs => SimpleObject.cs} | 6 +- .../Dynamic/SimpleObjectWithNestedObject.cs | 22 + .../DynamicObjectAdapterTest.cs | 231 ++++ .../DynamicTestObject.cs | 87 ++ .../{InheritedDTO.cs => InheritedObject.cs} | 2 +- .../DynamicObjectIntegrationTests.cs | 263 +++++ ...nPatchDocumentJsonPropertyAttributeTest.cs | 38 +- ...TO.cs => JsonPropertyComplexNameObject.cs} | 4 +- ...onPropertyDTO.cs => JsonPropertyObject.cs} | 2 +- ...s => JsonPropertyWithAnotherNameObject.cs} | 2 +- .../JsonPropertyWithInheritanceDTO.cs | 19 - .../JsonPropertyWithInheritanceObject.cs | 15 + .../ListAdapterTest.cs | 86 +- .../{NestedDTO.cs => NestedObject.cs} | 2 +- .../NestedObjectTests.cs | 1030 ++++++++--------- .../ObjectAdapterTests.cs | 422 +++---- .../ObjectVisitorTest.cs | 44 +- .../SimpleDTOWithNestedDTO.cs | 30 - .../SimpleDTOWithNestedDTOWithNullCheck.cs | 15 - .../{SimpleDTO.cs => SimpleObject.cs} | 2 +- .../SimpleObjectWithNestedObject.cs | 30 + ...mpleObjectWithNestedObjectWithNullCheck.cs | 15 + ...lCheck.cs => SimpleObjectWithNullCheck.cs} | 2 +- 41 files changed, 1950 insertions(+), 1208 deletions(-) create mode 100644 src/Microsoft.AspNetCore.JsonPatch/Internal/DynamicObjectAdapter.cs create mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/InheritedObject.cs rename test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/{NestedDTO.cs => NestedObject.cs} (78%) delete mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/SimpleDTOWithNestedDTO.cs rename test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/{SimpleDTO.cs => SimpleObject.cs} (81%) create mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/SimpleObjectWithNestedObject.cs create mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/DynamicObjectAdapterTest.cs create mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/DynamicTestObject.cs rename test/Microsoft.AspNetCore.JsonPatch.Test/{InheritedDTO.cs => InheritedObject.cs} (85%) create mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/DynamicObjectIntegrationTests.cs rename test/Microsoft.AspNetCore.JsonPatch.Test/{JsonPropertyComplexNameDTO.cs => JsonPropertyComplexNameObject.cs} (78%) rename test/Microsoft.AspNetCore.JsonPatch.Test/{JsonPropertyDTO.cs => JsonPropertyObject.cs} (90%) rename test/Microsoft.AspNetCore.JsonPatch.Test/{JsonPropertyWithAnotherNameDTO.cs => JsonPropertyWithAnotherNameObject.cs} (84%) delete mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyWithInheritanceDTO.cs create mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyWithInheritanceObject.cs rename test/Microsoft.AspNetCore.JsonPatch.Test/{NestedDTO.cs => NestedObject.cs} (89%) delete mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTOWithNestedDTO.cs delete mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTOWithNestedDTOWithNullCheck.cs rename test/Microsoft.AspNetCore.JsonPatch.Test/{SimpleDTO.cs => SimpleObject.cs} (95%) create mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/SimpleObjectWithNestedObject.cs create mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/SimpleObjectWithNestedObjectWithNullCheck.cs rename test/Microsoft.AspNetCore.JsonPatch.Test/{SimpleDTOWithNullCheck.cs => SimpleObjectWithNullCheck.cs} (93%) diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/DynamicObjectAdapter.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/DynamicObjectAdapter.cs new file mode 100644 index 0000000000..433326ce53 --- /dev/null +++ b/src/Microsoft.AspNetCore.JsonPatch/Internal/DynamicObjectAdapter.cs @@ -0,0 +1,211 @@ +// Copyright (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.Serialization; +using CSharpBinder = Microsoft.CSharp.RuntimeBinder; + +namespace Microsoft.AspNetCore.JsonPatch.Internal +{ + public class DynamicObjectAdapter : IAdapter + { + public 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 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 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 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 (!TrySetDynamicObjectProperty(target, contractResolver, segment, convertedValue, out errorMessage)) + { + return false; + } + + errorMessage = null; + return true; + } + + public 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; + } + } + + private 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; + } + } + + private 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; + } + } + + private 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/Microsoft.AspNetCore.JsonPatch/Internal/ObjectVisitor.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/ObjectVisitor.cs index b604f65a17..bbf6db4ff6 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Internal/ObjectVisitor.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Internal/ObjectVisitor.cs @@ -15,13 +15,8 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal public ObjectVisitor(ParsedPath path, IContractResolver contractResolver) { - if (contractResolver == null) - { - throw new ArgumentNullException(nameof(contractResolver)); - } - _path = path; - _contractResolver = contractResolver; + _contractResolver = contractResolver ?? throw new ArgumentNullException(nameof(contractResolver)); } public bool TryVisit(ref object target, out IAdapter adapter, out string errorMessage) @@ -38,8 +33,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal // Traverse until the penultimate segment to get the target object and adapter for (var i = 0; i < _path.Segments.Count - 1; i++) { - object next; - if (!adapter.TryTraverse(target, _path.Segments[i], _contractResolver, out next, out errorMessage)) + if (!adapter.TryTraverse(target, _path.Segments[i], _contractResolver, out var next, out errorMessage)) { adapter = null; return false; @@ -59,6 +53,10 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal { return new ExpandoObjectAdapter(); } + else if (targetObject is IDynamicMetaObjectProvider) + { + return new DynamicObjectAdapter(); + } else if (targetObject is IDictionary) { return new DictionaryAdapter(); diff --git a/src/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs index 97c98c2b05..cd99292061 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs @@ -10,277 +10,243 @@ namespace Microsoft.AspNetCore.JsonPatch private static readonly ResourceManager _resourceManager = new ResourceManager("Microsoft.AspNetCore.JsonPatch.Resources", typeof(Resources).GetTypeInfo().Assembly); - /// - /// The type of the property at path '{0}' could not be determined. - /// - internal static string CannotDeterminePropertyType - { - get { return GetString("CannotDeterminePropertyType"); } - } - - /// - /// The type of the property at path '{0}' could not be determined. - /// - internal static string FormatCannotDeterminePropertyType(object p0) - { - return string.Format(CultureInfo.CurrentCulture, GetString("CannotDeterminePropertyType"), p0); - } - /// /// The property at '{0}' could not be copied. /// - internal static string CannotCannotCopyProperty + internal static string CannotCopyProperty { - get { return GetString("CannotCannotCopyProperty"); } + 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 { - return string.Format(CultureInfo.CurrentCulture, GetString("CannotCannotCopyProperty"), p0); + 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 { return GetString("CannotPerformOperation"); } + get => GetString("CannotPerformOperation"); } /// /// The '{0}' operation at path '{1}' could not be performed. /// internal static string FormatCannotPerformOperation(object p0, object p1) - { - return string.Format(CultureInfo.CurrentCulture, GetString("CannotPerformOperation"), p0, p1); - } + => string.Format(CultureInfo.CurrentCulture, GetString("CannotPerformOperation"), p0, p1); /// /// The property at '{0}' could not be read. /// internal static string CannotReadProperty { - get { return GetString("CannotReadProperty"); } + get => GetString("CannotReadProperty"); } /// /// The property at '{0}' could not be read. /// internal static string FormatCannotReadProperty(object p0) - { - return string.Format(CultureInfo.CurrentCulture, GetString("CannotReadProperty"), p0); - } + => string.Format(CultureInfo.CurrentCulture, GetString("CannotReadProperty"), p0); /// /// The property at path '{0}' could not be updated. /// internal static string CannotUpdateProperty { - get { return GetString("CannotUpdateProperty"); } + get => GetString("CannotUpdateProperty"); } /// /// The property at path '{0}' could not be updated. /// internal static string FormatCannotUpdateProperty(object p0) - { - return string.Format(CultureInfo.CurrentCulture, GetString("CannotUpdateProperty"), p0); - } + => string.Format(CultureInfo.CurrentCulture, GetString("CannotUpdateProperty"), p0); /// /// The index value provided by path segment '{0}' is out of bounds of the array size. /// internal static string IndexOutOfBounds { - get { return GetString("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) - { - return string.Format(CultureInfo.CurrentCulture, GetString("IndexOutOfBounds"), p0); - } + => string.Format(CultureInfo.CurrentCulture, GetString("IndexOutOfBounds"), p0); /// /// The path segment '{0}' is invalid for an array index. /// internal static string InvalidIndexValue { - get { return GetString("InvalidIndexValue"); } + get => GetString("InvalidIndexValue"); } /// /// The path segment '{0}' is invalid for an array index. /// internal static string FormatInvalidIndexValue(object p0) - { - return string.Format(CultureInfo.CurrentCulture, GetString("InvalidIndexValue"), p0); - } + => string.Format(CultureInfo.CurrentCulture, GetString("InvalidIndexValue"), p0); /// /// The type '{0}' was malformed and could not be parsed. /// internal static string InvalidJsonPatchDocument { - get { return GetString("InvalidJsonPatchDocument"); } + get => GetString("InvalidJsonPatchDocument"); } /// /// The type '{0}' was malformed and could not be parsed. /// internal static string FormatInvalidJsonPatchDocument(object p0) - { - return string.Format(CultureInfo.CurrentCulture, GetString("InvalidJsonPatchDocument"), p0); - } + => string.Format(CultureInfo.CurrentCulture, GetString("InvalidJsonPatchDocument"), p0); /// /// Invalid JsonPatch operation '{0}'. /// internal static string InvalidJsonPatchOperation { - get { return GetString("InvalidJsonPatchOperation"); } + get => GetString("InvalidJsonPatchOperation"); } /// /// Invalid JsonPatch operation '{0}'. /// internal static string FormatInvalidJsonPatchOperation(object p0) - { - return string.Format(CultureInfo.CurrentCulture, GetString("InvalidJsonPatchOperation"), p0); - } + => string.Format(CultureInfo.CurrentCulture, GetString("InvalidJsonPatchOperation"), p0); /// /// The provided string '{0}' is an invalid path. /// internal static string InvalidValueForPath { - get { return GetString("InvalidValueForPath"); } + get => GetString("InvalidValueForPath"); } /// /// The provided string '{0}' is an invalid path. /// internal static string FormatInvalidValueForPath(object p0) - { - return string.Format(CultureInfo.CurrentCulture, GetString("InvalidValueForPath"), p0); - } + => string.Format(CultureInfo.CurrentCulture, GetString("InvalidValueForPath"), p0); /// /// The value '{0}' is invalid for target location. /// internal static string InvalidValueForProperty { - get { return GetString("InvalidValueForProperty"); } + get => GetString("InvalidValueForProperty"); } /// /// The value '{0}' is invalid for target location. /// internal static string FormatInvalidValueForProperty(object p0) - { - return string.Format(CultureInfo.CurrentCulture, GetString("InvalidValueForProperty"), p0); - } + => string.Format(CultureInfo.CurrentCulture, GetString("InvalidValueForProperty"), p0); /// /// '{0}' must be of type '{1}'. /// internal static string ParameterMustMatchType { - get { return GetString("ParameterMustMatchType"); } + get => GetString("ParameterMustMatchType"); } /// /// '{0}' must be of type '{1}'. /// internal static string FormatParameterMustMatchType(object p0, object p1) - { - return string.Format(CultureInfo.CurrentCulture, GetString("ParameterMustMatchType"), p0, 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 { return GetString("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) - { - return string.Format(CultureInfo.CurrentCulture, GetString("PatchNotSupportedForArrays"), 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 { return GetString("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) - { - return string.Format(CultureInfo.CurrentCulture, GetString("PatchNotSupportedForNonGenericLists"), p0); - } + => string.Format(CultureInfo.CurrentCulture, GetString("PatchNotSupportedForNonGenericLists"), p0); /// /// The target location specified by path segment '{0}' was not found. /// internal static string TargetLocationAtPathSegmentNotFound { - get { return GetString("TargetLocationAtPathSegmentNotFound"); } + get => GetString("TargetLocationAtPathSegmentNotFound"); } /// /// The target location specified by path segment '{0}' was not found. /// internal static string FormatTargetLocationAtPathSegmentNotFound(object p0) - { - return string.Format(CultureInfo.CurrentCulture, GetString("TargetLocationAtPathSegmentNotFound"), 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 { return GetString("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) - { - return string.Format(CultureInfo.CurrentCulture, GetString("TargetLocationNotFound"), p0, p1); - } + => string.Format(CultureInfo.CurrentCulture, GetString("TargetLocationNotFound"), p0, p1); /// /// The test operation is not supported. /// internal static string TestOperationNotSupported { - get { return GetString("TestOperationNotSupported"); } + get => GetString("TestOperationNotSupported"); } /// /// The test operation is not supported. /// internal static string FormatTestOperationNotSupported() - { - return GetString("TestOperationNotSupported"); - } + => GetString("TestOperationNotSupported"); private static string GetString(string name, params string[] formatterNames) { diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/DictionaryAdapterTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/DictionaryAdapterTest.cs index bc50b872a2..084aa57379 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/DictionaryAdapterTest.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/DictionaryAdapterTest.cs @@ -20,10 +20,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal dictionary[nameKey] = "Mike"; var dictionaryAdapter = new DictionaryAdapter(); var resolver = new Mock(MockBehavior.Strict); - string message = null; // Act - var addStatus = dictionaryAdapter.TryAdd(dictionary, nameKey, resolver.Object, "James", out message); + var addStatus = dictionaryAdapter.TryAdd(dictionary, nameKey, resolver.Object, "James", out var message); // Assert Assert.True(addStatus); @@ -38,12 +37,11 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal // Arrange var dictionaryAdapter = new DictionaryAdapter(); var resolver = new Mock(MockBehavior.Strict); - string message = null; var nameKey = "Name"; var dictionary = new Dictionary(StringComparer.Ordinal); // Act - var addStatus = dictionaryAdapter.TryAdd(dictionary, nameKey, resolver.Object, "James", out message); + var addStatus = dictionaryAdapter.TryAdd(dictionary, nameKey, resolver.Object, "James", out var message); // Assert Assert.True(addStatus); @@ -52,8 +50,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal Assert.Equal("James", dictionary[nameKey]); // Act - object outValue = null; - addStatus = dictionaryAdapter.TryGet(dictionary, nameKey.ToUpper(), resolver.Object, out outValue, out message); + addStatus = dictionaryAdapter.TryGet(dictionary, nameKey.ToUpper(), resolver.Object, out var outValue, out message); // Assert Assert.True(addStatus); @@ -67,12 +64,11 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal // Arrange var dictionaryAdapter = new DictionaryAdapter(); var resolver = new Mock(MockBehavior.Strict); - string message = null; var nameKey = "Name"; var dictionary = new Dictionary(StringComparer.Ordinal); // Act - var addStatus = dictionaryAdapter.TryAdd(dictionary, nameKey, resolver.Object, "James", out message); + var addStatus = dictionaryAdapter.TryAdd(dictionary, nameKey, resolver.Object, "James", out var message); // Assert Assert.True(addStatus); @@ -81,8 +77,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal Assert.Equal("James", dictionary[nameKey]); // Act - object outValue = null; - addStatus = dictionaryAdapter.TryGet(dictionary, nameKey, resolver.Object, out outValue, out message); + addStatus = dictionaryAdapter.TryGet(dictionary, nameKey, resolver.Object, out var outValue, out message); // Assert Assert.True(addStatus); @@ -99,10 +94,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal dictionary.Add(nameKey, "Mike"); var dictionaryAdapter = new DictionaryAdapter(); var resolver = new Mock(MockBehavior.Strict); - string message = null; // Act - var replaceStatus = dictionaryAdapter.TryReplace(dictionary, nameKey, resolver.Object, "James", out message); + var replaceStatus = dictionaryAdapter.TryReplace(dictionary, nameKey, resolver.Object, "James", out var message); // Assert Assert.True(replaceStatus); @@ -119,10 +113,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal var dictionary = new Dictionary(StringComparer.Ordinal); var dictionaryAdapter = new DictionaryAdapter(); var resolver = new Mock(MockBehavior.Strict); - string message = null; // Act - var replaceStatus = dictionaryAdapter.TryReplace(dictionary, nameKey, resolver.Object, "Mike", out message); + var replaceStatus = dictionaryAdapter.TryReplace(dictionary, nameKey, resolver.Object, "Mike", out var message); // Assert Assert.False(replaceStatus); @@ -140,10 +133,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal var dictionary = new Dictionary(StringComparer.Ordinal); var dictionaryAdapter = new DictionaryAdapter(); var resolver = new Mock(MockBehavior.Strict); - string message = null; // Act - var removeStatus = dictionaryAdapter.TryRemove(dictionary, nameKey, resolver.Object, out message); + var removeStatus = dictionaryAdapter.TryRemove(dictionary, nameKey, resolver.Object, out var message); // Assert Assert.False(removeStatus); @@ -162,10 +154,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal dictionary[nameKey] = "James"; var dictionaryAdapter = new DictionaryAdapter(); var resolver = new Mock(MockBehavior.Strict); - string message = null; // Act - var removeStatus = dictionaryAdapter.TryRemove(dictionary, nameKey, resolver.Object, out message); + var removeStatus = dictionaryAdapter.TryRemove(dictionary, nameKey, resolver.Object, out var message); //Assert Assert.True(removeStatus); diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddOperationTests.cs index e1cdb21df2..493444066b 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddOperationTests.cs @@ -8,7 +8,7 @@ using Microsoft.AspNetCore.JsonPatch.Exceptions; using Newtonsoft.Json; using Xunit; -namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic +namespace Microsoft.AspNetCore.JsonPatch.Internal { public class AddOperationTests { @@ -86,7 +86,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic dynamic doc = new { Test = 1, - nested = new NestedDTO() + nested = new NestedObject() }; // create patch @@ -111,7 +111,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic dynamic doc = new { Test = 1, - nested = new NestedDTO() + nested = new NestedObject() }; // create patch @@ -152,7 +152,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic [Fact] public void AddNewPropertyToExpandoOjectInTypedObject() { - var doc = new NestedDTO() + var doc = new NestedObject() { DynamicProperty = new ExpandoObject() }; @@ -175,7 +175,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic dynamic dynamicProperty = new ExpandoObject(); dynamicProperty.StringProperty = "A"; - var doc = new NestedDTO() + var doc = new NestedObject() { DynamicProperty = dynamicProperty }; @@ -284,7 +284,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic public void AddResultsShouldReplaceInNestedInDynamic() { dynamic doc = new ExpandoObject(); - doc.Nested = new NestedDTO(); + doc.Nested = new NestedObject(); doc.Nested.DynamicProperty = new ExpandoObject(); doc.Nested.DynamicProperty.InBetweenFirst = new ExpandoObject(); doc.Nested.DynamicProperty.InBetweenFirst.InBetweenSecond = new ExpandoObject(); @@ -319,7 +319,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic // the root of the document, nor a member of an existing object, nor a // member of an existing array. - var doc = new NestedDTO() + var doc = new NestedObject() { DynamicProperty = new ExpandoObject() }; diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddTypedOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddTypedOperationTests.cs index bbf5118962..b2eb4d3a3c 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddTypedOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddTypedOperationTests.cs @@ -6,14 +6,14 @@ using Microsoft.AspNetCore.JsonPatch.Exceptions; using Newtonsoft.Json; using Xunit; -namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic +namespace Microsoft.AspNetCore.JsonPatch.Internal { public class AddTypedOperationTests { [Fact] public void AddToListNegativePosition() { - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; @@ -37,11 +37,11 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic [Fact] public void AddToListInList() { - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - ListOfSimpleDTO = new List() + ListOfSimpleObject = new List() { - new SimpleDTO() + new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } @@ -50,23 +50,23 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic // create patch var patchDoc = new JsonPatchDocument(); - patchDoc.Add("ListOfSimpleDTO/0/IntegerList/0", 4); + patchDoc.Add("ListOfSimpleObject/0/IntegerList/0", 4); var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); deserialized.ApplyTo(doc); - Assert.Equal(new List() { 4, 1, 2, 3 }, doc.ListOfSimpleDTO[0].IntegerList); + Assert.Equal(new List() { 4, 1, 2, 3 }, doc.ListOfSimpleObject[0].IntegerList); } [Fact] public void AddToListInListInvalidPositionTooSmall() { - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - ListOfSimpleDTO = new List() + ListOfSimpleObject = new List() { - new SimpleDTO() + new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } @@ -75,7 +75,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic // create patch var patchDoc = new JsonPatchDocument(); - patchDoc.Add("ListOfSimpleDTO/-1/IntegerList/0", 4); + patchDoc.Add("ListOfSimpleObject/-1/IntegerList/0", 4); var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); @@ -92,11 +92,11 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic [Fact] public void AddToListInListInvalidPositionTooLarge() { - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - ListOfSimpleDTO = new List() + ListOfSimpleObject = new List() { - new SimpleDTO() + new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } @@ -104,7 +104,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic }; // create patch var patchDoc = new JsonPatchDocument(); - patchDoc.Add("ListOfSimpleDTO/20/IntegerList/0", 4); + patchDoc.Add("ListOfSimpleObject/20/IntegerList/0", 4); var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CopyOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CopyOperationTests.cs index 42dd0072c4..b2faff25a0 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CopyOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CopyOperationTests.cs @@ -6,7 +6,7 @@ using System.Dynamic; using Newtonsoft.Json; using Xunit; -namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic +namespace Microsoft.AspNetCore.JsonPatch.Internal { public class CopyOperationTests { @@ -122,7 +122,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic public void NestedCopy() { dynamic doc = new ExpandoObject(); - doc.SimpleDTO = new SimpleDTO() + doc.SimpleObject = new SimpleObject() { StringProperty = "A", AnotherStringProperty = "B" @@ -130,82 +130,82 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic // create patch var patchDoc = new JsonPatchDocument(); - patchDoc.Copy("SimpleDTO/StringProperty", "SimpleDTO/AnotherStringProperty"); + patchDoc.Copy("SimpleObject/StringProperty", "SimpleObject/AnotherStringProperty"); var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); deserialized.ApplyTo(doc); - Assert.Equal("A", doc.SimpleDTO.AnotherStringProperty); + Assert.Equal("A", doc.SimpleObject.AnotherStringProperty); } [Fact] public void NestedCopyInList() { dynamic doc = new ExpandoObject(); - doc.SimpleDTO = new SimpleDTO() + doc.SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch var patchDoc = new JsonPatchDocument(); - patchDoc.Copy("SimpleDTO/IntegerList/0", "SimpleDTO/IntegerList/1"); + patchDoc.Copy("SimpleObject/IntegerList/0", "SimpleObject/IntegerList/1"); var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); deserialized.ApplyTo(doc); - Assert.Equal(new List() { 1, 1, 2, 3 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 1, 1, 2, 3 }, doc.SimpleObject.IntegerList); } [Fact] public void NestedCopyFromListToEndOfList() { dynamic doc = new ExpandoObject(); - doc.SimpleDTO = new SimpleDTO() + doc.SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch var patchDoc = new JsonPatchDocument(); - patchDoc.Copy("SimpleDTO/IntegerList/0", "SimpleDTO/IntegerList/-"); + patchDoc.Copy("SimpleObject/IntegerList/0", "SimpleObject/IntegerList/-"); var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); deserialized.ApplyTo(doc); - Assert.Equal(new List() { 1, 2, 3, 1 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 1, 2, 3, 1 }, doc.SimpleObject.IntegerList); } [Fact] public void NestedCopyFromListToNonList() { dynamic doc = new ExpandoObject(); - doc.SimpleDTO = new SimpleDTO() + doc.SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch var patchDoc = new JsonPatchDocument(); - patchDoc.Copy("SimpleDTO/IntegerList/0", "SimpleDTO/IntegerValue"); + patchDoc.Copy("SimpleObject/IntegerList/0", "SimpleObject/IntegerValue"); var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); deserialized.ApplyTo(doc); - Assert.Equal(1, doc.SimpleDTO.IntegerValue); + Assert.Equal(1, doc.SimpleObject.IntegerValue); } [Fact] public void NestedCopyFromNonListToList() { dynamic doc = new ExpandoObject(); - doc.SimpleDTO = new SimpleDTO() + doc.SimpleObject = new SimpleObject() { IntegerValue = 5, IntegerList = new List() { 1, 2, 3 } @@ -213,19 +213,19 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic // create patch var patchDoc = new JsonPatchDocument(); - patchDoc.Copy("SimpleDTO/IntegerValue", "SimpleDTO/IntegerList/0"); + patchDoc.Copy("SimpleObject/IntegerValue", "SimpleObject/IntegerList/0"); var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); deserialized.ApplyTo(doc); - Assert.Equal(new List() { 5, 1, 2, 3 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 5, 1, 2, 3 }, doc.SimpleObject.IntegerList); } [Fact] public void NestedCopyToEndOfList() { dynamic doc = new ExpandoObject(); - doc.SimpleDTO = new SimpleDTO() + doc.SimpleObject = new SimpleObject() { IntegerValue = 5, IntegerList = new List() { 1, 2, 3 } @@ -233,13 +233,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic // create patch var patchDoc = new JsonPatchDocument(); - patchDoc.Copy("SimpleDTO/IntegerValue", "SimpleDTO/IntegerList/-"); + patchDoc.Copy("SimpleObject/IntegerValue", "SimpleObject/IntegerList/-"); var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); deserialized.ApplyTo(doc); - Assert.Equal(new List() { 1, 2, 3, 5 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 1, 2, 3, 5 }, doc.SimpleObject.IntegerList); } } } diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CopyTypedOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CopyTypedOperationTests.cs index 0ea602da03..d0b0847c71 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CopyTypedOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CopyTypedOperationTests.cs @@ -5,14 +5,14 @@ using System.Collections.Generic; using Newtonsoft.Json; using Xunit; -namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic +namespace Microsoft.AspNetCore.JsonPatch.Internal { public class CopyTypedOperationTests { [Fact] public void Copy() { - var doc = new SimpleDTO() + var doc = new SimpleObject() { StringProperty = "A", AnotherStringProperty = "B" @@ -32,7 +32,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic [Fact] public void CopyInList() { - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; @@ -52,7 +52,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic [Fact] public void CopyFromListToEndOfList() { - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; @@ -71,7 +71,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic [Fact] public void CopyFromListToNonList() { - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; @@ -91,7 +91,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic [Fact] public void CopyFromNonListToList() { - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerValue = 5, IntegerList = new List() { 1, 2, 3 } @@ -111,7 +111,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic [Fact] public void CopyToEndOfList() { - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerValue = 5, IntegerList = new List() { 1, 2, 3 } @@ -132,9 +132,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic [Fact] public void NestedCopy() { - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { StringProperty = "A", AnotherStringProperty = "B" @@ -143,22 +143,22 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic // create patch var patchDoc = new JsonPatchDocument(); - patchDoc.Copy("SimpleDTO/StringProperty", "SimpleDTO/AnotherStringProperty"); + patchDoc.Copy("SimpleObject/StringProperty", "SimpleObject/AnotherStringProperty"); var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); deserialized.ApplyTo(doc); - Assert.Equal("A", doc.SimpleDTO.AnotherStringProperty); + Assert.Equal("A", doc.SimpleObject.AnotherStringProperty); } [Fact] public void NestedCopyInList() { - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } @@ -166,21 +166,21 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic // create patch var patchDoc = new JsonPatchDocument(); - patchDoc.Copy("SimpleDTO/IntegerList/0", "SimpleDTO/IntegerList/1"); + patchDoc.Copy("SimpleObject/IntegerList/0", "SimpleObject/IntegerList/1"); var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); deserialized.ApplyTo(doc); - Assert.Equal(new List() { 1, 1, 2, 3 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 1, 1, 2, 3 }, doc.SimpleObject.IntegerList); } [Fact] public void NestedCopyFromListToEndOfList() { - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } @@ -188,22 +188,22 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic // create patch var patchDoc = new JsonPatchDocument(); - patchDoc.Copy("SimpleDTO/IntegerList/0", "SimpleDTO/IntegerList/-"); + patchDoc.Copy("SimpleObject/IntegerList/0", "SimpleObject/IntegerList/-"); var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); deserialized.ApplyTo(doc); - Assert.Equal(new List() { 1, 2, 3, 1 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 1, 2, 3, 1 }, doc.SimpleObject.IntegerList); } [Fact] public void NestedCopyFromListToNonList() { - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } @@ -211,21 +211,21 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic // create patch var patchDoc = new JsonPatchDocument(); - patchDoc.Copy("SimpleDTO/IntegerList/0", "SimpleDTO/IntegerValue"); + patchDoc.Copy("SimpleObject/IntegerList/0", "SimpleObject/IntegerValue"); var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); deserialized.ApplyTo(doc); - Assert.Equal(1, doc.SimpleDTO.IntegerValue); + Assert.Equal(1, doc.SimpleObject.IntegerValue); } [Fact] public void NestedCopyFromNonListToList() { - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerValue = 5, IntegerList = new List() { 1, 2, 3 } @@ -234,20 +234,20 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic // create patch var patchDoc = new JsonPatchDocument(); - patchDoc.Copy("SimpleDTO/IntegerValue", "SimpleDTO/IntegerList/0"); + patchDoc.Copy("SimpleObject/IntegerValue", "SimpleObject/IntegerList/0"); var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); deserialized.ApplyTo(doc); - Assert.Equal(new List() { 5, 1, 2, 3 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 5, 1, 2, 3 }, doc.SimpleObject.IntegerList); } [Fact] public void NestedCopyToEndOfList() { - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerValue = 5, IntegerList = new List() { 1, 2, 3 } @@ -256,13 +256,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic // create patch var patchDoc = new JsonPatchDocument(); - patchDoc.Copy("SimpleDTO/IntegerValue", "SimpleDTO/IntegerList/-"); + patchDoc.Copy("SimpleObject/IntegerValue", "SimpleObject/IntegerList/-"); var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); deserialized.ApplyTo(doc); - Assert.Equal(new List() { 1, 2, 3, 5 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 1, 2, 3, 5 }, doc.SimpleObject.IntegerList); } } } diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/InheritedObject.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/InheritedObject.cs new file mode 100644 index 0000000000..29424d591e --- /dev/null +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/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.Internal +{ + public class InheritedObject : SimpleObject + { + public string AdditionalStringProperty { get; set; } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveOperationTests.cs index 0e3ea2cea0..31f58c4b82 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveOperationTests.cs @@ -6,7 +6,7 @@ using System.Dynamic; using Newtonsoft.Json; using Xunit; -namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic +namespace Microsoft.AspNetCore.JsonPatch.Internal { public class MoveOperationTests { @@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic Assert.Equal("A", doc.AnotherStringProperty); var cont = doc as IDictionary; - cont.TryGetValue("StringProperty", out var valueFromDictionary); + cont.TryGetValue("StringProperty", out object valueFromDictionary); Assert.Null(valueFromDictionary); } @@ -60,7 +60,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic { dynamic doc = new ExpandoObject(); doc.StringProperty = "A"; - doc.SimpleDTO = new SimpleDTO() { AnotherStringProperty = "B" }; + doc.SimpleDTO = new SimpleObject() { AnotherStringProperty = "B" }; // create patch var patchDoc = new JsonPatchDocument(); @@ -74,7 +74,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic Assert.Equal("A", doc.SimpleDTO.AnotherStringProperty); var cont = doc as IDictionary; - cont.TryGetValue("StringProperty", out var valueFromDictionary); + cont.TryGetValue("StringProperty", out object valueFromDictionary); Assert.Null(valueFromDictionary); } @@ -83,7 +83,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic { dynamic doc = new ExpandoObject(); doc.StringProperty = "A"; - doc.SimpleDTO = new SimpleDTO() { AnotherStringProperty = "B" }; + doc.SimpleDTO = new SimpleObject() { AnotherStringProperty = "B" }; // create patch var patchDoc = new JsonPatchDocument(); @@ -102,7 +102,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic public void NestedMove() { dynamic doc = new ExpandoObject(); - doc.Nested = new SimpleDTO() + doc.Nested = new SimpleObject() { StringProperty = "A", AnotherStringProperty = "B" @@ -143,7 +143,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic public void NestedMoveInList() { dynamic doc = new ExpandoObject(); - doc.Nested = new SimpleDTO() + doc.Nested = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; @@ -181,7 +181,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic public void NestedMoveFromListToEndOfList() { dynamic doc = new ExpandoObject(); - doc.Nested = new SimpleDTO() + doc.Nested = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; @@ -220,7 +220,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic public void NestedMoveFomListToNonList() { dynamic doc = new ExpandoObject(); - doc.Nested = new SimpleDTO() + doc.Nested = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; @@ -255,7 +255,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic deserialized.ApplyTo(doc); var cont = doc as IDictionary; - cont.TryGetValue("IntegerValue", out var valueFromDictionary); + cont.TryGetValue("IntegerValue", out object valueFromDictionary); Assert.Null(valueFromDictionary); Assert.Equal(new List() { 5, 1, 2, 3 }, doc.IntegerList); @@ -265,7 +265,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic public void NestedMoveFromNonListToList() { dynamic doc = new ExpandoObject(); - doc.Nested = new SimpleDTO() + doc.Nested = new SimpleObject() { IntegerValue = 5, IntegerList = new List() { 1, 2, 3 } @@ -311,7 +311,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic public void NestedMoveToEndOfList() { dynamic doc = new ExpandoObject(); - doc.Nested = new SimpleDTO() + doc.Nested = new SimpleObject() { IntegerValue = 5, IntegerList = new List() { 1, 2, 3 } diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveTypedOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveTypedOperationTests.cs index bfd79a0ea2..4638718a59 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveTypedOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveTypedOperationTests.cs @@ -5,14 +5,14 @@ using System.Collections.Generic; using Newtonsoft.Json; using Xunit; -namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic +namespace Microsoft.AspNetCore.JsonPatch.Internal { public class MoveTypedOperationTests { [Fact] public void Move() { - var doc = new SimpleDTO() + var doc = new SimpleObject() { StringProperty = "A", AnotherStringProperty = "B" @@ -34,7 +34,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic [Fact] public void MoveInList() { - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; @@ -54,7 +54,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic [Fact] public void MoveFromListToEndOfList() { - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; @@ -73,7 +73,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic [Fact] public void MoveFomListToNonList() { - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; @@ -94,7 +94,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic [Fact] public void MoveFromNonListToList() { - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerValue = 5, IntegerList = new List() { 1, 2, 3 } @@ -116,7 +116,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic [Fact] public void MoveToEndOfList() { - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerValue = 5, IntegerList = new List() { 1, 2, 3 } diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/NestedDTO.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/NestedObject.cs similarity index 78% rename from test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/NestedDTO.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/NestedObject.cs index f94ad05d97..050ad3a3b4 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/NestedDTO.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/NestedObject.cs @@ -1,9 +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 Microsoft.AspNetCore.JsonPatch.Test.Dynamic +namespace Microsoft.AspNetCore.JsonPatch.Internal { - public class NestedDTO + public class NestedObject { public string StringProperty { get; set; } public dynamic DynamicProperty { get; set; } diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/PatchDocumentTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/PatchDocumentTests.cs index e86dc8acbd..403238bf99 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/PatchDocumentTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/PatchDocumentTests.cs @@ -5,7 +5,7 @@ using Microsoft.AspNetCore.JsonPatch.Exceptions; using Newtonsoft.Json; using Xunit; -namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic +namespace Microsoft.AspNetCore.JsonPatch.Internal { public class PatchDocumentTests { @@ -51,7 +51,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic [Fact] public void NonGenericPatchDocToGenericMustSerialize() { - var doc = new SimpleDTO() + var doc = new SimpleObject() { StringProperty = "A", AnotherStringProperty = "B" @@ -61,7 +61,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic patchDoc.Copy("StringProperty", "AnotherStringProperty"); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); deserialized.ApplyTo(doc); @@ -71,14 +71,14 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic [Fact] public void GenericPatchDocToNonGenericMustSerialize() { - var doc = new SimpleDTO() + var doc = new SimpleObject() { StringProperty = "A", AnotherStringProperty = "B" }; - var patchDocTyped = new JsonPatchDocument(); - patchDocTyped.Copy(o => o.StringProperty, o => o.AnotherStringProperty); + var patchDocTyped = new JsonPatchDocument(); + patchDocTyped.Copy(o => o.StringProperty, o => o.AnotherStringProperty); var patchDocUntyped = new JsonPatchDocument(); patchDocUntyped.Copy("StringProperty", "AnotherStringProperty"); diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveOperationTests.cs index c8985e3a86..22707add87 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveOperationTests.cs @@ -7,7 +7,7 @@ using Microsoft.AspNetCore.JsonPatch.Exceptions; using Newtonsoft.Json; using Xunit; -namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic +namespace Microsoft.AspNetCore.JsonPatch.Internal { public class RemoveOperationTests { @@ -73,7 +73,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic deserialized.ApplyTo(obj); var cont = obj as IDictionary; - cont.TryGetValue("Test", out var valueFromDictionary); + cont.TryGetValue("Test", out object valueFromDictionary); Assert.Null(valueFromDictionary); } @@ -94,9 +94,11 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic { deserialized.ApplyTo(obj); }); + Assert.Equal( - string.Format("The target location specified by path segment '{0}' was not found.", - "test"), + string.Format( + "The target location specified by path segment '{0}' was not found.", + "test"), exception.Message); } @@ -117,7 +119,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic deserialized.ApplyTo(obj); var cont = obj as IDictionary; - cont.TryGetValue("Test", out var valueFromDictionary); + cont.TryGetValue("Test", out object valueFromDictionary); Assert.Null(valueFromDictionary); } @@ -139,8 +141,11 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic { deserialized.ApplyTo(obj); }); + Assert.Equal( - string.Format("The target location specified by path segment '{0}' was not found.", "test"), + string.Format( + "The target location specified by path segment '{0}' was not found.", + "test"), exception.Message); } @@ -148,7 +153,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic public void NestedRemove() { dynamic doc = new ExpandoObject(); - doc.SimpleDTO = new SimpleDTO() + doc.SimpleDTO = new SimpleObject() { StringProperty = "A" }; @@ -168,14 +173,14 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic public void NestedRemove_MixedCase_ThrowsPathNotFoundException() { dynamic doc = new ExpandoObject(); - doc.SimpleDTO = new SimpleDTO() + doc.SimpleObject = new SimpleObject() { StringProperty = "A" }; // create patch var patchDoc = new JsonPatchDocument(); - patchDoc.Remove("Simpledto/stringProperty"); + patchDoc.Remove("Simpleobject/stringProperty"); var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); @@ -184,10 +189,12 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic { deserialized.ApplyTo(doc); }); + Assert.Equal( - string.Format("For operation '{0}', the target location specified by path '{1}' was not found.", - "remove", - "/Simpledto/stringProperty"), + string.Format( + "For operation '{0}', the target location specified by path '{1}' was not found.", + "remove", + "/Simpleobject/stringProperty"), exception.Message); } @@ -195,7 +202,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic public void NestedRemoveFromList() { dynamic doc = new ExpandoObject(); - doc.SimpleDTO = new SimpleDTO() + doc.SimpleDTO = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; @@ -213,10 +220,10 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic } [Fact] - public void NestedRemoveFromListMixedCase() + public void NestedRemoveFromList_MixedCase() { dynamic doc = new ExpandoObject(); - doc.SimpleDTO = new SimpleDTO() + doc.SimpleDTO = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; @@ -237,7 +244,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic public void NestedRemoveFromListInvalidPositionTooLarge() { dynamic doc = new ExpandoObject(); - doc.SimpleDTO = new SimpleDTO() + doc.SimpleDTO = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; @@ -262,7 +269,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic public void NestedRemoveFromListInvalidPositionTooSmall() { dynamic doc = new ExpandoObject(); - doc.SimpleDTO = new SimpleDTO() + doc.SimpleDTO = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; @@ -287,7 +294,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic public void NestedRemoveFromEndOfList() { dynamic doc = new ExpandoObject(); - doc.SimpleDTO = new SimpleDTO() + doc.SimpleDTO = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveTypedOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveTypedOperationTests.cs index f65b2e6342..000b049b1b 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveTypedOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveTypedOperationTests.cs @@ -6,14 +6,14 @@ using Microsoft.AspNetCore.JsonPatch.Exceptions; using Newtonsoft.Json; using Xunit; -namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic +namespace Microsoft.AspNetCore.JsonPatch.Internal { public class RemoveTypedOperationTests { [Fact] public void Remove() { - var doc = new SimpleDTO() + var doc = new SimpleObject() { StringProperty = "A" }; @@ -33,7 +33,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic [Fact] public void RemoveFromList() { - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; @@ -53,7 +53,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic [Fact] public void RemoveFromListInvalidPositionTooLarge() { - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; @@ -77,7 +77,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic [Fact] public void RemoveFromListInvalidPositionTooSmall() { - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; @@ -101,7 +101,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic [Fact] public void RemoveFromEndOfList() { - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; @@ -121,9 +121,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic [Fact] public void NestedRemove() { - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { StringProperty = "A" } @@ -131,22 +131,22 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic // create patch var patchDoc = new JsonPatchDocument(); - patchDoc.Remove("SimpleDTO/StringProperty"); + patchDoc.Remove("SimpleObject/StringProperty"); var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); deserialized.ApplyTo(doc); - Assert.Null(doc.SimpleDTO.StringProperty); + Assert.Null(doc.SimpleObject.StringProperty); } [Fact] public void NestedRemoveFromList() { - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } @@ -154,22 +154,22 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic // create patch var patchDoc = new JsonPatchDocument(); - patchDoc.Remove("SimpleDTO/IntegerList/2"); + patchDoc.Remove("SimpleObject/IntegerList/2"); var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); deserialized.ApplyTo(doc); - Assert.Equal(new List() { 1, 2 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 1, 2 }, doc.SimpleObject.IntegerList); } [Fact] public void NestedRemoveFromListInvalidPositionTooLarge() { - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } @@ -177,7 +177,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic // create patch var patchDoc = new JsonPatchDocument(); - patchDoc.Remove("SimpleDTO/IntegerList/3"); + patchDoc.Remove("SimpleObject/IntegerList/3"); var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); @@ -194,9 +194,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic [Fact] public void NestedRemoveFromListInvalidPositionTooSmall() { - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } @@ -204,7 +204,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic // create patch var patchDoc = new JsonPatchDocument(); - patchDoc.Remove("SimpleDTO/IntegerList/-1"); + patchDoc.Remove("SimpleObject/IntegerList/-1"); var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); @@ -221,9 +221,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic [Fact] public void NestedRemoveFromEndOfList() { - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } @@ -231,14 +231,14 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic // create patch var patchDoc = new JsonPatchDocument(); - patchDoc.Remove("SimpleDTO/IntegerList/-"); + patchDoc.Remove("SimpleObject/IntegerList/-"); var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); deserialized.ApplyTo(doc); - Assert.Equal(new List() { 1, 2 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 1, 2 }, doc.SimpleObject.IntegerList); } } } diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceOperationTests.cs index c5936ec1b0..88d1662e1d 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceOperationTests.cs @@ -9,21 +9,21 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Xunit; -namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic +namespace Microsoft.AspNetCore.JsonPatch.Internal { public class ReplaceOperationTests { [Fact] public void ReplaceGuidTest() { - dynamic doc = new SimpleDTO() + dynamic doc = new SimpleObject() { GuidValue = Guid.NewGuid() }; var newGuid = Guid.NewGuid(); // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Replace("GuidValue", newGuid); // serialize & deserialize @@ -43,7 +43,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic var newGuid = Guid.NewGuid(); // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Replace("GuidValue", newGuid); // serialize & deserialize @@ -68,7 +68,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic var newGuid = Guid.NewGuid(); // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Replace("nestedobject/GuidValue", newGuid); // serialize & deserialize @@ -84,19 +84,19 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic public void ReplaceNestedObjectTest() { dynamic doc = new ExpandoObject(); - doc.SimpleDTO = new SimpleDTO() + doc.SimpleDTO = new SimpleObject() { IntegerValue = 5, IntegerList = new List() { 1, 2, 3 } }; - var newDTO = new SimpleDTO() + var newDTO = new SimpleObject() { DoubleValue = 1 }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Replace("SimpleDTO", newDTO); // serialize & deserialize @@ -117,7 +117,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic doc.IntegerList = new List() { 1, 2, 3 }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Replace("IntegerList/0", 5); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -135,7 +135,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic doc.IntegerList = new List() { 1, 2, 3 }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Replace("IntegerList", new List() { 4, 5, 6 }); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -150,13 +150,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic public void ReplaceInListInList() { dynamic doc = new ExpandoObject(); - doc.SimpleDTOList = new List() { - new SimpleDTO() { + doc.SimpleDTOList = new List() { + new SimpleObject() { IntegerList = new List(){1,2,3} }}; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Replace("SimpleDTOList/0/IntegerList/0", 4); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -171,13 +171,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic public void ReplaceInListInListAtEnd() { dynamic doc = new ExpandoObject(); - doc.SimpleDTOList = new List() { - new SimpleDTO() { + doc.SimpleDTOList = new List() { + new SimpleObject() { IntegerList = new List(){1,2,3} }}; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Replace("SimpleDTOList/0/IntegerList/-", 4); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -195,7 +195,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic doc.IntegerList = new List() { 1, 2, 3 }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Replace("IntegerList", new List() { 4, 5, 6 }); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -213,7 +213,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic doc.IntegerList = new List() { 1, 2, 3 }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Replace("IntegerList", new Collection() { 4, 5, 6 }); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -231,7 +231,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic doc.IntegerList = new List() { 1, 2, 3 }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Replace("IntegerList/-", 5); var serialized = JsonConvert.SerializeObject(patchDoc); diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceTypedOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceTypedOperationTests.cs index d0bf23f487..94131ff3b5 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceTypedOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceTypedOperationTests.cs @@ -8,21 +8,21 @@ using System.Linq; using Newtonsoft.Json; using Xunit; -namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic +namespace Microsoft.AspNetCore.JsonPatch.Internal { public class ReplaceTypedOperationTests { [Fact] public void ReplaceGuidTest() { - var doc = new SimpleDTO() + var doc = new SimpleObject() { GuidValue = Guid.NewGuid() }; var newGuid = Guid.NewGuid(); // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Replace("GuidValue", newGuid); // serialize & deserialize @@ -37,23 +37,23 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic [Fact] public void SerializeAndReplaceNestedObjectTest() { - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerValue = 5, IntegerList = new List() { 1, 2, 3 } } }; - var newDTO = new SimpleDTO() + var newDTO = new SimpleObject() { DoubleValue = 1 }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); - patchDoc.Replace("SimpleDTO", newDTO); + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace("SimpleObject", newDTO); // serialize & deserialize var serialized = JsonConvert.SerializeObject(patchDoc); @@ -61,21 +61,21 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic deserialized.ApplyTo(doc); - Assert.Equal(1, doc.SimpleDTO.DoubleValue); - Assert.Equal(0, doc.SimpleDTO.IntegerValue); - Assert.Null(doc.SimpleDTO.IntegerList); + Assert.Equal(1, doc.SimpleObject.DoubleValue); + Assert.Equal(0, doc.SimpleObject.IntegerValue); + Assert.Null(doc.SimpleObject.IntegerList); } [Fact] public void ReplaceInList() { - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Replace("IntegerList/0", 5); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -89,13 +89,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic [Fact] public void ReplaceFullList() { - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Replace("IntegerList", new List() { 4, 5, 6 }); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -109,36 +109,36 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic [Fact] public void ReplaceInListInList() { - var doc = new SimpleDTO() + var doc = new SimpleObject() { - SimpleDTOList = new List() { - new SimpleDTO() { + SimpleObjectList = new List() { + new SimpleObject() { IntegerList = new List(){1,2,3} }} }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); - patchDoc.Replace("SimpleDTOList/0/IntegerList/0", 4); + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace("SimpleObjectList/0/IntegerList/0", 4); var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject(serialized); deserialized.ApplyTo(doc); - Assert.Equal(4, doc.SimpleDTOList.First().IntegerList.First()); + Assert.Equal(4, doc.SimpleObjectList.First().IntegerList.First()); } [Fact] public void ReplaceFullListFromEnumerable() { - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Replace("IntegerList", new List() { 4, 5, 6 }); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -152,13 +152,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic [Fact] public void ReplaceFullListWithCollection() { - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Replace("IntegerList", new Collection() { 4, 5, 6 }); var serialized = JsonConvert.SerializeObject(patchDoc); @@ -172,13 +172,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic [Fact] public void ReplaceAtEndOfList() { - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - JsonPatchDocument patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Replace("IntegerList/-", 5); var serialized = JsonConvert.SerializeObject(patchDoc); diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/SimpleDTOWithNestedDTO.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/SimpleDTOWithNestedDTO.cs deleted file mode 100644 index f8af4bb390..0000000000 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/SimpleDTOWithNestedDTO.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Collections.Generic; - -namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic -{ - public class SimpleDTOWithNestedDTO - { - public int IntegerValue { get; set; } - public NestedDTO NestedDTO { get; set; } - public SimpleDTO SimpleDTO { get; set; } - public List ListOfSimpleDTO { get; set; } - - public SimpleDTOWithNestedDTO() - { - NestedDTO = new NestedDTO(); - SimpleDTO = new SimpleDTO(); - ListOfSimpleDTO = new List(); - } - } -} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/SimpleDTO.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/SimpleObject.cs similarity index 81% rename from test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/SimpleDTO.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/SimpleObject.cs index d4bf19f75a..01a890d7be 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/SimpleDTO.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/SimpleObject.cs @@ -4,11 +4,11 @@ using System; using System.Collections.Generic; -namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic +namespace Microsoft.AspNetCore.JsonPatch.Internal { - public class SimpleDTO + public class SimpleObject { - public List SimpleDTOList { get; set; } + public List SimpleObjectList { get; set; } public List IntegerList { get; set; } public int IntegerValue { get; set; } public string StringProperty { get; set; } diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/SimpleObjectWithNestedObject.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/SimpleObjectWithNestedObject.cs new file mode 100644 index 0000000000..aa766b8438 --- /dev/null +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/SimpleObjectWithNestedObject.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.Collections.Generic; + +namespace Microsoft.AspNetCore.JsonPatch.Internal +{ + public class SimpleObjectWithNestedObject + { + public int IntegerValue { get; set; } + public NestedObject NestedObject { get; set; } + public SimpleObject SimpleObject { get; set; } + public List ListOfSimpleObject { get; set; } + + public SimpleObjectWithNestedObject() + { + NestedObject = new NestedObject(); + SimpleObject = new SimpleObject(); + ListOfSimpleObject = new List(); + } + } +} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/DynamicObjectAdapterTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/DynamicObjectAdapterTest.cs new file mode 100644 index 0000000000..18bb7a775c --- /dev/null +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/DynamicObjectAdapterTest.cs @@ -0,0 +1,231 @@ +// Copyright (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_ReplacesPropertyValue() + { + // Arrange + var adapter = new DynamicObjectAdapter(); + dynamic target = new DynamicTestObject(); + 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); + } + } +} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/DynamicTestObject.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/DynamicTestObject.cs new file mode 100644 index 0000000000..4268d5526c --- /dev/null +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/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.Internal +{ + 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/test/Microsoft.AspNetCore.JsonPatch.Test/InheritedDTO.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/InheritedObject.cs similarity index 85% rename from test/Microsoft.AspNetCore.JsonPatch.Test/InheritedDTO.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/InheritedObject.cs index a784a6304b..37b8a10dc9 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/InheritedDTO.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/InheritedObject.cs @@ -3,7 +3,7 @@ namespace Microsoft.AspNetCore.JsonPatch { - public class InheritedDTO : SimpleDTO + public class InheritedObject : SimpleObject { public string AdditionalStringProperty { get; set; } } diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/DynamicObjectIntegrationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/DynamicObjectIntegrationTests.cs new file mode 100644 index 0000000000..4b5fc96e24 --- /dev/null +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/DynamicObjectIntegrationTests.cs @@ -0,0 +1,263 @@ +// Copyright (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.Internal +{ + public class DynamicObjectIntegrationTests + { + [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 patchDoc = new JsonPatchDocument(); + patchDoc.Add("/Nested/DynamicProperty/InBetweenFirst/InBetweenSecond/StringProperty", "B"); + + // Act + patchDoc.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 patchDoc = new JsonPatchDocument(); + patchDoc.Add("DynamicProperty/OtherProperty/IntProperty", 1); + + // Act + var exception = Assert.Throws(() => + { + patchDoc.ApplyTo(nestedObject); + }); + + // Assert + Assert.Equal( + string.Format( + "The target location specified by path segment '{0}' was not found.", + "OtherProperty"), + 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 patchDoc = new JsonPatchDocument(); + patchDoc.Copy("NestedDynamicObject/StringProperty", "NestedDynamicObject/AnotherStringProperty"); + + // Act + patchDoc.ApplyTo(dynamicTestObject); + + // Assert + Assert.Equal("A", dynamicTestObject.NestedDynamicObject.AnotherStringProperty); + } + + + [Fact] + public void MoveToNonExistingProperty_InDynamicObject_ShouldAddNewProperty() + { + // Arrange + dynamic dynamicTestObject = new DynamicTestObject(); + dynamicTestObject.StringProperty = "A"; + + var patchDoc = new JsonPatchDocument(); + patchDoc.Move("StringProperty", "AnotherStringProperty"); + + // Act + patchDoc.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 patchDoc = new JsonPatchDocument(); + patchDoc.Move("StringProperty", "SimpleObject/AnotherStringProperty"); + + // Act + patchDoc.ApplyTo(dynamicTestObject); + dynamicTestObject.TryGetValue("StringProperty", out object valueFromDictionary); + + // Assert + Assert.Equal("A", dynamicTestObject.SimpleObject.AnotherStringProperty); + Assert.Null(valueFromDictionary); + } + + [Fact] + public void MovePropertyValue_FromListToNonList_InNestedTypedObject_InDynamicObject() + { + // Arrange + dynamic dynamicTestObject = new DynamicTestObject(); + dynamicTestObject.Nested = new SimpleObject() + { + IntegerList = new List() { 1, 2, 3 } + }; + + var patchDoc = new JsonPatchDocument(); + patchDoc.Move("Nested/IntegerList/0", "Nested/IntegerValue"); + + // Act + patchDoc.ApplyTo(dynamicTestObject); + + // Assert + Assert.Equal(new List() { 2, 3 }, dynamicTestObject.Nested.IntegerList); + Assert.Equal(1, dynamicTestObject.Nested.IntegerValue); + } + + [Fact] + public void RemoveNestedProperty_FromDynamicObject() + { + // Arrange + dynamic dynamicTestObject = new DynamicTestObject(); + dynamicTestObject.Test = new DynamicTestObject(); + dynamicTestObject.Test.AnotherTest = "A"; + + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove("Test"); + + // Act + patchDoc.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 patchDoc = new JsonPatchDocument(); + patchDoc.Remove("Simpleobject/stringProperty"); + + // Act + var exception = Assert.Throws(() => + { + patchDoc.ApplyTo(dynamicTestObject); + }); + + // Assert + Assert.Equal( + string.Format("The target location specified by path segment '{0}' was not found.", + "Simpleobject"), + exception.Message); + } + + [Fact] + public void RemoveFromList_NestedInDynamicObject() + { + // Arrange + dynamic dynamicTestObject = new DynamicTestObject(); + dynamicTestObject.SimpleObject = new SimpleObject() + { + IntegerList = new List() { 1, 2, 3 } + }; + + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove("SimpleObject/IntegerList/2"); + + // Act + patchDoc.ApplyTo(dynamicTestObject); + + // Assert + Assert.Equal(new List() { 1, 2 }, dynamicTestObject.SimpleObject.IntegerList); + } + + [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 patchDoc = new JsonPatchDocument(); + patchDoc.Replace("SimpleObject", newObject); + + // Act + patchDoc.ApplyTo(dynamicTestObject); + + // Assert + Assert.Equal(1, dynamicTestObject.SimpleObject.DoubleValue); + Assert.Equal(0, dynamicTestObject.SimpleObject.IntegerValue); + Assert.Null(dynamicTestObject.SimpleObject.IntegerList); + } + + [Fact] + public void ReplaceFullList_InDynamicObject() + { + // Arrange + dynamic dynamicTestObject = new DynamicTestObject(); + dynamicTestObject.IntegerList = new List() { 1, 2, 3 }; + + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace("IntegerList", new List() { 4, 5, 6 }); + + // Act + patchDoc.ApplyTo(dynamicTestObject); + + // Assert + Assert.Equal(new List() { 4, 5, 6 }, dynamicTestObject.IntegerList); + } + } +} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs index efc780b388..3948b79484 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs @@ -14,14 +14,14 @@ namespace Microsoft.AspNetCore.JsonPatch [Fact] public void Add_WithExpression_RespectsJsonPropertyName_ForModelProperty() { - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add(p => p.Name, "John"); var serialized = JsonConvert.SerializeObject(patchDoc); // serialized value should have "AnotherName" as path // deserialize to a JsonPatchDocument to check var deserialized = - JsonConvert.DeserializeObject>(serialized); + JsonConvert.DeserializeObject>(serialized); // get path var pathToCheck = deserialized.Operations.First().path; @@ -65,19 +65,19 @@ namespace Microsoft.AspNetCore.JsonPatch [Fact] public void Add_WithExpression_RespectsJsonPropertyName_WhenApplyingToDifferentlyTypedClassWithPropertyMatchingJsonPropertyName() { - var patchDocToSerialize = new JsonPatchDocument(); + var patchDocToSerialize = new JsonPatchDocument(); patchDocToSerialize.Add(p => p.Name, "John"); // the patchdoc will deserialize to "anothername". We should thus be able to apply // it to a class that HAS that other property name. - var doc = new JsonPropertyWithAnotherNameDTO() + var doc = new JsonPropertyWithAnotherNameObject() { AnotherName = "InitialValue" }; var serialized = JsonConvert.SerializeObject(patchDocToSerialize); var deserialized = - JsonConvert.DeserializeObject> + JsonConvert.DeserializeObject> (serialized); deserialized.ApplyTo(doc); @@ -88,21 +88,21 @@ namespace Microsoft.AspNetCore.JsonPatch [Fact] public void Add_WithExpression_RespectsJsonPropertyName_WhenApplyingToSameTypedClassWithMatchingJsonPropertyName() { - var patchDocToSerialize = new JsonPatchDocument(); + var patchDocToSerialize = new JsonPatchDocument(); patchDocToSerialize.Add(p => p.Name, "John"); // the patchdoc will deserialize to "anothername". As JsonPropertyDTO has // a JsonProperty signifying that "Name" should be deseriallized from "AnotherName", // we should be able to apply the patchDoc. - var doc = new JsonPropertyDTO() + var doc = new JsonPropertyObject() { Name = "InitialValue" }; var serialized = JsonConvert.SerializeObject(patchDocToSerialize); var deserialized = - JsonConvert.DeserializeObject> + JsonConvert.DeserializeObject> (serialized); deserialized.ApplyTo(doc); @@ -113,7 +113,7 @@ namespace Microsoft.AspNetCore.JsonPatch [Fact] public void Add_OnApplyFromJson_RespectsJsonPropertyNameOnJsonDocument() { - var doc = new JsonPropertyDTO() + var doc = new JsonPropertyObject() { Name = "InitialValue" }; @@ -121,7 +121,7 @@ namespace Microsoft.AspNetCore.JsonPatch // serialization should serialize to "AnotherName" var serialized = "[{\"value\":\"Kevin\",\"path\":\"/AnotherName\",\"op\":\"add\"}]"; var deserialized = - JsonConvert.DeserializeObject>(serialized); + JsonConvert.DeserializeObject>(serialized); deserialized.ApplyTo(doc); @@ -131,7 +131,7 @@ namespace Microsoft.AspNetCore.JsonPatch [Fact] public void Remove_OnApplyFromJson_RespectsJsonPropertyNameOnJsonDocument() { - var doc = new JsonPropertyDTO() + var doc = new JsonPropertyObject() { Name = "InitialValue" }; @@ -139,7 +139,7 @@ namespace Microsoft.AspNetCore.JsonPatch // serialization should serialize to "AnotherName" var serialized = "[{\"path\":\"/AnotherName\",\"op\":\"remove\"}]"; var deserialized = - JsonConvert.DeserializeObject>(serialized); + JsonConvert.DeserializeObject>(serialized); deserialized.ApplyTo(doc); @@ -149,7 +149,7 @@ namespace Microsoft.AspNetCore.JsonPatch [Fact] public void Add_OnApplyFromJson_RespectsInheritedJsonPropertyNameOnJsonDocument() { - var doc = new JsonPropertyWithInheritanceDTO() + var doc = new JsonPropertyWithInheritanceObject() { Name = "InitialName" }; @@ -157,7 +157,7 @@ namespace Microsoft.AspNetCore.JsonPatch // serialization should serialize to "AnotherName" var serialized = "[{\"value\":\"Kevin\",\"path\":\"/AnotherName\",\"op\":\"add\"}]"; var deserialized = - JsonConvert.DeserializeObject>(serialized); + JsonConvert.DeserializeObject>(serialized); deserialized.ApplyTo(doc); @@ -167,14 +167,14 @@ namespace Microsoft.AspNetCore.JsonPatch [Fact] public void Add_WithExpression_RespectsJsonPropertyName_ForInheritedModelProperty() { - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add(p => p.Name, "John"); var serialized = JsonConvert.SerializeObject(patchDoc); // serialized value should have "AnotherName" as path // deserialize to a JsonPatchDocument to check var deserialized = - JsonConvert.DeserializeObject>(serialized); + JsonConvert.DeserializeObject>(serialized); // get path var pathToCheck = deserialized.Operations.First().path; @@ -184,10 +184,10 @@ namespace Microsoft.AspNetCore.JsonPatch [Fact] public void Add_OnApplyFromJson_EscapingHandledOnComplexJsonPropertyNameOnJsonDocument() { - var doc = new JsonPropertyComplexNameDTO() + var doc = new JsonPropertyComplexNameObject() { FooSlashBars = "InitialName", - FooSlashTilde = new SimpleDTO + FooSlashTilde = new SimpleObject { StringProperty = "Initial Value" } @@ -196,7 +196,7 @@ namespace Microsoft.AspNetCore.JsonPatch // serialization should serialize to "AnotherName" var serialized = "[{\"value\":\"Kevin\",\"path\":\"/foo~1bar~0\",\"op\":\"add\"},{\"value\":\"Final Value\",\"path\":\"/foo~1~0/StringProperty\",\"op\":\"replace\"}]"; var deserialized = - JsonConvert.DeserializeObject>(serialized); + JsonConvert.DeserializeObject>(serialized); deserialized.ApplyTo(doc); diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyComplexNameDTO.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyComplexNameObject.cs similarity index 78% rename from test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyComplexNameDTO.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyComplexNameObject.cs index 7ff66481ad..a39aa8e30c 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyComplexNameDTO.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyComplexNameObject.cs @@ -5,12 +5,12 @@ using Newtonsoft.Json; namespace Microsoft.AspNetCore.JsonPatch { - public class JsonPropertyComplexNameDTO + public class JsonPropertyComplexNameObject { [JsonProperty("foo/bar~")] public string FooSlashBars { get; set; } [JsonProperty("foo/~")] - public SimpleDTO FooSlashTilde { get; set; } + public SimpleObject FooSlashTilde { get; set; } } } diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyDTO.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyObject.cs similarity index 90% rename from test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyDTO.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyObject.cs index c926d9f5fd..245ae6bb65 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyDTO.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyObject.cs @@ -5,7 +5,7 @@ using Newtonsoft.Json; namespace Microsoft.AspNetCore.JsonPatch { - public class JsonPropertyDTO + public class JsonPropertyObject { [JsonProperty("AnotherName")] public string Name { get; set; } diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyWithAnotherNameDTO.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyWithAnotherNameObject.cs similarity index 84% rename from test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyWithAnotherNameDTO.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyWithAnotherNameObject.cs index 9b61e09005..4581a4826d 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyWithAnotherNameDTO.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyWithAnotherNameObject.cs @@ -3,7 +3,7 @@ namespace Microsoft.AspNetCore.JsonPatch { - public class JsonPropertyWithAnotherNameDTO + public class JsonPropertyWithAnotherNameObject { public string AnotherName { get; set; } } diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyWithInheritanceDTO.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyWithInheritanceDTO.cs deleted file mode 100644 index fa69425ea9..0000000000 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyWithInheritanceDTO.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Microsoft.AspNetCore.JsonPatch -{ - public class JsonPropertyWithInheritanceDTO : JsonPropertyWithInheritanceBaseDTO - { - public override string Name { get; set; } - } - - public abstract class JsonPropertyWithInheritanceBaseDTO - { - [JsonProperty("AnotherName")] - public abstract string Name { get; set; } - } -} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyWithInheritanceObject.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyWithInheritanceObject.cs new file mode 100644 index 0000000000..935ef275ad --- /dev/null +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyWithInheritanceObject.cs @@ -0,0 +1,15 @@ +using Newtonsoft.Json; + +namespace Microsoft.AspNetCore.JsonPatch +{ + public class JsonPropertyWithInheritanceObject : JsonPropertyWithInheritanceBaseObject + { + public override string Name { get; set; } + } + + public abstract class JsonPropertyWithInheritanceBaseObject + { + [JsonProperty("AnotherName")] + public abstract string Name { get; set; } + } +} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/ListAdapterTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/ListAdapterTest.cs index 6a087edd8f..3c692ea150 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/ListAdapterTest.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/ListAdapterTest.cs @@ -18,10 +18,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal var resolver = new Mock(MockBehavior.Strict); var targetObject = new[] { 20, 30 }; var listAdapter = new ListAdapter(); - string message = null; // Act - var addStatus = listAdapter.TryAdd(targetObject, "0", resolver.Object, "40", out message); + var addStatus = listAdapter.TryAdd(targetObject, "0", resolver.Object, "40", out var message); // Assert Assert.False(addStatus); @@ -41,10 +40,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal targetObject.Add(20); targetObject.Add(30); var listAdapter = new ListAdapter(); - string message = null; // Act - var addStatus = listAdapter.TryAdd(targetObject, "-", resolver.Object, "40", out message); + var addStatus = listAdapter.TryAdd(targetObject, "-", resolver.Object, "40", out var message); // Assert Assert.False(addStatus); @@ -62,11 +60,10 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal var resolver = new Mock(MockBehavior.Strict); var targetObject = new List() { "James", "Mike" }; var listAdapter = new ListAdapter(); - string message = null; var position = targetObject.Count.ToString(); // Act - var addStatus = listAdapter.TryAdd(targetObject, position, resolver.Object, "Rob", out message); + var addStatus = listAdapter.TryAdd(targetObject, position, resolver.Object, "Rob", out var message); // Assert Assert.Null(message); @@ -85,10 +82,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal var resolver = new Mock(MockBehavior.Strict); var targetObject = new List() { "James", "Mike" }; var listAdapter = new ListAdapter(); - string message = null; // Act - var addStatus = listAdapter.TryAdd(targetObject, position, resolver.Object, "40", out message); + var addStatus = listAdapter.TryAdd(targetObject, position, resolver.Object, "40", out var message); // Assert Assert.False(addStatus); @@ -106,10 +102,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal var resolver = new Mock(MockBehavior.Strict); var targetObject = new List() { "James", "Mike" }; var listAdapter = new ListAdapter(); - string message = null; // Act - var addStatus = listAdapter.TryAdd(targetObject, position, resolver.Object, "40", out message); + var addStatus = listAdapter.TryAdd(targetObject, position, resolver.Object, "40", out var message); // Assert Assert.False(addStatus); @@ -143,10 +138,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal // Arrange var resolver = new Mock(MockBehavior.Strict); var listAdapter = new ListAdapter(); - string message = null; // Act - var addStatus = listAdapter.TryAdd(targetObject, "-", resolver.Object, "20", out message); + var addStatus = listAdapter.TryAdd(targetObject, "-", resolver.Object, "20", out var message); // Assert Assert.True(addStatus); @@ -162,10 +156,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal var resolver = new Mock(MockBehavior.Strict); var listAdapter = new ListAdapter(); var targetObject = new List() { "James", "Mike" }; - string message = null; // Act - var addStatus = listAdapter.TryAdd(targetObject, "-", resolver.Object, value: null, errorMessage: out message); + var addStatus = listAdapter.TryAdd(targetObject, "-", resolver.Object, value: null, errorMessage: out var message); // Assert Assert.True(addStatus); @@ -178,21 +171,20 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal public void Add_CompatibleTypeWorks() { // Arrange - var sDto = new SimpleDTO(); - var iDto = new InheritedDTO(); + var sDto = new SimpleObject(); + var iDto = new InheritedObject(); var resolver = new Mock(MockBehavior.Strict); - var targetObject = new List() { sDto }; + var targetObject = new List() { sDto }; var listAdapter = new ListAdapter(); - string message = null; // Act - var addStatus = listAdapter.TryAdd(targetObject, "-", resolver.Object, iDto, out message); + 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); + Assert.Equal(new List() { sDto, iDto }, targetObject); } [Fact] @@ -202,10 +194,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal var resolver = new Mock(MockBehavior.Strict); var targetObject = new List() { 10, 20 }; var listAdapter = new ListAdapter(); - string message = null; // Act - var addStatus = listAdapter.TryAdd(targetObject, "-", resolver.Object, "James", out message); + var addStatus = listAdapter.TryAdd(targetObject, "-", resolver.Object, "James", out var message); // Assert Assert.False(addStatus); @@ -253,10 +244,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal // Arrange var resolver = new Mock(MockBehavior.Strict); var listAdapter = new ListAdapter(); - string message = null; // Act - var addStatus = listAdapter.TryAdd(targetObject, position, resolver.Object, value, out message); + var addStatus = listAdapter.TryAdd(targetObject, position, resolver.Object, value, out var message); // Assert Assert.True(addStatus); @@ -267,34 +257,34 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal public static TheoryData AddingKeepsObjectReferenceData { get { - var sDto1 = new SimpleDTO(); - var sDto2 = new SimpleDTO(); - var sDto3 = new SimpleDTO(); + var sDto1 = new SimpleObject(); + var sDto2 = new SimpleObject(); + var sDto3 = new SimpleObject(); return new TheoryData() { { - new List() { }, + new List() { }, sDto1, "-", - new List() { sDto1 } + new List() { sDto1 } }, { - new List() { sDto1, sDto2 }, + new List() { sDto1, sDto2 }, sDto3, "-", - new List() { sDto1, sDto2, sDto3 } + new List() { sDto1, sDto2, sDto3 } }, { - new List() { sDto1, sDto2 }, + new List() { sDto1, sDto2 }, sDto3, "0", - new List() { sDto3, sDto1, sDto2 } + new List() { sDto3, sDto1, sDto2 } }, { - new List() { sDto1, sDto2 }, + new List() { sDto1, sDto2 }, sDto3, "1", - new List() { sDto1, sDto3, sDto2 } + new List() { sDto1, sDto3, sDto2 } } }; } @@ -307,10 +297,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal // Arrange var resolver = new Mock(MockBehavior.Strict); var listAdapter = new ListAdapter(); - string message = null; // Act - var addStatus = listAdapter.TryAdd(targetObject, position, resolver.Object, value, out message); + var addStatus = listAdapter.TryAdd(targetObject, position, resolver.Object, value, out var message); // Assert Assert.True(addStatus); @@ -329,11 +318,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal var resolver = new Mock(MockBehavior.Strict); var targetObject = new List(input); var listAdapter = new ListAdapter(); - string message = null; - object value = null; // Act - var getStatus = listAdapter.TryGet(targetObject, position, resolver.Object, out value, out message); + var getStatus = listAdapter.TryGet(targetObject, position, resolver.Object, out var value, out var message); // Assert Assert.False(getStatus); @@ -352,11 +339,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal var resolver = new Mock(MockBehavior.Strict); var targetObject = new List(input); var listAdapter = new ListAdapter(); - string message = null; - object value = null; // Act - var getStatus = listAdapter.TryGet(targetObject, position, resolver.Object, out value, out message); + var getStatus = listAdapter.TryGet(targetObject, position, resolver.Object, out var value, out var message); // Assert Assert.True(getStatus); @@ -374,10 +359,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal var resolver = new Mock(MockBehavior.Strict); var targetObject = new List(input); var listAdapter = new ListAdapter(); - string message = null; // Act - var removeStatus = listAdapter.TryRemove(targetObject, position, resolver.Object, out message); + var removeStatus = listAdapter.TryRemove(targetObject, position, resolver.Object, out var message); // Assert Assert.False(removeStatus); @@ -396,10 +380,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal var resolver = new Mock(MockBehavior.Strict); var targetObject = new List(input); var listAdapter = new ListAdapter(); - string message = null; // Act - var removeStatus = listAdapter.TryRemove(targetObject, position, resolver.Object, out message); + var removeStatus = listAdapter.TryRemove(targetObject, position, resolver.Object, out var message); // Assert Assert.True(removeStatus); @@ -413,10 +396,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal var resolver = new Mock(MockBehavior.Strict); var targetObject = new List() { 10, 20 }; var listAdapter = new ListAdapter(); - string message = null; // Act - var replaceStatus = listAdapter.TryReplace(targetObject, "-", resolver.Object, "James", out message); + var replaceStatus = listAdapter.TryReplace(targetObject, "-", resolver.Object, "James", out var message); // Assert Assert.False(replaceStatus); @@ -432,10 +414,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal var resolver = new Mock(MockBehavior.Strict); var targetObject = new List() { 10, 20 }; var listAdapter = new ListAdapter(); - string message = null; // Act - var replaceStatus = listAdapter.TryReplace(targetObject, "-", resolver.Object, "30", out message); + var replaceStatus = listAdapter.TryReplace(targetObject, "-", resolver.Object, "30", out var message); // Assert Assert.True(replaceStatus); @@ -469,10 +450,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal var resolver = new Mock(MockBehavior.Strict); var targetObject = new List() { 10, 20 }; var listAdapter = new ListAdapter(); - string message = null; // Act - var replaceStatus = listAdapter.TryReplace(targetObject, position, resolver.Object, "30", out message); + var replaceStatus = listAdapter.TryReplace(targetObject, position, resolver.Object, "30", out var message); // Assert Assert.True(replaceStatus); diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/NestedDTO.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/NestedObject.cs similarity index 89% rename from test/Microsoft.AspNetCore.JsonPatch.Test/NestedDTO.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/NestedObject.cs index 90be5152cb..8f0927297e 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/NestedDTO.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/NestedObject.cs @@ -3,7 +3,7 @@ namespace Microsoft.AspNetCore.JsonPatch { - public class NestedDTO + public class NestedObject { public string StringProperty { get; set; } } diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/NestedObjectTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/NestedObjectTests.cs index 4aa25a3af1..a0b5bd7e3f 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/NestedObjectTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/NestedObjectTests.cs @@ -15,249 +15,249 @@ namespace Microsoft.AspNetCore.JsonPatch public void ReplacePropertyInNestedObject() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { IntegerValue = 1 }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.NestedDTO.StringProperty, "B"); + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.NestedObject.StringProperty, "B"); // Act patchDoc.ApplyTo(doc); // Assert - Assert.Equal("B", doc.NestedDTO.StringProperty); + Assert.Equal("B", doc.NestedObject.StringProperty); } [Fact] public void ReplacePropertyInNestedObjectWithSerialization() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { IntegerValue = 1 }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.NestedDTO.StringProperty, "B"); + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.NestedObject.StringProperty, "B"); // serialize & deserialize var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); // Assert - Assert.Equal("B", doc.NestedDTO.StringProperty); + Assert.Equal("B", doc.NestedObject.StringProperty); } [Fact] public void ReplaceNestedObject() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { IntegerValue = 1 }; - var newNested = new NestedDTO() { StringProperty = "B" }; + var newNested = new NestedObject() { StringProperty = "B" }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.NestedDTO, newNested); + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.NestedObject, newNested); // Act patchDoc.ApplyTo(doc); // Assert - Assert.Equal("B", doc.NestedDTO.StringProperty); + Assert.Equal("B", doc.NestedObject.StringProperty); } [Fact] public void ReplaceNestedObjectWithSerialization() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { IntegerValue = 1 }; - var newNested = new NestedDTO() { StringProperty = "B" }; + var newNested = new NestedObject() { StringProperty = "B" }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.NestedDTO, newNested); + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.NestedObject, newNested); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); // Assert - Assert.Equal("B", doc.NestedDTO.StringProperty); + Assert.Equal("B", doc.NestedObject.StringProperty); } [Fact] public void AddResultsInReplace() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { StringProperty = "A" } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.SimpleDTO.StringProperty, "B"); + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.SimpleObject.StringProperty, "B"); // Act patchDoc.ApplyTo(doc); // Assert - Assert.Equal("B", doc.SimpleDTO.StringProperty); + Assert.Equal("B", doc.SimpleObject.StringProperty); } [Fact] public void AddResultsInReplaceWithSerialization() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { StringProperty = "A" } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.SimpleDTO.StringProperty, "B"); + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.SimpleObject.StringProperty, "B"); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); // Assert - Assert.Equal("B", doc.SimpleDTO.StringProperty); + Assert.Equal("B", doc.SimpleObject.StringProperty); } [Fact] public void AddToList() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.SimpleDTO.IntegerList, 4, 0); + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.SimpleObject.IntegerList, 4, 0); // Act patchDoc.ApplyTo(doc); // Assert - Assert.Equal(new List() { 4, 1, 2, 3 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 4, 1, 2, 3 }, doc.SimpleObject.IntegerList); } [Fact] public void AddToListWithSerialization() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.SimpleDTO.IntegerList, 4, 0); + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.SimpleObject.IntegerList, 4, 0); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); // Assert - Assert.Equal(new List() { 4, 1, 2, 3 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 4, 1, 2, 3 }, doc.SimpleObject.IntegerList); } [Fact] public void AddToIntegerIList() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerIList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => (List)o.SimpleDTO.IntegerIList, 4, 0); + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => (List)o.SimpleObject.IntegerIList, 4, 0); // Act patchDoc.ApplyTo(doc); // Assert - Assert.Equal(new List() { 4, 1, 2, 3 }, doc.SimpleDTO.IntegerIList); + Assert.Equal(new List() { 4, 1, 2, 3 }, doc.SimpleObject.IntegerIList); } [Fact] public void AddToIntegerIListWithSerialization() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerIList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => (List)o.SimpleDTO.IntegerIList, 4, 0); + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => (List)o.SimpleObject.IntegerIList, 4, 0); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); // Assert - Assert.Equal(new List() { 4, 1, 2, 3 }, doc.SimpleDTO.IntegerIList); + Assert.Equal(new List() { 4, 1, 2, 3 }, doc.SimpleObject.IntegerIList); } [Fact] public void AddToNestedIntegerIList() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTOIList = new List + SimpleObjectIList = new List { - new SimpleDTO + new SimpleObject { IntegerIList = new List() { 1, 2, 3 } } @@ -265,25 +265,25 @@ namespace Microsoft.AspNetCore.JsonPatch }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => (List)o.SimpleDTOIList[0].IntegerIList, 4, 0); + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => (List)o.SimpleObjectIList[0].IntegerIList, 4, 0); // Act patchDoc.ApplyTo(doc); // Assert - Assert.Equal(new List() { 4, 1, 2, 3 }, doc.SimpleDTOIList[0].IntegerIList); + Assert.Equal(new List() { 4, 1, 2, 3 }, doc.SimpleObjectIList[0].IntegerIList); } [Fact] public void AddToNestedIntegerIListWithSerialization() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTOIList = new List + SimpleObjectIList = new List { - new SimpleDTO + new SimpleObject { IntegerIList = new List() { 1, 2, 3 } } @@ -291,32 +291,32 @@ namespace Microsoft.AspNetCore.JsonPatch }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => (List)o.SimpleDTOIList[0].IntegerIList, 4, 0); + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => (List)o.SimpleObjectIList[0].IntegerIList, 4, 0); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); // Assert - Assert.Equal(new List() { 4, 1, 2, 3 }, doc.SimpleDTOIList[0].IntegerIList); + Assert.Equal(new List() { 4, 1, 2, 3 }, doc.SimpleObjectIList[0].IntegerIList); } [Fact] public void AddToComplextTypeListSpecifyIndex() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTOList = new List() + SimpleObjectList = new List() { - new SimpleDTO + new SimpleObject { StringProperty = "String1" }, - new SimpleDTO + new SimpleObject { StringProperty = "String2" } @@ -324,29 +324,29 @@ namespace Microsoft.AspNetCore.JsonPatch }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.SimpleDTOList[0].StringProperty, "ChangedString1"); + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.SimpleObjectList[0].StringProperty, "ChangedString1"); // Act patchDoc.ApplyTo(doc); // Assert - Assert.Equal("ChangedString1", doc.SimpleDTOList[0].StringProperty); + Assert.Equal("ChangedString1", doc.SimpleObjectList[0].StringProperty); } [Fact] public void AddToComplextTypeListSpecifyIndexWithSerialization() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTOList = new List() + SimpleObjectList = new List() { - new SimpleDTO + new SimpleObject { StringProperty = "String1" }, - new SimpleDTO + new SimpleObject { StringProperty = "String2" } @@ -354,34 +354,34 @@ namespace Microsoft.AspNetCore.JsonPatch }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.SimpleDTOList[0].StringProperty, "ChangedString1"); + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.SimpleObjectList[0].StringProperty, "ChangedString1"); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); // Assert - Assert.Equal("ChangedString1", doc.SimpleDTOList[0].StringProperty); + Assert.Equal("ChangedString1", doc.SimpleObjectList[0].StringProperty); } [Fact] public void AddToListInvalidPositionTooLarge() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.SimpleDTO.IntegerList, 4, 4); + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.SimpleObject.IntegerList, 4, 4); // Act & Assert var exception = Assert.Throws(() => { patchDoc.ApplyTo(doc); }); @@ -395,20 +395,20 @@ namespace Microsoft.AspNetCore.JsonPatch public void AddToListInvalidPositionTooLargeWithSerialization() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.SimpleDTO.IntegerList, 4, 4); + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.SimpleObject.IntegerList, 4, 4); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act & Assert var exception = Assert.Throws(() => @@ -424,19 +424,19 @@ namespace Microsoft.AspNetCore.JsonPatch public void AddToListInvalidPositionTooLarge_LogsError() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.SimpleDTO.IntegerList, 4, 4); + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.SimpleObject.IntegerList, 4, 4); - var logger = new TestErrorLogger(); + var logger = new TestErrorLogger(); patchDoc.ApplyTo(doc, logger.LogErrorMessage); @@ -452,17 +452,17 @@ namespace Microsoft.AspNetCore.JsonPatch public void AddToListInvalidPositionTooSmall() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.SimpleDTO.IntegerList, 4, -1); + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.SimpleObject.IntegerList, 4, -1); // Act & Assert var exception = Assert.Throws(() => { patchDoc.ApplyTo(doc); }); @@ -475,20 +475,20 @@ namespace Microsoft.AspNetCore.JsonPatch public void AddToListInvalidPositionTooSmallWithSerialization() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.SimpleDTO.IntegerList, 4, -1); + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.SimpleObject.IntegerList, 4, -1); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act & Assert var exception = Assert.Throws(() => @@ -504,19 +504,19 @@ namespace Microsoft.AspNetCore.JsonPatch public void AddToListInvalidPositionTooSmall_LogsError() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.SimpleDTO.IntegerList, 4, -1); + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.SimpleObject.IntegerList, 4, -1); - var logger = new TestErrorLogger(); + var logger = new TestErrorLogger(); patchDoc.ApplyTo(doc, logger.LogErrorMessage); @@ -532,164 +532,164 @@ namespace Microsoft.AspNetCore.JsonPatch public void AddToListAppend() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.SimpleDTO.IntegerList, 4); + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.SimpleObject.IntegerList, 4); // Act patchDoc.ApplyTo(doc); // Assert - Assert.Equal(new List() { 1, 2, 3, 4 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 1, 2, 3, 4 }, doc.SimpleObject.IntegerList); } [Fact] public void AddToListAppendWithSerialization() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.SimpleDTO.IntegerList, 4); + var patchDoc = new JsonPatchDocument(); + patchDoc.Add(o => o.SimpleObject.IntegerList, 4); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); // Assert - Assert.Equal(new List() { 1, 2, 3, 4 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 1, 2, 3, 4 }, doc.SimpleObject.IntegerList); } [Fact] public void Remove() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { StringProperty = "A" } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove(o => o.SimpleDTO.StringProperty); + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove(o => o.SimpleObject.StringProperty); // Act patchDoc.ApplyTo(doc); // Assert - Assert.Null(doc.SimpleDTO.StringProperty); + Assert.Null(doc.SimpleObject.StringProperty); } [Fact] public void RemoveWithSerialization() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { StringProperty = "A" } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove(o => o.SimpleDTO.StringProperty); + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove(o => o.SimpleObject.StringProperty); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); // Assert - Assert.Null(doc.SimpleDTO.StringProperty); + Assert.Null(doc.SimpleObject.StringProperty); } [Fact] public void RemoveFromList() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove(o => o.SimpleDTO.IntegerList, 2); + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove(o => o.SimpleObject.IntegerList, 2); // Act patchDoc.ApplyTo(doc); // Assert - Assert.Equal(new List() { 1, 2 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 1, 2 }, doc.SimpleObject.IntegerList); } [Fact] public void RemoveFromListWithSerialization() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove(o => o.SimpleDTO.IntegerList, 2); + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove(o => o.SimpleObject.IntegerList, 2); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); // Assert - Assert.Equal(new List() { 1, 2 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 1, 2 }, doc.SimpleObject.IntegerList); } [Fact] public void RemoveFromListInvalidPositionTooLarge() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove(o => o.SimpleDTO.IntegerList, 3); + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove(o => o.SimpleObject.IntegerList, 3); // Act & Assert var exception = Assert.Throws(() => { patchDoc.ApplyTo(doc); }); @@ -702,20 +702,20 @@ namespace Microsoft.AspNetCore.JsonPatch public void RemoveFromListInvalidPositionTooLargeWithSerialization() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove(o => o.SimpleDTO.IntegerList, 3); + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove(o => o.SimpleObject.IntegerList, 3); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act & Assert var exception = Assert.Throws(() => @@ -731,19 +731,19 @@ namespace Microsoft.AspNetCore.JsonPatch public void RemoveFromListInvalidPositionTooLarge_LogsError() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove(o => o.SimpleDTO.IntegerList, 3); + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove(o => o.SimpleObject.IntegerList, 3); - var logger = new TestErrorLogger(); + var logger = new TestErrorLogger(); patchDoc.ApplyTo(doc, logger.LogErrorMessage); @@ -757,17 +757,17 @@ namespace Microsoft.AspNetCore.JsonPatch public void RemoveFromListInvalidPositionTooSmall() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove(o => o.SimpleDTO.IntegerList, -1); + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove(o => o.SimpleObject.IntegerList, -1); // Act & Assert var exception = Assert.Throws(() => { patchDoc.ApplyTo(doc); }); @@ -780,20 +780,20 @@ namespace Microsoft.AspNetCore.JsonPatch public void RemoveFromListInvalidPositionTooSmallWithSerialization() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove(o => o.SimpleDTO.IntegerList, -1); + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove(o => o.SimpleObject.IntegerList, -1); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act & Assert var exception = Assert.Throws(() => @@ -809,19 +809,19 @@ namespace Microsoft.AspNetCore.JsonPatch public void RemoveFromListInvalidPositionTooSmall_LogsError() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove(o => o.SimpleDTO.IntegerList, -1); + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove(o => o.SimpleObject.IntegerList, -1); - var logger = new TestErrorLogger(); + var logger = new TestErrorLogger(); patchDoc.ApplyTo(doc, logger.LogErrorMessage); @@ -836,58 +836,58 @@ namespace Microsoft.AspNetCore.JsonPatch public void RemoveFromEndOfList() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove(o => o.SimpleDTO.IntegerList); + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove(o => o.SimpleObject.IntegerList); // Act patchDoc.ApplyTo(doc); // Assert - Assert.Equal(new List() { 1, 2 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 1, 2 }, doc.SimpleObject.IntegerList); } [Fact] public void RemoveFromEndOfListWithSerialization() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove(o => o.SimpleDTO.IntegerList); + var patchDoc = new JsonPatchDocument(); + patchDoc.Remove(o => o.SimpleObject.IntegerList); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); // Assert - Assert.Equal(new List() { 1, 2 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 1, 2 }, doc.SimpleObject.IntegerList); } [Fact] public void Replace() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { StringProperty = "A", DecimalValue = 10 @@ -895,48 +895,48 @@ namespace Microsoft.AspNetCore.JsonPatch }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.SimpleDTO.StringProperty, "B"); - patchDoc.Replace(o => o.SimpleDTO.DecimalValue, 12); + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.SimpleObject.StringProperty, "B"); + patchDoc.Replace(o => o.SimpleObject.DecimalValue, 12); // Act patchDoc.ApplyTo(doc); // Assert - Assert.Equal("B", doc.SimpleDTO.StringProperty); - Assert.Equal(12, doc.SimpleDTO.DecimalValue); + Assert.Equal("B", doc.SimpleObject.StringProperty); + Assert.Equal(12, doc.SimpleObject.DecimalValue); } [Fact] public void Replace_DTOWithNullCheck() { // Arrange - var doc = new SimpleDTOWithNestedDTOWithNullCheck() + var doc = new SimpleObjectWithNestedObjectWithNullCheck() { - SimpleDTOWithNullCheck = new SimpleDTOWithNullCheck() + SimpleObjectWithNullCheck = new SimpleObjectWithNullCheck() { StringProperty = "A" } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.SimpleDTOWithNullCheck.StringProperty, "B"); + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.SimpleObjectWithNullCheck.StringProperty, "B"); // Act patchDoc.ApplyTo(doc); // Assert - Assert.Equal("B", doc.SimpleDTOWithNullCheck.StringProperty); + Assert.Equal("B", doc.SimpleObjectWithNullCheck.StringProperty); } [Fact] public void ReplaceWithSerialization() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { StringProperty = "A", DecimalValue = 10 @@ -944,28 +944,28 @@ namespace Microsoft.AspNetCore.JsonPatch }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.SimpleDTO.StringProperty, "B"); - patchDoc.Replace(o => o.SimpleDTO.DecimalValue, 12); + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.SimpleObject.StringProperty, "B"); + patchDoc.Replace(o => o.SimpleObject.DecimalValue, 12); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); // Assert - Assert.Equal("B", doc.SimpleDTO.StringProperty); - Assert.Equal(12, doc.SimpleDTO.DecimalValue); + Assert.Equal("B", doc.SimpleObject.StringProperty); + Assert.Equal(12, doc.SimpleObject.DecimalValue); } [Fact] public void SerializationTests() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { StringProperty = "A", DecimalValue = 10, @@ -976,288 +976,288 @@ namespace Microsoft.AspNetCore.JsonPatch }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.SimpleDTO.StringProperty, "B"); - patchDoc.Replace(o => o.SimpleDTO.DecimalValue, 12); - patchDoc.Replace(o => o.SimpleDTO.DoubleValue, 12); - patchDoc.Replace(o => o.SimpleDTO.FloatValue, 12); - patchDoc.Replace(o => o.SimpleDTO.IntegerValue, 12); + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.SimpleObject.StringProperty, "B"); + patchDoc.Replace(o => o.SimpleObject.DecimalValue, 12); + patchDoc.Replace(o => o.SimpleObject.DoubleValue, 12); + patchDoc.Replace(o => o.SimpleObject.FloatValue, 12); + patchDoc.Replace(o => o.SimpleObject.IntegerValue, 12); // serialize & deserialize var serialized = JsonConvert.SerializeObject(patchDoc); - var deserizalized = JsonConvert.DeserializeObject>(serialized); + var deserizalized = JsonConvert.DeserializeObject>(serialized); // Act deserizalized.ApplyTo(doc); // Assert - Assert.Equal("B", doc.SimpleDTO.StringProperty); - Assert.Equal(12, doc.SimpleDTO.DecimalValue); - Assert.Equal(12, doc.SimpleDTO.DoubleValue); - Assert.Equal(12, doc.SimpleDTO.FloatValue); - Assert.Equal(12, doc.SimpleDTO.IntegerValue); + Assert.Equal("B", doc.SimpleObject.StringProperty); + Assert.Equal(12, doc.SimpleObject.DecimalValue); + Assert.Equal(12, doc.SimpleObject.DoubleValue); + Assert.Equal(12, doc.SimpleObject.FloatValue); + Assert.Equal(12, doc.SimpleObject.IntegerValue); } [Fact] public void ReplaceInList() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.SimpleDTO.IntegerList, 5, 0); + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.SimpleObject.IntegerList, 5, 0); // Act patchDoc.ApplyTo(doc); // Assert - Assert.Equal(new List() { 5, 2, 3 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 5, 2, 3 }, doc.SimpleObject.IntegerList); } [Fact] public void ReplaceInListWithSerialization() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.SimpleDTO.IntegerList, 5, 0); + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.SimpleObject.IntegerList, 5, 0); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); // Assert - Assert.Equal(new List() { 5, 2, 3 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 5, 2, 3 }, doc.SimpleObject.IntegerList); } [Fact] public void ReplaceFullList() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace>(o => o.SimpleDTO.IntegerList, new List() { 4, 5, 6 }); + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.SimpleObject.IntegerList, new List() { 4, 5, 6 }); // Act patchDoc.ApplyTo(doc); // Arrange - Assert.Equal(new List() { 4, 5, 6 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 4, 5, 6 }, doc.SimpleObject.IntegerList); } [Fact] public void ReplaceFullListWithSerialiation() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace>(o => o.SimpleDTO.IntegerList, new List() { 4, 5, 6 }); + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.SimpleObject.IntegerList, new List() { 4, 5, 6 }); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); // Assert - Assert.Equal(new List() { 4, 5, 6 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 4, 5, 6 }, doc.SimpleObject.IntegerList); } [Fact] public void ReplaceFullListFromEnumerable() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace>(o => o.SimpleDTO.IntegerList, new List() { 4, 5, 6 }); + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace>(o => o.SimpleObject.IntegerList, new List() { 4, 5, 6 }); // Act patchDoc.ApplyTo(doc); // Assert - Assert.Equal(new List() { 4, 5, 6 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 4, 5, 6 }, doc.SimpleObject.IntegerList); } [Fact] public void ReplaceFullListFromEnumerableWithSerialization() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace>(o => o.SimpleDTO.IntegerList, new List() { 4, 5, 6 }); + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace>(o => o.SimpleObject.IntegerList, new List() { 4, 5, 6 }); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); // Assert - Assert.Equal(new List() { 4, 5, 6 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 4, 5, 6 }, doc.SimpleObject.IntegerList); } [Fact] public void ReplaceFullListWithCollection() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace>(o => o.SimpleDTO.IntegerList, new Collection() { 4, 5, 6 }); + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace>(o => o.SimpleObject.IntegerList, new Collection() { 4, 5, 6 }); // Act patchDoc.ApplyTo(doc); // Assert - Assert.Equal(new List() { 4, 5, 6 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 4, 5, 6 }, doc.SimpleObject.IntegerList); } [Fact] public void ReplaceFullListWithCollectionWithSerialization() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace>(o => o.SimpleDTO.IntegerList, new Collection() { 4, 5, 6 }); + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace>(o => o.SimpleObject.IntegerList, new Collection() { 4, 5, 6 }); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); // Assert - Assert.Equal(new List() { 4, 5, 6 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 4, 5, 6 }, doc.SimpleObject.IntegerList); } [Fact] public void ReplaceAtEndOfList() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.SimpleDTO.IntegerList, 5); + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.SimpleObject.IntegerList, 5); // Act patchDoc.ApplyTo(doc); // Assert - Assert.Equal(new List() { 1, 2, 5 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 1, 2, 5 }, doc.SimpleObject.IntegerList); } [Fact] public void ReplaceAtEndOfListWithSerialization() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.SimpleDTO.IntegerList, 5); + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.SimpleObject.IntegerList, 5); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); // Assert - Assert.Equal(new List() { 1, 2, 5 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 1, 2, 5 }, doc.SimpleObject.IntegerList); } [Fact] public void ReplaceInListInvalidInvalidPositionTooLarge() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.SimpleDTO.IntegerList, 5, 3); + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.SimpleObject.IntegerList, 5, 3); // Act & Assert var exception = Assert.Throws(() => { patchDoc.ApplyTo(doc); }); @@ -1270,20 +1270,20 @@ namespace Microsoft.AspNetCore.JsonPatch public void ReplaceInListInvalidInvalidPositionTooLargeWithSerialization() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.SimpleDTO.IntegerList, 5, 3); + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.SimpleObject.IntegerList, 5, 3); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act & Assert var exception = Assert.Throws(() => @@ -1299,19 +1299,19 @@ namespace Microsoft.AspNetCore.JsonPatch public void ReplaceInListInvalid_PositionTooLarge_LogsError() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.SimpleDTO.IntegerList, 5, 3); + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.SimpleObject.IntegerList, 5, 3); - var logger = new TestErrorLogger(); + var logger = new TestErrorLogger(); patchDoc.ApplyTo(doc, logger.LogErrorMessage); @@ -1327,17 +1327,17 @@ namespace Microsoft.AspNetCore.JsonPatch public void ReplaceInListInvalidPositionTooSmall() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.SimpleDTO.IntegerList, 5, -1); + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.SimpleObject.IntegerList, 5, -1); // Act & Assert var exception = Assert.Throws(() => { patchDoc.ApplyTo(doc); }); @@ -1350,20 +1350,20 @@ namespace Microsoft.AspNetCore.JsonPatch public void ReplaceInListInvalidPositionTooSmallWithSerialization() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.SimpleDTO.IntegerList, 5, -1); + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.SimpleObject.IntegerList, 5, -1); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act & Assert var exception = Assert.Throws(() => { deserialized.ApplyTo(doc); }); @@ -1376,19 +1376,19 @@ namespace Microsoft.AspNetCore.JsonPatch public void ReplaceInListInvalidPositionTooSmall_LogsError() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.SimpleDTO.IntegerList, 5, -1); + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.SimpleObject.IntegerList, 5, -1); - var logger = new TestErrorLogger(); + var logger = new TestErrorLogger(); patchDoc.ApplyTo(doc, logger.LogErrorMessage); @@ -1404,9 +1404,9 @@ namespace Microsoft.AspNetCore.JsonPatch public void Copy() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { StringProperty = "A", AnotherStringProperty = "B" @@ -1414,23 +1414,23 @@ namespace Microsoft.AspNetCore.JsonPatch }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.SimpleDTO.StringProperty, o => o.SimpleDTO.AnotherStringProperty); + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.SimpleObject.StringProperty, o => o.SimpleObject.AnotherStringProperty); // Act patchDoc.ApplyTo(doc); // Assert - Assert.Equal("A", doc.SimpleDTO.AnotherStringProperty); + Assert.Equal("A", doc.SimpleObject.AnotherStringProperty); } [Fact] public void CopyWithSerialization() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { StringProperty = "A", AnotherStringProperty = "B" @@ -1438,173 +1438,173 @@ namespace Microsoft.AspNetCore.JsonPatch }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.SimpleDTO.StringProperty, o => o.SimpleDTO.AnotherStringProperty); + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.SimpleObject.StringProperty, o => o.SimpleObject.AnotherStringProperty); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); // Assert - Assert.Equal("A", doc.SimpleDTO.AnotherStringProperty); + Assert.Equal("A", doc.SimpleObject.AnotherStringProperty); } [Fact] public void CopyInList() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.SimpleDTO.IntegerList, 0, o => o.SimpleDTO.IntegerList, 1); + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.SimpleObject.IntegerList, 0, o => o.SimpleObject.IntegerList, 1); // Act patchDoc.ApplyTo(doc); // Assert - Assert.Equal(new List() { 1, 1, 2, 3 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 1, 1, 2, 3 }, doc.SimpleObject.IntegerList); } [Fact] public void CopyInListWithSerialization() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.SimpleDTO.IntegerList, 0, o => o.SimpleDTO.IntegerList, 1); + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.SimpleObject.IntegerList, 0, o => o.SimpleObject.IntegerList, 1); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); // Assert - Assert.Equal(new List() { 1, 1, 2, 3 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 1, 1, 2, 3 }, doc.SimpleObject.IntegerList); } [Fact] public void CopyFromListToEndOfList() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.SimpleDTO.IntegerList, 0, o => o.SimpleDTO.IntegerList); + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.SimpleObject.IntegerList, 0, o => o.SimpleObject.IntegerList); // Act patchDoc.ApplyTo(doc); // Assert - Assert.Equal(new List() { 1, 2, 3, 1 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 1, 2, 3, 1 }, doc.SimpleObject.IntegerList); } [Fact] public void CopyFromListToEndOfListWithSerialization() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.SimpleDTO.IntegerList, 0, o => o.SimpleDTO.IntegerList); + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.SimpleObject.IntegerList, 0, o => o.SimpleObject.IntegerList); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); // Assert - Assert.Equal(new List() { 1, 2, 3, 1 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 1, 2, 3, 1 }, doc.SimpleObject.IntegerList); } [Fact] public void CopyFromListToNonList() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.SimpleDTO.IntegerList, 0, o => o.SimpleDTO.IntegerValue); + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.SimpleObject.IntegerList, 0, o => o.SimpleObject.IntegerValue); // Act patchDoc.ApplyTo(doc); // Assert - Assert.Equal(1, doc.SimpleDTO.IntegerValue); + Assert.Equal(1, doc.SimpleObject.IntegerValue); } [Fact] public void CopyFromListToNonListWithSerialization() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.SimpleDTO.IntegerList, 0, o => o.SimpleDTO.IntegerValue); + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.SimpleObject.IntegerList, 0, o => o.SimpleObject.IntegerValue); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); // Assert - Assert.Equal(1, doc.SimpleDTO.IntegerValue); + Assert.Equal(1, doc.SimpleObject.IntegerValue); } [Fact] public void CopyFromNonListToList() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerValue = 5, IntegerList = new List() { 1, 2, 3 } @@ -1612,23 +1612,23 @@ namespace Microsoft.AspNetCore.JsonPatch }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.SimpleDTO.IntegerValue, o => o.SimpleDTO.IntegerList, 0); + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.SimpleObject.IntegerValue, o => o.SimpleObject.IntegerList, 0); // Act patchDoc.ApplyTo(doc); // Assert - Assert.Equal(new List() { 5, 1, 2, 3 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 5, 1, 2, 3 }, doc.SimpleObject.IntegerList); } [Fact] public void CopyFromNonListToListWithSerialization() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerValue = 5, IntegerList = new List() { 1, 2, 3 } @@ -1636,25 +1636,25 @@ namespace Microsoft.AspNetCore.JsonPatch }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.SimpleDTO.IntegerValue, o => o.SimpleDTO.IntegerList, 0); + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.SimpleObject.IntegerValue, o => o.SimpleObject.IntegerList, 0); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); // Assert - Assert.Equal(new List() { 5, 1, 2, 3 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 5, 1, 2, 3 }, doc.SimpleObject.IntegerList); } [Fact] public void CopyToEndOfList() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerValue = 5, IntegerList = new List() { 1, 2, 3 } @@ -1662,23 +1662,23 @@ namespace Microsoft.AspNetCore.JsonPatch }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.SimpleDTO.IntegerValue, o => o.SimpleDTO.IntegerList); + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.SimpleObject.IntegerValue, o => o.SimpleObject.IntegerList); // Act patchDoc.ApplyTo(doc); // Assert - Assert.Equal(new List() { 1, 2, 3, 5 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 1, 2, 3, 5 }, doc.SimpleObject.IntegerList); } [Fact] public void CopyToEndOfListWithSerialization() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerValue = 5, IntegerList = new List() { 1, 2, 3 } @@ -1686,31 +1686,31 @@ namespace Microsoft.AspNetCore.JsonPatch }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.SimpleDTO.IntegerValue, o => o.SimpleDTO.IntegerList); + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.SimpleObject.IntegerValue, o => o.SimpleObject.IntegerList); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); // Assert - Assert.Equal(new List() { 1, 2, 3, 5 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 1, 2, 3, 5 }, doc.SimpleObject.IntegerList); } [Fact] public void Copy_DeepClonesObject() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { StringProperty = "A", AnotherStringProperty = "B" }, - InheritedDTO = new InheritedDTO() + InheritedObject = new InheritedObject() { StringProperty = "C", AnotherStringProperty = "D" @@ -1718,69 +1718,69 @@ namespace Microsoft.AspNetCore.JsonPatch }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.InheritedDTO, o => o.SimpleDTO); + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.InheritedObject, o => o.SimpleObject); // Act patchDoc.ApplyTo(doc); // Assert - Assert.Equal("C", doc.SimpleDTO.StringProperty); - Assert.Equal("D", doc.SimpleDTO.AnotherStringProperty); - Assert.Equal("C", doc.InheritedDTO.StringProperty); - Assert.Equal("D", doc.InheritedDTO.AnotherStringProperty); - Assert.NotSame(doc.SimpleDTO.StringProperty, doc.InheritedDTO.StringProperty); + Assert.Equal("C", doc.SimpleObject.StringProperty); + Assert.Equal("D", doc.SimpleObject.AnotherStringProperty); + Assert.Equal("C", doc.InheritedObject.StringProperty); + Assert.Equal("D", doc.InheritedObject.AnotherStringProperty); + Assert.NotSame(doc.SimpleObject.StringProperty, doc.InheritedObject.StringProperty); } [Fact] public void Copy_KeepsObjectType() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO(), - InheritedDTO = new InheritedDTO() + SimpleObject = new SimpleObject(), + InheritedObject = new InheritedObject() }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.InheritedDTO, o => o.SimpleDTO); + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.InheritedObject, o => o.SimpleObject); // Act patchDoc.ApplyTo(doc); // Assert - Assert.Equal(typeof(InheritedDTO), doc.SimpleDTO.GetType()); + Assert.Equal(typeof(InheritedObject), doc.SimpleObject.GetType()); } [Fact] public void Copy_BreaksObjectReference() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO(), - InheritedDTO = new InheritedDTO() + SimpleObject = new SimpleObject(), + InheritedObject = new InheritedObject() }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.InheritedDTO, o => o.SimpleDTO); + var patchDoc = new JsonPatchDocument(); + patchDoc.Copy(o => o.InheritedObject, o => o.SimpleObject); // Act patchDoc.ApplyTo(doc); // Assert - Assert.NotSame(doc.SimpleDTO, doc.InheritedDTO); + Assert.NotSame(doc.SimpleObject, doc.InheritedObject); } [Fact] public void Move() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { StringProperty = "A", AnotherStringProperty = "B" @@ -1788,24 +1788,24 @@ namespace Microsoft.AspNetCore.JsonPatch }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.SimpleDTO.StringProperty, o => o.SimpleDTO.AnotherStringProperty); + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.SimpleObject.StringProperty, o => o.SimpleObject.AnotherStringProperty); // Act patchDoc.ApplyTo(doc); // Assert - Assert.Equal("A", doc.SimpleDTO.AnotherStringProperty); - Assert.Null(doc.SimpleDTO.StringProperty); + Assert.Equal("A", doc.SimpleObject.AnotherStringProperty); + Assert.Null(doc.SimpleObject.StringProperty); } [Fact] public void MoveWithSerialization() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { StringProperty = "A", AnotherStringProperty = "B" @@ -1813,150 +1813,150 @@ namespace Microsoft.AspNetCore.JsonPatch }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.SimpleDTO.StringProperty, o => o.SimpleDTO.AnotherStringProperty); + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.SimpleObject.StringProperty, o => o.SimpleObject.AnotherStringProperty); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); // Assert - Assert.Equal("A", doc.SimpleDTO.AnotherStringProperty); - Assert.Null(doc.SimpleDTO.StringProperty); + Assert.Equal("A", doc.SimpleObject.AnotherStringProperty); + Assert.Null(doc.SimpleObject.StringProperty); } [Fact] public void Move_KeepsObjectReference() { // Arrange - var sDto = new SimpleDTO() + var sDto = new SimpleObject() { StringProperty = "A", AnotherStringProperty = "B" }; - var iDto = new InheritedDTO() + var iDto = new InheritedObject() { StringProperty = "C", AnotherStringProperty = "D" }; - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = sDto, - InheritedDTO = iDto + SimpleObject = sDto, + InheritedObject = iDto }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.InheritedDTO, o => o.SimpleDTO); + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.InheritedObject, o => o.SimpleObject); // Act patchDoc.ApplyTo(doc); // Assert - Assert.Equal("C", doc.SimpleDTO.StringProperty); - Assert.Equal("D", doc.SimpleDTO.AnotherStringProperty); - Assert.Same(iDto, doc.SimpleDTO); - Assert.Null(doc.InheritedDTO); + Assert.Equal("C", doc.SimpleObject.StringProperty); + Assert.Equal("D", doc.SimpleObject.AnotherStringProperty); + Assert.Same(iDto, doc.SimpleObject); + Assert.Null(doc.InheritedObject); } [Fact] public void Move_KeepsObjectReferenceWithSerialization() { // Arrange - var sDto = new SimpleDTO() + var sDto = new SimpleObject() { StringProperty = "A", AnotherStringProperty = "B" }; - var iDto = new InheritedDTO() + var iDto = new InheritedObject() { StringProperty = "C", AnotherStringProperty = "D" }; - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = sDto, - InheritedDTO = iDto + SimpleObject = sDto, + InheritedObject = iDto }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.InheritedDTO, o => o.SimpleDTO); + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.InheritedObject, o => o.SimpleObject); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); // Assert - Assert.Equal("C", doc.SimpleDTO.StringProperty); - Assert.Equal("D", doc.SimpleDTO.AnotherStringProperty); - Assert.Same(iDto, doc.SimpleDTO); - Assert.Null(doc.InheritedDTO); + Assert.Equal("C", doc.SimpleObject.StringProperty); + Assert.Equal("D", doc.SimpleObject.AnotherStringProperty); + Assert.Same(iDto, doc.SimpleObject); + Assert.Null(doc.InheritedObject); } [Fact] public void MoveInList() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.SimpleDTO.IntegerList, 0, o => o.SimpleDTO.IntegerList, 1); + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.SimpleObject.IntegerList, 0, o => o.SimpleObject.IntegerList, 1); // Act patchDoc.ApplyTo(doc); // Assert - Assert.Equal(new List() { 2, 1, 3 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 2, 1, 3 }, doc.SimpleObject.IntegerList); } [Fact] public void MoveInListWithSerialization() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.SimpleDTO.IntegerList, 0, o => o.SimpleDTO.IntegerList, 1); + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.SimpleObject.IntegerList, 0, o => o.SimpleObject.IntegerList, 1); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); // Assert - Assert.Equal(new List() { 2, 1, 3 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 2, 1, 3 }, doc.SimpleObject.IntegerList); } [Fact] public void Move_KeepsObjectReferenceInList() { // Arrange - var sDto1 = new SimpleDTO() { IntegerValue = 1 }; - var sDto2 = new SimpleDTO() { IntegerValue = 2 }; - var sDto3 = new SimpleDTO() { IntegerValue = 3 }; - var doc = new SimpleDTOWithNestedDTO() + var sDto1 = new SimpleObject() { IntegerValue = 1 }; + var sDto2 = new SimpleObject() { IntegerValue = 2 }; + var sDto3 = new SimpleObject() { IntegerValue = 3 }; + var doc = new SimpleObjectWithNestedObject() { - SimpleDTOList = new List() { + SimpleObjectList = new List() { sDto1, sDto2, sDto3 @@ -1964,30 +1964,30 @@ namespace Microsoft.AspNetCore.JsonPatch }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.SimpleDTOList, 0, o => o.SimpleDTOList, 1); + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.SimpleObjectList, 0, o => o.SimpleObjectList, 1); // Act patchDoc.ApplyTo(doc); // Assert - Assert.Equal(new List() { sDto2, sDto1, sDto3 }, doc.SimpleDTOList); - Assert.Equal(2, doc.SimpleDTOList[0].IntegerValue); - Assert.Equal(1, doc.SimpleDTOList[1].IntegerValue); - Assert.Same(sDto2, doc.SimpleDTOList[0]); - Assert.Same(sDto1, doc.SimpleDTOList[1]); + Assert.Equal(new List() { sDto2, sDto1, sDto3 }, doc.SimpleObjectList); + Assert.Equal(2, doc.SimpleObjectList[0].IntegerValue); + Assert.Equal(1, doc.SimpleObjectList[1].IntegerValue); + Assert.Same(sDto2, doc.SimpleObjectList[0]); + Assert.Same(sDto1, doc.SimpleObjectList[1]); } [Fact] public void Move_KeepsObjectReferenceInListWithSerialization() { // Arrange - var sDto1 = new SimpleDTO() { IntegerValue = 1 }; - var sDto2 = new SimpleDTO() { IntegerValue = 2 }; - var sDto3 = new SimpleDTO() { IntegerValue = 3 }; - var doc = new SimpleDTOWithNestedDTO() + var sDto1 = new SimpleObject() { IntegerValue = 1 }; + var sDto2 = new SimpleObject() { IntegerValue = 2 }; + var sDto3 = new SimpleObject() { IntegerValue = 3 }; + var doc = new SimpleObjectWithNestedObject() { - SimpleDTOList = new List() { + SimpleObjectList = new List() { sDto1, sDto2, sDto3 @@ -1995,144 +1995,144 @@ namespace Microsoft.AspNetCore.JsonPatch }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.SimpleDTOList, 0, o => o.SimpleDTOList, 1); + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.SimpleObjectList, 0, o => o.SimpleObjectList, 1); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act patchDoc.ApplyTo(doc); // Assert - Assert.Equal(new List() { sDto2, sDto1, sDto3 }, doc.SimpleDTOList); - Assert.Equal(2, doc.SimpleDTOList[0].IntegerValue); - Assert.Equal(1, doc.SimpleDTOList[1].IntegerValue); - Assert.Same(sDto2, doc.SimpleDTOList[0]); - Assert.Same(sDto1, doc.SimpleDTOList[1]); + Assert.Equal(new List() { sDto2, sDto1, sDto3 }, doc.SimpleObjectList); + Assert.Equal(2, doc.SimpleObjectList[0].IntegerValue); + Assert.Equal(1, doc.SimpleObjectList[1].IntegerValue); + Assert.Same(sDto2, doc.SimpleObjectList[0]); + Assert.Same(sDto1, doc.SimpleObjectList[1]); } [Fact] public void MoveFromListToEndOfList() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.SimpleDTO.IntegerList, 0, o => o.SimpleDTO.IntegerList); + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.SimpleObject.IntegerList, 0, o => o.SimpleObject.IntegerList); // Act patchDoc.ApplyTo(doc); // Assert - Assert.Equal(new List() { 2, 3, 1 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 2, 3, 1 }, doc.SimpleObject.IntegerList); } [Fact] public void MoveFromListToEndOfListWithSerialization() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.SimpleDTO.IntegerList, 0, o => o.SimpleDTO.IntegerList); + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.SimpleObject.IntegerList, 0, o => o.SimpleObject.IntegerList); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); // Assert - Assert.Equal(new List() { 2, 3, 1 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 2, 3, 1 }, doc.SimpleObject.IntegerList); } [Fact] public void MoveFomListToNonList() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.SimpleDTO.IntegerList, 0, o => o.SimpleDTO.IntegerValue); + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.SimpleObject.IntegerList, 0, o => o.SimpleObject.IntegerValue); // Act patchDoc.ApplyTo(doc); // Assert - Assert.Equal(new List() { 2, 3 }, doc.SimpleDTO.IntegerList); - Assert.Equal(1, doc.SimpleDTO.IntegerValue); + Assert.Equal(new List() { 2, 3 }, doc.SimpleObject.IntegerList); + Assert.Equal(1, doc.SimpleObject.IntegerValue); } [Fact] public void MoveFomListToNonListWithSerialization() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.SimpleDTO.IntegerList, 0, o => o.SimpleDTO.IntegerValue); + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.SimpleObject.IntegerList, 0, o => o.SimpleObject.IntegerValue); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); // Assert - Assert.Equal(new List() { 2, 3 }, doc.SimpleDTO.IntegerList); - Assert.Equal(1, doc.SimpleDTO.IntegerValue); + Assert.Equal(new List() { 2, 3 }, doc.SimpleObject.IntegerList); + Assert.Equal(1, doc.SimpleObject.IntegerValue); } [Fact] public void MoveFomListToNonListBetweenHierarchy() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.SimpleDTO.IntegerList, 0, o => o.IntegerValue); + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.SimpleObject.IntegerList, 0, o => o.IntegerValue); // Act patchDoc.ApplyTo(doc); // Assert - Assert.Equal(new List() { 2, 3 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 2, 3 }, doc.SimpleObject.IntegerList); Assert.Equal(1, doc.IntegerValue); } @@ -2140,26 +2140,26 @@ namespace Microsoft.AspNetCore.JsonPatch public void MoveFomListToNonListBetweenHierarchyWithSerialization() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } } }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.SimpleDTO.IntegerList, 0, o => o.IntegerValue); + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.SimpleObject.IntegerList, 0, o => o.IntegerValue); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); // Assert - Assert.Equal(new List() { 2, 3 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 2, 3 }, doc.SimpleObject.IntegerList); Assert.Equal(1, doc.IntegerValue); } @@ -2167,9 +2167,9 @@ namespace Microsoft.AspNetCore.JsonPatch public void MoveFromNonListToList() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerValue = 5, IntegerList = new List() { 1, 2, 3 } @@ -2177,24 +2177,24 @@ namespace Microsoft.AspNetCore.JsonPatch }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.SimpleDTO.IntegerValue, o => o.SimpleDTO.IntegerList, 0); + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.SimpleObject.IntegerValue, o => o.SimpleObject.IntegerList, 0); // Act patchDoc.ApplyTo(doc); // Assert Assert.Equal(0, doc.IntegerValue); - Assert.Equal(new List() { 5, 1, 2, 3 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 5, 1, 2, 3 }, doc.SimpleObject.IntegerList); } [Fact] public void MoveFromNonListToListWithSerialization() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerValue = 5, IntegerList = new List() { 1, 2, 3 } @@ -2202,27 +2202,27 @@ namespace Microsoft.AspNetCore.JsonPatch }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.SimpleDTO.IntegerValue, o => o.SimpleDTO.IntegerList, 0); + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.SimpleObject.IntegerValue, o => o.SimpleObject.IntegerList, 0); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); // Assert Assert.Equal(0, doc.IntegerValue); - Assert.Equal(new List() { 5, 1, 2, 3 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 5, 1, 2, 3 }, doc.SimpleObject.IntegerList); } [Fact] public void MoveToEndOfList() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerValue = 5, IntegerList = new List() { 1, 2, 3 } @@ -2230,24 +2230,24 @@ namespace Microsoft.AspNetCore.JsonPatch }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.SimpleDTO.IntegerValue, o => o.SimpleDTO.IntegerList); + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.SimpleObject.IntegerValue, o => o.SimpleObject.IntegerList); // Act patchDoc.ApplyTo(doc); // Assert Assert.Equal(0, doc.IntegerValue); - Assert.Equal(new List() { 1, 2, 3, 5 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 1, 2, 3, 5 }, doc.SimpleObject.IntegerList); } [Fact] public void MoveToEndOfListWithSerialization() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerValue = 5, IntegerList = new List() { 1, 2, 3 } @@ -2255,18 +2255,18 @@ namespace Microsoft.AspNetCore.JsonPatch }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.SimpleDTO.IntegerValue, o => o.SimpleDTO.IntegerList); + var patchDoc = new JsonPatchDocument(); + patchDoc.Move(o => o.SimpleObject.IntegerValue, o => o.SimpleObject.IntegerList); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); // Assert Assert.Equal(0, doc.IntegerValue); - Assert.Equal(new List() { 1, 2, 3, 5 }, doc.SimpleDTO.IntegerList); + Assert.Equal(new List() { 1, 2, 3, 5 }, doc.SimpleObject.IntegerList); } } } diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs index 34a8c97b67..d35f8eb4e9 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs @@ -16,13 +16,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void AddResultsShouldReplace() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { StringProperty = "A" }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add(o => o.StringProperty, "B"); // Act @@ -36,17 +36,17 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void AddResultsShouldReplaceWithSerialization() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { StringProperty = "A" }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add(o => o.StringProperty, "B"); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); @@ -59,13 +59,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void AddToList() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add(o => o.IntegerList, 4, 0); // Act @@ -79,17 +79,17 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void AddToListWithSerialization() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add(o => o.IntegerList, 4, 0); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); @@ -102,13 +102,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void AddToIntegerIList() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerIList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add(o => o.IntegerIList, 4, 0); // Act @@ -122,17 +122,17 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void AddToIntegerIListWithSerialization() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerIList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add(o => o.IntegerIList, 4, 0); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); @@ -145,13 +145,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void AddToListInvalidPositionTooLarge() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add(o => o.IntegerList, 4, 4); // Act & Assert @@ -165,17 +165,17 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void AddToListInvalidPositionTooLargeWithSerialization() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add(o => o.IntegerList, 4, 4); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act & Assert var exception = Assert.Throws(() => { deserialized.ApplyTo(doc); }); @@ -188,16 +188,16 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void AddToListInvalidPositionTooLarge_LogsError() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add(o => o.IntegerList, 4, 4); - var logger = new TestErrorLogger(); + var logger = new TestErrorLogger(); patchDoc.ApplyTo(doc, logger.LogErrorMessage); @@ -212,13 +212,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void AddToListAtBeginning() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add(o => o.IntegerList, 4, 0); // Act @@ -232,17 +232,17 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void AddToListAtBeginningWithSerialization() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add(o => o.IntegerList, 4, 0); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); @@ -255,13 +255,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void AddToListInvalidPositionTooSmall() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add(o => o.IntegerList, 4, -1); // Act & Assert @@ -275,17 +275,17 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void AddToListInvalidPositionTooSmallWithSerialization() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add(o => o.IntegerList, 4, -1); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act & Assert var exception = Assert.Throws(() => { deserialized.ApplyTo(doc); }); @@ -298,16 +298,16 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void AddToListInvalidPositionTooSmall_LogsError() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add(o => o.IntegerList, 4, -1); - var logger = new TestErrorLogger(); + var logger = new TestErrorLogger(); patchDoc.ApplyTo(doc, logger.LogErrorMessage); @@ -321,13 +321,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void AddToListAppend() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add(o => o.IntegerList, 4); // Act @@ -341,17 +341,17 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void AddToListAppendWithSerialization() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add(o => o.IntegerList, 4); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); @@ -364,13 +364,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void Remove() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { StringProperty = "A" }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Remove(o => o.StringProperty); // Act @@ -384,17 +384,17 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void RemoveWithSerialization() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { StringProperty = "A" }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Remove(o => o.StringProperty); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); @@ -407,13 +407,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void RemoveFromList() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Remove(o => o.IntegerList, 2); // Act @@ -427,17 +427,17 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void RemoveFromListWithSerialization() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Remove(o => o.IntegerList, 2); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); @@ -450,13 +450,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void RemoveFromListInvalidPositionTooLarge() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Remove(o => o.IntegerList, 3); // Act & Assert @@ -470,17 +470,17 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void RemoveFromListInvalidPositionTooLargeWithSerialization() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Remove(o => o.IntegerList, 3); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act & Assert var exception = Assert.Throws(() => { deserialized.ApplyTo(doc); }); @@ -493,16 +493,16 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void RemoveFromListInvalidPositionTooLarge_LogsError() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Remove(o => o.IntegerList, 3); - var logger = new TestErrorLogger(); + var logger = new TestErrorLogger(); patchDoc.ApplyTo(doc, logger.LogErrorMessage); @@ -517,13 +517,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void RemoveFromListInvalidPositionTooSmall() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Remove(o => o.IntegerList, -1); // Act & Assert @@ -537,17 +537,17 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void RemoveFromListInvalidPositionTooSmallWithSerialization() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Remove(o => o.IntegerList, -1); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act & Assert var exception = Assert.Throws(() => { deserialized.ApplyTo(doc); }); @@ -560,16 +560,16 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void RemoveFromListInvalidPositionTooSmall_LogsError() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Remove(o => o.IntegerList, -1); - var logger = new TestErrorLogger(); + var logger = new TestErrorLogger(); patchDoc.ApplyTo(doc, logger.LogErrorMessage); @@ -585,13 +585,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void RemoveFromEndOfList() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Remove(o => o.IntegerList); // Act @@ -605,17 +605,17 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void RemoveFromEndOfListWithSerialization() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Remove(o => o.IntegerList); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); @@ -628,14 +628,14 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void Replace() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { StringProperty = "A", DecimalValue = 10 }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Replace(o => o.StringProperty, "B"); patchDoc.Replace(o => o.DecimalValue, 12); @@ -652,13 +652,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void Replace_DTOWithNullCheck() { // Arrange - var doc = new SimpleDTOWithNullCheck() + var doc = new SimpleObjectWithNullCheck() { StringProperty = "A", }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Replace(o => o.StringProperty, "B"); // Act @@ -672,20 +672,20 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void ReplaceWithSerialization() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { StringProperty = "A", DecimalValue = 10 }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Replace(o => o.StringProperty, "B"); patchDoc.Replace(o => o.DecimalValue, 12); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); @@ -699,7 +699,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void SerializationMustNotIncudeEnvelope() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { StringProperty = "A", DecimalValue = 10, @@ -709,7 +709,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Replace(o => o.StringProperty, "B"); patchDoc.Replace(o => o.DecimalValue, 12); patchDoc.Replace(o => o.DoubleValue, 12); @@ -728,7 +728,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void DeserializationMustWorkWithoutEnvelope() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { StringProperty = "A", DecimalValue = 10, @@ -738,7 +738,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Replace(o => o.StringProperty, "B"); patchDoc.Replace(o => o.DecimalValue, 12); patchDoc.Replace(o => o.DoubleValue, 12); @@ -749,23 +749,23 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters var serialized = JsonConvert.SerializeObject(patchDoc); // Act - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Assert - Assert.IsType>(deserialized); + Assert.IsType>(deserialized); } [Fact] public void DeserializationMustFailWithEnvelope() { // Arrange - string serialized = "{\"Operations\": [{ \"op\": \"replace\", \"path\": \"/title\", \"value\": \"New Title\"}]}"; + var serialized = "{\"Operations\": [{ \"op\": \"replace\", \"path\": \"/title\", \"value\": \"New Title\"}]}"; // Act & Assert var exception = Assert.Throws(() => { var deserialized - = JsonConvert.DeserializeObject>(serialized); + = JsonConvert.DeserializeObject>(serialized); }); Assert.Equal("The type 'JsonPatchDocument`1' was malformed and could not be parsed.", exception.Message); @@ -775,7 +775,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void SerializationTests() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { StringProperty = "A", DecimalValue = 10, @@ -785,7 +785,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Replace(o => o.StringProperty, "B"); patchDoc.Replace(o => o.DecimalValue, 12); patchDoc.Replace(o => o.DoubleValue, 12); @@ -794,7 +794,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters // serialize & deserialize var serialized = JsonConvert.SerializeObject(patchDoc); - var deserizalized = JsonConvert.DeserializeObject>(serialized); + var deserizalized = JsonConvert.DeserializeObject>(serialized); // Act deserizalized.ApplyTo(doc); @@ -811,19 +811,19 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void SerializeAndReplaceGuidTest() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { GuidValue = Guid.NewGuid() }; var newGuid = Guid.NewGuid(); // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Replace(o => o.GuidValue, newGuid); // serialize & deserialize var serialized = JsonConvert.SerializeObject(patchDoc); - var deserizalized = JsonConvert.DeserializeObject>(serialized); + var deserizalized = JsonConvert.DeserializeObject>(serialized); // Act deserizalized.ApplyTo(doc); @@ -836,48 +836,48 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void SerializeAndReplaceNestedObjectTest() { // Arrange - var doc = new SimpleDTOWithNestedDTO() + var doc = new SimpleObjectWithNestedObject() { - SimpleDTO = new SimpleDTO() + SimpleObject = new SimpleObject() { IntegerValue = 5, IntegerList = new List() { 1, 2, 3 } } }; - var newDTO = new SimpleDTO() + var newDTO = new SimpleObject() { DoubleValue = 1 }; // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.SimpleDTO, newDTO); + var patchDoc = new JsonPatchDocument(); + patchDoc.Replace(o => o.SimpleObject, newDTO); // serialize & deserialize var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); // Assert - Assert.Equal(1, doc.SimpleDTO.DoubleValue); - Assert.Equal(0, doc.SimpleDTO.IntegerValue); - Assert.Null(doc.SimpleDTO.IntegerList); + Assert.Equal(1, doc.SimpleObject.DoubleValue); + Assert.Equal(0, doc.SimpleObject.IntegerValue); + Assert.Null(doc.SimpleObject.IntegerList); } [Fact] public void ReplaceInList() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Replace(o => o.IntegerList, 5, 0); // Act @@ -891,17 +891,17 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void ReplaceInListWithSerialization() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Replace(o => o.IntegerList, 5, 0); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); @@ -914,13 +914,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void ReplaceFullList() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Replace>(o => o.IntegerList, new List() { 4, 5, 6 }); // Act @@ -934,17 +934,17 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void ReplaceFullListWithSerialization() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Replace>(o => o.IntegerList, new List() { 4, 5, 6 }); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); @@ -957,13 +957,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void ReplaceFullListFromEnumerable() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Replace>(o => o.IntegerList, new List() { 4, 5, 6 }); // Act @@ -977,17 +977,17 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void ReplaceFullListFromEnumerableWithSerialization() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Replace>(o => o.IntegerList, new List() { 4, 5, 6 }); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); @@ -1000,13 +1000,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void ReplaceFullListWithCollection() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Replace>(o => o.IntegerList, new Collection() { 4, 5, 6 }); // Act @@ -1020,17 +1020,17 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void ReplaceFullListWithCollectionWithSerialization() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Replace>(o => o.IntegerList, new Collection() { 4, 5, 6 }); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); @@ -1043,13 +1043,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void ReplaceAtEndOfList() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Replace(o => o.IntegerList, 5); // Act @@ -1063,16 +1063,16 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void ReplaceAtEndOfListWithSerialization() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Replace(o => o.IntegerList, 5); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); @@ -1085,13 +1085,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void ReplaceInListInvalidInvalidPositionTooLarge() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Replace(o => o.IntegerList, 5, 3); // Act & Assert @@ -1108,16 +1108,16 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void ReplaceInListInvalidInvalidPositionTooLargeWithSerialization() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Replace(o => o.IntegerList, 5, 3); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act & Assert var exception = Assert.Throws(() => @@ -1133,13 +1133,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void ReplaceInListInvalidPositionTooSmall() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Replace(o => o.IntegerList, 5, -1); // Act & Assert @@ -1156,17 +1156,17 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void ReplaceInListInvalidPositionTooSmallWithSerialization() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Replace(o => o.IntegerList, 5, -1); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act & Assert var exception = Assert.Throws(() => @@ -1182,14 +1182,14 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void Copy() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { StringProperty = "A", AnotherStringProperty = "B" }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Copy(o => o.StringProperty, o => o.AnotherStringProperty); // Act @@ -1203,17 +1203,17 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void CopyWithSerialization() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { StringProperty = "A", AnotherStringProperty = "B" }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Copy(o => o.StringProperty, o => o.AnotherStringProperty); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); @@ -1226,13 +1226,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void CopyInList() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Copy(o => o.IntegerList, 0, o => o.IntegerList, 1); // Act @@ -1246,17 +1246,17 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void CopyInListWithSerialization() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Copy(o => o.IntegerList, 0, o => o.IntegerList, 1); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); @@ -1269,13 +1269,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void CopyFromListToEndOfList() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Copy(o => o.IntegerList, 0, o => o.IntegerList); // Act @@ -1289,17 +1289,17 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void CopyFromListToEndOfListWithSerialization() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Copy(o => o.IntegerList, 0, o => o.IntegerList); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); @@ -1312,13 +1312,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void CopyFromListToNonList() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Copy(o => o.IntegerList, 0, o => o.IntegerValue); // Act @@ -1332,17 +1332,17 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void CopyFromListToNonListWithSerialization() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Copy(o => o.IntegerList, 0, o => o.IntegerValue); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); @@ -1355,14 +1355,14 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void CopyFromNonListToList() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerValue = 5, IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Copy(o => o.IntegerValue, o => o.IntegerList, 0); // Act @@ -1376,18 +1376,18 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void CopyFromNonListToListWithSerialization() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerValue = 5, IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Copy(o => o.IntegerValue, o => o.IntegerList, 0); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); @@ -1400,14 +1400,14 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void CopyToEndOfList() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerValue = 5, IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Copy(o => o.IntegerValue, o => o.IntegerList); // Act @@ -1421,18 +1421,18 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void CopyToEndOfListWithSerialization() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerValue = 5, IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Copy(o => o.IntegerValue, o => o.IntegerList); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); @@ -1445,14 +1445,14 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void Move() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { StringProperty = "A", AnotherStringProperty = "B" }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Move(o => o.StringProperty, o => o.AnotherStringProperty); // Act @@ -1467,18 +1467,18 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void MoveWithSerialization() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { StringProperty = "A", AnotherStringProperty = "B" }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Move(o => o.StringProperty, o => o.AnotherStringProperty); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); @@ -1492,13 +1492,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void MoveInList() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Move(o => o.IntegerList, 0, o => o.IntegerList, 1); // Act @@ -1512,17 +1512,17 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void MoveInListWithSerialization() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Move(o => o.IntegerList, 0, o => o.IntegerList, 1); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); @@ -1535,13 +1535,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void MoveFromListToEndOfList() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Move(o => o.IntegerList, 0, o => o.IntegerList); // Act @@ -1555,17 +1555,17 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void MoveFromListToEndOfListWithSerialization() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Move(o => o.IntegerList, 0, o => o.IntegerList); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); @@ -1578,13 +1578,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void MoveFomListToNonList() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Move(o => o.IntegerList, 0, o => o.IntegerValue); // Act @@ -1599,17 +1599,17 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void MoveFomListToNonListWithSerialization() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Move(o => o.IntegerList, 0, o => o.IntegerValue); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); @@ -1623,14 +1623,14 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void MoveFromNonListToList() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerValue = 5, IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Move(o => o.IntegerValue, o => o.IntegerList, 0); // Act @@ -1645,18 +1645,18 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void MoveFromNonListToListWithSerialization() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerValue = 5, IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Move(o => o.IntegerValue, o => o.IntegerList, 0); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); @@ -1670,14 +1670,14 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void MoveToEndOfList() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerValue = 5, IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Move(o => o.IntegerValue, o => o.IntegerList); // Act @@ -1692,18 +1692,18 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void MoveToEndOfListWithSerialization() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerValue = 5, IntegerList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Move(o => o.IntegerValue, o => o.IntegerList); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); @@ -1950,13 +1950,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void AddMember_OnPOCO_WithNullPropertyValue_ShouldAddPropertyValue() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { StringProperty = null }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add(o => o.StringProperty, "B"); // Act @@ -2175,13 +2175,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void AddElement_ToList_OnPOCO_ShouldAddValue_AtSuppliedPosition() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { IntegerIList = new List() { 1, 2, 3 } }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Add(o => o.IntegerIList, 4, 0); // Act @@ -2193,7 +2193,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters class Class3 { - public SimpleDTO SimpleDTOProperty { get; set; } = new SimpleDTO(); + public SimpleObject SimpleObjectProperty { get; set; } = new SimpleObject(); } [Fact] @@ -2202,19 +2202,19 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters // Arrange var model = new Class3() { - SimpleDTOProperty = new SimpleDTO() + SimpleObjectProperty = new SimpleObject() { IntegerIList = new List() { 1, 2, 3 } } }; var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.SimpleDTOProperty.IntegerIList, value: 4, position: 0); + patchDoc.Add(o => o.SimpleObjectProperty.IntegerIList, value: 4, position: 0); // Act patchDoc.ApplyTo(model); // Assert - Assert.Equal(new List() { 4, 1, 2, 3 }, model.SimpleDTOProperty.IntegerIList); + Assert.Equal(new List() { 4, 1, 2, 3 }, model.SimpleObjectProperty.IntegerIList); } [Fact] @@ -2223,13 +2223,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters // Arrange var model = new Class3() { - SimpleDTOProperty = new SimpleDTO() + SimpleObjectProperty = new SimpleObject() { IntegerIList = new List() { 1, 2, 3 } } }; var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.SimpleDTOProperty.IntegerIList, value: 4, position: 0); + patchDoc.Add(o => o.SimpleObjectProperty.IntegerIList, value: 4, position: 0); var serialized = JsonConvert.SerializeObject(patchDoc); var deserialized = JsonConvert.DeserializeObject>(serialized); @@ -2237,7 +2237,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters deserialized.ApplyTo(model); // Assert - Assert.Equal(new List() { 4, 1, 2, 3 }, model.SimpleDTOProperty.IntegerIList); + Assert.Equal(new List() { 4, 1, 2, 3 }, model.SimpleObjectProperty.IntegerIList); } class Class4 @@ -2267,17 +2267,17 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters public void Remove_OnNonReferenceType_POCOProperty_ShouldSetDefaultValue_WithSerialization() { // Arrange - var doc = new SimpleDTO() + var doc = new SimpleObject() { StringProperty = "A" }; // create patch - var patchDoc = new JsonPatchDocument(); + var patchDoc = new JsonPatchDocument(); patchDoc.Remove(o => o.StringProperty); var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); + var deserialized = JsonConvert.DeserializeObject>(serialized); // Act deserialized.ApplyTo(doc); diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectVisitorTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectVisitorTest.cs index 391b5ebe2c..5eddac8685 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectVisitorTest.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectVisitorTest.cs @@ -46,11 +46,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal { // Arrange var visitor = new ObjectVisitor(new ParsedPath(path), new DefaultContractResolver()); - IAdapter adapter = null; - string message = null; // Act - var visitStatus = visitor.TryVisit(ref targetObject, out adapter, out message); + var visitStatus = visitor.TryVisit(ref targetObject, out var adapter, out var message); // Assert Assert.True(visitStatus); @@ -81,11 +79,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal { // Arrange var visitor = new ObjectVisitor(new ParsedPath(path), new DefaultContractResolver()); - IAdapter adapter = null; - string message = null; // Act - var visitStatus = visitor.TryVisit(ref targetObject, out adapter, out message); + var visitStatus = visitor.TryVisit(ref targetObject, out var adapter, out var message); // Assert Assert.True(visitStatus); @@ -112,11 +108,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal { // Arrange var visitor = new ObjectVisitor(new ParsedPath(path), new DefaultContractResolver()); - IAdapter adapter = null; - string message = null; // Act - var visitStatus = visitor.TryVisit(ref targetObject, out adapter, out message); + var visitStatus = visitor.TryVisit(ref targetObject, out var adapter, out var message); // Assert Assert.True(visitStatus); @@ -146,11 +140,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal { // Arrange var visitor = new ObjectVisitor(new ParsedPath(path), new DefaultContractResolver()); - IAdapter adapter = null; - string message = null; // Act - var visitStatus = visitor.TryVisit(ref targetObject, out adapter, out message); + var visitStatus = visitor.TryVisit(ref targetObject, out var adapter, out var message); // Assert Assert.True(visitStatus); @@ -168,11 +160,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal var visitor = new ObjectVisitor(new ParsedPath($"/Customers/{position}/States/-"), new DefaultContractResolver()); var automobileDepartment = new Class1Nested(); object targetObject = automobileDepartment; - IAdapter adapter = null; - string message = null; // Act - var visitStatus = visitor.TryVisit(ref targetObject, out adapter, out message); + var visitStatus = visitor.TryVisit(ref targetObject, out var adapter, out var message); // Assert Assert.False(visitStatus); @@ -190,11 +180,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal var visitor = new ObjectVisitor(new ParsedPath($"/Customers/{position}/States/-"), new DefaultContractResolver()); var automobileDepartment = new Class1Nested(); object targetObject = automobileDepartment; - IAdapter adapter = null; - string message = null; // Act - var visitStatus = visitor.TryVisit(ref targetObject, out adapter, out message); + var visitStatus = visitor.TryVisit(ref targetObject, out var adapter, out var message); // Assert Assert.False(visitStatus); @@ -211,16 +199,30 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal var visitor = new ObjectVisitor(new ParsedPath($"/NonExisting"), new DefaultContractResolver()); var model = new Class1(); object targetObject = model; - IAdapter adapter = null; - string message = null; // Act - var visitStatus = visitor.TryVisit(ref targetObject, out adapter, out message); + 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_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/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTOWithNestedDTO.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTOWithNestedDTO.cs deleted file mode 100644 index de089eb25f..0000000000 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTOWithNestedDTO.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Collections.Generic; - -namespace Microsoft.AspNetCore.JsonPatch -{ - public class SimpleDTOWithNestedDTO - { - public int IntegerValue { get; set; } - - public NestedDTO NestedDTO { get; set; } - - public SimpleDTO SimpleDTO { get; set; } - - public InheritedDTO InheritedDTO { get; set; } - - public List SimpleDTOList { get; set; } - - public IList SimpleDTOIList { get; set; } - - public SimpleDTOWithNestedDTO() - { - this.NestedDTO = new NestedDTO(); - this.SimpleDTO = new SimpleDTO(); - this.InheritedDTO = new InheritedDTO(); - this.SimpleDTOList = new List(); - } - } -} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTOWithNestedDTOWithNullCheck.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTOWithNestedDTOWithNullCheck.cs deleted file mode 100644 index 308f23b470..0000000000 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTOWithNestedDTOWithNullCheck.cs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -namespace Microsoft.AspNetCore.JsonPatch -{ - public class SimpleDTOWithNestedDTOWithNullCheck - { - public SimpleDTOWithNullCheck SimpleDTOWithNullCheck { get; set; } - - public SimpleDTOWithNestedDTOWithNullCheck() - { - SimpleDTOWithNullCheck = new SimpleDTOWithNullCheck(); - } - } -} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTO.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleObject.cs similarity index 95% rename from test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTO.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/SimpleObject.cs index 6dc1f173de..28a9570c2b 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTO.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleObject.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; namespace Microsoft.AspNetCore.JsonPatch { - public class SimpleDTO + public class SimpleObject { public List IntegerList { get; set; } public IList IntegerIList { get; set; } diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleObjectWithNestedObject.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleObjectWithNestedObject.cs new file mode 100644 index 0000000000..4d7c0e2bd8 --- /dev/null +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/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/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleObjectWithNestedObjectWithNullCheck.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleObjectWithNestedObjectWithNullCheck.cs new file mode 100644 index 0000000000..f2423700d8 --- /dev/null +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleObjectWithNestedObjectWithNullCheck.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 SimpleObjectWithNestedObjectWithNullCheck + { + public SimpleObjectWithNullCheck SimpleObjectWithNullCheck { get; set; } + + public SimpleObjectWithNestedObjectWithNullCheck() + { + SimpleObjectWithNullCheck = new SimpleObjectWithNullCheck(); + } + } +} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTOWithNullCheck.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleObjectWithNullCheck.cs similarity index 93% rename from test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTOWithNullCheck.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/SimpleObjectWithNullCheck.cs index d2a5fe51a4..83338c5a23 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleDTOWithNullCheck.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleObjectWithNullCheck.cs @@ -5,7 +5,7 @@ using System; namespace Microsoft.AspNetCore.JsonPatch { - public class SimpleDTOWithNullCheck + public class SimpleObjectWithNullCheck { private string stringProperty; From 51781762195bcc463d837d5c8914f218a6d43659 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 29 Aug 2017 09:41:12 -0700 Subject: [PATCH 271/471] Use Directory.Build.props/targets --- appveyor.yml => .appveyor.yml | 0 build/common.props => Directory.Build.props | 8 ++++---- Directory.Build.targets | 2 ++ .../Microsoft.AspNetCore.Html.Abstractions.csproj | 2 -- .../Microsoft.Extensions.WebEncoders.csproj | 2 -- test/Directory.Build.props | 10 ++++++++++ .../Microsoft.AspNetCore.Html.Abstractions.Test.csproj | 9 --------- .../Microsoft.Extensions.WebEncoders.Tests.csproj | 5 ----- 8 files changed, 16 insertions(+), 22 deletions(-) rename appveyor.yml => .appveyor.yml (100%) rename build/common.props => Directory.Build.props (75%) create mode 100644 Directory.Build.targets create mode 100644 test/Directory.Build.props diff --git a/appveyor.yml b/.appveyor.yml similarity index 100% rename from appveyor.yml rename to .appveyor.yml diff --git a/build/common.props b/Directory.Build.props similarity index 75% rename from build/common.props rename to Directory.Build.props index c03e5c1314..620aa5b381 100644 --- a/build/common.props +++ b/Directory.Build.props @@ -1,11 +1,11 @@ - - - + + + https://github.com/aspnet/HtmlAbstractions git - $(MSBuildThisFileDirectory)Key.snk + $(MSBuildThisFileDirectory)build\Key.snk true true $(VersionSuffix)-$(BuildNumber) diff --git a/Directory.Build.targets b/Directory.Build.targets new file mode 100644 index 0000000000..f75adf7e4d --- /dev/null +++ b/Directory.Build.targets @@ -0,0 +1,2 @@ + + diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.csproj b/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.csproj index c26d590912..d6d301320f 100755 --- a/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.csproj +++ b/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.csproj @@ -1,7 +1,5 @@  - - Microsoft ASP.NET Core ASP.NET Core HTML abstractions used for building HTML content. diff --git a/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.csproj b/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.csproj index de62d482f9..04359f96f5 100755 --- a/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.csproj +++ b/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.csproj @@ -1,7 +1,5 @@  - - Microsoft .NET Extensions Contains registration and configuration APIs to add the core framework encoders to a dependency injection container. diff --git a/test/Directory.Build.props b/test/Directory.Build.props new file mode 100644 index 0000000000..98d33955fd --- /dev/null +++ b/test/Directory.Build.props @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.csproj b/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.csproj index 5030f90ad5..f899e1a699 100755 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.csproj +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.csproj @@ -1,7 +1,5 @@  - - netcoreapp2.0;net461 netcoreapp2.0 @@ -12,11 +10,4 @@ - - - - - - - diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj b/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj index 19406979f2..0236c3e9af 100755 --- a/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj +++ b/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj @@ -1,7 +1,5 @@  - - netcoreapp2.0;net461 netcoreapp2.0 @@ -13,9 +11,6 @@ - - - From 11377e08f6ceff699aa2d64a568bb81bc0d48f20 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 29 Aug 2017 09:42:24 -0700 Subject: [PATCH 272/471] Use PackageLineup to manage PackageReference versions --- Directory.Build.props | 3 +-- Directory.Build.targets | 14 +++++++++++++- NuGet.config | 1 - build/dependencies.props | 12 ------------ build/repo.props | 6 ++++++ .../Microsoft.AspNetCore.Html.Abstractions.csproj | 2 +- .../Microsoft.Extensions.WebEncoders.csproj | 6 +++--- test/Directory.Build.props | 8 ++++---- .../Microsoft.Extensions.WebEncoders.Tests.csproj | 2 +- 9 files changed, 29 insertions(+), 25 deletions(-) delete mode 100644 build/dependencies.props create mode 100644 build/repo.props diff --git a/Directory.Build.props b/Directory.Build.props index 620aa5b381..74b2f8246d 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,5 +1,4 @@  - @@ -13,7 +12,7 @@ - + diff --git a/Directory.Build.targets b/Directory.Build.targets index f75adf7e4d..bc118fd907 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -1,2 +1,14 @@ - + + + + <_BootstrapperFile Condition=" $([MSBuild]::IsOSUnixLike()) ">build.sh + <_BootstrapperFile Condition="! $([MSBuild]::IsOSUnixLike()) ">build.cmd + <_BootstrapperError> + Package references have not been pinned. Run './$(_BootstrapperFile) /t:Pin'. + Also, you can run './$(_BootstrapperFile) /t:Restore' which will pin *and* restore packages. '$(_BootstrapperFile)' can be found in '$(MSBuildThisFileDirectory)'. + + + + + diff --git a/NuGet.config b/NuGet.config index 4e8a1f6de1..20060c934e 100644 --- a/NuGet.config +++ b/NuGet.config @@ -3,7 +3,6 @@ - diff --git a/build/dependencies.props b/build/dependencies.props deleted file mode 100644 index 1235e00530..0000000000 --- a/build/dependencies.props +++ /dev/null @@ -1,12 +0,0 @@ - - - 2.1.0-* - 4.4.0-* - 2.1.1-* - 2.0.0-* - 2.0.0-* - 2.0.0-* - 15.3.0 - 2.3.0-beta4-build3742 - - diff --git a/build/repo.props b/build/repo.props new file mode 100644 index 0000000000..13fe1c296a --- /dev/null +++ b/build/repo.props @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.csproj b/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.csproj index d6d301320f..79e5ea01a5 100755 --- a/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.csproj +++ b/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.csproj @@ -12,7 +12,7 @@ Microsoft.AspNetCore.Html.IHtmlContent - + diff --git a/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.csproj b/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.csproj index 04359f96f5..cd0c144633 100755 --- a/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.csproj +++ b/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.csproj @@ -11,9 +11,9 @@ - - - + + + diff --git a/test/Directory.Build.props b/test/Directory.Build.props index 98d33955fd..a728ed268e 100644 --- a/test/Directory.Build.props +++ b/test/Directory.Build.props @@ -2,9 +2,9 @@ - - - - + + + + diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj b/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj index 0236c3e9af..c019c8b97e 100755 --- a/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj +++ b/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj @@ -10,7 +10,7 @@ - + From 0f51c56c3fa120edeeaec51629117338c6265fd3 Mon Sep 17 00:00:00 2001 From: Jass Bagga Date: Tue, 5 Sep 2017 16:07:25 -0700 Subject: [PATCH 273/471] Combine ExpandoObjectAdapter and DictionaryAdapter (#106) Use JsonDictionaryContract in the DictionaryAdapter and combine with ExpandoObjectAdapter --- .../Internal/DictionaryAdapter.cs | 111 ------------ ...ectAdapter.cs => DictionaryAdapterOfTU.cs} | 115 ++++++++---- .../Internal/ObjectVisitor.cs | 27 +-- .../JsonPatchDocumentOfT.cs | 14 +- .../Properties/Resources.Designer.cs | 14 ++ .../Resources.resx | 3 + .../DictionaryAdapterTest.cs | 171 +++++++++++++++--- .../Dynamic/ReplaceOperationTests.cs | 60 ++---- .../ObjectVisitorTest.cs | 8 +- 9 files changed, 273 insertions(+), 250 deletions(-) delete mode 100644 src/Microsoft.AspNetCore.JsonPatch/Internal/DictionaryAdapter.cs rename src/Microsoft.AspNetCore.JsonPatch/Internal/{ExpandoObjectAdapter.cs => DictionaryAdapterOfTU.cs} (52%) diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/DictionaryAdapter.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/DictionaryAdapter.cs deleted file mode 100644 index 4c7651e475..0000000000 --- a/src/Microsoft.AspNetCore.JsonPatch/Internal/DictionaryAdapter.cs +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Collections; -using Newtonsoft.Json.Serialization; - -namespace Microsoft.AspNetCore.JsonPatch.Internal -{ - public class DictionaryAdapter : IAdapter - { - public bool TryAdd( - object target, - string segment, - IContractResolver contractResolver, - object value, - out string errorMessage) - { - var dictionary = (IDictionary)target; - - // As per JsonPatch spec, if a key already exists, adding should replace the existing value - dictionary[segment] = value; - - errorMessage = null; - return true; - } - - public bool TryGet( - object target, - string segment, - IContractResolver contractResolver, - out object value, - out string errorMessage) - { - var dictionary = (IDictionary)target; - - value = dictionary[segment]; - errorMessage = null; - return true; - } - - public bool TryRemove( - object target, - string segment, - IContractResolver contractResolver, - out string errorMessage) - { - var dictionary = (IDictionary)target; - - // As per JsonPatch spec, the target location must exist for remove to be successful - if (!dictionary.Contains(segment)) - { - errorMessage = Resources.FormatTargetLocationAtPathSegmentNotFound(segment); - return false; - } - - dictionary.Remove(segment); - errorMessage = null; - return true; - } - - public bool TryReplace( - object target, - string segment, - IContractResolver contractResolver, - object value, - out string errorMessage) - { - var dictionary = (IDictionary)target; - - // As per JsonPatch spec, the target location must exist for remove to be successful - if (!dictionary.Contains(segment)) - { - errorMessage = Resources.FormatTargetLocationAtPathSegmentNotFound(segment); - return false; - } - - dictionary[segment] = value; - errorMessage = null; - return true; - } - - public bool TryTraverse( - object target, - string segment, - IContractResolver contractResolver, - out object nextTarget, - out string errorMessage) - { - var dictionary = target as IDictionary; - if (dictionary == null) - { - nextTarget = null; - errorMessage = null; - return false; - } - - if (dictionary.Contains(segment)) - { - nextTarget = dictionary[segment]; - errorMessage = null; - return true; - } - else - { - nextTarget = null; - errorMessage = null; - return false; - } - } - } -} diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/ExpandoObjectAdapter.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/DictionaryAdapterOfTU.cs similarity index 52% rename from src/Microsoft.AspNetCore.JsonPatch/Internal/ExpandoObjectAdapter.cs rename to src/Microsoft.AspNetCore.JsonPatch/Internal/DictionaryAdapterOfTU.cs index c35d1b702c..67fd33e231 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Internal/ExpandoObjectAdapter.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Internal/DictionaryAdapterOfTU.cs @@ -2,12 +2,11 @@ // 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; namespace Microsoft.AspNetCore.JsonPatch.Internal { - public class ExpandoObjectAdapter : IAdapter + public class DictionaryAdapter : IAdapter { public bool TryAdd( object target, @@ -18,11 +17,20 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal { var contract = (JsonDictionaryContract)contractResolver.ResolveContract(target.GetType()); var key = contract.DictionaryKeyResolver(segment); - var dictionary = (IDictionary)target; + var dictionary = (IDictionary)target; // As per JsonPatch spec, if a key already exists, adding should replace the existing value - dictionary[key] = ConvertValue(dictionary, key, 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; } @@ -36,10 +44,22 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal { var contract = (JsonDictionaryContract)contractResolver.ResolveContract(target.GetType()); var key = contract.DictionaryKeyResolver(segment); - var dictionary = (IDictionary)target; + var dictionary = (IDictionary)target; - value = dictionary[key]; + 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; } @@ -52,16 +72,21 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal { var contract = (JsonDictionaryContract)contractResolver.ResolveContract(target.GetType()); var key = contract.DictionaryKeyResolver(segment); - var dictionary = (IDictionary)target; + 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(key)) + if (!dictionary.ContainsKey(convertedKey)) { errorMessage = Resources.FormatTargetLocationAtPathSegmentNotFound(segment); return false; } - dictionary.Remove(key); + dictionary.Remove(convertedKey); errorMessage = null; return true; @@ -76,16 +101,26 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal { var contract = (JsonDictionaryContract)contractResolver.ResolveContract(target.GetType()); var key = contract.DictionaryKeyResolver(segment); - var dictionary = (IDictionary)target; + 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(key)) + if (!dictionary.ContainsKey(convertedKey)) { errorMessage = Resources.FormatTargetLocationAtPathSegmentNotFound(segment); return false; } - dictionary[key] = ConvertValue(dictionary, key, value); + if (!TryConvertValue(value, out var convertedValue, out errorMessage)) + { + return false; + } + + dictionary[convertedKey] = convertedValue; errorMessage = null; return true; @@ -98,21 +133,19 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal out object nextTarget, out string errorMessage) { - var expandoObject = target as ExpandoObject; - if (expandoObject == null) + var contract = (JsonDictionaryContract)contractResolver.ResolveContract(target.GetType()); + var key = contract.DictionaryKeyResolver(segment); + var dictionary = (IDictionary)target; + + if (!TryConvertKey(key, out var convertedKey, out errorMessage)) { - errorMessage = null; nextTarget = null; return false; } - var contract = (JsonDictionaryContract)contractResolver.ResolveContract(target.GetType()); - var key = contract.DictionaryKeyResolver(segment); - var dictionary = (IDictionary)expandoObject; - - if (dictionary.ContainsKey(key)) + if (dictionary.ContainsKey(convertedKey)) { - nextTarget = dictionary[key]; + nextTarget = dictionary[convertedKey]; errorMessage = null; return true; } @@ -124,20 +157,38 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal } } - private object ConvertValue(IDictionary dictionary, string key, object newValue) + private bool TryConvertKey(string key, out TKey convertedKey, out string errorMessage) { - if (dictionary.TryGetValue(key, out var existingValue)) + var conversionResult = ConversionResultProvider.ConvertTo(key, typeof(TKey)); + if (conversionResult.CanBeConverted) { - if (existingValue != null) - { - var conversionResult = ConversionResultProvider.ConvertTo(newValue, existingValue.GetType()); - if (conversionResult.CanBeConverted) - { - return conversionResult.ConvertedInstance; - } - } + errorMessage = null; + convertedKey = (TKey)conversionResult.ConvertedInstance; + return true; + } + else + { + errorMessage = Resources.FormatInvalidPathSegment(key); + convertedKey = default(TKey); + return false; + } + } + + private 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; } - return newValue; } } } diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/ObjectVisitor.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/ObjectVisitor.cs index bbf6db4ff6..97f108c0a0 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Internal/ObjectVisitor.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Internal/ObjectVisitor.cs @@ -3,7 +3,9 @@ using System; using System.Collections; +using System.Collections.Generic; using System.Dynamic; +using Microsoft.AspNetCore.JsonPatch.Adapters; using Newtonsoft.Json.Serialization; namespace Microsoft.AspNetCore.JsonPatch.Internal @@ -49,22 +51,21 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal private IAdapter SelectAdapater(object targetObject) { - if (targetObject is ExpandoObject) - { - return new ExpandoObjectAdapter(); - } - else if (targetObject is IDynamicMetaObjectProvider) - { - return new DynamicObjectAdapter(); - } - else if (targetObject is IDictionary) - { - return new DictionaryAdapter(); - } - else if (targetObject is IList) + var jsonContract = _contractResolver.ResolveContract(targetObject.GetType()); + + if (targetObject 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/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs b/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs index c81c4e4d6c..d669970407 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs @@ -37,18 +37,8 @@ namespace Microsoft.AspNetCore.JsonPatch // Create from list of operations 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; + Operations = operations ?? throw new ArgumentNullException(nameof(operations)); + ContractResolver = contractResolver ?? throw new ArgumentNullException(nameof(contractResolver)); } /// diff --git a/src/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs index cd99292061..896a3d2ad4 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs @@ -206,6 +206,20 @@ namespace Microsoft.AspNetCore.JsonPatch internal static string FormatPatchNotSupportedForNonGenericLists(object p0) => string.Format(CultureInfo.CurrentCulture, GetString("PatchNotSupportedForNonGenericLists"), 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 target location specified by path segment '{0}' was not found. /// diff --git a/src/Microsoft.AspNetCore.JsonPatch/Resources.resx b/src/Microsoft.AspNetCore.JsonPatch/Resources.resx index 87ed5c0a17..0b67084233 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Resources.resx +++ b/src/Microsoft.AspNetCore.JsonPatch/Resources.resx @@ -144,6 +144,9 @@ Invalid JsonPatch operation '{0}'. + + The provided path segment '{0}' cannot be converted to the target type. + The provided string '{0}' is an invalid path. diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/DictionaryAdapterTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/DictionaryAdapterTest.cs index 084aa57379..cfb99d61ce 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/DictionaryAdapterTest.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/DictionaryAdapterTest.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using Moq; using Newtonsoft.Json.Serialization; using Xunit; @@ -15,33 +14,83 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal public void Add_KeyWhichAlreadyExists_ReplacesExistingValue() { // Arrange - var nameKey = "Name"; - var dictionary = new Dictionary(StringComparer.Ordinal); - dictionary[nameKey] = "Mike"; - var dictionaryAdapter = new DictionaryAdapter(); - var resolver = new Mock(MockBehavior.Strict); + 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, nameKey, resolver.Object, "James", out var message); + 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("James", dictionary[nameKey]); + 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( + string.Format("The provided path segment '{0}' cannot be converted to the target type.", guidKey.ToString()), + message); + Assert.Null(outValue); } [Fact] public void Get_UsingCaseSensitiveKey_FailureScenario() { // Arrange - var dictionaryAdapter = new DictionaryAdapter(); - var resolver = new Mock(MockBehavior.Strict); + 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.Object, "James", out var message); + var addStatus = dictionaryAdapter.TryAdd(dictionary, nameKey, resolver, "James", out var message); // Assert Assert.True(addStatus); @@ -50,11 +99,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal Assert.Equal("James", dictionary[nameKey]); // Act - addStatus = dictionaryAdapter.TryGet(dictionary, nameKey.ToUpper(), resolver.Object, out var outValue, out message); + var getStatus = dictionaryAdapter.TryGet(dictionary, nameKey.ToUpper(), resolver, out var outValue, out message); // Assert - Assert.True(addStatus); - Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.False(getStatus); + Assert.Equal( + string.Format("The target location specified by path segment '{0}' was not found.", nameKey.ToUpper()), + message); Assert.Null(outValue); } @@ -62,13 +113,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal public void Get_UsingCaseSensitiveKey_SuccessScenario() { // Arrange - var dictionaryAdapter = new DictionaryAdapter(); - var resolver = new Mock(MockBehavior.Strict); + 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.Object, "James", out var message); + var addStatus = dictionaryAdapter.TryAdd(dictionary, nameKey, resolver, "James", out var message); // Assert Assert.True(addStatus); @@ -77,7 +128,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal Assert.Equal("James", dictionary[nameKey]); // Act - addStatus = dictionaryAdapter.TryGet(dictionary, nameKey, resolver.Object, out var outValue, out message); + addStatus = dictionaryAdapter.TryGet(dictionary, nameKey, resolver, out var outValue, out message); // Assert Assert.True(addStatus); @@ -92,11 +143,11 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal var nameKey = "Name"; var dictionary = new Dictionary(StringComparer.Ordinal); dictionary.Add(nameKey, "Mike"); - var dictionaryAdapter = new DictionaryAdapter(); - var resolver = new Mock(MockBehavior.Strict); + var dictionaryAdapter = new DictionaryAdapter(); + var resolver = new DefaultContractResolver(); // Act - var replaceStatus = dictionaryAdapter.TryReplace(dictionary, nameKey, resolver.Object, "James", out var message); + var replaceStatus = dictionaryAdapter.TryReplace(dictionary, nameKey, resolver, "James", out var message); // Assert Assert.True(replaceStatus); @@ -105,17 +156,58 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal 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( + string.Format("The value '{0}' is invalid for target location.", "test"), + 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 Mock(MockBehavior.Strict); + var dictionaryAdapter = new DictionaryAdapter(); + var resolver = new DefaultContractResolver(); // Act - var replaceStatus = dictionaryAdapter.TryReplace(dictionary, nameKey, resolver.Object, "Mike", out var message); + var replaceStatus = dictionaryAdapter.TryReplace(dictionary, nameKey, resolver, "Mike", out var message); // Assert Assert.False(replaceStatus); @@ -131,11 +223,11 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal // Arrange var nameKey = "Name"; var dictionary = new Dictionary(StringComparer.Ordinal); - var dictionaryAdapter = new DictionaryAdapter(); - var resolver = new Mock(MockBehavior.Strict); + var dictionaryAdapter = new DictionaryAdapter(); + var resolver = new DefaultContractResolver(); // Act - var removeStatus = dictionaryAdapter.TryRemove(dictionary, nameKey, resolver.Object, out var message); + var removeStatus = dictionaryAdapter.TryRemove(dictionary, nameKey, resolver, out var message); // Assert Assert.False(removeStatus); @@ -152,11 +244,30 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal var nameKey = "Name"; var dictionary = new Dictionary(StringComparer.Ordinal); dictionary[nameKey] = "James"; - var dictionaryAdapter = new DictionaryAdapter(); - var resolver = new Mock(MockBehavior.Strict); + var dictionaryAdapter = new DictionaryAdapter(); + var resolver = new DefaultContractResolver(); // Act - var removeStatus = dictionaryAdapter.TryRemove(dictionary, nameKey, resolver.Object, out var message); + 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); diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceOperationTests.cs index 88d1662e1d..5d1fa77d85 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceOperationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceOperationTests.cs @@ -5,8 +5,6 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Dynamic; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; using Xunit; namespace Microsoft.AspNetCore.JsonPatch.Internal @@ -26,11 +24,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal var patchDoc = new JsonPatchDocument(); patchDoc.Replace("GuidValue", newGuid); - // serialize & deserialize - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserizalized = JsonConvert.DeserializeObject(serialized); - - deserizalized.ApplyTo(doc); + patchDoc.ApplyTo(doc); Assert.Equal(newGuid, doc.GuidValue); } @@ -46,11 +40,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal var patchDoc = new JsonPatchDocument(); patchDoc.Replace("GuidValue", newGuid); - // serialize & deserialize - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserizalized = JsonConvert.DeserializeObject(serialized); - - deserizalized.ApplyTo(doc); + patchDoc.ApplyTo(doc); Assert.Equal(newGuid, doc.GuidValue); } @@ -71,11 +61,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal var patchDoc = new JsonPatchDocument(); patchDoc.Replace("nestedobject/GuidValue", newGuid); - // serialize & deserialize - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserizalized = JsonConvert.DeserializeObject(serialized); - - deserizalized.ApplyTo(doc); + patchDoc.ApplyTo(doc); Assert.Equal(newGuid, doc.NestedObject.GuidValue); } @@ -99,11 +85,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal var patchDoc = new JsonPatchDocument(); patchDoc.Replace("SimpleDTO", newDTO); - // serialize & deserialize - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); + patchDoc.ApplyTo(doc); Assert.Equal(1, doc.SimpleDTO.DoubleValue); Assert.Equal(0, doc.SimpleDTO.IntegerValue); @@ -120,10 +102,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal var patchDoc = new JsonPatchDocument(); patchDoc.Replace("IntegerList/0", 5); - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); + patchDoc.ApplyTo(doc); Assert.Equal(new List() { 5, 2, 3 }, doc.IntegerList); } @@ -138,10 +117,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal var patchDoc = new JsonPatchDocument(); patchDoc.Replace("IntegerList", new List() { 4, 5, 6 }); - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); + patchDoc.ApplyTo(doc); Assert.Equal(new List() { 4, 5, 6 }, doc.IntegerList); } @@ -159,10 +135,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal var patchDoc = new JsonPatchDocument(); patchDoc.Replace("SimpleDTOList/0/IntegerList/0", 4); - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); + patchDoc.ApplyTo(doc); Assert.Equal(4, doc.SimpleDTOList[0].IntegerList[0]); } @@ -180,10 +153,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal var patchDoc = new JsonPatchDocument(); patchDoc.Replace("SimpleDTOList/0/IntegerList/-", 4); - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); + patchDoc.ApplyTo(doc); Assert.Equal(4, doc.SimpleDTOList[0].IntegerList[2]); } @@ -198,10 +168,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal var patchDoc = new JsonPatchDocument(); patchDoc.Replace("IntegerList", new List() { 4, 5, 6 }); - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); + patchDoc.ApplyTo(doc); Assert.Equal(new List() { 4, 5, 6 }, doc.IntegerList); } @@ -216,10 +183,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal var patchDoc = new JsonPatchDocument(); patchDoc.Replace("IntegerList", new Collection() { 4, 5, 6 }); - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); + patchDoc.ApplyTo(doc); Assert.Equal(new List() { 4, 5, 6 }, doc.IntegerList); } @@ -234,9 +198,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal var patchDoc = new JsonPatchDocument(); patchDoc.Replace("IntegerList/-", 5); - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - deserialized.ApplyTo(doc); + patchDoc.ApplyTo(doc); Assert.Equal(new List() { 1, 2, 5 }, doc.IntegerList); } diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectVisitorTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectVisitorTest.cs index 5eddac8685..3384986c28 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectVisitorTest.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectVisitorTest.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; using System.Collections.Generic; using System.Dynamic; using Newtonsoft.Json.Serialization; @@ -87,7 +88,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal Assert.True(visitStatus); Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); Assert.Same(expectedTargetObject, targetObject); - Assert.IsType(adapter); + Assert.Equal(typeof(DictionaryAdapter), adapter.GetType()); } public static IEnumerable ReturnsExpandoAdapterData @@ -107,7 +108,8 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal public void Visit_ValidPathToExpandoObject_ReturnsExpandoAdapter(object targetObject, string path, object expectedTargetObject) { // Arrange - var visitor = new ObjectVisitor(new ParsedPath(path), new DefaultContractResolver()); + 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); @@ -116,7 +118,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal Assert.True(visitStatus); Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); Assert.Same(expectedTargetObject, targetObject); - Assert.IsType(adapter); + Assert.Same(typeof(DictionaryAdapter), adapter.GetType()); } public static IEnumerable ReturnsPocoAdapterData From bf5c043de39d1f415baedc38f559db23ebc4d2e2 Mon Sep 17 00:00:00 2001 From: Jass Bagga Date: Mon, 11 Sep 2017 09:54:29 -0700 Subject: [PATCH 274/471] Refactor GetPath in JsonPatchDocumentOfT (#107) Addresses #98 --- .../JsonPatchDocumentOfT.cs | 167 ++++++++---------- .../Properties/AssemblyInfo.cs | 7 + .../Properties/Resources.Designer.cs | 42 +++-- .../Resources.resx | 3 + .../JsonPatchDocumentGetPathTest.cs | 124 +++++++++++++ ...nPatchDocumentJsonPropertyAttributeTest.cs | 31 ++++ ...Microsoft.AspNetCore.JsonPatch.Test.csproj | 4 + 7 files changed, 274 insertions(+), 104 deletions(-) create mode 100644 src/Microsoft.AspNetCore.JsonPatch/Properties/AssemblyInfo.cs create mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentGetPathTest.cs diff --git a/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs b/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs index d669970407..33e1e5033f 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs @@ -58,7 +58,7 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "add", - GetPath(path), + GetPath(path, null), from: null, value: value)); @@ -85,7 +85,7 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "add", - GetPath(path) + "/" + position, + GetPath(path, position.ToString()), from: null, value: value)); @@ -93,7 +93,7 @@ namespace Microsoft.AspNetCore.JsonPatch } /// - /// At value at end of list + /// Add value to the end of the list /// /// value type /// target location @@ -108,7 +108,7 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "add", - GetPath(path) + "/-", + GetPath(path, "-"), from: null, value: value)); @@ -128,7 +128,7 @@ namespace Microsoft.AspNetCore.JsonPatch throw new ArgumentNullException(nameof(path)); } - Operations.Add(new Operation("remove", GetPath(path), from: null)); + Operations.Add(new Operation("remove", GetPath(path, null), from: null)); return this; } @@ -149,7 +149,7 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "remove", - GetPath(path) + "/" + position, + GetPath(path, position.ToString()), from: null)); return this; @@ -170,7 +170,7 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "remove", - GetPath(path) + "/-", + GetPath(path, "-"), from: null)); return this; @@ -192,7 +192,7 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "replace", - GetPath(path), + GetPath(path, null), from: null, value: value)); @@ -217,7 +217,7 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "replace", - GetPath(path) + "/" + position, + GetPath(path, position.ToString()), from: null, value: value)); @@ -240,7 +240,7 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "replace", - GetPath(path) + "/-", + GetPath(path, "-"), from: null, value: value)); @@ -270,8 +270,8 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "move", - GetPath(path), - GetPath(from))); + GetPath(path, null), + GetPath(from, null))); return this; } @@ -301,8 +301,8 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "move", - GetPath(path), - GetPath(from) + "/" + positionFrom)); + GetPath(path, null), + GetPath(from, positionFrom.ToString()))); return this; } @@ -332,8 +332,8 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "move", - GetPath(path) + "/" + positionTo, - GetPath(from))); + GetPath(path, positionTo.ToString()), + GetPath(from, null))); return this; } @@ -365,8 +365,8 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "move", - GetPath(path) + "/" + positionTo, - GetPath(from) + "/" + positionFrom)); + GetPath(path, positionTo.ToString()), + GetPath(from, positionFrom.ToString()))); return this; } @@ -396,8 +396,8 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "move", - GetPath(path) + "/-", - GetPath(from) + "/" + positionFrom)); + GetPath(path, "-"), + GetPath(from, positionFrom.ToString()))); return this; } @@ -425,8 +425,8 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "move", - GetPath(path) + "/-", - GetPath(from))); + GetPath(path, "-"), + GetPath(from, null))); return this; } @@ -454,8 +454,8 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "copy", - GetPath(path) - , GetPath(from))); + GetPath(path, null), + GetPath(from, null))); return this; } @@ -485,8 +485,8 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "copy", - GetPath(path), - GetPath(from) + "/" + positionFrom)); + GetPath(path, null), + GetPath(from, positionFrom.ToString()))); return this; } @@ -516,8 +516,8 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "copy", - GetPath(path) + "/" + positionTo, - GetPath(from))); + GetPath(path, positionTo.ToString()), + GetPath(from, null))); return this; } @@ -549,8 +549,8 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "copy", - GetPath(path) + "/" + positionTo, - GetPath(from) + "/" + positionFrom)); + GetPath(path, positionTo.ToString()), + GetPath(from, positionFrom.ToString()))); return this; } @@ -580,8 +580,8 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "copy", - GetPath(path) + "/-", - GetPath(from) + "/" + positionFrom)); + GetPath(path, "-"), + GetPath(from, positionFrom.ToString()))); return this; } @@ -609,8 +609,8 @@ namespace Microsoft.AspNetCore.JsonPatch Operations.Add(new Operation( "copy", - GetPath(path) + "/-", - GetPath(from))); + GetPath(path, "-"), + GetPath(from, null))); return this; } @@ -705,61 +705,57 @@ namespace Microsoft.AspNetCore.JsonPatch return allOps; } - private string GetPath(Expression> expr) + // Internal for testing + internal string GetPath(Expression> expr, string position) { - return "/" + GetPath(expr.Body, true).ToLowerInvariant(); + var segments = GetPathSegments(expr.Body); + var path = String.Join("/", segments); + if (position != null) + { + path += "/" + position; + if (segments.Count == 0) + { + return path.ToLowerInvariant(); + } + } + + return "/" + path.ToLowerInvariant(); } - private string GetPath(Expression expr, bool firstTime) + 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; - if (ContinueWithSubPath(binaryExpression.Left.NodeType, false)) - { - var leftFromBinaryExpression = GetPath(binaryExpression.Left, false); - return leftFromBinaryExpression + "/" + binaryExpression.Right.ToString(); - } - else - { - return binaryExpression.Right.ToString(); - } case ExpressionType.Call: var methodCallExpression = (MethodCallExpression)expr; + listOfSegments.AddRange(GetPathSegments(methodCallExpression.Object)); + listOfSegments.Add(EvaluateExpression(methodCallExpression.Arguments[0])); + return listOfSegments; - if (ContinueWithSubPath(methodCallExpression.Object.NodeType, false)) - { - var leftFromMemberCallExpression = GetPath(methodCallExpression.Object, false); - return leftFromMemberCallExpression + "/" + - GetIndexerInvocation(methodCallExpression.Arguments[0]); - } - else - { - return GetIndexerInvocation(methodCallExpression.Arguments[0]); - } case ExpressionType.Convert: - return GetPath(((UnaryExpression)expr).Operand, false); + 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; - if (ContinueWithSubPath(memberExpression.Expression.NodeType, false)) - { - var left = GetPath(memberExpression.Expression, false); - // Get property name, respecting JsonProperty attribute - return left + "/" + GetPropertyNameFromMemberExpression(memberExpression); - } - else - { - // Get property name, respecting JsonProperty attribute - return GetPropertyNameFromMemberExpression(memberExpression); - } case ExpressionType.Parameter: // Fits "x => x" (the whole document which is "" as JSON pointer) - return firstTime ? string.Empty : null; + return listOfSegments; + default: - return string.Empty; + throw new InvalidOperationException(Resources.FormatExpressionTypeNotSupported(expr)); } } @@ -776,33 +772,24 @@ namespace Microsoft.AspNetCore.JsonPatch return null; } - private static bool ContinueWithSubPath(ExpressionType expressionType, bool firstTime) + private static bool ContinueWithSubPath(ExpressionType expressionType) { - if (firstTime) - { - return (expressionType == ExpressionType.ArrayIndex - || expressionType == ExpressionType.Call - || expressionType == ExpressionType.Convert - || expressionType == ExpressionType.MemberAccess - || expressionType == ExpressionType.Parameter); - } - else - { - return (expressionType == ExpressionType.ArrayIndex - || expressionType == ExpressionType.Call - || expressionType == ExpressionType.Convert - || expressionType == ExpressionType.MemberAccess); - } + return (expressionType == ExpressionType.ArrayIndex + || expressionType == ExpressionType.Call + || expressionType == ExpressionType.Convert + || expressionType == ExpressionType.MemberAccess); + } - private static string GetIndexerInvocation(Expression expression) + // 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); - Func func; - - func = lambda.Compile(); + var func = lambda.Compile(); return Convert.ToString(func(null), CultureInfo.InvariantCulture); } diff --git a/src/Microsoft.AspNetCore.JsonPatch/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.JsonPatch/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..08e6f5e01c --- /dev/null +++ b/src/Microsoft.AspNetCore.JsonPatch/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.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] diff --git a/src/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs index 896a3d2ad4..432fab2cbf 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs @@ -80,6 +80,20 @@ namespace Microsoft.AspNetCore.JsonPatch internal static string FormatCannotUpdateProperty(object p0) => string.Format(CultureInfo.CurrentCulture, GetString("CannotUpdateProperty"), p0); + /// + /// The expression '{0}' is not supported. + /// + internal static string ExpressionTypeNotSupported + { + get => GetString("ExpressionTypeNotSupported"); + } + + /// + /// The expression '{0}' is not supported. + /// + 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. /// @@ -136,6 +150,20 @@ namespace Microsoft.AspNetCore.JsonPatch 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. /// @@ -206,20 +234,6 @@ namespace Microsoft.AspNetCore.JsonPatch internal static string FormatPatchNotSupportedForNonGenericLists(object p0) => string.Format(CultureInfo.CurrentCulture, GetString("PatchNotSupportedForNonGenericLists"), 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 target location specified by path segment '{0}' was not found. /// diff --git a/src/Microsoft.AspNetCore.JsonPatch/Resources.resx b/src/Microsoft.AspNetCore.JsonPatch/Resources.resx index 0b67084233..bf07e4a31e 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Resources.resx +++ b/src/Microsoft.AspNetCore.JsonPatch/Resources.resx @@ -132,6 +132,9 @@ 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. diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentGetPathTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentGetPathTest.cs new file mode 100644 index 0000000000..dcde4b442d --- /dev/null +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentGetPathTest.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.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( + string.Format("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/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs index 3948b79484..50ab6a9f5b 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.Collections.Generic; using System.Linq; using System.Reflection; using Newtonsoft.Json; @@ -11,6 +12,36 @@ namespace Microsoft.AspNetCore.JsonPatch { public class JsonPatchDocumentJsonPropertyAttributeTest { + [Fact] + public void Add_ToRoot_OfListOfObjects_AtEndOfList() + { + var patchDoc = new JsonPatchDocument>(); + patchDoc.Add(p => p, new JsonPropertyObject()); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = + JsonConvert.DeserializeObject>(serialized); + + // get path + var pathToCheck = deserialized.Operations.First().path; + Assert.Equal("/-", pathToCheck); + } + + [Fact] + public void Add_ToRoot_OfListOfObjects_AtGivenPosition() + { + var patchDoc = new JsonPatchDocument>(); + patchDoc.Add(p => p[3], new JsonPropertyObject()); + + var serialized = JsonConvert.SerializeObject(patchDoc); + var deserialized = + JsonConvert.DeserializeObject>(serialized); + + // get path + var pathToCheck = deserialized.Operations.First().path; + Assert.Equal("/3", pathToCheck); + } + [Fact] public void Add_WithExpression_RespectsJsonPropertyName_ForModelProperty() { diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj index 2e4f68b538..6d7b403a79 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj @@ -14,4 +14,8 @@ + + + + From 148942979220ea964f10191cf676d8865a13d9d3 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Thu, 21 Sep 2017 17:47:46 -0700 Subject: [PATCH 275/471] Increase Minimum Version of Visual Studio to 15.3.0 --- HtmlAbstractions.sln | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HtmlAbstractions.sln b/HtmlAbstractions.sln index 5b6b09416f..5ee1cb4612 100644 --- a/HtmlAbstractions.sln +++ b/HtmlAbstractions.sln @@ -1,7 +1,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.26127.0 -MinimumVisualStudioVersion = 10.0.40219.1 +MinimumVisualStudioVersion = 15.0.26730.03 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A5A15F1C-885A-452A-A731-B0173DDBD913}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{F31FF137-390C-49BF-A3BD-7C6ED3597C21}" From 34f59ad305166e1efe64d17f96c5e5e30d728628 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Thu, 21 Sep 2017 17:49:32 -0700 Subject: [PATCH 276/471] Increase Minimum Version of Visual Studio to 15.3.0 --- JsonPatch.sln | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JsonPatch.sln b/JsonPatch.sln index 87b48a8ea1..f0b6a578f1 100644 --- a/JsonPatch.sln +++ b/JsonPatch.sln @@ -1,7 +1,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.26815.3 -MinimumVisualStudioVersion = 10.0.40219.1 +MinimumVisualStudioVersion = 15.0.26730.03 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{430B59ED-F960-4D3A-8FFE-3370008E168D}" ProjectSection(SolutionItems) = preProject src\Directory.Build.props = src\Directory.Build.props From f3ae0489befacdbc9d1361f8bedcc45d6dd5b302 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Wed, 20 Sep 2017 13:20:26 -0700 Subject: [PATCH 277/471] Update bootstrappers --- .appveyor.yml | 4 +- build.cmd | 2 +- build.sh | 197 +------------------------------------- run.cmd | 2 + build.ps1 => run.ps1 | 56 +++++++---- run.sh | 223 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 266 insertions(+), 218 deletions(-) create mode 100644 run.cmd rename build.ps1 => run.ps1 (73%) create mode 100755 run.sh diff --git a/.appveyor.yml b/.appveyor.yml index 31efd8196f..46038786c9 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,4 +1,4 @@ -init: +init: - git config --global core.autocrlf true branches: only: @@ -7,7 +7,7 @@ branches: - dev - /^(.*\/)?ci-.*$/ build_script: - - ps: .\build.ps1 + - ps: .\run.ps1 default-build clone_depth: 1 environment: global: diff --git a/build.cmd b/build.cmd index b6c8d24864..c0050bda12 100644 --- a/build.cmd +++ b/build.cmd @@ -1,2 +1,2 @@ @ECHO OFF -PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0build.ps1' %*; exit $LASTEXITCODE" +PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0run.ps1' default-build %*; exit $LASTEXITCODE" diff --git a/build.sh b/build.sh index 11cdbe5504..98a4b22765 100755 --- a/build.sh +++ b/build.sh @@ -1,199 +1,8 @@ #!/usr/bin/env bash set -euo pipefail - -# -# variables -# - -RESET="\033[0m" -RED="\033[0;31m" -MAGENTA="\033[0;95m" DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -[ -z "${DOTNET_HOME:-}" ] && DOTNET_HOME="$HOME/.dotnet" -config_file="$DIR/version.xml" -verbose=false -update=false -repo_path="$DIR" -channel='' -tools_source='' -# -# Functions -# -__usage() { - echo "Usage: $(basename "${BASH_SOURCE[0]}") [options] [[--] ...]" - echo "" - echo "Arguments:" - echo " ... Arguments passed to MSBuild. Variable number of arguments allowed." - echo "" - echo "Options:" - echo " --verbose Show verbose output." - echo " -c|--channel The channel of KoreBuild to download. Overrides the value from the config file.." - echo " --config-file TThe path to the configuration file that stores values. Defaults to version.xml." - echo " -d|--dotnet-home The directory where .NET Core tools will be stored. Defaults to '\$DOTNET_HOME' or '\$HOME/.dotnet." - echo " --path The directory to build. Defaults to the directory containing the script." - echo " -s|--tools-source The base url where build tools can be downloaded. Overrides the value from the config file." - echo " -u|--update Update to the latest KoreBuild even if the lock file is present." - echo "" - echo "Description:" - echo " This function will create a file \$DIR/korebuild-lock.txt. This lock file can be committed to source, but does not have to be." - echo " When the lockfile is not present, KoreBuild will create one using latest available version from \$channel." - - if [[ "${1:-}" != '--no-exit' ]]; then - exit 2 - fi -} - -get_korebuild() { - local version - local lock_file="$repo_path/korebuild-lock.txt" - if [ ! -f "$lock_file" ] || [ "$update" = true ]; then - __get_remote_file "$tools_source/korebuild/channels/$channel/latest.txt" "$lock_file" - fi - version="$(grep 'version:*' -m 1 "$lock_file")" - if [[ "$version" == '' ]]; then - __error "Failed to parse version from $lock_file. Expected a line that begins with 'version:'" - return 1 - fi - version="$(echo "${version#version:}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" - local korebuild_path="$DOTNET_HOME/buildtools/korebuild/$version" - - { - if [ ! -d "$korebuild_path" ]; then - mkdir -p "$korebuild_path" - local remote_path="$tools_source/korebuild/artifacts/$version/korebuild.$version.zip" - tmpfile="$(mktemp)" - echo -e "${MAGENTA}Downloading KoreBuild ${version}${RESET}" - if __get_remote_file "$remote_path" "$tmpfile"; then - unzip -q -d "$korebuild_path" "$tmpfile" - fi - rm "$tmpfile" || true - fi - - source "$korebuild_path/KoreBuild.sh" - } || { - if [ -d "$korebuild_path" ]; then - echo "Cleaning up after failed installation" - rm -rf "$korebuild_path" || true - fi - return 1 - } -} - -__error() { - echo -e "${RED}$*${RESET}" 1>&2 -} - -__machine_has() { - hash "$1" > /dev/null 2>&1 - return $? -} - -__get_remote_file() { - local remote_path=$1 - local local_path=$2 - - if [[ "$remote_path" != 'http'* ]]; then - cp "$remote_path" "$local_path" - return 0 - fi - - local failed=false - if __machine_has wget; then - wget --tries 10 --quiet -O "$local_path" "$remote_path" || failed=true - else - failed=true - fi - - if [ "$failed" = true ] && __machine_has curl; then - failed=false - curl --retry 10 -sSL -f --create-dirs -o "$local_path" "$remote_path" || failed=true - fi - - if [ "$failed" = true ]; then - __error "Download failed: $remote_path" 1>&2 - return 1 - fi -} - -__read_dom () { local IFS=\> ; read -r -d \< ENTITY CONTENT ;} - -# -# main -# - -while [[ $# -gt 0 ]]; do - case $1 in - -\?|-h|--help) - __usage --no-exit - exit 0 - ;; - -c|--channel|-Channel) - shift - channel="${1:-}" - [ -z "$channel" ] && __usage - ;; - --config-file|-ConfigFile) - shift - config_file="${1:-}" - [ -z "$config_file" ] && __usage - ;; - -d|--dotnet-home|-DotNetHome) - shift - DOTNET_HOME="${1:-}" - [ -z "$DOTNET_HOME" ] && __usage - ;; - --path|-Path) - shift - repo_path="${1:-}" - [ -z "$repo_path" ] && __usage - ;; - -s|--tools-source|-ToolsSource) - shift - tools_source="${1:-}" - [ -z "$tools_source" ] && __usage - ;; - -u|--update|-Update) - update=true - ;; - --verbose|-Verbose) - verbose=true - ;; - --) - shift - break - ;; - *) - break - ;; - esac - shift -done - -if ! __machine_has unzip; then - __error 'Missing required command: unzip' - exit 1 -fi - -if ! __machine_has curl && ! __machine_has wget; then - __error 'Missing required command. Either wget or curl is required.' - exit 1 -fi - -if [ -f "$config_file" ]; then - comment=false - while __read_dom; do - if [ "$comment" = true ]; then [[ $CONTENT == *'-->'* ]] && comment=false ; continue; fi - if [[ $ENTITY == '!--'* ]]; then comment=true; continue; fi - if [ -z "$channel" ] && [[ $ENTITY == "KoreBuildChannel" ]]; then channel=$CONTENT; fi - if [ -z "$tools_source" ] && [[ $ENTITY == "KoreBuildToolsSource" ]]; then tools_source=$CONTENT; fi - done < "$config_file" -fi - -[ -z "$channel" ] && channel='dev' -[ -z "$tools_source" ] && tools_source='https://aspnetcore.blob.core.windows.net/buildtools' - -get_korebuild -install_tools "$tools_source" "$DOTNET_HOME" -invoke_repository_build "$repo_path" "$@" +# Call "sync" between "chmod" and execution to prevent "text file busy" error in Docker (aufs) +chmod +x "$DIR/run.sh"; sync +"$DIR/run.sh" default-build "$@" diff --git a/run.cmd b/run.cmd new file mode 100644 index 0000000000..d52d5c7e68 --- /dev/null +++ b/run.cmd @@ -0,0 +1,2 @@ +@ECHO OFF +PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0run.ps1' %*; exit $LASTEXITCODE" diff --git a/build.ps1 b/run.ps1 similarity index 73% rename from build.ps1 rename to run.ps1 index d5eb4d5cf2..49c2899856 100644 --- a/build.ps1 +++ b/run.ps1 @@ -3,10 +3,13 @@ <# .SYNOPSIS -Build this repository +Executes KoreBuild commands. .DESCRIPTION -Downloads korebuild if required. Then builds the repository. +Downloads korebuild if required. Then executes the KoreBuild command. To see available commands, execute with `-Command help`. + +.PARAMETER Command +The KoreBuild command to run. .PARAMETER Path The folder to build. Defaults to the folder containing this script. @@ -24,31 +27,32 @@ The base url where build tools can be downloaded. Overrides the value from the c Updates KoreBuild to the latest version even if a lock file is present. .PARAMETER ConfigFile -The path to the configuration file that stores values. Defaults to version.xml. +The path to the configuration file that stores values. Defaults to korebuild.json. -.PARAMETER MSBuildArgs -Arguments to be passed to MSBuild +.PARAMETER Arguments +Arguments to be passed to the command .NOTES This function will create a file $PSScriptRoot/korebuild-lock.txt. This lock file can be committed to source, but does not have to be. When the lockfile is not present, KoreBuild will create one using latest available version from $Channel. -The $ConfigFile is expected to be an XML file. It is optional, and the configuration values in it are optional as well. +The $ConfigFile is expected to be an JSON file. It is optional, and the configuration values in it are optional as well. Any options set +in the file are overridden by command line parameters. .EXAMPLE Example config file: -```xml - - - - dev - https://aspnetcore.blob.core.windows.net/buildtools - - +```json +{ + "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/dev/tools/korebuild.schema.json", + "channel": "dev", + "toolsSource": "https://aspnetcore.blob.core.windows.net/buildtools" +} ``` #> [CmdletBinding(PositionalBinding = $false)] param( + [Parameter(Mandatory=$true, Position = 0)] + [string]$Command, [string]$Path = $PSScriptRoot, [Alias('c')] [string]$Channel, @@ -58,9 +62,9 @@ param( [string]$ToolsSource, [Alias('u')] [switch]$Update, - [string]$ConfigFile = (Join-Path $PSScriptRoot 'version.xml'), + [string]$ConfigFile, [Parameter(ValueFromRemainingArguments = $true)] - [string[]]$MSBuildArgs + [string[]]$Arguments ) Set-StrictMode -Version 2 @@ -147,10 +151,20 @@ function Get-RemoteFile([string]$RemotePath, [string]$LocalPath) { # Load configuration or set defaults +$Path = Resolve-Path $Path +if (!$ConfigFile) { $ConfigFile = Join-Path $Path 'korebuild.json' } + if (Test-Path $ConfigFile) { - [xml] $config = Get-Content $ConfigFile - if (!($Channel)) { [string] $Channel = Select-Xml -Xml $config -XPath '/Project/PropertyGroup/KoreBuildChannel' } - if (!($ToolsSource)) { [string] $ToolsSource = Select-Xml -Xml $config -XPath '/Project/PropertyGroup/KoreBuildToolsSource' } + try { + $config = Get-Content -Raw -Encoding UTF8 -Path $ConfigFile | ConvertFrom-Json + if ($config) { + if (!($Channel) -and (Get-Member -Name 'channel' -InputObject $config)) { [string] $Channel = $config.channel } + if (!($ToolsSource) -and (Get-Member -Name 'toolsSource' -InputObject $config)) { [string] $ToolsSource = $config.toolsSource} + } + } catch { + Write-Warning "$ConfigFile could not be read. Its settings will be ignored." + Write-Warning $Error[0] + } } if (!$DotNetHome) { @@ -169,8 +183,8 @@ $korebuildPath = Get-KoreBuild Import-Module -Force -Scope Local (Join-Path $korebuildPath 'KoreBuild.psd1') try { - Install-Tools $ToolsSource $DotNetHome - Invoke-RepositoryBuild $Path @MSBuildArgs + Set-KoreBuildSettings -ToolsSource $ToolsSource -DotNetHome $DotNetHome -RepoPath $Path -ConfigFile $ConfigFile + Invoke-KoreBuildCommand $Command @Arguments } finally { Remove-Module 'KoreBuild' -ErrorAction Ignore diff --git a/run.sh b/run.sh new file mode 100755 index 0000000000..c278423acc --- /dev/null +++ b/run.sh @@ -0,0 +1,223 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# +# variables +# + +RESET="\033[0m" +RED="\033[0;31m" +YELLOW="\033[0;33m" +MAGENTA="\033[0;95m" +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +[ -z "${DOTNET_HOME:-}" ] && DOTNET_HOME="$HOME/.dotnet" +verbose=false +update=false +repo_path="$DIR" +channel='' +tools_source='' + +# +# Functions +# +__usage() { + echo "Usage: $(basename "${BASH_SOURCE[0]}") command [options] [[--] ...]" + echo "" + echo "Arguments:" + echo " command The command to be run." + echo " ... Arguments passed to the command. Variable number of arguments allowed." + echo "" + echo "Options:" + echo " --verbose Show verbose output." + echo " -c|--channel The channel of KoreBuild to download. Overrides the value from the config file.." + echo " --config-file The path to the configuration file that stores values. Defaults to korebuild.json." + echo " -d|--dotnet-home The directory where .NET Core tools will be stored. Defaults to '\$DOTNET_HOME' or '\$HOME/.dotnet." + echo " --path The directory to build. Defaults to the directory containing the script." + echo " -s|--tools-source|-ToolsSource The base url where build tools can be downloaded. Overrides the value from the config file." + echo " -u|--update Update to the latest KoreBuild even if the lock file is present." + echo "" + echo "Description:" + echo " This function will create a file \$DIR/korebuild-lock.txt. This lock file can be committed to source, but does not have to be." + echo " When the lockfile is not present, KoreBuild will create one using latest available version from \$channel." + + if [[ "${1:-}" != '--no-exit' ]]; then + exit 2 + fi +} + +get_korebuild() { + local version + local lock_file="$repo_path/korebuild-lock.txt" + if [ ! -f "$lock_file" ] || [ "$update" = true ]; then + __get_remote_file "$tools_source/korebuild/channels/$channel/latest.txt" "$lock_file" + fi + version="$(grep 'version:*' -m 1 "$lock_file")" + if [[ "$version" == '' ]]; then + __error "Failed to parse version from $lock_file. Expected a line that begins with 'version:'" + return 1 + fi + version="$(echo "${version#version:}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" + local korebuild_path="$DOTNET_HOME/buildtools/korebuild/$version" + + { + if [ ! -d "$korebuild_path" ]; then + mkdir -p "$korebuild_path" + local remote_path="$tools_source/korebuild/artifacts/$version/korebuild.$version.zip" + tmpfile="$(mktemp)" + echo -e "${MAGENTA}Downloading KoreBuild ${version}${RESET}" + if __get_remote_file "$remote_path" "$tmpfile"; then + unzip -q -d "$korebuild_path" "$tmpfile" + fi + rm "$tmpfile" || true + fi + + source "$korebuild_path/KoreBuild.sh" + } || { + if [ -d "$korebuild_path" ]; then + echo "Cleaning up after failed installation" + rm -rf "$korebuild_path" || true + fi + return 1 + } +} + +__error() { + echo -e "${RED}error: $*${RESET}" 1>&2 +} + +__warn() { + echo -e "${YELLOW}warning: $*${RESET}" +} + +__machine_has() { + hash "$1" > /dev/null 2>&1 + return $? +} + +__get_remote_file() { + local remote_path=$1 + local local_path=$2 + + if [[ "$remote_path" != 'http'* ]]; then + cp "$remote_path" "$local_path" + return 0 + fi + + local failed=false + if __machine_has wget; then + wget --tries 10 --quiet -O "$local_path" "$remote_path" || failed=true + else + failed=true + fi + + if [ "$failed" = true ] && __machine_has curl; then + failed=false + curl --retry 10 -sSL -f --create-dirs -o "$local_path" "$remote_path" || failed=true + fi + + if [ "$failed" = true ]; then + __error "Download failed: $remote_path" 1>&2 + return 1 + fi +} + +# +# main +# + +command="${1:-}" +shift + +while [[ $# -gt 0 ]]; do + case $1 in + -\?|-h|--help) + __usage --no-exit + exit 0 + ;; + -c|--channel|-Channel) + shift + channel="${1:-}" + [ -z "$channel" ] && __usage + ;; + --config-file|-ConfigFile) + shift + config_file="${1:-}" + [ -z "$config_file" ] && __usage + if [ ! -f "$config_file" ]; then + __error "Invalid value for --config-file. $config_file does not exist." + exit 1 + fi + ;; + -d|--dotnet-home|-DotNetHome) + shift + DOTNET_HOME="${1:-}" + [ -z "$DOTNET_HOME" ] && __usage + ;; + --path|-Path) + shift + repo_path="${1:-}" + [ -z "$repo_path" ] && __usage + ;; + -s|--tools-source|-ToolsSource) + shift + tools_source="${1:-}" + [ -z "$tools_source" ] && __usage + ;; + -u|--update|-Update) + update=true + ;; + --verbose|-Verbose) + verbose=true + ;; + --) + shift + break + ;; + *) + break + ;; + esac + shift +done + +if ! __machine_has unzip; then + __error 'Missing required command: unzip' + exit 1 +fi + +if ! __machine_has curl && ! __machine_has wget; then + __error 'Missing required command. Either wget or curl is required.' + exit 1 +fi + +[ -z "${config_file:-}" ] && config_file="$repo_path/korebuild.json" +if [ -f "$config_file" ]; then + if __machine_has jq ; then + if jq '.' "$config_file" >/dev/null ; then + config_channel="$(jq -r 'select(.channel!=null) | .channel' "$config_file")" + config_tools_source="$(jq -r 'select(.toolsSource!=null) | .toolsSource' "$config_file")" + else + __warn "$config_file is invalid JSON. Its settings will be ignored." + fi + elif __machine_has python ; then + if python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'))" >/dev/null ; then + config_channel="$(python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['channel'] if 'channel' in obj else '')")" + config_tools_source="$(python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['toolsSource'] if 'toolsSource' in obj else '')")" + else + __warn "$config_file is invalid JSON. Its settings will be ignored." + fi + else + __warn 'Missing required command: jq or pyton. Could not parse the JSON file. Its settings will be ignored.' + fi + + [ ! -z "${config_channel:-}" ] && channel="$config_channel" + [ ! -z "${config_tools_source:-}" ] && tools_source="$config_tools_source" +fi + +[ -z "$channel" ] && channel='dev' +[ -z "$tools_source" ] && tools_source='https://aspnetcore.blob.core.windows.net/buildtools' + +get_korebuild +set_korebuildsettings "$tools_source" "$DOTNET_HOME" "$repo_path" "$config_file" +invoke_korebuild_command "$command" "$@" From e4a412e1644dfea026b20c8625a6f5a636ee1134 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Wed, 20 Sep 2017 13:21:17 -0700 Subject: [PATCH 278/471] Update bootstrappers --- .appveyor.yml | 4 +- build.cmd | 2 +- build.sh | 197 +------------------------------------- run.cmd | 2 + build.ps1 => run.ps1 | 56 +++++++---- run.sh | 223 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 266 insertions(+), 218 deletions(-) create mode 100644 run.cmd rename build.ps1 => run.ps1 (73%) create mode 100755 run.sh diff --git a/.appveyor.yml b/.appveyor.yml index 31efd8196f..46038786c9 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,4 +1,4 @@ -init: +init: - git config --global core.autocrlf true branches: only: @@ -7,7 +7,7 @@ branches: - dev - /^(.*\/)?ci-.*$/ build_script: - - ps: .\build.ps1 + - ps: .\run.ps1 default-build clone_depth: 1 environment: global: diff --git a/build.cmd b/build.cmd index b6c8d24864..c0050bda12 100644 --- a/build.cmd +++ b/build.cmd @@ -1,2 +1,2 @@ @ECHO OFF -PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0build.ps1' %*; exit $LASTEXITCODE" +PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0run.ps1' default-build %*; exit $LASTEXITCODE" diff --git a/build.sh b/build.sh index 11cdbe5504..98a4b22765 100755 --- a/build.sh +++ b/build.sh @@ -1,199 +1,8 @@ #!/usr/bin/env bash set -euo pipefail - -# -# variables -# - -RESET="\033[0m" -RED="\033[0;31m" -MAGENTA="\033[0;95m" DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -[ -z "${DOTNET_HOME:-}" ] && DOTNET_HOME="$HOME/.dotnet" -config_file="$DIR/version.xml" -verbose=false -update=false -repo_path="$DIR" -channel='' -tools_source='' -# -# Functions -# -__usage() { - echo "Usage: $(basename "${BASH_SOURCE[0]}") [options] [[--] ...]" - echo "" - echo "Arguments:" - echo " ... Arguments passed to MSBuild. Variable number of arguments allowed." - echo "" - echo "Options:" - echo " --verbose Show verbose output." - echo " -c|--channel The channel of KoreBuild to download. Overrides the value from the config file.." - echo " --config-file TThe path to the configuration file that stores values. Defaults to version.xml." - echo " -d|--dotnet-home The directory where .NET Core tools will be stored. Defaults to '\$DOTNET_HOME' or '\$HOME/.dotnet." - echo " --path The directory to build. Defaults to the directory containing the script." - echo " -s|--tools-source The base url where build tools can be downloaded. Overrides the value from the config file." - echo " -u|--update Update to the latest KoreBuild even if the lock file is present." - echo "" - echo "Description:" - echo " This function will create a file \$DIR/korebuild-lock.txt. This lock file can be committed to source, but does not have to be." - echo " When the lockfile is not present, KoreBuild will create one using latest available version from \$channel." - - if [[ "${1:-}" != '--no-exit' ]]; then - exit 2 - fi -} - -get_korebuild() { - local version - local lock_file="$repo_path/korebuild-lock.txt" - if [ ! -f "$lock_file" ] || [ "$update" = true ]; then - __get_remote_file "$tools_source/korebuild/channels/$channel/latest.txt" "$lock_file" - fi - version="$(grep 'version:*' -m 1 "$lock_file")" - if [[ "$version" == '' ]]; then - __error "Failed to parse version from $lock_file. Expected a line that begins with 'version:'" - return 1 - fi - version="$(echo "${version#version:}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" - local korebuild_path="$DOTNET_HOME/buildtools/korebuild/$version" - - { - if [ ! -d "$korebuild_path" ]; then - mkdir -p "$korebuild_path" - local remote_path="$tools_source/korebuild/artifacts/$version/korebuild.$version.zip" - tmpfile="$(mktemp)" - echo -e "${MAGENTA}Downloading KoreBuild ${version}${RESET}" - if __get_remote_file "$remote_path" "$tmpfile"; then - unzip -q -d "$korebuild_path" "$tmpfile" - fi - rm "$tmpfile" || true - fi - - source "$korebuild_path/KoreBuild.sh" - } || { - if [ -d "$korebuild_path" ]; then - echo "Cleaning up after failed installation" - rm -rf "$korebuild_path" || true - fi - return 1 - } -} - -__error() { - echo -e "${RED}$*${RESET}" 1>&2 -} - -__machine_has() { - hash "$1" > /dev/null 2>&1 - return $? -} - -__get_remote_file() { - local remote_path=$1 - local local_path=$2 - - if [[ "$remote_path" != 'http'* ]]; then - cp "$remote_path" "$local_path" - return 0 - fi - - local failed=false - if __machine_has wget; then - wget --tries 10 --quiet -O "$local_path" "$remote_path" || failed=true - else - failed=true - fi - - if [ "$failed" = true ] && __machine_has curl; then - failed=false - curl --retry 10 -sSL -f --create-dirs -o "$local_path" "$remote_path" || failed=true - fi - - if [ "$failed" = true ]; then - __error "Download failed: $remote_path" 1>&2 - return 1 - fi -} - -__read_dom () { local IFS=\> ; read -r -d \< ENTITY CONTENT ;} - -# -# main -# - -while [[ $# -gt 0 ]]; do - case $1 in - -\?|-h|--help) - __usage --no-exit - exit 0 - ;; - -c|--channel|-Channel) - shift - channel="${1:-}" - [ -z "$channel" ] && __usage - ;; - --config-file|-ConfigFile) - shift - config_file="${1:-}" - [ -z "$config_file" ] && __usage - ;; - -d|--dotnet-home|-DotNetHome) - shift - DOTNET_HOME="${1:-}" - [ -z "$DOTNET_HOME" ] && __usage - ;; - --path|-Path) - shift - repo_path="${1:-}" - [ -z "$repo_path" ] && __usage - ;; - -s|--tools-source|-ToolsSource) - shift - tools_source="${1:-}" - [ -z "$tools_source" ] && __usage - ;; - -u|--update|-Update) - update=true - ;; - --verbose|-Verbose) - verbose=true - ;; - --) - shift - break - ;; - *) - break - ;; - esac - shift -done - -if ! __machine_has unzip; then - __error 'Missing required command: unzip' - exit 1 -fi - -if ! __machine_has curl && ! __machine_has wget; then - __error 'Missing required command. Either wget or curl is required.' - exit 1 -fi - -if [ -f "$config_file" ]; then - comment=false - while __read_dom; do - if [ "$comment" = true ]; then [[ $CONTENT == *'-->'* ]] && comment=false ; continue; fi - if [[ $ENTITY == '!--'* ]]; then comment=true; continue; fi - if [ -z "$channel" ] && [[ $ENTITY == "KoreBuildChannel" ]]; then channel=$CONTENT; fi - if [ -z "$tools_source" ] && [[ $ENTITY == "KoreBuildToolsSource" ]]; then tools_source=$CONTENT; fi - done < "$config_file" -fi - -[ -z "$channel" ] && channel='dev' -[ -z "$tools_source" ] && tools_source='https://aspnetcore.blob.core.windows.net/buildtools' - -get_korebuild -install_tools "$tools_source" "$DOTNET_HOME" -invoke_repository_build "$repo_path" "$@" +# Call "sync" between "chmod" and execution to prevent "text file busy" error in Docker (aufs) +chmod +x "$DIR/run.sh"; sync +"$DIR/run.sh" default-build "$@" diff --git a/run.cmd b/run.cmd new file mode 100644 index 0000000000..d52d5c7e68 --- /dev/null +++ b/run.cmd @@ -0,0 +1,2 @@ +@ECHO OFF +PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0run.ps1' %*; exit $LASTEXITCODE" diff --git a/build.ps1 b/run.ps1 similarity index 73% rename from build.ps1 rename to run.ps1 index d5eb4d5cf2..49c2899856 100644 --- a/build.ps1 +++ b/run.ps1 @@ -3,10 +3,13 @@ <# .SYNOPSIS -Build this repository +Executes KoreBuild commands. .DESCRIPTION -Downloads korebuild if required. Then builds the repository. +Downloads korebuild if required. Then executes the KoreBuild command. To see available commands, execute with `-Command help`. + +.PARAMETER Command +The KoreBuild command to run. .PARAMETER Path The folder to build. Defaults to the folder containing this script. @@ -24,31 +27,32 @@ The base url where build tools can be downloaded. Overrides the value from the c Updates KoreBuild to the latest version even if a lock file is present. .PARAMETER ConfigFile -The path to the configuration file that stores values. Defaults to version.xml. +The path to the configuration file that stores values. Defaults to korebuild.json. -.PARAMETER MSBuildArgs -Arguments to be passed to MSBuild +.PARAMETER Arguments +Arguments to be passed to the command .NOTES This function will create a file $PSScriptRoot/korebuild-lock.txt. This lock file can be committed to source, but does not have to be. When the lockfile is not present, KoreBuild will create one using latest available version from $Channel. -The $ConfigFile is expected to be an XML file. It is optional, and the configuration values in it are optional as well. +The $ConfigFile is expected to be an JSON file. It is optional, and the configuration values in it are optional as well. Any options set +in the file are overridden by command line parameters. .EXAMPLE Example config file: -```xml - - - - dev - https://aspnetcore.blob.core.windows.net/buildtools - - +```json +{ + "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/dev/tools/korebuild.schema.json", + "channel": "dev", + "toolsSource": "https://aspnetcore.blob.core.windows.net/buildtools" +} ``` #> [CmdletBinding(PositionalBinding = $false)] param( + [Parameter(Mandatory=$true, Position = 0)] + [string]$Command, [string]$Path = $PSScriptRoot, [Alias('c')] [string]$Channel, @@ -58,9 +62,9 @@ param( [string]$ToolsSource, [Alias('u')] [switch]$Update, - [string]$ConfigFile = (Join-Path $PSScriptRoot 'version.xml'), + [string]$ConfigFile, [Parameter(ValueFromRemainingArguments = $true)] - [string[]]$MSBuildArgs + [string[]]$Arguments ) Set-StrictMode -Version 2 @@ -147,10 +151,20 @@ function Get-RemoteFile([string]$RemotePath, [string]$LocalPath) { # Load configuration or set defaults +$Path = Resolve-Path $Path +if (!$ConfigFile) { $ConfigFile = Join-Path $Path 'korebuild.json' } + if (Test-Path $ConfigFile) { - [xml] $config = Get-Content $ConfigFile - if (!($Channel)) { [string] $Channel = Select-Xml -Xml $config -XPath '/Project/PropertyGroup/KoreBuildChannel' } - if (!($ToolsSource)) { [string] $ToolsSource = Select-Xml -Xml $config -XPath '/Project/PropertyGroup/KoreBuildToolsSource' } + try { + $config = Get-Content -Raw -Encoding UTF8 -Path $ConfigFile | ConvertFrom-Json + if ($config) { + if (!($Channel) -and (Get-Member -Name 'channel' -InputObject $config)) { [string] $Channel = $config.channel } + if (!($ToolsSource) -and (Get-Member -Name 'toolsSource' -InputObject $config)) { [string] $ToolsSource = $config.toolsSource} + } + } catch { + Write-Warning "$ConfigFile could not be read. Its settings will be ignored." + Write-Warning $Error[0] + } } if (!$DotNetHome) { @@ -169,8 +183,8 @@ $korebuildPath = Get-KoreBuild Import-Module -Force -Scope Local (Join-Path $korebuildPath 'KoreBuild.psd1') try { - Install-Tools $ToolsSource $DotNetHome - Invoke-RepositoryBuild $Path @MSBuildArgs + Set-KoreBuildSettings -ToolsSource $ToolsSource -DotNetHome $DotNetHome -RepoPath $Path -ConfigFile $ConfigFile + Invoke-KoreBuildCommand $Command @Arguments } finally { Remove-Module 'KoreBuild' -ErrorAction Ignore diff --git a/run.sh b/run.sh new file mode 100755 index 0000000000..c278423acc --- /dev/null +++ b/run.sh @@ -0,0 +1,223 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# +# variables +# + +RESET="\033[0m" +RED="\033[0;31m" +YELLOW="\033[0;33m" +MAGENTA="\033[0;95m" +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +[ -z "${DOTNET_HOME:-}" ] && DOTNET_HOME="$HOME/.dotnet" +verbose=false +update=false +repo_path="$DIR" +channel='' +tools_source='' + +# +# Functions +# +__usage() { + echo "Usage: $(basename "${BASH_SOURCE[0]}") command [options] [[--] ...]" + echo "" + echo "Arguments:" + echo " command The command to be run." + echo " ... Arguments passed to the command. Variable number of arguments allowed." + echo "" + echo "Options:" + echo " --verbose Show verbose output." + echo " -c|--channel The channel of KoreBuild to download. Overrides the value from the config file.." + echo " --config-file The path to the configuration file that stores values. Defaults to korebuild.json." + echo " -d|--dotnet-home The directory where .NET Core tools will be stored. Defaults to '\$DOTNET_HOME' or '\$HOME/.dotnet." + echo " --path The directory to build. Defaults to the directory containing the script." + echo " -s|--tools-source|-ToolsSource The base url where build tools can be downloaded. Overrides the value from the config file." + echo " -u|--update Update to the latest KoreBuild even if the lock file is present." + echo "" + echo "Description:" + echo " This function will create a file \$DIR/korebuild-lock.txt. This lock file can be committed to source, but does not have to be." + echo " When the lockfile is not present, KoreBuild will create one using latest available version from \$channel." + + if [[ "${1:-}" != '--no-exit' ]]; then + exit 2 + fi +} + +get_korebuild() { + local version + local lock_file="$repo_path/korebuild-lock.txt" + if [ ! -f "$lock_file" ] || [ "$update" = true ]; then + __get_remote_file "$tools_source/korebuild/channels/$channel/latest.txt" "$lock_file" + fi + version="$(grep 'version:*' -m 1 "$lock_file")" + if [[ "$version" == '' ]]; then + __error "Failed to parse version from $lock_file. Expected a line that begins with 'version:'" + return 1 + fi + version="$(echo "${version#version:}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" + local korebuild_path="$DOTNET_HOME/buildtools/korebuild/$version" + + { + if [ ! -d "$korebuild_path" ]; then + mkdir -p "$korebuild_path" + local remote_path="$tools_source/korebuild/artifacts/$version/korebuild.$version.zip" + tmpfile="$(mktemp)" + echo -e "${MAGENTA}Downloading KoreBuild ${version}${RESET}" + if __get_remote_file "$remote_path" "$tmpfile"; then + unzip -q -d "$korebuild_path" "$tmpfile" + fi + rm "$tmpfile" || true + fi + + source "$korebuild_path/KoreBuild.sh" + } || { + if [ -d "$korebuild_path" ]; then + echo "Cleaning up after failed installation" + rm -rf "$korebuild_path" || true + fi + return 1 + } +} + +__error() { + echo -e "${RED}error: $*${RESET}" 1>&2 +} + +__warn() { + echo -e "${YELLOW}warning: $*${RESET}" +} + +__machine_has() { + hash "$1" > /dev/null 2>&1 + return $? +} + +__get_remote_file() { + local remote_path=$1 + local local_path=$2 + + if [[ "$remote_path" != 'http'* ]]; then + cp "$remote_path" "$local_path" + return 0 + fi + + local failed=false + if __machine_has wget; then + wget --tries 10 --quiet -O "$local_path" "$remote_path" || failed=true + else + failed=true + fi + + if [ "$failed" = true ] && __machine_has curl; then + failed=false + curl --retry 10 -sSL -f --create-dirs -o "$local_path" "$remote_path" || failed=true + fi + + if [ "$failed" = true ]; then + __error "Download failed: $remote_path" 1>&2 + return 1 + fi +} + +# +# main +# + +command="${1:-}" +shift + +while [[ $# -gt 0 ]]; do + case $1 in + -\?|-h|--help) + __usage --no-exit + exit 0 + ;; + -c|--channel|-Channel) + shift + channel="${1:-}" + [ -z "$channel" ] && __usage + ;; + --config-file|-ConfigFile) + shift + config_file="${1:-}" + [ -z "$config_file" ] && __usage + if [ ! -f "$config_file" ]; then + __error "Invalid value for --config-file. $config_file does not exist." + exit 1 + fi + ;; + -d|--dotnet-home|-DotNetHome) + shift + DOTNET_HOME="${1:-}" + [ -z "$DOTNET_HOME" ] && __usage + ;; + --path|-Path) + shift + repo_path="${1:-}" + [ -z "$repo_path" ] && __usage + ;; + -s|--tools-source|-ToolsSource) + shift + tools_source="${1:-}" + [ -z "$tools_source" ] && __usage + ;; + -u|--update|-Update) + update=true + ;; + --verbose|-Verbose) + verbose=true + ;; + --) + shift + break + ;; + *) + break + ;; + esac + shift +done + +if ! __machine_has unzip; then + __error 'Missing required command: unzip' + exit 1 +fi + +if ! __machine_has curl && ! __machine_has wget; then + __error 'Missing required command. Either wget or curl is required.' + exit 1 +fi + +[ -z "${config_file:-}" ] && config_file="$repo_path/korebuild.json" +if [ -f "$config_file" ]; then + if __machine_has jq ; then + if jq '.' "$config_file" >/dev/null ; then + config_channel="$(jq -r 'select(.channel!=null) | .channel' "$config_file")" + config_tools_source="$(jq -r 'select(.toolsSource!=null) | .toolsSource' "$config_file")" + else + __warn "$config_file is invalid JSON. Its settings will be ignored." + fi + elif __machine_has python ; then + if python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'))" >/dev/null ; then + config_channel="$(python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['channel'] if 'channel' in obj else '')")" + config_tools_source="$(python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['toolsSource'] if 'toolsSource' in obj else '')")" + else + __warn "$config_file is invalid JSON. Its settings will be ignored." + fi + else + __warn 'Missing required command: jq or pyton. Could not parse the JSON file. Its settings will be ignored.' + fi + + [ ! -z "${config_channel:-}" ] && channel="$config_channel" + [ ! -z "${config_tools_source:-}" ] && tools_source="$config_tools_source" +fi + +[ -z "$channel" ] && channel='dev' +[ -z "$tools_source" ] && tools_source='https://aspnetcore.blob.core.windows.net/buildtools' + +get_korebuild +set_korebuildsettings "$tools_source" "$DOTNET_HOME" "$repo_path" "$config_file" +invoke_korebuild_command "$command" "$@" From f1efb29b18d1dece867300f2d6f2115e9fd0e248 Mon Sep 17 00:00:00 2001 From: Jass Bagga Date: Wed, 11 Oct 2017 14:09:35 -0700 Subject: [PATCH 279/471] Use ContractResolver instead of forcing to lower case (#112) Addresses #90 --- .../JsonPatchDocumentOfT.cs | 17 +++++++++-------- .../JsonPatchDocumentGetPathTest.cs | 4 ++-- ...sonPatchDocumentJsonPropertyAttributeTest.cs | 14 +++++++------- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs b/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs index 33e1e5033f..5b9df2b52b 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs @@ -691,12 +691,13 @@ namespace Microsoft.AspNetCore.JsonPatch { 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; + var untypedOp = new Operation + { + op = op.op, + value = op.value, + path = op.path, + from = op.from + }; allOps.Add(untypedOp); } @@ -715,11 +716,11 @@ namespace Microsoft.AspNetCore.JsonPatch path += "/" + position; if (segments.Count == 0) { - return path.ToLowerInvariant(); + return path; } } - return "/" + path.ToLowerInvariant(); + return "/" + path; } private List GetPathSegments(Expression expr) diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentGetPathTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentGetPathTest.cs index dcde4b442d..7d3331231c 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentGetPathTest.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentGetPathTest.cs @@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.JsonPatch var path = patchDocument.GetPath(p => p.SimpleObject.IntegerList, "-"); // Assert - Assert.Equal("/simpleobject/integerlist/-", path); + Assert.Equal("/SimpleObject/IntegerList/-", path); } [Fact] @@ -84,7 +84,7 @@ namespace Microsoft.AspNetCore.JsonPatch var path = patchDocument.GetPath(p => (BaseClass)p.DerivedObject, null); // Assert - Assert.Equal("/derivedobject", path); + Assert.Equal("/DerivedObject", path); } [Fact] diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs index 50ab6a9f5b..882e09ffe7 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs @@ -56,7 +56,7 @@ namespace Microsoft.AspNetCore.JsonPatch // get path var pathToCheck = deserialized.Operations.First().path; - Assert.Equal("/anothername", pathToCheck); + Assert.Equal("/AnotherName", pathToCheck); } [Fact] @@ -73,7 +73,7 @@ namespace Microsoft.AspNetCore.JsonPatch // Assert var pathToCheck = deserialized.Operations.First().path; - Assert.Equal("/stringproperty", pathToCheck); + Assert.Equal("/StringProperty", pathToCheck); } [Fact] @@ -90,7 +90,7 @@ namespace Microsoft.AspNetCore.JsonPatch // Assert var pathToCheck = deserialized.Operations.First().path; - Assert.Equal("/arrayproperty/-", pathToCheck); + Assert.Equal("/ArrayProperty/-", pathToCheck); } [Fact] @@ -209,7 +209,7 @@ namespace Microsoft.AspNetCore.JsonPatch // get path var pathToCheck = deserialized.Operations.First().path; - Assert.Equal("/anothername", pathToCheck); + Assert.Equal("/AnotherName", pathToCheck); } [Fact] @@ -249,9 +249,9 @@ namespace Microsoft.AspNetCore.JsonPatch // Assert var fromPath = deserialized.Operations.First().from; - Assert.Equal("/stringproperty", fromPath); + Assert.Equal("/StringProperty", fromPath); var toPath = deserialized.Operations.First().path; - Assert.Equal("/stringproperty2", toPath); + Assert.Equal("/StringProperty2", toPath); } [Fact] @@ -269,7 +269,7 @@ namespace Microsoft.AspNetCore.JsonPatch // Assert var path = deserialized.Operations.First().path; - Assert.Equal("/socialsecuritynumber", path); + Assert.Equal("/SocialSecurityNumber", path); } private class JsonPropertyWithNoPropertyName From b1ccd606e56843726cbe253736a789c7f9d6fa82 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Mon, 16 Oct 2017 12:49:40 -0700 Subject: [PATCH 280/471] Add RepositoryRoot --- Directory.Build.props | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 74b2f8246d..50b555b540 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,9 +1,10 @@ - + https://github.com/aspnet/HtmlAbstractions git + $(MSBuildThisFileDirectory) $(MSBuildThisFileDirectory)build\Key.snk true true From e245de21fcc6bda605991f5b9963f1a6b9bb6125 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Mon, 16 Oct 2017 12:50:35 -0700 Subject: [PATCH 281/471] Add RepositoryRoot --- Directory.Build.props | 1 + 1 file changed, 1 insertion(+) diff --git a/Directory.Build.props b/Directory.Build.props index 57d9ef7e6a..fb7dfae923 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -5,6 +5,7 @@ Microsoft ASP.NET Core https://github.com/aspnet/JsonPatch git + $(MSBuildThisFileDirectory) $(MSBuildThisFileDirectory)build\Key.snk true true From 8eefe0fdc22793f6573f82c9856abcbe36a7bb80 Mon Sep 17 00:00:00 2001 From: Jass Bagga Date: Thu, 19 Oct 2017 10:46:08 -0700 Subject: [PATCH 282/471] Add Test Operation (#114) Addresses #1 --- .../Adapters/IObjectAdapter.cs | 95 ++++++- .../Adapters/IObjectAdapterWithTest.cs | 32 +++ .../Adapters/ObjectAdapter.cs | 172 +++---------- .../Internal/DictionaryAdapterOfTU.cs | 51 ++++ .../Internal/DynamicObjectAdapter.cs | 32 +++ .../Internal/IAdapter.cs | 7 + .../Internal/ListAdapter.cs | 39 +++ .../Internal/ObjectVisitor.cs | 9 +- .../Internal/PocoAdapter.cs | 39 +++ .../JsonPatchDocument.cs | 18 ++ .../JsonPatchDocumentOfT.cs | 71 ++++++ .../Operations/Operation.cs | 10 +- .../Operations/OperationOfT.cs | 11 +- .../Properties/Resources.Designer.cs | 46 +++- .../Resources.resx | 9 + .../{ => Adapters}/DictionaryAdapterTest.cs | 37 +++ .../DynamicObjectAdapterTest.cs | 37 +++ .../{ => Adapters}/ListAdapterTest.cs | 50 ++++ .../Adapters/PocoAdapterTest.cs | 241 ++++++++++++++++++ ...tegrationTests.cs => DynamicObjectTest.cs} | 42 ++- .../JsonPatchDocumentTest.cs | 36 --- 21 files changed, 895 insertions(+), 189 deletions(-) create mode 100644 src/Microsoft.AspNetCore.JsonPatch/Adapters/IObjectAdapterWithTest.cs rename test/Microsoft.AspNetCore.JsonPatch.Test/{ => Adapters}/DictionaryAdapterTest.cs (88%) rename test/Microsoft.AspNetCore.JsonPatch.Test/{ => Adapters}/DynamicObjectAdapterTest.cs (85%) rename test/Microsoft.AspNetCore.JsonPatch.Test/{ => Adapters}/ListAdapterTest.cs (89%) create mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/Adapters/PocoAdapterTest.cs rename test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/{DynamicObjectIntegrationTests.cs => DynamicObjectTest.cs} (86%) diff --git a/src/Microsoft.AspNetCore.JsonPatch/Adapters/IObjectAdapter.cs b/src/Microsoft.AspNetCore.JsonPatch/Adapters/IObjectAdapter.cs index f699755ed4..e5206bfa0d 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Adapters/IObjectAdapter.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Adapters/IObjectAdapter.cs @@ -8,12 +8,105 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters /// /// Defines the operations that can be performed on a JSON patch document. /// - public interface IObjectAdapter + 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/Microsoft.AspNetCore.JsonPatch/Adapters/IObjectAdapterWithTest.cs b/src/Microsoft.AspNetCore.JsonPatch/Adapters/IObjectAdapterWithTest.cs new file mode 100644 index 0000000000..e1b4ce7950 --- /dev/null +++ b/src/Microsoft.AspNetCore.JsonPatch/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/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs b/src/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs index a30343868a..73095b52c2 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs @@ -9,7 +9,7 @@ using Newtonsoft.Json.Serialization; namespace Microsoft.AspNetCore.JsonPatch.Adapters { /// - public class ObjectAdapter : IObjectAdapter + public class ObjectAdapter : IObjectAdapterWithTest { /// /// Initializes a new instance of . @@ -34,66 +34,6 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters /// public Action LogErrorAction { get; } - /// - /// The "add" operation performs one of the following functions, - /// depending upon what the target location references: - /// - /// o If the target location specifies an array index, a new value is - /// inserted into the array at the specified index. - /// - /// o If the target location specifies an object member that does not - /// already exist, a new member is added to the object. - /// - /// o If the target location specifies an object member that 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" ] } - /// - /// When the operation is applied, the target location MUST reference one - /// of: - /// - /// o The root of the target document - whereupon the specified value - /// becomes the entire content of the target document. - /// - /// o A member to add to an existing object - whereupon the supplied - /// value is added to that object at the indicated location. If the - /// member already exists, it is replaced by the specified value. - /// - /// o An element to add to an existing array - whereupon the supplied - /// value is added to the array at the indicated location. Any - /// elements at or above the specified index are shifted one position - /// to the right. The specified index MUST NOT be greater than the - /// number of elements in the array. If the "-" character is used to - /// index the end of the array (see [RFC6901]), this has the effect of - /// appending the value to the array. - /// - /// Because this operation is designed to add to existing objects and - /// arrays, its target location will often not exist. Although the - /// pointer's error handling algorithm will thus be invoked, this - /// specification defines the error handling behavior for "add" pointers - /// to ignore that error and add the value as specified. - /// - /// However, the object itself or an array containing it does need to - /// exist, and it remains an error for that not to be the case. For - /// example, an "add" with a target location of "/a/b" starting with this - /// document: - /// - /// { "a": { "foo": 1 } } - /// - /// is not an error, because "a" exists, and "b" will be added to its - /// value. It is an error in this document: - /// - /// { "q": { "bar": 2 } } - /// - /// because "a" does not exist. - /// - /// The add operation. - /// Object to apply the operation to. public void Add(Operation operation, object objectToApplyTo) { if (operation == null) @@ -153,29 +93,6 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters } } - /// - /// The "move" operation removes the value at a specified location and - /// adds it to the target location. - /// - /// The operation object MUST contain a "from" member, which is a string - /// containing a JSON Pointer value that 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" } - /// - /// This operation is functionally identical to a "remove" operation on - /// the "from" location, followed immediately by an "add" operation at - /// the target location with the value that was just removed. - /// - /// The "from" location MUST NOT be a proper prefix of the "path" - /// location; i.e., a location cannot be moved into one of its children. - /// - /// The move operation. - /// Object to apply the operation to. public void Move(Operation operation, object objectToApplyTo) { if (operation == null) @@ -202,20 +119,6 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters } } - /// - /// The "remove" operation removes the value at the target location. - /// - /// 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. - /// - /// The remove operation. - /// Object to apply the operation to. public void Remove(Operation operation, object objectToApplyTo) { if (operation == null) @@ -259,26 +162,6 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters } } - /// - /// The "replace" operation replaces the value at the target location - /// with a new value. The operation object MUST contain a "value" member - /// whose content 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 } - /// - /// This operation is functionally identical to a "remove" operation for - /// a value, followed immediately by an "add" operation at the same - /// location with the replacement value. - /// - /// Note: even though it's the same functionally, we do not call remove + add - /// for performance reasons (multiple checks of same requirements). - /// - /// The replace operation. - /// Object to apply the operation to. public void Replace(Operation operation, object objectToApplyTo) { if (operation == null) @@ -310,28 +193,6 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters } } - /// - /// The "copy" operation copies the value at a specified location to the - /// target location. - /// - /// The operation object MUST contain a "from" member, which is a string - /// containing a JSON Pointer value that 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" } - /// - /// This operation is functionally identical to an "add" operation at the - /// target location using the value specified in the "from" member. - /// - /// Note: even though it's the same functionally, we do not call add with - /// the value specified in from for performance reasons (multiple checks of same requirements). - /// - /// The copy operation. - /// Object to apply the operation to. public void Copy(Operation operation, object objectToApplyTo) { if (operation == null) @@ -365,6 +226,37 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters } } + 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); + + 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, diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/DictionaryAdapterOfTU.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/DictionaryAdapterOfTU.cs index 67fd33e231..8a344e24ee 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Internal/DictionaryAdapterOfTU.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Internal/DictionaryAdapterOfTU.cs @@ -2,6 +2,8 @@ // 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 @@ -126,6 +128,55 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal return true; } + public 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 bool TryTraverse( object target, string segment, diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/DynamicObjectAdapter.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/DynamicObjectAdapter.cs index 433326ce53..fb4adeb1f2 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Internal/DynamicObjectAdapter.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Internal/DynamicObjectAdapter.cs @@ -6,6 +6,8 @@ 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; @@ -103,6 +105,36 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal return true; } + public 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 bool TryTraverse( object target, string segment, diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/IAdapter.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/IAdapter.cs index 1866b42ed4..ec28131f7d 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Internal/IAdapter.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Internal/IAdapter.cs @@ -40,5 +40,12 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal IContractResolver contractResolver, object value, out string errorMessage); + + bool TryTest( + object target, + string segment, + IContractResolver contractResolver, + object value, + out string errorMessage); } } diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/ListAdapter.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/ListAdapter.cs index a1c0498e47..d1348fd5c6 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Internal/ListAdapter.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Internal/ListAdapter.cs @@ -5,6 +5,8 @@ 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 @@ -150,6 +152,43 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal return true; } + public 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 bool TryTraverse( object target, string segment, diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/ObjectVisitor.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/ObjectVisitor.cs index 97f108c0a0..8994f0aa52 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Internal/ObjectVisitor.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Internal/ObjectVisitor.cs @@ -3,9 +3,6 @@ using System; using System.Collections; -using System.Collections.Generic; -using System.Dynamic; -using Microsoft.AspNetCore.JsonPatch.Adapters; using Newtonsoft.Json.Serialization; namespace Microsoft.AspNetCore.JsonPatch.Internal @@ -30,7 +27,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal return false; } - adapter = SelectAdapater(target); + 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++) @@ -42,14 +39,14 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal } target = next; - adapter = SelectAdapater(target); + adapter = SelectAdapter(target); } errorMessage = null; return true; } - private IAdapter SelectAdapater(object targetObject) + private IAdapter SelectAdapter(object targetObject) { var jsonContract = _contractResolver.ResolveContract(targetObject.GetType()); diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/PocoAdapter.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/PocoAdapter.cs index eab16a3035..0eee0fc889 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Internal/PocoAdapter.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Internal/PocoAdapter.cs @@ -4,6 +4,8 @@ using System; using System.Linq; using System.Reflection; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using Newtonsoft.Json.Serialization; namespace Microsoft.AspNetCore.JsonPatch.Internal @@ -132,6 +134,43 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal return true; } + public 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 bool TryTraverse( object target, string segment, diff --git a/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocument.cs b/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocument.cs index 4da2bdbe1e..4420e576bf 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocument.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocument.cs @@ -99,6 +99,24 @@ namespace Microsoft.AspNetCore.JsonPatch 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.NormalizePath(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" } diff --git a/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs b/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs index 5b9df2b52b..8ae1430185 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs @@ -247,6 +247,77 @@ namespace Microsoft.AspNetCore.JsonPatch 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" } diff --git a/src/Microsoft.AspNetCore.JsonPatch/Operations/Operation.cs b/src/Microsoft.AspNetCore.JsonPatch/Operations/Operation.cs index ea81b0c668..690ade4776 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Operations/Operation.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Operations/Operation.cs @@ -58,7 +58,15 @@ namespace Microsoft.AspNetCore.JsonPatch.Operations adapter.Copy(this, objectToApplyTo); break; case OperationType.Test: - throw new NotSupportedException(Resources.TestOperationNotSupported); + if (adapter is IObjectAdapterWithTest adapterWithTest) + { + adapterWithTest.Test(this, objectToApplyTo); + break; + } + else + { + throw new NotSupportedException(Resources.TestOperationNotSupported); + } default: break; } diff --git a/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationOfT.cs b/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationOfT.cs index 7189cf8210..bd13528775 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationOfT.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationOfT.cs @@ -74,7 +74,15 @@ namespace Microsoft.AspNetCore.JsonPatch.Operations adapter.Copy(this, objectToApplyTo); break; case OperationType.Test: - throw new JsonPatchException(new JsonPatchError(objectToApplyTo, this, Resources.TestOperationNotSupported)); + 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); @@ -82,6 +90,5 @@ namespace Microsoft.AspNetCore.JsonPatch.Operations break; } } - } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs index 432fab2cbf..cfb8e087d0 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs @@ -81,7 +81,7 @@ namespace Microsoft.AspNetCore.JsonPatch => string.Format(CultureInfo.CurrentCulture, GetString("CannotUpdateProperty"), p0); /// - /// The expression '{0}' is not supported. + /// The expression '{0}' is not supported. Supported expressions include member access and indexer expressions. /// internal static string ExpressionTypeNotSupported { @@ -89,7 +89,7 @@ namespace Microsoft.AspNetCore.JsonPatch } /// - /// The expression '{0}' is not supported. + /// 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); @@ -276,6 +276,48 @@ namespace Microsoft.AspNetCore.JsonPatch 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); diff --git a/src/Microsoft.AspNetCore.JsonPatch/Resources.resx b/src/Microsoft.AspNetCore.JsonPatch/Resources.resx index bf07e4a31e..3763e4a841 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Resources.resx +++ b/src/Microsoft.AspNetCore.JsonPatch/Resources.resx @@ -174,4 +174,13 @@ 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/test/Microsoft.AspNetCore.JsonPatch.Test/DictionaryAdapterTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Adapters/DictionaryAdapterTest.cs similarity index 88% rename from test/Microsoft.AspNetCore.JsonPatch.Test/DictionaryAdapterTest.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/Adapters/DictionaryAdapterTest.cs index cfb99d61ce..d1d2216c2c 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/DictionaryAdapterTest.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Adapters/DictionaryAdapterTest.cs @@ -274,5 +274,42 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal 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(); + dictionary[key] = "James"; + var dictionaryAdapter = new DictionaryAdapter(); + var resolver = new DefaultContractResolver(); + + // Act + var testStatus = dictionaryAdapter.TryTest(dictionary, key, resolver, "James", 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/test/Microsoft.AspNetCore.JsonPatch.Test/DynamicObjectAdapterTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Adapters/DynamicObjectAdapterTest.cs similarity index 85% rename from test/Microsoft.AspNetCore.JsonPatch.Test/DynamicObjectAdapterTest.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/Adapters/DynamicObjectAdapterTest.cs index 18bb7a775c..9ed9a51ed0 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/DynamicObjectAdapterTest.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Adapters/DynamicObjectAdapterTest.cs @@ -227,5 +227,42 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal 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(); + target.NewProperty = "Joana"; + var segment = "NewProperty"; + var resolver = new DefaultContractResolver(); + + // Act + var testStatus = adapter.TryTest(target, segment, resolver, "Joana", out string errorMessage); + + // Assert + Assert.Equal("Joana", 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/test/Microsoft.AspNetCore.JsonPatch.Test/ListAdapterTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Adapters/ListAdapterTest.cs similarity index 89% rename from test/Microsoft.AspNetCore.JsonPatch.Test/ListAdapterTest.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/Adapters/ListAdapterTest.cs index 3c692ea150..25d8ae387b 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/ListAdapterTest.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Adapters/ListAdapterTest.cs @@ -459,5 +459,55 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal 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/test/Microsoft.AspNetCore.JsonPatch.Test/Adapters/PocoAdapterTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Adapters/PocoAdapterTest.cs new file mode 100644 index 0000000000..9a31ea11a8 --- /dev/null +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Adapters/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/test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/DynamicObjectIntegrationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/DynamicObjectTest.cs similarity index 86% rename from test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/DynamicObjectIntegrationTests.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/DynamicObjectTest.cs index 4b5fc96e24..be7738419f 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/DynamicObjectIntegrationTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/DynamicObjectTest.cs @@ -7,7 +7,7 @@ using Xunit; namespace Microsoft.AspNetCore.JsonPatch.Internal { - public class DynamicObjectIntegrationTests + public class DynamicObjectTest { [Fact] public void AddResults_ShouldReplaceExistingPropertyValue_InNestedDynamicObject() @@ -259,5 +259,45 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal // Assert Assert.Equal(new List() { 4, 5, 6 }, dynamicTestObject.IntegerList); } + + [Fact] + public void TestPropertyValue_FromListToNonList_InNestedTypedObject_InDynamicObject() + { + // Arrange + dynamic dynamicTestObject = new DynamicTestObject(); + dynamicTestObject.Nested = new SimpleObject() + { + IntegerList = new List() { 1, 2, 3 } + }; + + var patchDoc = new JsonPatchDocument(); + patchDoc.Test("Nested/IntegerList/1", 2); + + // Act & Assert + patchDoc.ApplyTo(dynamicTestObject); + } + + [Fact] + public void TestPropertyValue_FromListToNonList_InNestedTypedObject_InDynamicObject_ThrowsJsonPatchException_IfTestFails() + { + // Arrange + dynamic dynamicTestObject = new DynamicTestObject(); + dynamicTestObject.Nested = new SimpleObject() + { + IntegerList = new List() { 1, 2, 3 } + }; + + var patchDoc = new JsonPatchDocument(); + patchDoc.Test("Nested/IntegerList/0", 2); + + // Act + var exception = Assert.Throws(() => + { + patchDoc.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/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentTest.cs index 723ef15b64..d754e8da5b 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentTest.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentTest.cs @@ -9,42 +9,6 @@ namespace Microsoft.AspNetCore.JsonPatch.Test { public class JsonPatchDocumentTest { - [Fact] - public void TestOperation_ThrowsException_CallsIntoLogErrorAction() - { - // Arrange - var serialized = "[{\"value\":\"John\",\"path\":\"/Name\",\"op\":\"test\"}]"; - var jsonPatchDocument = JsonConvert.DeserializeObject>(serialized); - var model = new Customer(); - var expectedErrorMessage = "The test operation is not supported."; - string actualErrorMessage = null; - - // Act - jsonPatchDocument.ApplyTo(model, (jsonPatchError) => - { - actualErrorMessage = jsonPatchError.ErrorMessage; - }); - - // Assert - Assert.Equal(expectedErrorMessage, actualErrorMessage); - } - - [Fact] - public void TestOperation_NoLogErrorAction_ThrowsJsonPatchException() - { - // Arrange - var serialized = "[{\"value\":\"John\",\"path\":\"/Name\",\"op\":\"test\"}]"; - var jsonPatchDocument = JsonConvert.DeserializeObject>(serialized); - var model = new Customer(); - var expectedErrorMessage = "The test operation is not supported."; - - // Act - var jsonPatchException = Assert.Throws(() => jsonPatchDocument.ApplyTo(model)); - - // Assert - Assert.Equal(expectedErrorMessage, jsonPatchException.Message); - } - [Fact] public void InvalidOperation_ThrowsException_CallsIntoLogErrorAction() { From e46ba481c8b281b04fbb682ca4db92bee6799d24 Mon Sep 17 00:00:00 2001 From: Jass Bagga Date: Thu, 19 Oct 2017 13:32:04 -0700 Subject: [PATCH 283/471] Throw JsonSerializationException from converters (#116) --- .../Converters/JsonPatchDocumentConverter.cs | 2 +- .../TypedJsonPatchDocumentConverter.cs | 3 +-- .../Properties/Resources.Designer.cs | 8 +++---- .../Resources.resx | 2 +- .../ObjectAdapterTests.cs | 24 +++++++++++++++---- 5 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/Microsoft.AspNetCore.JsonPatch/Converters/JsonPatchDocumentConverter.cs b/src/Microsoft.AspNetCore.JsonPatch/Converters/JsonPatchDocumentConverter.cs index e93e84e12a..aed9c48474 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Converters/JsonPatchDocumentConverter.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Converters/JsonPatchDocumentConverter.cs @@ -57,7 +57,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Converters } catch (Exception ex) { - throw new JsonPatchException(Resources.FormatInvalidJsonPatchDocument(objectType.Name), ex); + throw new JsonSerializationException(Resources.InvalidJsonPatchDocument, ex); } } diff --git a/src/Microsoft.AspNetCore.JsonPatch/Converters/TypedJsonPatchDocumentConverter.cs b/src/Microsoft.AspNetCore.JsonPatch/Converters/TypedJsonPatchDocumentConverter.cs index 292a3be556..fd779ba4ee 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Converters/TypedJsonPatchDocumentConverter.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Converters/TypedJsonPatchDocumentConverter.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Reflection; -using Microsoft.AspNetCore.JsonPatch.Exceptions; using Microsoft.AspNetCore.JsonPatch.Operations; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -58,7 +57,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Converters } catch (Exception ex) { - throw new JsonPatchException(Resources.FormatInvalidJsonPatchDocument(objectType.Name), ex); + throw new JsonSerializationException(Resources.InvalidJsonPatchDocument, ex); } } } diff --git a/src/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs index cfb8e087d0..c314465238 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs @@ -123,7 +123,7 @@ namespace Microsoft.AspNetCore.JsonPatch => string.Format(CultureInfo.CurrentCulture, GetString("InvalidIndexValue"), p0); /// - /// The type '{0}' was malformed and could not be parsed. + /// The JSON patch document was malformed and could not be parsed. /// internal static string InvalidJsonPatchDocument { @@ -131,10 +131,10 @@ namespace Microsoft.AspNetCore.JsonPatch } /// - /// The type '{0}' was malformed and could not be parsed. + /// The JSON patch document was malformed and could not be parsed. /// - internal static string FormatInvalidJsonPatchDocument(object p0) - => string.Format(CultureInfo.CurrentCulture, GetString("InvalidJsonPatchDocument"), p0); + internal static string FormatInvalidJsonPatchDocument() + => GetString("InvalidJsonPatchDocument"); /// /// Invalid JsonPatch operation '{0}'. diff --git a/src/Microsoft.AspNetCore.JsonPatch/Resources.resx b/src/Microsoft.AspNetCore.JsonPatch/Resources.resx index 3763e4a841..87cc399c62 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Resources.resx +++ b/src/Microsoft.AspNetCore.JsonPatch/Resources.resx @@ -142,7 +142,7 @@ The path segment '{0}' is invalid for an array index. - The type '{0}' was malformed and could not be parsed. + The JSON patch document was malformed and could not be parsed. Invalid JsonPatch operation '{0}'. diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs index d35f8eb4e9..c1d005e897 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs @@ -725,7 +725,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters } [Fact] - public void DeserializationMustWorkWithoutEnvelope() + public void Deserialization_Successful_ForValidJsonPatchDocument() { // Arrange var doc = new SimpleObject() @@ -756,19 +756,35 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters } [Fact] - public void DeserializationMustFailWithEnvelope() + public void Deserialization_Fails_ForInvalidJsonPatchDocument() { // Arrange var serialized = "{\"Operations\": [{ \"op\": \"replace\", \"path\": \"/title\", \"value\": \"New Title\"}]}"; // Act & Assert - var exception = Assert.Throws(() => + var exception = Assert.Throws(() => + { + var deserialized + = JsonConvert.DeserializeObject(serialized); + }); + + 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 & Assert + var exception = Assert.Throws(() => { var deserialized = JsonConvert.DeserializeObject>(serialized); }); - Assert.Equal("The type 'JsonPatchDocument`1' was malformed and could not be parsed.", exception.Message); + Assert.Equal("The JSON patch document was malformed and could not be parsed.", exception.Message); } [Fact] From e453fafad52649daff689c24fa2374a143f43654 Mon Sep 17 00:00:00 2001 From: Jass Bagga Date: Thu, 26 Oct 2017 12:51:06 -0700 Subject: [PATCH 284/471] Reorganize tests (#117) Addresses #105 --- .../CustomNamingStrategyTests.cs | 153 ++ .../Dynamic/AddOperationTests.cs | 553 ---- .../Dynamic/AddTypedOperationTests.cs | 121 - .../Dynamic/CopyOperationTests.cs | 245 -- .../Dynamic/CopyTypedOperationTests.cs | 268 -- .../Dynamic/CustomNamingStrategyTests.cs | 154 -- .../Dynamic/InheritedObject.cs | 10 - .../Dynamic/MoveOperationTests.cs | 333 --- .../Dynamic/MoveTypedOperationTests.cs | 138 - .../Dynamic/PatchDocumentTests.cs | 95 - .../Dynamic/RemoveOperationTests.cs | 313 --- .../Dynamic/RemoveTypedOperationTests.cs | 244 -- .../Dynamic/ReplaceOperationTests.cs | 206 -- .../Dynamic/ReplaceTypedOperationTests.cs | 191 -- .../Dynamic/SimpleObject.cs | 21 - .../Dynamic/SimpleObjectWithNestedObject.cs | 22 - .../AnonymousObjectIntegrationTest.cs | 190 ++ .../DictionaryIntegrationTest.cs | 319 +++ ...est.cs => DynamicObjectIntegrationTest.cs} | 141 +- .../ExpandoObjectIntegrationTest.cs | 327 +++ .../IntegrationTests/ListIntegrationTest.cs | 366 +++ .../NestedObjectIntegrationTest.cs | 342 +++ .../SimpleObjectIntegrationTest.cs | 128 + .../DictionaryAdapterTest.cs | 34 +- .../DynamicObjectAdapterTest.cs | 12 +- .../{Adapters => Internal}/ListAdapterTest.cs | 40 +- .../{ => Internal}/ObjectVisitorTest.cs | 10 +- .../{ => Internal}/ParsedPathTests.cs | 7 +- .../{Adapters => Internal}/PocoAdapterTest.cs | 0 .../JsonPatchDocumentGetPathTest.cs | 4 +- ...nPatchDocumentJsonPropertyAttributeTest.cs | 271 +- .../JsonPatchDocumentTest.cs | 171 +- .../JsonPropertyComplexNameObject.cs | 16 - .../JsonPropertyObject.cs | 13 - .../JsonPropertyWithAnotherNameObject.cs | 10 - .../JsonPropertyWithInheritanceObject.cs | 15 - .../NestedObject.cs | 10 - .../NestedObjectTests.cs | 2272 ---------------- .../ObjectAdapterTests.cs | 2331 ----------------- ...mpleObjectWithNestedObjectWithNullCheck.cs | 15 - .../SimpleObjectWithNullCheck.cs | 30 - .../TestObjectModels/Customer.cs | 17 + .../DynamicTestObject.cs | 2 +- .../{ => TestObjectModels}/InheritedObject.cs | 0 .../NestedObject.cs | 4 +- .../{ => TestObjectModels}/SimpleObject.cs | 2 + .../SimpleObjectWithNestedObject.cs | 0 47 files changed, 2091 insertions(+), 8075 deletions(-) create mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/CustomNamingStrategyTests.cs delete mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddOperationTests.cs delete mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddTypedOperationTests.cs delete mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CopyOperationTests.cs delete mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CopyTypedOperationTests.cs delete mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CustomNamingStrategyTests.cs delete mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/InheritedObject.cs delete mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveOperationTests.cs delete mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveTypedOperationTests.cs delete mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/PatchDocumentTests.cs delete mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveOperationTests.cs delete mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveTypedOperationTests.cs delete mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceOperationTests.cs delete mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceTypedOperationTests.cs delete mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/SimpleObject.cs delete mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/SimpleObjectWithNestedObject.cs create mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/AnonymousObjectIntegrationTest.cs create mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/DictionaryIntegrationTest.cs rename test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/{DynamicObjectTest.cs => DynamicObjectIntegrationTest.cs} (58%) create mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/ExpandoObjectIntegrationTest.cs create mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/ListIntegrationTest.cs create mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/NestedObjectIntegrationTest.cs create mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/SimpleObjectIntegrationTest.cs rename test/Microsoft.AspNetCore.JsonPatch.Test/{Adapters => Internal}/DictionaryAdapterTest.cs (91%) rename test/Microsoft.AspNetCore.JsonPatch.Test/{Adapters => Internal}/DynamicObjectAdapterTest.cs (97%) rename test/Microsoft.AspNetCore.JsonPatch.Test/{Adapters => Internal}/ListAdapterTest.cs (91%) rename test/Microsoft.AspNetCore.JsonPatch.Test/{ => Internal}/ObjectVisitorTest.cs (95%) rename test/Microsoft.AspNetCore.JsonPatch.Test/{ => Internal}/ParsedPathTests.cs (91%) rename test/Microsoft.AspNetCore.JsonPatch.Test/{Adapters => Internal}/PocoAdapterTest.cs (100%) delete mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyComplexNameObject.cs delete mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyObject.cs delete mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyWithAnotherNameObject.cs delete mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyWithInheritanceObject.cs delete mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/NestedObject.cs delete mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/NestedObjectTests.cs delete mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs delete mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/SimpleObjectWithNestedObjectWithNullCheck.cs delete mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/SimpleObjectWithNullCheck.cs create mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/TestObjectModels/Customer.cs rename test/Microsoft.AspNetCore.JsonPatch.Test/{ => TestObjectModels}/DynamicTestObject.cs (98%) rename test/Microsoft.AspNetCore.JsonPatch.Test/{ => TestObjectModels}/InheritedObject.cs (100%) rename test/Microsoft.AspNetCore.JsonPatch.Test/{Dynamic => TestObjectModels}/NestedObject.cs (85%) rename test/Microsoft.AspNetCore.JsonPatch.Test/{ => TestObjectModels}/SimpleObject.cs (86%) rename test/Microsoft.AspNetCore.JsonPatch.Test/{ => TestObjectModels}/SimpleObjectWithNestedObject.cs (100%) diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/CustomNamingStrategyTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/CustomNamingStrategyTests.cs new file mode 100644 index 0000000000..ebc45874d9 --- /dev/null +++ b/test/Microsoft.AspNetCore.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/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddOperationTests.cs deleted file mode 100644 index 493444066b..0000000000 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddOperationTests.cs +++ /dev/null @@ -1,553 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Dynamic; -using Microsoft.AspNetCore.JsonPatch.Exceptions; -using Newtonsoft.Json; -using Xunit; - -namespace Microsoft.AspNetCore.JsonPatch.Internal -{ - public class AddOperationTests - { - [Fact] - public void AddNewPropertyShouldFailIfRootIsNotAnExpandoObject() - { - dynamic doc = new - { - Test = 1 - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("NewInt", 1); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - var exception = Assert.Throws(() => - { - deserialized.ApplyTo(doc); - }); - Assert.Equal( - string.Format("The target location specified by path segment '{0}' was not found.", "NewInt"), - exception.Message); - } - - [Fact] - public void AddNewProperty() - { - dynamic obj = new ExpandoObject(); - obj.Test = 1; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("NewInt", 1); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(obj); - - Assert.Equal(1, obj.NewInt); - Assert.Equal(1, obj.Test); - } - - [Fact] - public void AddNewPropertyToNestedAnonymousObjectShouldFail() - { - dynamic doc = new - { - Test = 1, - nested = new { } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("Nested/NewInt", 1); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - var exception = Assert.Throws(() => - { - deserialized.ApplyTo(doc); - }); - Assert.Equal( - string.Format("The target location specified by path segment '{0}' was not found.", "NewInt"), - exception.Message); - } - - [Fact] - public void AddNewPropertyToTypedObjectShouldFail() - { - dynamic doc = new - { - Test = 1, - nested = new NestedObject() - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("Nested/NewInt", 1); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - var exception = Assert.Throws(() => - { - deserialized.ApplyTo(doc); - }); - Assert.Equal( - string.Format("The target location specified by path segment '{0}' was not found.", "NewInt"), - exception.Message); - } - - [Fact] - public void AddToExistingPropertyOnNestedObject() - { - dynamic doc = new - { - Test = 1, - nested = new NestedObject() - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("Nested/StringProperty", "A"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal("A", doc.nested.StringProperty); - Assert.Equal(1, doc.Test); - } - - [Fact] - public void AddNewPropertyToExpandoOject() - { - dynamic doc = new - { - Test = 1, - nested = new ExpandoObject() - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("Nested/NewInt", 1); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal(1, doc.nested.NewInt); - Assert.Equal(1, doc.Test); - } - - [Fact] - public void AddNewPropertyToExpandoOjectInTypedObject() - { - var doc = new NestedObject() - { - DynamicProperty = new ExpandoObject() - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("DynamicProperty/NewInt", 1); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal(1, doc.DynamicProperty.NewInt); - } - - [Fact] - public void AddNewPropertyToTypedObjectInExpandoObject() - { - dynamic dynamicProperty = new ExpandoObject(); - dynamicProperty.StringProperty = "A"; - - var doc = new NestedObject() - { - DynamicProperty = dynamicProperty - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("DynamicProperty/StringProperty", "B"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal("B", doc.DynamicProperty.StringProperty); - } - - [Fact] - public void AddNewPropertyToAnonymousObjectShouldFail() - { - dynamic doc = new - { - Test = 1 - }; - - dynamic valueToAdd = new { IntValue = 1, StringValue = "test", GuidValue = Guid.NewGuid() }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("ComplexProperty", valueToAdd); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - var exception = Assert.Throws(() => - { - deserialized.ApplyTo(doc); - }); - Assert.Equal( - string.Format("The target location specified by path segment '{0}' was not found.", "ComplexProperty"), - exception.Message); - } - - [Fact] - public void AddResultsReplaceShouldFailOnAnonymousDueToNoSetter() - { - var doc = new - { - StringProperty = "A" - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("StringProperty", "B"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - var exception = Assert.Throws(() => - { - deserialized.ApplyTo(doc); - }); - Assert.Equal( - string.Format("The property at path '{0}' could not be updated.", "StringProperty"), - exception.Message); - } - - [Fact] - public void AddResultsShouldReplace() - { - dynamic doc = new ExpandoObject(); - doc.StringProperty = "A"; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("StringProperty", "B"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal("B", doc.StringProperty); - } - - [Fact] - public void AddResultsShouldReplaceInNested() - { - dynamic doc = new ExpandoObject(); - doc.InBetweenFirst = new ExpandoObject(); - doc.InBetweenFirst.InBetweenSecond = new ExpandoObject(); - doc.InBetweenFirst.InBetweenSecond.StringProperty = "A"; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("/InBetweenFirst/InBetweenSecond/StringProperty", "B"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal("B", doc.InBetweenFirst.InBetweenSecond.StringProperty); - } - - [Fact] - public void AddResultsShouldReplaceInNestedInDynamic() - { - dynamic doc = new ExpandoObject(); - doc.Nested = new NestedObject(); - doc.Nested.DynamicProperty = new ExpandoObject(); - doc.Nested.DynamicProperty.InBetweenFirst = new ExpandoObject(); - doc.Nested.DynamicProperty.InBetweenFirst.InBetweenSecond = new ExpandoObject(); - doc.Nested.DynamicProperty.InBetweenFirst.InBetweenSecond.StringProperty = "A"; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("/Nested/DynamicProperty/InBetweenFirst/InBetweenSecond/StringProperty", "B"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal("B", doc.Nested.DynamicProperty.InBetweenFirst.InBetweenSecond.StringProperty); - } - - [Fact] - public void ShouldNotBeAbleToAddToNonExistingPropertyThatIsNotTheRoot() - { - //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. - - var doc = new NestedObject() - { - DynamicProperty = new ExpandoObject() - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("DynamicProperty/OtherProperty/IntProperty", 1); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - var exception = Assert.Throws(() => - { - deserialized.ApplyTo(doc); - }); - Assert.Equal( - string.Format( - "For operation '{0}', the target location specified by path '{1}' was not found.", - "add", - "/DynamicProperty/OtherProperty/IntProperty"), - exception.Message); - } - - [Fact] - public void ShouldNotBeAbleToAddToNonExistingPropertyInNestedPropertyThatIsNotTheRoot() - { - //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. - - var doc = new - { - Foo = "bar" - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("baz/bat", "qux"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - var exception = Assert.Throws(() => - { - deserialized.ApplyTo(doc); - }); - Assert.Equal( - string.Format("The target location specified by path segment '{0}' was not found.", "baz"), - exception.Message); - } - - [Fact] - public void ShouldNotReplacePropertyWithDifferentCase() - { - dynamic doc = new ExpandoObject(); - doc.StringProperty = "A"; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("stringproperty", "B"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal("A", doc.StringProperty); - Assert.Equal("B", doc.stringproperty); - } - - [Fact] - public void AddToList() - { - var doc = new - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("IntegerList/0", 4); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 4, 1, 2, 3 }, doc.IntegerList); - } - - [Fact] - public void AddToListNegativePosition() - { - dynamic doc = new ExpandoObject(); - doc.IntegerList = new List() { 1, 2, 3 }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("IntegerList/-1", 4); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - var exception = Assert.Throws(() => - { - deserialized.ApplyTo(doc); - }); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), - exception.Message); - } - - [Fact] - public void ShouldAddToListWithDifferentCase() - { - var doc = new - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("integerlist/0", 4); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 4, 1, 2, 3 }, doc.IntegerList); - } - - [Fact] - public void AddToListInvalidPositionTooLarge() - { - var doc = new - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("IntegerList/4", 4); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - var exception = Assert.Throws(() => - { - deserialized.ApplyTo(doc); - }); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "4"), - exception.Message); - } - - [Fact] - public void AddToListAtBeginning() - { - var doc = new - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("IntegerList/0", 4); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 4, 1, 2, 3 }, doc.IntegerList); - } - - [Fact] - public void AddToListInvalidPositionTooSmall() - { - var doc = new - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("IntegerList/-1", 4); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - var exception = Assert.Throws(() => - { - deserialized.ApplyTo(doc); - }); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), - exception.Message); - } - - [Fact] - public void AddToListAppend() - { - var doc = new - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("IntegerList/-", 4); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 1, 2, 3, 4 }, doc.IntegerList); - } - } -} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddTypedOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddTypedOperationTests.cs deleted file mode 100644 index b2eb4d3a3c..0000000000 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddTypedOperationTests.cs +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Collections.Generic; -using Microsoft.AspNetCore.JsonPatch.Exceptions; -using Newtonsoft.Json; -using Xunit; - -namespace Microsoft.AspNetCore.JsonPatch.Internal -{ - public class AddTypedOperationTests - { - [Fact] - public void AddToListNegativePosition() - { - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("IntegerList/-1", 4); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - var exception = Assert.Throws(() => - { - deserialized.ApplyTo(doc); - }); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), - exception.Message); - } - - [Fact] - public void AddToListInList() - { - var doc = new SimpleObjectWithNestedObject() - { - ListOfSimpleObject = new List() - { - new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("ListOfSimpleObject/0/IntegerList/0", 4); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - Assert.Equal(new List() { 4, 1, 2, 3 }, doc.ListOfSimpleObject[0].IntegerList); - } - - [Fact] - public void AddToListInListInvalidPositionTooSmall() - { - var doc = new SimpleObjectWithNestedObject() - { - ListOfSimpleObject = new List() - { - new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("ListOfSimpleObject/-1/IntegerList/0", 4); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - var exception = Assert.Throws(() => - { - deserialized.ApplyTo(doc); - }); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), - exception.Message); - } - - [Fact] - public void AddToListInListInvalidPositionTooLarge() - { - var doc = new SimpleObjectWithNestedObject() - { - ListOfSimpleObject = new List() - { - new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - } - }; - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("ListOfSimpleObject/20/IntegerList/0", 4); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - var exception = Assert.Throws(() => - { - deserialized.ApplyTo(doc); - }); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "20"), - exception.Message); - } - } -} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CopyOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CopyOperationTests.cs deleted file mode 100644 index b2faff25a0..0000000000 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CopyOperationTests.cs +++ /dev/null @@ -1,245 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Collections.Generic; -using System.Dynamic; -using Newtonsoft.Json; -using Xunit; - -namespace Microsoft.AspNetCore.JsonPatch.Internal -{ - public class CopyOperationTests - { - [Fact] - public void Copy() - { - dynamic doc = new ExpandoObject(); - - doc.StringProperty = "A"; - doc.AnotherStringProperty = "B"; - - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy("StringProperty", "AnotherStringProperty"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - deserialized.ApplyTo(doc); - - Assert.Equal("A", doc.AnotherStringProperty); - } - - [Fact] - public void CopyInList() - { - dynamic doc = new ExpandoObject(); - doc.IntegerList = new List() { 1, 2, 3 }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy("IntegerList/0", "IntegerList/1"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 1, 1, 2, 3 }, doc.IntegerList); - } - - [Fact] - public void CopyFromListToEndOfList() - { - dynamic doc = new ExpandoObject(); - doc.IntegerList = new List() { 1, 2, 3 }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy("IntegerList/0", "IntegerList/-"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 1, 2, 3, 1 }, doc.IntegerList); - } - - [Fact] - public void CopyFromListToNonList() - { - dynamic doc = new ExpandoObject(); - doc.IntegerList = new List() { 1, 2, 3 }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy("IntegerList/0", "IntegerValue"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal(1, doc.IntegerValue); - } - - [Fact] - public void CopyFromNonListToList() - { - dynamic doc = new ExpandoObject(); - doc.IntegerValue = 5; - doc.IntegerList = new List() { 1, 2, 3 }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy("IntegerValue", "IntegerList/0"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 5, 1, 2, 3 }, doc.IntegerList); - } - - [Fact] - public void CopyToEndOfList() - { - dynamic doc = new ExpandoObject(); - doc.IntegerValue = 5; - doc.IntegerList = new List() { 1, 2, 3 }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy("IntegerValue", "IntegerList/-"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 1, 2, 3, 5 }, doc.IntegerList); - } - - [Fact] - public void NestedCopy() - { - dynamic doc = new ExpandoObject(); - doc.SimpleObject = new SimpleObject() - { - StringProperty = "A", - AnotherStringProperty = "B" - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy("SimpleObject/StringProperty", "SimpleObject/AnotherStringProperty"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal("A", doc.SimpleObject.AnotherStringProperty); - } - - [Fact] - public void NestedCopyInList() - { - dynamic doc = new ExpandoObject(); - doc.SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy("SimpleObject/IntegerList/0", "SimpleObject/IntegerList/1"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 1, 1, 2, 3 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void NestedCopyFromListToEndOfList() - { - dynamic doc = new ExpandoObject(); - doc.SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy("SimpleObject/IntegerList/0", "SimpleObject/IntegerList/-"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 1, 2, 3, 1 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void NestedCopyFromListToNonList() - { - dynamic doc = new ExpandoObject(); - doc.SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy("SimpleObject/IntegerList/0", "SimpleObject/IntegerValue"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - deserialized.ApplyTo(doc); - - Assert.Equal(1, doc.SimpleObject.IntegerValue); - } - - [Fact] - public void NestedCopyFromNonListToList() - { - dynamic doc = new ExpandoObject(); - doc.SimpleObject = new SimpleObject() - { - IntegerValue = 5, - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy("SimpleObject/IntegerValue", "SimpleObject/IntegerList/0"); - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 5, 1, 2, 3 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void NestedCopyToEndOfList() - { - dynamic doc = new ExpandoObject(); - doc.SimpleObject = new SimpleObject() - { - IntegerValue = 5, - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy("SimpleObject/IntegerValue", "SimpleObject/IntegerList/-"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 1, 2, 3, 5 }, doc.SimpleObject.IntegerList); - } - } -} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CopyTypedOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CopyTypedOperationTests.cs deleted file mode 100644 index d0b0847c71..0000000000 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CopyTypedOperationTests.cs +++ /dev/null @@ -1,268 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Collections.Generic; -using Newtonsoft.Json; -using Xunit; - -namespace Microsoft.AspNetCore.JsonPatch.Internal -{ - public class CopyTypedOperationTests - { - [Fact] - public void Copy() - { - var doc = new SimpleObject() - { - StringProperty = "A", - AnotherStringProperty = "B" - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy("StringProperty", "AnotherStringProperty"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - deserialized.ApplyTo(doc); - - Assert.Equal("A", doc.AnotherStringProperty); - } - - [Fact] - public void CopyInList() - { - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy("IntegerList/0", "IntegerList/1"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 1, 1, 2, 3 }, doc.IntegerList); - } - - [Fact] - public void CopyFromListToEndOfList() - { - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy("IntegerList/0", "IntegerList/-"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 1, 2, 3, 1 }, doc.IntegerList); - } - - [Fact] - public void CopyFromListToNonList() - { - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy("IntegerList/0", "IntegerValue"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal(1, doc.IntegerValue); - } - - [Fact] - public void CopyFromNonListToList() - { - var doc = new SimpleObject() - { - IntegerValue = 5, - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy("IntegerValue", "IntegerList/0"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 5, 1, 2, 3 }, doc.IntegerList); - } - - [Fact] - public void CopyToEndOfList() - { - var doc = new SimpleObject() - { - IntegerValue = 5, - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy("IntegerValue", "IntegerList/-"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 1, 2, 3, 5 }, doc.IntegerList); - } - - [Fact] - public void NestedCopy() - { - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - StringProperty = "A", - AnotherStringProperty = "B" - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy("SimpleObject/StringProperty", "SimpleObject/AnotherStringProperty"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal("A", doc.SimpleObject.AnotherStringProperty); - } - - [Fact] - public void NestedCopyInList() - { - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy("SimpleObject/IntegerList/0", "SimpleObject/IntegerList/1"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 1, 1, 2, 3 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void NestedCopyFromListToEndOfList() - { - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy("SimpleObject/IntegerList/0", "SimpleObject/IntegerList/-"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 1, 2, 3, 1 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void NestedCopyFromListToNonList() - { - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy("SimpleObject/IntegerList/0", "SimpleObject/IntegerValue"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - deserialized.ApplyTo(doc); - - Assert.Equal(1, doc.SimpleObject.IntegerValue); - } - - [Fact] - public void NestedCopyFromNonListToList() - { - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerValue = 5, - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy("SimpleObject/IntegerValue", "SimpleObject/IntegerList/0"); - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 5, 1, 2, 3 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void NestedCopyToEndOfList() - { - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerValue = 5, - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy("SimpleObject/IntegerValue", "SimpleObject/IntegerList/-"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 1, 2, 3, 5 }, doc.SimpleObject.IntegerList); - } - } -} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CustomNamingStrategyTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CustomNamingStrategyTests.cs deleted file mode 100644 index b829b81902..0000000000 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/CustomNamingStrategyTests.cs +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Collections.Generic; -using System.Dynamic; -using Newtonsoft.Json.Serialization; -using Xunit; - -namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic -{ - public class CustomNamingStrategyTests - { - [Fact] - public void AddProperty_ToExpandoObject_WithCustomNamingStrategy() - { - // Arrange - var contractResolver = new DefaultContractResolver - { - NamingStrategy = new TestNamingStrategy() - }; - - dynamic obj = new ExpandoObject(); - obj.Test = 1; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("NewInt", 1); - patchDoc.ContractResolver = contractResolver; - - // Act - patchDoc.ApplyTo(obj); - - // Assert - Assert.Equal(1, obj.customNewInt); - Assert.Equal(1, obj.Test); - } - - [Fact] - public void CopyPropertyValue_ForExpandoObject_WithCustomNamingStrategy() - { - // Arrange - var contractResolver = new DefaultContractResolver - { - NamingStrategy = new TestNamingStrategy() - }; - - dynamic obj = new ExpandoObject(); - obj.customStringProperty = "A"; - obj.customAnotherStringProperty = "B"; - - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy("StringProperty", "AnotherStringProperty"); - patchDoc.ContractResolver = contractResolver; - - // Act - patchDoc.ApplyTo(obj); - - // Assert - Assert.Equal("A", obj.customAnotherStringProperty); - } - - [Fact] - public void MovePropertyValue_ForExpandoObject_WithCustomNamingStrategy() - { - // Arrange - var contractResolver = new DefaultContractResolver - { - NamingStrategy = new TestNamingStrategy() - }; - - dynamic obj = new ExpandoObject(); - obj.customStringProperty = "A"; - obj.customAnotherStringProperty = "B"; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move("StringProperty", "AnotherStringProperty"); - patchDoc.ContractResolver = contractResolver; - - // Act - patchDoc.ApplyTo(obj); - var cont = obj as IDictionary; - cont.TryGetValue("customStringProperty", out var valueFromDictionary); - - // Assert - Assert.Equal("A", obj.customAnotherStringProperty); - Assert.Null(valueFromDictionary); - } - - [Fact] - public void RemoveProperty_FromExpandoObject_WithCustomNamingStrategy() - { - // Arrange - var contractResolver = new DefaultContractResolver - { - NamingStrategy = new TestNamingStrategy() - }; - - dynamic obj = new ExpandoObject(); - obj.customTest = 1; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove("Test"); - patchDoc.ContractResolver = contractResolver; - - // Act - patchDoc.ApplyTo(obj); - var cont = obj as IDictionary; - cont.TryGetValue("customTest", out var valueFromDictionary); - - // Assert - Assert.Null(valueFromDictionary); - } - - [Fact] - public void ReplacePropertyValue_ForExpandoObject_WithCustomNamingStrategy() - { - // Arrange - var contractResolver = new DefaultContractResolver - { - NamingStrategy = new TestNamingStrategy() - }; - - dynamic obj = new ExpandoObject(); - obj.customTest = 1; - - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace("Test", 2); - patchDoc.ContractResolver = contractResolver; - - // Act - patchDoc.ApplyTo(obj); - - // Assert - Assert.Equal(2, obj.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/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/InheritedObject.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/InheritedObject.cs deleted file mode 100644 index 29424d591e..0000000000 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/InheritedObject.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -namespace Microsoft.AspNetCore.JsonPatch.Internal -{ - public class InheritedObject : SimpleObject - { - public string AdditionalStringProperty { get; set; } - } -} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveOperationTests.cs deleted file mode 100644 index 31f58c4b82..0000000000 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveOperationTests.cs +++ /dev/null @@ -1,333 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Collections.Generic; -using System.Dynamic; -using Newtonsoft.Json; -using Xunit; - -namespace Microsoft.AspNetCore.JsonPatch.Internal -{ - public class MoveOperationTests - { - [Fact] - public void Move() - { - dynamic doc = new ExpandoObject(); - doc.StringProperty = "A"; - doc.AnotherStringProperty = "B"; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move("StringProperty", "AnotherStringProperty"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal("A", doc.AnotherStringProperty); - - var cont = doc as IDictionary; - cont.TryGetValue("StringProperty", out object valueFromDictionary); - Assert.Null(valueFromDictionary); - } - - [Fact] - public void MoveToNonExisting() - { - dynamic doc = new ExpandoObject(); - doc.StringProperty = "A"; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move("StringProperty", "AnotherStringProperty"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal("A", doc.AnotherStringProperty); - - var cont = doc as IDictionary; - cont.TryGetValue("StringProperty", out var valueFromDictionary); - Assert.Null(valueFromDictionary); - } - - [Fact] - public void MoveDynamicToTyped() - { - dynamic doc = new ExpandoObject(); - doc.StringProperty = "A"; - doc.SimpleDTO = new SimpleObject() { AnotherStringProperty = "B" }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move("StringProperty", "SimpleDTO/AnotherStringProperty"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal("A", doc.SimpleDTO.AnotherStringProperty); - - var cont = doc as IDictionary; - cont.TryGetValue("StringProperty", out object valueFromDictionary); - Assert.Null(valueFromDictionary); - } - - [Fact] - public void MoveTypedToDynamic() - { - dynamic doc = new ExpandoObject(); - doc.StringProperty = "A"; - doc.SimpleDTO = new SimpleObject() { AnotherStringProperty = "B" }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move("SimpleDTO/AnotherStringProperty", "StringProperty"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal("B", doc.StringProperty); - Assert.Null(doc.SimpleDTO.AnotherStringProperty); - } - - [Fact] - public void NestedMove() - { - dynamic doc = new ExpandoObject(); - doc.Nested = new SimpleObject() - { - StringProperty = "A", - AnotherStringProperty = "B" - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move("Nested/StringProperty", "Nested/AnotherStringProperty"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal("A", doc.Nested.AnotherStringProperty); - Assert.Null(doc.Nested.StringProperty); - } - - [Fact] - public void MoveInList() - { - dynamic doc = new ExpandoObject(); - doc.IntegerList = new List() { 1, 2, 3 }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move("IntegerList/0", "IntegerList/1"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 2, 1, 3 }, doc.IntegerList); - } - - [Fact] - public void NestedMoveInList() - { - dynamic doc = new ExpandoObject(); - doc.Nested = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move("Nested/IntegerList/0", "Nested/IntegerList/1"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 2, 1, 3 }, doc.Nested.IntegerList); - } - - [Fact] - public void MoveFromListToEndOfList() - { - dynamic doc = new ExpandoObject(); - doc.IntegerList = new List() { 1, 2, 3 }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move("IntegerList/0", "IntegerList/-"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 2, 3, 1 }, doc.IntegerList); - } - - [Fact] - public void NestedMoveFromListToEndOfList() - { - dynamic doc = new ExpandoObject(); - doc.Nested = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move("Nested/IntegerList/0", "Nested/IntegerList/-"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 2, 3, 1 }, doc.Nested.IntegerList); - } - - [Fact] - public void MoveFomListToNonList() - { - dynamic doc = new ExpandoObject(); - doc.IntegerList = new List() { 1, 2, 3 }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move("IntegerList/0", "IntegerValue"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 2, 3 }, doc.IntegerList); - Assert.Equal(1, doc.IntegerValue); - } - - [Fact] - public void NestedMoveFomListToNonList() - { - dynamic doc = new ExpandoObject(); - doc.Nested = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move("Nested/IntegerList/0", "Nested/IntegerValue"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 2, 3 }, doc.Nested.IntegerList); - Assert.Equal(1, doc.Nested.IntegerValue); - } - - [Fact] - public void MoveFromNonListToList() - { - dynamic doc = new ExpandoObject(); - doc.IntegerValue = 5; - doc.IntegerList = new List() { 1, 2, 3 }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move("IntegerValue", "IntegerList/0"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - var cont = doc as IDictionary; - cont.TryGetValue("IntegerValue", out object valueFromDictionary); - Assert.Null(valueFromDictionary); - - Assert.Equal(new List() { 5, 1, 2, 3 }, doc.IntegerList); - } - - [Fact] - public void NestedMoveFromNonListToList() - { - dynamic doc = new ExpandoObject(); - doc.Nested = new SimpleObject() - { - IntegerValue = 5, - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move("Nested/IntegerValue", "Nested/IntegerList/0"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal(0, doc.Nested.IntegerValue); - Assert.Equal(new List() { 5, 1, 2, 3 }, doc.Nested.IntegerList); - } - - [Fact] - public void MoveToEndOfList() - { - dynamic doc = new ExpandoObject(); - doc.IntegerValue = 5; - doc.IntegerList = new List() { 1, 2, 3 }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move("IntegerValue", "IntegerList/-"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - var cont = doc as IDictionary; - cont.TryGetValue("IntegerValue", out var valueFromDictionary); - Assert.Null(valueFromDictionary); - - Assert.Equal(new List() { 1, 2, 3, 5 }, doc.IntegerList); - } - - [Fact] - public void NestedMoveToEndOfList() - { - dynamic doc = new ExpandoObject(); - doc.Nested = new SimpleObject() - { - IntegerValue = 5, - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move("Nested/IntegerValue", "Nested/IntegerList/-"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal(0, doc.Nested.IntegerValue); - Assert.Equal(new List() { 1, 2, 3, 5 }, doc.Nested.IntegerList); - } - } -} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveTypedOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveTypedOperationTests.cs deleted file mode 100644 index 4638718a59..0000000000 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/MoveTypedOperationTests.cs +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Collections.Generic; -using Newtonsoft.Json; -using Xunit; - -namespace Microsoft.AspNetCore.JsonPatch.Internal -{ - public class MoveTypedOperationTests - { - [Fact] - public void Move() - { - var doc = new SimpleObject() - { - StringProperty = "A", - AnotherStringProperty = "B" - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move("StringProperty", "AnotherStringProperty"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal("A", doc.AnotherStringProperty); - Assert.Null(doc.StringProperty); - } - - [Fact] - public void MoveInList() - { - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move("IntegerList/0", "IntegerList/1"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 2, 1, 3 }, doc.IntegerList); - } - - [Fact] - public void MoveFromListToEndOfList() - { - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move("IntegerList/0", "IntegerList/-"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 2, 3, 1 }, doc.IntegerList); - } - - [Fact] - public void MoveFomListToNonList() - { - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move("IntegerList/0", "IntegerValue"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 2, 3 }, doc.IntegerList); - Assert.Equal(1, doc.IntegerValue); - } - - [Fact] - public void MoveFromNonListToList() - { - var doc = new SimpleObject() - { - IntegerValue = 5, - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move("IntegerValue", "IntegerList/0"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal(0, doc.IntegerValue); - Assert.Equal(new List() { 5, 1, 2, 3 }, doc.IntegerList); - } - - [Fact] - public void MoveToEndOfList() - { - var doc = new SimpleObject() - { - IntegerValue = 5, - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move("IntegerValue", "IntegerList/-"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal(0, doc.IntegerValue); - Assert.Equal(new List() { 1, 2, 3, 5 }, doc.IntegerList); - } - } -} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/PatchDocumentTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/PatchDocumentTests.cs deleted file mode 100644 index 403238bf99..0000000000 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/PatchDocumentTests.cs +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using Microsoft.AspNetCore.JsonPatch.Exceptions; -using Newtonsoft.Json; -using Xunit; - -namespace Microsoft.AspNetCore.JsonPatch.Internal -{ - public class PatchDocumentTests - { - [Fact] - public void InvalidPathAtBeginningShouldThrowException() - { - var patchDoc = new JsonPatchDocument(); - var exception = Assert.Throws(() => - { - patchDoc.Add("//NewInt", 1); - }); - Assert.Equal( - "The provided string '//NewInt' is an invalid path.", - exception.Message); - } - - [Fact] - public void InvalidPathAtEndShouldThrowException() - { - var patchDoc = new JsonPatchDocument(); - var exception = Assert.Throws(() => - { - patchDoc.Add("NewInt//", 1); - }); - Assert.Equal( - "The provided string 'NewInt//' is an invalid path.", - exception.Message); - } - - [Fact] - public void InvalidPathWithDotShouldThrowException() - { - var patchDoc = new JsonPatchDocument(); - var exception = Assert.Throws(() => - { - patchDoc.Add("NewInt.Test", 1); - }); - Assert.Equal( - "The provided string 'NewInt.Test' is an invalid path.", - exception.Message); - } - - [Fact] - public void NonGenericPatchDocToGenericMustSerialize() - { - var doc = new SimpleObject() - { - StringProperty = "A", - AnotherStringProperty = "B" - }; - - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy("StringProperty", "AnotherStringProperty"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal("A", doc.AnotherStringProperty); - } - - [Fact] - public void GenericPatchDocToNonGenericMustSerialize() - { - var doc = 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); - - deserialized.ApplyTo(doc); - - Assert.Equal("A", doc.AnotherStringProperty); - } - } -} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveOperationTests.cs deleted file mode 100644 index 22707add87..0000000000 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveOperationTests.cs +++ /dev/null @@ -1,313 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Collections.Generic; -using System.Dynamic; -using Microsoft.AspNetCore.JsonPatch.Exceptions; -using Newtonsoft.Json; -using Xunit; - -namespace Microsoft.AspNetCore.JsonPatch.Internal -{ - public class RemoveOperationTests - { - [Fact] - public void RemovePropertyShouldFailIfRootIsAnonymous() - { - dynamic doc = new - { - Test = 1 - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove("Test"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - var exception = Assert.Throws(() => - { - deserialized.ApplyTo(doc); - }); - Assert.Equal( - string.Format("The property at path '{0}' could not be updated.", "Test"), - exception.Message); - } - - [Fact] - public void RemovePropertyShouldFailIfItDoesntExist() - { - dynamic doc = new ExpandoObject(); - doc.Test = 1; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove("NonExisting"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - var exception = Assert.Throws(() => - { - deserialized.ApplyTo(doc); - }); - Assert.Equal( - string.Format("The target location specified by path segment '{0}' was not found.", "NonExisting"), - exception.Message); - } - - [Fact] - public void RemovePropertyFromExpandoObject() - { - dynamic obj = new ExpandoObject(); - obj.Test = 1; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove("Test"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(obj); - - var cont = obj as IDictionary; - cont.TryGetValue("Test", out object valueFromDictionary); - Assert.Null(valueFromDictionary); - } - - [Fact] - public void RemoveProperty_FromExpandoObject_MixedCase_ThrowsPathNotFoundException() - { - dynamic obj = new ExpandoObject(); - obj.Test = 1; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove("test"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - var exception = Assert.Throws(() => - { - deserialized.ApplyTo(obj); - }); - - Assert.Equal( - string.Format( - "The target location specified by path segment '{0}' was not found.", - "test"), - exception.Message); - } - - [Fact] - public void RemoveNestedPropertyFromExpandoObject() - { - dynamic obj = new ExpandoObject(); - obj.Test = new ExpandoObject(); - obj.Test.AnotherTest = "A"; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove("Test"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(obj); - - var cont = obj as IDictionary; - cont.TryGetValue("Test", out object valueFromDictionary); - Assert.Null(valueFromDictionary); - } - - [Fact] - public void RemoveNestedProperty_FromExpandoObject_MixedCase_ThrowsPathNotFoundException() - { - dynamic obj = new ExpandoObject(); - obj.Test = new ExpandoObject(); - obj.Test.AnotherTest = "A"; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove("test"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - var exception = Assert.Throws(() => - { - deserialized.ApplyTo(obj); - }); - - Assert.Equal( - string.Format( - "The target location specified by path segment '{0}' was not found.", - "test"), - exception.Message); - } - - [Fact] - public void NestedRemove() - { - dynamic doc = new ExpandoObject(); - doc.SimpleDTO = new SimpleObject() - { - StringProperty = "A" - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove("SimpleDTO/StringProperty"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - Assert.Null(doc.SimpleDTO.StringProperty); - } - - [Fact] - public void NestedRemove_MixedCase_ThrowsPathNotFoundException() - { - dynamic doc = new ExpandoObject(); - doc.SimpleObject = new SimpleObject() - { - StringProperty = "A" - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove("Simpleobject/stringProperty"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - var exception = Assert.Throws(() => - { - deserialized.ApplyTo(doc); - }); - - Assert.Equal( - string.Format( - "For operation '{0}', the target location specified by path '{1}' was not found.", - "remove", - "/Simpleobject/stringProperty"), - exception.Message); - } - - [Fact] - public void NestedRemoveFromList() - { - dynamic doc = new ExpandoObject(); - doc.SimpleDTO = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove("SimpleDTO/IntegerList/2"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 1, 2 }, doc.SimpleDTO.IntegerList); - } - - [Fact] - public void NestedRemoveFromList_MixedCase() - { - dynamic doc = new ExpandoObject(); - doc.SimpleDTO = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove("SimpleDTO/Integerlist/2"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 1, 2 }, doc.SimpleDTO.IntegerList); - } - - [Fact] - public void NestedRemoveFromListInvalidPositionTooLarge() - { - dynamic doc = new ExpandoObject(); - doc.SimpleDTO = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove("SimpleDTO/IntegerList/3"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - var exception = Assert.Throws(() => - { - deserialized.ApplyTo(doc); - }); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "3"), - exception.Message); - } - - [Fact] - public void NestedRemoveFromListInvalidPositionTooSmall() - { - dynamic doc = new ExpandoObject(); - doc.SimpleDTO = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove("SimpleDTO/IntegerList/-1"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - var exception = Assert.Throws(() => - { - deserialized.ApplyTo(doc); - }); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), - exception.Message); - } - - [Fact] - public void NestedRemoveFromEndOfList() - { - dynamic doc = new ExpandoObject(); - doc.SimpleDTO = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove("SimpleDTO/IntegerList/-"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - Assert.Equal(new List() { 1, 2 }, doc.SimpleDTO.IntegerList); - } - } -} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveTypedOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveTypedOperationTests.cs deleted file mode 100644 index 000b049b1b..0000000000 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/RemoveTypedOperationTests.cs +++ /dev/null @@ -1,244 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Collections.Generic; -using Microsoft.AspNetCore.JsonPatch.Exceptions; -using Newtonsoft.Json; -using Xunit; - -namespace Microsoft.AspNetCore.JsonPatch.Internal -{ - public class RemoveTypedOperationTests - { - [Fact] - public void Remove() - { - var doc = new SimpleObject() - { - StringProperty = "A" - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove("StringProperty"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Null(doc.StringProperty); - } - - [Fact] - public void RemoveFromList() - { - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove("IntegerList/2"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 1, 2 }, doc.IntegerList); - } - - [Fact] - public void RemoveFromListInvalidPositionTooLarge() - { - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove("IntegerList/3"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - var exception = Assert.Throws(() => - { - deserialized.ApplyTo(doc); - }); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "3"), - exception.Message); - } - - [Fact] - public void RemoveFromListInvalidPositionTooSmall() - { - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove("IntegerList/-1"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - var exception = Assert.Throws(() => - { - deserialized.ApplyTo(doc); - }); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), - exception.Message); - } - - [Fact] - public void RemoveFromEndOfList() - { - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove("IntegerList/-"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 1, 2 }, doc.IntegerList); - } - - [Fact] - public void NestedRemove() - { - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - StringProperty = "A" - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove("SimpleObject/StringProperty"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Null(doc.SimpleObject.StringProperty); - } - - [Fact] - public void NestedRemoveFromList() - { - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove("SimpleObject/IntegerList/2"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 1, 2 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void NestedRemoveFromListInvalidPositionTooLarge() - { - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove("SimpleObject/IntegerList/3"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - var exception = Assert.Throws(() => - { - deserialized.ApplyTo(doc); - }); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "3"), - exception.Message); - } - - [Fact] - public void NestedRemoveFromListInvalidPositionTooSmall() - { - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove("SimpleObject/IntegerList/-1"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - var exception = Assert.Throws(() => - { - deserialized.ApplyTo(doc); - }); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), - exception.Message); - } - - [Fact] - public void NestedRemoveFromEndOfList() - { - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove("SimpleObject/IntegerList/-"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 1, 2 }, doc.SimpleObject.IntegerList); - } - } -} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceOperationTests.cs deleted file mode 100644 index 5d1fa77d85..0000000000 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceOperationTests.cs +++ /dev/null @@ -1,206 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Dynamic; -using Xunit; - -namespace Microsoft.AspNetCore.JsonPatch.Internal -{ - public class ReplaceOperationTests - { - [Fact] - public void ReplaceGuidTest() - { - dynamic doc = new SimpleObject() - { - GuidValue = Guid.NewGuid() - }; - - var newGuid = Guid.NewGuid(); - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace("GuidValue", newGuid); - - patchDoc.ApplyTo(doc); - - Assert.Equal(newGuid, doc.GuidValue); - } - - [Fact] - public void ReplaceGuidTestExpandoObject() - { - dynamic doc = new ExpandoObject(); - doc.GuidValue = Guid.NewGuid(); - - var newGuid = Guid.NewGuid(); - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace("GuidValue", newGuid); - - patchDoc.ApplyTo(doc); - - Assert.Equal(newGuid, doc.GuidValue); - } - - [Fact] - public void ReplaceGuidTestExpandoObjectInAnonymous() - { - dynamic nestedObject = new ExpandoObject(); - nestedObject.GuidValue = Guid.NewGuid(); - - dynamic doc = new - { - NestedObject = nestedObject - }; - - var newGuid = Guid.NewGuid(); - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace("nestedobject/GuidValue", newGuid); - - patchDoc.ApplyTo(doc); - - Assert.Equal(newGuid, doc.NestedObject.GuidValue); - } - - [Fact] - public void ReplaceNestedObjectTest() - { - dynamic doc = new ExpandoObject(); - doc.SimpleDTO = new SimpleObject() - { - IntegerValue = 5, - IntegerList = new List() { 1, 2, 3 } - }; - - var newDTO = new SimpleObject() - { - DoubleValue = 1 - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace("SimpleDTO", newDTO); - - patchDoc.ApplyTo(doc); - - Assert.Equal(1, doc.SimpleDTO.DoubleValue); - Assert.Equal(0, doc.SimpleDTO.IntegerValue); - Assert.Null(doc.SimpleDTO.IntegerList); - } - - [Fact] - public void ReplaceInList() - { - dynamic doc = new ExpandoObject(); - doc.IntegerList = new List() { 1, 2, 3 }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace("IntegerList/0", 5); - - patchDoc.ApplyTo(doc); - - Assert.Equal(new List() { 5, 2, 3 }, doc.IntegerList); - } - - [Fact] - public void ReplaceFullList() - { - dynamic doc = new ExpandoObject(); - doc.IntegerList = new List() { 1, 2, 3 }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace("IntegerList", new List() { 4, 5, 6 }); - - patchDoc.ApplyTo(doc); - - Assert.Equal(new List() { 4, 5, 6 }, doc.IntegerList); - } - - [Fact] - public void ReplaceInListInList() - { - dynamic doc = new ExpandoObject(); - doc.SimpleDTOList = new List() { - new SimpleObject() { - IntegerList = new List(){1,2,3} - }}; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace("SimpleDTOList/0/IntegerList/0", 4); - - patchDoc.ApplyTo(doc); - - Assert.Equal(4, doc.SimpleDTOList[0].IntegerList[0]); - } - - [Fact] - public void ReplaceInListInListAtEnd() - { - dynamic doc = new ExpandoObject(); - doc.SimpleDTOList = new List() { - new SimpleObject() { - IntegerList = new List(){1,2,3} - }}; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace("SimpleDTOList/0/IntegerList/-", 4); - - patchDoc.ApplyTo(doc); - - Assert.Equal(4, doc.SimpleDTOList[0].IntegerList[2]); - } - - [Fact] - public void ReplaceFullListFromEnumerable() - { - dynamic doc = new ExpandoObject(); - doc.IntegerList = new List() { 1, 2, 3 }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace("IntegerList", new List() { 4, 5, 6 }); - - patchDoc.ApplyTo(doc); - - Assert.Equal(new List() { 4, 5, 6 }, doc.IntegerList); - } - - [Fact] - public void ReplaceFullListWithCollection() - { - dynamic doc = new ExpandoObject(); - doc.IntegerList = new List() { 1, 2, 3 }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace("IntegerList", new Collection() { 4, 5, 6 }); - - patchDoc.ApplyTo(doc); - - Assert.Equal(new List() { 4, 5, 6 }, doc.IntegerList); - } - - [Fact] - public void ReplaceAtEndOfList() - { - dynamic doc = new ExpandoObject(); - doc.IntegerList = new List() { 1, 2, 3 }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace("IntegerList/-", 5); - - patchDoc.ApplyTo(doc); - - Assert.Equal(new List() { 1, 2, 5 }, doc.IntegerList); - } - } -} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceTypedOperationTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceTypedOperationTests.cs deleted file mode 100644 index 94131ff3b5..0000000000 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/ReplaceTypedOperationTests.cs +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using Newtonsoft.Json; -using Xunit; - -namespace Microsoft.AspNetCore.JsonPatch.Internal -{ - public class ReplaceTypedOperationTests - { - [Fact] - public void ReplaceGuidTest() - { - var doc = new SimpleObject() - { - GuidValue = Guid.NewGuid() - }; - - var newGuid = Guid.NewGuid(); - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace("GuidValue", newGuid); - - // serialize & deserialize - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserizalized = JsonConvert.DeserializeObject(serialized); - - deserizalized.ApplyTo(doc); - - Assert.Equal(newGuid, doc.GuidValue); - } - - [Fact] - public void SerializeAndReplaceNestedObjectTest() - { - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerValue = 5, - IntegerList = new List() { 1, 2, 3 } - } - }; - - var newDTO = new SimpleObject() - { - DoubleValue = 1 - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace("SimpleObject", newDTO); - - // serialize & deserialize - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal(1, doc.SimpleObject.DoubleValue); - Assert.Equal(0, doc.SimpleObject.IntegerValue); - Assert.Null(doc.SimpleObject.IntegerList); - } - - [Fact] - public void ReplaceInList() - { - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace("IntegerList/0", 5); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 5, 2, 3 }, doc.IntegerList); - } - - [Fact] - public void ReplaceFullList() - { - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace("IntegerList", new List() { 4, 5, 6 }); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 4, 5, 6 }, doc.IntegerList); - } - - [Fact] - public void ReplaceInListInList() - { - var doc = new SimpleObject() - { - SimpleObjectList = new List() { - new SimpleObject() { - IntegerList = new List(){1,2,3} - }} - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace("SimpleObjectList/0/IntegerList/0", 4); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal(4, doc.SimpleObjectList.First().IntegerList.First()); - } - - [Fact] - public void ReplaceFullListFromEnumerable() - { - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace("IntegerList", new List() { 4, 5, 6 }); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 4, 5, 6 }, doc.IntegerList); - } - - [Fact] - public void ReplaceFullListWithCollection() - { - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace("IntegerList", new Collection() { 4, 5, 6 }); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 4, 5, 6 }, doc.IntegerList); - } - - [Fact] - public void ReplaceAtEndOfList() - { - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace("IntegerList/-", 5); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject(serialized); - deserialized.ApplyTo(doc); - - Assert.Equal(new List() { 1, 2, 5 }, doc.IntegerList); - } - } -} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/SimpleObject.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/SimpleObject.cs deleted file mode 100644 index 01a890d7be..0000000000 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/SimpleObject.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; - -namespace Microsoft.AspNetCore.JsonPatch.Internal -{ - public class SimpleObject - { - public List SimpleObjectList { get; set; } - public List IntegerList { get; set; } - public int IntegerValue { 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; } - } -} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/SimpleObjectWithNestedObject.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/SimpleObjectWithNestedObject.cs deleted file mode 100644 index aa766b8438..0000000000 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/SimpleObjectWithNestedObject.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Collections.Generic; - -namespace Microsoft.AspNetCore.JsonPatch.Internal -{ - public class SimpleObjectWithNestedObject - { - public int IntegerValue { get; set; } - public NestedObject NestedObject { get; set; } - public SimpleObject SimpleObject { get; set; } - public List ListOfSimpleObject { get; set; } - - public SimpleObjectWithNestedObject() - { - NestedObject = new NestedObject(); - SimpleObject = new SimpleObject(); - ListOfSimpleObject = new List(); - } - } -} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/AnonymousObjectIntegrationTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/AnonymousObjectIntegrationTest.cs new file mode 100644 index 0000000000..4f290aae2f --- /dev/null +++ b/test/Microsoft.AspNetCore.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/test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/DictionaryIntegrationTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/DictionaryIntegrationTest.cs new file mode 100644 index 0000000000..da990e3e8c --- /dev/null +++ b/test/Microsoft.AspNetCore.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/test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/DynamicObjectTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/DynamicObjectIntegrationTest.cs similarity index 58% rename from test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/DynamicObjectTest.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/DynamicObjectIntegrationTest.cs index be7738419f..ec15951a85 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/DynamicObjectTest.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/DynamicObjectIntegrationTest.cs @@ -5,9 +5,9 @@ using System.Collections.Generic; using Microsoft.AspNetCore.JsonPatch.Exceptions; using Xunit; -namespace Microsoft.AspNetCore.JsonPatch.Internal +namespace Microsoft.AspNetCore.JsonPatch.IntegrationTests { - public class DynamicObjectTest + public class DynamicObjectIntegrationTest { [Fact] public void AddResults_ShouldReplaceExistingPropertyValue_InNestedDynamicObject() @@ -20,11 +20,11 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal dynamicTestObject.Nested.DynamicProperty.InBetweenFirst.InBetweenSecond = new DynamicTestObject(); dynamicTestObject.Nested.DynamicProperty.InBetweenFirst.InBetweenSecond.StringProperty = "A"; - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("/Nested/DynamicProperty/InBetweenFirst/InBetweenSecond/StringProperty", "B"); + var patchDocument = new JsonPatchDocument(); + patchDocument.Add("/Nested/DynamicProperty/InBetweenFirst/InBetweenSecond/StringProperty", "B"); // Act - patchDoc.ApplyTo(dynamicTestObject); + patchDocument.ApplyTo(dynamicTestObject); // Assert Assert.Equal("B", dynamicTestObject.Nested.DynamicProperty.InBetweenFirst.InBetweenSecond.StringProperty); @@ -53,21 +53,17 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal DynamicProperty = new DynamicTestObject() }; - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("DynamicProperty/OtherProperty/IntProperty", 1); + var patchDocument = new JsonPatchDocument(); + patchDocument.Add("DynamicProperty/OtherProperty/IntProperty", 1); // Act var exception = Assert.Throws(() => { - patchDoc.ApplyTo(nestedObject); + patchDocument.ApplyTo(nestedObject); }); // Assert - Assert.Equal( - string.Format( - "The target location specified by path segment '{0}' was not found.", - "OtherProperty"), - exception.Message); + Assert.Equal("The target location specified by path segment 'OtherProperty' was not found.", exception.Message); } [Fact] @@ -79,11 +75,11 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal dynamicTestObject.NestedDynamicObject.StringProperty = "A"; dynamicTestObject.NestedDynamicObject.AnotherStringProperty = "B"; - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy("NestedDynamicObject/StringProperty", "NestedDynamicObject/AnotherStringProperty"); + var patchDocument = new JsonPatchDocument(); + patchDocument.Copy("NestedDynamicObject/StringProperty", "NestedDynamicObject/AnotherStringProperty"); // Act - patchDoc.ApplyTo(dynamicTestObject); + patchDocument.ApplyTo(dynamicTestObject); // Assert Assert.Equal("A", dynamicTestObject.NestedDynamicObject.AnotherStringProperty); @@ -97,11 +93,11 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal dynamic dynamicTestObject = new DynamicTestObject(); dynamicTestObject.StringProperty = "A"; - var patchDoc = new JsonPatchDocument(); - patchDoc.Move("StringProperty", "AnotherStringProperty"); + var patchDocument = new JsonPatchDocument(); + patchDocument.Move("StringProperty", "AnotherStringProperty"); // Act - patchDoc.ApplyTo(dynamicTestObject); + patchDocument.ApplyTo(dynamicTestObject); dynamicTestObject.TryGetValue("StringProperty", out object valueFromDictionary); // Assert @@ -117,11 +113,11 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal dynamicTestObject.StringProperty = "A"; dynamicTestObject.SimpleObject = new SimpleObject() { AnotherStringProperty = "B" }; - var patchDoc = new JsonPatchDocument(); - patchDoc.Move("StringProperty", "SimpleObject/AnotherStringProperty"); + var patchDocument = new JsonPatchDocument(); + patchDocument.Move("StringProperty", "SimpleObject/AnotherStringProperty"); // Act - patchDoc.ApplyTo(dynamicTestObject); + patchDocument.ApplyTo(dynamicTestObject); dynamicTestObject.TryGetValue("StringProperty", out object valueFromDictionary); // Assert @@ -129,27 +125,6 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal Assert.Null(valueFromDictionary); } - [Fact] - public void MovePropertyValue_FromListToNonList_InNestedTypedObject_InDynamicObject() - { - // Arrange - dynamic dynamicTestObject = new DynamicTestObject(); - dynamicTestObject.Nested = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - var patchDoc = new JsonPatchDocument(); - patchDoc.Move("Nested/IntegerList/0", "Nested/IntegerValue"); - - // Act - patchDoc.ApplyTo(dynamicTestObject); - - // Assert - Assert.Equal(new List() { 2, 3 }, dynamicTestObject.Nested.IntegerList); - Assert.Equal(1, dynamicTestObject.Nested.IntegerValue); - } - [Fact] public void RemoveNestedProperty_FromDynamicObject() { @@ -158,11 +133,11 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal dynamicTestObject.Test = new DynamicTestObject(); dynamicTestObject.Test.AnotherTest = "A"; - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove("Test"); + var patchDocument = new JsonPatchDocument(); + patchDocument.Remove("Test"); // Act - patchDoc.ApplyTo(dynamicTestObject); + patchDocument.ApplyTo(dynamicTestObject); dynamicTestObject.TryGetValue("Test", out object valueFromDictionary); // Assert @@ -179,41 +154,19 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal StringProperty = "A" }; - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove("Simpleobject/stringProperty"); + var patchDocument = new JsonPatchDocument(); + patchDocument.Remove("Simpleobject/stringProperty"); // Act var exception = Assert.Throws(() => { - patchDoc.ApplyTo(dynamicTestObject); + patchDocument.ApplyTo(dynamicTestObject); }); // Assert - Assert.Equal( - string.Format("The target location specified by path segment '{0}' was not found.", - "Simpleobject"), - exception.Message); + Assert.Equal("The target location specified by path segment 'Simpleobject' was not found.", exception.Message); } - [Fact] - public void RemoveFromList_NestedInDynamicObject() - { - // Arrange - dynamic dynamicTestObject = new DynamicTestObject(); - dynamicTestObject.SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove("SimpleObject/IntegerList/2"); - - // Act - patchDoc.ApplyTo(dynamicTestObject); - - // Assert - Assert.Equal(new List() { 1, 2 }, dynamicTestObject.SimpleObject.IntegerList); - } [Fact] public void ReplaceNestedTypedObject_InDynamicObject() @@ -231,11 +184,11 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal DoubleValue = 1 }; - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace("SimpleObject", newObject); + var patchDocument = new JsonPatchDocument(); + patchDocument.Replace("SimpleObject", newObject); // Act - patchDoc.ApplyTo(dynamicTestObject); + patchDocument.ApplyTo(dynamicTestObject); // Assert Assert.Equal(1, dynamicTestObject.SimpleObject.DoubleValue); @@ -244,41 +197,21 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal } [Fact] - public void ReplaceFullList_InDynamicObject() + public void TestStringPropertyValue_IsSuccessful() { // Arrange dynamic dynamicTestObject = new DynamicTestObject(); - dynamicTestObject.IntegerList = new List() { 1, 2, 3 }; + dynamicTestObject.Property = "A"; - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace("IntegerList", new List() { 4, 5, 6 }); - - // Act - patchDoc.ApplyTo(dynamicTestObject); - - // Assert - Assert.Equal(new List() { 4, 5, 6 }, dynamicTestObject.IntegerList); - } - - [Fact] - public void TestPropertyValue_FromListToNonList_InNestedTypedObject_InDynamicObject() - { - // Arrange - dynamic dynamicTestObject = new DynamicTestObject(); - dynamicTestObject.Nested = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - var patchDoc = new JsonPatchDocument(); - patchDoc.Test("Nested/IntegerList/1", 2); + var patchDocument = new JsonPatchDocument(); + patchDocument.Test("Property", "A"); // Act & Assert - patchDoc.ApplyTo(dynamicTestObject); + patchDocument.ApplyTo(dynamicTestObject); } [Fact] - public void TestPropertyValue_FromListToNonList_InNestedTypedObject_InDynamicObject_ThrowsJsonPatchException_IfTestFails() + public void TestIntegerPropertyValue_ThrowsJsonPatchException_IfTestFails() { // Arrange dynamic dynamicTestObject = new DynamicTestObject(); @@ -287,13 +220,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal IntegerList = new List() { 1, 2, 3 } }; - var patchDoc = new JsonPatchDocument(); - patchDoc.Test("Nested/IntegerList/0", 2); + var patchDocument = new JsonPatchDocument(); + patchDocument.Test("Nested/IntegerList/0", 2); // Act var exception = Assert.Throws(() => { - patchDoc.ApplyTo(dynamicTestObject); + patchDocument.ApplyTo(dynamicTestObject); }); // Assert diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/ExpandoObjectIntegrationTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/ExpandoObjectIntegrationTest.cs new file mode 100644 index 0000000000..b1b58556f0 --- /dev/null +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/ExpandoObjectIntegrationTest.cs @@ -0,0 +1,327 @@ +// Copyright (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 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/test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/ListIntegrationTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/ListIntegrationTest.cs new file mode 100644 index 0000000000..5e261ea08b --- /dev/null +++ b/test/Microsoft.AspNetCore.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/test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/NestedObjectIntegrationTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/NestedObjectIntegrationTest.cs new file mode 100644 index 0000000000..92c0e7fb2d --- /dev/null +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/NestedObjectIntegrationTest.cs @@ -0,0 +1,342 @@ +// Copyright (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 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/test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/SimpleObjectIntegrationTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/SimpleObjectIntegrationTest.cs new file mode 100644 index 0000000000..669c6d7af4 --- /dev/null +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/SimpleObjectIntegrationTest.cs @@ -0,0 +1,128 @@ +// Copyright (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 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 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); + } + + } +} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Adapters/DictionaryAdapterTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Internal/DictionaryAdapterTest.cs similarity index 91% rename from test/Microsoft.AspNetCore.JsonPatch.Test/Adapters/DictionaryAdapterTest.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/Internal/DictionaryAdapterTest.cs index d1d2216c2c..a0dcd82ab0 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Adapters/DictionaryAdapterTest.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Internal/DictionaryAdapterTest.cs @@ -74,9 +74,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal // Assert Assert.False(getStatus); - Assert.Equal( - string.Format("The provided path segment '{0}' cannot be converted to the target type.", guidKey.ToString()), - message); + Assert.Equal($"The provided path segment '{guidKey.ToString()}' cannot be converted to the target type.", message); Assert.Null(outValue); } @@ -103,9 +101,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal // Assert Assert.False(getStatus); - Assert.Equal( - string.Format("The target location specified by path segment '{0}' was not found.", nameKey.ToUpper()), - message); + Assert.Equal("The target location specified by path segment 'NAME' was not found.", message); Assert.Null(outValue); } @@ -191,9 +187,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal // Assert Assert.False(replaceStatus); - Assert.Equal( - string.Format("The value '{0}' is invalid for target location.", "test"), - message); + Assert.Equal("The value 'test' is invalid for target location.", message); Assert.Equal(5, dictionary[guidKey]); } @@ -211,9 +205,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal // Assert Assert.False(replaceStatus); - Assert.Equal( - string.Format("The target location specified by path segment '{0}' was not found.", nameKey), - message); + Assert.Equal("The target location specified by path segment 'Name' was not found.", message); Assert.Empty(dictionary); } @@ -231,9 +223,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal // Assert Assert.False(removeStatus); - Assert.Equal( - string.Format("The target location specified by path segment '{0}' was not found.", nameKey), - message); + Assert.Equal("The target location specified by path segment 'Name' was not found.", message); Assert.Empty(dictionary); } @@ -280,13 +270,19 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal { // Arrange var key = "Name"; - var dictionary = new Dictionary(); - dictionary[key] = "James"; - var dictionaryAdapter = new DictionaryAdapter(); + 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, "James", out var message); + var testStatus = dictionaryAdapter.TryTest(dictionary, key, resolver, value, out var message); //Assert Assert.True(testStatus); diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Adapters/DynamicObjectAdapterTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Internal/DynamicObjectAdapterTest.cs similarity index 97% rename from test/Microsoft.AspNetCore.JsonPatch.Test/Adapters/DynamicObjectAdapterTest.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/Internal/DynamicObjectAdapterTest.cs index 9ed9a51ed0..96b1aee935 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Adapters/DynamicObjectAdapterTest.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Internal/DynamicObjectAdapterTest.cs @@ -233,15 +233,21 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal { var adapter = new DynamicObjectAdapter(); dynamic target = new DynamicTestObject(); - target.NewProperty = "Joana"; + 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, "Joana", out string errorMessage); + var testStatus = adapter.TryTest(target, segment, resolver, value, out string errorMessage); // Assert - Assert.Equal("Joana", target.NewProperty); + Assert.Equal(value, target.NewProperty); Assert.True(testStatus); Assert.True(string.IsNullOrEmpty(errorMessage), "Expected no error message"); } diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Adapters/ListAdapterTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Internal/ListAdapterTest.cs similarity index 91% rename from test/Microsoft.AspNetCore.JsonPatch.Test/Adapters/ListAdapterTest.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/Internal/ListAdapterTest.cs index 25d8ae387b..f31e57541b 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Adapters/ListAdapterTest.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Internal/ListAdapterTest.cs @@ -24,11 +24,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal // Assert Assert.False(addStatus); - Assert.Equal( - string.Format( - "The type '{0}' which is an array is not supported for json patch operations as it has a fixed size.", - targetObject.GetType().FullName), - message); + 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] @@ -46,11 +42,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal // Assert Assert.False(addStatus); - Assert.Equal( - string.Format( - "The type '{0}' which is a non generic list is not supported for json patch operations. Only generic list types are supported.", - targetObject.GetType().FullName), - message); + 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] @@ -88,9 +80,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal // Assert Assert.False(addStatus); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", position), - message); + Assert.Equal($"The index value provided by path segment '{position}' is out of bounds of the array size.", message); } [Theory] @@ -108,9 +98,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal // Assert Assert.False(addStatus); - Assert.Equal( - string.Format("The path segment '{0}' is invalid for an array index.", position), - message); + Assert.Equal($"The path segment '{position}' is invalid for an array index.", message); } public static TheoryData, List> AppendAtEndOfListData @@ -200,7 +188,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal // Assert Assert.False(addStatus); - Assert.Equal(string.Format("The value '{0}' is invalid for target location.", "James"), message); + Assert.Equal("The value 'James' is invalid for target location.", message); } public static TheoryData AddingDifferentComplexTypeWorksData @@ -255,8 +243,10 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal Assert.Equal(expected, targetObject); } - public static TheoryData AddingKeepsObjectReferenceData { - get { + public static TheoryData AddingKeepsObjectReferenceData + { + get + { var sDto1 = new SimpleObject(); var sDto2 = new SimpleObject(); var sDto3 = new SimpleObject(); @@ -324,9 +314,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal // Assert Assert.False(getStatus); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", position), - message); + Assert.Equal($"The index value provided by path segment '{position}' is out of bounds of the array size.", message); } [Theory] @@ -365,9 +353,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal // Assert Assert.False(removeStatus); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", position), - message); + Assert.Equal($"The index value provided by path segment '{position}' is out of bounds of the array size.", message); } [Theory] @@ -402,9 +388,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal // Assert Assert.False(replaceStatus); - Assert.Equal( - string.Format("The value '{0}' is invalid for target location.", "James"), - message); + Assert.Equal("The value 'James' is invalid for target location.", message); } [Fact] diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectVisitorTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Internal/ObjectVisitorTest.cs similarity index 95% rename from test/Microsoft.AspNetCore.JsonPatch.Test/ObjectVisitorTest.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/Internal/ObjectVisitorTest.cs index 3384986c28..cb299cf0dc 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectVisitorTest.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Internal/ObjectVisitorTest.cs @@ -1,7 +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; using System.Collections.Generic; using System.Dynamic; using Newtonsoft.Json.Serialization; @@ -168,9 +167,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal // Assert Assert.False(visitStatus); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", position), - message); + Assert.Equal($"The index value provided by path segment '{position}' is out of bounds of the array size.", message); } [Theory] @@ -188,12 +185,9 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal // Assert Assert.False(visitStatus); - Assert.Equal(string.Format( - "The path segment '{0}' is invalid for an array index.", position), - message); + Assert.Equal($"The path segment '{position}' is invalid for an array index.", message); } - // The adapter takes care of the responsibility of validating the final segment [Fact] public void Visit_DoesNotValidate_FinalPathSegment() { diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/ParsedPathTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Internal/ParsedPathTests.cs similarity index 91% rename from test/Microsoft.AspNetCore.JsonPatch.Test/ParsedPathTests.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/Internal/ParsedPathTests.cs index 6b7c2e69cb..c23abcdb5e 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/ParsedPathTests.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Internal/ParsedPathTests.cs @@ -2,10 +2,9 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.AspNetCore.JsonPatch.Exceptions; -using Microsoft.AspNetCore.JsonPatch.Internal; using Xunit; -namespace Microsoft.AspNetCore.JsonPatch.Test +namespace Microsoft.AspNetCore.JsonPatch.Internal { public class ParsedPathTests { @@ -19,7 +18,10 @@ namespace Microsoft.AspNetCore.JsonPatch.Test [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); } @@ -30,6 +32,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Test [InlineData("foo~3bar")] public void PathWithInvalidEscapeSequenceShouldFail(string path) { + // Arrange, Act & Assert Assert.Throws(() => { var parsedPath = new ParsedPath(path); diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Adapters/PocoAdapterTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Internal/PocoAdapterTest.cs similarity index 100% rename from test/Microsoft.AspNetCore.JsonPatch.Test/Adapters/PocoAdapterTest.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/Internal/PocoAdapterTest.cs diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentGetPathTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentGetPathTest.cs index 7d3331231c..266202c7a5 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentGetPathTest.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentGetPathTest.cs @@ -100,9 +100,7 @@ namespace Microsoft.AspNetCore.JsonPatch }); // Assert - Assert.Equal( - string.Format("The expression '(p.IntegerValue >= 4)' is not supported. Supported expressions include member access and indexer expressions."), - exception.Message); + Assert.Equal("The expression '(p.IntegerValue >= 4)' is not supported. Supported expressions include member access and indexer expressions.", exception.Message); } } diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs index 882e09ffe7..f5d6377989 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs @@ -1,9 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System.Collections.Generic; using System.Linq; -using System.Reflection; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using Xunit; @@ -13,263 +11,39 @@ namespace Microsoft.AspNetCore.JsonPatch public class JsonPatchDocumentJsonPropertyAttributeTest { [Fact] - public void Add_ToRoot_OfListOfObjects_AtEndOfList() + public void Add_RespectsJsonPropertyAttribute() { - var patchDoc = new JsonPatchDocument>(); - patchDoc.Add(p => p, new JsonPropertyObject()); + // Arrange + var patchDocument = new JsonPatchDocument(); - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = - JsonConvert.DeserializeObject>(serialized); + // Act + patchDocument.Add(p => p.Name, "John"); - // get path - var pathToCheck = deserialized.Operations.First().path; - Assert.Equal("/-", pathToCheck); - } - - [Fact] - public void Add_ToRoot_OfListOfObjects_AtGivenPosition() - { - var patchDoc = new JsonPatchDocument>(); - patchDoc.Add(p => p[3], new JsonPropertyObject()); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = - JsonConvert.DeserializeObject>(serialized); - - // get path - var pathToCheck = deserialized.Operations.First().path; - Assert.Equal("/3", pathToCheck); - } - - [Fact] - public void Add_WithExpression_RespectsJsonPropertyName_ForModelProperty() - { - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(p => p.Name, "John"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - // serialized value should have "AnotherName" as path - // deserialize to a JsonPatchDocument to check - var deserialized = - JsonConvert.DeserializeObject>(serialized); - - // get path - var pathToCheck = deserialized.Operations.First().path; + // Assert + var pathToCheck = patchDocument.Operations.First().path; Assert.Equal("/AnotherName", pathToCheck); } [Fact] - public void Add_WithExpressionOnStringProperty_FallsbackToPropertyName_WhenJsonPropertyName_IsEmpty() + public void Move_FallsbackToPropertyName_WhenJsonPropertyAttributeName_IsEmpty() { // Arrange - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(m => m.StringProperty, "Test"); - var serialized = JsonConvert.SerializeObject(patchDoc); + var patchDocument = new JsonPatchDocument(); // Act - var deserialized = - JsonConvert.DeserializeObject>(serialized); + patchDocument.Move(m => m.StringProperty, m => m.StringProperty2); // Assert - var pathToCheck = deserialized.Operations.First().path; - Assert.Equal("/StringProperty", pathToCheck); - } - - [Fact] - public void Add_WithExpressionOnArrayProperty_FallsbackToPropertyName_WhenJsonPropertyName_IsEmpty() - { - // Arrange - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(m => m.ArrayProperty, "James"); - var serialized = JsonConvert.SerializeObject(patchDoc); - - // Act - var deserialized = - JsonConvert.DeserializeObject>(serialized); - - // Assert - var pathToCheck = deserialized.Operations.First().path; - Assert.Equal("/ArrayProperty/-", pathToCheck); - } - - [Fact] - public void Add_WithExpression_RespectsJsonPropertyName_WhenApplyingToDifferentlyTypedClassWithPropertyMatchingJsonPropertyName() - { - var patchDocToSerialize = new JsonPatchDocument(); - patchDocToSerialize.Add(p => p.Name, "John"); - - // the patchdoc will deserialize to "anothername". We should thus be able to apply - // it to a class that HAS that other property name. - var doc = new JsonPropertyWithAnotherNameObject() - { - AnotherName = "InitialValue" - }; - - var serialized = JsonConvert.SerializeObject(patchDocToSerialize); - var deserialized = - JsonConvert.DeserializeObject> - (serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal("John", doc.AnotherName); - } - - [Fact] - public void Add_WithExpression_RespectsJsonPropertyName_WhenApplyingToSameTypedClassWithMatchingJsonPropertyName() - { - var patchDocToSerialize = new JsonPatchDocument(); - patchDocToSerialize.Add(p => p.Name, "John"); - - // the patchdoc will deserialize to "anothername". As JsonPropertyDTO has - // a JsonProperty signifying that "Name" should be deseriallized from "AnotherName", - // we should be able to apply the patchDoc. - - var doc = new JsonPropertyObject() - { - Name = "InitialValue" - }; - - var serialized = JsonConvert.SerializeObject(patchDocToSerialize); - var deserialized = - JsonConvert.DeserializeObject> - (serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal("John", doc.Name); - } - - [Fact] - public void Add_OnApplyFromJson_RespectsJsonPropertyNameOnJsonDocument() - { - var doc = new JsonPropertyObject() - { - Name = "InitialValue" - }; - - // serialization should serialize to "AnotherName" - var serialized = "[{\"value\":\"Kevin\",\"path\":\"/AnotherName\",\"op\":\"add\"}]"; - var deserialized = - JsonConvert.DeserializeObject>(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal("Kevin", doc.Name); - } - - [Fact] - public void Remove_OnApplyFromJson_RespectsJsonPropertyNameOnJsonDocument() - { - var doc = new JsonPropertyObject() - { - Name = "InitialValue" - }; - - // serialization should serialize to "AnotherName" - var serialized = "[{\"path\":\"/AnotherName\",\"op\":\"remove\"}]"; - var deserialized = - JsonConvert.DeserializeObject>(serialized); - - deserialized.ApplyTo(doc); - - Assert.Null(doc.Name); - } - - [Fact] - public void Add_OnApplyFromJson_RespectsInheritedJsonPropertyNameOnJsonDocument() - { - var doc = new JsonPropertyWithInheritanceObject() - { - Name = "InitialName" - }; - - // serialization should serialize to "AnotherName" - var serialized = "[{\"value\":\"Kevin\",\"path\":\"/AnotherName\",\"op\":\"add\"}]"; - var deserialized = - JsonConvert.DeserializeObject>(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal("Kevin", doc.Name); - } - - [Fact] - public void Add_WithExpression_RespectsJsonPropertyName_ForInheritedModelProperty() - { - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(p => p.Name, "John"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - // serialized value should have "AnotherName" as path - // deserialize to a JsonPatchDocument to check - var deserialized = - JsonConvert.DeserializeObject>(serialized); - - // get path - var pathToCheck = deserialized.Operations.First().path; - Assert.Equal("/AnotherName", pathToCheck); - } - - [Fact] - public void Add_OnApplyFromJson_EscapingHandledOnComplexJsonPropertyNameOnJsonDocument() - { - var doc = new JsonPropertyComplexNameObject() - { - FooSlashBars = "InitialName", - FooSlashTilde = new SimpleObject - { - StringProperty = "Initial Value" - } - }; - - // serialization should serialize to "AnotherName" - var serialized = "[{\"value\":\"Kevin\",\"path\":\"/foo~1bar~0\",\"op\":\"add\"},{\"value\":\"Final Value\",\"path\":\"/foo~1~0/StringProperty\",\"op\":\"replace\"}]"; - var deserialized = - JsonConvert.DeserializeObject>(serialized); - - deserialized.ApplyTo(doc); - - Assert.Equal("Kevin", doc.FooSlashBars); - Assert.Equal("Final Value", doc.FooSlashTilde.StringProperty); - } - - [Fact] - public void Move_WithExpression_FallsbackToPropertyName_WhenJsonPropertyName_IsEmpty() - { - // Arrange - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(m => m.StringProperty, m => m.StringProperty2); - var serialized = JsonConvert.SerializeObject(patchDoc); - - // Act - var deserialized = - JsonConvert.DeserializeObject>(serialized); - - // Assert - var fromPath = deserialized.Operations.First().from; + var fromPath = patchDocument.Operations.First().from; Assert.Equal("/StringProperty", fromPath); - var toPath = deserialized.Operations.First().path; + var toPath = patchDocument.Operations.First().path; Assert.Equal("/StringProperty2", toPath); } - [Fact] - public void Add_WithExpression_AndCustomContractResolver_UsesPropertyName_SetByContractResolver() + private class JsonPropertyObject { - // Arrange - var patchDoc = new JsonPatchDocument(); - patchDoc.ContractResolver = new CustomContractResolver(); - patchDoc.Add(m => m.SSN, "123-45-6789"); - var serialized = JsonConvert.SerializeObject(patchDoc); - - // Act - var deserialized = - JsonConvert.DeserializeObject>(serialized); - - // Assert - var path = deserialized.Operations.First().path; - Assert.Equal("/SocialSecurityNumber", path); + [JsonProperty("AnotherName")] + public string Name { get; set; } } private class JsonPropertyWithNoPropertyName @@ -286,20 +60,5 @@ namespace Microsoft.AspNetCore.JsonPatch [JsonProperty] public string SSN { get; set; } } - - private class CustomContractResolver : DefaultContractResolver - { - protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) - { - var jsonProperty = base.CreateProperty(member, memberSerialization); - - if (jsonProperty.PropertyName == "SSN") - { - jsonProperty.PropertyName = "SocialSecurityNumber"; - } - - return jsonProperty; - } - } } } diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentTest.cs index d754e8da5b..6b44b6696c 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentTest.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentTest.cs @@ -1,55 +1,180 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (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.Test +namespace Microsoft.AspNetCore.JsonPatch { public class JsonPatchDocumentTest { [Fact] - public void InvalidOperation_ThrowsException_CallsIntoLogErrorAction() + public void InvalidPathAtBeginningShouldThrowException() { // Arrange - var operationName = "foo"; - var serialized = "[{\"value\":\"John\",\"path\":\"/Name\",\"op\":\"" + operationName + "\"}]"; - var jsonPatchDocument = JsonConvert.DeserializeObject>(serialized); - var model = new Customer(); - var expectedErrorMessage = $"Invalid JsonPatch operation '{operationName}'."; - string actualErrorMessage = null; + var patchDocument = new JsonPatchDocument(); // Act - jsonPatchDocument.ApplyTo(model, (jsonPatchError) => + var exception = Assert.Throws(() => { - actualErrorMessage = jsonPatchError.ErrorMessage; + patchDocument.Add("//NewInt", 1); }); // Assert - Assert.Equal(expectedErrorMessage, actualErrorMessage); + Assert.Equal( + "The provided string '//NewInt' is an invalid path.", + exception.Message); } [Fact] - public void InvalidOperation_NoLogErrorAction_ThrowsJsonPatchException() + public void InvalidPathAtEndShouldThrowException() { // Arrange - var operationName = "foo"; - var serialized = "[{\"value\":\"John\",\"path\":\"/Name\",\"op\":\"" + operationName + "\"}]"; - var jsonPatchDocument = JsonConvert.DeserializeObject>(serialized); - var model = new Customer(); - var expectedErrorMessage = $"Invalid JsonPatch operation '{operationName}'."; + var patchDocument = new JsonPatchDocument(); // Act - var jsonPatchException = Assert.Throws(() => jsonPatchDocument.ApplyTo(model)); + var exception = Assert.Throws(() => + { + patchDocument.Add("NewInt//", 1); + }); // Assert - Assert.Equal(expectedErrorMessage, jsonPatchException.Message); + Assert.Equal( + "The provided string 'NewInt//' is an invalid path.", + exception.Message); } - private class Customer + [Fact] + public void InvalidPathWithDotShouldThrowException() { - public string Name { get; set; } + // Arrange + var patchDocument = new JsonPatchDocument(); + + // Act + var exception = Assert.Throws(() => + { + patchDocument.Add("NewInt.Test", 1); + }); + + // Assert + Assert.Equal( + "The provided string 'NewInt.Test' 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); } } -} +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyComplexNameObject.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyComplexNameObject.cs deleted file mode 100644 index a39aa8e30c..0000000000 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyComplexNameObject.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using Newtonsoft.Json; - -namespace Microsoft.AspNetCore.JsonPatch -{ - public class JsonPropertyComplexNameObject - { - [JsonProperty("foo/bar~")] - public string FooSlashBars { get; set; } - - [JsonProperty("foo/~")] - public SimpleObject FooSlashTilde { get; set; } - } -} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyObject.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyObject.cs deleted file mode 100644 index 245ae6bb65..0000000000 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyObject.cs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using Newtonsoft.Json; - -namespace Microsoft.AspNetCore.JsonPatch -{ - public class JsonPropertyObject - { - [JsonProperty("AnotherName")] - public string Name { get; set; } - } -} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyWithAnotherNameObject.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyWithAnotherNameObject.cs deleted file mode 100644 index 4581a4826d..0000000000 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyWithAnotherNameObject.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -namespace Microsoft.AspNetCore.JsonPatch -{ - public class JsonPropertyWithAnotherNameObject - { - public string AnotherName { get; set; } - } -} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyWithInheritanceObject.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyWithInheritanceObject.cs deleted file mode 100644 index 935ef275ad..0000000000 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPropertyWithInheritanceObject.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Newtonsoft.Json; - -namespace Microsoft.AspNetCore.JsonPatch -{ - public class JsonPropertyWithInheritanceObject : JsonPropertyWithInheritanceBaseObject - { - public override string Name { get; set; } - } - - public abstract class JsonPropertyWithInheritanceBaseObject - { - [JsonProperty("AnotherName")] - public abstract string Name { get; set; } - } -} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/NestedObject.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/NestedObject.cs deleted file mode 100644 index 8f0927297e..0000000000 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/NestedObject.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -namespace Microsoft.AspNetCore.JsonPatch -{ - public class NestedObject - { - public string StringProperty { get; set; } - } -} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/NestedObjectTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/NestedObjectTests.cs deleted file mode 100644 index a0b5bd7e3f..0000000000 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/NestedObjectTests.cs +++ /dev/null @@ -1,2272 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Collections.Generic; -using System.Collections.ObjectModel; -using Microsoft.AspNetCore.JsonPatch.Exceptions; -using Newtonsoft.Json; -using Xunit; - -namespace Microsoft.AspNetCore.JsonPatch -{ - public class NestedObjectTests - { - [Fact] - public void ReplacePropertyInNestedObject() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - IntegerValue = 1 - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.NestedObject.StringProperty, "B"); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal("B", doc.NestedObject.StringProperty); - } - - [Fact] - public void ReplacePropertyInNestedObjectWithSerialization() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - IntegerValue = 1 - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.NestedObject.StringProperty, "B"); - - // serialize & deserialize - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal("B", doc.NestedObject.StringProperty); - } - - [Fact] - public void ReplaceNestedObject() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - IntegerValue = 1 - }; - - var newNested = new NestedObject() { StringProperty = "B" }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.NestedObject, newNested); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal("B", doc.NestedObject.StringProperty); - } - - [Fact] - public void ReplaceNestedObjectWithSerialization() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - IntegerValue = 1 - }; - - var newNested = new NestedObject() { StringProperty = "B" }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.NestedObject, newNested); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal("B", doc.NestedObject.StringProperty); - } - - [Fact] - public void AddResultsInReplace() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - StringProperty = "A" - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.SimpleObject.StringProperty, "B"); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal("B", doc.SimpleObject.StringProperty); - } - - [Fact] - public void AddResultsInReplaceWithSerialization() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - StringProperty = "A" - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.SimpleObject.StringProperty, "B"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal("B", doc.SimpleObject.StringProperty); - } - - [Fact] - public void AddToList() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.SimpleObject.IntegerList, 4, 0); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 4, 1, 2, 3 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void AddToListWithSerialization() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.SimpleObject.IntegerList, 4, 0); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 4, 1, 2, 3 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void AddToIntegerIList() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerIList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => (List)o.SimpleObject.IntegerIList, 4, 0); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 4, 1, 2, 3 }, doc.SimpleObject.IntegerIList); - } - - [Fact] - public void AddToIntegerIListWithSerialization() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerIList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => (List)o.SimpleObject.IntegerIList, 4, 0); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 4, 1, 2, 3 }, doc.SimpleObject.IntegerIList); - } - - [Fact] - public void AddToNestedIntegerIList() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObjectIList = new List - { - new SimpleObject - { - IntegerIList = new List() { 1, 2, 3 } - } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => (List)o.SimpleObjectIList[0].IntegerIList, 4, 0); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 4, 1, 2, 3 }, doc.SimpleObjectIList[0].IntegerIList); - } - - [Fact] - public void AddToNestedIntegerIListWithSerialization() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObjectIList = new List - { - new SimpleObject - { - IntegerIList = new List() { 1, 2, 3 } - } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => (List)o.SimpleObjectIList[0].IntegerIList, 4, 0); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 4, 1, 2, 3 }, doc.SimpleObjectIList[0].IntegerIList); - } - - [Fact] - public void AddToComplextTypeListSpecifyIndex() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObjectList = new List() - { - new SimpleObject - { - StringProperty = "String1" - }, - new SimpleObject - { - StringProperty = "String2" - } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.SimpleObjectList[0].StringProperty, "ChangedString1"); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal("ChangedString1", doc.SimpleObjectList[0].StringProperty); - } - - [Fact] - public void AddToComplextTypeListSpecifyIndexWithSerialization() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObjectList = new List() - { - new SimpleObject - { - StringProperty = "String1" - }, - new SimpleObject - { - StringProperty = "String2" - } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.SimpleObjectList[0].StringProperty, "ChangedString1"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal("ChangedString1", doc.SimpleObjectList[0].StringProperty); - } - - [Fact] - public void AddToListInvalidPositionTooLarge() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.SimpleObject.IntegerList, 4, 4); - - // Act & Assert - var exception = Assert.Throws(() => { patchDoc.ApplyTo(doc); }); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "4"), - exception.Message); - - } - - [Fact] - public void AddToListInvalidPositionTooLargeWithSerialization() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.SimpleObject.IntegerList, 4, 4); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act & Assert - var exception = Assert.Throws(() => - { - deserialized.ApplyTo(doc); - }); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "4"), - exception.Message); - } - - [Fact] - public void AddToListInvalidPositionTooLarge_LogsError() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.SimpleObject.IntegerList, 4, 4); - - var logger = new TestErrorLogger(); - - patchDoc.ApplyTo(doc, logger.LogErrorMessage); - - - //Assert - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "4"), - logger.ErrorMessage); - - } - - [Fact] - public void AddToListInvalidPositionTooSmall() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.SimpleObject.IntegerList, 4, -1); - - // Act & Assert - var exception = Assert.Throws(() => { patchDoc.ApplyTo(doc); }); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), - exception.Message); - } - - [Fact] - public void AddToListInvalidPositionTooSmallWithSerialization() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.SimpleObject.IntegerList, 4, -1); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act & Assert - var exception = Assert.Throws(() => - { - deserialized.ApplyTo(doc); - }); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), - exception.Message); - } - - [Fact] - public void AddToListInvalidPositionTooSmall_LogsError() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.SimpleObject.IntegerList, 4, -1); - - var logger = new TestErrorLogger(); - - - patchDoc.ApplyTo(doc, logger.LogErrorMessage); - - - //Assert - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), - logger.ErrorMessage); - } - - [Fact] - public void AddToListAppend() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.SimpleObject.IntegerList, 4); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 1, 2, 3, 4 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void AddToListAppendWithSerialization() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.SimpleObject.IntegerList, 4); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 1, 2, 3, 4 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void Remove() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - StringProperty = "A" - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove(o => o.SimpleObject.StringProperty); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Null(doc.SimpleObject.StringProperty); - } - - [Fact] - public void RemoveWithSerialization() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - StringProperty = "A" - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove(o => o.SimpleObject.StringProperty); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Null(doc.SimpleObject.StringProperty); - } - - [Fact] - public void RemoveFromList() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove(o => o.SimpleObject.IntegerList, 2); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 1, 2 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void RemoveFromListWithSerialization() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove(o => o.SimpleObject.IntegerList, 2); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 1, 2 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void RemoveFromListInvalidPositionTooLarge() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove(o => o.SimpleObject.IntegerList, 3); - - // Act & Assert - var exception = Assert.Throws(() => { patchDoc.ApplyTo(doc); }); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "3"), - exception.Message); - } - - [Fact] - public void RemoveFromListInvalidPositionTooLargeWithSerialization() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove(o => o.SimpleObject.IntegerList, 3); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act & Assert - var exception = Assert.Throws(() => - { - deserialized.ApplyTo(doc); - }); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "3"), - exception.Message); - } - - [Fact] - public void RemoveFromListInvalidPositionTooLarge_LogsError() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove(o => o.SimpleObject.IntegerList, 3); - - var logger = new TestErrorLogger(); - - patchDoc.ApplyTo(doc, logger.LogErrorMessage); - - // Assert - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "3"), - logger.ErrorMessage); - } - - [Fact] - public void RemoveFromListInvalidPositionTooSmall() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove(o => o.SimpleObject.IntegerList, -1); - - // Act & Assert - var exception = Assert.Throws(() => { patchDoc.ApplyTo(doc); }); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), - exception.Message); - } - - [Fact] - public void RemoveFromListInvalidPositionTooSmallWithSerialization() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove(o => o.SimpleObject.IntegerList, -1); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act & Assert - var exception = Assert.Throws(() => - { - deserialized.ApplyTo(doc); - }); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), - exception.Message); - } - - [Fact] - public void RemoveFromListInvalidPositionTooSmall_LogsError() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove(o => o.SimpleObject.IntegerList, -1); - - var logger = new TestErrorLogger(); - - - patchDoc.ApplyTo(doc, logger.LogErrorMessage); - - // Assert - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), - logger.ErrorMessage); - } - - [Fact] - public void RemoveFromEndOfList() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove(o => o.SimpleObject.IntegerList); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 1, 2 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void RemoveFromEndOfListWithSerialization() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove(o => o.SimpleObject.IntegerList); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 1, 2 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void Replace() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - StringProperty = "A", - DecimalValue = 10 - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.SimpleObject.StringProperty, "B"); - patchDoc.Replace(o => o.SimpleObject.DecimalValue, 12); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal("B", doc.SimpleObject.StringProperty); - Assert.Equal(12, doc.SimpleObject.DecimalValue); - } - - [Fact] - public void Replace_DTOWithNullCheck() - { - // Arrange - var doc = new SimpleObjectWithNestedObjectWithNullCheck() - { - SimpleObjectWithNullCheck = new SimpleObjectWithNullCheck() - { - StringProperty = "A" - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.SimpleObjectWithNullCheck.StringProperty, "B"); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal("B", doc.SimpleObjectWithNullCheck.StringProperty); - } - - [Fact] - public void ReplaceWithSerialization() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - StringProperty = "A", - DecimalValue = 10 - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.SimpleObject.StringProperty, "B"); - patchDoc.Replace(o => o.SimpleObject.DecimalValue, 12); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal("B", doc.SimpleObject.StringProperty); - Assert.Equal(12, doc.SimpleObject.DecimalValue); - } - - [Fact] - public void SerializationTests() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - StringProperty = "A", - DecimalValue = 10, - DoubleValue = 10, - FloatValue = 10, - IntegerValue = 10 - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.SimpleObject.StringProperty, "B"); - patchDoc.Replace(o => o.SimpleObject.DecimalValue, 12); - patchDoc.Replace(o => o.SimpleObject.DoubleValue, 12); - patchDoc.Replace(o => o.SimpleObject.FloatValue, 12); - patchDoc.Replace(o => o.SimpleObject.IntegerValue, 12); - - // serialize & deserialize - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserizalized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserizalized.ApplyTo(doc); - - // Assert - Assert.Equal("B", doc.SimpleObject.StringProperty); - Assert.Equal(12, doc.SimpleObject.DecimalValue); - Assert.Equal(12, doc.SimpleObject.DoubleValue); - Assert.Equal(12, doc.SimpleObject.FloatValue); - Assert.Equal(12, doc.SimpleObject.IntegerValue); - } - - [Fact] - public void ReplaceInList() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.SimpleObject.IntegerList, 5, 0); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 5, 2, 3 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void ReplaceInListWithSerialization() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.SimpleObject.IntegerList, 5, 0); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 5, 2, 3 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void ReplaceFullList() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.SimpleObject.IntegerList, new List() { 4, 5, 6 }); - - // Act - patchDoc.ApplyTo(doc); - - // Arrange - Assert.Equal(new List() { 4, 5, 6 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void ReplaceFullListWithSerialiation() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.SimpleObject.IntegerList, new List() { 4, 5, 6 }); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 4, 5, 6 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void ReplaceFullListFromEnumerable() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace>(o => o.SimpleObject.IntegerList, new List() { 4, 5, 6 }); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 4, 5, 6 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void ReplaceFullListFromEnumerableWithSerialization() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace>(o => o.SimpleObject.IntegerList, new List() { 4, 5, 6 }); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 4, 5, 6 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void ReplaceFullListWithCollection() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace>(o => o.SimpleObject.IntegerList, new Collection() { 4, 5, 6 }); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 4, 5, 6 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void ReplaceFullListWithCollectionWithSerialization() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace>(o => o.SimpleObject.IntegerList, new Collection() { 4, 5, 6 }); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 4, 5, 6 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void ReplaceAtEndOfList() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.SimpleObject.IntegerList, 5); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 1, 2, 5 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void ReplaceAtEndOfListWithSerialization() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.SimpleObject.IntegerList, 5); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 1, 2, 5 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void ReplaceInListInvalidInvalidPositionTooLarge() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.SimpleObject.IntegerList, 5, 3); - - // Act & Assert - var exception = Assert.Throws(() => { patchDoc.ApplyTo(doc); }); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "3"), - exception.Message); - } - - [Fact] - public void ReplaceInListInvalidInvalidPositionTooLargeWithSerialization() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.SimpleObject.IntegerList, 5, 3); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act & Assert - var exception = Assert.Throws(() => - { - deserialized.ApplyTo(doc); - }); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "3"), - exception.Message); - } - - [Fact] - public void ReplaceInListInvalid_PositionTooLarge_LogsError() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.SimpleObject.IntegerList, 5, 3); - - var logger = new TestErrorLogger(); - - - patchDoc.ApplyTo(doc, logger.LogErrorMessage); - - - // Assert - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "3"), - logger.ErrorMessage); - } - - [Fact] - public void ReplaceInListInvalidPositionTooSmall() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.SimpleObject.IntegerList, 5, -1); - - // Act & Assert - var exception = Assert.Throws(() => { patchDoc.ApplyTo(doc); }); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), - exception.Message); - } - - [Fact] - public void ReplaceInListInvalidPositionTooSmallWithSerialization() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.SimpleObject.IntegerList, 5, -1); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act & Assert - var exception = Assert.Throws(() => { deserialized.ApplyTo(doc); }); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), - exception.Message); - } - - [Fact] - public void ReplaceInListInvalidPositionTooSmall_LogsError() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.SimpleObject.IntegerList, 5, -1); - - var logger = new TestErrorLogger(); - - - patchDoc.ApplyTo(doc, logger.LogErrorMessage); - - - // Assert - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), - logger.ErrorMessage); - } - - [Fact] - public void Copy() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - StringProperty = "A", - AnotherStringProperty = "B" - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.SimpleObject.StringProperty, o => o.SimpleObject.AnotherStringProperty); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal("A", doc.SimpleObject.AnotherStringProperty); - } - - [Fact] - public void CopyWithSerialization() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - StringProperty = "A", - AnotherStringProperty = "B" - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.SimpleObject.StringProperty, o => o.SimpleObject.AnotherStringProperty); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal("A", doc.SimpleObject.AnotherStringProperty); - } - - [Fact] - public void CopyInList() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.SimpleObject.IntegerList, 0, o => o.SimpleObject.IntegerList, 1); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 1, 1, 2, 3 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void CopyInListWithSerialization() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.SimpleObject.IntegerList, 0, o => o.SimpleObject.IntegerList, 1); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 1, 1, 2, 3 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void CopyFromListToEndOfList() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.SimpleObject.IntegerList, 0, o => o.SimpleObject.IntegerList); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 1, 2, 3, 1 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void CopyFromListToEndOfListWithSerialization() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.SimpleObject.IntegerList, 0, o => o.SimpleObject.IntegerList); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 1, 2, 3, 1 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void CopyFromListToNonList() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.SimpleObject.IntegerList, 0, o => o.SimpleObject.IntegerValue); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(1, doc.SimpleObject.IntegerValue); - } - - [Fact] - public void CopyFromListToNonListWithSerialization() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.SimpleObject.IntegerList, 0, o => o.SimpleObject.IntegerValue); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(1, doc.SimpleObject.IntegerValue); - } - - [Fact] - public void CopyFromNonListToList() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerValue = 5, - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.SimpleObject.IntegerValue, o => o.SimpleObject.IntegerList, 0); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 5, 1, 2, 3 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void CopyFromNonListToListWithSerialization() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerValue = 5, - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.SimpleObject.IntegerValue, o => o.SimpleObject.IntegerList, 0); - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 5, 1, 2, 3 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void CopyToEndOfList() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerValue = 5, - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.SimpleObject.IntegerValue, o => o.SimpleObject.IntegerList); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 1, 2, 3, 5 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void CopyToEndOfListWithSerialization() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerValue = 5, - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.SimpleObject.IntegerValue, o => o.SimpleObject.IntegerList); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 1, 2, 3, 5 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void Copy_DeepClonesObject() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - StringProperty = "A", - AnotherStringProperty = "B" - }, - InheritedObject = new InheritedObject() - { - StringProperty = "C", - AnotherStringProperty = "D" - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.InheritedObject, o => o.SimpleObject); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal("C", doc.SimpleObject.StringProperty); - Assert.Equal("D", doc.SimpleObject.AnotherStringProperty); - Assert.Equal("C", doc.InheritedObject.StringProperty); - Assert.Equal("D", doc.InheritedObject.AnotherStringProperty); - Assert.NotSame(doc.SimpleObject.StringProperty, doc.InheritedObject.StringProperty); - } - - [Fact] - public void Copy_KeepsObjectType() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject(), - InheritedObject = new InheritedObject() - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.InheritedObject, o => o.SimpleObject); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(typeof(InheritedObject), doc.SimpleObject.GetType()); - } - - [Fact] - public void Copy_BreaksObjectReference() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject(), - InheritedObject = new InheritedObject() - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.InheritedObject, o => o.SimpleObject); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.NotSame(doc.SimpleObject, doc.InheritedObject); - } - - [Fact] - public void Move() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - StringProperty = "A", - AnotherStringProperty = "B" - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.SimpleObject.StringProperty, o => o.SimpleObject.AnotherStringProperty); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal("A", doc.SimpleObject.AnotherStringProperty); - Assert.Null(doc.SimpleObject.StringProperty); - } - - [Fact] - public void MoveWithSerialization() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - StringProperty = "A", - AnotherStringProperty = "B" - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.SimpleObject.StringProperty, o => o.SimpleObject.AnotherStringProperty); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal("A", doc.SimpleObject.AnotherStringProperty); - Assert.Null(doc.SimpleObject.StringProperty); - } - - [Fact] - public void Move_KeepsObjectReference() - { - // Arrange - var sDto = new SimpleObject() - { - StringProperty = "A", - AnotherStringProperty = "B" - }; - var iDto = new InheritedObject() - { - StringProperty = "C", - AnotherStringProperty = "D" - }; - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = sDto, - InheritedObject = iDto - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.InheritedObject, o => o.SimpleObject); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal("C", doc.SimpleObject.StringProperty); - Assert.Equal("D", doc.SimpleObject.AnotherStringProperty); - Assert.Same(iDto, doc.SimpleObject); - Assert.Null(doc.InheritedObject); - } - - [Fact] - public void Move_KeepsObjectReferenceWithSerialization() - { - // Arrange - var sDto = new SimpleObject() - { - StringProperty = "A", - AnotherStringProperty = "B" - }; - var iDto = new InheritedObject() - { - StringProperty = "C", - AnotherStringProperty = "D" - }; - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = sDto, - InheritedObject = iDto - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.InheritedObject, o => o.SimpleObject); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal("C", doc.SimpleObject.StringProperty); - Assert.Equal("D", doc.SimpleObject.AnotherStringProperty); - Assert.Same(iDto, doc.SimpleObject); - Assert.Null(doc.InheritedObject); - } - - [Fact] - public void MoveInList() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.SimpleObject.IntegerList, 0, o => o.SimpleObject.IntegerList, 1); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 2, 1, 3 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void MoveInListWithSerialization() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.SimpleObject.IntegerList, 0, o => o.SimpleObject.IntegerList, 1); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 2, 1, 3 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void Move_KeepsObjectReferenceInList() - { - // Arrange - var sDto1 = new SimpleObject() { IntegerValue = 1 }; - var sDto2 = new SimpleObject() { IntegerValue = 2 }; - var sDto3 = new SimpleObject() { IntegerValue = 3 }; - var doc = new SimpleObjectWithNestedObject() - { - SimpleObjectList = new List() { - sDto1, - sDto2, - sDto3 - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.SimpleObjectList, 0, o => o.SimpleObjectList, 1); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { sDto2, sDto1, sDto3 }, doc.SimpleObjectList); - Assert.Equal(2, doc.SimpleObjectList[0].IntegerValue); - Assert.Equal(1, doc.SimpleObjectList[1].IntegerValue); - Assert.Same(sDto2, doc.SimpleObjectList[0]); - Assert.Same(sDto1, doc.SimpleObjectList[1]); - } - - [Fact] - public void Move_KeepsObjectReferenceInListWithSerialization() - { - // Arrange - var sDto1 = new SimpleObject() { IntegerValue = 1 }; - var sDto2 = new SimpleObject() { IntegerValue = 2 }; - var sDto3 = new SimpleObject() { IntegerValue = 3 }; - var doc = new SimpleObjectWithNestedObject() - { - SimpleObjectList = new List() { - sDto1, - sDto2, - sDto3 - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.SimpleObjectList, 0, o => o.SimpleObjectList, 1); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { sDto2, sDto1, sDto3 }, doc.SimpleObjectList); - Assert.Equal(2, doc.SimpleObjectList[0].IntegerValue); - Assert.Equal(1, doc.SimpleObjectList[1].IntegerValue); - Assert.Same(sDto2, doc.SimpleObjectList[0]); - Assert.Same(sDto1, doc.SimpleObjectList[1]); - } - - [Fact] - public void MoveFromListToEndOfList() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.SimpleObject.IntegerList, 0, o => o.SimpleObject.IntegerList); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 2, 3, 1 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void MoveFromListToEndOfListWithSerialization() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.SimpleObject.IntegerList, 0, o => o.SimpleObject.IntegerList); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 2, 3, 1 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void MoveFomListToNonList() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.SimpleObject.IntegerList, 0, o => o.SimpleObject.IntegerValue); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 2, 3 }, doc.SimpleObject.IntegerList); - Assert.Equal(1, doc.SimpleObject.IntegerValue); - } - - [Fact] - public void MoveFomListToNonListWithSerialization() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.SimpleObject.IntegerList, 0, o => o.SimpleObject.IntegerValue); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 2, 3 }, doc.SimpleObject.IntegerList); - Assert.Equal(1, doc.SimpleObject.IntegerValue); - } - - [Fact] - public void MoveFomListToNonListBetweenHierarchy() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.SimpleObject.IntegerList, 0, o => o.IntegerValue); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 2, 3 }, doc.SimpleObject.IntegerList); - Assert.Equal(1, doc.IntegerValue); - } - - [Fact] - public void MoveFomListToNonListBetweenHierarchyWithSerialization() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.SimpleObject.IntegerList, 0, o => o.IntegerValue); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 2, 3 }, doc.SimpleObject.IntegerList); - Assert.Equal(1, doc.IntegerValue); - } - - [Fact] - public void MoveFromNonListToList() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerValue = 5, - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.SimpleObject.IntegerValue, o => o.SimpleObject.IntegerList, 0); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(0, doc.IntegerValue); - Assert.Equal(new List() { 5, 1, 2, 3 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void MoveFromNonListToListWithSerialization() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerValue = 5, - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.SimpleObject.IntegerValue, o => o.SimpleObject.IntegerList, 0); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(0, doc.IntegerValue); - Assert.Equal(new List() { 5, 1, 2, 3 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void MoveToEndOfList() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerValue = 5, - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.SimpleObject.IntegerValue, o => o.SimpleObject.IntegerList); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(0, doc.IntegerValue); - Assert.Equal(new List() { 1, 2, 3, 5 }, doc.SimpleObject.IntegerList); - } - - [Fact] - public void MoveToEndOfListWithSerialization() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerValue = 5, - IntegerList = new List() { 1, 2, 3 } - } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.SimpleObject.IntegerValue, o => o.SimpleObject.IntegerList); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(0, doc.IntegerValue); - Assert.Equal(new List() { 1, 2, 3, 5 }, doc.SimpleObject.IntegerList); - } - } -} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs deleted file mode 100644 index c1d005e897..0000000000 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/ObjectAdapterTests.cs +++ /dev/null @@ -1,2331 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using Microsoft.AspNetCore.JsonPatch.Exceptions; -using Newtonsoft.Json; -using Xunit; - -namespace Microsoft.AspNetCore.JsonPatch.Adapters -{ - public class ObjectAdapterTests - { - [Fact] - public void AddResultsShouldReplace() - { - // Arrange - var doc = new SimpleObject() - { - StringProperty = "A" - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.StringProperty, "B"); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal("B", doc.StringProperty); - } - - [Fact] - public void AddResultsShouldReplaceWithSerialization() - { - // Arrange - var doc = new SimpleObject() - { - StringProperty = "A" - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.StringProperty, "B"); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal("B", doc.StringProperty); - } - - [Fact] - public void AddToList() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.IntegerList, 4, 0); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 4, 1, 2, 3 }, doc.IntegerList); - } - - [Fact] - public void AddToListWithSerialization() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.IntegerList, 4, 0); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 4, 1, 2, 3 }, doc.IntegerList); - } - - [Fact] - public void AddToIntegerIList() - { - // Arrange - var doc = new SimpleObject() - { - IntegerIList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.IntegerIList, 4, 0); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 4, 1, 2, 3 }, doc.IntegerIList); - } - - [Fact] - public void AddToIntegerIListWithSerialization() - { - // Arrange - var doc = new SimpleObject() - { - IntegerIList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.IntegerIList, 4, 0); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 4, 1, 2, 3 }, doc.IntegerIList); - } - - [Fact] - public void AddToListInvalidPositionTooLarge() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.IntegerList, 4, 4); - - // Act & Assert - var exception = Assert.Throws(() => { patchDoc.ApplyTo(doc); }); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "4"), - exception.Message); - } - - [Fact] - public void AddToListInvalidPositionTooLargeWithSerialization() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.IntegerList, 4, 4); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act & Assert - var exception = Assert.Throws(() => { deserialized.ApplyTo(doc); }); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "4"), - exception.Message); - } - - [Fact] - public void AddToListInvalidPositionTooLarge_LogsError() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.IntegerList, 4, 4); - - var logger = new TestErrorLogger(); - - patchDoc.ApplyTo(doc, logger.LogErrorMessage); - - - // Assert - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "4"), - logger.ErrorMessage); - } - - [Fact] - public void AddToListAtBeginning() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.IntegerList, 4, 0); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 4, 1, 2, 3 }, doc.IntegerList); - } - - [Fact] - public void AddToListAtBeginningWithSerialization() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.IntegerList, 4, 0); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 4, 1, 2, 3 }, doc.IntegerList); - } - - [Fact] - public void AddToListInvalidPositionTooSmall() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.IntegerList, 4, -1); - - // Act & Assert - var exception = Assert.Throws(() => { patchDoc.ApplyTo(doc); }); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), - exception.Message); - } - - [Fact] - public void AddToListInvalidPositionTooSmallWithSerialization() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.IntegerList, 4, -1); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act & Assert - var exception = Assert.Throws(() => { deserialized.ApplyTo(doc); }); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), - exception.Message); - } - - [Fact] - public void AddToListInvalidPositionTooSmall_LogsError() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.IntegerList, 4, -1); - - var logger = new TestErrorLogger(); - - patchDoc.ApplyTo(doc, logger.LogErrorMessage); - - // Assert - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), - logger.ErrorMessage); - } - - [Fact] - public void AddToListAppend() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.IntegerList, 4); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 1, 2, 3, 4 }, doc.IntegerList); - } - - [Fact] - public void AddToListAppendWithSerialization() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.IntegerList, 4); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 1, 2, 3, 4 }, doc.IntegerList); - } - - [Fact] - public void Remove() - { - // Arrange - var doc = new SimpleObject() - { - StringProperty = "A" - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove(o => o.StringProperty); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Null(doc.StringProperty); - } - - [Fact] - public void RemoveWithSerialization() - { - // Arrange - var doc = new SimpleObject() - { - StringProperty = "A" - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove(o => o.StringProperty); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Null(doc.StringProperty); - } - - [Fact] - public void RemoveFromList() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove(o => o.IntegerList, 2); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 1, 2 }, doc.IntegerList); - } - - [Fact] - public void RemoveFromListWithSerialization() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove(o => o.IntegerList, 2); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 1, 2 }, doc.IntegerList); - } - - [Fact] - public void RemoveFromListInvalidPositionTooLarge() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove(o => o.IntegerList, 3); - - // Act & Assert - var exception = Assert.Throws(() => { patchDoc.ApplyTo(doc); }); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "3"), - exception.Message); - } - - [Fact] - public void RemoveFromListInvalidPositionTooLargeWithSerialization() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove(o => o.IntegerList, 3); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act & Assert - var exception = Assert.Throws(() => { deserialized.ApplyTo(doc); }); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "3"), - exception.Message); - } - - [Fact] - public void RemoveFromListInvalidPositionTooLarge_LogsError() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove(o => o.IntegerList, 3); - - var logger = new TestErrorLogger(); - - patchDoc.ApplyTo(doc, logger.LogErrorMessage); - - - // Assert - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "3"), - logger.ErrorMessage); - } - - [Fact] - public void RemoveFromListInvalidPositionTooSmall() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove(o => o.IntegerList, -1); - - // Act & Assert - var exception = Assert.Throws(() => { patchDoc.ApplyTo(doc); }); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), - exception.Message); - } - - [Fact] - public void RemoveFromListInvalidPositionTooSmallWithSerialization() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove(o => o.IntegerList, -1); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act & Assert - var exception = Assert.Throws(() => { deserialized.ApplyTo(doc); }); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), - exception.Message); - } - - [Fact] - public void RemoveFromListInvalidPositionTooSmall_LogsError() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove(o => o.IntegerList, -1); - - var logger = new TestErrorLogger(); - - - patchDoc.ApplyTo(doc, logger.LogErrorMessage); - - - // Assert - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), - logger.ErrorMessage); - } - - [Fact] - public void RemoveFromEndOfList() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove(o => o.IntegerList); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 1, 2 }, doc.IntegerList); - } - - [Fact] - public void RemoveFromEndOfListWithSerialization() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove(o => o.IntegerList); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 1, 2 }, doc.IntegerList); - } - - [Fact] - public void Replace() - { - // Arrange - var doc = new SimpleObject() - { - StringProperty = "A", - DecimalValue = 10 - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.StringProperty, "B"); - - patchDoc.Replace(o => o.DecimalValue, 12); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal("B", doc.StringProperty); - Assert.Equal(12, doc.DecimalValue); - } - - [Fact] - public void Replace_DTOWithNullCheck() - { - // Arrange - var doc = new SimpleObjectWithNullCheck() - { - StringProperty = "A", - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.StringProperty, "B"); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal("B", doc.StringProperty); - } - - [Fact] - public void ReplaceWithSerialization() - { - // Arrange - var doc = new SimpleObject() - { - StringProperty = "A", - DecimalValue = 10 - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.StringProperty, "B"); - - patchDoc.Replace(o => o.DecimalValue, 12); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal("B", doc.StringProperty); - Assert.Equal(12, doc.DecimalValue); - } - - [Fact] - public void SerializationMustNotIncudeEnvelope() - { - // Arrange - var doc = new SimpleObject() - { - StringProperty = "A", - DecimalValue = 10, - DoubleValue = 10, - FloatValue = 10, - IntegerValue = 10 - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.StringProperty, "B"); - patchDoc.Replace(o => o.DecimalValue, 12); - patchDoc.Replace(o => o.DoubleValue, 12); - patchDoc.Replace(o => o.FloatValue, 12); - patchDoc.Replace(o => o.IntegerValue, 12); - - // Act - var serialized = JsonConvert.SerializeObject(patchDoc); - - // Assert - Assert.DoesNotContain("operations", serialized); - Assert.DoesNotContain("Operations", serialized); - } - - [Fact] - public void Deserialization_Successful_ForValidJsonPatchDocument() - { - // Arrange - var doc = new SimpleObject() - { - StringProperty = "A", - DecimalValue = 10, - DoubleValue = 10, - FloatValue = 10, - IntegerValue = 10 - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.StringProperty, "B"); - patchDoc.Replace(o => o.DecimalValue, 12); - patchDoc.Replace(o => o.DoubleValue, 12); - patchDoc.Replace(o => o.FloatValue, 12); - patchDoc.Replace(o => o.IntegerValue, 12); - - // default: no envelope - var serialized = JsonConvert.SerializeObject(patchDoc); - - // 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 & Assert - var exception = Assert.Throws(() => - { - var deserialized - = JsonConvert.DeserializeObject(serialized); - }); - - 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 & Assert - var exception = Assert.Throws(() => - { - var deserialized - = JsonConvert.DeserializeObject>(serialized); - }); - - Assert.Equal("The JSON patch document was malformed and could not be parsed.", exception.Message); - } - - [Fact] - public void SerializationTests() - { - // Arrange - var doc = new SimpleObject() - { - StringProperty = "A", - DecimalValue = 10, - DoubleValue = 10, - FloatValue = 10, - IntegerValue = 10 - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.StringProperty, "B"); - patchDoc.Replace(o => o.DecimalValue, 12); - patchDoc.Replace(o => o.DoubleValue, 12); - patchDoc.Replace(o => o.FloatValue, 12); - patchDoc.Replace(o => o.IntegerValue, 12); - - // serialize & deserialize - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserizalized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserizalized.ApplyTo(doc); - - // Assert - Assert.Equal("B", doc.StringProperty); - Assert.Equal(12, doc.DecimalValue); - Assert.Equal(12, doc.DoubleValue); - Assert.Equal(12, doc.FloatValue); - Assert.Equal(12, doc.IntegerValue); - } - - [Fact] - public void SerializeAndReplaceGuidTest() - { - // Arrange - var doc = new SimpleObject() - { - GuidValue = Guid.NewGuid() - }; - - var newGuid = Guid.NewGuid(); - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.GuidValue, newGuid); - - // serialize & deserialize - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserizalized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserizalized.ApplyTo(doc); - - // Assert - Assert.Equal(newGuid, doc.GuidValue); - } - - [Fact] - public void SerializeAndReplaceNestedObjectTest() - { - // Arrange - var doc = new SimpleObjectWithNestedObject() - { - SimpleObject = new SimpleObject() - { - IntegerValue = 5, - IntegerList = new List() { 1, 2, 3 } - } - }; - - var newDTO = new SimpleObject() - { - DoubleValue = 1 - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.SimpleObject, newDTO); - - // serialize & deserialize - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(1, doc.SimpleObject.DoubleValue); - Assert.Equal(0, doc.SimpleObject.IntegerValue); - Assert.Null(doc.SimpleObject.IntegerList); - } - - [Fact] - public void ReplaceInList() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.IntegerList, 5, 0); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 5, 2, 3 }, doc.IntegerList); - } - - [Fact] - public void ReplaceInListWithSerialization() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.IntegerList, 5, 0); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 5, 2, 3 }, doc.IntegerList); - } - - [Fact] - public void ReplaceFullList() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace>(o => o.IntegerList, new List() { 4, 5, 6 }); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 4, 5, 6 }, doc.IntegerList); - } - - [Fact] - public void ReplaceFullListWithSerialization() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace>(o => o.IntegerList, new List() { 4, 5, 6 }); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 4, 5, 6 }, doc.IntegerList); - } - - [Fact] - public void ReplaceFullListFromEnumerable() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace>(o => o.IntegerList, new List() { 4, 5, 6 }); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 4, 5, 6 }, doc.IntegerList); - } - - [Fact] - public void ReplaceFullListFromEnumerableWithSerialization() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace>(o => o.IntegerList, new List() { 4, 5, 6 }); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 4, 5, 6 }, doc.IntegerList); - } - - [Fact] - public void ReplaceFullListWithCollection() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace>(o => o.IntegerList, new Collection() { 4, 5, 6 }); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 4, 5, 6 }, doc.IntegerList); - } - - [Fact] - public void ReplaceFullListWithCollectionWithSerialization() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace>(o => o.IntegerList, new Collection() { 4, 5, 6 }); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 4, 5, 6 }, doc.IntegerList); - } - - [Fact] - public void ReplaceAtEndOfList() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.IntegerList, 5); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 1, 2, 5 }, doc.IntegerList); - } - - [Fact] - public void ReplaceAtEndOfListWithSerialization() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.IntegerList, 5); - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 1, 2, 5 }, doc.IntegerList); - } - - [Fact] - public void ReplaceInListInvalidInvalidPositionTooLarge() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.IntegerList, 5, 3); - - // Act & Assert - var exception = Assert.Throws(() => - { - patchDoc.ApplyTo(doc); - }); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "3"), - exception.Message); - } - - [Fact] - public void ReplaceInListInvalidInvalidPositionTooLargeWithSerialization() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.IntegerList, 5, 3); - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act & Assert - var exception = Assert.Throws(() => - { - deserialized.ApplyTo(doc); - }); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "3"), - exception.Message); - } - - [Fact] - public void ReplaceInListInvalidPositionTooSmall() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.IntegerList, 5, -1); - - // Act & Assert - var exception = Assert.Throws(() => - { - patchDoc.ApplyTo(doc); - }); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), - exception.Message); - } - - [Fact] - public void ReplaceInListInvalidPositionTooSmallWithSerialization() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Replace(o => o.IntegerList, 5, -1); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act & Assert - var exception = Assert.Throws(() => - { - deserialized.ApplyTo(doc); - }); - Assert.Equal( - string.Format("The index value provided by path segment '{0}' is out of bounds of the array size.", "-1"), - exception.Message); - } - - [Fact] - public void Copy() - { - // Arrange - var doc = new SimpleObject() - { - StringProperty = "A", - AnotherStringProperty = "B" - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.StringProperty, o => o.AnotherStringProperty); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal("A", doc.AnotherStringProperty); - } - - [Fact] - public void CopyWithSerialization() - { - // Arrange - var doc = new SimpleObject() - { - StringProperty = "A", - AnotherStringProperty = "B" - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.StringProperty, o => o.AnotherStringProperty); - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal("A", doc.AnotherStringProperty); - } - - [Fact] - public void CopyInList() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.IntegerList, 0, o => o.IntegerList, 1); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 1, 1, 2, 3 }, doc.IntegerList); - } - - [Fact] - public void CopyInListWithSerialization() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.IntegerList, 0, o => o.IntegerList, 1); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 1, 1, 2, 3 }, doc.IntegerList); - } - - [Fact] - public void CopyFromListToEndOfList() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.IntegerList, 0, o => o.IntegerList); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 1, 2, 3, 1 }, doc.IntegerList); - } - - [Fact] - public void CopyFromListToEndOfListWithSerialization() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.IntegerList, 0, o => o.IntegerList); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 1, 2, 3, 1 }, doc.IntegerList); - } - - [Fact] - public void CopyFromListToNonList() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.IntegerList, 0, o => o.IntegerValue); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(1, doc.IntegerValue); - } - - [Fact] - public void CopyFromListToNonListWithSerialization() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.IntegerList, 0, o => o.IntegerValue); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(1, doc.IntegerValue); - } - - [Fact] - public void CopyFromNonListToList() - { - // Arrange - var doc = new SimpleObject() - { - IntegerValue = 5, - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.IntegerValue, o => o.IntegerList, 0); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 5, 1, 2, 3 }, doc.IntegerList); - } - - [Fact] - public void CopyFromNonListToListWithSerialization() - { - // Arrange - var doc = new SimpleObject() - { - IntegerValue = 5, - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.IntegerValue, o => o.IntegerList, 0); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 5, 1, 2, 3 }, doc.IntegerList); - } - - [Fact] - public void CopyToEndOfList() - { - // Arrange - var doc = new SimpleObject() - { - IntegerValue = 5, - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.IntegerValue, o => o.IntegerList); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 1, 2, 3, 5 }, doc.IntegerList); - } - - [Fact] - public void CopyToEndOfListWithSerialization() - { - // Arrange - var doc = new SimpleObject() - { - IntegerValue = 5, - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Copy(o => o.IntegerValue, o => o.IntegerList); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 1, 2, 3, 5 }, doc.IntegerList); - } - - [Fact] - public void Move() - { - // Arrange - var doc = new SimpleObject() - { - StringProperty = "A", - AnotherStringProperty = "B" - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.StringProperty, o => o.AnotherStringProperty); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal("A", doc.AnotherStringProperty); - Assert.Null(doc.StringProperty); - } - - [Fact] - public void MoveWithSerialization() - { - // Arrange - var doc = new SimpleObject() - { - StringProperty = "A", - AnotherStringProperty = "B" - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.StringProperty, o => o.AnotherStringProperty); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal("A", doc.AnotherStringProperty); - Assert.Null(doc.StringProperty); - } - - [Fact] - public void MoveInList() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.IntegerList, 0, o => o.IntegerList, 1); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 2, 1, 3 }, doc.IntegerList); - } - - [Fact] - public void MoveInListWithSerialization() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.IntegerList, 0, o => o.IntegerList, 1); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 2, 1, 3 }, doc.IntegerList); - } - - [Fact] - public void MoveFromListToEndOfList() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.IntegerList, 0, o => o.IntegerList); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 2, 3, 1 }, doc.IntegerList); - } - - [Fact] - public void MoveFromListToEndOfListWithSerialization() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.IntegerList, 0, o => o.IntegerList); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 2, 3, 1 }, doc.IntegerList); - } - - [Fact] - public void MoveFomListToNonList() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.IntegerList, 0, o => o.IntegerValue); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 2, 3 }, doc.IntegerList); - Assert.Equal(1, doc.IntegerValue); - } - - [Fact] - public void MoveFomListToNonListWithSerialization() - { - // Arrange - var doc = new SimpleObject() - { - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.IntegerList, 0, o => o.IntegerValue); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 2, 3 }, doc.IntegerList); - Assert.Equal(1, doc.IntegerValue); - } - - [Fact] - public void MoveFromNonListToList() - { - // Arrange - var doc = new SimpleObject() - { - IntegerValue = 5, - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.IntegerValue, o => o.IntegerList, 0); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(0, doc.IntegerValue); - Assert.Equal(new List() { 5, 1, 2, 3 }, doc.IntegerList); - } - - [Fact] - public void MoveFromNonListToListWithSerialization() - { - // Arrange - var doc = new SimpleObject() - { - IntegerValue = 5, - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.IntegerValue, o => o.IntegerList, 0); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(0, doc.IntegerValue); - Assert.Equal(new List() { 5, 1, 2, 3 }, doc.IntegerList); - } - - [Fact] - public void MoveToEndOfList() - { - // Arrange - var doc = new SimpleObject() - { - IntegerValue = 5, - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.IntegerValue, o => o.IntegerList); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(0, doc.IntegerValue); - Assert.Equal(new List() { 1, 2, 3, 5 }, doc.IntegerList); - } - - [Fact] - public void MoveToEndOfListWithSerialization() - { - // Arrange - var doc = new SimpleObject() - { - IntegerValue = 5, - IntegerList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Move(o => o.IntegerValue, o => o.IntegerList); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Equal(0, doc.IntegerValue); - Assert.Equal(new List() { 1, 2, 3, 5 }, doc.IntegerList); - } - - private class Class6 - { - public IDictionary DictionaryOfStringToInteger { get; } = new Dictionary(); - } - - [Fact] - public void Add_WhenDictionary_ValueIsNonObject_Succeeds() - { - // Arrange - var model = new Class6(); - 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 Remove_WhenDictionary_ValueIsNonObject_Succeeds() - { - // Arrange - var model = new Class6(); - 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 Replace_WhenDictionary_ValueIsNonObject_Succeeds() - { - // Arrange - var model = new Class6(); - 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"]); - } - - private class Customer - { - public string Name { get; set; } - public Address Address { get; set; } - } - - private class Address - { - public string City { get; set; } - } - - private class Class8 - { - public IDictionary DictionaryOfStringToCustomer { get; } = new Dictionary(); - } - - [Fact] - public void Replace_WhenDictionary_ValueAPocoType_Succeeds() - { - // Arrange - var key1 = "key1"; - var value1 = new Customer() { Name = "Jamesss" }; - var key2 = "key2"; - var value2 = new Customer() { Name = "Mike" }; - var model = new Class8(); - 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 Replace_WhenDictionary_ValueAPocoType_Succeeds_WithSerialization() - { - // Arrange - var key1 = "key1"; - var value1 = new Customer() { Name = "Jamesss" }; - var key2 = "key2"; - var value2 = new Customer() { Name = "Mike" }; - var model = new Class8(); - model.DictionaryOfStringToCustomer[key1] = value1; - model.DictionaryOfStringToCustomer[key2] = value2; - var patchDocument = new JsonPatchDocument(); - patchDocument.Replace($"/DictionaryOfStringToCustomer/{key1}/Name", "James"); - var serialized = JsonConvert.SerializeObject(patchDocument); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // 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 Replace_WhenDictionary_ValueAPocoType_WithEscaping_Succeeds() - { - // Arrange - var key1 = "Foo/Name"; - var value1 = new Customer() { Name = "Jamesss" }; - var key2 = "Foo"; - var value2 = new Customer() { Name = "Mike" }; - var model = new Class8(); - model.DictionaryOfStringToCustomer[key1] = value1; - model.DictionaryOfStringToCustomer[key2] = value2; - var patchDocument = new JsonPatchDocument(); - patchDocument.Replace($"/DictionaryOfStringToCustomer/Foo~1Name/Name", "James"); - - // Act - patchDocument.ApplyTo(model); - - // Assert - Assert.Equal(2, model.DictionaryOfStringToCustomer.Count); - var actualValue1 = model.DictionaryOfStringToCustomer[key1]; - var actualValue2 = model.DictionaryOfStringToCustomer[key2]; - Assert.NotNull(actualValue1); - Assert.Equal("James", actualValue1.Name); - Assert.Equal("Mike", actualValue2.Name); - - } - - [Fact] - public void Replace_DeepNested_DictionaryValue_Succeeds() - { - // Arrange - var key1 = "key1"; - var value1 = new Customer() { Name = "Jamesss" }; - var key2 = "key2"; - var value2 = new Customer() { Name = "Mike" }; - var model = new Class8(); - 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 Replace_DeepNested_DictionaryValue_Succeeds_WithSerialization() - { - // Arrange - var key1 = "key1"; - var value1 = new Customer() { Name = "James", Address = new Address { City = "Redmond" } }; - var key2 = "key2"; - var value2 = new Customer() { Name = "Mike", Address = new Address { City = "Seattle" } }; - var model = new Class8(); - model.DictionaryOfStringToCustomer[key1] = value1; - model.DictionaryOfStringToCustomer[key2] = value2; - var patchDocument = new JsonPatchDocument(); - patchDocument.Replace($"/DictionaryOfStringToCustomer/{key1}/Address/City", "Bellevue"); - var serialized = JsonConvert.SerializeObject(patchDocument); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - patchDocument.ApplyTo(model); - - // Assert - Assert.Equal(2, model.DictionaryOfStringToCustomer.Count); - var actualValue1 = model.DictionaryOfStringToCustomer[key1]; - Assert.NotNull(actualValue1); - Assert.Equal("James", actualValue1.Name); - var address = actualValue1.Address; - Assert.NotNull(address); - Assert.Equal("Bellevue", address.City); - } - - class Class9 - { - public List StringList { get; set; } = new List(); - } - - [Fact] - public void AddToNonIntegerListAtEnd() - { - // Arrange - var model = new Class9() - { - StringList = new List() - }; - model.StringList.Add("string1"); - model.StringList.Add("string2"); - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("/StringList/0", "string3"); - - // Act - patchDoc.ApplyTo(model); - - // Assert - Assert.Equal(new List() { "string3", "string1", "string2" }, model.StringList); - } - - [Fact] - public void AddMember_OnPOCO_WithNullPropertyValue_ShouldAddPropertyValue() - { - // Arrange - var doc = new SimpleObject() - { - StringProperty = null - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.StringProperty, "B"); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal("B", doc.StringProperty); - } - - private class Class1 - { - public IDictionary USStates { get; set; } = new Dictionary(); - } - - [Fact] - public void AddMember_OnDictionaryProperty_ShouldAddKeyValueMember() - { - // Arrange - var expected = "Washington"; - var model = new Class1(); - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("/USStates/WA", expected); - - // Act - patchDoc.ApplyTo(model); - - // Assert - Assert.Equal(1, model.USStates.Count); - Assert.Equal(expected, model.USStates["WA"]); - } - - [Fact] - public void AddMember_OnDictionaryProperty_ShouldAddKeyValueMember_WithSerialization() - { - // Arrange - var expected = "Washington"; - var model = new Class1(); - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("/USStates/WA", expected); - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(model); - - // Assert - Assert.Equal(1, model.USStates.Count); - Assert.Equal(expected, model.USStates["WA"]); - } - - private class Class2 - { - public Class1 Class1Property { get; set; } = new Class1(); - } - - [Fact] - public void AddMember_OnDictionaryPropertyDeeplyNested_ShouldAddKeyValueMember() - { - // Arrange - var expected = "Washington"; - var model = new Class2(); - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("/Class1Property/USStates/WA", expected); - - // Act - patchDoc.ApplyTo(model); - - // Assert - Assert.Equal(1, model.Class1Property.USStates.Count); - Assert.Equal(expected, model.Class1Property.USStates["WA"]); - } - - [Fact] - public void AddMember_OnDictionaryPropertyDeeplyNested_ShouldAddKeyValueMember_WithSerialization() - { - // Arrange - var expected = "Washington"; - var model = new Class2(); - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("/Class1Property/USStates/WA", expected); - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(model); - - // Assert - Assert.Equal(1, model.Class1Property.USStates.Count); - Assert.Equal(expected, model.Class1Property.USStates["WA"]); - } - - [Fact] - public void AddMember_OnDictionaryObjectDirectly_ShouldAddKeyValueMember() - { - // Arrange - var expected = "Washington"; - var model = new Dictionary(); - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("/WA", expected); - - // Act - patchDoc.ApplyTo(model); - - // Assert - Assert.Single(model); - Assert.Equal(expected, model["WA"]); - } - - [Fact] - public void AddMember_OnDictionaryObjectDirectly_ShouldAddKeyValueMember_WithSerialization() - { - // Arrange - var expected = "Washington"; - var model = new Dictionary(); - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("/WA", expected); - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>>(serialized); - - // Act - deserialized.ApplyTo(model); - - // Assert - Assert.Single(model); - Assert.Equal(expected, model["WA"]); - } - - [Fact] - public void AddElement_ToListDirectly_ShouldAppendValue() - { - // Arrange - var model = new List() { 1, 2, 3 }; - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("/-", value: 4); - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>>(serialized); - - // Act - deserialized.ApplyTo(model); - - // Assert - Assert.Equal(new List() { 1, 2, 3, 4 }, model); - } - - [Fact] - public void AddElement_ToListDirectly_ShouldAppendValue_WithSerialization() - { - // Arrange - var model = new List() { 1, 2, 3 }; - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("/-", value: 4); - - // Act - patchDoc.ApplyTo(model); - - // Assert - Assert.Equal(new List() { 1, 2, 3, 4 }, model); - } - - [Fact] - public void AddElement_ToListDirectly_ShouldAddValue_AtSuppliedPosition() - { - // Arrange - var model = new List() { 1, 2, 3 }; - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("/0", value: 4); - - // Act - patchDoc.ApplyTo(model); - - // Assert - Assert.Equal(new List() { 4, 1, 2, 3 }, model); - } - - [Fact] - public void AddElement_ToListDirectly_ShouldAddValue_AtSuppliedPosition_WithSerialization() - { - // Arrange - var model = new List() { 1, 2, 3 }; - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("/0", value: 4); - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>>(serialized); - - // Act - deserialized.ApplyTo(model); - - // Assert - Assert.Equal(new List() { 4, 1, 2, 3 }, model); - } - - class ListOnDictionary - { - public IDictionary> NamesAndBadgeIds { get; set; } = new Dictionary>(); - } - - [Fact] - public void AddElement_ToList_OnDictionary_ShouldAddValue_AtSuppliedPosition() - { - // Arrange - var model = new ListOnDictionary(); - model.NamesAndBadgeIds["James"] = new List(); - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("/NamesAndBadgeIds/James/-", 200); - - // Act - patchDoc.ApplyTo(model); - - // Assert - var list = model.NamesAndBadgeIds["James"]; - Assert.NotNull(list); - Assert.Equal(new List() { 200 }, list); - } - - [Fact] - public void AddElement_ToList_OnPOCO_ShouldAddValue_AtSuppliedPosition() - { - // Arrange - var doc = new SimpleObject() - { - IntegerIList = new List() { 1, 2, 3 } - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.IntegerIList, 4, 0); - - // Act - patchDoc.ApplyTo(doc); - - // Assert - Assert.Equal(new List() { 4, 1, 2, 3 }, doc.IntegerIList); - } - - class Class3 - { - public SimpleObject SimpleObjectProperty { get; set; } = new SimpleObject(); - } - - [Fact] - public void AddElement_ToDeeplyNestedListProperty_OnPOCO_ShouldAddValue_AtSuppliedPosition() - { - // Arrange - var model = new Class3() - { - SimpleObjectProperty = new SimpleObject() - { - IntegerIList = new List() { 1, 2, 3 } - } - }; - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.SimpleObjectProperty.IntegerIList, value: 4, position: 0); - - // Act - patchDoc.ApplyTo(model); - - // Assert - Assert.Equal(new List() { 4, 1, 2, 3 }, model.SimpleObjectProperty.IntegerIList); - } - - [Fact] - public void AddElement_ToDeeplyNestedListProperty_OnPOCO_ShouldAddValue_AtSuppliedPosition_WithSerialization() - { - // Arrange - var model = new Class3() - { - SimpleObjectProperty = new SimpleObject() - { - IntegerIList = new List() { 1, 2, 3 } - } - }; - var patchDoc = new JsonPatchDocument(); - patchDoc.Add(o => o.SimpleObjectProperty.IntegerIList, value: 4, position: 0); - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(model); - - // Assert - Assert.Equal(new List() { 4, 1, 2, 3 }, model.SimpleObjectProperty.IntegerIList); - } - - class Class4 - { - public int IntegerProperty { get; set; } - } - - [Fact] - public void Remove_OnNonReferenceType_POCOProperty_ShouldSetDefaultValue() - { - // Arrange - var model = new Class4() - { - IntegerProperty = 10 - }; - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove(o => o.IntegerProperty); - - // Act - patchDoc.ApplyTo(model); - - // Assert - Assert.Equal(0, model.IntegerProperty); - } - - [Fact] - public void Remove_OnNonReferenceType_POCOProperty_ShouldSetDefaultValue_WithSerialization() - { - // Arrange - var doc = new SimpleObject() - { - StringProperty = "A" - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Remove(o => o.StringProperty); - - var serialized = JsonConvert.SerializeObject(patchDoc); - var deserialized = JsonConvert.DeserializeObject>(serialized); - - // Act - deserialized.ApplyTo(doc); - - // Assert - Assert.Null(doc.StringProperty); - } - - class ClassWithPrivateProperties - { - public string Name { get; set; } - private int Age { get; set; } = 45; - } - - [Fact] - public void Add_OnPrivateProperties_FailesWithException() - { - // Arrange - var doc = new ClassWithPrivateProperties() - { - Name = "James" - }; - - // create patch - var patchDoc = new JsonPatchDocument(); - patchDoc.Add("/Age", 30); - - // Act & Assert - var exception = Assert.Throws(() => patchDoc.ApplyTo(doc)); - Assert.Equal( - string.Format("The target location specified by path segment '{0}' was not found.", "Age"), - exception.Message); - } - } -} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleObjectWithNestedObjectWithNullCheck.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleObjectWithNestedObjectWithNullCheck.cs deleted file mode 100644 index f2423700d8..0000000000 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleObjectWithNestedObjectWithNullCheck.cs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -namespace Microsoft.AspNetCore.JsonPatch -{ - public class SimpleObjectWithNestedObjectWithNullCheck - { - public SimpleObjectWithNullCheck SimpleObjectWithNullCheck { get; set; } - - public SimpleObjectWithNestedObjectWithNullCheck() - { - SimpleObjectWithNullCheck = new SimpleObjectWithNullCheck(); - } - } -} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleObjectWithNullCheck.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleObjectWithNullCheck.cs deleted file mode 100644 index 83338c5a23..0000000000 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleObjectWithNullCheck.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; - -namespace Microsoft.AspNetCore.JsonPatch -{ - public class SimpleObjectWithNullCheck - { - private string stringProperty; - - public string StringProperty - { - get - { - return stringProperty; - } - - set - { - if (value == null) - { - throw new ArgumentNullException(); - } - - stringProperty = value; - } - } - } -} diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/TestObjectModels/Customer.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/TestObjectModels/Customer.cs new file mode 100644 index 0000000000..c8a5aa22b1 --- /dev/null +++ b/test/Microsoft.AspNetCore.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/test/Microsoft.AspNetCore.JsonPatch.Test/DynamicTestObject.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/TestObjectModels/DynamicTestObject.cs similarity index 98% rename from test/Microsoft.AspNetCore.JsonPatch.Test/DynamicTestObject.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/TestObjectModels/DynamicTestObject.cs index 4268d5526c..94ecf1685d 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/DynamicTestObject.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/TestObjectModels/DynamicTestObject.cs @@ -4,7 +4,7 @@ using System.Collections.Generic; using System.Dynamic; -namespace Microsoft.AspNetCore.JsonPatch.Internal +namespace Microsoft.AspNetCore.JsonPatch { public class DynamicTestObject : DynamicObject { diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/InheritedObject.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/TestObjectModels/InheritedObject.cs similarity index 100% rename from test/Microsoft.AspNetCore.JsonPatch.Test/InheritedObject.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/TestObjectModels/InheritedObject.cs diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/NestedObject.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/TestObjectModels/NestedObject.cs similarity index 85% rename from test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/NestedObject.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/TestObjectModels/NestedObject.cs index 050ad3a3b4..1b42d0d7ef 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/NestedObject.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/TestObjectModels/NestedObject.cs @@ -1,11 +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.Internal +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/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleObject.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/TestObjectModels/SimpleObject.cs similarity index 86% rename from test/Microsoft.AspNetCore.JsonPatch.Test/SimpleObject.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/TestObjectModels/SimpleObject.cs index 28a9570c2b..651a91bdcf 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleObject.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/TestObjectModels/SimpleObject.cs @@ -8,9 +8,11 @@ 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; } diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/SimpleObjectWithNestedObject.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/TestObjectModels/SimpleObjectWithNestedObject.cs similarity index 100% rename from test/Microsoft.AspNetCore.JsonPatch.Test/SimpleObjectWithNestedObject.cs rename to test/Microsoft.AspNetCore.JsonPatch.Test/TestObjectModels/SimpleObjectWithNestedObject.cs From d687617a356b9a875ea5b09163ef9d443b4256bb Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 1 Nov 2017 09:29:41 -0700 Subject: [PATCH 285/471] Pin tool and package versions to make builds more repeatable Part of aspnet/Universe#575 --- .gitignore | 1 - Directory.Build.props | 8 ++++---- Directory.Build.targets | 17 ++++------------- NuGet.config | 1 + build/dependencies.props | 18 ++++++++++++++++++ build/repo.props | 9 +++++---- korebuild-lock.txt | 2 ++ korebuild.json | 4 ++++ ...crosoft.AspNetCore.Html.Abstractions.csproj | 2 +- .../Microsoft.Extensions.WebEncoders.csproj | 6 +++--- test/Directory.Build.props | 10 +++++----- ...crosoft.Extensions.WebEncoders.Tests.csproj | 2 +- version.props | 10 ++++++++++ version.xml | 8 -------- 14 files changed, 58 insertions(+), 40 deletions(-) create mode 100644 build/dependencies.props create mode 100644 korebuild-lock.txt create mode 100644 korebuild.json create mode 100644 version.props delete mode 100644 version.xml diff --git a/.gitignore b/.gitignore index a7fdfd773b..6da3c6a3e9 100644 --- a/.gitignore +++ b/.gitignore @@ -38,4 +38,3 @@ node_modules .build/ .testPublish/ global.json -korebuild-lock.txt diff --git a/Directory.Build.props b/Directory.Build.props index 50b555b540..9db4d01587 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,5 +1,6 @@ - - + + + https://github.com/aspnet/HtmlAbstractions @@ -8,12 +9,11 @@ $(MSBuildThisFileDirectory)build\Key.snk true true - $(VersionSuffix)-$(BuildNumber) true - + diff --git a/Directory.Build.targets b/Directory.Build.targets index bc118fd907..e83ff95e39 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -1,14 +1,5 @@ - - - - <_BootstrapperFile Condition=" $([MSBuild]::IsOSUnixLike()) ">build.sh - <_BootstrapperFile Condition="! $([MSBuild]::IsOSUnixLike()) ">build.cmd - <_BootstrapperError> - Package references have not been pinned. Run './$(_BootstrapperFile) /t:Pin'. - Also, you can run './$(_BootstrapperFile) /t:Restore' which will pin *and* restore packages. '$(_BootstrapperFile)' can be found in '$(MSBuildThisFileDirectory)'. - - - - - + + + $(MicrosoftNETCoreApp20PackageVersion) + diff --git a/NuGet.config b/NuGet.config index 20060c934e..4e8a1f6de1 100644 --- a/NuGet.config +++ b/NuGet.config @@ -3,6 +3,7 @@ + diff --git a/build/dependencies.props b/build/dependencies.props new file mode 100644 index 0000000000..410f1c8697 --- /dev/null +++ b/build/dependencies.props @@ -0,0 +1,18 @@ + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + + + 2.1.0-preview1-15549 + 2.1.0-preview1-27488 + 2.1.0-preview1-27488 + 2.1.0-preview1-27488 + 2.1.0-preview1-27488 + 2.0.0 + 15.3.0 + 4.4.0 + 2.3.0 + 2.3.0 + + + diff --git a/build/repo.props b/build/repo.props index 13fe1c296a..b55e651b87 100644 --- a/build/repo.props +++ b/build/repo.props @@ -1,6 +1,7 @@  - - - - + + + Internal.AspNetCore.Universe.Lineup + https://dotnet.myget.org/F/aspnetcore-ci-dev/api/v3/index.json + diff --git a/korebuild-lock.txt b/korebuild-lock.txt new file mode 100644 index 0000000000..45463cc71e --- /dev/null +++ b/korebuild-lock.txt @@ -0,0 +1,2 @@ +version:2.1.0-preview1-15549 +commithash:f570e08585fec510dd60cd4bfe8795388b757a95 diff --git a/korebuild.json b/korebuild.json new file mode 100644 index 0000000000..bd5d51a51b --- /dev/null +++ b/korebuild.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/dev/tools/korebuild.schema.json", + "channel": "dev" +} diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.csproj b/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.csproj index 79e5ea01a5..271cc6c7fa 100755 --- a/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.csproj +++ b/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.csproj @@ -12,7 +12,7 @@ Microsoft.AspNetCore.Html.IHtmlContent - + diff --git a/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.csproj b/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.csproj index cd0c144633..5e6b3392b5 100755 --- a/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.csproj +++ b/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.csproj @@ -11,9 +11,9 @@ - - - + + + diff --git a/test/Directory.Build.props b/test/Directory.Build.props index a728ed268e..80e7258054 100644 --- a/test/Directory.Build.props +++ b/test/Directory.Build.props @@ -1,10 +1,10 @@ - + - - - - + + + + diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj b/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj index c019c8b97e..f016febe5c 100755 --- a/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj +++ b/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj @@ -10,7 +10,7 @@ - + diff --git a/version.props b/version.props new file mode 100644 index 0000000000..5c4a7c32d1 --- /dev/null +++ b/version.props @@ -0,0 +1,10 @@ + + + 2.1.0 + preview1 + $(VersionPrefix) + $(VersionPrefix)-$(VersionSuffix)-final + t000 + $(VersionSuffix)-$(BuildNumber) + + diff --git a/version.xml b/version.xml deleted file mode 100644 index 3c05022b7d..0000000000 --- a/version.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - dev - 2.1.0 - preview1 - - From 478c640a68bc9e91c25ee5edd81363c67d98c6e0 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 1 Nov 2017 15:11:36 -0700 Subject: [PATCH 286/471] Pin tool and package versions to make builds more repeatable Part of aspnet/Universe#575 --- .gitignore | 1 - Directory.Build.props | 6 +++--- Directory.Build.targets | 17 ++++------------- build/dependencies.props | 19 +++++++++++++++++++ build/repo.props | 11 ++++++----- korebuild-lock.txt | 2 ++ korebuild.json | 4 ++++ src/Directory.Build.props | 2 +- .../Microsoft.AspNetCore.JsonPatch.csproj | 6 +++--- test/Directory.Build.props | 10 +++++----- ...Microsoft.AspNetCore.JsonPatch.Test.csproj | 6 +++--- version.props | 10 ++++++++++ version.xml | 8 -------- 13 files changed, 60 insertions(+), 42 deletions(-) create mode 100644 build/dependencies.props create mode 100644 korebuild-lock.txt create mode 100644 korebuild.json create mode 100644 version.props delete mode 100644 version.xml diff --git a/.gitignore b/.gitignore index 24d990294f..2e8ec28064 100644 --- a/.gitignore +++ b/.gitignore @@ -37,4 +37,3 @@ node_modules *launchSettings.json *.orig global.json -korebuild-lock.txt diff --git a/Directory.Build.props b/Directory.Build.props index fb7dfae923..442db60e74 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,5 +1,6 @@ - - + + + Microsoft ASP.NET Core @@ -9,7 +10,6 @@ $(MSBuildThisFileDirectory)build\Key.snk true true - $(VersionSuffix)-$(BuildNumber) true diff --git a/Directory.Build.targets b/Directory.Build.targets index 9989b1046b..e83ff95e39 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -1,14 +1,5 @@ - - - - <_BootstrapperFile Condition=" $([MSBuild]::IsOSUnixLike()) ">build.sh - <_BootstrapperFile Condition="! $([MSBuild]::IsOSUnixLike()) ">build.cmd - <_BootstrapperError> - Package references have not been pinned. Run './$(_BootstrapperFile) /t:Pin'. - Also, you can run './$(_BootstrapperFile) /t:Restore' which will pin *and* restore packages. '$(_BootstrapperFile)' can be found in '$(MSBuildThisFileDirectory)'. - - - - - + + + $(MicrosoftNETCoreApp20PackageVersion) + diff --git a/build/dependencies.props b/build/dependencies.props new file mode 100644 index 0000000000..ba20d698d6 --- /dev/null +++ b/build/dependencies.props @@ -0,0 +1,19 @@ + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + + + 2.1.0-preview1-15550 + 2.1.0-preview1-27497 + 4.4.0 + 2.1.0-preview1-27497 + 2.0.0 + 15.3.0 + 4.7.49 + 10.0.1 + 0.7.0 + 2.3.0 + 2.3.0 + + + diff --git a/build/repo.props b/build/repo.props index c5d91e8a2c..b55e651b87 100644 --- a/build/repo.props +++ b/build/repo.props @@ -1,6 +1,7 @@ - - - - - + + + + Internal.AspNetCore.Universe.Lineup + https://dotnet.myget.org/F/aspnetcore-ci-dev/api/v3/index.json + diff --git a/korebuild-lock.txt b/korebuild-lock.txt new file mode 100644 index 0000000000..36d8056037 --- /dev/null +++ b/korebuild-lock.txt @@ -0,0 +1,2 @@ +version:2.1.0-preview1-15550 +commithash:0dd080d0d87b4d1966ec0af9961dc8bacc04f84f diff --git a/korebuild.json b/korebuild.json new file mode 100644 index 0000000000..bd5d51a51b --- /dev/null +++ b/korebuild.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/dev/tools/korebuild.schema.json", + "channel": "dev" +} diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 5236edee58..4b89a431e7 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -2,6 +2,6 @@ - + diff --git a/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj b/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj index a364de22ef..9bd08214f6 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj +++ b/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj @@ -9,9 +9,9 @@ - - - + + + diff --git a/test/Directory.Build.props b/test/Directory.Build.props index 31ed7dd07c..b10972fadd 100644 --- a/test/Directory.Build.props +++ b/test/Directory.Build.props @@ -2,10 +2,10 @@ - - - - - + + + + + diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj index 6d7b403a79..241271d58f 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj @@ -1,4 +1,4 @@ - + netcoreapp2.0;net461 @@ -10,8 +10,8 @@ - - + + diff --git a/version.props b/version.props new file mode 100644 index 0000000000..5c4a7c32d1 --- /dev/null +++ b/version.props @@ -0,0 +1,10 @@ + + + 2.1.0 + preview1 + $(VersionPrefix) + $(VersionPrefix)-$(VersionSuffix)-final + t000 + $(VersionSuffix)-$(BuildNumber) + + diff --git a/version.xml b/version.xml deleted file mode 100644 index 3c05022b7d..0000000000 --- a/version.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - dev - 2.1.0 - preview1 - - From 70c8133fce523b6eb42f39cc4da78e9ac11e99dc Mon Sep 17 00:00:00 2001 From: arerlend <30675661+arerlend@users.noreply.github.com> Date: Tue, 7 Nov 2017 11:24:52 -0800 Subject: [PATCH 287/471] allow paths that contain '.' (#125) * allow paths that contain '.' * remove InvalidPathWithDotShouldThrowException test --- .../Internal/PathHelpers.cs | 2 +- .../JsonPatchDocumentTest.cs | 20 +------------------ 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/PathHelpers.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/PathHelpers.cs index 7ef8fe7baf..d46314c148 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Internal/PathHelpers.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Internal/PathHelpers.cs @@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal // absolutely necessary, but it allows us to already catch mistakes // on creation of the patch document rather than on execute. - if (path.Contains(".") || path.Contains("//") || path.Contains(" ") || path.Contains("\\")) + if (path.Contains("//") || path.Contains(" ") || path.Contains("\\")) { throw new JsonPatchException(Resources.FormatInvalidValueForPath(path), null); } diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentTest.cs index 6b44b6696c..197e514cee 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentTest.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentTest.cs @@ -45,24 +45,6 @@ namespace Microsoft.AspNetCore.JsonPatch exception.Message); } - [Fact] - public void InvalidPathWithDotShouldThrowException() - { - // Arrange - var patchDocument = new JsonPatchDocument(); - - // Act - var exception = Assert.Throws(() => - { - patchDocument.Add("NewInt.Test", 1); - }); - - // Assert - Assert.Equal( - "The provided string 'NewInt.Test' is an invalid path.", - exception.Message); - } - [Fact] public void NonGenericPatchDocToGenericMustSerialize() { @@ -177,4 +159,4 @@ namespace Microsoft.AspNetCore.JsonPatch Assert.Equal("The JSON patch document was malformed and could not be parsed.", exception.Message); } } -} \ No newline at end of file +} From 42d3bdb82d0a241259e079aec06c79e3873cd3c1 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 13 Nov 2017 15:19:26 -0800 Subject: [PATCH 288/471] Update samples and tests to target netcoreapp2.1 --- Directory.Build.props | 4 ++++ korebuild-lock.txt | 4 ++-- test/Directory.Build.props | 7 +++++++ .../Microsoft.AspNetCore.Html.Abstractions.Test.csproj | 3 +-- .../Microsoft.Extensions.WebEncoders.Tests.csproj | 3 +-- 5 files changed, 15 insertions(+), 6 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 9db4d01587..ffc398567e 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,4 +1,8 @@  + + diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 45463cc71e..95f4613014 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview1-15549 -commithash:f570e08585fec510dd60cd4bfe8795388b757a95 +version:2.1.0-preview1-15567 +commithash:903e3104807b1bb8cddd28bdef205b1e2dc021d1 diff --git a/test/Directory.Build.props b/test/Directory.Build.props index 80e7258054..0b706cbca5 100644 --- a/test/Directory.Build.props +++ b/test/Directory.Build.props @@ -1,6 +1,13 @@ + + netcoreapp2.1 + $(DeveloperBuildTestTfms) + netcoreapp2.1;netcoreapp2.0 + $(StandardTestTfms);net461 + + diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.csproj b/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.csproj index f899e1a699..1577693497 100755 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.csproj +++ b/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.csproj @@ -1,8 +1,7 @@  - netcoreapp2.0;net461 - netcoreapp2.0 + $(StandardTestTfms) diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj b/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj index f016febe5c..247ccd19b3 100755 --- a/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj +++ b/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj @@ -1,8 +1,7 @@  - netcoreapp2.0;net461 - netcoreapp2.0 + $(StandardTestTfms) From 39db8585c1327d9ff50de3d73ef471e76a536d19 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 10 Nov 2017 10:19:50 -0800 Subject: [PATCH 289/471] Target netcoreapp2.1 in tests and samples --- Directory.Build.props | 4 ++++ korebuild-lock.txt | 4 ++-- test/Directory.Build.props | 7 +++++++ .../Microsoft.AspNetCore.JsonPatch.Test.csproj | 3 +-- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 442db60e74..2843f64536 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,4 +1,8 @@  + + diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 36d8056037..07a4d73a83 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview1-15550 -commithash:0dd080d0d87b4d1966ec0af9961dc8bacc04f84f +version:2.1.0-preview1-15564 +commithash:1f3f14382764e06b7e691e5ee89d12a280249284 diff --git a/test/Directory.Build.props b/test/Directory.Build.props index b10972fadd..98685a5e13 100644 --- a/test/Directory.Build.props +++ b/test/Directory.Build.props @@ -1,6 +1,13 @@ + + netcoreapp2.1 + $(DeveloperBuildTestTfms) + $(StandardTestTfms);netcoreapp2.0 + $(StandardTestTfms);net461 + + diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj index 241271d58f..ce1d92802d 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj @@ -1,8 +1,7 @@ - netcoreapp2.0;net461 - netcoreapp2.0 + $(StandardTestTfms) From 330960460cf4c7718f54dedaf4ca63a46a2fec7d Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 17 Nov 2017 13:00:25 -0800 Subject: [PATCH 290/471] Use MicrosoftNETCoreApp21PackageVersion to determine the runtime framework in netcoreapp2.1 --- Directory.Build.targets | 1 + build/dependencies.props | 1 + 2 files changed, 2 insertions(+) diff --git a/Directory.Build.targets b/Directory.Build.targets index e83ff95e39..894b1d0cf8 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -1,5 +1,6 @@  $(MicrosoftNETCoreApp20PackageVersion) + $(MicrosoftNETCoreApp21PackageVersion) diff --git a/build/dependencies.props b/build/dependencies.props index 410f1c8697..fa9a01ce97 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -9,6 +9,7 @@ 2.1.0-preview1-27488 2.1.0-preview1-27488 2.0.0 + 2.1.0-preview1-25907-02 15.3.0 4.4.0 2.3.0 From bccd5a1244637eed3f23d86367c2ac146e6a7576 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 17 Nov 2017 13:00:25 -0800 Subject: [PATCH 291/471] Use MicrosoftNETCoreApp21PackageVersion to determine the runtime framework in netcoreapp2.1 --- Directory.Build.targets | 1 + build/dependencies.props | 1 + 2 files changed, 2 insertions(+) diff --git a/Directory.Build.targets b/Directory.Build.targets index e83ff95e39..894b1d0cf8 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -1,5 +1,6 @@  $(MicrosoftNETCoreApp20PackageVersion) + $(MicrosoftNETCoreApp21PackageVersion) diff --git a/build/dependencies.props b/build/dependencies.props index ba20d698d6..3072c1d6e4 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -8,6 +8,7 @@ 4.4.0 2.1.0-preview1-27497 2.0.0 + 2.1.0-preview1-25907-02 15.3.0 4.7.49 10.0.1 From dc095b1f4d5e2c1a03a2dc1de98f5b0883ef65d4 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Mon, 20 Nov 2017 12:15:56 -0800 Subject: [PATCH 292/471] Use MSBuild to set NuGet feeds instead of NuGet.config --- Directory.Build.props | 1 + NuGet.config | 4 +--- build/sources.props | 16 ++++++++++++++++ 3 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 build/sources.props diff --git a/Directory.Build.props b/Directory.Build.props index ffc398567e..b7176c688d 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -5,6 +5,7 @@ + https://github.com/aspnet/HtmlAbstractions diff --git a/NuGet.config b/NuGet.config index 4e8a1f6de1..e32bddfd51 100644 --- a/NuGet.config +++ b/NuGet.config @@ -2,8 +2,6 @@ - - - + diff --git a/build/sources.props b/build/sources.props new file mode 100644 index 0000000000..c03f3ddb60 --- /dev/null +++ b/build/sources.props @@ -0,0 +1,16 @@ + + + + + $(DotNetRestoreSources) + + $(RestoreSources); + https://dotnet.myget.org/F/aspnetcore-ci-dev/api/v3/index.json; + https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json; + + + $(RestoreSources); + https://api.nuget.org/v3/index.json; + + + From 0d4e34e0a1d66e87df2bc580320de93d215d093b Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Mon, 20 Nov 2017 12:18:17 -0800 Subject: [PATCH 293/471] Use MSBuild to set NuGet feeds instead of NuGet.config --- Directory.Build.props | 1 + NuGet.config | 4 +--- build/sources.props | 16 ++++++++++++++++ 3 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 build/sources.props diff --git a/Directory.Build.props b/Directory.Build.props index 2843f64536..88b93729bb 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -5,6 +5,7 @@ + Microsoft ASP.NET Core diff --git a/NuGet.config b/NuGet.config index 4e8a1f6de1..e32bddfd51 100644 --- a/NuGet.config +++ b/NuGet.config @@ -2,8 +2,6 @@ - - - + diff --git a/build/sources.props b/build/sources.props new file mode 100644 index 0000000000..c03f3ddb60 --- /dev/null +++ b/build/sources.props @@ -0,0 +1,16 @@ + + + + + $(DotNetRestoreSources) + + $(RestoreSources); + https://dotnet.myget.org/F/aspnetcore-ci-dev/api/v3/index.json; + https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json; + + + $(RestoreSources); + https://api.nuget.org/v3/index.json; + + + From f6341853de7e6f305d3f47756a0d63f01b8cc1e1 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 21 Nov 2017 15:47:50 -0800 Subject: [PATCH 294/471] Replace aspnetcore-ci-dev feed with aspnetcore-dev --- build/dependencies.props | 12 ++++++------ build/repo.props | 2 +- build/sources.props | 2 +- korebuild-lock.txt | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index fa9a01ce97..9b84aca3eb 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,13 +1,13 @@ - + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview1-15549 - 2.1.0-preview1-27488 - 2.1.0-preview1-27488 - 2.1.0-preview1-27488 - 2.1.0-preview1-27488 + 2.1.0-preview1-15576 + 2.1.0-preview1-27644 + 2.1.0-preview1-27644 + 2.1.0-preview1-27644 + 2.1.0-preview1-27644 2.0.0 2.1.0-preview1-25907-02 15.3.0 diff --git a/build/repo.props b/build/repo.props index b55e651b87..07c5f08325 100644 --- a/build/repo.props +++ b/build/repo.props @@ -2,6 +2,6 @@ Internal.AspNetCore.Universe.Lineup - https://dotnet.myget.org/F/aspnetcore-ci-dev/api/v3/index.json + https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json diff --git a/build/sources.props b/build/sources.props index c03f3ddb60..9feff29d09 100644 --- a/build/sources.props +++ b/build/sources.props @@ -5,7 +5,7 @@ $(DotNetRestoreSources) $(RestoreSources); - https://dotnet.myget.org/F/aspnetcore-ci-dev/api/v3/index.json; + https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json; https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json; diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 95f4613014..1a99066b7c 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview1-15567 -commithash:903e3104807b1bb8cddd28bdef205b1e2dc021d1 +version:2.1.0-preview1-15576 +commithash:2f3856d2ba4f659fcb9253215b83946a06794a27 From b5906870fdf158abfdaaef30eb89c6c68503cc84 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 21 Nov 2017 15:48:09 -0800 Subject: [PATCH 295/471] Replace aspnetcore-ci-dev feed with aspnetcore-dev --- build/dependencies.props | 8 ++++---- build/repo.props | 2 +- build/sources.props | 2 +- korebuild-lock.txt | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 3072c1d6e4..34524aaba3 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,12 +1,12 @@ - + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview1-15550 - 2.1.0-preview1-27497 + 2.1.0-preview1-15576 + 2.1.0-preview1-27644 4.4.0 - 2.1.0-preview1-27497 + 2.1.0-preview1-27644 2.0.0 2.1.0-preview1-25907-02 15.3.0 diff --git a/build/repo.props b/build/repo.props index b55e651b87..07c5f08325 100644 --- a/build/repo.props +++ b/build/repo.props @@ -2,6 +2,6 @@ Internal.AspNetCore.Universe.Lineup - https://dotnet.myget.org/F/aspnetcore-ci-dev/api/v3/index.json + https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json diff --git a/build/sources.props b/build/sources.props index c03f3ddb60..9feff29d09 100644 --- a/build/sources.props +++ b/build/sources.props @@ -5,7 +5,7 @@ $(DotNetRestoreSources) $(RestoreSources); - https://dotnet.myget.org/F/aspnetcore-ci-dev/api/v3/index.json; + https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json; https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json; diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 07a4d73a83..1a99066b7c 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview1-15564 -commithash:1f3f14382764e06b7e691e5ee89d12a280249284 +version:2.1.0-preview1-15576 +commithash:2f3856d2ba4f659fcb9253215b83946a06794a27 From b9867d21b35cd653730eacb6ebc56c94f618372a Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 29 Nov 2017 14:09:26 -0800 Subject: [PATCH 296/471] Specify runtime versions to install --- build/repo.props | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build/repo.props b/build/repo.props index 07c5f08325..78b0ce5879 100644 --- a/build/repo.props +++ b/build/repo.props @@ -1,7 +1,14 @@  + + Internal.AspNetCore.Universe.Lineup https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json + + + + + From fe4d3c7ea9ceff78e3347d3ee40b99a12dcc9631 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 29 Nov 2017 14:09:27 -0800 Subject: [PATCH 297/471] Specify runtime versions to install --- build/repo.props | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build/repo.props b/build/repo.props index 07c5f08325..78b0ce5879 100644 --- a/build/repo.props +++ b/build/repo.props @@ -1,7 +1,14 @@  + + Internal.AspNetCore.Universe.Lineup https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json + + + + + From 62a1d5c1769e0bbb6bc6ac99fd9ee97e165f540b Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Fri, 1 Dec 2017 10:23:41 -0800 Subject: [PATCH 298/471] Update bootstrappers --- run.ps1 | 17 +++++++++++------ run.sh | 30 +++++++++++++++++++----------- 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/run.ps1 b/run.ps1 index 49c2899856..27dcf848f8 100644 --- a/run.ps1 +++ b/run.ps1 @@ -29,6 +29,9 @@ Updates KoreBuild to the latest version even if a lock file is present. .PARAMETER ConfigFile The path to the configuration file that stores values. Defaults to korebuild.json. +.PARAMETER ToolsSourceSuffix +The Suffix to append to the end of the ToolsSource. Useful for query strings in blob stores. + .PARAMETER Arguments Arguments to be passed to the command @@ -51,7 +54,7 @@ Example config file: #> [CmdletBinding(PositionalBinding = $false)] param( - [Parameter(Mandatory=$true, Position = 0)] + [Parameter(Mandatory = $true, Position = 0)] [string]$Command, [string]$Path = $PSScriptRoot, [Alias('c')] @@ -63,6 +66,7 @@ param( [Alias('u')] [switch]$Update, [string]$ConfigFile, + [string]$ToolsSourceSuffix, [Parameter(ValueFromRemainingArguments = $true)] [string[]]$Arguments ) @@ -79,7 +83,7 @@ function Get-KoreBuild { $lockFile = Join-Path $Path 'korebuild-lock.txt' if (!(Test-Path $lockFile) -or $Update) { - Get-RemoteFile "$ToolsSource/korebuild/channels/$Channel/latest.txt" $lockFile + Get-RemoteFile "$ToolsSource/korebuild/channels/$Channel/latest.txt" $lockFile $ToolsSourceSuffix } $version = Get-Content $lockFile | Where-Object { $_ -like 'version:*' } | Select-Object -first 1 @@ -96,7 +100,7 @@ function Get-KoreBuild { try { $tmpfile = Join-Path ([IO.Path]::GetTempPath()) "KoreBuild-$([guid]::NewGuid()).zip" - Get-RemoteFile $remotePath $tmpfile + Get-RemoteFile $remotePath $tmpfile $ToolsSourceSuffix if (Get-Command -Name 'Expand-Archive' -ErrorAction Ignore) { # Use built-in commands where possible as they are cross-plat compatible Expand-Archive -Path $tmpfile -DestinationPath $korebuildPath @@ -124,7 +128,7 @@ function Join-Paths([string]$path, [string[]]$childPaths) { return $path } -function Get-RemoteFile([string]$RemotePath, [string]$LocalPath) { +function Get-RemoteFile([string]$RemotePath, [string]$LocalPath, [string]$RemoteSuffix) { if ($RemotePath -notlike 'http*') { Copy-Item $RemotePath $LocalPath return @@ -134,7 +138,7 @@ function Get-RemoteFile([string]$RemotePath, [string]$LocalPath) { while ($retries -gt 0) { $retries -= 1 try { - Invoke-WebRequest -UseBasicParsing -Uri $RemotePath -OutFile $LocalPath + Invoke-WebRequest -UseBasicParsing -Uri $($RemotePath + $RemoteSuffix) -OutFile $LocalPath return } catch { @@ -161,7 +165,8 @@ if (Test-Path $ConfigFile) { if (!($Channel) -and (Get-Member -Name 'channel' -InputObject $config)) { [string] $Channel = $config.channel } if (!($ToolsSource) -and (Get-Member -Name 'toolsSource' -InputObject $config)) { [string] $ToolsSource = $config.toolsSource} } - } catch { + } + catch { Write-Warning "$ConfigFile could not be read. Its settings will be ignored." Write-Warning $Error[0] } diff --git a/run.sh b/run.sh index c278423acc..834961fc3a 100755 --- a/run.sh +++ b/run.sh @@ -17,6 +17,7 @@ update=false repo_path="$DIR" channel='' tools_source='' +tools_source_suffix='' # # Functions @@ -29,13 +30,14 @@ __usage() { echo " ... Arguments passed to the command. Variable number of arguments allowed." echo "" echo "Options:" - echo " --verbose Show verbose output." - echo " -c|--channel The channel of KoreBuild to download. Overrides the value from the config file.." - echo " --config-file The path to the configuration file that stores values. Defaults to korebuild.json." - echo " -d|--dotnet-home The directory where .NET Core tools will be stored. Defaults to '\$DOTNET_HOME' or '\$HOME/.dotnet." - echo " --path The directory to build. Defaults to the directory containing the script." - echo " -s|--tools-source|-ToolsSource The base url where build tools can be downloaded. Overrides the value from the config file." - echo " -u|--update Update to the latest KoreBuild even if the lock file is present." + echo " --verbose Show verbose output." + echo " -c|--channel The channel of KoreBuild to download. Overrides the value from the config file.." + echo " --config-file The path to the configuration file that stores values. Defaults to korebuild.json." + echo " -d|--dotnet-home The directory where .NET Core tools will be stored. Defaults to '\$DOTNET_HOME' or '\$HOME/.dotnet." + echo " --path The directory to build. Defaults to the directory containing the script." + echo " -s|--tools-source|-ToolsSource The base url where build tools can be downloaded. Overrides the value from the config file." + echo " --tools-source-suffix|-ToolsSourceSuffix The suffix to append to tools-source. Useful for query strings." + echo " -u|--update Update to the latest KoreBuild even if the lock file is present." echo "" echo "Description:" echo " This function will create a file \$DIR/korebuild-lock.txt. This lock file can be committed to source, but does not have to be." @@ -50,7 +52,7 @@ get_korebuild() { local version local lock_file="$repo_path/korebuild-lock.txt" if [ ! -f "$lock_file" ] || [ "$update" = true ]; then - __get_remote_file "$tools_source/korebuild/channels/$channel/latest.txt" "$lock_file" + __get_remote_file "$tools_source/korebuild/channels/$channel/latest.txt" "$lock_file" "$tools_source_suffix" fi version="$(grep 'version:*' -m 1 "$lock_file")" if [[ "$version" == '' ]]; then @@ -66,7 +68,7 @@ get_korebuild() { local remote_path="$tools_source/korebuild/artifacts/$version/korebuild.$version.zip" tmpfile="$(mktemp)" echo -e "${MAGENTA}Downloading KoreBuild ${version}${RESET}" - if __get_remote_file "$remote_path" "$tmpfile"; then + if __get_remote_file "$remote_path" "$tmpfile" "$tools_source_suffix"; then unzip -q -d "$korebuild_path" "$tmpfile" fi rm "$tmpfile" || true @@ -98,6 +100,7 @@ __machine_has() { __get_remote_file() { local remote_path=$1 local local_path=$2 + local remote_path_suffix=$3 if [[ "$remote_path" != 'http'* ]]; then cp "$remote_path" "$local_path" @@ -106,14 +109,14 @@ __get_remote_file() { local failed=false if __machine_has wget; then - wget --tries 10 --quiet -O "$local_path" "$remote_path" || failed=true + wget --tries 10 --quiet -O "$local_path" "${remote_path}${remote_path_suffix}" || failed=true else failed=true fi if [ "$failed" = true ] && __machine_has curl; then failed=false - curl --retry 10 -sSL -f --create-dirs -o "$local_path" "$remote_path" || failed=true + curl --retry 10 -sSL -f --create-dirs -o "$local_path" "${remote_path}${remote_path_suffix}" || failed=true fi if [ "$failed" = true ]; then @@ -164,6 +167,11 @@ while [[ $# -gt 0 ]]; do tools_source="${1:-}" [ -z "$tools_source" ] && __usage ;; + --tools-source-suffix|-ToolsSourceSuffix) + shift + tools_source_suffix="${1:-}" + [ -z "$tools_source_suffix" ] && __usage + ;; -u|--update|-Update) update=true ;; From a928adee30db55c591eaece34de7fddd2e9ab834 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Fri, 1 Dec 2017 10:24:45 -0800 Subject: [PATCH 299/471] Update bootstrappers --- run.ps1 | 17 +++++++++++------ run.sh | 30 +++++++++++++++++++----------- 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/run.ps1 b/run.ps1 index 49c2899856..27dcf848f8 100644 --- a/run.ps1 +++ b/run.ps1 @@ -29,6 +29,9 @@ Updates KoreBuild to the latest version even if a lock file is present. .PARAMETER ConfigFile The path to the configuration file that stores values. Defaults to korebuild.json. +.PARAMETER ToolsSourceSuffix +The Suffix to append to the end of the ToolsSource. Useful for query strings in blob stores. + .PARAMETER Arguments Arguments to be passed to the command @@ -51,7 +54,7 @@ Example config file: #> [CmdletBinding(PositionalBinding = $false)] param( - [Parameter(Mandatory=$true, Position = 0)] + [Parameter(Mandatory = $true, Position = 0)] [string]$Command, [string]$Path = $PSScriptRoot, [Alias('c')] @@ -63,6 +66,7 @@ param( [Alias('u')] [switch]$Update, [string]$ConfigFile, + [string]$ToolsSourceSuffix, [Parameter(ValueFromRemainingArguments = $true)] [string[]]$Arguments ) @@ -79,7 +83,7 @@ function Get-KoreBuild { $lockFile = Join-Path $Path 'korebuild-lock.txt' if (!(Test-Path $lockFile) -or $Update) { - Get-RemoteFile "$ToolsSource/korebuild/channels/$Channel/latest.txt" $lockFile + Get-RemoteFile "$ToolsSource/korebuild/channels/$Channel/latest.txt" $lockFile $ToolsSourceSuffix } $version = Get-Content $lockFile | Where-Object { $_ -like 'version:*' } | Select-Object -first 1 @@ -96,7 +100,7 @@ function Get-KoreBuild { try { $tmpfile = Join-Path ([IO.Path]::GetTempPath()) "KoreBuild-$([guid]::NewGuid()).zip" - Get-RemoteFile $remotePath $tmpfile + Get-RemoteFile $remotePath $tmpfile $ToolsSourceSuffix if (Get-Command -Name 'Expand-Archive' -ErrorAction Ignore) { # Use built-in commands where possible as they are cross-plat compatible Expand-Archive -Path $tmpfile -DestinationPath $korebuildPath @@ -124,7 +128,7 @@ function Join-Paths([string]$path, [string[]]$childPaths) { return $path } -function Get-RemoteFile([string]$RemotePath, [string]$LocalPath) { +function Get-RemoteFile([string]$RemotePath, [string]$LocalPath, [string]$RemoteSuffix) { if ($RemotePath -notlike 'http*') { Copy-Item $RemotePath $LocalPath return @@ -134,7 +138,7 @@ function Get-RemoteFile([string]$RemotePath, [string]$LocalPath) { while ($retries -gt 0) { $retries -= 1 try { - Invoke-WebRequest -UseBasicParsing -Uri $RemotePath -OutFile $LocalPath + Invoke-WebRequest -UseBasicParsing -Uri $($RemotePath + $RemoteSuffix) -OutFile $LocalPath return } catch { @@ -161,7 +165,8 @@ if (Test-Path $ConfigFile) { if (!($Channel) -and (Get-Member -Name 'channel' -InputObject $config)) { [string] $Channel = $config.channel } if (!($ToolsSource) -and (Get-Member -Name 'toolsSource' -InputObject $config)) { [string] $ToolsSource = $config.toolsSource} } - } catch { + } + catch { Write-Warning "$ConfigFile could not be read. Its settings will be ignored." Write-Warning $Error[0] } diff --git a/run.sh b/run.sh index c278423acc..834961fc3a 100755 --- a/run.sh +++ b/run.sh @@ -17,6 +17,7 @@ update=false repo_path="$DIR" channel='' tools_source='' +tools_source_suffix='' # # Functions @@ -29,13 +30,14 @@ __usage() { echo " ... Arguments passed to the command. Variable number of arguments allowed." echo "" echo "Options:" - echo " --verbose Show verbose output." - echo " -c|--channel The channel of KoreBuild to download. Overrides the value from the config file.." - echo " --config-file The path to the configuration file that stores values. Defaults to korebuild.json." - echo " -d|--dotnet-home The directory where .NET Core tools will be stored. Defaults to '\$DOTNET_HOME' or '\$HOME/.dotnet." - echo " --path The directory to build. Defaults to the directory containing the script." - echo " -s|--tools-source|-ToolsSource The base url where build tools can be downloaded. Overrides the value from the config file." - echo " -u|--update Update to the latest KoreBuild even if the lock file is present." + echo " --verbose Show verbose output." + echo " -c|--channel The channel of KoreBuild to download. Overrides the value from the config file.." + echo " --config-file The path to the configuration file that stores values. Defaults to korebuild.json." + echo " -d|--dotnet-home The directory where .NET Core tools will be stored. Defaults to '\$DOTNET_HOME' or '\$HOME/.dotnet." + echo " --path The directory to build. Defaults to the directory containing the script." + echo " -s|--tools-source|-ToolsSource The base url where build tools can be downloaded. Overrides the value from the config file." + echo " --tools-source-suffix|-ToolsSourceSuffix The suffix to append to tools-source. Useful for query strings." + echo " -u|--update Update to the latest KoreBuild even if the lock file is present." echo "" echo "Description:" echo " This function will create a file \$DIR/korebuild-lock.txt. This lock file can be committed to source, but does not have to be." @@ -50,7 +52,7 @@ get_korebuild() { local version local lock_file="$repo_path/korebuild-lock.txt" if [ ! -f "$lock_file" ] || [ "$update" = true ]; then - __get_remote_file "$tools_source/korebuild/channels/$channel/latest.txt" "$lock_file" + __get_remote_file "$tools_source/korebuild/channels/$channel/latest.txt" "$lock_file" "$tools_source_suffix" fi version="$(grep 'version:*' -m 1 "$lock_file")" if [[ "$version" == '' ]]; then @@ -66,7 +68,7 @@ get_korebuild() { local remote_path="$tools_source/korebuild/artifacts/$version/korebuild.$version.zip" tmpfile="$(mktemp)" echo -e "${MAGENTA}Downloading KoreBuild ${version}${RESET}" - if __get_remote_file "$remote_path" "$tmpfile"; then + if __get_remote_file "$remote_path" "$tmpfile" "$tools_source_suffix"; then unzip -q -d "$korebuild_path" "$tmpfile" fi rm "$tmpfile" || true @@ -98,6 +100,7 @@ __machine_has() { __get_remote_file() { local remote_path=$1 local local_path=$2 + local remote_path_suffix=$3 if [[ "$remote_path" != 'http'* ]]; then cp "$remote_path" "$local_path" @@ -106,14 +109,14 @@ __get_remote_file() { local failed=false if __machine_has wget; then - wget --tries 10 --quiet -O "$local_path" "$remote_path" || failed=true + wget --tries 10 --quiet -O "$local_path" "${remote_path}${remote_path_suffix}" || failed=true else failed=true fi if [ "$failed" = true ] && __machine_has curl; then failed=false - curl --retry 10 -sSL -f --create-dirs -o "$local_path" "$remote_path" || failed=true + curl --retry 10 -sSL -f --create-dirs -o "$local_path" "${remote_path}${remote_path_suffix}" || failed=true fi if [ "$failed" = true ]; then @@ -164,6 +167,11 @@ while [[ $# -gt 0 ]]; do tools_source="${1:-}" [ -z "$tools_source" ] && __usage ;; + --tools-source-suffix|-ToolsSourceSuffix) + shift + tools_source_suffix="${1:-}" + [ -z "$tools_source_suffix" ] && __usage + ;; -u|--update|-Update) update=true ;; From 1760bab38fc7e601b9165f6dc60268b3739b7863 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 10 Dec 2017 12:48:34 -0800 Subject: [PATCH 300/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 18 +++++++++--------- korebuild-lock.txt | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 9b84aca3eb..00ce6f22db 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,17 +3,17 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview1-15576 - 2.1.0-preview1-27644 - 2.1.0-preview1-27644 - 2.1.0-preview1-27644 - 2.1.0-preview1-27644 + 2.1.0-preview1-15618 + 2.1.0-preview1-27773 + 2.1.0-preview1-27773 + 2.1.0-preview1-27773 + 2.1.0-preview1-27773 2.0.0 - 2.1.0-preview1-25907-02 + 2.1.0-preview1-25915-01 15.3.0 - 4.4.0 - 2.3.0 - 2.3.0 + 4.5.0-preview1-25914-04 + 2.3.1 + 2.3.1 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 1a99066b7c..e7cce93009 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview1-15576 -commithash:2f3856d2ba4f659fcb9253215b83946a06794a27 +version:2.1.0-preview1-15618 +commithash:00ce1383114015fe89b221146036e59e6bc11219 From 84194387a22ae103166fe5d59a0b30f335f616fb Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 10 Dec 2017 13:01:26 -0800 Subject: [PATCH 301/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 16 ++++++++-------- korebuild-lock.txt | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 34524aaba3..1808025509 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,18 +3,18 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview1-15576 - 2.1.0-preview1-27644 - 4.4.0 - 2.1.0-preview1-27644 + 2.1.0-preview1-15618 + 2.1.0-preview1-27773 + 4.5.0-preview1-25914-04 + 2.1.0-preview1-27773 2.0.0 - 2.1.0-preview1-25907-02 + 2.1.0-preview1-25915-01 15.3.0 4.7.49 10.0.1 - 0.7.0 - 2.3.0 - 2.3.0 + 0.8.0 + 2.3.1 + 2.3.1 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 1a99066b7c..e7cce93009 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview1-15576 -commithash:2f3856d2ba4f659fcb9253215b83946a06794a27 +version:2.1.0-preview1-15618 +commithash:00ce1383114015fe89b221146036e59e6bc11219 From d3c71cce948c400c40c26f818b2bec177ba9827c Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Wed, 13 Dec 2017 20:49:48 +0000 Subject: [PATCH 302/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 14 +++++++------- korebuild-lock.txt | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 00ce6f22db..9333aa7bd3 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,15 +3,15 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview1-15618 - 2.1.0-preview1-27773 - 2.1.0-preview1-27773 - 2.1.0-preview1-27773 - 2.1.0-preview1-27773 + 2.1.0-preview1-15626 + 2.1.0-preview1-27807 + 2.1.0-preview1-27807 + 2.1.0-preview1-27807 + 2.1.0-preview1-27807 2.0.0 - 2.1.0-preview1-25915-01 + 2.1.0-preview1-26008-01 15.3.0 - 4.5.0-preview1-25914-04 + 4.5.0-preview1-26006-06 2.3.1 2.3.1 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index e7cce93009..8d52a6128c 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview1-15618 -commithash:00ce1383114015fe89b221146036e59e6bc11219 +version:2.1.0-preview1-15626 +commithash:fd6410e9c90c428bc01238372303ad09cb9ec889 From 77de59903060c225b31ee8fb1ef0885d13a6cdf9 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Wed, 13 Dec 2017 21:01:02 +0000 Subject: [PATCH 303/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 10 +++++----- korebuild-lock.txt | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 1808025509..2e1d5008e8 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,12 +3,12 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview1-15618 - 2.1.0-preview1-27773 - 4.5.0-preview1-25914-04 - 2.1.0-preview1-27773 + 2.1.0-preview1-15626 + 2.1.0-preview1-27807 + 4.5.0-preview1-26006-06 + 2.1.0-preview1-27807 2.0.0 - 2.1.0-preview1-25915-01 + 2.1.0-preview1-26008-01 15.3.0 4.7.49 10.0.1 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index e7cce93009..8d52a6128c 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview1-15618 -commithash:00ce1383114015fe89b221146036e59e6bc11219 +version:2.1.0-preview1-15626 +commithash:fd6410e9c90c428bc01238372303ad09cb9ec889 From 1d427b4065d2dcb421b161b3c1abe4dd29796639 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 17 Dec 2017 12:35:17 -0800 Subject: [PATCH 304/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 2e1d5008e8..ab34d96520 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,11 +4,11 @@ 2.1.0-preview1-15626 - 2.1.0-preview1-27807 - 4.5.0-preview1-26006-06 - 2.1.0-preview1-27807 + 2.1.0-preview1-27838 + 4.5.0-preview1-26014-03 + 2.1.0-preview1-27838 2.0.0 - 2.1.0-preview1-26008-01 + 2.1.0-preview1-26015-01 15.3.0 4.7.49 10.0.1 From d3fa87c6c5fd0e362d758da44c6423283a9e7145 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Mon, 18 Dec 2017 17:04:20 -0800 Subject: [PATCH 305/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 9333aa7bd3..766fe3e033 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,14 +4,14 @@ 2.1.0-preview1-15626 - 2.1.0-preview1-27807 - 2.1.0-preview1-27807 - 2.1.0-preview1-27807 - 2.1.0-preview1-27807 + 2.1.0-preview1-27849 + 2.1.0-preview1-27849 + 2.1.0-preview1-27849 + 2.1.0-preview1-27849 2.0.0 - 2.1.0-preview1-26008-01 + 2.1.0-preview1-26016-05 15.3.0 - 4.5.0-preview1-26006-06 + 4.5.0-preview1-26016-05 2.3.1 2.3.1 From a0316af7b207cb94372db1ab727b97ea720651e8 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Mon, 18 Dec 2017 17:15:24 -0800 Subject: [PATCH 306/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index ab34d96520..06cca20623 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,11 +4,11 @@ 2.1.0-preview1-15626 - 2.1.0-preview1-27838 - 4.5.0-preview1-26014-03 - 2.1.0-preview1-27838 + 2.1.0-preview1-27849 + 4.5.0-preview1-26016-05 + 2.1.0-preview1-27849 2.0.0 - 2.1.0-preview1-26015-01 + 2.1.0-preview1-26016-05 15.3.0 4.7.49 10.0.1 From 48cc16eadc2e58190fdf8100cdec1653da08a6d8 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 31 Dec 2017 21:05:44 +0000 Subject: [PATCH 307/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 10 +++++----- korebuild-lock.txt | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 766fe3e033..e5e9ff8abf 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,11 +3,11 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview1-15626 - 2.1.0-preview1-27849 - 2.1.0-preview1-27849 - 2.1.0-preview1-27849 - 2.1.0-preview1-27849 + 2.1.0-preview1-15651 + 2.1.0-preview1-27942 + 2.1.0-preview1-27942 + 2.1.0-preview1-27942 + 2.1.0-preview1-27942 2.0.0 2.1.0-preview1-26016-05 15.3.0 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 8d52a6128c..7c2e97aa79 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview1-15626 -commithash:fd6410e9c90c428bc01238372303ad09cb9ec889 +version:2.1.0-preview1-15651 +commithash:ebf2365121c2c6a6a0fbfa9b0f37bb5effc89323 From a7589fbd7d132b02efb553e8a3c339559c1dfe44 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 31 Dec 2017 21:18:01 +0000 Subject: [PATCH 308/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 6 +++--- korebuild-lock.txt | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 06cca20623..71f186007d 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,10 +3,10 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview1-15626 - 2.1.0-preview1-27849 + 2.1.0-preview1-15651 + 2.1.0-preview1-27942 4.5.0-preview1-26016-05 - 2.1.0-preview1-27849 + 2.1.0-preview1-27942 2.0.0 2.1.0-preview1-26016-05 15.3.0 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 8d52a6128c..7c2e97aa79 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview1-15626 -commithash:fd6410e9c90c428bc01238372303ad09cb9ec889 +version:2.1.0-preview1-15651 +commithash:ebf2365121c2c6a6a0fbfa9b0f37bb5effc89323 From 721e8ac93921ee5655f4208f620a19e1edc23b81 Mon Sep 17 00:00:00 2001 From: Eilon Lipton Date: Tue, 2 Jan 2018 14:25:50 -0800 Subject: [PATCH 309/471] Create ISSUE_TEMPLATE.md --- .github/ISSUE_TEMPLATE.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000000..101a084f0a --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,3 @@ +THIS ISSUE TRACKER IS CLOSED - please log new issues here: https://github.com/aspnet/Home/issues + +For information about this change, see https://github.com/aspnet/Announcements/issues/283 From 6a1046d3b9bfc53baf74127b21f8310516cf5e32 Mon Sep 17 00:00:00 2001 From: Eilon Lipton Date: Tue, 2 Jan 2018 14:34:07 -0800 Subject: [PATCH 310/471] Create ISSUE_TEMPLATE.md --- .github/ISSUE_TEMPLATE.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000000..101a084f0a --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,3 @@ +THIS ISSUE TRACKER IS CLOSED - please log new issues here: https://github.com/aspnet/Home/issues + +For information about this change, see https://github.com/aspnet/Announcements/issues/283 From 0f65354175f9cfdcd48c37902a1bd6311d8a278e Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Thu, 4 Jan 2018 01:12:22 +0000 Subject: [PATCH 311/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index e5e9ff8abf..c5a5bf4ea0 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,10 +4,10 @@ 2.1.0-preview1-15651 - 2.1.0-preview1-27942 - 2.1.0-preview1-27942 - 2.1.0-preview1-27942 - 2.1.0-preview1-27942 + 2.1.0-preview1-27965 + 2.1.0-preview1-27965 + 2.1.0-preview1-27965 + 2.1.0-preview1-27965 2.0.0 2.1.0-preview1-26016-05 15.3.0 From add34207364e4eb8a918ee46af8ddef1f430f7cb Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Thu, 4 Jan 2018 01:24:28 +0000 Subject: [PATCH 312/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 71f186007d..8ebfd2751f 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,9 +4,9 @@ 2.1.0-preview1-15651 - 2.1.0-preview1-27942 + 2.1.0-preview1-27965 4.5.0-preview1-26016-05 - 2.1.0-preview1-27942 + 2.1.0-preview1-27965 2.0.0 2.1.0-preview1-26016-05 15.3.0 From 3746bf4286db95096849e2b064069ef24616d026 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sat, 6 Jan 2018 14:44:10 -0800 Subject: [PATCH 313/471] Update dependencies.props [auto-updated: dependencies] --- korebuild-lock.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 7c2e97aa79..2146d006d7 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview1-15651 -commithash:ebf2365121c2c6a6a0fbfa9b0f37bb5effc89323 +version:2.1.0-preview1-15661 +commithash:c9349d4c8a495d3085d9b879214d80f2f45e2193 From 8f09923324ec5f9f9f58adf43e414edf978874c1 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sat, 6 Jan 2018 14:57:37 -0800 Subject: [PATCH 314/471] Update dependencies.props [auto-updated: dependencies] --- korebuild-lock.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 7c2e97aa79..2146d006d7 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview1-15651 -commithash:ebf2365121c2c6a6a0fbfa9b0f37bb5effc89323 +version:2.1.0-preview1-15661 +commithash:c9349d4c8a495d3085d9b879214d80f2f45e2193 From d208eca57fdd0af1e2a638eb2feed891dc8aa146 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 23 Jan 2018 15:31:08 -0800 Subject: [PATCH 315/471] Branching for 2.1.0-preview1 --- build/dependencies.props | 14 +++++++------- build/repo.props | 4 ++-- build/sources.props | 4 ++-- korebuild-lock.txt | 4 ++-- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index c5a5bf4ea0..aacad395d0 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,15 +3,15 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview1-15651 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 + 2.1.0-preview1-15679 + 2.1.0-preview1-28153 + 2.1.0-preview1-28153 + 2.1.0-preview1-28153 + 2.1.0-preview1-28153 2.0.0 - 2.1.0-preview1-26016-05 + 2.1.0-preview1-26115-03 15.3.0 - 4.5.0-preview1-26016-05 + 4.5.0-preview1-26112-01 2.3.1 2.3.1 diff --git a/build/repo.props b/build/repo.props index 78b0ce5879..d94ff7d00d 100644 --- a/build/repo.props +++ b/build/repo.props @@ -1,10 +1,10 @@ - + Internal.AspNetCore.Universe.Lineup - https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json + https://dotnet.myget.org/F/aspnetcore-release/api/v3/index.json diff --git a/build/sources.props b/build/sources.props index 9feff29d09..5d66393335 100644 --- a/build/sources.props +++ b/build/sources.props @@ -1,11 +1,11 @@ - + $(DotNetRestoreSources) $(RestoreSources); - https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json; + https://dotnet.myget.org/F/aspnetcore-release/api/v3/index.json; https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json; diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 2146d006d7..a474bc0e35 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview1-15661 -commithash:c9349d4c8a495d3085d9b879214d80f2f45e2193 +version:2.1.0-preview1-15679 +commithash:5347461137cb45a77ddcc0b55b2478092de43338 From eafe3e7aa39c4023883394d4fbab16131d190295 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 23 Jan 2018 15:31:40 -0800 Subject: [PATCH 316/471] Branching for 2.1.0-preview1 --- build/dependencies.props | 10 +++++----- build/repo.props | 4 ++-- build/sources.props | 4 ++-- korebuild-lock.txt | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 8ebfd2751f..5382af18d5 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,12 +3,12 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview1-15651 - 2.1.0-preview1-27965 - 4.5.0-preview1-26016-05 - 2.1.0-preview1-27965 + 2.1.0-preview1-15679 + 2.1.0-preview1-28153 + 4.5.0-preview1-26112-01 + 2.1.0-preview1-28153 2.0.0 - 2.1.0-preview1-26016-05 + 2.1.0-preview1-26115-03 15.3.0 4.7.49 10.0.1 diff --git a/build/repo.props b/build/repo.props index 78b0ce5879..d94ff7d00d 100644 --- a/build/repo.props +++ b/build/repo.props @@ -1,10 +1,10 @@ - + Internal.AspNetCore.Universe.Lineup - https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json + https://dotnet.myget.org/F/aspnetcore-release/api/v3/index.json diff --git a/build/sources.props b/build/sources.props index 9feff29d09..5d66393335 100644 --- a/build/sources.props +++ b/build/sources.props @@ -1,11 +1,11 @@ - + $(DotNetRestoreSources) $(RestoreSources); - https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json; + https://dotnet.myget.org/F/aspnetcore-release/api/v3/index.json; https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json; diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 2146d006d7..a474bc0e35 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview1-15661 -commithash:c9349d4c8a495d3085d9b879214d80f2f45e2193 +version:2.1.0-preview1-15679 +commithash:5347461137cb45a77ddcc0b55b2478092de43338 From 26c76a2f17c590ab21651d32eabe25f968b682eb Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 24 Jan 2018 15:00:27 -0800 Subject: [PATCH 317/471] Updating version to preview2 --- version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.props b/version.props index 5c4a7c32d1..370d5ababd 100644 --- a/version.props +++ b/version.props @@ -1,7 +1,7 @@ 2.1.0 - preview1 + preview2 $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final t000 From 8fb433d276a2ce76e706cf26391abb0c02fa24a5 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 24 Jan 2018 15:00:28 -0800 Subject: [PATCH 318/471] Updating version to preview2 --- version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.props b/version.props index 5c4a7c32d1..370d5ababd 100644 --- a/version.props +++ b/version.props @@ -1,7 +1,7 @@ 2.1.0 - preview1 + preview2 $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final t000 From a7219e0c5cdc1de5cf6f5871b3f2b89b9d7e5040 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 31 Jan 2018 15:01:11 -0800 Subject: [PATCH 319/471] Update dependencies.props to 2.1.0-preview-28193, build tools to 2.1.0-preview1-1010 [ci skip] Scripted changes: - updated travis and appveyor.yml files to only build dev, ci, and release branches - updated dependencies.props - updated korebuild-lock.txt - updated korebuild.json to release/2.1 channel --- .appveyor.yml | 15 +++++++-------- .travis.yml | 23 ++++++++++++----------- build/dependencies.props | 14 +++++++------- korebuild-lock.txt | 4 ++-- korebuild.json | 4 ++-- 5 files changed, 30 insertions(+), 30 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 46038786c9..4eea96ab69 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,18 +1,17 @@ init: - - git config --global core.autocrlf true +- git config --global core.autocrlf true branches: only: - - master - - release - - dev - - /^(.*\/)?ci-.*$/ + - dev + - /^release\/.*$/ + - /^(.*\/)?ci-.*$/ build_script: - - ps: .\run.ps1 default-build +- ps: .\run.ps1 default-build clone_depth: 1 environment: global: DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true DOTNET_CLI_TELEMETRY_OPTOUT: 1 -test: off -deploy: off +test: 'off' +deploy: 'off' os: Visual Studio 2017 diff --git a/.travis.yml b/.travis.yml index b10be14215..64bdbb4441 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,24 +3,25 @@ sudo: false dist: trusty env: global: - - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true - - DOTNET_CLI_TELEMETRY_OPTOUT: 1 + - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + - DOTNET_CLI_TELEMETRY_OPTOUT: 1 mono: none os: - - linux - - osx +- linux +- osx osx_image: xcode8.2 addons: apt: packages: - - libunwind8 + - libunwind8 branches: only: - - master - - release - - dev - - /^(.*\/)?ci-.*$/ + - dev + - /^release\/.*$/ + - /^(.*\/)?ci-.*$/ before_install: - - if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/; fi +- if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; ln -s + /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib + /usr/local/lib/; fi script: - - ./build.sh +- ./build.sh diff --git a/build/dependencies.props b/build/dependencies.props index aacad395d0..a3badf6fc0 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,15 +3,15 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview1-15679 - 2.1.0-preview1-28153 - 2.1.0-preview1-28153 - 2.1.0-preview1-28153 - 2.1.0-preview1-28153 + 2.1.0-preview1-1010 + 2.1.0-preview1-28193 + 2.1.0-preview1-28193 + 2.1.0-preview1-28193 + 2.1.0-preview1-28193 2.0.0 - 2.1.0-preview1-26115-03 + 2.1.0-preview1-26122-01 15.3.0 - 4.5.0-preview1-26112-01 + 4.5.0-preview1-26119-06 2.3.1 2.3.1 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index a474bc0e35..851bfbf203 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview1-15679 -commithash:5347461137cb45a77ddcc0b55b2478092de43338 +version:2.1.0-preview1-1010 +commithash:75ca924dfbd673c38841025b04c4dcd93b84f56d diff --git a/korebuild.json b/korebuild.json index bd5d51a51b..678d8bb948 100644 --- a/korebuild.json +++ b/korebuild.json @@ -1,4 +1,4 @@ { - "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/dev/tools/korebuild.schema.json", - "channel": "dev" + "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/release/2.1/tools/korebuild.schema.json", + "channel": "release/2.1" } From 829db1aae540b51ac3b5e369ae8b13863e63ef73 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 31 Jan 2018 15:01:12 -0800 Subject: [PATCH 320/471] Update dependencies.props to 2.1.0-preview-28193, build tools to 2.1.0-preview1-1010 [ci skip] Scripted changes: - updated travis and appveyor.yml files to only build dev, ci, and release branches - updated dependencies.props - updated korebuild-lock.txt - updated korebuild.json to release/2.1 channel --- .appveyor.yml | 15 +++++++-------- .travis.yml | 23 ++++++++++++----------- build/dependencies.props | 10 +++++----- korebuild-lock.txt | 4 ++-- korebuild.json | 4 ++-- 5 files changed, 28 insertions(+), 28 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 46038786c9..4eea96ab69 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,18 +1,17 @@ init: - - git config --global core.autocrlf true +- git config --global core.autocrlf true branches: only: - - master - - release - - dev - - /^(.*\/)?ci-.*$/ + - dev + - /^release\/.*$/ + - /^(.*\/)?ci-.*$/ build_script: - - ps: .\run.ps1 default-build +- ps: .\run.ps1 default-build clone_depth: 1 environment: global: DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true DOTNET_CLI_TELEMETRY_OPTOUT: 1 -test: off -deploy: off +test: 'off' +deploy: 'off' os: Visual Studio 2017 diff --git a/.travis.yml b/.travis.yml index b10be14215..64bdbb4441 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,24 +3,25 @@ sudo: false dist: trusty env: global: - - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true - - DOTNET_CLI_TELEMETRY_OPTOUT: 1 + - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + - DOTNET_CLI_TELEMETRY_OPTOUT: 1 mono: none os: - - linux - - osx +- linux +- osx osx_image: xcode8.2 addons: apt: packages: - - libunwind8 + - libunwind8 branches: only: - - master - - release - - dev - - /^(.*\/)?ci-.*$/ + - dev + - /^release\/.*$/ + - /^(.*\/)?ci-.*$/ before_install: - - if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/; fi +- if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; ln -s + /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib + /usr/local/lib/; fi script: - - ./build.sh +- ./build.sh diff --git a/build/dependencies.props b/build/dependencies.props index 5382af18d5..9c5ea2b351 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,12 +3,12 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview1-15679 - 2.1.0-preview1-28153 - 4.5.0-preview1-26112-01 - 2.1.0-preview1-28153 + 2.1.0-preview1-1010 + 2.1.0-preview1-28193 + 4.5.0-preview1-26119-06 + 2.1.0-preview1-28193 2.0.0 - 2.1.0-preview1-26115-03 + 2.1.0-preview1-26122-01 15.3.0 4.7.49 10.0.1 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index a474bc0e35..851bfbf203 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview1-15679 -commithash:5347461137cb45a77ddcc0b55b2478092de43338 +version:2.1.0-preview1-1010 +commithash:75ca924dfbd673c38841025b04c4dcd93b84f56d diff --git a/korebuild.json b/korebuild.json index bd5d51a51b..678d8bb948 100644 --- a/korebuild.json +++ b/korebuild.json @@ -1,4 +1,4 @@ { - "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/dev/tools/korebuild.schema.json", - "channel": "dev" + "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/release/2.1/tools/korebuild.schema.json", + "channel": "release/2.1" } From 22c2797d84e091221767ccb4cb50cad470695f44 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Thu, 1 Feb 2018 03:29:53 +0000 Subject: [PATCH 321/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 14 +++++++------- korebuild-lock.txt | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index c5a5bf4ea0..c1e4d6ef27 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,15 +3,15 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview1-15651 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 + 2.1.0-preview2-15692 + 2.1.0-preview2-28215 + 2.1.0-preview2-28215 + 2.1.0-preview2-28215 + 2.1.0-preview2-28215 2.0.0 - 2.1.0-preview1-26016-05 + 2.1.0-preview2-26130-04 15.3.0 - 4.5.0-preview1-26016-05 + 4.5.0-preview2-26130-01 2.3.1 2.3.1 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 2146d006d7..232cb858c2 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview1-15661 -commithash:c9349d4c8a495d3085d9b879214d80f2f45e2193 +version:2.1.0-preview2-15692 +commithash:5d9f445ce3f8492451a6f461df7e739bbed6a7f8 From 9bdbac7049d530e1f25f6b95ec8c78c04d3b1702 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Thu, 1 Feb 2018 03:42:02 +0000 Subject: [PATCH 322/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 10 +++++----- korebuild-lock.txt | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 8ebfd2751f..4aa9e9db7f 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,12 +3,12 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview1-15651 - 2.1.0-preview1-27965 - 4.5.0-preview1-26016-05 - 2.1.0-preview1-27965 + 2.1.0-preview2-15692 + 2.1.0-preview2-28215 + 4.5.0-preview2-26130-01 + 2.1.0-preview2-28215 2.0.0 - 2.1.0-preview1-26016-05 + 2.1.0-preview2-26130-04 15.3.0 4.7.49 10.0.1 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 2146d006d7..232cb858c2 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview1-15661 -commithash:c9349d4c8a495d3085d9b879214d80f2f45e2193 +version:2.1.0-preview2-15692 +commithash:5d9f445ce3f8492451a6f461df7e739bbed6a7f8 From 0b4285caa28f7ec84ebf02f79036845b0af3509a Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sat, 3 Feb 2018 02:46:03 +0000 Subject: [PATCH 323/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 10 +++++----- korebuild-lock.txt | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index c1e4d6ef27..b9e0d540c9 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,11 +3,11 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview2-15692 - 2.1.0-preview2-28215 - 2.1.0-preview2-28215 - 2.1.0-preview2-28215 - 2.1.0-preview2-28215 + 2.1.0-preview2-15694 + 2.1.0-preview2-30020 + 2.1.0-preview2-30020 + 2.1.0-preview2-30020 + 2.1.0-preview2-30020 2.0.0 2.1.0-preview2-26130-04 15.3.0 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 232cb858c2..6f294ef0e6 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview2-15692 -commithash:5d9f445ce3f8492451a6f461df7e739bbed6a7f8 +version:2.1.0-preview2-15694 +commithash:f61af02b48e89592c9aadb7ebaebe84228666c3b From a063328ba2c7eab3427dddb068547a99d07ee11b Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sat, 3 Feb 2018 02:51:35 +0000 Subject: [PATCH 324/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 6 +++--- korebuild-lock.txt | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 4aa9e9db7f..875796c3b7 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,10 +3,10 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview2-15692 - 2.1.0-preview2-28215 + 2.1.0-preview2-15694 + 2.1.0-preview2-30020 4.5.0-preview2-26130-01 - 2.1.0-preview2-28215 + 2.1.0-preview2-30020 2.0.0 2.1.0-preview2-26130-04 15.3.0 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 232cb858c2..6f294ef0e6 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview2-15692 -commithash:5d9f445ce3f8492451a6f461df7e739bbed6a7f8 +version:2.1.0-preview2-15694 +commithash:f61af02b48e89592c9aadb7ebaebe84228666c3b From 52249d6038339a493739c8bc82eebfad7ae2c81b Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Fri, 9 Feb 2018 11:43:03 -0800 Subject: [PATCH 325/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 10 +++++----- korebuild-lock.txt | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index b9e0d540c9..3636a35d79 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,11 +3,11 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview2-15694 - 2.1.0-preview2-30020 - 2.1.0-preview2-30020 - 2.1.0-preview2-30020 - 2.1.0-preview2-30020 + 2.1.0-preview2-15698 + 2.1.0-preview2-30066 + 2.1.0-preview2-30066 + 2.1.0-preview2-30066 + 2.1.0-preview2-30066 2.0.0 2.1.0-preview2-26130-04 15.3.0 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 6f294ef0e6..3e2b56b91b 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview2-15694 -commithash:f61af02b48e89592c9aadb7ebaebe84228666c3b +version:2.1.0-preview2-15698 +commithash:7216e5068cb1957e09d45fcbe58a744dd5c2de73 From 6d0dfc114552ab09b1dd1afac133ae5107b7d32d Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Fri, 9 Feb 2018 11:48:21 -0800 Subject: [PATCH 326/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 6 +++--- korebuild-lock.txt | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 875796c3b7..399130aab9 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,10 +3,10 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview2-15694 - 2.1.0-preview2-30020 + 2.1.0-preview2-15698 + 2.1.0-preview2-30066 4.5.0-preview2-26130-01 - 2.1.0-preview2-30020 + 2.1.0-preview2-30066 2.0.0 2.1.0-preview2-26130-04 15.3.0 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 6f294ef0e6..3e2b56b91b 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview2-15694 -commithash:f61af02b48e89592c9aadb7ebaebe84228666c3b +version:2.1.0-preview2-15698 +commithash:7216e5068cb1957e09d45fcbe58a744dd5c2de73 From fbfafa06ce20d5a236c284e5a6bdaecc1fa1cea7 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 11 Feb 2018 12:24:21 -0800 Subject: [PATCH 327/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 3636a35d79..e01cfca7d0 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,16 +4,16 @@ 2.1.0-preview2-15698 - 2.1.0-preview2-30066 - 2.1.0-preview2-30066 - 2.1.0-preview2-30066 - 2.1.0-preview2-30066 + 2.1.0-preview2-30077 + 2.1.0-preview2-30077 + 2.1.0-preview2-30077 + 2.1.0-preview2-30077 2.0.0 2.1.0-preview2-26130-04 15.3.0 4.5.0-preview2-26130-01 2.3.1 - 2.3.1 + 2.4.0-beta.1.build3945 From 55169b1c92400bfbe1347ccf7d6e6379c244af19 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 11 Feb 2018 12:29:38 -0800 Subject: [PATCH 328/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 399130aab9..31af71a3d5 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,9 +4,9 @@ 2.1.0-preview2-15698 - 2.1.0-preview2-30066 + 2.1.0-preview2-30077 4.5.0-preview2-26130-01 - 2.1.0-preview2-30066 + 2.1.0-preview2-30077 2.0.0 2.1.0-preview2-26130-04 15.3.0 @@ -14,7 +14,7 @@ 10.0.1 0.8.0 2.3.1 - 2.3.1 + 2.4.0-beta.1.build3945 From bee7ced54f90756c41362bbbb5a7cadac4b1ca3d Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 18 Feb 2018 12:17:51 -0800 Subject: [PATCH 329/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 10 +++++----- korebuild-lock.txt | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index e01cfca7d0..9e7f39f805 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,11 +3,11 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview2-15698 - 2.1.0-preview2-30077 - 2.1.0-preview2-30077 - 2.1.0-preview2-30077 - 2.1.0-preview2-30077 + 2.1.0-preview2-15707 + 2.1.0-preview2-30131 + 2.1.0-preview2-30131 + 2.1.0-preview2-30131 + 2.1.0-preview2-30131 2.0.0 2.1.0-preview2-26130-04 15.3.0 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 3e2b56b91b..89d0ad3d15 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview2-15698 -commithash:7216e5068cb1957e09d45fcbe58a744dd5c2de73 +version:2.1.0-preview2-15707 +commithash:e74e53f129ab34332947fea7ac7b7591b027cb22 From 686b15825db4368e4738bfaa337d35ce2b138d6d Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 18 Feb 2018 12:22:41 -0800 Subject: [PATCH 330/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 6 +++--- korebuild-lock.txt | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 31af71a3d5..ffa9c07cb7 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,10 +3,10 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview2-15698 - 2.1.0-preview2-30077 + 2.1.0-preview2-15707 + 2.1.0-preview2-30131 4.5.0-preview2-26130-01 - 2.1.0-preview2-30077 + 2.1.0-preview2-30131 2.0.0 2.1.0-preview2-26130-04 15.3.0 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 3e2b56b91b..89d0ad3d15 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview2-15698 -commithash:7216e5068cb1957e09d45fcbe58a744dd5c2de73 +version:2.1.0-preview2-15707 +commithash:e74e53f129ab34332947fea7ac7b7591b027cb22 From b7873a42496513170360b374a1e5b9dd6203e7b6 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 21 Feb 2018 18:26:57 -0800 Subject: [PATCH 331/471] Use FeatureBranchVersionSuffix when generating VersionSuffix --- version.props | 1 + 1 file changed, 1 insertion(+) diff --git a/version.props b/version.props index 370d5ababd..65c8a07e37 100644 --- a/version.props +++ b/version.props @@ -5,6 +5,7 @@ $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final t000 + $(VersionSuffix)-$([System.Text.RegularExpressions.Regex]::Replace('$(FeatureBranchVersionSuffix)', '[^\w-]', '-')) $(VersionSuffix)-$(BuildNumber) From d851546646260e5f7d94d655175d118fff7df368 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 21 Feb 2018 18:27:01 -0800 Subject: [PATCH 332/471] Use FeatureBranchVersionSuffix when generating VersionSuffix --- version.props | 1 + 1 file changed, 1 insertion(+) diff --git a/version.props b/version.props index 370d5ababd..65c8a07e37 100644 --- a/version.props +++ b/version.props @@ -5,6 +5,7 @@ $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final t000 + $(VersionSuffix)-$([System.Text.RegularExpressions.Regex]::Replace('$(FeatureBranchVersionSuffix)', '[^\w-]', '-')) $(VersionSuffix)-$(BuildNumber) From a992ce0d7b881dc6cf9fa579c22d5c7b4ecc8d83 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Mon, 26 Feb 2018 11:01:44 -0800 Subject: [PATCH 333/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 12 ++++++------ korebuild-lock.txt | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 9e7f39f805..a4ee848bcc 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,14 +3,14 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview2-15707 - 2.1.0-preview2-30131 - 2.1.0-preview2-30131 - 2.1.0-preview2-30131 - 2.1.0-preview2-30131 + 2.1.0-preview2-15721 + 2.1.0-preview2-30187 + 2.1.0-preview2-30187 + 2.1.0-preview2-30187 + 2.1.0-preview2-30187 2.0.0 2.1.0-preview2-26130-04 - 15.3.0 + 15.6.0 4.5.0-preview2-26130-01 2.3.1 2.4.0-beta.1.build3945 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 89d0ad3d15..e6c7fddffa 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview2-15707 -commithash:e74e53f129ab34332947fea7ac7b7591b027cb22 +version:2.1.0-preview2-15721 +commithash:f9bb4be59e39938ec59a6975257e26099b0d03c1 From a1b6c4c7aad396bdd887448de21b41229a268c5f Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Mon, 26 Feb 2018 11:06:37 -0800 Subject: [PATCH 334/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 8 ++++---- korebuild-lock.txt | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index ffa9c07cb7..4ada242a87 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,13 +3,13 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview2-15707 - 2.1.0-preview2-30131 + 2.1.0-preview2-15721 + 2.1.0-preview2-30187 4.5.0-preview2-26130-01 - 2.1.0-preview2-30131 + 2.1.0-preview2-30187 2.0.0 2.1.0-preview2-26130-04 - 15.3.0 + 15.6.0 4.7.49 10.0.1 0.8.0 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 89d0ad3d15..e6c7fddffa 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview2-15707 -commithash:e74e53f129ab34332947fea7ac7b7591b027cb22 +version:2.1.0-preview2-15721 +commithash:f9bb4be59e39938ec59a6975257e26099b0d03c1 From 63f03228106c61b6af2965c874f09758f7a5439e Mon Sep 17 00:00:00 2001 From: Ajay Bhargav Baaskaran Date: Tue, 27 Feb 2018 12:41:38 -0800 Subject: [PATCH 335/471] Allow whitespace and backslash in path --- .../Internal/PathHelpers.cs | 7 ++--- .../JsonPatchDocument.cs | 12 ++++----- ...nPatchDocumentJsonPropertyAttributeTest.cs | 26 +++++++++++++++++++ 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/PathHelpers.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/PathHelpers.cs index d46314c148..f0afedb60e 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Internal/PathHelpers.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Internal/PathHelpers.cs @@ -2,23 +2,24 @@ // 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 NormalizePath(string path) + 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("//") || path.Contains(" ") || path.Contains("\\")) + if (path.Contains("//")) { throw new JsonPatchException(Resources.FormatInvalidValueForPath(path), null); } - if (!(path.StartsWith("/"))) + if (!path.StartsWith("/", StringComparison.Ordinal)) { return "/" + path; } diff --git a/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocument.cs b/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocument.cs index 4420e576bf..b6539caae8 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocument.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocument.cs @@ -60,7 +60,7 @@ namespace Microsoft.AspNetCore.JsonPatch throw new ArgumentNullException(nameof(path)); } - Operations.Add(new Operation("add", PathHelpers.NormalizePath(path), null, value)); + Operations.Add(new Operation("add", PathHelpers.ValidateAndNormalizePath(path), null, value)); return this; } @@ -77,7 +77,7 @@ namespace Microsoft.AspNetCore.JsonPatch throw new ArgumentNullException(nameof(path)); } - Operations.Add(new Operation("remove", PathHelpers.NormalizePath(path), null, null)); + Operations.Add(new Operation("remove", PathHelpers.ValidateAndNormalizePath(path), null, null)); return this; } @@ -95,7 +95,7 @@ namespace Microsoft.AspNetCore.JsonPatch throw new ArgumentNullException(nameof(path)); } - Operations.Add(new Operation("replace", PathHelpers.NormalizePath(path), null, value)); + Operations.Add(new Operation("replace", PathHelpers.ValidateAndNormalizePath(path), null, value)); return this; } @@ -113,7 +113,7 @@ namespace Microsoft.AspNetCore.JsonPatch throw new ArgumentNullException(nameof(path)); } - Operations.Add(new Operation("test", PathHelpers.NormalizePath(path), null, value)); + Operations.Add(new Operation("test", PathHelpers.ValidateAndNormalizePath(path), null, value)); return this; } @@ -136,7 +136,7 @@ namespace Microsoft.AspNetCore.JsonPatch throw new ArgumentNullException(nameof(path)); } - Operations.Add(new Operation("move", PathHelpers.NormalizePath(path), PathHelpers.NormalizePath(from))); + Operations.Add(new Operation("move", PathHelpers.ValidateAndNormalizePath(path), PathHelpers.ValidateAndNormalizePath(from))); return this; } @@ -159,7 +159,7 @@ namespace Microsoft.AspNetCore.JsonPatch throw new ArgumentNullException(nameof(path)); } - Operations.Add(new Operation("copy", PathHelpers.NormalizePath(path), PathHelpers.NormalizePath(from))); + Operations.Add(new Operation("copy", PathHelpers.ValidateAndNormalizePath(path), PathHelpers.ValidateAndNormalizePath(from))); return this; } diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs index f5d6377989..a9c3d8500b 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs @@ -24,6 +24,23 @@ namespace Microsoft.AspNetCore.JsonPatch 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() { @@ -46,6 +63,15 @@ namespace Microsoft.AspNetCore.JsonPatch 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] From a34a3e319ed1c07562a0dfcd6908485462242a1e Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 6 Mar 2018 10:03:51 -0800 Subject: [PATCH 336/471] Use dotnet-core feed in repos --- build/sources.props | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build/sources.props b/build/sources.props index 9feff29d09..9215df9751 100644 --- a/build/sources.props +++ b/build/sources.props @@ -1,10 +1,11 @@ - + $(DotNetRestoreSources) $(RestoreSources); + https://dotnet.myget.org/F/dotnet-core/api/v3/index.json; https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json; https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json; From 2e5964f709aedcff192587bd5ad636392b8c5797 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 6 Mar 2018 10:03:51 -0800 Subject: [PATCH 337/471] Prepend FeatureBranchVersionPrefix if FeatureBranchVersionSuffix is specified --- version.props | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/version.props b/version.props index 65c8a07e37..a11ea1ed52 100644 --- a/version.props +++ b/version.props @@ -5,7 +5,8 @@ $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final t000 - $(VersionSuffix)-$([System.Text.RegularExpressions.Regex]::Replace('$(FeatureBranchVersionSuffix)', '[^\w-]', '-')) + a- + $(FeatureBranchVersionPrefix)$(VersionSuffix)-$([System.Text.RegularExpressions.Regex]::Replace('$(FeatureBranchVersionSuffix)', '[^\w-]', '-')) $(VersionSuffix)-$(BuildNumber) From a2c82ff883b77fca85d43b3ece416166339a2472 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 6 Mar 2018 10:04:32 -0800 Subject: [PATCH 338/471] Use dotnet-core feed in repos --- build/sources.props | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build/sources.props b/build/sources.props index 9feff29d09..9215df9751 100644 --- a/build/sources.props +++ b/build/sources.props @@ -1,10 +1,11 @@ - + $(DotNetRestoreSources) $(RestoreSources); + https://dotnet.myget.org/F/dotnet-core/api/v3/index.json; https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json; https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json; From 93817a51930e4734b6fa22025afbdc7df48abeae Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 6 Mar 2018 10:04:32 -0800 Subject: [PATCH 339/471] Prepend FeatureBranchVersionPrefix if FeatureBranchVersionSuffix is specified --- version.props | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/version.props b/version.props index 65c8a07e37..a11ea1ed52 100644 --- a/version.props +++ b/version.props @@ -5,7 +5,8 @@ $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final t000 - $(VersionSuffix)-$([System.Text.RegularExpressions.Regex]::Replace('$(FeatureBranchVersionSuffix)', '[^\w-]', '-')) + a- + $(FeatureBranchVersionPrefix)$(VersionSuffix)-$([System.Text.RegularExpressions.Regex]::Replace('$(FeatureBranchVersionSuffix)', '[^\w-]', '-')) $(VersionSuffix)-$(BuildNumber) From d5e6c6a81e857d798a4375e5524262037f49776e Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Thu, 8 Mar 2018 13:00:13 -0800 Subject: [PATCH 340/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 14 +++++++------- korebuild-lock.txt | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index a4ee848bcc..30d6e336de 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,15 +3,15 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview2-15721 - 2.1.0-preview2-30187 - 2.1.0-preview2-30187 - 2.1.0-preview2-30187 - 2.1.0-preview2-30187 + 2.1.0-preview2-15728 + 2.1.0-preview2-30272 + 2.1.0-preview2-30272 + 2.1.0-preview2-30272 + 2.1.0-preview2-30272 2.0.0 - 2.1.0-preview2-26130-04 + 2.1.0-preview2-26225-03 15.6.0 - 4.5.0-preview2-26130-01 + 4.5.0-preview2-26224-02 2.3.1 2.4.0-beta.1.build3945 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index e6c7fddffa..138d848db1 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview2-15721 -commithash:f9bb4be59e39938ec59a6975257e26099b0d03c1 +version:2.1.0-preview2-15728 +commithash:393377068ddcf51dfee0536536d455f57a828b06 From 1f29add11975cb7858a6845fbf76b6f571099d64 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Thu, 8 Mar 2018 13:05:01 -0800 Subject: [PATCH 341/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 10 +++++----- korebuild-lock.txt | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 4ada242a87..9335150db5 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,12 +3,12 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview2-15721 - 2.1.0-preview2-30187 - 4.5.0-preview2-26130-01 - 2.1.0-preview2-30187 + 2.1.0-preview2-15728 + 2.1.0-preview2-30272 + 4.5.0-preview2-26224-02 + 2.1.0-preview2-30272 2.0.0 - 2.1.0-preview2-26130-04 + 2.1.0-preview2-26225-03 15.6.0 4.7.49 10.0.1 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index e6c7fddffa..138d848db1 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview2-15721 -commithash:f9bb4be59e39938ec59a6975257e26099b0d03c1 +version:2.1.0-preview2-15728 +commithash:393377068ddcf51dfee0536536d455f57a828b06 From 7b13960c6d6bf71867a500eb8c1c1f7d89f6aa12 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 16 Mar 2018 11:14:38 -0700 Subject: [PATCH 342/471] Branching for 2.1.0-preview2 --- build/dependencies.props | 14 +++++++------- build/repo.props | 4 ++-- build/sources.props | 2 +- korebuild-lock.txt | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 30d6e336de..e2ad411a23 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,15 +3,15 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview2-15728 - 2.1.0-preview2-30272 - 2.1.0-preview2-30272 - 2.1.0-preview2-30272 - 2.1.0-preview2-30272 + 2.1.0-preview2-15742 + 2.1.0-preview2-30355 + 2.1.0-preview2-30355 + 2.1.0-preview2-30355 + 2.1.0-preview2-30355 2.0.0 - 2.1.0-preview2-26225-03 + 2.1.0-preview2-26314-02 15.6.0 - 4.5.0-preview2-26224-02 + 4.5.0-preview2-26313-01 2.3.1 2.4.0-beta.1.build3945 diff --git a/build/repo.props b/build/repo.props index 78b0ce5879..d94ff7d00d 100644 --- a/build/repo.props +++ b/build/repo.props @@ -1,10 +1,10 @@ - + Internal.AspNetCore.Universe.Lineup - https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json + https://dotnet.myget.org/F/aspnetcore-release/api/v3/index.json diff --git a/build/sources.props b/build/sources.props index 9215df9751..36045f12b5 100644 --- a/build/sources.props +++ b/build/sources.props @@ -6,7 +6,7 @@ $(RestoreSources); https://dotnet.myget.org/F/dotnet-core/api/v3/index.json; - https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json; + https://dotnet.myget.org/F/aspnetcore-release/api/v3/index.json; https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json; diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 138d848db1..e40ef6651b 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview2-15728 -commithash:393377068ddcf51dfee0536536d455f57a828b06 +version:2.1.0-preview2-15742 +commithash:21fbb0f2c3fe4a9216e2d59632b98cfd7d685962 From 416dc545af13192f78e6ad286554b1c7923adfcc Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 16 Mar 2018 11:15:22 -0700 Subject: [PATCH 343/471] Branching for 2.1.0-preview2 --- build/dependencies.props | 10 +++++----- build/repo.props | 4 ++-- build/sources.props | 2 +- korebuild-lock.txt | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 9335150db5..e11bd088f7 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,12 +3,12 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview2-15728 - 2.1.0-preview2-30272 - 4.5.0-preview2-26224-02 - 2.1.0-preview2-30272 + 2.1.0-preview2-15742 + 2.1.0-preview2-30355 + 4.5.0-preview2-26313-01 + 2.1.0-preview2-30355 2.0.0 - 2.1.0-preview2-26225-03 + 2.1.0-preview2-26314-02 15.6.0 4.7.49 10.0.1 diff --git a/build/repo.props b/build/repo.props index 78b0ce5879..d94ff7d00d 100644 --- a/build/repo.props +++ b/build/repo.props @@ -1,10 +1,10 @@ - + Internal.AspNetCore.Universe.Lineup - https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json + https://dotnet.myget.org/F/aspnetcore-release/api/v3/index.json diff --git a/build/sources.props b/build/sources.props index 9215df9751..36045f12b5 100644 --- a/build/sources.props +++ b/build/sources.props @@ -6,7 +6,7 @@ $(RestoreSources); https://dotnet.myget.org/F/dotnet-core/api/v3/index.json; - https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json; + https://dotnet.myget.org/F/aspnetcore-release/api/v3/index.json; https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json; diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 138d848db1..e40ef6651b 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview2-15728 -commithash:393377068ddcf51dfee0536536d455f57a828b06 +version:2.1.0-preview2-15742 +commithash:21fbb0f2c3fe4a9216e2d59632b98cfd7d685962 From a12fa391fb7fab32b52abc4a9b002a427ba928a3 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 16 Mar 2018 11:26:21 -0700 Subject: [PATCH 344/471] Update version prefix to preview3 --- version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.props b/version.props index a11ea1ed52..24f2b00a0a 100644 --- a/version.props +++ b/version.props @@ -1,7 +1,7 @@ 2.1.0 - preview2 + preview3 $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final t000 From 39959a72ef8cc0a5cbbb7d078d6cabd592cd6a05 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 16 Mar 2018 11:26:57 -0700 Subject: [PATCH 345/471] Update version prefix to preview3 --- version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.props b/version.props index a11ea1ed52..24f2b00a0a 100644 --- a/version.props +++ b/version.props @@ -1,7 +1,7 @@ 2.1.0 - preview2 + preview3 $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final t000 From cb9a800b6b424edefe673e3988cd7a3f3759eb7b Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 16 Mar 2018 12:29:47 -0700 Subject: [PATCH 346/471] Update KoreBuild channel --- korebuild.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/korebuild.json b/korebuild.json index bd5d51a51b..678d8bb948 100644 --- a/korebuild.json +++ b/korebuild.json @@ -1,4 +1,4 @@ { - "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/dev/tools/korebuild.schema.json", - "channel": "dev" + "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/release/2.1/tools/korebuild.schema.json", + "channel": "release/2.1" } From ed7c645939b3e9ca361b1af5a6c5bc0deeda22a1 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 16 Mar 2018 12:30:53 -0700 Subject: [PATCH 347/471] Update KoreBuild channel --- korebuild.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/korebuild.json b/korebuild.json index bd5d51a51b..678d8bb948 100644 --- a/korebuild.json +++ b/korebuild.json @@ -1,4 +1,4 @@ { - "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/dev/tools/korebuild.schema.json", - "channel": "dev" + "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/release/2.1/tools/korebuild.schema.json", + "channel": "release/2.1" } From c8f5b2e3ae543c4ccb705b01a0702e4b89653860 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Wed, 14 Mar 2018 15:33:57 -0700 Subject: [PATCH 348/471] Set 2.0 baselines --- build/dependencies.props | 2 +- korebuild-lock.txt | 4 ++-- .../baseline.netcore.json | 10 +++++++++- .../baseline.netcore.json | 2 +- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index e2ad411a23..dc9945767a 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,7 +3,7 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview2-15742 + 2.1.0-preview2-15744 2.1.0-preview2-30355 2.1.0-preview2-30355 2.1.0-preview2-30355 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index e40ef6651b..f531e7b0f7 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview2-15742 -commithash:21fbb0f2c3fe4a9216e2d59632b98cfd7d685962 +version:2.1.0-preview2-15744 +commithash:9e15cb6062ab5b9790d3fa699e018543a6950713 diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/baseline.netcore.json b/src/Microsoft.AspNetCore.Html.Abstractions/baseline.netcore.json index 7e3a4d0d00..b0b320e216 100644 --- a/src/Microsoft.AspNetCore.Html.Abstractions/baseline.netcore.json +++ b/src/Microsoft.AspNetCore.Html.Abstractions/baseline.netcore.json @@ -1,5 +1,5 @@ { - "AssemblyIdentity": "Microsoft.AspNetCore.Html.Abstractions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "AssemblyIdentity": "Microsoft.AspNetCore.Html.Abstractions, Version=2.0.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", "Types": [ { "Name": "Microsoft.AspNetCore.Html.HtmlContentBuilder", @@ -9,6 +9,14 @@ "Microsoft.AspNetCore.Html.IHtmlContentBuilder" ], "Members": [ + { + "Kind": "Method", + "Name": "get_Count", + "Parameters": [], + "ReturnType": "System.Int32", + "Visibility": "Public", + "GenericParameter": [] + }, { "Kind": "Method", "Name": "Append", diff --git a/src/Microsoft.Extensions.WebEncoders/baseline.netcore.json b/src/Microsoft.Extensions.WebEncoders/baseline.netcore.json index db16203ed1..cc93cc7458 100644 --- a/src/Microsoft.Extensions.WebEncoders/baseline.netcore.json +++ b/src/Microsoft.Extensions.WebEncoders/baseline.netcore.json @@ -1,5 +1,5 @@ { - "AssemblyIdentity": "Microsoft.Extensions.WebEncoders, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "AssemblyIdentity": "Microsoft.Extensions.WebEncoders, Version=2.0.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", "Types": [ { "Name": "Microsoft.Extensions.WebEncoders.WebEncoderOptions", From ede8417bb1a3da411cc1b2fb3cf77a2926dc59cc Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 25 Mar 2018 15:39:25 -0700 Subject: [PATCH 349/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 16 ++++++++-------- korebuild-lock.txt | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 30d6e336de..7d0d2b0bf2 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,15 +3,15 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview2-15728 - 2.1.0-preview2-30272 - 2.1.0-preview2-30272 - 2.1.0-preview2-30272 - 2.1.0-preview2-30272 + 2.1.0-preview3-17001 + 2.1.0-preview3-32037 + 2.1.0-preview3-32037 + 2.1.0-preview3-32037 + 2.1.0-preview3-32037 2.0.0 - 2.1.0-preview2-26225-03 - 15.6.0 - 4.5.0-preview2-26224-02 + 2.1.0-preview2-26314-02 + 15.6.1 + 4.5.0-preview2-26313-01 2.3.1 2.4.0-beta.1.build3945 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 138d848db1..3a326c7d58 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview2-15728 -commithash:393377068ddcf51dfee0536536d455f57a828b06 +version:2.1.0-preview3-17001 +commithash:dda68c56abf0d3b911fe6a2315872c446b314585 From 94374a2af5d4e28daf124502b1e630b041506f2d Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 25 Mar 2018 15:45:13 -0700 Subject: [PATCH 350/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 14 +++++++------- korebuild-lock.txt | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 9335150db5..6678906caa 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,15 +3,15 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview2-15728 - 2.1.0-preview2-30272 - 4.5.0-preview2-26224-02 - 2.1.0-preview2-30272 + 2.1.0-preview3-17001 + 2.1.0-preview3-32037 + 4.5.0-preview2-26313-01 + 2.1.0-preview3-32037 2.0.0 - 2.1.0-preview2-26225-03 - 15.6.0 + 2.1.0-preview2-26314-02 + 15.6.1 4.7.49 - 10.0.1 + 11.0.1 0.8.0 2.3.1 2.4.0-beta.1.build3945 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 138d848db1..3a326c7d58 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview2-15728 -commithash:393377068ddcf51dfee0536536d455f57a828b06 +version:2.1.0-preview3-17001 +commithash:dda68c56abf0d3b911fe6a2315872c446b314585 From 00d595932354b96431e6684b49c3b436bae08e20 Mon Sep 17 00:00:00 2001 From: "Nate McMaster (automated)" Date: Wed, 28 Mar 2018 10:45:08 -0700 Subject: [PATCH 351/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 16 ++++++++-------- korebuild-lock.txt | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index dc9945767a..8776af33dd 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,15 +3,15 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview2-15744 - 2.1.0-preview2-30355 - 2.1.0-preview2-30355 - 2.1.0-preview2-30355 - 2.1.0-preview2-30355 + 2.1.0-preview2-15749 + 2.1.0-preview2-30478 + 2.1.0-preview2-30478 + 2.1.0-preview2-30478 + 2.1.0-preview2-30478 2.0.0 - 2.1.0-preview2-26314-02 - 15.6.0 - 4.5.0-preview2-26313-01 + 2.1.0-preview2-26326-03 + 15.6.1 + 4.5.0-preview2-26326-04 2.3.1 2.4.0-beta.1.build3945 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index f531e7b0f7..b8e036fe2c 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview2-15744 -commithash:9e15cb6062ab5b9790d3fa699e018543a6950713 +version:2.1.0-preview2-15749 +commithash:5544c9ab20fa5e24b9e155d8958a3c3b6f5f9df9 From fc1b2ab5489337be36e56b86b3ab7cf71f6596f2 Mon Sep 17 00:00:00 2001 From: "Nate McMaster (automated)" Date: Wed, 28 Mar 2018 10:52:05 -0700 Subject: [PATCH 352/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 14 +++++++------- korebuild-lock.txt | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index e11bd088f7..47dc1d300d 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,15 +3,15 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview2-15742 - 2.1.0-preview2-30355 - 4.5.0-preview2-26313-01 - 2.1.0-preview2-30355 + 2.1.0-preview2-15749 + 2.1.0-preview2-30478 + 4.5.0-preview2-26326-04 + 2.1.0-preview2-30478 2.0.0 - 2.1.0-preview2-26314-02 - 15.6.0 + 2.1.0-preview2-26326-03 + 15.6.1 4.7.49 - 10.0.1 + 11.0.2 0.8.0 2.3.1 2.4.0-beta.1.build3945 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index e40ef6651b..b8e036fe2c 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview2-15742 -commithash:21fbb0f2c3fe4a9216e2d59632b98cfd7d685962 +version:2.1.0-preview2-15749 +commithash:5544c9ab20fa5e24b9e155d8958a3c3b6f5f9df9 From ac3bce603baa478103f7c3c432ececa6a1744fd9 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Tue, 3 Apr 2018 22:26:47 +0000 Subject: [PATCH 353/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 14 +++++++------- korebuild-lock.txt | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 7d0d2b0bf2..ae5170fa13 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,15 +3,15 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview3-17001 - 2.1.0-preview3-32037 - 2.1.0-preview3-32037 - 2.1.0-preview3-32037 - 2.1.0-preview3-32037 + 2.1.0-preview3-17002 + 2.1.0-preview3-32110 + 2.1.0-preview3-32110 + 2.1.0-preview3-32110 + 2.1.0-preview3-32110 2.0.0 - 2.1.0-preview2-26314-02 + 2.1.0-preview3-26331-01 15.6.1 - 4.5.0-preview2-26313-01 + 4.5.0-preview3-26331-02 2.3.1 2.4.0-beta.1.build3945 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 3a326c7d58..b3af0b8bce 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview3-17001 -commithash:dda68c56abf0d3b911fe6a2315872c446b314585 +version:2.1.0-preview3-17002 +commithash:b8e4e6ab104adc94c0719bb74229870e9b584a7f From 9969beccbcf471d8269f40a2196fe25e0f066716 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Tue, 3 Apr 2018 22:32:28 +0000 Subject: [PATCH 354/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 12 ++++++------ korebuild-lock.txt | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 6678906caa..dec32e9f37 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,15 +3,15 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview3-17001 - 2.1.0-preview3-32037 - 4.5.0-preview2-26313-01 - 2.1.0-preview3-32037 + 2.1.0-preview3-17002 + 2.1.0-preview3-32110 + 4.5.0-preview3-26331-02 + 2.1.0-preview3-32110 2.0.0 - 2.1.0-preview2-26314-02 + 2.1.0-preview3-26331-01 15.6.1 4.7.49 - 11.0.1 + 11.0.2 0.8.0 2.3.1 2.4.0-beta.1.build3945 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 3a326c7d58..b3af0b8bce 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview3-17001 -commithash:dda68c56abf0d3b911fe6a2315872c446b314585 +version:2.1.0-preview3-17002 +commithash:b8e4e6ab104adc94c0719bb74229870e9b584a7f From 411d583631e8ef191e8dbcc4eadfff0d99787d6b Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 15 Apr 2018 14:09:55 -0700 Subject: [PATCH 355/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 14 +++++++------- korebuild-lock.txt | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index ae5170fa13..d4c70b5608 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,15 +3,15 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview3-17002 - 2.1.0-preview3-32110 - 2.1.0-preview3-32110 - 2.1.0-preview3-32110 - 2.1.0-preview3-32110 + 2.1.0-preview3-17018 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 2.0.0 - 2.1.0-preview3-26331-01 + 2.1.0-preview3-26413-05 15.6.1 - 4.5.0-preview3-26331-02 + 4.5.0-preview3-26413-02 2.3.1 2.4.0-beta.1.build3945 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index b3af0b8bce..b419d767b9 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview3-17002 -commithash:b8e4e6ab104adc94c0719bb74229870e9b584a7f +version:2.1.0-preview3-17018 +commithash:af264ca131f212b5ba8aafbc5110fc0fc510a2be From 4ca59af5469ddd6c38d80430944c19b13b8936f5 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 15 Apr 2018 14:16:23 -0700 Subject: [PATCH 356/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 10 +++++----- korebuild-lock.txt | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index dec32e9f37..1fa3452a34 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,12 +3,12 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview3-17002 - 2.1.0-preview3-32110 - 4.5.0-preview3-26331-02 - 2.1.0-preview3-32110 + 2.1.0-preview3-17018 + 2.1.0-preview3-32233 + 4.5.0-preview3-26413-02 + 2.1.0-preview3-32233 2.0.0 - 2.1.0-preview3-26331-01 + 2.1.0-preview3-26413-05 15.6.1 4.7.49 11.0.2 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index b3af0b8bce..b419d767b9 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview3-17002 -commithash:b8e4e6ab104adc94c0719bb74229870e9b584a7f +version:2.1.0-preview3-17018 +commithash:af264ca131f212b5ba8aafbc5110fc0fc510a2be From 6c2432e5448fc71889e374fee3f6c7472c18628a Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Mon, 16 Apr 2018 16:57:26 -0700 Subject: [PATCH 357/471] Branching for 2.1.0-rc1 --- build/repo.props | 3 ++- korebuild.json | 4 ++-- version.props | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/build/repo.props b/build/repo.props index 78b0ce5879..dab1601c88 100644 --- a/build/repo.props +++ b/build/repo.props @@ -1,9 +1,10 @@ - + Internal.AspNetCore.Universe.Lineup + 2.1.0-rc1-* https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json diff --git a/korebuild.json b/korebuild.json index bd5d51a51b..678d8bb948 100644 --- a/korebuild.json +++ b/korebuild.json @@ -1,4 +1,4 @@ { - "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/dev/tools/korebuild.schema.json", - "channel": "dev" + "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/release/2.1/tools/korebuild.schema.json", + "channel": "release/2.1" } diff --git a/version.props b/version.props index 24f2b00a0a..e27532787e 100644 --- a/version.props +++ b/version.props @@ -1,7 +1,7 @@ 2.1.0 - preview3 + rc1 $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final t000 From 5fd1e648e2ec4eba89223efc1ab16b2f932bc196 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Mon, 16 Apr 2018 16:57:31 -0700 Subject: [PATCH 358/471] Update version number to 2.2.0 --- version.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.props b/version.props index 24f2b00a0a..44985cedb3 100644 --- a/version.props +++ b/version.props @@ -1,7 +1,7 @@ - 2.1.0 - preview3 + 2.2.0 + preview1 $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final t000 From 40d5c7f839f86a927bd39777e8b4198aafc098ee Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Mon, 16 Apr 2018 16:58:44 -0700 Subject: [PATCH 359/471] Branching for 2.1.0-rc1 --- build/repo.props | 3 ++- korebuild.json | 4 ++-- version.props | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/build/repo.props b/build/repo.props index 78b0ce5879..dab1601c88 100644 --- a/build/repo.props +++ b/build/repo.props @@ -1,9 +1,10 @@ - + Internal.AspNetCore.Universe.Lineup + 2.1.0-rc1-* https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json diff --git a/korebuild.json b/korebuild.json index bd5d51a51b..678d8bb948 100644 --- a/korebuild.json +++ b/korebuild.json @@ -1,4 +1,4 @@ { - "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/dev/tools/korebuild.schema.json", - "channel": "dev" + "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/release/2.1/tools/korebuild.schema.json", + "channel": "release/2.1" } diff --git a/version.props b/version.props index 24f2b00a0a..e27532787e 100644 --- a/version.props +++ b/version.props @@ -1,7 +1,7 @@ 2.1.0 - preview3 + rc1 $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final t000 From 3aaf2726d9bf70cb3d922e3bcb43cf0f9516c67c Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Mon, 16 Apr 2018 16:58:49 -0700 Subject: [PATCH 360/471] Update version number to 2.2.0 --- version.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.props b/version.props index 24f2b00a0a..44985cedb3 100644 --- a/version.props +++ b/version.props @@ -1,7 +1,7 @@ - 2.1.0 - preview3 + 2.2.0 + preview1 $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final t000 From b392ef5ed7c1b509ceadfa9261c671bb78f6334e Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Thu, 19 Apr 2018 16:39:10 -0700 Subject: [PATCH 361/471] Set NETStandardImplicitPackageVersion via dependencies.props --- Directory.Build.targets | 1 + build/dependencies.props | 1 + 2 files changed, 2 insertions(+) diff --git a/Directory.Build.targets b/Directory.Build.targets index 894b1d0cf8..53b3f6e1da 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -2,5 +2,6 @@ $(MicrosoftNETCoreApp20PackageVersion) $(MicrosoftNETCoreApp21PackageVersion) + $(NETStandardLibrary20PackageVersion) diff --git a/build/dependencies.props b/build/dependencies.props index d4c70b5608..577926b344 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -11,6 +11,7 @@ 2.0.0 2.1.0-preview3-26413-05 15.6.1 + 2.0.1 4.5.0-preview3-26413-02 2.3.1 2.4.0-beta.1.build3945 From 6c6cd890865f4d6f61900c7274bd38bfca9d4f00 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Thu, 19 Apr 2018 16:40:16 -0700 Subject: [PATCH 362/471] Set NETStandardImplicitPackageVersion via dependencies.props --- Directory.Build.targets | 1 + build/dependencies.props | 1 + 2 files changed, 2 insertions(+) diff --git a/Directory.Build.targets b/Directory.Build.targets index 894b1d0cf8..53b3f6e1da 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -2,5 +2,6 @@ $(MicrosoftNETCoreApp20PackageVersion) $(MicrosoftNETCoreApp21PackageVersion) + $(NETStandardLibrary20PackageVersion) diff --git a/build/dependencies.props b/build/dependencies.props index 1fa3452a34..89f812caa6 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -11,6 +11,7 @@ 2.1.0-preview3-26413-05 15.6.1 4.7.49 + 2.0.1 11.0.2 0.8.0 2.3.1 From 065f9f9dbcba5cb8d1c37dc70f922a0b6609d934 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Thu, 19 Apr 2018 22:21:45 -0700 Subject: [PATCH 363/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 14 +++++++------- korebuild-lock.txt | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 577926b344..dc2db7956c 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,16 +3,16 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview3-17018 - 2.1.0-preview3-32233 - 2.1.0-preview3-32233 - 2.1.0-preview3-32233 - 2.1.0-preview3-32233 + 2.1.0-rc1-15774 + 2.1.0-rc1-30613 + 2.1.0-rc1-30613 + 2.1.0-rc1-30613 + 2.1.0-rc1-30613 2.0.0 - 2.1.0-preview3-26413-05 + 2.1.0-rc1-26419-02 15.6.1 2.0.1 - 4.5.0-preview3-26413-02 + 4.5.0-rc1-26419-03 2.3.1 2.4.0-beta.1.build3945 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index b419d767b9..9d4ef8c888 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview3-17018 -commithash:af264ca131f212b5ba8aafbc5110fc0fc510a2be +version:2.1.0-rc1-15774 +commithash:ed5ca9de3c652347dbb0158a9a65eff3471d2114 From 09232faae42de90b96180645f83f82a4989e91b3 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Thu, 19 Apr 2018 22:27:34 -0700 Subject: [PATCH 364/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 10 +++++----- korebuild-lock.txt | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 89f812caa6..649af28432 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,12 +3,12 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview3-17018 - 2.1.0-preview3-32233 - 4.5.0-preview3-26413-02 - 2.1.0-preview3-32233 + 2.1.0-rc1-15774 + 2.1.0-rc1-30613 + 4.5.0-rc1-26419-03 + 2.1.0-rc1-30613 2.0.0 - 2.1.0-preview3-26413-05 + 2.1.0-rc1-26419-02 15.6.1 4.7.49 2.0.1 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index b419d767b9..9d4ef8c888 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview3-17018 -commithash:af264ca131f212b5ba8aafbc5110fc0fc510a2be +version:2.1.0-rc1-15774 +commithash:ed5ca9de3c652347dbb0158a9a65eff3471d2114 From 39101569474435dd67f1d8ec7e872f675019eb92 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Mon, 23 Apr 2018 12:08:58 -0700 Subject: [PATCH 365/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 14 +++++++------- korebuild-lock.txt | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index dc2db7956c..360c641b28 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,16 +3,16 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-rc1-15774 - 2.1.0-rc1-30613 - 2.1.0-rc1-30613 - 2.1.0-rc1-30613 - 2.1.0-rc1-30613 + 2.2.0-preview1-17037 + 2.2.0-preview1-34029 + 2.2.0-preview1-34029 + 2.2.0-preview1-34029 + 2.2.0-preview1-34029 2.0.0 - 2.1.0-rc1-26419-02 + 2.1.0-preview3-26413-05 15.6.1 2.0.1 - 4.5.0-rc1-26419-03 + 4.5.0-preview3-26413-02 2.3.1 2.4.0-beta.1.build3945 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index b419d767b9..f27a67b442 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview3-17018 -commithash:af264ca131f212b5ba8aafbc5110fc0fc510a2be +version:2.2.0-preview1-17037 +commithash:557055a86cbdc359c97d4fb1c2d23a3dc7ae731e From 39b31e022395c4750374140073c10970944d0c87 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Mon, 23 Apr 2018 12:15:24 -0700 Subject: [PATCH 366/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 10 +++++----- korebuild-lock.txt | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 649af28432..1b21c323aa 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,12 +3,12 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-rc1-15774 - 2.1.0-rc1-30613 - 4.5.0-rc1-26419-03 - 2.1.0-rc1-30613 + 2.2.0-preview1-17037 + 2.2.0-preview1-34029 + 4.5.0-preview3-26413-02 + 2.2.0-preview1-34029 2.0.0 - 2.1.0-rc1-26419-02 + 2.1.0-preview3-26413-05 15.6.1 4.7.49 2.0.1 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index b419d767b9..f27a67b442 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview3-17018 -commithash:af264ca131f212b5ba8aafbc5110fc0fc510a2be +version:2.2.0-preview1-17037 +commithash:557055a86cbdc359c97d4fb1c2d23a3dc7ae731e From e9896d3be06f966612a469d304274bd81cb353f3 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 29 Apr 2018 12:16:29 -0700 Subject: [PATCH 367/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 16 ++++++++-------- korebuild-lock.txt | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 360c641b28..509b7d5539 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,16 +3,16 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.2.0-preview1-17037 - 2.2.0-preview1-34029 - 2.2.0-preview1-34029 - 2.2.0-preview1-34029 - 2.2.0-preview1-34029 + 2.2.0-preview1-17042 + 2.2.0-preview1-34066 + 2.2.0-preview1-34066 + 2.2.0-preview1-34066 + 2.2.0-preview1-34066 2.0.0 - 2.1.0-preview3-26413-05 + 2.2.0-preview1-26424-04 15.6.1 - 2.0.1 - 4.5.0-preview3-26413-02 + 2.0.3 + 4.5.0-preview3-26423-04 2.3.1 2.4.0-beta.1.build3945 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index f27a67b442..335e579e06 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-17037 -commithash:557055a86cbdc359c97d4fb1c2d23a3dc7ae731e +version:2.2.0-preview1-17042 +commithash:edf0705d014293c260de763543784330514db9a3 From d442f8c498b910f3fc12dcb6e2ab1cadafe608b9 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 29 Apr 2018 12:22:39 -0700 Subject: [PATCH 368/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 12 ++++++------ korebuild-lock.txt | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 1b21c323aa..03999cb59f 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,15 +3,15 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.2.0-preview1-17037 - 2.2.0-preview1-34029 - 4.5.0-preview3-26413-02 - 2.2.0-preview1-34029 + 2.2.0-preview1-17042 + 2.2.0-preview1-34066 + 4.5.0-preview3-26423-04 + 2.2.0-preview1-34066 2.0.0 - 2.1.0-preview3-26413-05 + 2.2.0-preview1-26424-04 15.6.1 4.7.49 - 2.0.1 + 2.0.3 11.0.2 0.8.0 2.3.1 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index f27a67b442..335e579e06 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-17037 -commithash:557055a86cbdc359c97d4fb1c2d23a3dc7ae731e +version:2.2.0-preview1-17042 +commithash:edf0705d014293c260de763543784330514db9a3 From b8b90e1bed89ed2783b6d85d81828f7ef96d6d46 Mon Sep 17 00:00:00 2001 From: "Nate McMaster (automated)" Date: Mon, 30 Apr 2018 14:51:40 -0700 Subject: [PATCH 369/471] Bump version to 2.1.0-rtm --- version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.props b/version.props index e27532787e..b9552451d8 100644 --- a/version.props +++ b/version.props @@ -1,7 +1,7 @@ 2.1.0 - rc1 + rtm $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final t000 From 4f3e31431a0c96d687b2ef41e436f878ae79db31 Mon Sep 17 00:00:00 2001 From: "Nate McMaster (automated)" Date: Mon, 30 Apr 2018 14:51:42 -0700 Subject: [PATCH 370/471] Bump version to 2.1.0-rtm --- version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.props b/version.props index e27532787e..b9552451d8 100644 --- a/version.props +++ b/version.props @@ -1,7 +1,7 @@ 2.1.0 - rc1 + rtm $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final t000 From dd2eaa1ed3f9e7bebd3c7b001a2f7a95bf4b6c09 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Fri, 4 May 2018 07:35:13 -0700 Subject: [PATCH 371/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 16 ++++++++-------- korebuild-lock.txt | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index dc2db7956c..007238eb66 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,16 +3,16 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-rc1-15774 - 2.1.0-rc1-30613 - 2.1.0-rc1-30613 - 2.1.0-rc1-30613 - 2.1.0-rc1-30613 + 2.1.0-rtm-15783 + 2.1.0-rtm-30721 + 2.1.0-rtm-30721 + 2.1.0-rtm-30721 + 2.1.0-rtm-30721 2.0.0 - 2.1.0-rc1-26419-02 + 2.1.0-rtm-26502-02 15.6.1 - 2.0.1 - 4.5.0-rc1-26419-03 + 2.0.3 + 4.5.0-rtm-26502-02 2.3.1 2.4.0-beta.1.build3945 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 9d4ef8c888..3673744db9 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-rc1-15774 -commithash:ed5ca9de3c652347dbb0158a9a65eff3471d2114 +version:2.1.0-rtm-15783 +commithash:5fc2b2f607f542a2ffde11c19825e786fc1a3774 From 54e6ffce343b4b6113e824ccbb4006f786ad8e8c Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Fri, 4 May 2018 07:41:29 -0700 Subject: [PATCH 372/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 12 ++++++------ korebuild-lock.txt | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 649af28432..acedb0a6ca 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,15 +3,15 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-rc1-15774 - 2.1.0-rc1-30613 - 4.5.0-rc1-26419-03 - 2.1.0-rc1-30613 + 2.1.0-rtm-15783 + 2.1.0-rtm-30721 + 4.5.0-rtm-26502-02 + 2.1.0-rtm-30721 2.0.0 - 2.1.0-rc1-26419-02 + 2.1.0-rtm-26502-02 15.6.1 4.7.49 - 2.0.1 + 2.0.3 11.0.2 0.8.0 2.3.1 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 9d4ef8c888..3673744db9 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-rc1-15774 -commithash:ed5ca9de3c652347dbb0158a9a65eff3471d2114 +version:2.1.0-rtm-15783 +commithash:5fc2b2f607f542a2ffde11c19825e786fc1a3774 From 7fe6dae3c5e4844bac3f0d36039c456e03a41e04 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 6 May 2018 12:15:43 -0700 Subject: [PATCH 373/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 10 +++++----- korebuild-lock.txt | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 509b7d5539..de67da1c2a 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,11 +3,11 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.2.0-preview1-17042 - 2.2.0-preview1-34066 - 2.2.0-preview1-34066 - 2.2.0-preview1-34066 - 2.2.0-preview1-34066 + 2.2.0-preview1-17047 + 2.2.0-preview1-34135 + 2.2.0-preview1-34135 + 2.2.0-preview1-34135 + 2.2.0-preview1-34135 2.0.0 2.2.0-preview1-26424-04 15.6.1 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 335e579e06..a16d4b9ee4 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-17042 -commithash:edf0705d014293c260de763543784330514db9a3 +version:2.2.0-preview1-17047 +commithash:e1957b52ddc8b62bd39c5c400322fccb5364624c From 376a542a5dc6faff669423655a801667a3a1a029 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 6 May 2018 12:21:51 -0700 Subject: [PATCH 374/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 6 +++--- korebuild-lock.txt | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 03999cb59f..3389a20912 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,10 +3,10 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.2.0-preview1-17042 - 2.2.0-preview1-34066 + 2.2.0-preview1-17047 + 2.2.0-preview1-34135 4.5.0-preview3-26423-04 - 2.2.0-preview1-34066 + 2.2.0-preview1-34135 2.0.0 2.2.0-preview1-26424-04 15.6.1 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 335e579e06..a16d4b9ee4 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-17042 -commithash:edf0705d014293c260de763543784330514db9a3 +version:2.2.0-preview1-17047 +commithash:e1957b52ddc8b62bd39c5c400322fccb5364624c From 73592b904b82d8f11d1d508dd54e5d08ebeeed1f Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Mon, 7 May 2018 15:11:20 -0700 Subject: [PATCH 375/471] Upgrade to netcoreapp22 --- Directory.Build.targets | 5 ++++- build/dependencies.props | 13 +++++++------ build/repo.props | 3 ++- korebuild-lock.txt | 4 ++-- test/Directory.Build.props | 4 ++-- 5 files changed, 17 insertions(+), 12 deletions(-) diff --git a/Directory.Build.targets b/Directory.Build.targets index 53b3f6e1da..78626b773e 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -1,7 +1,10 @@ - + $(MicrosoftNETCoreApp20PackageVersion) $(MicrosoftNETCoreApp21PackageVersion) + $(MicrosoftNETCoreApp22PackageVersion) $(NETStandardLibrary20PackageVersion) + + 99.9 diff --git a/build/dependencies.props b/build/dependencies.props index de67da1c2a..56bced18f5 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,15 +1,16 @@ - + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.2.0-preview1-17047 - 2.2.0-preview1-34135 - 2.2.0-preview1-34135 - 2.2.0-preview1-34135 - 2.2.0-preview1-34135 + 2.2.0-preview1-17048 + 2.2.0-preview1-34140 + 2.2.0-preview1-34140 + 2.2.0-preview1-34140 + 2.2.0-preview1-34140 2.0.0 2.2.0-preview1-26424-04 + 2.2.0-preview1-26502-01 15.6.1 2.0.3 4.5.0-preview3-26423-04 diff --git a/build/repo.props b/build/repo.props index 78b0ce5879..17a98ac7e7 100644 --- a/build/repo.props +++ b/build/repo.props @@ -1,4 +1,4 @@ - + @@ -10,5 +10,6 @@ + diff --git a/korebuild-lock.txt b/korebuild-lock.txt index a16d4b9ee4..2573a03995 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-17047 -commithash:e1957b52ddc8b62bd39c5c400322fccb5364624c +version:2.2.0-preview1-17048 +commithash:de14a0ee5fb48508ee8a29c14280a2928f8dabf8 diff --git a/test/Directory.Build.props b/test/Directory.Build.props index 0b706cbca5..d5d5869c56 100644 --- a/test/Directory.Build.props +++ b/test/Directory.Build.props @@ -2,9 +2,9 @@ - netcoreapp2.1 + netcoreapp2.2 $(DeveloperBuildTestTfms) - netcoreapp2.1;netcoreapp2.0 + $(StandardTestTfms);net461 From d7ac5c57efe1e7b3c8b1492107b5bf17744c83f7 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Mon, 7 May 2018 15:12:35 -0700 Subject: [PATCH 376/471] Upgrade to netcoreapp22 --- Directory.Build.targets | 5 ++++- build/dependencies.props | 9 +++++---- build/repo.props | 3 ++- korebuild-lock.txt | 4 ++-- test/Directory.Build.props | 4 ++-- 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/Directory.Build.targets b/Directory.Build.targets index 53b3f6e1da..78626b773e 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -1,7 +1,10 @@ - + $(MicrosoftNETCoreApp20PackageVersion) $(MicrosoftNETCoreApp21PackageVersion) + $(MicrosoftNETCoreApp22PackageVersion) $(NETStandardLibrary20PackageVersion) + + 99.9 diff --git a/build/dependencies.props b/build/dependencies.props index 3389a20912..441743f2aa 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,14 +1,15 @@ - + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.2.0-preview1-17047 - 2.2.0-preview1-34135 + 2.2.0-preview1-17048 + 2.2.0-preview1-34140 4.5.0-preview3-26423-04 - 2.2.0-preview1-34135 + 2.2.0-preview1-34140 2.0.0 2.2.0-preview1-26424-04 + 2.2.0-preview1-26502-01 15.6.1 4.7.49 2.0.3 diff --git a/build/repo.props b/build/repo.props index 78b0ce5879..17a98ac7e7 100644 --- a/build/repo.props +++ b/build/repo.props @@ -1,4 +1,4 @@ - + @@ -10,5 +10,6 @@ + diff --git a/korebuild-lock.txt b/korebuild-lock.txt index a16d4b9ee4..2573a03995 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-17047 -commithash:e1957b52ddc8b62bd39c5c400322fccb5364624c +version:2.2.0-preview1-17048 +commithash:de14a0ee5fb48508ee8a29c14280a2928f8dabf8 diff --git a/test/Directory.Build.props b/test/Directory.Build.props index 98685a5e13..fc128b9108 100644 --- a/test/Directory.Build.props +++ b/test/Directory.Build.props @@ -2,9 +2,9 @@ - netcoreapp2.1 + netcoreapp2.2 $(DeveloperBuildTestTfms) - $(StandardTestTfms);netcoreapp2.0 + $(StandardTestTfms) $(StandardTestTfms);net461 From 4d92d76b64e3229ea61679945eb8a8bdf4537226 Mon Sep 17 00:00:00 2001 From: DHumphreys Date: Fri, 11 May 2018 15:08:09 -0400 Subject: [PATCH 377/471] Initial commit providing the AdapterFactory directly to the ObjectAdapter to all for customization of the Adapter selection and the ability to override the built in adapters to leverage their ability as much as possible. --- .../Adapters/AdapterFactory.cs | 39 ++++++++++ .../Adapters/IAdapterFactory.cs | 22 ++++++ .../Adapters/ObjectAdapter.cs | 36 +++++++-- .../Internal/DictionaryAdapterOfTU.cs | 16 ++-- .../Internal/DynamicObjectAdapter.cs | 18 ++--- .../Internal/ListAdapter.cs | 24 +++--- .../Internal/ObjectVisitor.cs | 39 +++++----- .../Internal/PocoAdapter.cs | 16 ++-- .../JsonPatchDocument.cs | 19 ++++- .../JsonPatchDocumentOfT.cs | 19 ++++- .../Adapters/AdapterFactoryTests.cs | 73 +++++++++++++++++++ .../Adapters/TestDynamicObject.cs | 10 +++ 12 files changed, 263 insertions(+), 68 deletions(-) create mode 100644 src/Microsoft.AspNetCore.JsonPatch/Adapters/AdapterFactory.cs create mode 100644 src/Microsoft.AspNetCore.JsonPatch/Adapters/IAdapterFactory.cs create mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/Adapters/AdapterFactoryTests.cs create mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/Adapters/TestDynamicObject.cs diff --git a/src/Microsoft.AspNetCore.JsonPatch/Adapters/AdapterFactory.cs b/src/Microsoft.AspNetCore.JsonPatch/Adapters/AdapterFactory.cs new file mode 100644 index 0000000000..c963fcffdd --- /dev/null +++ b/src/Microsoft.AspNetCore.JsonPatch/Adapters/AdapterFactory.cs @@ -0,0 +1,39 @@ +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) + { + 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/Microsoft.AspNetCore.JsonPatch/Adapters/IAdapterFactory.cs b/src/Microsoft.AspNetCore.JsonPatch/Adapters/IAdapterFactory.cs new file mode 100644 index 0000000000..43ca1e65b6 --- /dev/null +++ b/src/Microsoft.AspNetCore.JsonPatch/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/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs b/src/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs index 73095b52c2..48d7e69b0f 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs @@ -18,17 +18,37 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters /// The for logging . public ObjectAdapter( IContractResolver contractResolver, - Action logErrorAction) + Action logErrorAction): + this(contractResolver, logErrorAction, new AdapterFactory()) { - ContractResolver = contractResolver ?? throw new ArgumentNullException(nameof(contractResolver)); - LogErrorAction = logErrorAction; } + /// + /// 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; set; } + /// /// Action for logging . /// @@ -75,7 +95,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters } var parsedPath = new ParsedPath(path); - var visitor = new ObjectVisitor(parsedPath, ContractResolver); + var visitor = new ObjectVisitor(parsedPath, ContractResolver, AdapterFactory); var target = objectToApplyTo; if (!visitor.TryVisit(ref target, out var adapter, out var errorMessage)) @@ -144,7 +164,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters private void Remove(string path, object objectToApplyTo, Operation operationToReport) { var parsedPath = new ParsedPath(path); - var visitor = new ObjectVisitor(parsedPath, ContractResolver); + var visitor = new ObjectVisitor(parsedPath, ContractResolver, AdapterFactory); var target = objectToApplyTo; if (!visitor.TryVisit(ref target, out var adapter, out var errorMessage)) @@ -175,7 +195,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters } var parsedPath = new ParsedPath(operation.path); - var visitor = new ObjectVisitor(parsedPath, ContractResolver); + var visitor = new ObjectVisitor(parsedPath, ContractResolver, AdapterFactory); var target = objectToApplyTo; if (!visitor.TryVisit(ref target, out var adapter, out var errorMessage)) @@ -239,7 +259,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters } var parsedPath = new ParsedPath(operation.path); - var visitor = new ObjectVisitor(parsedPath, ContractResolver); + var visitor = new ObjectVisitor(parsedPath, ContractResolver, AdapterFactory); var target = objectToApplyTo; if (!visitor.TryVisit(ref target, out var adapter, out var errorMessage)) @@ -281,7 +301,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters propertyValue = null; var parsedPath = new ParsedPath(fromLocation); - var visitor = new ObjectVisitor(parsedPath, ContractResolver); + var visitor = new ObjectVisitor(parsedPath, ContractResolver, AdapterFactory); var target = objectToGetValueFrom; if (!visitor.TryVisit(ref target, out var adapter, out var errorMessage)) diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/DictionaryAdapterOfTU.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/DictionaryAdapterOfTU.cs index 8a344e24ee..be2bbffd86 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Internal/DictionaryAdapterOfTU.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Internal/DictionaryAdapterOfTU.cs @@ -10,7 +10,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal { public class DictionaryAdapter : IAdapter { - public bool TryAdd( + public virtual bool TryAdd( object target, string segment, IContractResolver contractResolver, @@ -37,7 +37,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal return true; } - public bool TryGet( + public virtual bool TryGet( object target, string segment, IContractResolver contractResolver, @@ -66,7 +66,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal return true; } - public bool TryRemove( + public virtual bool TryRemove( object target, string segment, IContractResolver contractResolver, @@ -94,7 +94,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal return true; } - public bool TryReplace( + public virtual bool TryReplace( object target, string segment, IContractResolver contractResolver, @@ -128,7 +128,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal return true; } - public bool TryTest( + public virtual bool TryTest( object target, string segment, IContractResolver contractResolver, @@ -177,7 +177,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal } } - public bool TryTraverse( + public virtual bool TryTraverse( object target, string segment, IContractResolver contractResolver, @@ -208,7 +208,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal } } - private bool TryConvertKey(string key, out TKey convertedKey, out string errorMessage) + protected virtual bool TryConvertKey(string key, out TKey convertedKey, out string errorMessage) { var conversionResult = ConversionResultProvider.ConvertTo(key, typeof(TKey)); if (conversionResult.CanBeConverted) @@ -225,7 +225,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal } } - private bool TryConvertValue(object value, out TValue convertedValue, out string errorMessage) + protected virtual bool TryConvertValue(object value, out TValue convertedValue, out string errorMessage) { var conversionResult = ConversionResultProvider.ConvertTo(value, typeof(TValue)); if (conversionResult.CanBeConverted) diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/DynamicObjectAdapter.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/DynamicObjectAdapter.cs index fb4adeb1f2..dc3c48266f 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Internal/DynamicObjectAdapter.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Internal/DynamicObjectAdapter.cs @@ -15,7 +15,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal { public class DynamicObjectAdapter : IAdapter { - public bool TryAdd( + public virtual bool TryAdd( object target, string segment, IContractResolver contractResolver, @@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal return true; } - public bool TryGet( + public virtual bool TryGet( object target, string segment, IContractResolver contractResolver, @@ -48,7 +48,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal return true; } - public bool TryRemove( + public virtual bool TryRemove( object target, string segment, IContractResolver contractResolver, @@ -78,7 +78,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal } - public bool TryReplace( + public virtual bool TryReplace( object target, string segment, IContractResolver contractResolver, @@ -105,7 +105,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal return true; } - public bool TryTest( + public virtual bool TryTest( object target, string segment, IContractResolver contractResolver, @@ -135,7 +135,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal } } - public bool TryTraverse( + public virtual bool TryTraverse( object target, string segment, IContractResolver contractResolver, @@ -155,7 +155,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal } } - private bool TryGetDynamicObjectProperty( + protected virtual bool TryGetDynamicObjectProperty( object target, IContractResolver contractResolver, string segment, @@ -191,7 +191,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal } } - private bool TrySetDynamicObjectProperty( + protected virtual bool TrySetDynamicObjectProperty( object target, IContractResolver contractResolver, string segment, @@ -227,7 +227,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal } } - private bool TryConvertValue(object value, Type propertyType, out object convertedValue) + protected virtual bool TryConvertValue(object value, Type propertyType, out object convertedValue) { var conversionResult = ConversionResultProvider.ConvertTo(value, propertyType); if (!conversionResult.CanBeConverted) diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/ListAdapter.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/ListAdapter.cs index d1348fd5c6..597f7b9f5f 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Internal/ListAdapter.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Internal/ListAdapter.cs @@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal { public class ListAdapter : IAdapter { - public bool TryAdd( + public virtual bool TryAdd( object target, string segment, IContractResolver contractResolver, @@ -50,7 +50,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal return true; } - public bool TryGet( + public virtual bool TryGet( object target, string segment, IContractResolver contractResolver, @@ -84,7 +84,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal return true; } - public bool TryRemove( + public virtual bool TryRemove( object target, string segment, IContractResolver contractResolver, @@ -115,7 +115,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal return true; } - public bool TryReplace( + public virtual bool TryReplace( object target, string segment, IContractResolver contractResolver, @@ -152,7 +152,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal return true; } - public bool TryTest( + public virtual bool TryTest( object target, string segment, IContractResolver contractResolver, @@ -189,7 +189,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal } } - public bool TryTraverse( + public virtual bool TryTraverse( object target, string segment, IContractResolver contractResolver, @@ -224,7 +224,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal return true; } - private bool TryConvertValue( + protected virtual bool TryConvertValue( object originalValue, Type listTypeArgument, string segment, @@ -244,7 +244,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal return true; } - private bool TryGetListTypeArgument(IList list, out Type listTypeArgument, out string errorMessage) + 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(); @@ -272,7 +272,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal } } - private bool TryGetPositionInfo( + protected virtual bool TryGetPositionInfo( IList list, string segment, OperationType operationType, @@ -318,7 +318,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal } } - private struct PositionInfo + protected struct PositionInfo { public PositionInfo(PositionType type, int index) { @@ -330,7 +330,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal public int Index { get; } } - private enum PositionType + protected enum PositionType { Index, // valid index EndOfList, // '-' @@ -338,7 +338,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal OutOfBounds } - private enum OperationType + protected enum OperationType { Add, Remove, diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/ObjectVisitor.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/ObjectVisitor.cs index 8994f0aa52..a988afa300 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Internal/ObjectVisitor.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Internal/ObjectVisitor.cs @@ -3,19 +3,38 @@ using System; using System.Collections; +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) @@ -48,25 +67,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal private IAdapter SelectAdapter(object targetObject) { - var jsonContract = _contractResolver.ResolveContract(targetObject.GetType()); - - if (targetObject 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(); - } + return _adapterFactory.Create(targetObject, _contractResolver); } } } diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/PocoAdapter.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/PocoAdapter.cs index 0eee0fc889..5ba3e5587b 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Internal/PocoAdapter.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Internal/PocoAdapter.cs @@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal { public class PocoAdapter : IAdapter { - public bool TryAdd( + public virtual bool TryAdd( object target, string segment, IContractResolver contractResolver, @@ -43,7 +43,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal return true; } - public bool TryGet( + public virtual bool TryGet( object target, string segment, IContractResolver contractResolver, @@ -69,7 +69,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal return true; } - public bool TryRemove( + public virtual bool TryRemove( object target, string segment, IContractResolver contractResolver, @@ -102,7 +102,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal return true; } - public bool TryReplace( + public virtual bool TryReplace( object target, string segment, IContractResolver @@ -134,7 +134,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal return true; } - public bool TryTest( + public virtual bool TryTest( object target, string segment, IContractResolver @@ -171,7 +171,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal return true; } - public bool TryTraverse( + public virtual bool TryTraverse( object target, string segment, IContractResolver contractResolver, @@ -197,7 +197,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal return false; } - private bool TryGetJsonProperty( + protected virtual bool TryGetJsonProperty( object target, IContractResolver contractResolver, string segment, @@ -220,7 +220,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal return false; } - private bool TryConvertValue(object value, Type propertyType, out object convertedValue) + protected virtual bool TryConvertValue(object value, Type propertyType, out object convertedValue) { var conversionResult = ConversionResultProvider.ConvertTo(value, propertyType); if (!conversionResult.CanBeConverted) diff --git a/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocument.cs b/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocument.cs index b6539caae8..1888ea6b4b 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocument.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocument.cs @@ -174,7 +174,7 @@ namespace Microsoft.AspNetCore.JsonPatch throw new ArgumentNullException(nameof(objectToApplyTo)); } - ApplyTo(objectToApplyTo, new ObjectAdapter(ContractResolver, logErrorAction: null)); + ApplyTo(objectToApplyTo, new ObjectAdapter(ContractResolver, null, new AdapterFactory())); } /// @@ -183,13 +183,28 @@ namespace Microsoft.AspNetCore.JsonPatch /// 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)); } - var adapter = new ObjectAdapter(ContractResolver, logErrorAction); + if (adapter == null) + { + throw new ArgumentNullException(nameof(adapter)); + } + foreach (var op in Operations) { try diff --git a/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs b/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs index 8ae1430185..3db0aac458 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs @@ -697,7 +697,7 @@ namespace Microsoft.AspNetCore.JsonPatch throw new ArgumentNullException(nameof(objectToApplyTo)); } - ApplyTo(objectToApplyTo, new ObjectAdapter(ContractResolver, logErrorAction: null)); + ApplyTo(objectToApplyTo, new ObjectAdapter(ContractResolver, null, new AdapterFactory())); } /// @@ -706,13 +706,28 @@ namespace Microsoft.AspNetCore.JsonPatch /// 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)); } - var adapter = new ObjectAdapter(ContractResolver, logErrorAction); + if (adapter == null) + { + throw new ArgumentNullException(nameof(adapter)); + } + foreach (var op in Operations) { try diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Adapters/AdapterFactoryTests.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Adapters/AdapterFactoryTests.cs new file mode 100644 index 0000000000..1e961c29e9 --- /dev/null +++ b/test/Microsoft.AspNetCore.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/test/Microsoft.AspNetCore.JsonPatch.Test/Adapters/TestDynamicObject.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Adapters/TestDynamicObject.cs new file mode 100644 index 0000000000..08371f25c6 --- /dev/null +++ b/test/Microsoft.AspNetCore.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 + { } +} From 146427fa5ade76db9c9a965a535a104a1de830d0 Mon Sep 17 00:00:00 2001 From: DHumphreys Date: Fri, 11 May 2018 16:33:59 -0400 Subject: [PATCH 378/471] Updates per PR feedback --- .../Adapters/AdapterFactory.cs | 10 ++++++++++ .../Adapters/ObjectAdapter.cs | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.AspNetCore.JsonPatch/Adapters/AdapterFactory.cs b/src/Microsoft.AspNetCore.JsonPatch/Adapters/AdapterFactory.cs index c963fcffdd..82aaa56a70 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Adapters/AdapterFactory.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Adapters/AdapterFactory.cs @@ -15,6 +15,16 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters /// 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) diff --git a/src/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs b/src/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs index 48d7e69b0f..d625176376 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs @@ -47,7 +47,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters /// /// Gets or sets the /// - public IAdapterFactory AdapterFactory { get; set; } + public IAdapterFactory AdapterFactory { get; } /// /// Action for logging . From d67c2cb2cc2bb582357bb54606f3e4d5d4ab6fb9 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 13 May 2018 14:08:54 -0700 Subject: [PATCH 379/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 18 +++++++++--------- korebuild-lock.txt | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 56bced18f5..0715a36542 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,19 +1,19 @@ - + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.2.0-preview1-17048 - 2.2.0-preview1-34140 - 2.2.0-preview1-34140 - 2.2.0-preview1-34140 - 2.2.0-preview1-34140 + 2.2.0-preview1-17051 + 2.2.0-preview1-34184 + 2.2.0-preview1-34184 + 2.2.0-preview1-34184 + 2.2.0-preview1-34184 2.0.0 - 2.2.0-preview1-26424-04 - 2.2.0-preview1-26502-01 + 2.1.0-rc1 + 2.2.0-preview1-26509-06 15.6.1 2.0.3 - 4.5.0-preview3-26423-04 + 4.6.0-preview1-26508-04 2.3.1 2.4.0-beta.1.build3945 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 2573a03995..89629b454c 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-17048 -commithash:de14a0ee5fb48508ee8a29c14280a2928f8dabf8 +version:2.2.0-preview1-17051 +commithash:253c3a480063bc3abaa5cde42f6e27b58457ef9b From 98d374d01c537044375203a54ec813f76ecd2d32 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 13 May 2018 14:14:38 -0700 Subject: [PATCH 380/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 14 +++++++------- korebuild-lock.txt | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 441743f2aa..81510fd56a 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,15 +1,15 @@ - + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.2.0-preview1-17048 - 2.2.0-preview1-34140 - 4.5.0-preview3-26423-04 - 2.2.0-preview1-34140 + 2.2.0-preview1-17051 + 2.2.0-preview1-34184 + 4.6.0-preview1-26508-04 + 2.2.0-preview1-34184 2.0.0 - 2.2.0-preview1-26424-04 - 2.2.0-preview1-26502-01 + 2.1.0-rc1 + 2.2.0-preview1-26509-06 15.6.1 4.7.49 2.0.3 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 2573a03995..89629b454c 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-17048 -commithash:de14a0ee5fb48508ee8a29c14280a2928f8dabf8 +version:2.2.0-preview1-17051 +commithash:253c3a480063bc3abaa5cde42f6e27b58457ef9b From b4be87d7a369065177ce505b778969423bb2adbf Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 20 May 2018 19:32:03 +0000 Subject: [PATCH 381/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 10 +++++----- korebuild-lock.txt | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 0715a36542..c873c30462 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,11 +3,11 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.2.0-preview1-17051 - 2.2.0-preview1-34184 - 2.2.0-preview1-34184 - 2.2.0-preview1-34184 - 2.2.0-preview1-34184 + 2.2.0-preview1-17060 + 2.2.0-preview1-34255 + 2.2.0-preview1-34255 + 2.2.0-preview1-34255 + 2.2.0-preview1-34255 2.0.0 2.1.0-rc1 2.2.0-preview1-26509-06 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 89629b454c..cf2fff7def 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-17051 -commithash:253c3a480063bc3abaa5cde42f6e27b58457ef9b +version:2.2.0-preview1-17060 +commithash:25b4b134d6f8f7b461928f0d495cfc695ccabb5b From 38c530f265b8953c190af0fd79edabbeaba1e47d Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 20 May 2018 19:37:47 +0000 Subject: [PATCH 382/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 6 +++--- korebuild-lock.txt | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 81510fd56a..99209a80a1 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,10 +3,10 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.2.0-preview1-17051 - 2.2.0-preview1-34184 + 2.2.0-preview1-17060 + 2.2.0-preview1-34255 4.6.0-preview1-26508-04 - 2.2.0-preview1-34184 + 2.2.0-preview1-34255 2.0.0 2.1.0-rc1 2.2.0-preview1-26509-06 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 89629b454c..cf2fff7def 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-17051 -commithash:253c3a480063bc3abaa5cde42f6e27b58457ef9b +version:2.2.0-preview1-17060 +commithash:25b4b134d6f8f7b461928f0d495cfc695ccabb5b From 79a90e5ed85f7aaa05dadc584173480fe99a89b6 Mon Sep 17 00:00:00 2001 From: "Nate McMaster (automated)" Date: Fri, 25 May 2018 16:14:17 -0700 Subject: [PATCH 383/471] Update bootstrapper scripts (automated commit) [ci skip] --- run.ps1 | 25 +++++++++++++++++++------ run.sh | 33 +++++++++++++++++++++++++++++---- 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/run.ps1 b/run.ps1 index 27dcf848f8..3b27382468 100644 --- a/run.ps1 +++ b/run.ps1 @@ -26,12 +26,18 @@ The base url where build tools can be downloaded. Overrides the value from the c .PARAMETER Update Updates KoreBuild to the latest version even if a lock file is present. +.PARAMETER Reinstall +Re-installs KoreBuild + .PARAMETER ConfigFile The path to the configuration file that stores values. Defaults to korebuild.json. .PARAMETER ToolsSourceSuffix The Suffix to append to the end of the ToolsSource. Useful for query strings in blob stores. +.PARAMETER CI +Sets up CI specific settings and variables. + .PARAMETER Arguments Arguments to be passed to the command @@ -65,8 +71,10 @@ param( [string]$ToolsSource, [Alias('u')] [switch]$Update, - [string]$ConfigFile, + [switch]$Reinstall, [string]$ToolsSourceSuffix, + [string]$ConfigFile = $null, + [switch]$CI, [Parameter(ValueFromRemainingArguments = $true)] [string[]]$Arguments ) @@ -93,6 +101,10 @@ function Get-KoreBuild { $version = $version.TrimStart('version:').Trim() $korebuildPath = Join-Paths $DotNetHome ('buildtools', 'korebuild', $version) + if ($Reinstall -and (Test-Path $korebuildPath)) { + Remove-Item -Force -Recurse $korebuildPath + } + if (!(Test-Path $korebuildPath)) { Write-Host -ForegroundColor Magenta "Downloading KoreBuild $version" New-Item -ItemType Directory -Path $korebuildPath | Out-Null @@ -101,9 +113,9 @@ function Get-KoreBuild { try { $tmpfile = Join-Path ([IO.Path]::GetTempPath()) "KoreBuild-$([guid]::NewGuid()).zip" Get-RemoteFile $remotePath $tmpfile $ToolsSourceSuffix - if (Get-Command -Name 'Expand-Archive' -ErrorAction Ignore) { + if (Get-Command -Name 'Microsoft.PowerShell.Archive\Expand-Archive' -ErrorAction Ignore) { # Use built-in commands where possible as they are cross-plat compatible - Expand-Archive -Path $tmpfile -DestinationPath $korebuildPath + Microsoft.PowerShell.Archive\Expand-Archive -Path $tmpfile -DestinationPath $korebuildPath } else { # Fallback to old approach for old installations of PowerShell @@ -167,8 +179,9 @@ if (Test-Path $ConfigFile) { } } catch { - Write-Warning "$ConfigFile could not be read. Its settings will be ignored." - Write-Warning $Error[0] + Write-Host -ForegroundColor Red $Error[0] + Write-Error "$ConfigFile contains invalid JSON." + exit 1 } } @@ -188,7 +201,7 @@ $korebuildPath = Get-KoreBuild Import-Module -Force -Scope Local (Join-Path $korebuildPath 'KoreBuild.psd1') try { - Set-KoreBuildSettings -ToolsSource $ToolsSource -DotNetHome $DotNetHome -RepoPath $Path -ConfigFile $ConfigFile + Set-KoreBuildSettings -ToolsSource $ToolsSource -DotNetHome $DotNetHome -RepoPath $Path -ConfigFile $ConfigFile -CI:$CI Invoke-KoreBuildCommand $Command @Arguments } finally { diff --git a/run.sh b/run.sh index 834961fc3a..02aac15874 100755 --- a/run.sh +++ b/run.sh @@ -14,10 +14,12 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" [ -z "${DOTNET_HOME:-}" ] && DOTNET_HOME="$HOME/.dotnet" verbose=false update=false +reinstall=false repo_path="$DIR" channel='' tools_source='' tools_source_suffix='' +ci=false # # Functions @@ -38,6 +40,8 @@ __usage() { echo " -s|--tools-source|-ToolsSource The base url where build tools can be downloaded. Overrides the value from the config file." echo " --tools-source-suffix|-ToolsSourceSuffix The suffix to append to tools-source. Useful for query strings." echo " -u|--update Update to the latest KoreBuild even if the lock file is present." + echo " --reinstall Reinstall KoreBuild." + echo " --ci Apply CI specific settings and environment variables." echo "" echo "Description:" echo " This function will create a file \$DIR/korebuild-lock.txt. This lock file can be committed to source, but does not have to be." @@ -62,6 +66,10 @@ get_korebuild() { version="$(echo "${version#version:}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" local korebuild_path="$DOTNET_HOME/buildtools/korebuild/$version" + if [ "$reinstall" = true ] && [ -d "$korebuild_path" ]; then + rm -rf "$korebuild_path" + fi + { if [ ! -d "$korebuild_path" ]; then mkdir -p "$korebuild_path" @@ -175,6 +183,12 @@ while [[ $# -gt 0 ]]; do -u|--update|-Update) update=true ;; + --reinstall|-[Rr]einstall) + reinstall=true + ;; + --ci|-[Cc][Ii]) + ci=true + ;; --verbose|-Verbose) verbose=true ;; @@ -206,17 +220,28 @@ if [ -f "$config_file" ]; then config_channel="$(jq -r 'select(.channel!=null) | .channel' "$config_file")" config_tools_source="$(jq -r 'select(.toolsSource!=null) | .toolsSource' "$config_file")" else - __warn "$config_file is invalid JSON. Its settings will be ignored." + _error "$config_file contains invalid JSON." + exit 1 fi elif __machine_has python ; then if python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'))" >/dev/null ; then config_channel="$(python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['channel'] if 'channel' in obj else '')")" config_tools_source="$(python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['toolsSource'] if 'toolsSource' in obj else '')")" else - __warn "$config_file is invalid JSON. Its settings will be ignored." + _error "$config_file contains invalid JSON." + exit 1 + fi + elif __machine_has python3 ; then + if python3 -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'))" >/dev/null ; then + config_channel="$(python3 -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['channel'] if 'channel' in obj else '')")" + config_tools_source="$(python3 -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['toolsSource'] if 'toolsSource' in obj else '')")" + else + _error "$config_file contains invalid JSON." + exit 1 fi else - __warn 'Missing required command: jq or pyton. Could not parse the JSON file. Its settings will be ignored.' + _error 'Missing required command: jq or python. Could not parse the JSON file.' + exit 1 fi [ ! -z "${config_channel:-}" ] && channel="$config_channel" @@ -227,5 +252,5 @@ fi [ -z "$tools_source" ] && tools_source='https://aspnetcore.blob.core.windows.net/buildtools' get_korebuild -set_korebuildsettings "$tools_source" "$DOTNET_HOME" "$repo_path" "$config_file" +set_korebuildsettings "$tools_source" "$DOTNET_HOME" "$repo_path" "$config_file" "$ci" invoke_korebuild_command "$command" "$@" From b731294dc17e3a6062ddacba9348ab8c95011bf3 Mon Sep 17 00:00:00 2001 From: "Nate McMaster (automated)" Date: Fri, 25 May 2018 16:15:53 -0700 Subject: [PATCH 384/471] Update bootstrapper scripts (automated commit) [ci skip] --- run.ps1 | 25 +++++++++++++++++++------ run.sh | 33 +++++++++++++++++++++++++++++---- 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/run.ps1 b/run.ps1 index 27dcf848f8..3b27382468 100644 --- a/run.ps1 +++ b/run.ps1 @@ -26,12 +26,18 @@ The base url where build tools can be downloaded. Overrides the value from the c .PARAMETER Update Updates KoreBuild to the latest version even if a lock file is present. +.PARAMETER Reinstall +Re-installs KoreBuild + .PARAMETER ConfigFile The path to the configuration file that stores values. Defaults to korebuild.json. .PARAMETER ToolsSourceSuffix The Suffix to append to the end of the ToolsSource. Useful for query strings in blob stores. +.PARAMETER CI +Sets up CI specific settings and variables. + .PARAMETER Arguments Arguments to be passed to the command @@ -65,8 +71,10 @@ param( [string]$ToolsSource, [Alias('u')] [switch]$Update, - [string]$ConfigFile, + [switch]$Reinstall, [string]$ToolsSourceSuffix, + [string]$ConfigFile = $null, + [switch]$CI, [Parameter(ValueFromRemainingArguments = $true)] [string[]]$Arguments ) @@ -93,6 +101,10 @@ function Get-KoreBuild { $version = $version.TrimStart('version:').Trim() $korebuildPath = Join-Paths $DotNetHome ('buildtools', 'korebuild', $version) + if ($Reinstall -and (Test-Path $korebuildPath)) { + Remove-Item -Force -Recurse $korebuildPath + } + if (!(Test-Path $korebuildPath)) { Write-Host -ForegroundColor Magenta "Downloading KoreBuild $version" New-Item -ItemType Directory -Path $korebuildPath | Out-Null @@ -101,9 +113,9 @@ function Get-KoreBuild { try { $tmpfile = Join-Path ([IO.Path]::GetTempPath()) "KoreBuild-$([guid]::NewGuid()).zip" Get-RemoteFile $remotePath $tmpfile $ToolsSourceSuffix - if (Get-Command -Name 'Expand-Archive' -ErrorAction Ignore) { + if (Get-Command -Name 'Microsoft.PowerShell.Archive\Expand-Archive' -ErrorAction Ignore) { # Use built-in commands where possible as they are cross-plat compatible - Expand-Archive -Path $tmpfile -DestinationPath $korebuildPath + Microsoft.PowerShell.Archive\Expand-Archive -Path $tmpfile -DestinationPath $korebuildPath } else { # Fallback to old approach for old installations of PowerShell @@ -167,8 +179,9 @@ if (Test-Path $ConfigFile) { } } catch { - Write-Warning "$ConfigFile could not be read. Its settings will be ignored." - Write-Warning $Error[0] + Write-Host -ForegroundColor Red $Error[0] + Write-Error "$ConfigFile contains invalid JSON." + exit 1 } } @@ -188,7 +201,7 @@ $korebuildPath = Get-KoreBuild Import-Module -Force -Scope Local (Join-Path $korebuildPath 'KoreBuild.psd1') try { - Set-KoreBuildSettings -ToolsSource $ToolsSource -DotNetHome $DotNetHome -RepoPath $Path -ConfigFile $ConfigFile + Set-KoreBuildSettings -ToolsSource $ToolsSource -DotNetHome $DotNetHome -RepoPath $Path -ConfigFile $ConfigFile -CI:$CI Invoke-KoreBuildCommand $Command @Arguments } finally { diff --git a/run.sh b/run.sh index 834961fc3a..02aac15874 100755 --- a/run.sh +++ b/run.sh @@ -14,10 +14,12 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" [ -z "${DOTNET_HOME:-}" ] && DOTNET_HOME="$HOME/.dotnet" verbose=false update=false +reinstall=false repo_path="$DIR" channel='' tools_source='' tools_source_suffix='' +ci=false # # Functions @@ -38,6 +40,8 @@ __usage() { echo " -s|--tools-source|-ToolsSource The base url where build tools can be downloaded. Overrides the value from the config file." echo " --tools-source-suffix|-ToolsSourceSuffix The suffix to append to tools-source. Useful for query strings." echo " -u|--update Update to the latest KoreBuild even if the lock file is present." + echo " --reinstall Reinstall KoreBuild." + echo " --ci Apply CI specific settings and environment variables." echo "" echo "Description:" echo " This function will create a file \$DIR/korebuild-lock.txt. This lock file can be committed to source, but does not have to be." @@ -62,6 +66,10 @@ get_korebuild() { version="$(echo "${version#version:}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" local korebuild_path="$DOTNET_HOME/buildtools/korebuild/$version" + if [ "$reinstall" = true ] && [ -d "$korebuild_path" ]; then + rm -rf "$korebuild_path" + fi + { if [ ! -d "$korebuild_path" ]; then mkdir -p "$korebuild_path" @@ -175,6 +183,12 @@ while [[ $# -gt 0 ]]; do -u|--update|-Update) update=true ;; + --reinstall|-[Rr]einstall) + reinstall=true + ;; + --ci|-[Cc][Ii]) + ci=true + ;; --verbose|-Verbose) verbose=true ;; @@ -206,17 +220,28 @@ if [ -f "$config_file" ]; then config_channel="$(jq -r 'select(.channel!=null) | .channel' "$config_file")" config_tools_source="$(jq -r 'select(.toolsSource!=null) | .toolsSource' "$config_file")" else - __warn "$config_file is invalid JSON. Its settings will be ignored." + _error "$config_file contains invalid JSON." + exit 1 fi elif __machine_has python ; then if python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'))" >/dev/null ; then config_channel="$(python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['channel'] if 'channel' in obj else '')")" config_tools_source="$(python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['toolsSource'] if 'toolsSource' in obj else '')")" else - __warn "$config_file is invalid JSON. Its settings will be ignored." + _error "$config_file contains invalid JSON." + exit 1 + fi + elif __machine_has python3 ; then + if python3 -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'))" >/dev/null ; then + config_channel="$(python3 -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['channel'] if 'channel' in obj else '')")" + config_tools_source="$(python3 -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['toolsSource'] if 'toolsSource' in obj else '')")" + else + _error "$config_file contains invalid JSON." + exit 1 fi else - __warn 'Missing required command: jq or pyton. Could not parse the JSON file. Its settings will be ignored.' + _error 'Missing required command: jq or python. Could not parse the JSON file.' + exit 1 fi [ ! -z "${config_channel:-}" ] && channel="$config_channel" @@ -227,5 +252,5 @@ fi [ -z "$tools_source" ] && tools_source='https://aspnetcore.blob.core.windows.net/buildtools' get_korebuild -set_korebuildsettings "$tools_source" "$DOTNET_HOME" "$repo_path" "$config_file" +set_korebuildsettings "$tools_source" "$DOTNET_HOME" "$repo_path" "$config_file" "$ci" invoke_korebuild_command "$command" "$@" From f2eb510b83b368089eddba695421594be6d51d18 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 27 May 2018 19:14:45 +0000 Subject: [PATCH 385/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 14 +++++++------- korebuild-lock.txt | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index c873c30462..0c63257c38 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,17 +3,17 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.2.0-preview1-17060 - 2.2.0-preview1-34255 - 2.2.0-preview1-34255 - 2.2.0-preview1-34255 - 2.2.0-preview1-34255 + 2.2.0-preview1-17064 + 2.2.0-preview1-34326 + 2.2.0-preview1-34326 + 2.2.0-preview1-34326 + 2.2.0-preview1-34326 2.0.0 2.1.0-rc1 - 2.2.0-preview1-26509-06 + 2.2.0-preview1-26526-03 15.6.1 2.0.3 - 4.6.0-preview1-26508-04 + 4.6.0-preview1-26525-01 2.3.1 2.4.0-beta.1.build3945 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index cf2fff7def..3028b66761 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-17060 -commithash:25b4b134d6f8f7b461928f0d495cfc695ccabb5b +version:2.2.0-preview1-17064 +commithash:5380a2461b135b261646f31d1c919ab0a7b577a8 From fdafad711b11ff22563df005741f6ec8bf86432b Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 27 May 2018 19:20:26 +0000 Subject: [PATCH 386/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 10 +++++----- korebuild-lock.txt | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 99209a80a1..9163891c8c 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,13 +3,13 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.2.0-preview1-17060 - 2.2.0-preview1-34255 - 4.6.0-preview1-26508-04 - 2.2.0-preview1-34255 + 2.2.0-preview1-17064 + 2.2.0-preview1-34326 + 4.6.0-preview1-26525-01 + 2.2.0-preview1-34326 2.0.0 2.1.0-rc1 - 2.2.0-preview1-26509-06 + 2.2.0-preview1-26526-03 15.6.1 4.7.49 2.0.3 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index cf2fff7def..3028b66761 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-17060 -commithash:25b4b134d6f8f7b461928f0d495cfc695ccabb5b +version:2.2.0-preview1-17064 +commithash:5380a2461b135b261646f31d1c919ab0a7b577a8 From f4b98641d2ae8f95682bed02802dea5beffc9b46 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Tue, 29 May 2018 09:38:05 -0700 Subject: [PATCH 387/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 14 +++++++------- korebuild-lock.txt | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 007238eb66..a1e264ee96 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,16 +3,16 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-rtm-15783 - 2.1.0-rtm-30721 - 2.1.0-rtm-30721 - 2.1.0-rtm-30721 - 2.1.0-rtm-30721 + 2.1.1-rtm-15790 + 2.1.0 + 2.1.0 + 2.1.0 + 2.1.0 2.0.0 - 2.1.0-rtm-26502-02 + 2.1.0 15.6.1 2.0.3 - 4.5.0-rtm-26502-02 + 4.5.0 2.3.1 2.4.0-beta.1.build3945 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 3673744db9..cd5b409a1e 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-rtm-15783 -commithash:5fc2b2f607f542a2ffde11c19825e786fc1a3774 +version:2.1.1-rtm-15790 +commithash:274c65868e735f29f4078c1884c61c4371ee1fc0 From e3a21b2a92ddc8d971f4f21c617bb69ca0ae3761 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Tue, 29 May 2018 09:44:06 -0700 Subject: [PATCH 388/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 10 +++++----- korebuild-lock.txt | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index acedb0a6ca..5b7c18bdae 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,12 +3,12 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-rtm-15783 - 2.1.0-rtm-30721 - 4.5.0-rtm-26502-02 - 2.1.0-rtm-30721 + 2.1.1-rtm-15790 + 2.1.0 + 4.5.0 + 2.1.0 2.0.0 - 2.1.0-rtm-26502-02 + 2.1.0 15.6.1 4.7.49 2.0.3 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 3673744db9..cd5b409a1e 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-rtm-15783 -commithash:5fc2b2f607f542a2ffde11c19825e786fc1a3774 +version:2.1.1-rtm-15790 +commithash:274c65868e735f29f4078c1884c61c4371ee1fc0 From fe4ff1a2c437d08a67282fdb4fdab9f0800842c9 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 3 Jun 2018 19:14:37 +0000 Subject: [PATCH 389/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 16 ++++++++-------- korebuild-lock.txt | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 0c63257c38..8331dd7d03 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,17 +3,17 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.2.0-preview1-17064 - 2.2.0-preview1-34326 - 2.2.0-preview1-34326 - 2.2.0-preview1-34326 - 2.2.0-preview1-34326 + 2.2.0-preview1-17067 + 2.2.0-preview1-34373 + 2.2.0-preview1-34373 + 2.2.0-preview1-34373 + 2.2.0-preview1-34373 2.0.0 - 2.1.0-rc1 - 2.2.0-preview1-26526-03 + 2.1.0 + 2.2.0-preview1-26531-03 15.6.1 2.0.3 - 4.6.0-preview1-26525-01 + 4.6.0-preview1-26531-03 2.3.1 2.4.0-beta.1.build3945 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 3028b66761..06ba6285b7 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-17064 -commithash:5380a2461b135b261646f31d1c919ab0a7b577a8 +version:2.2.0-preview1-17067 +commithash:2af0e2e3d02329b4f0290061ab9bd8c7ca1aa26f From 75126c0726bb3f19cfe7b17b2a01faf749872789 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 3 Jun 2018 19:19:39 +0000 Subject: [PATCH 390/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 12 ++++++------ korebuild-lock.txt | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 9163891c8c..2cfb5c02e8 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,13 +3,13 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.2.0-preview1-17064 - 2.2.0-preview1-34326 - 4.6.0-preview1-26525-01 - 2.2.0-preview1-34326 + 2.2.0-preview1-17067 + 2.2.0-preview1-34373 + 4.6.0-preview1-26531-03 + 2.2.0-preview1-34373 2.0.0 - 2.1.0-rc1 - 2.2.0-preview1-26526-03 + 2.1.0 + 2.2.0-preview1-26531-03 15.6.1 4.7.49 2.0.3 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 3028b66761..06ba6285b7 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-17064 -commithash:5380a2461b135b261646f31d1c919ab0a7b577a8 +version:2.2.0-preview1-17067 +commithash:2af0e2e3d02329b4f0290061ab9bd8c7ca1aa26f From 4764c44e93d0bb772def90285d16572bc2bc376c Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 5 Jun 2018 09:11:34 -0700 Subject: [PATCH 391/471] Bumping version from 2.1.0 to 2.1.1 --- version.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.props b/version.props index b9552451d8..669c874829 100644 --- a/version.props +++ b/version.props @@ -1,6 +1,6 @@ - + - 2.1.0 + 2.1.1 rtm $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final From d89db5fcd7302d08a94a995f280fb30f715b0b16 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 5 Jun 2018 09:11:39 -0700 Subject: [PATCH 392/471] Bumping version from 2.1.0 to 2.1.1 --- version.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.props b/version.props index b9552451d8..669c874829 100644 --- a/version.props +++ b/version.props @@ -1,6 +1,6 @@ - + - 2.1.0 + 2.1.1 rtm $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final From 2b9d2c1c97aad072ddae2af30f66427cae5df6e8 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 5 Jun 2018 22:32:10 -0700 Subject: [PATCH 393/471] Add certificate names for code signing --- Directory.Build.props | 2 ++ korebuild-lock.txt | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index b7176c688d..d5b8bf3650 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -13,6 +13,8 @@ $(MSBuildThisFileDirectory) $(MSBuildThisFileDirectory)build\Key.snk true + Microsoft + MicrosoftNuGet true true diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 06ba6285b7..b679b80427 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-17067 -commithash:2af0e2e3d02329b4f0290061ab9bd8c7ca1aa26f +version:2.2.0-preview1-17075 +commithash:d9f07c7f313a0af1d49f003f5424b4dbbdd3e09f From 5613206ffe01846738551f59c7f01e4136744a7a Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 5 Jun 2018 22:33:05 -0700 Subject: [PATCH 394/471] Add certificate names for code signing --- Directory.Build.props | 2 ++ korebuild-lock.txt | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 88b93729bb..0c6cb2e37f 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -14,6 +14,8 @@ $(MSBuildThisFileDirectory) $(MSBuildThisFileDirectory)build\Key.snk true + Microsoft + MicrosoftNuGet true true diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 06ba6285b7..b679b80427 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-17067 -commithash:2af0e2e3d02329b4f0290061ab9bd8c7ca1aa26f +version:2.2.0-preview1-17075 +commithash:d9f07c7f313a0af1d49f003f5424b4dbbdd3e09f From c4ce63be536d0b28e50713d0b11281633cf32729 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Thu, 7 Jun 2018 19:35:24 +0000 Subject: [PATCH 395/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 14 +++++++------- korebuild-lock.txt | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 8331dd7d03..b793716276 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,17 +3,17 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.2.0-preview1-17067 - 2.2.0-preview1-34373 - 2.2.0-preview1-34373 - 2.2.0-preview1-34373 - 2.2.0-preview1-34373 + 2.2.0-preview1-17081 + 2.2.0-preview1-34411 + 2.2.0-preview1-34411 + 2.2.0-preview1-34411 + 2.2.0-preview1-34411 2.0.0 2.1.0 - 2.2.0-preview1-26531-03 + 2.2.0-preview1-26606-01 15.6.1 2.0.3 - 4.6.0-preview1-26531-03 + 4.6.0-preview1-26605-01 2.3.1 2.4.0-beta.1.build3945 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index b679b80427..deb7e546f0 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-17075 -commithash:d9f07c7f313a0af1d49f003f5424b4dbbdd3e09f +version:2.2.0-preview1-17081 +commithash:73f09c256e2a54270951562ecc0ef4a953926c36 From d45ef9d007278b8898303574bad5393398c0a867 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Thu, 7 Jun 2018 19:40:35 +0000 Subject: [PATCH 396/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 10 +++++----- korebuild-lock.txt | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 2cfb5c02e8..15ef04fe4b 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,13 +3,13 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.2.0-preview1-17067 - 2.2.0-preview1-34373 - 4.6.0-preview1-26531-03 - 2.2.0-preview1-34373 + 2.2.0-preview1-17081 + 2.2.0-preview1-34411 + 4.6.0-preview1-26605-01 + 2.2.0-preview1-34411 2.0.0 2.1.0 - 2.2.0-preview1-26531-03 + 2.2.0-preview1-26606-01 15.6.1 4.7.49 2.0.3 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index b679b80427..deb7e546f0 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-17075 -commithash:d9f07c7f313a0af1d49f003f5424b4dbbdd3e09f +version:2.2.0-preview1-17081 +commithash:73f09c256e2a54270951562ecc0ef4a953926c36 From 556c2de4829f976d8b6d6ecb6105a50934c91616 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Thu, 7 Jun 2018 15:45:02 -0700 Subject: [PATCH 397/471] Adding VSTS file --- .vsts-pipelines/builds/ci-internal.yml | 13 +++++++++++++ .vsts-pipelines/builds/ci-public.yml | 15 +++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 .vsts-pipelines/builds/ci-internal.yml create mode 100644 .vsts-pipelines/builds/ci-public.yml diff --git a/.vsts-pipelines/builds/ci-internal.yml b/.vsts-pipelines/builds/ci-internal.yml new file mode 100644 index 0000000000..d7ceb76378 --- /dev/null +++ b/.vsts-pipelines/builds/ci-internal.yml @@ -0,0 +1,13 @@ +trigger: +- dev +- release/* + +resources: + repositories: + - repository: buildtools + type: git + name: aspnet-BuildTools + ref: refs/heads/dev + +phases: +- template: .vsts-pipelines/templates/project-ci.yml@buildtools diff --git a/.vsts-pipelines/builds/ci-public.yml b/.vsts-pipelines/builds/ci-public.yml new file mode 100644 index 0000000000..b7f25723f8 --- /dev/null +++ b/.vsts-pipelines/builds/ci-public.yml @@ -0,0 +1,15 @@ +trigger: +- dev +- release/* + +# See https://github.com/aspnet/BuildTools +resources: + repositories: + - repository: buildtools + type: github + endpoint: DotNet-Bot GitHub Connection + name: aspnet/BuildTools + ref: refs/heads/dev + +phases: +- template: .vsts-pipelines/templates/project-ci.yml@buildtools From 9657ed60e83d82ae0b9d25d704b74064f262aba3 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Thu, 7 Jun 2018 15:45:57 -0700 Subject: [PATCH 398/471] Adding VSTS file --- .vsts-pipelines/builds/ci-internal.yml | 13 +++++++++++++ .vsts-pipelines/builds/ci-public.yml | 15 +++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 .vsts-pipelines/builds/ci-internal.yml create mode 100644 .vsts-pipelines/builds/ci-public.yml diff --git a/.vsts-pipelines/builds/ci-internal.yml b/.vsts-pipelines/builds/ci-internal.yml new file mode 100644 index 0000000000..d7ceb76378 --- /dev/null +++ b/.vsts-pipelines/builds/ci-internal.yml @@ -0,0 +1,13 @@ +trigger: +- dev +- release/* + +resources: + repositories: + - repository: buildtools + type: git + name: aspnet-BuildTools + ref: refs/heads/dev + +phases: +- template: .vsts-pipelines/templates/project-ci.yml@buildtools diff --git a/.vsts-pipelines/builds/ci-public.yml b/.vsts-pipelines/builds/ci-public.yml new file mode 100644 index 0000000000..b7f25723f8 --- /dev/null +++ b/.vsts-pipelines/builds/ci-public.yml @@ -0,0 +1,15 @@ +trigger: +- dev +- release/* + +# See https://github.com/aspnet/BuildTools +resources: + repositories: + - repository: buildtools + type: github + endpoint: DotNet-Bot GitHub Connection + name: aspnet/BuildTools + ref: refs/heads/dev + +phases: +- template: .vsts-pipelines/templates/project-ci.yml@buildtools From 256f7755bae10204ba6c3b669d2289b7de33308a Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Tue, 12 Jun 2018 19:19:58 +0000 Subject: [PATCH 399/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 10 +++++----- korebuild-lock.txt | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index a1e264ee96..dc47d2ca18 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,13 +3,13 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.1-rtm-15790 + 2.1.1-rtm-15793 2.1.0 - 2.1.0 - 2.1.0 - 2.1.0 + 2.1.1 + 2.1.1 + 2.1.1 2.0.0 - 2.1.0 + 2.1.1 15.6.1 2.0.3 4.5.0 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index cd5b409a1e..bc84e0cd53 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.1-rtm-15790 -commithash:274c65868e735f29f4078c1884c61c4371ee1fc0 +version:2.1.1-rtm-15793 +commithash:988313f4b064d6c69fc6f7b845b6384a6af3447a From 1780662ac507c9b21bf7054bc1f68ccd07ed93ff Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Tue, 12 Jun 2018 19:25:45 +0000 Subject: [PATCH 400/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 6 +++--- korebuild-lock.txt | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 5b7c18bdae..c7a3e03395 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,12 +3,12 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.1-rtm-15790 + 2.1.1-rtm-15793 2.1.0 4.5.0 - 2.1.0 + 2.1.1 2.0.0 - 2.1.0 + 2.1.1 15.6.1 4.7.49 2.0.3 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index cd5b409a1e..bc84e0cd53 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.1-rtm-15790 -commithash:274c65868e735f29f4078c1884c61c4371ee1fc0 +version:2.1.1-rtm-15793 +commithash:988313f4b064d6c69fc6f7b845b6384a6af3447a From d396d85defb44dbb8032f65f295586016d16e8a2 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Wed, 13 Jun 2018 10:55:16 -0700 Subject: [PATCH 401/471] Set 2.1 baselines --- .../baseline.netcore.json | 106 +++++++++--------- .../baseline.netcore.json | 2 +- 2 files changed, 54 insertions(+), 54 deletions(-) diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/baseline.netcore.json b/src/Microsoft.AspNetCore.Html.Abstractions/baseline.netcore.json index b0b320e216..29f855f97b 100644 --- a/src/Microsoft.AspNetCore.Html.Abstractions/baseline.netcore.json +++ b/src/Microsoft.AspNetCore.Html.Abstractions/baseline.netcore.json @@ -1,5 +1,5 @@ { - "AssemblyIdentity": "Microsoft.AspNetCore.Html.Abstractions, Version=2.0.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "AssemblyIdentity": "Microsoft.AspNetCore.Html.Abstractions, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", "Types": [ { "Name": "Microsoft.AspNetCore.Html.HtmlContentBuilder", @@ -9,6 +9,58 @@ "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", @@ -76,58 +128,6 @@ "Visibility": "Public", "GenericParameter": [] }, - { - "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": "Constructor", "Name": ".ctor", diff --git a/src/Microsoft.Extensions.WebEncoders/baseline.netcore.json b/src/Microsoft.Extensions.WebEncoders/baseline.netcore.json index cc93cc7458..6da0ae0754 100644 --- a/src/Microsoft.Extensions.WebEncoders/baseline.netcore.json +++ b/src/Microsoft.Extensions.WebEncoders/baseline.netcore.json @@ -1,5 +1,5 @@ { - "AssemblyIdentity": "Microsoft.Extensions.WebEncoders, Version=2.0.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "AssemblyIdentity": "Microsoft.Extensions.WebEncoders, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", "Types": [ { "Name": "Microsoft.Extensions.WebEncoders.WebEncoderOptions", From b7c722bb68233b28475748c3c6fdabb63b854205 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Wed, 13 Jun 2018 10:55:16 -0700 Subject: [PATCH 402/471] Set 2.1 baselines --- .../baseline.netcore.json | 106 +++++++++--------- .../baseline.netcore.json | 2 +- 2 files changed, 54 insertions(+), 54 deletions(-) diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/baseline.netcore.json b/src/Microsoft.AspNetCore.Html.Abstractions/baseline.netcore.json index b0b320e216..29f855f97b 100644 --- a/src/Microsoft.AspNetCore.Html.Abstractions/baseline.netcore.json +++ b/src/Microsoft.AspNetCore.Html.Abstractions/baseline.netcore.json @@ -1,5 +1,5 @@ { - "AssemblyIdentity": "Microsoft.AspNetCore.Html.Abstractions, Version=2.0.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "AssemblyIdentity": "Microsoft.AspNetCore.Html.Abstractions, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", "Types": [ { "Name": "Microsoft.AspNetCore.Html.HtmlContentBuilder", @@ -9,6 +9,58 @@ "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", @@ -76,58 +128,6 @@ "Visibility": "Public", "GenericParameter": [] }, - { - "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": "Constructor", "Name": ".ctor", diff --git a/src/Microsoft.Extensions.WebEncoders/baseline.netcore.json b/src/Microsoft.Extensions.WebEncoders/baseline.netcore.json index cc93cc7458..6da0ae0754 100644 --- a/src/Microsoft.Extensions.WebEncoders/baseline.netcore.json +++ b/src/Microsoft.Extensions.WebEncoders/baseline.netcore.json @@ -1,5 +1,5 @@ { - "AssemblyIdentity": "Microsoft.Extensions.WebEncoders, Version=2.0.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "AssemblyIdentity": "Microsoft.Extensions.WebEncoders, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", "Types": [ { "Name": "Microsoft.Extensions.WebEncoders.WebEncoderOptions", From 78fc55675861ee33f102bd601ac951eff9bdbad3 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Thu, 14 Jun 2018 10:28:12 -0700 Subject: [PATCH 403/471] Set 2.1 baselines --- .../baseline.netcore.json | 315 +++++++++++++----- 1 file changed, 230 insertions(+), 85 deletions(-) diff --git a/src/Microsoft.AspNetCore.JsonPatch/baseline.netcore.json b/src/Microsoft.AspNetCore.JsonPatch/baseline.netcore.json index c84771a03c..3d90a8f017 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/baseline.netcore.json +++ b/src/Microsoft.AspNetCore.JsonPatch/baseline.netcore.json @@ -1,6 +1,73 @@ { - "AssemblyIdentity": "Microsoft.AspNetCore.JsonPatch, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "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", @@ -127,6 +194,23 @@ "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", @@ -484,6 +568,79 @@ } ] }, + { + "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", @@ -933,73 +1090,6 @@ ], "GenericParameters": [] }, - { - "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.Operations.Operation", "Visibility": "Public", @@ -1355,6 +1445,13 @@ "Parameters": [], "GenericParameter": [], "Literal": "5" + }, + { + "Kind": "Field", + "Name": "Invalid", + "Parameters": [], + "GenericParameter": [], + "Literal": "6" } ], "GenericParameters": [] @@ -1694,29 +1791,41 @@ "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.JsonPatch.Adapters.ObjectAdapter", + "Name": "Microsoft.AspNetCore.JsonPatch.Adapters.IObjectAdapterWithTest", "Visibility": "Public", - "Kind": "Class", + "Kind": "Interface", + "Abstract": true, "ImplementedInterfaces": [ "Microsoft.AspNetCore.JsonPatch.Adapters.IObjectAdapter" ], "Members": [ { "Kind": "Method", - "Name": "get_ContractResolver", - "Parameters": [], - "ReturnType": "Newtonsoft.Json.Serialization.IContractResolver", - "Visibility": "Public", + "Name": "Test", + "Parameters": [ + { + "Name": "operation", + "Type": "Microsoft.AspNetCore.JsonPatch.Operations.Operation" + }, + { + "Name": "objectToApplyTo", + "Type": "System.Object" + } + ], + "ReturnType": "System.Void", "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_LogErrorAction", - "Parameters": [], - "ReturnType": "System.Action", - "Visibility": "Public", - "GenericParameter": [] - }, + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.JsonPatch.Adapters.ObjectAdapter", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.JsonPatch.Adapters.IObjectAdapterWithTest" + ], + "Members": [ { "Kind": "Method", "Name": "Add", @@ -1737,6 +1846,26 @@ "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", @@ -1799,7 +1928,23 @@ }, { "Kind": "Method", - "Name": "Copy", + "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", @@ -1813,7 +1958,7 @@ "ReturnType": "System.Void", "Sealed": true, "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.JsonPatch.Adapters.IObjectAdapter", + "ImplementedInterface": "Microsoft.AspNetCore.JsonPatch.Adapters.IObjectAdapterWithTest", "Visibility": "Public", "GenericParameter": [] }, From b59f5dd8d4a90cc3de50b5abb8342442212cd2d3 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Thu, 14 Jun 2018 10:28:12 -0700 Subject: [PATCH 404/471] Set 2.1 baselines --- .../baseline.netcore.json | 315 +++++++++++++----- 1 file changed, 230 insertions(+), 85 deletions(-) diff --git a/src/Microsoft.AspNetCore.JsonPatch/baseline.netcore.json b/src/Microsoft.AspNetCore.JsonPatch/baseline.netcore.json index c84771a03c..3d90a8f017 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/baseline.netcore.json +++ b/src/Microsoft.AspNetCore.JsonPatch/baseline.netcore.json @@ -1,6 +1,73 @@ { - "AssemblyIdentity": "Microsoft.AspNetCore.JsonPatch, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "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", @@ -127,6 +194,23 @@ "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", @@ -484,6 +568,79 @@ } ] }, + { + "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", @@ -933,73 +1090,6 @@ ], "GenericParameters": [] }, - { - "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.Operations.Operation", "Visibility": "Public", @@ -1355,6 +1445,13 @@ "Parameters": [], "GenericParameter": [], "Literal": "5" + }, + { + "Kind": "Field", + "Name": "Invalid", + "Parameters": [], + "GenericParameter": [], + "Literal": "6" } ], "GenericParameters": [] @@ -1694,29 +1791,41 @@ "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.JsonPatch.Adapters.ObjectAdapter", + "Name": "Microsoft.AspNetCore.JsonPatch.Adapters.IObjectAdapterWithTest", "Visibility": "Public", - "Kind": "Class", + "Kind": "Interface", + "Abstract": true, "ImplementedInterfaces": [ "Microsoft.AspNetCore.JsonPatch.Adapters.IObjectAdapter" ], "Members": [ { "Kind": "Method", - "Name": "get_ContractResolver", - "Parameters": [], - "ReturnType": "Newtonsoft.Json.Serialization.IContractResolver", - "Visibility": "Public", + "Name": "Test", + "Parameters": [ + { + "Name": "operation", + "Type": "Microsoft.AspNetCore.JsonPatch.Operations.Operation" + }, + { + "Name": "objectToApplyTo", + "Type": "System.Object" + } + ], + "ReturnType": "System.Void", "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_LogErrorAction", - "Parameters": [], - "ReturnType": "System.Action", - "Visibility": "Public", - "GenericParameter": [] - }, + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.JsonPatch.Adapters.ObjectAdapter", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.JsonPatch.Adapters.IObjectAdapterWithTest" + ], + "Members": [ { "Kind": "Method", "Name": "Add", @@ -1737,6 +1846,26 @@ "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", @@ -1799,7 +1928,23 @@ }, { "Kind": "Method", - "Name": "Copy", + "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", @@ -1813,7 +1958,7 @@ "ReturnType": "System.Void", "Sealed": true, "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.JsonPatch.Adapters.IObjectAdapter", + "ImplementedInterface": "Microsoft.AspNetCore.JsonPatch.Adapters.IObjectAdapterWithTest", "Visibility": "Public", "GenericParameter": [] }, From fdf97c547ed8a38118fd5866ebd42b4aff609579 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Mon, 25 Jun 2018 11:15:22 -0700 Subject: [PATCH 405/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 14 +++++++------- korebuild-lock.txt | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index b793716276..e3fbf6767d 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,17 +3,17 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.2.0-preview1-17081 - 2.2.0-preview1-34411 - 2.2.0-preview1-34411 - 2.2.0-preview1-34411 - 2.2.0-preview1-34411 + 2.2.0-preview1-17090 + 2.2.0-preview1-34530 + 2.2.0-preview1-34530 + 2.2.0-preview1-34530 + 2.2.0-preview1-34530 2.0.0 2.1.0 - 2.2.0-preview1-26606-01 + 2.2.0-preview1-26618-02 15.6.1 2.0.3 - 4.6.0-preview1-26605-01 + 4.6.0-preview1-26617-01 2.3.1 2.4.0-beta.1.build3945 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index deb7e546f0..a8109db529 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-17081 -commithash:73f09c256e2a54270951562ecc0ef4a953926c36 +version:2.2.0-preview1-17090 +commithash:b19e903e946579cd9482089bce7d917e8bacd765 From a3ff5cfef7e02edf8b7ab05b437dfa4918669b3d Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Mon, 25 Jun 2018 11:20:42 -0700 Subject: [PATCH 406/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 10 +++++----- korebuild-lock.txt | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 15ef04fe4b..3474d55494 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,13 +3,13 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.2.0-preview1-17081 - 2.2.0-preview1-34411 - 4.6.0-preview1-26605-01 - 2.2.0-preview1-34411 + 2.2.0-preview1-17090 + 2.2.0-preview1-34530 + 4.6.0-preview1-26617-01 + 2.2.0-preview1-34530 2.0.0 2.1.0 - 2.2.0-preview1-26606-01 + 2.2.0-preview1-26618-02 15.6.1 4.7.49 2.0.3 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index deb7e546f0..a8109db529 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-17081 -commithash:73f09c256e2a54270951562ecc0ef4a953926c36 +version:2.2.0-preview1-17090 +commithash:b19e903e946579cd9482089bce7d917e8bacd765 From 47c5edd37aad2a12d14c9dea8cfb22ef48ddb005 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 27 Jun 2018 13:39:46 -0700 Subject: [PATCH 407/471] Bumping version from 2.1.1 to 2.1.2 --- version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.props b/version.props index 669c874829..478dfd16ed 100644 --- a/version.props +++ b/version.props @@ -1,6 +1,6 @@  - 2.1.1 + 2.1.2 rtm $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final From 5d39e86f1985d99d0c530e312d5b478ddc8682a4 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 27 Jun 2018 13:39:48 -0700 Subject: [PATCH 408/471] Bumping version from 2.1.1 to 2.1.2 --- version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.props b/version.props index 669c874829..478dfd16ed 100644 --- a/version.props +++ b/version.props @@ -1,6 +1,6 @@  - 2.1.1 + 2.1.2 rtm $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final From 2d659e53829c4fab0a03fed934b5fedc2ce39c79 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Thu, 28 Jun 2018 16:19:54 -0700 Subject: [PATCH 409/471] Update infrastructure for the 2.2 release --- .vsts-pipelines/builds/ci-internal.yml | 4 ++-- .vsts-pipelines/builds/ci-public.yml | 6 +++--- build/repo.props | 1 + korebuild.json | 4 ++-- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.vsts-pipelines/builds/ci-internal.yml b/.vsts-pipelines/builds/ci-internal.yml index d7ceb76378..dc7b8a3cb9 100644 --- a/.vsts-pipelines/builds/ci-internal.yml +++ b/.vsts-pipelines/builds/ci-internal.yml @@ -1,5 +1,5 @@ trigger: -- dev +- master - release/* resources: @@ -7,7 +7,7 @@ resources: - repository: buildtools type: git name: aspnet-BuildTools - ref: refs/heads/dev + ref: refs/heads/release/2.2 phases: - template: .vsts-pipelines/templates/project-ci.yml@buildtools diff --git a/.vsts-pipelines/builds/ci-public.yml b/.vsts-pipelines/builds/ci-public.yml index b7f25723f8..f5087d9c30 100644 --- a/.vsts-pipelines/builds/ci-public.yml +++ b/.vsts-pipelines/builds/ci-public.yml @@ -1,5 +1,5 @@ trigger: -- dev +- master - release/* # See https://github.com/aspnet/BuildTools @@ -9,7 +9,7 @@ resources: type: github endpoint: DotNet-Bot GitHub Connection name: aspnet/BuildTools - ref: refs/heads/dev - + ref: refs/heads/release/2.2 + phases: - template: .vsts-pipelines/templates/project-ci.yml@buildtools diff --git a/build/repo.props b/build/repo.props index 17a98ac7e7..f1fe24dd27 100644 --- a/build/repo.props +++ b/build/repo.props @@ -4,6 +4,7 @@ Internal.AspNetCore.Universe.Lineup + 2.2.0-* https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json diff --git a/korebuild.json b/korebuild.json index bd5d51a51b..d217d06e3e 100644 --- a/korebuild.json +++ b/korebuild.json @@ -1,4 +1,4 @@ { - "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/dev/tools/korebuild.schema.json", - "channel": "dev" + "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/release/2.2/tools/korebuild.schema.json", + "channel": "release/2.2" } From 2c1b6f9e8dec7f071a9d61f490d4edd639746688 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Thu, 28 Jun 2018 16:20:31 -0700 Subject: [PATCH 410/471] Update infrastructure for the 2.2 release --- .vsts-pipelines/builds/ci-internal.yml | 4 ++-- .vsts-pipelines/builds/ci-public.yml | 6 +++--- build/repo.props | 1 + korebuild.json | 4 ++-- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.vsts-pipelines/builds/ci-internal.yml b/.vsts-pipelines/builds/ci-internal.yml index d7ceb76378..dc7b8a3cb9 100644 --- a/.vsts-pipelines/builds/ci-internal.yml +++ b/.vsts-pipelines/builds/ci-internal.yml @@ -1,5 +1,5 @@ trigger: -- dev +- master - release/* resources: @@ -7,7 +7,7 @@ resources: - repository: buildtools type: git name: aspnet-BuildTools - ref: refs/heads/dev + ref: refs/heads/release/2.2 phases: - template: .vsts-pipelines/templates/project-ci.yml@buildtools diff --git a/.vsts-pipelines/builds/ci-public.yml b/.vsts-pipelines/builds/ci-public.yml index b7f25723f8..f5087d9c30 100644 --- a/.vsts-pipelines/builds/ci-public.yml +++ b/.vsts-pipelines/builds/ci-public.yml @@ -1,5 +1,5 @@ trigger: -- dev +- master - release/* # See https://github.com/aspnet/BuildTools @@ -9,7 +9,7 @@ resources: type: github endpoint: DotNet-Bot GitHub Connection name: aspnet/BuildTools - ref: refs/heads/dev - + ref: refs/heads/release/2.2 + phases: - template: .vsts-pipelines/templates/project-ci.yml@buildtools diff --git a/build/repo.props b/build/repo.props index 17a98ac7e7..f1fe24dd27 100644 --- a/build/repo.props +++ b/build/repo.props @@ -4,6 +4,7 @@ Internal.AspNetCore.Universe.Lineup + 2.2.0-* https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json diff --git a/korebuild.json b/korebuild.json index bd5d51a51b..d217d06e3e 100644 --- a/korebuild.json +++ b/korebuild.json @@ -1,4 +1,4 @@ { - "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/dev/tools/korebuild.schema.json", - "channel": "dev" + "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/release/2.2/tools/korebuild.schema.json", + "channel": "release/2.2" } From 8bb788ef9eef5ae4a6b48c04b3903f7c8319bbe9 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 8 Jul 2018 12:14:12 -0700 Subject: [PATCH 411/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 16 ++++++++-------- korebuild-lock.txt | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index e3fbf6767d..be2fe575b9 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,19 +3,19 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.2.0-preview1-17090 - 2.2.0-preview1-34530 - 2.2.0-preview1-34530 - 2.2.0-preview1-34530 - 2.2.0-preview1-34530 - 2.0.0 - 2.1.0 + 2.2.0-preview1-17099 + 2.2.0-preview1-34640 + 2.2.0-preview1-34640 + 2.2.0-preview1-34640 + 2.2.0-preview1-34640 + 2.0.7 + 2.1.1 2.2.0-preview1-26618-02 15.6.1 2.0.3 4.6.0-preview1-26617-01 2.3.1 - 2.4.0-beta.1.build3945 + 2.4.0-rc.1.build4038 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index a8109db529..27e2e80f9a 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-17090 -commithash:b19e903e946579cd9482089bce7d917e8bacd765 +version:2.2.0-preview1-17099 +commithash:263ed1db9866b6b419b1f5d5189a712aa218acb3 From b34f6284126e38e8b510b58e735a3d5587a8989c Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 8 Jul 2018 12:19:37 -0700 Subject: [PATCH 412/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 12 ++++++------ korebuild-lock.txt | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 3474d55494..df86701c7b 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,12 +3,12 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.2.0-preview1-17090 - 2.2.0-preview1-34530 + 2.2.0-preview1-17099 + 2.2.0-preview1-34640 4.6.0-preview1-26617-01 - 2.2.0-preview1-34530 - 2.0.0 - 2.1.0 + 2.2.0-preview1-34640 + 2.0.7 + 2.1.1 2.2.0-preview1-26618-02 15.6.1 4.7.49 @@ -16,7 +16,7 @@ 11.0.2 0.8.0 2.3.1 - 2.4.0-beta.1.build3945 + 2.4.0-rc.1.build4038 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index a8109db529..27e2e80f9a 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-17090 -commithash:b19e903e946579cd9482089bce7d917e8bacd765 +version:2.2.0-preview1-17099 +commithash:263ed1db9866b6b419b1f5d5189a712aa218acb3 From b24ae3eef557b13215950e9642b2a1d0da0ae895 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 11 Jul 2018 15:06:31 -0700 Subject: [PATCH 413/471] Reverting version from 2.1.2 back to 2.1.1 As a result of changing the way we apply servicing updates to aspnet core, this repo did not need the version bump because there are no planned product changes in this repo. --- version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.props b/version.props index 478dfd16ed..669c874829 100644 --- a/version.props +++ b/version.props @@ -1,6 +1,6 @@  - 2.1.2 + 2.1.1 rtm $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final From 3a16fe8d53d8fd8cf876854268071eba863f4f8d Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 11 Jul 2018 15:06:35 -0700 Subject: [PATCH 414/471] Reverting version from 2.1.2 back to 2.1.1 As a result of changing the way we apply servicing updates to aspnet core, this repo did not need the version bump because there are no planned product changes in this repo. --- version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.props b/version.props index 478dfd16ed..669c874829 100644 --- a/version.props +++ b/version.props @@ -1,6 +1,6 @@  - 2.1.2 + 2.1.1 rtm $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final From fd2613f1b2ba062a10015add7db585ca15293632 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 11 Jul 2018 18:48:36 -0700 Subject: [PATCH 415/471] Updating dependencies to 2.1.2 and adding a section for pinned variable versions --- build/dependencies.props | 13 ++++++++++--- korebuild-lock.txt | 4 ++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index dc47d2ca18..c5bba50310 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -2,19 +2,26 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - - 2.1.1-rtm-15793 + + + + 2.1.3-rtm-15802 2.1.0 2.1.1 2.1.1 2.1.1 2.0.0 - 2.1.1 + 2.1.2 15.6.1 2.0.3 4.5.0 2.3.1 2.4.0-beta.1.build3945 + + + + + diff --git a/korebuild-lock.txt b/korebuild-lock.txt index bc84e0cd53..251c227c83 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.1-rtm-15793 -commithash:988313f4b064d6c69fc6f7b845b6384a6af3447a +version:2.1.3-rtm-15802 +commithash:a7c08b45b440a7d2058a0aa1eaa3eb6ba811976a From 8177229ac88fd6f864a8819ac7e81b4cfc1c4df3 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 11 Jul 2018 18:49:06 -0700 Subject: [PATCH 416/471] Updating dependencies to 2.1.2 and adding a section for pinned variable versions --- build/dependencies.props | 13 ++++++++++--- korebuild-lock.txt | 4 ++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index c7a3e03395..d52f8aee1c 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -2,13 +2,15 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - - 2.1.1-rtm-15793 + + + + 2.1.3-rtm-15802 2.1.0 4.5.0 2.1.1 2.0.0 - 2.1.1 + 2.1.2 15.6.1 4.7.49 2.0.3 @@ -17,5 +19,10 @@ 2.3.1 2.4.0-beta.1.build3945 + + + + + diff --git a/korebuild-lock.txt b/korebuild-lock.txt index bc84e0cd53..251c227c83 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.1-rtm-15793 -commithash:988313f4b064d6c69fc6f7b845b6384a6af3447a +version:2.1.3-rtm-15802 +commithash:a7c08b45b440a7d2058a0aa1eaa3eb6ba811976a From 252ae0c434d93f5bfaf949c35edb9ef59730d0a3 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Thu, 12 Jul 2018 11:53:20 -0700 Subject: [PATCH 417/471] Pin version variables to the ASP.NET Core 2.1.2 baseline This reverts our previous policy of cascading versions on all servicing updates. This moves variables into the 'pinned' section, and points them to the latest stable release (versions that were used at the time of the 2.1.2 release). --- build/dependencies.props | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index c5bba50310..3c314a3476 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,12 +4,8 @@ - + 2.1.3-rtm-15802 - 2.1.0 - 2.1.1 - 2.1.1 - 2.1.1 2.0.0 2.1.2 15.6.1 @@ -23,5 +19,10 @@ - - + + 2.1.0 + 2.1.1 + 2.1.1 + 2.1.1 + + \ No newline at end of file From 218064c300a7cf5a76669e133340a98a0c5517a5 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Thu, 12 Jul 2018 11:54:35 -0700 Subject: [PATCH 418/471] Pin version variables to the ASP.NET Core 2.1.2 baseline This reverts our previous policy of cascading versions on all servicing updates. This moves variables into the 'pinned' section, and points them to the latest stable release (versions that were used at the time of the 2.1.2 release). --- build/dependencies.props | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index d52f8aee1c..55c598b536 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,11 +4,9 @@ - + 2.1.3-rtm-15802 - 2.1.0 4.5.0 - 2.1.1 2.0.0 2.1.2 15.6.1 @@ -24,5 +22,8 @@ - - + + 2.1.0 + 2.1.1 + + \ No newline at end of file From 2d44d6396e774122fb2be04d7317dbf011ba7213 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 15 Jul 2018 12:13:58 -0700 Subject: [PATCH 419/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index be2fe575b9..c5526396b7 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,16 +4,16 @@ 2.2.0-preview1-17099 - 2.2.0-preview1-34640 - 2.2.0-preview1-34640 - 2.2.0-preview1-34640 - 2.2.0-preview1-34640 - 2.0.7 - 2.1.1 + 2.2.0-preview1-34694 + 2.2.0-preview1-34694 + 2.2.0-preview1-34694 + 2.2.0-preview1-34694 + 2.0.9 + 2.1.2 2.2.0-preview1-26618-02 15.6.1 2.0.3 - 4.6.0-preview1-26617-01 + 4.5.0 2.3.1 2.4.0-rc.1.build4038 From bf2acb9c96787977ae26c34a050635e845066639 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 15 Jul 2018 12:19:00 -0700 Subject: [PATCH 420/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index df86701c7b..16fb368215 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,17 +4,17 @@ 2.2.0-preview1-17099 - 2.2.0-preview1-34640 - 4.6.0-preview1-26617-01 - 2.2.0-preview1-34640 - 2.0.7 - 2.1.1 + 2.2.0-preview1-34694 + 4.5.0 + 2.2.0-preview1-34694 + 2.0.9 + 2.1.2 2.2.0-preview1-26618-02 15.6.1 4.7.49 2.0.3 11.0.2 - 0.8.0 + 0.9.0 2.3.1 2.4.0-rc.1.build4038 From d503b0803436caa0637fc47e99342b3d57990738 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 22 Jul 2018 12:13:31 -0700 Subject: [PATCH 421/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index c5526396b7..ee95b37bfd 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,10 +4,10 @@ 2.2.0-preview1-17099 - 2.2.0-preview1-34694 - 2.2.0-preview1-34694 - 2.2.0-preview1-34694 - 2.2.0-preview1-34694 + 2.2.0-preview1-34755 + 2.2.0-preview1-34755 + 2.2.0-preview1-34755 + 2.2.0-preview1-34755 2.0.9 2.1.2 2.2.0-preview1-26618-02 From f47e0f61431fe7079e8f9fac79a63035b2f35bf1 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 22 Jul 2018 12:18:27 -0700 Subject: [PATCH 422/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 16fb368215..fe09987679 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,9 +4,9 @@ 2.2.0-preview1-17099 - 2.2.0-preview1-34694 + 2.2.0-preview1-34755 4.5.0 - 2.2.0-preview1-34694 + 2.2.0-preview1-34755 2.0.9 2.1.2 2.2.0-preview1-26618-02 From 884b1eb7adacb4680667cc045843dac3a12b3df9 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 29 Jul 2018 12:13:05 -0700 Subject: [PATCH 423/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 13 +++++++------ korebuild-lock.txt | 4 ++-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index ee95b37bfd..09d37136bd 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,11 +3,11 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.2.0-preview1-17099 - 2.2.0-preview1-34755 - 2.2.0-preview1-34755 - 2.2.0-preview1-34755 - 2.2.0-preview1-34755 + 2.2.0-preview1-17102 + 2.2.0-preview1-34823 + 2.2.0-preview1-34823 + 2.2.0-preview1-34823 + 2.2.0-preview1-34823 2.0.9 2.1.2 2.2.0-preview1-26618-02 @@ -15,7 +15,8 @@ 2.0.3 4.5.0 2.3.1 - 2.4.0-rc.1.build4038 + 2.4.0 + diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 27e2e80f9a..6b8da29e6b 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-17099 -commithash:263ed1db9866b6b419b1f5d5189a712aa218acb3 +version:2.2.0-preview1-17102 +commithash:e7e2b5a97ca92cfc6acc4def534cb0901a6d1eb9 From 31249603df7d0bedfb993e330484085a2dcfa317 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 29 Jul 2018 12:18:03 -0700 Subject: [PATCH 424/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 11 ++++++----- korebuild-lock.txt | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index fe09987679..5b45506395 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,10 +3,10 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.2.0-preview1-17099 - 2.2.0-preview1-34755 + 2.2.0-preview1-17102 + 2.2.0-preview1-34823 4.5.0 - 2.2.0-preview1-34755 + 2.2.0-preview1-34823 2.0.9 2.1.2 2.2.0-preview1-26618-02 @@ -14,9 +14,10 @@ 4.7.49 2.0.3 11.0.2 - 0.9.0 + 0.10.0 2.3.1 - 2.4.0-rc.1.build4038 + 2.4.0 + diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 27e2e80f9a..6b8da29e6b 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-17099 -commithash:263ed1db9866b6b419b1f5d5189a712aa218acb3 +version:2.2.0-preview1-17102 +commithash:e7e2b5a97ca92cfc6acc4def534cb0901a6d1eb9 From 2f2027fe5fe90190eca3df7a43adf9924abee4f8 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 5 Aug 2018 19:14:38 +0000 Subject: [PATCH 425/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 10 +++++----- korebuild-lock.txt | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 09d37136bd..4aa84ba6c2 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,11 +3,11 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.2.0-preview1-17102 - 2.2.0-preview1-34823 - 2.2.0-preview1-34823 - 2.2.0-preview1-34823 - 2.2.0-preview1-34823 + 2.2.0-preview1-20180731.1 + 2.2.0-preview1-34882 + 2.2.0-preview1-34882 + 2.2.0-preview1-34882 + 2.2.0-preview1-34882 2.0.9 2.1.2 2.2.0-preview1-26618-02 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 6b8da29e6b..c7af2292c7 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-17102 -commithash:e7e2b5a97ca92cfc6acc4def534cb0901a6d1eb9 +version:2.2.0-preview1-20180731.1 +commithash:29fde58465439f4bb9df40830635ed758e063daf From 91188201eea719cae1e58c07c486193ce5737932 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 5 Aug 2018 19:20:10 +0000 Subject: [PATCH 426/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 6 +++--- korebuild-lock.txt | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 5b45506395..f6d57f9ae8 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,10 +3,10 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.2.0-preview1-17102 - 2.2.0-preview1-34823 + 2.2.0-preview1-20180731.1 + 2.2.0-preview1-34882 4.5.0 - 2.2.0-preview1-34823 + 2.2.0-preview1-34882 2.0.9 2.1.2 2.2.0-preview1-26618-02 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 6b8da29e6b..c7af2292c7 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-17102 -commithash:e7e2b5a97ca92cfc6acc4def534cb0901a6d1eb9 +version:2.2.0-preview1-20180731.1 +commithash:29fde58465439f4bb9df40830635ed758e063daf From 04d476a729642e6d4304029ecef88bab98e4abd8 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Mon, 6 Aug 2018 20:36:56 +0000 Subject: [PATCH 427/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 4aa84ba6c2..b6626fdf05 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,10 +4,10 @@ 2.2.0-preview1-20180731.1 - 2.2.0-preview1-34882 - 2.2.0-preview1-34882 - 2.2.0-preview1-34882 - 2.2.0-preview1-34882 + 2.2.0-preview1-34896 + 2.2.0-preview1-34896 + 2.2.0-preview1-34896 + 2.2.0-preview1-34896 2.0.9 2.1.2 2.2.0-preview1-26618-02 From 8100421d2fe65d160044b3204151f6f5e5b323d2 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Mon, 6 Aug 2018 20:42:45 +0000 Subject: [PATCH 428/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index f6d57f9ae8..85c8596f07 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,9 +4,9 @@ 2.2.0-preview1-20180731.1 - 2.2.0-preview1-34882 + 2.2.0-preview1-34896 4.5.0 - 2.2.0-preview1-34882 + 2.2.0-preview1-34896 2.0.9 2.1.2 2.2.0-preview1-26618-02 From b4b9d5b0af1ac654157e30b81e09b9a889fc717b Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 12 Aug 2018 19:13:50 +0000 Subject: [PATCH 429/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 10 +++++----- korebuild-lock.txt | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index b6626fdf05..1f8d7ce1dc 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,11 +3,11 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.2.0-preview1-20180731.1 - 2.2.0-preview1-34896 - 2.2.0-preview1-34896 - 2.2.0-preview1-34896 - 2.2.0-preview1-34896 + 2.2.0-preview1-20180807.2 + 2.2.0-preview1-34967 + 2.2.0-preview1-34967 + 2.2.0-preview1-34967 + 2.2.0-preview1-34967 2.0.9 2.1.2 2.2.0-preview1-26618-02 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index c7af2292c7..3fbcc80189 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-20180731.1 -commithash:29fde58465439f4bb9df40830635ed758e063daf +version:2.2.0-preview1-20180807.2 +commithash:11495dbd236104434e08cb1152fcb58cf2a20923 From 06d1a535b3153efc0ca24adc4f68ea42eec70755 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 12 Aug 2018 19:19:45 +0000 Subject: [PATCH 430/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 6 +++--- korebuild-lock.txt | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 85c8596f07..d4e5106db9 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,10 +3,10 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.2.0-preview1-20180731.1 - 2.2.0-preview1-34896 + 2.2.0-preview1-20180807.2 + 2.2.0-preview1-34967 4.5.0 - 2.2.0-preview1-34896 + 2.2.0-preview1-34967 2.0.9 2.1.2 2.2.0-preview1-26618-02 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index c7af2292c7..3fbcc80189 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-20180731.1 -commithash:29fde58465439f4bb9df40830635ed758e063daf +version:2.2.0-preview1-20180807.2 +commithash:11495dbd236104434e08cb1152fcb58cf2a20923 From 386c024198d5b7b3dbb9c632df49479770d882b0 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Tue, 21 Aug 2018 13:33:50 -0700 Subject: [PATCH 431/471] Update package branding for 2.2.0-preview2 --- build/dependencies.props | 2 +- version.props | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 1f8d7ce1dc..e40e4c54a1 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -17,6 +17,6 @@ 2.3.1 2.4.0 - + diff --git a/version.props b/version.props index 44985cedb3..15637ba785 100644 --- a/version.props +++ b/version.props @@ -1,7 +1,7 @@ 2.2.0 - preview1 + preview2 $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final t000 From bd559b7966bd2a647e53c46697dbc39c87f29694 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Tue, 21 Aug 2018 13:33:50 -0700 Subject: [PATCH 432/471] Update package branding for 2.2.0-preview2 --- build/dependencies.props | 2 +- version.props | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index d4e5106db9..68adbeafb8 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -18,6 +18,6 @@ 2.3.1 2.4.0 - + diff --git a/version.props b/version.props index 44985cedb3..15637ba785 100644 --- a/version.props +++ b/version.props @@ -1,7 +1,7 @@ 2.2.0 - preview1 + preview2 $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final t000 From 8d5b123c611a6df427624e5c7499f14061646577 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 2 Sep 2018 12:13:02 -0700 Subject: [PATCH 433/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 10 +++++----- korebuild-lock.txt | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index e40e4c54a1..da718d7433 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,11 +3,11 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.2.0-preview1-20180807.2 - 2.2.0-preview1-34967 - 2.2.0-preview1-34967 - 2.2.0-preview1-34967 - 2.2.0-preview1-34967 + 2.2.0-preview1-20180821.1 + 2.2.0-preview2-35143 + 2.2.0-preview2-35143 + 2.2.0-preview2-35143 + 2.2.0-preview2-35143 2.0.9 2.1.2 2.2.0-preview1-26618-02 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 3fbcc80189..ad704918df 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-20180807.2 -commithash:11495dbd236104434e08cb1152fcb58cf2a20923 +version:2.2.0-preview1-20180821.1 +commithash:c8d0cc52cd1abb697be24e288ffd54f8fae8bf17 From cb569de67201c566b680f71a7a0bb7f0cac34600 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 2 Sep 2018 12:18:41 -0700 Subject: [PATCH 434/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 6 +++--- korebuild-lock.txt | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 68adbeafb8..c19ec5d60d 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,10 +3,10 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.2.0-preview1-20180807.2 - 2.2.0-preview1-34967 + 2.2.0-preview1-20180821.1 + 2.2.0-preview2-35143 4.5.0 - 2.2.0-preview1-34967 + 2.2.0-preview2-35143 2.0.9 2.1.2 2.2.0-preview1-26618-02 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 3fbcc80189..ad704918df 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-20180807.2 -commithash:11495dbd236104434e08cb1152fcb58cf2a20923 +version:2.2.0-preview1-20180821.1 +commithash:c8d0cc52cd1abb697be24e288ffd54f8fae8bf17 From eade194b39088b91c84c8c1aebd46d2ce7c85507 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Wed, 5 Sep 2018 16:34:28 -0700 Subject: [PATCH 435/471] Update branding to 2.2.0-preview3 --- version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.props b/version.props index 15637ba785..704cac087b 100644 --- a/version.props +++ b/version.props @@ -1,7 +1,7 @@ 2.2.0 - preview2 + preview3 $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final t000 From bb31ceee59fa27b52908bef651636247e1fce481 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Wed, 5 Sep 2018 16:35:05 -0700 Subject: [PATCH 436/471] Update branding to 2.2.0-preview3 --- version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.props b/version.props index 15637ba785..704cac087b 100644 --- a/version.props +++ b/version.props @@ -1,7 +1,7 @@ 2.2.0 - preview2 + preview3 $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final t000 From 05a34009e8184ae3a48bada25d9681f310746301 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 9 Sep 2018 12:13:56 -0700 Subject: [PATCH 437/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 14 +++++++------- korebuild-lock.txt | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index da718d7433..0c12fec871 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,14 +3,14 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.2.0-preview1-20180821.1 - 2.2.0-preview2-35143 - 2.2.0-preview2-35143 - 2.2.0-preview2-35143 - 2.2.0-preview2-35143 + 2.2.0-preview1-20180907.8 + 2.2.0-preview3-35202 + 2.2.0-preview3-35202 + 2.2.0-preview3-35202 + 2.2.0-preview3-35202 2.0.9 - 2.1.2 - 2.2.0-preview1-26618-02 + 2.1.3 + 2.2.0-preview2-26905-02 15.6.1 2.0.3 4.5.0 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index ad704918df..312f82f9a5 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-20180821.1 -commithash:c8d0cc52cd1abb697be24e288ffd54f8fae8bf17 +version:2.2.0-preview1-20180907.8 +commithash:078918eb5c1f176ee1da351c584fb4a4d7491aa0 From 3d0502f947a3ff8283d451ac140fa9d9f783b931 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 9 Sep 2018 12:21:00 -0700 Subject: [PATCH 438/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 10 +++++----- korebuild-lock.txt | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index c19ec5d60d..d36bf72206 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,13 +3,13 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.2.0-preview1-20180821.1 - 2.2.0-preview2-35143 + 2.2.0-preview1-20180907.8 + 2.2.0-preview3-35202 4.5.0 - 2.2.0-preview2-35143 + 2.2.0-preview3-35202 2.0.9 - 2.1.2 - 2.2.0-preview1-26618-02 + 2.1.3 + 2.2.0-preview2-26905-02 15.6.1 4.7.49 2.0.3 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index ad704918df..312f82f9a5 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-20180821.1 -commithash:c8d0cc52cd1abb697be24e288ffd54f8fae8bf17 +version:2.2.0-preview1-20180907.8 +commithash:078918eb5c1f176ee1da351c584fb4a4d7491aa0 From 89a2849126c5e06116dca8cb629af3c6ab44bf56 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 16 Sep 2018 12:12:38 -0700 Subject: [PATCH 439/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 10 +++++----- korebuild-lock.txt | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 0c12fec871..e49c4108ac 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,11 +3,11 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.2.0-preview1-20180907.8 - 2.2.0-preview3-35202 - 2.2.0-preview3-35202 - 2.2.0-preview3-35202 - 2.2.0-preview3-35202 + 2.2.0-preview1-20180911.1 + 2.2.0-preview3-35252 + 2.2.0-preview3-35252 + 2.2.0-preview3-35252 + 2.2.0-preview3-35252 2.0.9 2.1.3 2.2.0-preview2-26905-02 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 312f82f9a5..7124f37441 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-20180907.8 -commithash:078918eb5c1f176ee1da351c584fb4a4d7491aa0 +version:2.2.0-preview1-20180911.1 +commithash:ddfecdfc6e8e4859db5a0daea578070b862aac65 From 41614badf9bfac6265ea395b090a58ddcbcde067 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 16 Sep 2018 12:19:33 -0700 Subject: [PATCH 440/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 6 +++--- korebuild-lock.txt | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index d36bf72206..6500ecf53f 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,10 +3,10 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.2.0-preview1-20180907.8 - 2.2.0-preview3-35202 + 2.2.0-preview1-20180911.1 + 2.2.0-preview3-35252 4.5.0 - 2.2.0-preview3-35202 + 2.2.0-preview3-35252 2.0.9 2.1.3 2.2.0-preview2-26905-02 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 312f82f9a5..7124f37441 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-20180907.8 -commithash:078918eb5c1f176ee1da351c584fb4a4d7491aa0 +version:2.2.0-preview1-20180911.1 +commithash:ddfecdfc6e8e4859db5a0daea578070b862aac65 From e18cef609ece13d17a7e8880d8dc466e02c73fac Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 23 Sep 2018 19:14:47 +0000 Subject: [PATCH 441/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 10 +++++----- korebuild-lock.txt | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index e49c4108ac..3d199851a2 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,11 +3,11 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.2.0-preview1-20180911.1 - 2.2.0-preview3-35252 - 2.2.0-preview3-35252 - 2.2.0-preview3-35252 - 2.2.0-preview3-35252 + 2.2.0-preview1-20180918.1 + 2.2.0-preview3-35301 + 2.2.0-preview3-35301 + 2.2.0-preview3-35301 + 2.2.0-preview3-35301 2.0.9 2.1.3 2.2.0-preview2-26905-02 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 7124f37441..649bf2ba0b 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-20180911.1 -commithash:ddfecdfc6e8e4859db5a0daea578070b862aac65 +version:2.2.0-preview1-20180918.1 +commithash:ad5e3fc53442741a0dd49bce437d2ac72f4b5800 From 2fcf2215d8b7b450954475d899b682dd9aa3e9fe Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 23 Sep 2018 19:22:14 +0000 Subject: [PATCH 442/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 6 +++--- korebuild-lock.txt | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 6500ecf53f..b6ca4ad584 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,10 +3,10 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.2.0-preview1-20180911.1 - 2.2.0-preview3-35252 + 2.2.0-preview1-20180918.1 + 2.2.0-preview3-35301 4.5.0 - 2.2.0-preview3-35252 + 2.2.0-preview3-35301 2.0.9 2.1.3 2.2.0-preview2-26905-02 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 7124f37441..649bf2ba0b 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-20180911.1 -commithash:ddfecdfc6e8e4859db5a0daea578070b862aac65 +version:2.2.0-preview1-20180918.1 +commithash:ad5e3fc53442741a0dd49bce437d2ac72f4b5800 From 2c486604d7ff11ab83020aa29e5a3bc4b0fbb4d4 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Fri, 28 Sep 2018 17:10:34 -0700 Subject: [PATCH 443/471] automated: bulk infrastructure updates. Update bootstrapper scripts and remove unnecessary signing properties --- Directory.Build.props | 3 --- run.ps1 | 6 +++--- run.sh | 10 +++++----- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index d5b8bf3650..08fa9d2e3b 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -13,9 +13,6 @@ $(MSBuildThisFileDirectory) $(MSBuildThisFileDirectory)build\Key.snk true - Microsoft - MicrosoftNuGet - true true diff --git a/run.ps1 b/run.ps1 index 3b27382468..34604c7175 100644 --- a/run.ps1 +++ b/run.ps1 @@ -52,8 +52,8 @@ in the file are overridden by command line parameters. Example config file: ```json { - "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/dev/tools/korebuild.schema.json", - "channel": "dev", + "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/master/tools/korebuild.schema.json", + "channel": "master", "toolsSource": "https://aspnetcore.blob.core.windows.net/buildtools" } ``` @@ -192,7 +192,7 @@ if (!$DotNetHome) { else { Join-Path $PSScriptRoot '.dotnet'} } -if (!$Channel) { $Channel = 'dev' } +if (!$Channel) { $Channel = 'master' } if (!$ToolsSource) { $ToolsSource = 'https://aspnetcore.blob.core.windows.net/buildtools' } # Execute diff --git a/run.sh b/run.sh index 02aac15874..4c1fed5646 100755 --- a/run.sh +++ b/run.sh @@ -220,7 +220,7 @@ if [ -f "$config_file" ]; then config_channel="$(jq -r 'select(.channel!=null) | .channel' "$config_file")" config_tools_source="$(jq -r 'select(.toolsSource!=null) | .toolsSource' "$config_file")" else - _error "$config_file contains invalid JSON." + __error "$config_file contains invalid JSON." exit 1 fi elif __machine_has python ; then @@ -228,7 +228,7 @@ if [ -f "$config_file" ]; then config_channel="$(python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['channel'] if 'channel' in obj else '')")" config_tools_source="$(python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['toolsSource'] if 'toolsSource' in obj else '')")" else - _error "$config_file contains invalid JSON." + __error "$config_file contains invalid JSON." exit 1 fi elif __machine_has python3 ; then @@ -236,11 +236,11 @@ if [ -f "$config_file" ]; then config_channel="$(python3 -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['channel'] if 'channel' in obj else '')")" config_tools_source="$(python3 -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['toolsSource'] if 'toolsSource' in obj else '')")" else - _error "$config_file contains invalid JSON." + __error "$config_file contains invalid JSON." exit 1 fi else - _error 'Missing required command: jq or python. Could not parse the JSON file.' + __error 'Missing required command: jq or python. Could not parse the JSON file.' exit 1 fi @@ -248,7 +248,7 @@ if [ -f "$config_file" ]; then [ ! -z "${config_tools_source:-}" ] && tools_source="$config_tools_source" fi -[ -z "$channel" ] && channel='dev' +[ -z "$channel" ] && channel='master' [ -z "$tools_source" ] && tools_source='https://aspnetcore.blob.core.windows.net/buildtools' get_korebuild From 05b58f826367946013d890735e1326c20d391aa8 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Fri, 28 Sep 2018 17:10:36 -0700 Subject: [PATCH 444/471] automated: bulk infrastructure updates. Update bootstrapper scripts and remove unnecessary signing properties --- Directory.Build.props | 3 --- run.ps1 | 6 +++--- run.sh | 10 +++++----- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 0c6cb2e37f..4c54defe04 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -14,9 +14,6 @@ $(MSBuildThisFileDirectory) $(MSBuildThisFileDirectory)build\Key.snk true - Microsoft - MicrosoftNuGet - true true diff --git a/run.ps1 b/run.ps1 index 3b27382468..34604c7175 100644 --- a/run.ps1 +++ b/run.ps1 @@ -52,8 +52,8 @@ in the file are overridden by command line parameters. Example config file: ```json { - "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/dev/tools/korebuild.schema.json", - "channel": "dev", + "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/master/tools/korebuild.schema.json", + "channel": "master", "toolsSource": "https://aspnetcore.blob.core.windows.net/buildtools" } ``` @@ -192,7 +192,7 @@ if (!$DotNetHome) { else { Join-Path $PSScriptRoot '.dotnet'} } -if (!$Channel) { $Channel = 'dev' } +if (!$Channel) { $Channel = 'master' } if (!$ToolsSource) { $ToolsSource = 'https://aspnetcore.blob.core.windows.net/buildtools' } # Execute diff --git a/run.sh b/run.sh index 02aac15874..4c1fed5646 100755 --- a/run.sh +++ b/run.sh @@ -220,7 +220,7 @@ if [ -f "$config_file" ]; then config_channel="$(jq -r 'select(.channel!=null) | .channel' "$config_file")" config_tools_source="$(jq -r 'select(.toolsSource!=null) | .toolsSource' "$config_file")" else - _error "$config_file contains invalid JSON." + __error "$config_file contains invalid JSON." exit 1 fi elif __machine_has python ; then @@ -228,7 +228,7 @@ if [ -f "$config_file" ]; then config_channel="$(python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['channel'] if 'channel' in obj else '')")" config_tools_source="$(python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['toolsSource'] if 'toolsSource' in obj else '')")" else - _error "$config_file contains invalid JSON." + __error "$config_file contains invalid JSON." exit 1 fi elif __machine_has python3 ; then @@ -236,11 +236,11 @@ if [ -f "$config_file" ]; then config_channel="$(python3 -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['channel'] if 'channel' in obj else '')")" config_tools_source="$(python3 -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['toolsSource'] if 'toolsSource' in obj else '')")" else - _error "$config_file contains invalid JSON." + __error "$config_file contains invalid JSON." exit 1 fi else - _error 'Missing required command: jq or python. Could not parse the JSON file.' + __error 'Missing required command: jq or python. Could not parse the JSON file.' exit 1 fi @@ -248,7 +248,7 @@ if [ -f "$config_file" ]; then [ ! -z "${config_tools_source:-}" ] && tools_source="$config_tools_source" fi -[ -z "$channel" ] && channel='dev' +[ -z "$channel" ] && channel='master' [ -z "$tools_source" ] && tools_source='https://aspnetcore.blob.core.windows.net/buildtools' get_korebuild From 49e982cc658c65db432db2768ce6a4ba3706bcf3 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 30 Sep 2018 12:14:58 -0700 Subject: [PATCH 445/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 12 ++++++------ korebuild-lock.txt | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 3d199851a2..7465761b22 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,14 +3,14 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.2.0-preview1-20180918.1 - 2.2.0-preview3-35301 - 2.2.0-preview3-35301 - 2.2.0-preview3-35301 - 2.2.0-preview3-35301 + 2.2.0-preview1-20180928.5 + 2.2.0-preview3-35359 + 2.2.0-preview3-35359 + 2.2.0-preview3-35359 + 2.2.0-preview3-35359 2.0.9 2.1.3 - 2.2.0-preview2-26905-02 + 2.2.0-preview3-26927-02 15.6.1 2.0.3 4.5.0 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 649bf2ba0b..26697a21fa 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-20180918.1 -commithash:ad5e3fc53442741a0dd49bce437d2ac72f4b5800 +version:2.2.0-preview1-20180928.5 +commithash:43faa29f679f47b88689d645b39e6be5e0055d70 From ed49a91b675390bb1f1d7b0c3d94243c9b83ea22 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 30 Sep 2018 12:22:27 -0700 Subject: [PATCH 446/471] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 8 ++++---- korebuild-lock.txt | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index b6ca4ad584..9937fc7b36 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,13 +3,13 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.2.0-preview1-20180918.1 - 2.2.0-preview3-35301 + 2.2.0-preview1-20180928.5 + 2.2.0-preview3-35359 4.5.0 - 2.2.0-preview3-35301 + 2.2.0-preview3-35359 2.0.9 2.1.3 - 2.2.0-preview2-26905-02 + 2.2.0-preview3-26927-02 15.6.1 4.7.49 2.0.3 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 649bf2ba0b..26697a21fa 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-20180918.1 -commithash:ad5e3fc53442741a0dd49bce437d2ac72f4b5800 +version:2.2.0-preview1-20180928.5 +commithash:43faa29f679f47b88689d645b39e6be5e0055d70 From 6c5ca90d81f9013a8652da4c1752bd0b4d18e908 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Tue, 16 Oct 2018 12:48:14 -0700 Subject: [PATCH 447/471] Update package branding for 2.2 RTM --- version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.props b/version.props index 704cac087b..4889a26987 100644 --- a/version.props +++ b/version.props @@ -1,7 +1,7 @@ 2.2.0 - preview3 + rtm $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final t000 From aeb5c578e7d59cf9b100352f55f05f55c7cfebd1 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Tue, 16 Oct 2018 12:48:16 -0700 Subject: [PATCH 448/471] Update package branding for 2.2 RTM --- version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.props b/version.props index 704cac087b..4889a26987 100644 --- a/version.props +++ b/version.props @@ -1,7 +1,7 @@ 2.2.0 - preview3 + rtm $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final t000 From 3b485909ebec98d9437058dbcf45dac3ccd1f157 Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Wed, 31 Oct 2018 13:59:20 -0700 Subject: [PATCH 449/471] Fix aspnet/AspNetCore#3634 --- .../Internal/ObjectVisitor.cs | 8 +++++- .../SimpleObjectIntegrationTest.cs | 27 +++++++++++++++++++ .../Internal/ObjectVisitorTest.cs | 16 +++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/ObjectVisitor.cs b/src/Microsoft.AspNetCore.JsonPatch/Internal/ObjectVisitor.cs index a988afa300..6cb4d7450c 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Internal/ObjectVisitor.cs +++ b/src/Microsoft.AspNetCore.JsonPatch/Internal/ObjectVisitor.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Collections; using Microsoft.AspNetCore.JsonPatch.Adapters; using Newtonsoft.Json.Serialization; @@ -56,6 +55,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal 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); diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/SimpleObjectIntegrationTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/SimpleObjectIntegrationTest.cs index 669c6d7af4..4672d9c97b 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/SimpleObjectIntegrationTest.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/SimpleObjectIntegrationTest.cs @@ -2,6 +2,8 @@ // 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 @@ -124,5 +126,30 @@ namespace Microsoft.AspNetCore.JsonPatch.IntegrationTests 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/test/Microsoft.AspNetCore.JsonPatch.Test/Internal/ObjectVisitorTest.cs b/test/Microsoft.AspNetCore.JsonPatch.Test/Internal/ObjectVisitorTest.cs index cb299cf0dc..44f6fc81ae 100644 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Internal/ObjectVisitorTest.cs +++ b/test/Microsoft.AspNetCore.JsonPatch.Test/Internal/ObjectVisitorTest.cs @@ -205,6 +205,22 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal 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() { From 03c287406e2259b1fd647796634ee07e2ff5794d Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Thu, 8 Nov 2018 08:15:16 -0800 Subject: [PATCH 450/471] Updating submodule(s) EntityFrameworkCore => 68a631e43b262c1ad3039cd36728b49bed128cdd [auto-updated: submodules] --- modules/EntityFrameworkCore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/EntityFrameworkCore b/modules/EntityFrameworkCore index d5745f8b89..68a631e43b 160000 --- a/modules/EntityFrameworkCore +++ b/modules/EntityFrameworkCore @@ -1 +1 @@ -Subproject commit d5745f8b895de2c9f7636ecded35d387e2ff4d7b +Subproject commit 68a631e43b262c1ad3039cd36728b49bed128cdd From 79923e6a9f8ac4ceec0d69a3b3931b11eee77638 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Thu, 8 Nov 2018 17:21:41 +0000 Subject: [PATCH 451/471] Updating BuildTools from 2.1.3-rtm-15839 to 2.1.3-rtm-15840 [auto-updated: buildtools] --- korebuild-lock.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/korebuild-lock.txt b/korebuild-lock.txt index bf511bf4d6..f2b171d1e9 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.3-rtm-15839 -commithash:ee0ad5bd4ede948c6954704b621acc0c83445e5d +version:2.1.3-rtm-15840 +commithash:a47f557c0d6fecd333599e7691fa64239642ea33 From 0b77cfa4632a555201c4c529f3c3d76146609720 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Thu, 8 Nov 2018 17:35:13 +0000 Subject: [PATCH 452/471] Updating BuildTools from 2.1.3-rtm-15840 to 2.1.3-rtm-15841 [auto-updated: buildtools] --- korebuild-lock.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/korebuild-lock.txt b/korebuild-lock.txt index f2b171d1e9..774bb6d85d 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.3-rtm-15840 -commithash:a47f557c0d6fecd333599e7691fa64239642ea33 +version:2.1.3-rtm-15841 +commithash:b3eda40cef3d95be448f972e328801706267dfba From f260f0947498e47efe7b588adb0d4ad1690bc6e1 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Thu, 8 Nov 2018 15:08:35 -0800 Subject: [PATCH 453/471] Updating BuildTools from 2.1.3-rtm-15841 to 2.1.3-rtm-15842 [auto-updated: buildtools] --- korebuild-lock.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 774bb6d85d..08f95645f0 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.3-rtm-15841 -commithash:b3eda40cef3d95be448f972e328801706267dfba +version:2.1.3-rtm-15842 +commithash:b631cb7a2b982cbbfc4d2e02be66c6612f9e3afd From 0c6e4bebab2b2755b7dd6eda732d2f2443a9cea6 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Thu, 8 Nov 2018 17:07:18 -0800 Subject: [PATCH 454/471] Prepare to build the 2.1.7 patch (#3970) * Prepare 2.1.7 patch * Add documentation for how we prepare servicing updates --- build/submodules.props | 6 +- docs/preparing-patch-updates.md | 37 + modules/MetaPackages | 2 +- modules/Scaffolding | 2 +- modules/Templating | 2 +- src/IISIntegration/version.props | 2 +- .../ArchiveBaseline.2.1.6.txt | 675 ++++++++++++++++++ .../ArchiveBaseline.2.1.6.txt | 667 +++++++++++++++++ version.props | 2 +- 9 files changed, 1387 insertions(+), 8 deletions(-) create mode 100644 docs/preparing-patch-updates.md create mode 100644 src/PackageArchive/Archive.CiServer.Patch.Compat/ArchiveBaseline.2.1.6.txt create mode 100644 src/PackageArchive/Archive.CiServer.Patch/ArchiveBaseline.2.1.6.txt diff --git a/build/submodules.props b/build/submodules.props index 086b29a461..4064fe8af9 100644 --- a/build/submodules.props +++ b/build/submodules.props @@ -36,8 +36,7 @@ - - + @@ -55,6 +54,7 @@ + @@ -69,7 +69,7 @@ - + diff --git a/docs/preparing-patch-updates.md b/docs/preparing-patch-updates.md new file mode 100644 index 0000000000..87821935de --- /dev/null +++ b/docs/preparing-patch-updates.md @@ -0,0 +1,37 @@ +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 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/modules/MetaPackages b/modules/MetaPackages index 96be626c87..975011071b 160000 --- a/modules/MetaPackages +++ b/modules/MetaPackages @@ -1 +1 @@ -Subproject commit 96be626c87c3ca325b18aa6653602f5e7087497f +Subproject commit 975011071b02f6937261c604fcde48d7e43030ce diff --git a/modules/Scaffolding b/modules/Scaffolding index 840531e6a0..2f81b98c13 160000 --- a/modules/Scaffolding +++ b/modules/Scaffolding @@ -1 +1 @@ -Subproject commit 840531e6a03fab451c1efb83098ea4d724a5d03d +Subproject commit 2f81b98c133c24ec699f370bf07b557dd484c646 diff --git a/modules/Templating b/modules/Templating index 6bafc157e7..3f26b56fef 160000 --- a/modules/Templating +++ b/modules/Templating @@ -1 +1 @@ -Subproject commit 6bafc157e78371f4ad4c80e4671a9c9a00d03694 +Subproject commit 3f26b56fefaa559d1ca9ba9181a249c0af26b9c3 diff --git a/src/IISIntegration/version.props b/src/IISIntegration/version.props index e897351a24..eb76a7c8ee 100644 --- a/src/IISIntegration/version.props +++ b/src/IISIntegration/version.props @@ -2,7 +2,7 @@ 2 1 - 2 + 7 $(DotNetMajorVersion).$(DotNetMinorVersion).$(DotNetPatchVersion) 12 $(DotNetMinorVersion) 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/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/version.props b/version.props index c0217598a3..3e4178aafa 100644 --- a/version.props +++ b/version.props @@ -2,7 +2,7 @@ 2 1 - 6 + 7 servicing Servicing t000 From 34999a804e6ad9f99bb96ef7969dcf8180bd78bb Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Fri, 9 Nov 2018 08:48:42 -0800 Subject: [PATCH 455/471] Remove submodules for repos that merged to aspnet/Extensions (#3671) Builds of the packages in aspnet/Extensions repo go through ProdCon instead of building as a submodule of this repo. --- .gitmodules | 36 -- build/GenerateCode.targets | 17 - build/artifacts.props | 59 --- build/buildorder.props | 15 +- build/dependencies.props | 68 ++- build/external-dependencies.props | 76 ++++ build/repo.targets | 1 - build/submodules.props | 9 - build/tasks/AnalyzeBuildGraph.cs | 24 +- build/tasks/CodeGen/DirectedGraphXml.cs | 42 -- build/tasks/CodeGen/GenerateSubmoduleGraph.cs | 226 ---------- build/tasks/CodeGen/RepositoryProject.cs | 46 -- build/tasks/RepoTasks.tasks | 1 - modules/Caching | 1 - modules/Common | 1 - modules/Configuration | 1 - modules/DependencyInjection | 1 - modules/EventNotification | 1 - modules/FileSystem | 1 - modules/Logging | 1 - modules/Options | 1 - modules/SubmoduleGraph.dgml | 421 ------------------ modules/Testing | 1 - scripts/UpdateDependencies.ps1 | 8 +- 24 files changed, 165 insertions(+), 893 deletions(-) delete mode 100644 build/GenerateCode.targets delete mode 100644 build/tasks/CodeGen/DirectedGraphXml.cs delete mode 100644 build/tasks/CodeGen/GenerateSubmoduleGraph.cs delete mode 100644 build/tasks/CodeGen/RepositoryProject.cs delete mode 160000 modules/Caching delete mode 160000 modules/Common delete mode 160000 modules/Configuration delete mode 160000 modules/DependencyInjection delete mode 160000 modules/EventNotification delete mode 160000 modules/FileSystem delete mode 160000 modules/Logging delete mode 160000 modules/Options delete mode 100644 modules/SubmoduleGraph.dgml delete mode 160000 modules/Testing diff --git a/.gitmodules b/.gitmodules index e8c4effa7e..76458daf89 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,26 +22,10 @@ path = modules/BrowserLink url = https://github.com/aspnet/BrowserLink.git branch = release/2.1 -[submodule "modules/Caching"] - path = modules/Caching - url = https://github.com/aspnet/Caching.git - branch = release/2.1 -[submodule "modules/Common"] - path = modules/Common - url = https://github.com/aspnet/Common.git - branch = release/2.1 -[submodule "modules/Configuration"] - path = modules/Configuration - url = https://github.com/aspnet/Configuration.git - branch = release/2.1 [submodule "modules/CORS"] path = modules/CORS url = https://github.com/aspnet/CORS.git branch = release/2.1 -[submodule "modules/DependencyInjection"] - path = modules/DependencyInjection - url = https://github.com/aspnet/DependencyInjection.git - branch = release/2.1 [submodule "modules/Diagnostics"] path = modules/Diagnostics url = https://github.com/aspnet/Diagnostics.git @@ -54,14 +38,6 @@ path = modules/EntityFrameworkCore url = https://github.com/aspnet/EntityFrameworkCore.git branch = release/2.1 -[submodule "modules/EventNotification"] - path = modules/EventNotification - url = https://github.com/aspnet/EventNotification.git - branch = release/2.1 -[submodule "modules/FileSystem"] - path = modules/FileSystem - url = https://github.com/aspnet/FileSystem.git - branch = release/2.1 [submodule "modules/Hosting"] path = modules/Hosting url = https://github.com/aspnet/Hosting.git @@ -102,10 +78,6 @@ path = modules/Localization url = https://github.com/aspnet/Localization.git branch = release/2.1 -[submodule "modules/Logging"] - path = modules/Logging - url = https://github.com/aspnet/Logging.git - branch = release/2.1 [submodule "modules/MetaPackages"] path = modules/MetaPackages url = https://github.com/aspnet/MetaPackages.git @@ -122,10 +94,6 @@ path = modules/MvcPrecompilation url = https://github.com/aspnet/MvcPrecompilation.git branch = release/2.1 -[submodule "modules/Options"] - path = modules/Options - url = https://github.com/aspnet/Options.git - branch = release/2.1 [submodule "modules/Razor"] path = modules/Razor url = https://github.com/aspnet/Razor.git @@ -166,7 +134,3 @@ path = modules/Templating url = https://github.com/aspnet/Templating.git branch = release/2.1 -[submodule "modules/Testing"] - path = modules/Testing - url = https://github.com/aspnet/Testing.git - branch = release/2.1 diff --git a/build/GenerateCode.targets b/build/GenerateCode.targets deleted file mode 100644 index 069e358ae6..0000000000 --- a/build/GenerateCode.targets +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - diff --git a/build/artifacts.props b/build/artifacts.props index 39b35505e6..a4ec6e8774 100644 --- a/build/artifacts.props +++ b/build/artifacts.props @@ -51,9 +51,7 @@ - - @@ -156,7 +154,6 @@ - @@ -183,40 +180,10 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -225,32 +192,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/build/buildorder.props b/build/buildorder.props index fdc4e89b0f..1cb0f6cec8 100644 --- a/build/buildorder.props +++ b/build/buildorder.props @@ -7,18 +7,9 @@ - - - - - - - - - - - - + + + diff --git a/build/dependencies.props b/build/dependencies.props index 7de10ef40d..d906e02d29 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -2,9 +2,9 @@ - 2.1.6-servicing-27017-02 - 2.1.6-servicing-27017-02 - + 2.1.6 + 2.1.6 + @@ -19,6 +19,68 @@ + + 2.1.6 + 2.1.6 + 2.1.0 + 2.1.1 + 2.1.2 + 2.1.2 + 2.1.2 + 2.1.2 + 2.1.6 + 2.1.6 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.6 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.6 + 2.1.1 + 0.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.6 + 2.1.6 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.6 + 2.1.6 + 2.1.6 + 2.1.6 + 2.1.6 + 2.1.6 + 2.1.6 + 2.1.6 + 2.1.6 + 2.1.6 + + 0.9.9 0.10.13 4.2.1 diff --git a/build/external-dependencies.props b/build/external-dependencies.props index 8f8858d98c..d9edeee7cf 100644 --- a/build/external-dependencies.props +++ b/build/external-dependencies.props @@ -10,9 +10,85 @@ false + + + + + + + false + + false + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build/repo.targets b/build/repo.targets index 076c50232e..cde696935c 100644 --- a/build/repo.targets +++ b/build/repo.targets @@ -5,7 +5,6 @@ - diff --git a/build/submodules.props b/build/submodules.props index 4064fe8af9..8b30d5efcb 100644 --- a/build/submodules.props +++ b/build/submodules.props @@ -53,17 +53,11 @@ - - - - - - @@ -74,10 +68,8 @@ - - @@ -85,7 +77,6 @@ - diff --git a/build/tasks/AnalyzeBuildGraph.cs b/build/tasks/AnalyzeBuildGraph.cs index a7193d7735..c70d1d8a56 100644 --- a/build/tasks/AnalyzeBuildGraph.cs +++ b/build/tasks/AnalyzeBuildGraph.cs @@ -111,16 +111,26 @@ namespace RepoTasks var dependencyMap = new Dictionary>(StringComparer.OrdinalIgnoreCase); foreach (var dep in Dependencies) { - if (!dependencyMap.TryGetValue(dep.ItemSpec, out var versions)) + if (dep.GetMetadata("IsExtensionsPackage") == "true") { - dependencyMap[dep.ItemSpec] = versions = new List(); + buildPackageMap.Add(dep.ItemSpec, new ArtifactInfo.Package + { + PackageInfo = new PackageInfo(dep.ItemSpec, new NuGetVersion(dep.GetMetadata("Version")), null, null), + }); } - - versions.Add(new ExternalDependency + else { - PackageId = dep.ItemSpec, - Version = dep.GetMetadata("Version"), - }); + if (!dependencyMap.TryGetValue(dep.ItemSpec, out var versions)) + { + dependencyMap[dep.ItemSpec] = versions = new List(); + } + + versions.Add(new ExternalDependency + { + PackageId = dep.ItemSpec, + Version = dep.GetMetadata("Version"), + }); + } } var inconsistentVersions = new List(); diff --git a/build/tasks/CodeGen/DirectedGraphXml.cs b/build/tasks/CodeGen/DirectedGraphXml.cs deleted file mode 100644 index e90d66ca6b..0000000000 --- a/build/tasks/CodeGen/DirectedGraphXml.cs +++ /dev/null @@ -1,42 +0,0 @@ - -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Xml.Linq; - -namespace RepoTasks.CodeGen -{ - class DirectedGraphXml - { - private readonly XNamespace _ns = "http://schemas.microsoft.com/vs/2009/dgml"; - private readonly XDocument _doc; - private readonly XElement _nodes; - private readonly XElement _links; - - public DirectedGraphXml() - { - _doc = new XDocument(new XElement(_ns + "DirectedGraph")); - _nodes = new XElement(_ns + "Nodes"); - _links = new XElement(_ns + "Links"); - _doc.Root.Add(_nodes); - _doc.Root.Add(_links); - } - - public void AddNode(string id) - { - _nodes.Add(new XElement(_ns + "Node", new XAttribute("Id", id), new XAttribute("Label", id))); - } - - public void AddLink(string source, string target) - { - _links.Add(new XElement(_ns + "Link", - new XAttribute("Source", source), - new XAttribute("Target", target))); - } - - public void Save(string path) - { - _doc.Save(path); - } - } -} diff --git a/build/tasks/CodeGen/GenerateSubmoduleGraph.cs b/build/tasks/CodeGen/GenerateSubmoduleGraph.cs deleted file mode 100644 index 7940b5cba2..0000000000 --- a/build/tasks/CodeGen/GenerateSubmoduleGraph.cs +++ /dev/null @@ -1,226 +0,0 @@ - -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.IO; -using System.Text; -using System.Threading; -using Microsoft.Build.Framework; -using Microsoft.Build.Utilities; -using NuGet.Frameworks; -using NuGet.Versioning; -using RepoTools.BuildGraph; -using RepoTasks.ProjectModel; -using RepoTasks.Utilities; -using RepoTasks.CodeGen; -using NuGet.Packaging.Core; - -namespace RepoTasks -{ - public class GenerateSubmoduleGraph : Task, ICancelableTask - { - private readonly CancellationTokenSource _cts = new CancellationTokenSource(); - - /// - /// Repositories that we are building new versions of. - /// - [Required] - public ITaskItem[] Solutions { get; set; } - - [Required] - public ITaskItem[] Artifacts { get; set; } - - [Required] - public ITaskItem[] Repositories { get; set; } - - [Required] - public string RepositoryRoot { get; set; } - - [Required] - public string Properties { get; set; } - - public void Cancel() - { - _cts.Cancel(); - } - - public override bool Execute() - { - var packageArtifacts = Artifacts.Select(ArtifactInfo.Parse) - .OfType() - .Where(p => !p.IsSymbolsArtifact) - .ToDictionary(p => p.PackageInfo.Id, p => p, StringComparer.OrdinalIgnoreCase); - - var factory = new SolutionInfoFactory(Log, BuildEngine5); - var props = MSBuildListSplitter.GetNamedProperties(Properties); - - Log.LogMessage(MessageImportance.High, $"Beginning cross-repo analysis on {Solutions.Length} solutions. Hang tight..."); - - if (!props.TryGetValue("Configuration", out var defaultConfig)) - { - defaultConfig = "Debug"; - } - - var solutions = factory.Create(Solutions, props, defaultConfig, _cts.Token).OrderBy(f => f.Directory).ToList(); - Log.LogMessage($"Found {solutions.Count} and {solutions.Sum(p => p.Projects.Count)} projects"); - - if (_cts.IsCancellationRequested) - { - return false; - } - - return GenerateGraph(packageArtifacts, solutions); - } - - private bool GenerateGraph(IDictionary packageArtifacts, IReadOnlyList solutions) - { - var repoGraph = new AdjacencyMatrix(solutions.Count); - var packageToProjectMap = new Dictionary(); - - for (var i = 0; i < solutions.Count; i++) - { - var sln = repoGraph[i] = solutions[i]; - - foreach (var proj in sln.Projects) - { - if (!proj.IsPackable || proj.FullPath.Contains("samples")) - { - continue; - } - - var id = new PackageIdentity(proj.PackageId, new NuGetVersion(proj.PackageVersion)); - - if (packageToProjectMap.TryGetValue(id, out var otherProj)) - { - Log.LogError($"Both {proj.FullPath} and {otherProj.FullPath} produce {id}"); - continue; - } - - packageToProjectMap.Add(id, proj); - } - - var sharedSrc = Path.Combine(sln.Directory, "shared"); - if (Directory.Exists(sharedSrc)) - { - foreach (var dir in Directory.GetDirectories(sharedSrc, "*.Sources")) - { - var id = Path.GetFileName(dir); - var artifactInfo = packageArtifacts[id]; - var sharedSrcProj = new ProjectInfo(dir, - Array.Empty(), - Array.Empty(), - true, - artifactInfo.PackageInfo.Id, - artifactInfo.PackageInfo.Version.ToNormalizedString()); - sharedSrcProj.SolutionInfo = sln; - var identity = new PackageIdentity(artifactInfo.PackageInfo.Id, artifactInfo.PackageInfo.Version); - packageToProjectMap.Add(identity, sharedSrcProj); - } - } - } - - if (Log.HasLoggedErrors) - { - return false; - } - - for (var i = 0; i < solutions.Count; i++) - { - var sln = repoGraph[i]; - - var deps = from proj in sln.Projects - from tfm in proj.Frameworks - from dep in tfm.Dependencies.Values - select dep; - - foreach (var dep in deps) - { - if (packageToProjectMap.TryGetValue(new PackageIdentity(dep.Id, new NuGetVersion(dep.Version)), out var target)) - { - var j = repoGraph.FindIndex(target.SolutionInfo); - repoGraph.SetLink(i, j); - } - } - - var toolDeps = from proj in sln.Projects - from tool in proj.Tools - select tool; - - foreach (var toolDep in toolDeps) - { - if (packageToProjectMap.TryGetValue(new PackageIdentity(toolDep.Id, new NuGetVersion(toolDep.Version)), out var target)) - { - var j = repoGraph.FindIndex(target.SolutionInfo); - repoGraph.SetLink(i, j); - } - } - } - - CreateDgml(repoGraph); - return !Log.HasLoggedErrors; - } - - - private void CreateDgml(AdjacencyMatrix repoGraph) - { - var dgml = new DirectedGraphXml(); - - for (var i = 0; i < repoGraph.Count; i++) - { - var node = repoGraph[i]; - var nodeName = Path.GetFileName(node.Directory); - dgml.AddNode(nodeName); - - for (var j = 0; j < repoGraph.Count; j++) - { - if (j == i) continue; - if (repoGraph.HasLink(i, j)) - { - var target = repoGraph[j]; - var targetName = Path.GetFileName(target.Directory); - dgml.AddLink(nodeName, targetName); - } - } - } - - dgml.Save(Path.Combine(RepositoryRoot, "modules", "SubmoduleGraph.dgml")); - } - - private class AdjacencyMatrix - { - private readonly bool[,] _matrix; - private readonly SolutionInfo[] _items; - - public AdjacencyMatrix(int size) - { - _matrix = new bool[size, size]; - _items = new SolutionInfo[size]; - Count = size; - } - - public SolutionInfo this[int idx] - { - get => _items[idx]; - set => _items[idx] = value; - } - - public int FindIndex(SolutionInfo item) - { - return Array.FindIndex(_items, t => t.Equals(item)); - } - - public int Count { get; } - - public bool HasLink(int source, int target) => _matrix[source, target]; - - public void SetLink(int source, int target) - { - _matrix[source, target] = true; - } - } - } -} diff --git a/build/tasks/CodeGen/RepositoryProject.cs b/build/tasks/CodeGen/RepositoryProject.cs deleted file mode 100644 index 1cb3b76391..0000000000 --- a/build/tasks/CodeGen/RepositoryProject.cs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.IO; -using System.Text; -using Microsoft.Build.Construction; -using Microsoft.Build.Evaluation; - -namespace RepoTasks.CodeGen -{ - class RepositoryProject - { - private readonly ProjectRootElement _doc; - - public RepositoryProject(string repositoryRoot) - { - _doc = ProjectRootElement.Create(NewProjectFileOptions.None); - var import = _doc.CreateImportElement(@"$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props"); - var propGroup = _doc.AddPropertyGroup(); - if (repositoryRoot[repositoryRoot.Length - 1] != '\\') - { - repositoryRoot += '\\'; - } - propGroup.AddProperty("RepositoryRoot", repositoryRoot); - _doc.AddItemGroup(); - _doc.PrependChild(import); - _doc.AddImport(@"$(MSBuildToolsPath)\Microsoft.Common.targets"); - } - - public void AddProjectReference(string path) - { - _doc.AddItem("ProjectReference", path); - } - - public void AddProperty(string name, string value) - { - _doc.AddProperty(name, value); - } - - public void Save(string filePath) - { - _doc.Save(filePath, Encoding.UTF8); - } - } -} diff --git a/build/tasks/RepoTasks.tasks b/build/tasks/RepoTasks.tasks index 1339fcba27..2c2f8d48af 100644 --- a/build/tasks/RepoTasks.tasks +++ b/build/tasks/RepoTasks.tasks @@ -10,7 +10,6 @@ - diff --git a/modules/Caching b/modules/Caching deleted file mode 160000 index ced279b071..0000000000 --- a/modules/Caching +++ /dev/null @@ -1 +0,0 @@ -Subproject commit ced279b071920f055a309cd81acc333780ef2bf4 diff --git a/modules/Common b/modules/Common deleted file mode 160000 index 975fcf3026..0000000000 --- a/modules/Common +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 975fcf302632a83059086cd8faabb92379f09d02 diff --git a/modules/Configuration b/modules/Configuration deleted file mode 160000 index ef29dc86b9..0000000000 --- a/modules/Configuration +++ /dev/null @@ -1 +0,0 @@ -Subproject commit ef29dc86b970893147fd2a27d527f5a907af9fdd diff --git a/modules/DependencyInjection b/modules/DependencyInjection deleted file mode 160000 index 7a283947c2..0000000000 --- a/modules/DependencyInjection +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 7a283947c231b6585c8ac95e653950b660f3da96 diff --git a/modules/EventNotification b/modules/EventNotification deleted file mode 160000 index 69d9ba1300..0000000000 --- a/modules/EventNotification +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 69d9ba130050107409fc5c3d9d834ca55fc7a95d diff --git a/modules/FileSystem b/modules/FileSystem deleted file mode 160000 index baebb8b0c6..0000000000 --- a/modules/FileSystem +++ /dev/null @@ -1 +0,0 @@ -Subproject commit baebb8b0c672ab37bac72d7196da1b919d362cc5 diff --git a/modules/Logging b/modules/Logging deleted file mode 160000 index 8270c54522..0000000000 --- a/modules/Logging +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 8270c545224e8734d7297e54edef5c584ee82f01 diff --git a/modules/Options b/modules/Options deleted file mode 160000 index 2ea21ace21..0000000000 --- a/modules/Options +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 2ea21ace21105df2839766a5f13e8e2636b7fc41 diff --git a/modules/SubmoduleGraph.dgml b/modules/SubmoduleGraph.dgml deleted file mode 100644 index cdcd0a92cd..0000000000 --- a/modules/SubmoduleGraph.dgml +++ /dev/null @@ -1,421 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/modules/Testing b/modules/Testing deleted file mode 160000 index 8639233365..0000000000 --- a/modules/Testing +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 8639233365b85997c7e0b97b50f23aaddd36f671 diff --git a/scripts/UpdateDependencies.ps1 b/scripts/UpdateDependencies.ps1 index f8bfdac4fb..4ecb207047 100755 --- a/scripts/UpdateDependencies.ps1 +++ b/scripts/UpdateDependencies.ps1 @@ -54,10 +54,8 @@ foreach ($package in $remoteDeps.SelectNodes('//Package')) { } } - -$currentBranch = Invoke-Block { & git rev-parse --abbrev-ref HEAD } - if (-not $NoCommit) { + $currentBranch = Invoke-Block { & git rev-parse --abbrev-ref HEAD } $destinationBranch = "dotnetbot/UpdateDeps" Invoke-Block { & git checkout -tb $destinationBranch "origin/$GithubUpstreamBranch" } } @@ -74,5 +72,7 @@ try { } } finally { - Invoke-Block { & git checkout $currentBranch } + if (-not $NoCommit) { + Invoke-Block { & git checkout $currentBranch } + } } From a3baf40c7466a0d83dcb57f9f7a8934bdd4b4769 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Fri, 9 Nov 2018 09:12:52 -0800 Subject: [PATCH 456/471] Set dependency version on Microsoft.Extensions.DiagnosticAdapter to 2.1.0 and prune unused logging analyzers dependency There was never a 2.1.1 --- build/dependencies.props | 3 +-- build/external-dependencies.props | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index d906e02d29..dda2ffa595 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -46,7 +46,7 @@ 2.1.1 2.1.1 2.1.1 - 2.1.1 + 2.1.0 2.1.1 2.1.1 2.1.1 @@ -54,7 +54,6 @@ 2.1.1 2.1.6 2.1.1 - 0.1.1 2.1.1 2.1.1 2.1.1 diff --git a/build/external-dependencies.props b/build/external-dependencies.props index d9edeee7cf..ce501765b3 100644 --- a/build/external-dependencies.props +++ b/build/external-dependencies.props @@ -59,7 +59,6 @@ - From 8356baf7a612bd21cc92f8fc7098e292274de102 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Fri, 9 Nov 2018 11:10:33 -0800 Subject: [PATCH 457/471] Port ANCM installer changes to 2.1 (#3874) --- Directory.Build.props | 2 + Directory.Build.targets | 1 + THIRD-PARTY-NOTICES | 49 + eng/targets/Cpp.Common.props | 11 + eng/targets/Cpp.Common.targets | 6 + .../ANCMIISExpressV1/AncmIISExpressV1.wixproj | 72 + .../ANCMIISExpressV1/ancm_iis_express.wxs | 674 +++ .../ANCMPackageResolver.csproj | 25 + .../ANCMV1/AncmV1.wixproj | 74 + .../ANCMV1/aspnetcoremodule.wxs | 276 ++ .../CustomAction/Directory.Build.props | 15 + .../CustomAction/aspnetcoreCA.cpp | 184 + .../CustomAction/aspnetcoreCA.def | 23 + .../CustomAction/aspnetcoreCA.rc | 10 + .../CustomAction/aspnetcoreCA.vcxproj | 98 + .../CustomAction/avoid_restart.cpp | 244 + .../Directory.Build.props | 43 + .../IIS-Setup/IIS-Common/Common.sln | 41 + .../IIS-Setup/IIS-Common/Include/acache.h | 116 + .../IIS-Setup/IIS-Common/Include/ahutil.h | 264 + .../IIS-Setup/IIS-Common/Include/base64.hxx | 42 + .../IIS-Setup/IIS-Common/Include/buffer.h | 271 ++ .../IIS-Setup/IIS-Common/Include/datetime.h | 14 + .../IIS-Setup/IIS-Common/Include/dbgutil.h | 102 + .../IIS-Setup/IIS-Common/Include/debugutil.h | 124 + .../IIS-Setup/IIS-Common/Include/hashfn.h | 325 ++ .../IIS-Setup/IIS-Common/Include/hashtable.h | 666 +++ .../IIS-Setup/IIS-Common/Include/http_xp.h | 2797 +++++++++++ .../IIS-Common/Include/httpserv_xp.h | 3404 +++++++++++++ .../IIS-Common/Include/hybrid_array.h | 243 + .../IIS-Setup/IIS-Common/Include/listentry.h | 163 + .../IIS-Setup/IIS-Common/Include/macros.h | 63 + .../IIS-Setup/IIS-Common/Include/multisz.hxx | 225 + .../IIS-Setup/IIS-Common/Include/multisza.hxx | 225 + .../IIS-Setup/IIS-Common/Include/normalize.h | 40 + .../IIS-Setup/IIS-Common/Include/ntassert.h | 32 + .../IIS-Setup/IIS-Common/Include/percpu.h | 305 ++ .../IIS-Setup/IIS-Common/Include/prime.h | 85 + .../IIS-Setup/IIS-Common/Include/reftrace.h | 88 + .../IIS-Setup/IIS-Common/Include/rwlock.h | 193 + .../IIS-Setup/IIS-Common/Include/statichash.h | 730 +++ .../IIS-Setup/IIS-Common/Include/stdtypes.h | 24 + .../IIS-Setup/IIS-Common/Include/stringa.h | 515 ++ .../IIS-Setup/IIS-Common/Include/stringu.h | 433 ++ .../IIS-Setup/IIS-Common/Include/sttimer.h | 243 + .../IIS-Setup/IIS-Common/Include/tracelog.h | 105 + .../IIS-Setup/IIS-Common/Include/treehash.h | 850 ++++ .../IIS-Setup/IIS-Common/LICENSE | 21 + .../Managed/MySQL/MySqlConnector.cs | 28 + .../Managed/NativeMethods/AdvApi32.cs | 386 ++ .../Managed/NativeMethods/Common.cs | 111 + .../Managed/NativeMethods/Fusion.cs | 179 + .../Managed/NativeMethods/Kernel32.cs | 99 + .../IIS-Common/Managed/NativeMethods/Mlang.cs | 768 +++ .../Managed/NativeMethods/User32.cs | 88 + .../Managed/NativeMethods/UxTheme.cs | 46 + .../Managed/PseudoLoc/PseudoLoc.targets | 8 + .../Managed/PseudoLoc/PseudoLocalizer.cs | 456 ++ .../v7Sp1/Microsoft.Web.administration.dll | Bin 0 -> 126976 bytes .../v7Sp1/Microsoft.Web.management.dll | Bin 0 -> 999424 bytes .../Managed/Util/AuthenticationModule.cs | 111 + .../Managed/Util/ExceptionHelper.cs | 122 + .../Managed/Util/GACManagedAccess.cs | 192 + .../IIS-Common/Managed/Util/WebUtility.cs | 65 + .../IIS-Setup/IIS-Common/README.md | 18 + .../IIS-Common/UnitTests/common_tests.rc | 7 + .../IIS-Common/UnitTests/dbgutil_tests.cpp | 72 + .../IIS-Common/UnitTests/hash_tests.cpp | 52 + .../UnitTests/hybrid_array_tests.cpp | 95 + .../IIS-Setup/IIS-Common/UnitTests/my_hash.h | 63 + .../IIS-Common/UnitTests/precomp.hxx | 7 + .../IIS-Common/UnitTests/string_tests.cpp | 680 +++ .../IIS-Common/lib/CommonLib.vcxproj | 79 + .../IIS-Setup/IIS-Common/lib/acache.cxx | 443 ++ .../IIS-Setup/IIS-Common/lib/ahutil.cpp | 1734 +++++++ .../IIS-Setup/IIS-Common/lib/base64.cxx | 482 ++ .../IIS-Setup/IIS-Common/lib/datetime.cxx | 247 + .../IIS-Setup/IIS-Common/lib/multisz.cxx | 480 ++ .../IIS-Setup/IIS-Common/lib/multisza.cxx | 414 ++ .../IIS-Setup/IIS-Common/lib/normalize.cxx | 890 ++++ .../IIS-Setup/IIS-Common/lib/packages.config | 4 + .../IIS-Setup/IIS-Common/lib/precomp.h | 18 + .../IIS-Setup/IIS-Common/lib/stringa.cpp | 1767 +++++++ .../IIS-Setup/IIS-Common/lib/stringu.cpp | 1289 +++++ .../IIS-Setup/IIS-Common/lib/ulparse.cxx | 1416 ++++++ .../IIS-Setup/IIS-Common/lib/util.cxx | 74 + .../IIS-Setup/IIS-Common/open-inc/stbuff.h | 1013 ++++ .../IIS-Setup/IIS-Common/open-inc/stlist.h | 87 + .../IIS-Setup/IIS-Common/open-inc/stlock.h | 149 + .../IIS-Setup/IIS-Common/open-inc/sttable.h | 599 +++ .../IIS-Setup/IIS-Common/open-inc/sttimer.h | 232 + .../IIS-Common/reftrace/include/dbgutil2.h | 49 + .../IIS-Common/reftrace/include/irtldbg.h | 154 + .../IIS-Common/reftrace/include/irtlmisc.h | 131 + .../IIS-Common/reftrace/include/memorylog.hxx | 67 + .../IIS-Common/reftrace/include/precomp.hxx | 9 + .../IIS-Common/reftrace/include/pudebug.h | 748 +++ .../IIS-Common/reftrace/reftrace.vcxproj | 78 + .../reftrace/reftrace.vcxproj.filters | 54 + .../IIS-Common/reftrace/src/irtldbg.cpp | 150 + .../IIS-Common/reftrace/src/isplat.cxx | 63 + .../IIS-Common/reftrace/src/memorylog.cxx | 123 + .../IIS-Common/reftrace/src/pudebug.cxx | 1164 +++++ .../IIS-Common/reftrace/src/reftrace.c | 232 + .../IIS-Common/reftrace/src/tracelog.c | 239 + .../IIS-Common/reftrace/src/win32obj.cxx | 348 ++ .../IIS-Setup/IIS-Common/version/bldver.h | 64 + .../IIS-Setup/IIS-Common/version/bldver.rc | 73 + .../IIS-Setup/IIS-Setup.sln | 41 + .../AspNetCoreModule-Setup/IIS-Setup/LICENSE | 21 + .../IIS-Setup/README.md | 18 + .../IIS-Setup/appsearch/appsearch.wxi | 98 + .../IIS-Setup/iisca/lib/ConfigShared.cpp | 59 + .../IIS-Setup/iisca/lib/ConfigShared.h | 8 + .../IIS-Setup/iisca/lib/CustomAction.def | 15 + .../IIS-Setup/iisca/lib/cgi_restrictions.cpp | 271 ++ .../IIS-Setup/iisca/lib/cgi_restrictions.h | 30 + .../IIS-Setup/iisca/lib/config_custom.cpp | 72 + .../IIS-Setup/iisca/lib/config_custom.h | 16 + .../IIS-Setup/iisca/lib/consoleprops.cpp | 594 +++ .../IIS-Setup/iisca/lib/consoleprops.h | 16 + .../IIS-Setup/iisca/lib/defaults.cpp | 716 +++ .../IIS-Setup/iisca/lib/defaults.h | 52 + .../IIS-Setup/iisca/lib/elevatedsc.cpp | 346 ++ .../IIS-Setup/iisca/lib/elevatedsc.h | 16 + .../IIS-Setup/iisca/lib/handlers.cpp | 472 ++ .../IIS-Setup/iisca/lib/handlers.h | 54 + .../IIS-Setup/iisca/lib/hotfix.cpp | 766 +++ .../IIS-Setup/iisca/lib/httpapi.cpp | 518 ++ .../IIS-Setup/iisca/lib/httpapi.h | 55 + .../IIS-Setup/iisca/lib/iisca.cpp | 4302 +++++++++++++++++ .../IIS-Setup/iisca/lib/iisca.h | 255 + .../IIS-Setup/iisca/lib/iisca.vcxproj | 131 + .../IIS-Setup/iisca/lib/iiscaexp.cpp | 791 +++ .../IIS-Setup/iisca/lib/iiscaexp.h | 39 + .../IIS-Setup/iisca/lib/modules.cpp | 655 +++ .../IIS-Setup/iisca/lib/mof.cpp | 82 + .../IIS-Setup/iisca/lib/msiutil.cpp | 581 +++ .../IIS-Setup/iisca/lib/msiutil.h | 192 + .../IIS-Setup/iisca/lib/packages.config | 4 + .../IIS-Setup/iisca/lib/precomp.h | 51 + .../IIS-Setup/iisca/lib/schema.cpp | 741 +++ .../IIS-Setup/iisca/lib/secutils.cpp | 1125 +++++ .../IIS-Setup/iisca/lib/secutils.h | 98 + .../IIS-Setup/iisca/lib/setup_log.cpp | 423 ++ .../IIS-Setup/iisca/lib/setup_log.h | 53 + .../IIS-Setup/iisca/lib/tracing.cpp | 343 ++ .../IIS-Setup/iisca/lib/tracing.h | 36 + .../IIS-Setup/iisca/lib/uimodule.cpp | 637 +++ .../IIS-Setup/iisca/lib/wuerror.h | 2456 ++++++++++ .../IIS-Setup/iisca/wix/iisca.wxs | 209 + .../IIS-Setup/iisca/wix/setupstrings.wxl | 255 + .../IIS-Setup/iisca/wix3/ElevatedShortcut.wxi | 25 + .../iisca/wix3/FixPatchingBehavior.wxi | 36 + .../IIS-Setup/iisca/wix3/HttpListener.wxi | 44 + .../iisca/wix3/ShortcutConsoleProperties.wxi | 41 + .../IIS-Setup/iisca/wix3/WindowsHotfix.wxi | 41 + .../IIS-Setup/iisca/wix3/iisca.wxs | 99 + .../IIS-Setup/include.wxi | 32 + .../IIS-Setup/loc/CHS/misc/setupstrings.wxl | 351 ++ .../IIS-Setup/loc/CHT/misc/setupstrings.wxl | 351 ++ .../IIS-Setup/loc/CSY/misc/setupstrings.wxl | 351 ++ .../IIS-Setup/loc/DEU/misc/setupstrings.wxl | 351 ++ .../IIS-Setup/loc/ESN/misc/setupstrings.wxl | 351 ++ .../IIS-Setup/loc/FRA/misc/setupstrings.wxl | 352 ++ .../IIS-Setup/loc/ITA/misc/setupstrings.wxl | 351 ++ .../IIS-Setup/loc/JPN/misc/setupstrings.wxl | 351 ++ .../IIS-Setup/loc/KOR/misc/setupstrings.wxl | 351 ++ .../IIS-Setup/loc/PLK/misc/setupstrings.wxl | 351 ++ .../IIS-Setup/loc/PTB/misc/setupstrings.wxl | 351 ++ .../IIS-Setup/loc/RUS/misc/setupstrings.wxl | 351 ++ .../IIS-Setup/loc/TRK/misc/setupstrings.wxl | 351 ++ .../IIS-Setup/wcautil/dutil.h | 181 + .../IIS-Setup/wcautil/memutil.h | 42 + .../IIS-Setup/wcautil/precomp.h | 15 + .../IIS-Setup/wcautil/qtexec.cpp | 276 ++ .../IIS-Setup/wcautil/strutil.h | 165 + .../IIS-Setup/wcautil/wcalog.cpp | 150 + .../IIS-Setup/wcautil/wcascript.cpp | 447 ++ .../IIS-Setup/wcautil/wcautil.cpp | 201 + .../IIS-Setup/wcautil/wcautil.h | 344 ++ .../IIS-Setup/wcautil/wcawrap.cpp | 1419 ++++++ .../bitmaps/AspNetCoreModule.ico | Bin 0 -> 894 bytes .../bitmaps/bannrbmp.bmp | Bin 0 -> 5950 bytes .../AspNetCoreModule-Setup/bitmaps/dlgbmp.bmp | Bin 0 -> 20396 bytes .../build/copy-outputs.targets | 18 + .../build/exports.props | 13 + .../build/settings.props | 7 + .../build/settings/common.props | 53 + .../build/settings/debug.props | 29 + .../build/settings/release.props | 51 + .../build/submodule.props | 11 + .../build/versions.props | 38 + .../license/license.rtf | 97 + .../AspNetCoreModule-Setup/setupstrings.wxl | 52 + .../Windows/WindowsHostingBundle/ANCM.wxs | 4 +- src/Installers/Windows/WindowsInstallers.proj | 14 + src/Installers/Windows/Wix.props | 1 - src/Installers/Windows/Wix.targets | 3 +- .../Windows/clone_and_build_ancm.ps1 | 105 - 200 files changed, 59594 insertions(+), 109 deletions(-) create mode 100644 eng/targets/Cpp.Common.props create mode 100644 eng/targets/Cpp.Common.targets create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/ANCMIISExpressV1/AncmIISExpressV1.wixproj create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/ANCMIISExpressV1/ancm_iis_express.wxs create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/ANCMPackageResolver/ANCMPackageResolver.csproj create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/ANCMV1/AncmV1.wixproj create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/ANCMV1/aspnetcoremodule.wxs create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/CustomAction/Directory.Build.props create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/CustomAction/aspnetcoreCA.cpp create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/CustomAction/aspnetcoreCA.def create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/CustomAction/aspnetcoreCA.rc create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/CustomAction/aspnetcoreCA.vcxproj create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/CustomAction/avoid_restart.cpp create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/Directory.Build.props create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Common.sln create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/acache.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/ahutil.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/base64.hxx create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/buffer.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/datetime.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/dbgutil.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/debugutil.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/hashfn.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/hashtable.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/http_xp.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/httpserv_xp.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/hybrid_array.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/listentry.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/macros.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/multisz.hxx create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/multisza.hxx create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/normalize.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/ntassert.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/percpu.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/prime.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/reftrace.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/rwlock.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/statichash.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/stdtypes.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/stringa.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/stringu.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/sttimer.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/tracelog.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/treehash.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/LICENSE create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/MySQL/MySqlConnector.cs create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/NativeMethods/AdvApi32.cs create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/NativeMethods/Common.cs create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/NativeMethods/Fusion.cs create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/NativeMethods/Kernel32.cs create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/NativeMethods/Mlang.cs create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/NativeMethods/User32.cs create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/NativeMethods/UxTheme.cs create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/PseudoLoc/PseudoLoc.targets create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/PseudoLoc/PseudoLocalizer.cs create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/References/v7Sp1/Microsoft.Web.administration.dll create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/References/v7Sp1/Microsoft.Web.management.dll create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/Util/AuthenticationModule.cs create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/Util/ExceptionHelper.cs create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/Util/GACManagedAccess.cs create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/Util/WebUtility.cs create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/README.md create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/UnitTests/common_tests.rc create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/UnitTests/dbgutil_tests.cpp create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/UnitTests/hash_tests.cpp create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/UnitTests/hybrid_array_tests.cpp create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/UnitTests/my_hash.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/UnitTests/precomp.hxx create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/UnitTests/string_tests.cpp create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/CommonLib.vcxproj create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/acache.cxx create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/ahutil.cpp create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/base64.cxx create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/datetime.cxx create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/multisz.cxx create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/multisza.cxx create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/normalize.cxx create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/packages.config create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/precomp.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/stringa.cpp create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/stringu.cpp create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/ulparse.cxx create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/util.cxx create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/open-inc/stbuff.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/open-inc/stlist.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/open-inc/stlock.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/open-inc/sttable.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/open-inc/sttimer.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/include/dbgutil2.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/include/irtldbg.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/include/irtlmisc.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/include/memorylog.hxx create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/include/precomp.hxx create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/include/pudebug.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/reftrace.vcxproj create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/reftrace.vcxproj.filters create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/src/irtldbg.cpp create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/src/isplat.cxx create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/src/memorylog.cxx create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/src/pudebug.cxx create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/src/reftrace.c create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/src/tracelog.c create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/src/win32obj.cxx create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/version/bldver.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/version/bldver.rc create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Setup.sln create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/LICENSE create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/README.md create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/appsearch/appsearch.wxi create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/ConfigShared.cpp create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/ConfigShared.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/CustomAction.def create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/cgi_restrictions.cpp create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/cgi_restrictions.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/config_custom.cpp create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/config_custom.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/consoleprops.cpp create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/consoleprops.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/defaults.cpp create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/defaults.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/elevatedsc.cpp create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/elevatedsc.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/handlers.cpp create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/handlers.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/hotfix.cpp create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/httpapi.cpp create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/httpapi.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/iisca.cpp create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/iisca.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/iisca.vcxproj create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/iiscaexp.cpp create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/iiscaexp.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/modules.cpp create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/mof.cpp create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/msiutil.cpp create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/msiutil.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/packages.config create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/precomp.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/schema.cpp create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/secutils.cpp create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/secutils.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/setup_log.cpp create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/setup_log.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/tracing.cpp create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/tracing.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/uimodule.cpp create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/wuerror.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/wix/iisca.wxs create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/wix/setupstrings.wxl create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/wix3/ElevatedShortcut.wxi create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/wix3/FixPatchingBehavior.wxi create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/wix3/HttpListener.wxi create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/wix3/ShortcutConsoleProperties.wxi create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/wix3/WindowsHotfix.wxi create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/wix3/iisca.wxs create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/include.wxi create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/CHS/misc/setupstrings.wxl create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/CHT/misc/setupstrings.wxl create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/CSY/misc/setupstrings.wxl create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/DEU/misc/setupstrings.wxl create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/ESN/misc/setupstrings.wxl create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/FRA/misc/setupstrings.wxl create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/ITA/misc/setupstrings.wxl create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/JPN/misc/setupstrings.wxl create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/KOR/misc/setupstrings.wxl create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/PLK/misc/setupstrings.wxl create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/PTB/misc/setupstrings.wxl create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/RUS/misc/setupstrings.wxl create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/TRK/misc/setupstrings.wxl create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/dutil.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/memutil.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/precomp.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/qtexec.cpp create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/strutil.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/wcalog.cpp create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/wcascript.cpp create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/wcautil.cpp create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/wcautil.h create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/wcawrap.cpp create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/bitmaps/AspNetCoreModule.ico create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/bitmaps/bannrbmp.bmp create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/bitmaps/dlgbmp.bmp create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/build/copy-outputs.targets create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/build/exports.props create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/build/settings.props create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/build/settings/common.props create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/build/settings/debug.props create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/build/settings/release.props create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/build/submodule.props create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/build/versions.props create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/license/license.rtf create mode 100644 src/Installers/Windows/AspNetCoreModule-Setup/setupstrings.wxl delete mode 100644 src/Installers/Windows/clone_and_build_ancm.ps1 diff --git a/Directory.Build.props b/Directory.Build.props index bdb885cd9f..b281c92a76 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -35,4 +35,6 @@ + + diff --git a/Directory.Build.targets b/Directory.Build.targets index 30ce3e3322..b834d88ec0 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -14,4 +14,5 @@ + diff --git a/THIRD-PARTY-NOTICES b/THIRD-PARTY-NOTICES index a6470f40de..d1bf499032 100644 --- a/THIRD-PARTY-NOTICES +++ b/THIRD-PARTY-NOTICES @@ -35,3 +35,52 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +License notice for IIS-Common +------------------------------------ + +MIT License + +Copyright (c) Microsoft Corporation. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE + +License notice for IIS-Setup +------------------------------------ + +MIT License + +Copyright (c) Microsoft Corporation. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE diff --git a/eng/targets/Cpp.Common.props b/eng/targets/Cpp.Common.props new file mode 100644 index 0000000000..f295dbafad --- /dev/null +++ b/eng/targets/Cpp.Common.props @@ -0,0 +1,11 @@ + + + + + true + + + + + + diff --git a/eng/targets/Cpp.Common.targets b/eng/targets/Cpp.Common.targets new file mode 100644 index 0000000000..f2cad0d8c0 --- /dev/null +++ b/eng/targets/Cpp.Common.targets @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/ANCMIISExpressV1/AncmIISExpressV1.wixproj b/src/Installers/Windows/AspNetCoreModule-Setup/ANCMIISExpressV1/AncmIISExpressV1.wixproj new file mode 100644 index 0000000000..8aac844ad9 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/ANCMIISExpressV1/AncmIISExpressV1.wixproj @@ -0,0 +1,72 @@ + + + + + + AspNetCoreModuleIISExpress + 2A6A4709-30D2-4716-A597-55DF0FB74D37 + Package + ICE03 + true + + + + ancm_iis_express_x86_en + + + ancm_iis_express_x64_en + + + True + + + + + iisca.wxs + + + + + + + + + + This project is trying to import a missing file: {0}. + + + + + + + + + + $(WixExtDir)\WixUtilExtension.dll + WixUtilExtension + + + $(WixExtDir)\WixDependencyExtension.dll + WixDependencyExtension + + + $(WixExtDir)\WixUIExtension.dll + WixUIExtension + + + + + + setupstrings.wxl + + + + + include.wxi + + + + + + + \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/ANCMIISExpressV1/ancm_iis_express.wxs b/src/Installers/Windows/AspNetCoreModule-Setup/ANCMIISExpressV1/ancm_iis_express.wxs new file mode 100644 index 0000000000..00a8af36cf --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/ANCMIISExpressV1/ancm_iis_express.wxs @@ -0,0 +1,674 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Microsoft Corporation + + + + + + + + + + + (NOT NEWERVERSIONFOUND) OR Installed + + + Privileged + + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + !(loc.Error30001) + !(loc.Error30002) + + !(loc.WebServicesRunning) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/ANCMPackageResolver/ANCMPackageResolver.csproj b/src/Installers/Windows/AspNetCoreModule-Setup/ANCMPackageResolver/ANCMPackageResolver.csproj new file mode 100644 index 0000000000..591599ecca --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/ANCMPackageResolver/ANCMPackageResolver.csproj @@ -0,0 +1,25 @@ + + + netstandard1.0 + true + true + $(RepositoryRoot).deps\ANCM + + + + + + + + + $(RepositoryRoot).deps\ANCM; + + + $(RestoreSources); + https://dotnetfeed.blob.core.windows.net/dotnet-core/index.json; + https://api.nuget.org/v3/index.json; + https://dotnet.myget.org/F/dotnet-core/api/v3/index.json; + + + + \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/ANCMV1/AncmV1.wixproj b/src/Installers/Windows/AspNetCoreModule-Setup/ANCMV1/AncmV1.wixproj new file mode 100644 index 0000000000..c1f389495c --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/ANCMV1/AncmV1.wixproj @@ -0,0 +1,74 @@ + + + + + + AspNetCoreModule + D36FDC38-FE53-48CC-BC82-A17C28F1CEE1 + true + Package + true + + + + aspnetcoremodule_x86_en + + + aspnetcoremodule_x64_en + + + + True + + + + + iisca.wxs + + + + + + + + + + + This project is trying to import a missing file: {0}. + + + + + + + + + + $(WixExtDir)\WixUtilExtension.dll + WixUtilExtension + + + $(WixExtDir)\WixDependencyExtension.dll + WixDependencyExtension + + + $(WixExtDir)\WixUIExtension.dll + WixUIExtension + + + + + + setupstrings.wxl + + + + + include.wxi + + + + + + + \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/ANCMV1/aspnetcoremodule.wxs b/src/Installers/Windows/AspNetCoreModule-Setup/ANCMV1/aspnetcoremodule.wxs new file mode 100644 index 0000000000..cdb387e44f --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/ANCMV1/aspnetcoremodule.wxs @@ -0,0 +1,276 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Microsoft Corporation + + + + + + + + + + + + + + + + + + (NOT NEWERVERSIONFOUND) OR Installed + + + + Privileged + + + + + + + + + + + + + + + + 1 + + + + = 601)]]> + + + + + ((IISCOREWEBENGINEINSTALLED = "#1") AND (IISW3SVCINSTALLED = "#1")) OR (Installed) + + + + + NOT ( (VersionNT = 600) AND (ServicePackLevel = 1) AND (WINDOWSUPDATE_START_TYPE = "#4") ) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + !(loc.Error30001) + !(loc.Error30002) + + !(loc.WebServicesRunning) + + + + + + AspNetCoreModule + AspNetCoreModuleDll + + + + + + system.webServer/aspNetCore + AspNetCoreSchemaFile + Allow + + + + + + WWW Server + {3a2a4e84-4c21-4981-ae10-3fda0d9b0f83} + ANCM + 65536 + AspNetCoreModule + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/CustomAction/Directory.Build.props b/src/Installers/Windows/AspNetCoreModule-Setup/CustomAction/Directory.Build.props new file mode 100644 index 0000000000..2f47372910 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/CustomAction/Directory.Build.props @@ -0,0 +1,15 @@ + + + + + + + $(_TwoDigitYear)$(_ThreeDigitDayOfYear) + $(PRODUCT_MAJOR) + $(PRODUCT_MINOR) + $(BUILD_MAJOR) + $(BUILD_MINOR) + BLDVERMAJOR=$(BLDVERMAJOR);BLDVERMINOR=$(BLDVERMINOR);BLDNUMMAJOR=$(BLDNUMMAJOR);BLDNUMMINOR=$(BLDNUMMINOR);$(DefineConstants) + + + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/CustomAction/aspnetcoreCA.cpp b/src/Installers/Windows/AspNetCoreModule-Setup/CustomAction/aspnetcoreCA.cpp new file mode 100644 index 0000000000..48d826f720 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/CustomAction/aspnetcoreCA.cpp @@ -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. + +#include + +DECLARE_DEBUG_PRINT_OBJECT( "proxyCA.dll" ); + +HINSTANCE g_hinst; + +BOOL WINAPI +DllMain( + HINSTANCE hModule, + DWORD dwReason, + LPVOID lpReserved + ) +{ + UNREFERENCED_PARAMETER( lpReserved ); + switch( dwReason ) + { + case DLL_PROCESS_ATTACH: + CREATE_DEBUG_PRINT_OBJECT; + DisableThreadLibraryCalls( hModule ); + g_hinst = hModule; + break; + + case DLL_PROCESS_DETACH: + break; + } + + return TRUE; +} + + +struct COMPRESSION_MIME_TYPE +{ + PCWSTR pszMimeType; + BOOL fEnabled; +}; + +COMPRESSION_MIME_TYPE gMimeTypes[] = + { { L"text/event-stream", FALSE} }; + +UINT +WINAPI +RegisterANCMCompressionCA( + IN MSIHANDLE + ) +{ + HRESULT hr = S_OK; + DWORD i; + VARIANT varName; + IAppHostWritableAdminManager * pAdminMgr = NULL; + IAppHostElement * pHttpCompressionSection = NULL; + IAppHostElement * pDynamicCompressionElement = NULL; + IAppHostElementCollection * pMimeTypeCollection = NULL; + IAppHostElement * pMimeTypeElement = NULL; + + VariantInit(&varName); + + hr = CoCreateInstance(__uuidof(AppHostWritableAdminManager), + NULL, + CLSCTX_INPROC_SERVER, + __uuidof(IAppHostWritableAdminManager), + (VOID **)&pAdminMgr); + if (FAILED(hr)) + { + goto exit; + } + + hr = pAdminMgr->GetAdminSection(L"system.webServer/httpCompression", + L"MACHINE/WEBROOT/APPHOST", + &pHttpCompressionSection); + if (FAILED(hr)) + { + goto exit; + } + + hr = pHttpCompressionSection->GetElementByName(L"dynamicTypes", + &pDynamicCompressionElement); + if (FAILED(hr)) + { + goto exit; + } + + hr = pDynamicCompressionElement->get_Collection(&pMimeTypeCollection); + if (FAILED(hr)) + { + goto exit; + } + + hr = pMimeTypeCollection->get_Count(&i); + if (FAILED(hr) || i == 0) + { + // failure or DynamicCmpression is not enabled + goto exit; + } + + for (i=0; i<_countof(gMimeTypes); i++) + { + hr = pMimeTypeCollection->CreateNewElement(L"add", + &pMimeTypeElement); + if (FAILED(hr)) + { + goto exit; + } + + hr = VariantAssign(&varName, + gMimeTypes[i].pszMimeType); + if (FAILED(hr)) + { + goto exit; + } + + hr = SetElementProperty(pMimeTypeElement, + L"mimeType", + &varName); + if (FAILED(hr)) + { + goto exit; + } + VariantClear(&varName); + + varName.vt = VT_BOOL; + varName.boolVal = gMimeTypes[i].fEnabled ? VARIANT_TRUE : VARIANT_FALSE; + + hr = SetElementProperty(pMimeTypeElement, + L"enabled", + &varName); + if (FAILED(hr)) + { + goto exit; + } + VariantClear(&varName); + + hr = pMimeTypeCollection->AddElement(pMimeTypeElement); + if (FAILED(hr) && + hr != HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS)) + { + goto exit; + } + + pMimeTypeElement->Release(); + pMimeTypeElement = NULL; + } + + hr = pAdminMgr->CommitChanges(); + + exit: + + VariantClear(&varName); + + if (pMimeTypeElement != NULL) + { + pMimeTypeElement->Release(); + pMimeTypeElement = NULL; + } + + if (pMimeTypeCollection != NULL) + { + pMimeTypeCollection->Release(); + pMimeTypeCollection = NULL; + } + + if (pDynamicCompressionElement != NULL) + { + pDynamicCompressionElement->Release(); + pDynamicCompressionElement = NULL; + } + + if (pHttpCompressionSection != NULL) + { + pHttpCompressionSection->Release(); + pHttpCompressionSection = NULL; + } + + if (pAdminMgr != NULL) + { + pAdminMgr->Release(); + pAdminMgr = NULL; + } + + return (SUCCEEDED(hr)) ? ERROR_SUCCESS : ERROR_SUCCESS; +} + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/CustomAction/aspnetcoreCA.def b/src/Installers/Windows/AspNetCoreModule-Setup/CustomAction/aspnetcoreCA.def new file mode 100644 index 0000000000..3518cde35f --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/CustomAction/aspnetcoreCA.def @@ -0,0 +1,23 @@ +LIBRARY aspnetcoreCA + +EXPORTS + + ; IIS Common Config custom actions + + IISScheduleInstallCA + IISScheduleUninstallCA + IISExecuteCA + IISBeginTransactionCA + IISRollbackTransactionCA + IISCommitTransactionCA + + CheckForSharedConfigurationCA + + ScheduleInstallWindowsHotfixCA + ExecuteInstallWindowsHotfixCA + ExecuteCleanUpWindowsHotfixCA + ScheduleRebootIfRequiredCA + + RegisterANCMCompressionCA + + CheckForServicesRunningCA diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/CustomAction/aspnetcoreCA.rc b/src/Installers/Windows/AspNetCoreModule-Setup/CustomAction/aspnetcoreCA.rc new file mode 100644 index 0000000000..8f05349435 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/CustomAction/aspnetcoreCA.rc @@ -0,0 +1,10 @@ +#define VER_FILETYPE VFT_DLL +#define RC_VERSION_INTERNAL_NAME "aspnetcoreCA\0" +#define RC_VERSION_ORIGINAL_FILE_NAME "aspnetcoreCA.dll\0" +#define RC_VERSION_FILE_DESCRIPTION "IIS AspNet Core Support Module Custom Action DLL\0" +#define PRODUCT_MAJOR 7 +#define PRODUCT_MINOR 1 +#define BUILD_MAJOR 1972 +#define BUILD_MINOR 0 + +#include diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/CustomAction/aspnetcoreCA.vcxproj b/src/Installers/Windows/AspNetCoreModule-Setup/CustomAction/aspnetcoreCA.vcxproj new file mode 100644 index 0000000000..d4b2493fb9 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/CustomAction/aspnetcoreCA.vcxproj @@ -0,0 +1,98 @@ + + + + + $(MSBuildThisFileDirectory)..\ + + + + <_IIS-SetupExportsPath>$(ANCM-Setup)IIS-Setup\build\exports.props + + + + + + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {7C27E72F-54D0-4820-8CFA-5E4BE640974B} + aspnetcoreca + aspnetcoreCA + + + + DynamicLibrary + v141 + Unicode + + + true + + + + $(IIS-Common)version;$(IIS-Common)Include;$(IIS-Setup)iisca\lib;$(WIX)sdk\$(WixPlatformToolset)\inc;$(AdditionalIncludeDirectories) + + + + true + $(AdditionalIncludeDirectories) + + + httpapi.lib;shlwapi.lib;ahadmin.lib;xmllite.lib;msi.lib;Version.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + aspnetcoreCA.def + $(OutDir)$(TargetName).lib + /NODEFAULTLIB:MSVCRT %(AdditionalOptions) + + + + + + + + + + + + $(IIS-Common)version + + + + + {7324770c-0871-4d73-be3d-5e2f3e9e1b1e} + + + {b54a8f61-60de-4ad9-87ca-d102f230678e} + + + + + + + + This project is trying to import a missing file: {0}. + + + + + + + \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/CustomAction/avoid_restart.cpp b/src/Installers/Windows/AspNetCoreModule-Setup/CustomAction/avoid_restart.cpp new file mode 100644 index 0000000000..b0e4753c44 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/CustomAction/avoid_restart.cpp @@ -0,0 +1,244 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +#include +#include + +HRESULT +GetServiceCurrentState( + __in LPCWSTR pszServiceName, + __out SERVICE_STATUS * pServiceStatus +) +{ + HRESULT hr = S_OK; + SC_HANDLE hServiceControlManager = NULL; + SC_HANDLE hService = NULL; + + hServiceControlManager = OpenSCManager( NULL, // Local machine + NULL, + STANDARD_RIGHTS_READ ); + if ( hServiceControlManager == NULL ) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + DBGERROR_HR(hr); + goto Finished; + } + + hService = OpenService( hServiceControlManager, + pszServiceName, + SERVICE_QUERY_STATUS ); + if ( hService == NULL ) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + DBGERROR_HR(hr); + goto Finished; + } + + if ( !QueryServiceStatus( hService, + pServiceStatus ) ) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + DBGERROR_HR(hr); + goto Finished; + } + +Finished: + + if ( hService != NULL ) + { + CloseServiceHandle( hService ); + hService = NULL; + } + + if ( hServiceControlManager != NULL ) + { + CloseServiceHandle( hService ); + hService = NULL; + } + + return hr; +} + +BOOL +IsServiceRunning( + const SERVICE_STATUS & ServiceStatus +) +{ + switch( ServiceStatus.dwCurrentState ) + { + case SERVICE_RUNNING: + case SERVICE_START_PENDING: + case SERVICE_CONTINUE_PENDING: + return TRUE; + default: + return FALSE; + } +} + +HRESULT +IsQfeInstalled( + __in LPCWSTR pszQfeName, + __out BOOL * pfIsInstalled +) +{ + HRESULT hr = S_OK; + CComPtr< IWbemLocator > pLocator; + CComPtr< IWbemServices > pService; + CComPtr< IEnumWbemClassObject > pEnumerator; + ULONG Count = 0; + CComPtr< IWbemClassObject > pProcessor; + CComBSTR bstrNamespace; + CComBSTR bstrQueryLanguage; + CComBSTR bstrQuery; + + if ( FAILED( hr = bstrNamespace.Append( L"root\\CIMV2", 10 ) ) || + FAILED( hr = bstrQueryLanguage.Append( L"WQL", 3 ) ) || + FAILED( hr = bstrQuery.Append( L"SELECT HotFixID FROM Win32_QuickFixEngineering WHERE HotFixID='" ) ) || + FAILED( hr = bstrQuery.Append( pszQfeName ) ) || + FAILED( hr = bstrQuery.Append( L"'", 1 ) ) ) + { + goto Finished; + } + + hr = CoCreateInstance( __uuidof(WbemAdministrativeLocator), + NULL, // pUnkOuter + CLSCTX_INPROC_SERVER, + __uuidof(IWbemLocator), + reinterpret_cast< void** >( &pLocator ) ); + if ( FAILED( hr ) ) + { + goto Finished; + } + + hr = pLocator->ConnectServer( bstrNamespace, + NULL, // strUser + NULL, // strPassword + NULL, // strLocale + WBEM_FLAG_CONNECT_USE_MAX_WAIT, + NULL, // strAuthority + NULL, // pCtx + &pService ); + if ( FAILED( hr ) ) + { + goto Finished; + } + + // + // Set the proxy so that impersonation of the client occurs. + // + hr = CoSetProxyBlanket( pService, + RPC_C_AUTHN_DEFAULT, + RPC_C_AUTHZ_NONE, + NULL, + RPC_C_AUTHN_LEVEL_CONNECT, + RPC_C_IMP_LEVEL_IMPERSONATE, + NULL, + EOAC_NONE); + if ( FAILED( hr ) ) + { + goto Finished; + } + + hr = pService->ExecQuery( bstrQueryLanguage, + bstrQuery, + WBEM_FLAG_FORWARD_ONLY, + NULL, + &pEnumerator ); + if ( FAILED( hr ) ) + { + goto Finished; + } + + hr = pEnumerator->Next( WBEM_INFINITE, + 1L, + &pProcessor, + &Count ); + if ( FAILED( hr ) ) + { + goto Finished; + } + + *pfIsInstalled = Count > 0; + +Finished: + + return hr; +} + +UINT +WINAPI +CheckForServicesRunningCA( + MSIHANDLE hInstall +) +{ + HRESULT hr = S_OK; + BOOL fIsServiceRunning = FALSE; + SERVICE_STATUS ServiceStatus; + LPCWSTR rgServiceNames[] = { L"WAS", L"WMSVC" }; + + IISLogInitialize(hInstall, UNITEXT(__FUNCTION__)); + + // + // Check if any pService is running. + // + for( DWORD Index = 0; Index < _countof( rgServiceNames ); Index ++ ) + { + hr = GetServiceCurrentState( rgServiceNames[Index], + &ServiceStatus ); + if ( hr == HRESULT_FROM_WIN32( ERROR_SERVICE_DOES_NOT_EXIST ) ) + { + hr = S_OK; + } + else if ( FAILED( hr ) ) + { + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, + L"Failed to query the state of the service '%s' hr=0x%x", + rgServiceNames[Index], + hr ); + DBGERROR_HR(hr); + goto Finished; + } + else + { + fIsServiceRunning = IsServiceRunning( ServiceStatus ); + if ( fIsServiceRunning ) + { + break; + } + } + } + + if ( fIsServiceRunning ) + { + BOOL fQfeInstalled = FALSE; + + hr = IsQfeInstalled( L"KB954438", + &fQfeInstalled ); + if ( FAILED( hr ) ) + { + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, + L"Failed to query the hotfix 'KB949172' information hr=0x%x", + hr ); + DBGERROR_HR(hr); + goto Finished; + } + + if ( fQfeInstalled ) + { + // + // hotfix is already installed. + // + goto Finished; + } + + IISLogClose(); + return LogMsiCustomActionError( hInstall, 30003 ); + } + +Finished: + + IISLogClose(); + + // TODO Wire up when Rollback CA's are wired up + return (SUCCEEDED(hr)) ? ERROR_SUCCESS : ERROR_SUCCESS; +} diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/Directory.Build.props b/src/Installers/Windows/AspNetCoreModule-Setup/Directory.Build.props new file mode 100644 index 0000000000..e790ba07a1 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/Directory.Build.props @@ -0,0 +1,43 @@ + + + + + + + <_TwoDigitYear>$([MSBuild]::Subtract($([System.DateTime]::UtcNow.Year), 2000)) + <_ThreeDigitDayOfYear>$([System.DateTime]::UtcNow.DayOfYear.ToString().PadLeft(3, '0')) + + + $(_TwoDigitYear)$(_ThreeDigitDayOfYear) + $(PRODUCT_MAJOR) + $(PRODUCT_MINOR) + $(BUILD_MAJOR) + $(BUILD_MINOR) + + + 1$(AspNetCoreMajorVersion).$(AspNetCoreMinorVersion).$(BUILD_MAJOR).0 + + + 2.0.0 + + + $(RepositoryRoot)src\Installers\Windows\AspNetCoreModule-Setup\ + $(AspNetCoreSetupRoot)IIS-Setup\ + $(IIS-Setup)IIS-Common\ + $(AspNetCoreSetupRoot)build\ + + + CustomAction=$(AspNetCoreSetupRoot)CustomAction\bin\$(Configuration)\$(Platform)\aspnetcoreca.dll + $(RepositoryRoot).deps\ANCM\Microsoft.AspNetCore.AspNetCoreModule\$(MicrosoftAspNetCoreAspNetCoreModulePackageVersion)\ + $(RepositoryRoot).deps\ANCM\Microsoft.AspNetCore.AspNetCoreModuleV2\$(MicrosoftAspNetCoreAspNetCoreModuleV2PackageVersion)\ + $(PreBuiltANCMSchema)contentFiles\any\any\ + $(PreBuiltANCMV2Schema)contentFiles\any\any\ + + BLDVERMAJOR=$(BLDVERMAJOR);BLDVERMINOR=$(BLDVERMINOR);BLDNUMMAJOR=$(BLDNUMMAJOR);BLDNUMMINOR=$(BLDNUMMINOR);$(DefineConstants) + ANCMMsiVersion=$(ANCMMsiVersion);ANCMOutOfProcessNugetPackageHandlerVersion=$(ANCMOutOfProcessNugetPackageHandlerVersion);$(DefineConstants) + PreBuiltANCMRoot=$(PreBuiltANCMRoot);PreBuiltANCMV2Root=$(PreBuiltANCMV2Root);$(DefineConstants) + $(CustomActionVariable);PreBuiltANCMSchema=$(PreBuiltANCMSchema);PreBuiltANCMV2Schema=$(PreBuiltANCMV2Schema);$(DefineConstants) + + + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Common.sln b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Common.sln new file mode 100644 index 0000000000..5b48ec6769 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Common.sln @@ -0,0 +1,41 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27120.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CommonLib", "lib\CommonLib.vcxproj", "{B54A8F61-60DE-4AD9-87CA-D102F230678E}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "reftrace", "reftrace\reftrace.vcxproj", "{A2599642-CBE5-4230-8511-3DC2D81874BE}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B54A8F61-60DE-4AD9-87CA-D102F230678E}.Debug|x64.ActiveCfg = Debug|x64 + {B54A8F61-60DE-4AD9-87CA-D102F230678E}.Debug|x64.Build.0 = Debug|x64 + {B54A8F61-60DE-4AD9-87CA-D102F230678E}.Debug|x86.ActiveCfg = Debug|Win32 + {B54A8F61-60DE-4AD9-87CA-D102F230678E}.Debug|x86.Build.0 = Debug|Win32 + {B54A8F61-60DE-4AD9-87CA-D102F230678E}.Release|x64.ActiveCfg = Release|x64 + {B54A8F61-60DE-4AD9-87CA-D102F230678E}.Release|x64.Build.0 = Release|x64 + {B54A8F61-60DE-4AD9-87CA-D102F230678E}.Release|x86.ActiveCfg = Release|Win32 + {B54A8F61-60DE-4AD9-87CA-D102F230678E}.Release|x86.Build.0 = Release|Win32 + {A2599642-CBE5-4230-8511-3DC2D81874BE}.Debug|x64.ActiveCfg = Debug|x64 + {A2599642-CBE5-4230-8511-3DC2D81874BE}.Debug|x64.Build.0 = Debug|x64 + {A2599642-CBE5-4230-8511-3DC2D81874BE}.Debug|x86.ActiveCfg = Debug|Win32 + {A2599642-CBE5-4230-8511-3DC2D81874BE}.Debug|x86.Build.0 = Debug|Win32 + {A2599642-CBE5-4230-8511-3DC2D81874BE}.Release|x64.ActiveCfg = Release|x64 + {A2599642-CBE5-4230-8511-3DC2D81874BE}.Release|x64.Build.0 = Release|x64 + {A2599642-CBE5-4230-8511-3DC2D81874BE}.Release|x86.ActiveCfg = Release|Win32 + {A2599642-CBE5-4230-8511-3DC2D81874BE}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {81F5A61A-A12A-4F53-B0F9-C0E541CA6567} + EndGlobalSection +EndGlobal diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/acache.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/acache.h new file mode 100644 index 0000000000..83e39fd7ff --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/acache.h @@ -0,0 +1,116 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#pragma once + +#include "percpu.h" + + +class ALLOC_CACHE_HANDLER +{ +public: + + ALLOC_CACHE_HANDLER( + VOID + ); + + ~ALLOC_CACHE_HANDLER( + VOID + ); + + HRESULT + Initialize( + DWORD cbSize, + LONG nThreshold + ); + + LPVOID + Alloc( + VOID + ); + + VOID + Free( + __in LPVOID pMemory + ); + + +private: + + VOID + CleanupLookaside( + VOID + ); + + DWORD + QueryDepthForAllSLists( + VOID + ); + + LONG m_nThreshold; + DWORD m_cbSize; + + PER_CPU * m_pFreeLists; + + // + // Total heap allocations done over the lifetime. + // Note that this is not interlocked, it is just a hint for debugging. + // + volatile LONG m_nTotal; + + LONG m_nFillPattern; + +public: + + static + HRESULT + StaticInitialize( + VOID + ); + + static + VOID + StaticTerminate( + VOID + ); + + static + BOOL + IsPageheapEnabled(); + +private: + + static LONG sm_nFillPattern; + static HANDLE sm_hHeap; +}; + + +// You can use ALLOC_CACHE_HANDLER as a per-class allocator +// in your C++ classes. Add the following to your class definition: +// +// protected: +// static ALLOC_CACHE_HANDLER* sm_palloc; +// public: +// static void* operator new(size_t s) +// { +// IRTLASSERT(s == sizeof(C)); +// IRTLASSERT(sm_palloc != NULL); +// return sm_palloc->Alloc(); +// } +// static void operator delete(void* pv) +// { +// IRTLASSERT(pv != NULL); +// if (sm_palloc != NULL) +// sm_palloc->Free(pv); +// } +// +// Obviously, you must initialize sm_palloc before you can allocate +// any objects of this class. +// +// Note that if you derive a class from this base class, the derived class +// must also provide its own operator new and operator delete. If not, the +// base class's allocator will be called, but the size of the derived +// object will almost certainly be larger than that of the base object. +// Furthermore, the allocator will not be used for arrays of objects +// (override operator new[] and operator delete[]), but this is a +// harder problem since the allocator works with one fixed size. diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/ahutil.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/ahutil.h new file mode 100644 index 0000000000..a39c09bb73 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/ahutil.h @@ -0,0 +1,264 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#pragma once + +HRESULT +SetElementProperty( + IN IAppHostElement * pElement, + IN CONST WCHAR * szPropName, + IN CONST VARIANT * varPropValue + ); + +HRESULT +SetElementStringProperty( + IN IAppHostElement * pElement, + IN CONST WCHAR * szPropName, + IN CONST WCHAR * szPropValue + ); + +HRESULT +GetElementStringProperty( + IN IAppHostElement * pElement, + IN CONST WCHAR * szPropName, + OUT BSTR * pbstrPropValue + ); + +HRESULT +GetElementStringProperty( + IN IAppHostElement * pElement, + IN CONST WCHAR * szPropName, + OUT STRU * pstrPropValue + ); + +HRESULT +GetElementBoolProperty( + IN IAppHostElement * pElement, + IN LPCWSTR pszPropertyName, + OUT BOOL * pBool + ); + +HRESULT +GetElementBoolProperty( + IN IAppHostElement * pElement, + IN LPCWSTR pszPropertyName, + OUT bool * pBool + ); + +HRESULT +GetElementChildByName( + IN IAppHostElement * pElement, + IN LPCWSTR pszElementName, + OUT IAppHostElement ** ppChildElement + ); + +HRESULT +GetElementDWORDProperty( + IN IAppHostElement * pElement, + IN LPCWSTR pszPropertyName, + OUT DWORD * pdwValue + ); + +HRESULT +GetElementINTProperty( + IN IAppHostElement * pElement, + IN LPCWSTR pszPropertyName, + OUT INT * pintValue + ); + +HRESULT +GetElementLONGLONGProperty( + IN IAppHostElement * pElement, + IN LPCWSTR pszPropertyName, + OUT LONGLONG * pllValue +); + + +HRESULT +GetElementRawTimeSpanProperty( + IN IAppHostElement * pElement, + IN LPCWSTR pszPropertyName, + OUT ULONGLONG * pulonglong + ); + +#define FIND_ELEMENT_CASE_SENSITIVE 0x00000000 +#define FIND_ELEMENT_CASE_INSENSITIVE 0x00000001 + +HRESULT +DeleteElementFromCollection( + IAppHostElementCollection *pCollection, + CONST WCHAR * szKeyName, + CONST WCHAR * szKeyValue, + ULONG BehaviorFlags, + BOOL * pfDeleted + ); + +HRESULT +DeleteAllElementsFromCollection( + IAppHostElementCollection *pCollection, + CONST WCHAR * szKeyName, + CONST WCHAR * szKeyValue, + ULONG BehaviorFlags, + UINT * pNumDeleted + ); + +HRESULT +FindElementInCollection( + IAppHostElementCollection *pCollection, + CONST WCHAR * szKeyName, + CONST WCHAR * szKeyValue, + ULONG BehaviorFlags, + OUT ULONG * pIndex + ); + +HRESULT +VariantAssign( + IN OUT VARIANT * pv, + IN CONST WCHAR * sz + ); + +HRESULT +GetLocationFromFile( + IN IAppHostAdminManager * pAdminMgr, + IN CONST WCHAR * szConfigPath, + IN CONST WCHAR * szLocationPath, + OUT IAppHostConfigLocation ** ppLocation, + OUT BOOL * pFound + ); + +HRESULT +GetSectionFromLocation( + IN IAppHostConfigLocation * pLocation, + IN CONST WCHAR * szSectionName, + OUT IAppHostElement ** ppSectionElement, + OUT BOOL * pFound + ); + +HRESULT +GetAdminElement( + IN IAppHostAdminManager * pAdminMgr, + IN CONST WCHAR * szConfigPath, + IN CONST WCHAR * szElementName, + OUT IAppHostElement ** pElement + ); + +HRESULT +ClearAdminElement( + IN IAppHostAdminManager * pAdminMgr, + IN CONST WCHAR * szConfigPath, + IN CONST WCHAR * szElementName + ); + +HRESULT +ClearElementFromAllSites( + IN IAppHostAdminManager * pAdminMgr, + IN CONST WCHAR * szConfigPath, + IN CONST WCHAR * szElementName + ); + +HRESULT +ClearElementFromAllLocations( + IN IAppHostAdminManager * pAdminMgr, + IN CONST WCHAR * szConfigPath, + IN CONST WCHAR * szElementName + ); + +HRESULT +ClearLocationElements( + IN IAppHostConfigLocation * pLocation, + IN CONST WCHAR * szElementName + ); + +HRESULT +CompareElementName( + IN IAppHostElement * pElement, + IN CONST WCHAR * szNameToMatch, + OUT BOOL * pMatched + ); + +HRESULT +ClearChildElementsByName( + IN IAppHostChildElementCollection * pCollection, + IN CONST WCHAR * szElementName, + OUT BOOL * pFound + ); + +HRESULT +GetSitesCollection( + IN IAppHostAdminManager * pAdminMgr, + IN CONST WCHAR * szConfigPath, + OUT IAppHostElementCollection ** pSitesCollection + ); + +HRESULT +GetLocationCollection( + IN IAppHostAdminManager * pAdminMgr, + IN CONST WCHAR * szConfigPath, + OUT IAppHostConfigLocationCollection ** pLocationCollection + ); + +struct ENUM_INDEX +{ + VARIANT Index; + ULONG Count; +}; + +HRESULT +FindFirstElement( + IN IAppHostElementCollection * pCollection, + OUT ENUM_INDEX * pIndex, + OUT IAppHostElement ** pElement + ); + +HRESULT +FindNextElement( + IN IAppHostElementCollection * pCollection, + IN OUT ENUM_INDEX * pIndex, + OUT IAppHostElement ** pElement + ); + +HRESULT +FindFirstChildElement( + IN IAppHostChildElementCollection * pCollection, + OUT ENUM_INDEX * pIndex, + OUT IAppHostElement ** pElement + ); + +HRESULT +FindNextChildElement( + IN IAppHostChildElementCollection * pCollection, + IN OUT ENUM_INDEX * pIndex, + OUT IAppHostElement ** pElement + ); + +HRESULT +FindFirstLocation( + IN IAppHostConfigLocationCollection * pCollection, + OUT ENUM_INDEX * pIndex, + OUT IAppHostConfigLocation ** pLocation + ); + +HRESULT +FindNextLocation( + IN IAppHostConfigLocationCollection * pCollection, + IN OUT ENUM_INDEX * pIndex, + OUT IAppHostConfigLocation ** pLocation + ); + +HRESULT +FindFirstLocationElement( + IN IAppHostConfigLocation * pLocation, + OUT ENUM_INDEX * pIndex, + OUT IAppHostElement ** pElement + ); + +HRESULT +FindNextLocationElement( + IN IAppHostConfigLocation * pLocation, + IN OUT ENUM_INDEX * pIndex, + OUT IAppHostElement ** pElement + ); + +HRESULT GetSharedConfigEnabled( + BOOL * pfIsSharedConfig +); \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/base64.hxx b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/base64.hxx new file mode 100644 index 0000000000..871c7e8e0f --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/base64.hxx @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#ifndef _BASE64_HXX_ +#define _BASE64_HXX_ + +DWORD +Base64Encode( + __in_bcount( cbDecodedBufferSize ) VOID * pDecodedBuffer, + IN DWORD cbDecodedBufferSize, + __out_ecount_opt( cchEncodedStringSize ) PWSTR pszEncodedString, + IN DWORD cchEncodedStringSize, + __out_opt DWORD * pcchEncoded + ); + +DWORD +Base64Decode( + __in PCWSTR pszEncodedString, + __out_opt VOID * pDecodeBuffer, + __in DWORD cbDecodeBufferSize, + __out_opt DWORD * pcbDecoded + ); + +DWORD +Base64Encode( + __in_bcount( cbDecodedBufferSize ) VOID * pDecodedBuffer, + IN DWORD cbDecodedBufferSize, + __out_ecount_opt( cchEncodedStringSize ) PSTR pszEncodedString, + IN DWORD cchEncodedStringSize, + __out_opt DWORD * pcchEncoded + ); + +DWORD +Base64Decode( + __in PCSTR pszEncodedString, + __out_opt VOID * pDecodeBuffer, + __in DWORD cbDecodeBufferSize, + __out_opt DWORD * pcbDecoded + ); + +#endif // _BASE64_HXX_ + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/buffer.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/buffer.h new file mode 100644 index 0000000000..63e567be4d --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/buffer.h @@ -0,0 +1,271 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#pragma once + +#include + + +// +// BUFFER_T class shouldn't be used directly. Use BUFFER specialization class instead. +// The only BUFFER_T partners are STRU and STRA classes. +// BUFFER_T cannot hold other but primitive types since it doesn't call +// constructor and destructor. +// +// Note: Size is in bytes. +// +template +class BUFFER_T +{ +public: + + BUFFER_T() + : m_cbBuffer( sizeof(m_rgBuffer) ), + m_fHeapAllocated( false ), + m_pBuffer(m_rgBuffer) + /*++ + Description: + + Default constructor where the inline buffer is used. + + Arguments: + + None. + + Returns: + + None. + + --*/ + { + } + + BUFFER_T( + __inout_bcount(cbInit) T* pbInit, + __in DWORD cbInit + ) : m_pBuffer( pbInit ), + m_cbBuffer( cbInit ), + m_fHeapAllocated( false ) + /*++ + Description: + + Instantiate BUFFER, initially using pbInit as buffer + This is useful for stack-buffers and inline-buffer class members + (see STACK_BUFFER and INLINE_BUFFER_INIT below) + + BUFFER does not free pbInit. + + Arguments: + + pbInit - Initial buffer to use. + cbInit - Size of pbInit in bytes (not in elements). + + Returns: + + None. + + --*/ + { + _ASSERTE( NULL != pbInit ); + _ASSERTE( cbInit > 0 ); + } + + ~BUFFER_T() + { + if( IsHeapAllocated() ) + { + _ASSERTE( NULL != m_pBuffer ); + HeapFree( GetProcessHeap(), 0, m_pBuffer ); + m_pBuffer = NULL; + m_cbBuffer = 0; + m_fHeapAllocated = false; + } + } + + T* + QueryPtr( + VOID + ) const + { + // + // Return pointer to data buffer. + // + return m_pBuffer; + } + + DWORD + QuerySize( + VOID + ) const + { + // + // Return number of bytes. + // + return m_cbBuffer; + } + + __success(return == true) + bool + Resize( + const SIZE_T cbNewSize, + const bool fZeroMemoryBeyondOldSize = false + ) + /*++ + Description: + + Resizes the buffer. + + Arguments: + + cbNewSize - Size in bytes to grow to. + fZeroMemoryBeyondOldSize + - Whether to zero the region of memory of the + new buffer beyond the original size. + + Returns: + + TRUE on success, FALSE on failure. + + --*/ + { + PVOID pNewMem; + + if ( cbNewSize <= m_cbBuffer ) + { + return true; + } + + if ( cbNewSize > MAXDWORD ) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return false; + } + + DWORD dwHeapAllocFlags = fZeroMemoryBeyondOldSize ? HEAP_ZERO_MEMORY : 0; + + if( IsHeapAllocated() ) + { + pNewMem = HeapReAlloc( GetProcessHeap(), dwHeapAllocFlags, m_pBuffer, cbNewSize ); + } + else + { + pNewMem = HeapAlloc( GetProcessHeap(), dwHeapAllocFlags, cbNewSize ); + } + + if( pNewMem == NULL ) + { + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + return false; + } + + if( !IsHeapAllocated() ) + { + // + // First time this block is allocated. Copy over old contents. + // + memcpy_s( pNewMem, static_cast(cbNewSize), m_pBuffer, m_cbBuffer ); + m_fHeapAllocated = true; + } + + m_pBuffer = reinterpret_cast(pNewMem); + m_cbBuffer = static_cast(cbNewSize); + + _ASSERTE( m_pBuffer != NULL ); + + return true; + } + +private: + + bool + IsHeapAllocated( + VOID + ) const + { + return m_fHeapAllocated; + } + + // + // The default inline buffer. + // This member should be at the beginning for alignment purposes. + // + T m_rgBuffer[LENGTH]; + + // + // Is m_pBuffer dynamically allocated? + // + bool m_fHeapAllocated; + + // + // Size of the buffer as requested by client in bytes. + // + DWORD m_cbBuffer; + + // + // Pointer to buffer. + // + __field_bcount_full(m_cbBuffer) + T* m_pBuffer; +}; + +// +// Resizes the buffer by 2 if the ideal size is bigger +// than the buffer length. That give us lg(n) allocations. +// +// Use template inferring like: +// +// BUFFER buff; +// hr = ResizeBufferByTwo(buff, 100); +// +template +HRESULT +ResizeBufferByTwo( + BUFFER_T& Buffer, + SIZE_T cbIdealSize, + bool fZeroMemoryBeyondOldSize = false +) +{ + if (cbIdealSize > Buffer.QuerySize()) + { + if (!Buffer.Resize(max(cbIdealSize, static_cast(Buffer.QuerySize() * 2)), + fZeroMemoryBeyondOldSize)) + { + return E_OUTOFMEMORY; + } + } + return S_OK; +} + + +// +// +// Lots of code uses BUFFER class to store a bunch of different +// structures, so m_rgBuffer needs to be 8 byte aligned when it is used +// as an opaque buffer. +// +#define INLINED_BUFFER_LEN 32 +typedef BUFFER_T BUFFER; + +// +// Assumption of macros below for pointer alignment purposes +// +C_ASSERT( sizeof(VOID*) <= sizeof(ULONGLONG) ); + +// +// Declare a BUFFER that will use stack memory of +// bytes. If the buffer overflows then a heap buffer will be allocated. +// +#define STACK_BUFFER( _name, _size ) \ + ULONGLONG __aqw##_name[ ( ( (_size) + sizeof(ULONGLONG) - 1 ) / sizeof(ULONGLONG) ) ]; \ + BUFFER _name( (BYTE*)__aqw##_name, sizeof(__aqw##_name) ) + +// +// Macros for declaring and initializing a BUFFER that will use inline memory +// of bytes as a member of an object. +// +#define INLINE_BUFFER( _name, _size ) \ + ULONGLONG __aqw##_name[ ( ( (_size) + sizeof(ULONGLONG) - 1 ) / sizeof(ULONGLONG) ) ]; \ + BUFFER _name; + +#define INLINE_BUFFER_INIT( _name ) \ + _name( (BYTE*)__aqw##_name, sizeof( __aqw##_name ) ) diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/datetime.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/datetime.h new file mode 100644 index 0000000000..82ac441abd --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/datetime.h @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#ifndef _DATETIME_H_ +#define _DATETIME_H_ + +BOOL +StringTimeToFileTime( + PCSTR pszTime, + ULONGLONG * pulTime +); + +#endif + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/dbgutil.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/dbgutil.h new file mode 100644 index 0000000000..9a33cca394 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/dbgutil.h @@ -0,0 +1,102 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#ifndef _DBGUTIL_H_ +#define _DBGUTIL_H_ + +#include + +// +// TODO +// Using _CrtDbg implementation. If hooking is desired +// wrappers should be provided here so that we can reimplement +// if neecessary. +// +// IF_DEBUG/DEBUG FLAGS +// +// registry configuration +// + +// +// Debug error levels for DEBUG_FLAGS_VAR. +// + +#define DEBUG_FLAG_INFO 0x00000001 +#define DEBUG_FLAG_WARN 0x00000002 +#define DEBUG_FLAG_ERROR 0x00000004 + +// +// Predefined error level values. These are backwards from the +// windows definitions. +// + +#define DEBUG_FLAGS_INFO (DEBUG_FLAG_ERROR | DEBUG_FLAG_WARN | DEBUG_FLAG_INFO) +#define DEBUG_FLAGS_WARN (DEBUG_FLAG_ERROR | DEBUG_FLAG_WARN) +#define DEBUG_FLAGS_ERROR (DEBUG_FLAG_ERROR) +#define DEBUG_FLAGS_ANY (DEBUG_FLAG_INFO | DEBUG_FLAG_WARN | DEBUG_FLAG_ERROR) + +// +// Global variables to control tracing. Generally per module +// + +#ifndef DEBUG_FLAGS_VAR +#define DEBUG_FLAGS_VAR g_dwDebugFlags +#endif + +#ifndef DEBUG_LABEL_VAR +#define DEBUG_LABEL_VAR g_szDebugLabel +#endif + +extern PCSTR DEBUG_LABEL_VAR; +extern DWORD DEBUG_FLAGS_VAR; + +// +// Module should make this declaration globally. +// + +#define DECLARE_DEBUG_PRINT_OBJECT( _pszLabel_ ) \ + PCSTR DEBUG_LABEL_VAR = _pszLabel_; \ + DWORD DEBUG_FLAGS_VAR = DEBUG_FLAGS_ANY; \ + +#define DECLARE_DEBUG_PRINT_OBJECT2( _pszLabel_, _dwLevel_ ) \ + PCSTR DEBUG_LABEL_VAR = _pszLabel_; \ + DWORD DEBUG_FLAGS_VAR = _dwLevel_; \ + +// +// This doesn't do anything now. Should be safe to call in dll main. +// + +#define CREATE_DEBUG_PRINT_OBJECT + +// +// Trace macros +// + +#define DBG_CONTEXT _CRT_WARN, __FILE__, __LINE__, DEBUG_LABEL_VAR + +#ifdef DEBUG +#define DBGINFO(args) \ + {if( DEBUG_FLAGS_VAR & DEBUG_FLAG_INFO ) { _CrtDbgReport args; }} +#define DBGWARN(args) \ + {if( DEBUG_FLAGS_VAR & DEBUG_FLAG_WARN ) { _CrtDbgReport args; }} +#define DBGERROR(args) \ + {if( DEBUG_FLAGS_VAR & DEBUG_FLAG_ERROR ) { _CrtDbgReport args; }} +#else +#define DBGINFO +#define DBGWARN +#define DBGERROR +#endif + +#define DBGPRINTF DBGINFO + +// +// Simple error traces +// + +#define DBGERROR_HR( _hr_ ) \ + DBGERROR(( DBG_CONTEXT, "hr=0x%x\n", _hr_ )) + +#define DBGERROR_STATUS( _status_ ) \ + DBGERROR(( DBG_CONTEXT, "status=%d\n", _status_ )) + +#endif diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/debugutil.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/debugutil.h new file mode 100644 index 0000000000..39033973ce --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/debugutil.h @@ -0,0 +1,124 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#pragma once + +#define DEBUG_FLAG_INFO 0x00000001 +#define DEBUG_FLAG_WARN 0x00000002 +#define DEBUG_FLAG_ERROR 0x00000004 + +// +// Predefined error level values. These are backwards from the +// windows definitions. +// + +#define DEBUG_FLAGS_INFO (DEBUG_FLAG_ERROR | DEBUG_FLAG_WARN | DEBUG_FLAG_INFO) +#define DEBUG_FLAGS_WARN (DEBUG_FLAG_ERROR | DEBUG_FLAG_WARN) +#define DEBUG_FLAGS_ERROR (DEBUG_FLAG_ERROR) +#define DEBUG_FLAGS_ANY (DEBUG_FLAG_INFO | DEBUG_FLAG_WARN | DEBUG_FLAG_ERROR) + +#define DEBUG_FLAGS_REGISTRY_LOCATION_A "DebugFlags" + +extern DWORD g_dwDebugFlags; + +static +BOOL +IfDebug( + DWORD dwFlag + ) +{ + return ( dwFlag & g_dwDebugFlags ); +} + +static +VOID +DebugPrint( + DWORD dwFlag, + LPCSTR szString + ) +{ + STBUFF strOutput; + HRESULT hr; + + if ( IfDebug( dwFlag ) ) + { + hr = strOutput.Printf( "[dipmodule.dll] %s\r\n", + szString ); + + if ( FAILED( hr ) ) + { + goto Finished; + } + + OutputDebugStringA( strOutput.QueryStr() ); + } + +Finished: + + return; +} + +static +VOID +DebugPrintf( +DWORD dwFlag, +LPCSTR szFormat, +... +) +{ + STBUFF strCooked; + STBUFF strOutput; + va_list args; + HRESULT hr; + + if ( IfDebug( dwFlag ) ) + { + va_start( args, szFormat ); + + hr = strCooked.Vsprintf( (LPSTR)szFormat, args ); + + va_end( args ); + + if ( FAILED( hr ) ) + { + goto Finished; + } + + DebugPrint( dwFlag, strCooked.QueryStr() ); + } + +Finished: + + return; +} + +static void ReadDebugFlagFromRegistryKey(const char* pszRegKey, IN DWORD dwDefault) +{ + HKEY hkey = NULL; + g_dwDebugFlags = dwDefault; + DWORD dwType; + DWORD dwBuffer; + DWORD cbBuffer = sizeof(dwBuffer); + + DWORD dwError = RegOpenKeyExA(HKEY_LOCAL_MACHINE, + pszRegKey, + 0, + KEY_READ, + &hkey); + if ( dwError == NO_ERROR && hkey != NULL) + { + dwError = RegQueryValueExA( hkey, + DEBUG_FLAGS_REGISTRY_LOCATION_A, + NULL, + &dwType, + (LPBYTE)&dwBuffer, + &cbBuffer ); + if( ( dwError == NO_ERROR ) && ( dwType == REG_DWORD ) ) + { + g_dwDebugFlags = dwBuffer; + } + RegCloseKey( hkey); + hkey = NULL; + } +} + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/hashfn.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/hashfn.h new file mode 100644 index 0000000000..a86b0a1358 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/hashfn.h @@ -0,0 +1,325 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#ifndef __HASHFN_H__ +#define __HASHFN_H__ + + +// Produce a scrambled, randomish number in the range 0 to RANDOM_PRIME-1. +// Applying this to the results of the other hash functions is likely to +// produce a much better distribution, especially for the identity hash +// functions such as Hash(char c), where records will tend to cluster at +// the low end of the hashtable otherwise. LKRhash applies this internally +// to all hash signatures for exactly this reason. + +inline DWORD +HashScramble(DWORD dwHash) +{ + // Here are 10 primes slightly greater than 10^9 + // 1000000007, 1000000009, 1000000021, 1000000033, 1000000087, + // 1000000093, 1000000097, 1000000103, 1000000123, 1000000181. + + // default value for "scrambling constant" + const DWORD RANDOM_CONSTANT = 314159269UL; + // large prime number, also used for scrambling + const DWORD RANDOM_PRIME = 1000000007UL; + + return (RANDOM_CONSTANT * dwHash) % RANDOM_PRIME ; +} + + +// Faster scrambling function suggested by Eric Jacobsen + +inline DWORD +HashRandomizeBits(DWORD dw) +{ + return (((dw * 1103515245 + 12345) >> 16) + | ((dw * 69069 + 1) & 0xffff0000)); +} + + +// Small prime number used as a multiplier in the supplied hash functions +const DWORD HASH_MULTIPLIER = 101; + +#undef HASH_SHIFT_MULTIPLY + +#ifdef HASH_SHIFT_MULTIPLY +# define HASH_MULTIPLY(dw) (((dw) << 7) - (dw)) +#else +# define HASH_MULTIPLY(dw) ((dw) * HASH_MULTIPLIER) +#endif + +// Fast, simple hash function that tends to give a good distribution. +// Apply HashScramble to the result if you're using this for something +// other than LKRhash. + +inline DWORD +HashString( + const char* psz, + DWORD dwHash = 0) +{ + // force compiler to use unsigned arithmetic + const unsigned char* upsz = (const unsigned char*) psz; + + for ( ; *upsz; ++upsz) + dwHash = HASH_MULTIPLY(dwHash) + *upsz; + + return dwHash; +} + +inline DWORD +HashString( + __in_ecount(cch) const char* psz, + __in DWORD cch, + __in DWORD dwHash +) +{ + // force compiler to use unsigned arithmetic + const unsigned char* upsz = (const unsigned char*) psz; + + for (DWORD Index = 0; + Index < cch; + ++Index, ++upsz) + { + dwHash = HASH_MULTIPLY(dwHash) + *upsz; + } + + return dwHash; +} + + +// Unicode version of above + +inline DWORD +HashString( + const wchar_t* pwsz, + DWORD dwHash = 0) +{ + for ( ; *pwsz; ++pwsz) + dwHash = HASH_MULTIPLY(dwHash) + *pwsz; + + return dwHash; +} + +// Based on length of the string instead of null-terminating character + +inline DWORD +HashString( + __in_ecount(cch) const wchar_t* pwsz, + __in DWORD cch, + __in DWORD dwHash +) +{ + for (DWORD Index = 0; + Index < cch; + ++Index, ++pwsz) + { + dwHash = HASH_MULTIPLY(dwHash) + *pwsz; + } + + return dwHash; +} + + +// Quick-'n'-dirty case-insensitive string hash function. +// Make sure that you follow up with _stricmp or _mbsicmp. You should +// also cache the length of strings and check those first. Caching +// an uppercase version of a string can help too. +// Again, apply HashScramble to the result if using with something other +// than LKRhash. +// Note: this is not really adequate for MBCS strings. + +inline DWORD +HashStringNoCase( + const char* psz, + DWORD dwHash = 0) +{ + const unsigned char* upsz = (const unsigned char*) psz; + + for ( ; *upsz; ++upsz) + dwHash = HASH_MULTIPLY(dwHash) + + (*upsz & 0xDF); // strip off lowercase bit + + return dwHash; +} + +inline DWORD +HashStringNoCase( + __in_ecount(cch) + const char* psz, + SIZE_T cch, + DWORD dwHash) +{ + const unsigned char* upsz = (const unsigned char*) psz; + + for (SIZE_T Index = 0; + Index < cch; + ++Index, ++upsz) + { + dwHash = HASH_MULTIPLY(dwHash) + + (*upsz & 0xDF); // strip off lowercase bit + } + return dwHash; +} + + +// Unicode version of above + +inline DWORD +HashStringNoCase( + const wchar_t* pwsz, + DWORD dwHash = 0) +{ + for ( ; *pwsz; ++pwsz) + dwHash = HASH_MULTIPLY(dwHash) + (*pwsz & 0xFFDF); + + return dwHash; +} + +// Unicode version of above with length + +inline DWORD +HashStringNoCase( + __in_ecount(cch) + const wchar_t* pwsz, + SIZE_T cch, + DWORD dwHash) +{ + for (SIZE_T Index = 0; + Index < cch; + ++Index, ++pwsz) + { + dwHash = HASH_MULTIPLY(dwHash) + (*pwsz & 0xFFDF); + } + return dwHash; +} + + +// HashBlob returns the hash of a blob of arbitrary binary data. +// +// Warning: HashBlob is generally not the right way to hash a class object. +// Consider: +// class CFoo { +// public: +// char m_ch; +// double m_d; +// char* m_psz; +// }; +// +// inline DWORD Hash(const CFoo& rFoo) +// { return HashBlob(&rFoo, sizeof(CFoo)); } +// +// This is the wrong way to hash a CFoo for two reasons: (a) there will be +// a 7-byte gap between m_ch and m_d imposed by the alignment restrictions +// of doubles, which will be filled with random data (usually non-zero for +// stack variables), and (b) it hashes the address (rather than the +// contents) of the string m_psz. Similarly, +// +// bool operator==(const CFoo& rFoo1, const CFoo& rFoo2) +// { return memcmp(&rFoo1, &rFoo2, sizeof(CFoo)) == 0; } +// +// does the wrong thing. Much better to do this: +// +// DWORD Hash(const CFoo& rFoo) +// { +// return HashString(rFoo.m_psz, +// HASH_MULTIPLIER * Hash(rFoo.m_ch) +// + Hash(rFoo.m_d)); +// } +// +// Again, apply HashScramble if using with something other than LKRhash. + +inline DWORD +HashBlob( + const void* pv, + size_t cb, + DWORD dwHash = 0) +{ + const BYTE * pb = static_cast(pv); + + while (cb-- > 0) + dwHash = HASH_MULTIPLY(dwHash) + *pb++; + + return dwHash; +} + + + +// +// Overloaded hash functions for all the major builtin types. +// Again, apply HashScramble to result if using with something other than +// LKRhash. +// + +inline DWORD Hash(const char* psz) +{ return HashString(psz); } + +inline DWORD Hash(const unsigned char* pusz) +{ return HashString(reinterpret_cast(pusz)); } + +inline DWORD Hash(const signed char* pssz) +{ return HashString(reinterpret_cast(pssz)); } + +inline DWORD Hash(const wchar_t* pwsz) +{ return HashString(pwsz); } + +inline DWORD +Hash( + const GUID* pguid, + DWORD dwHash = 0) +{ + + return * reinterpret_cast(const_cast(pguid)) + dwHash; +} + +// Identity hash functions: scalar values map to themselves +inline DWORD Hash(char c) +{ return c; } + +inline DWORD Hash(unsigned char uc) +{ return uc; } + +inline DWORD Hash(signed char sc) +{ return sc; } + +inline DWORD Hash(short sh) +{ return sh; } + +inline DWORD Hash(unsigned short ush) +{ return ush; } + +inline DWORD Hash(int i) +{ return i; } + +inline DWORD Hash(unsigned int u) +{ return u; } + +inline DWORD Hash(long l) +{ return l; } + +inline DWORD Hash(unsigned long ul) +{ return ul; } + +inline DWORD Hash(float f) +{ + // be careful of rounding errors when computing keys + union { + float f; + DWORD dw; + } u; + u.f = f; + return u.dw; +} + +inline DWORD Hash(double dbl) +{ + // be careful of rounding errors when computing keys + union { + double dbl; + DWORD dw[2]; + } u; + u.dbl = dbl; + return u.dw[0] * HASH_MULTIPLIER + u.dw[1]; +} + +#endif // __HASHFN_H__ diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/hashtable.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/hashtable.h new file mode 100644 index 0000000000..9a299ca1af --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/hashtable.h @@ -0,0 +1,666 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#pragma once + +#include +#include "rwlock.h" +#include "prime.h" + +template +class HASH_NODE +{ + template + friend class HASH_TABLE; + + HASH_NODE( + _Record * pRecord, + DWORD dwHash + ) : _pNext (NULL), + _pRecord (pRecord), + _dwHash (dwHash) + {} + + ~HASH_NODE() + { + _ASSERTE(_pRecord == NULL); + } + + private: + // Next node in the hash table look-aside + HASH_NODE<_Record> *_pNext; + + // actual record + _Record * _pRecord; + + // hash value + DWORD _dwHash; +}; + +template +class HASH_TABLE +{ +protected: + typedef BOOL + (PFN_DELETE_IF)( + _Record * pRecord, + PVOID pvContext + ); + + typedef VOID + (PFN_APPLY)( + _Record * pRecord, + PVOID pvContext + ); + +public: + HASH_TABLE( + VOID + ) + : _ppBuckets( NULL ), + _nBuckets( 0 ), + _nItems( 0 ) + { + } + + virtual + ~HASH_TABLE(); + + virtual + VOID + ReferenceRecord( + _Record * pRecord + ) = 0; + + virtual + VOID + DereferenceRecord( + _Record * pRecord + ) = 0; + + virtual + _Key + ExtractKey( + _Record * pRecord + ) = 0; + + virtual + DWORD + CalcKeyHash( + _Key key + ) = 0; + + virtual + BOOL + EqualKeys( + _Key key1, + _Key key2 + ) = 0; + + DWORD + Count( + VOID + ) const; + + bool + IsInitialized( + VOID + ) const; + + virtual + VOID + Clear(); + + HRESULT + Initialize( + DWORD nBucketSize + ); + + virtual + VOID + FindKey( + _Key key, + _Record ** ppRecord + ); + + virtual + HRESULT + InsertRecord( + _Record * pRecord + ); + + virtual + VOID + DeleteKey( + _Key key + ); + + virtual + VOID + DeleteIf( + PFN_DELETE_IF pfnDeleteIf, + PVOID pvContext + ); + + VOID + Apply( + PFN_APPLY pfnApply, + PVOID pvContext + ); + +private: + + __success(*ppNode != NULL && return != FALSE) + BOOL + FindNodeInternal( + _Key key, + DWORD dwHash, + __deref_out + HASH_NODE<_Record> ** ppNode, + __deref_opt_out + HASH_NODE<_Record> *** pppPreviousNodeNextPointer = NULL + ); + + VOID + DeleteNode( + HASH_NODE<_Record> * pNode + ) + { + if (pNode->_pRecord != NULL) + { + DereferenceRecord(pNode->_pRecord); + pNode->_pRecord = NULL; + } + + delete pNode; + } + + VOID + RehashTableIfNeeded( + VOID + ); + + HASH_NODE<_Record> ** _ppBuckets; + DWORD _nBuckets; + DWORD _nItems; + // + // Allow to use lock object in const methods. + // + mutable + CWSDRWLock _tableLock; +}; + +template +HRESULT +HASH_TABLE<_Record,_Key>::Initialize( + DWORD nBuckets +) +{ + HRESULT hr = S_OK; + + if ( nBuckets == 0 ) + { + hr = E_INVALIDARG; + goto Failed; + } + + if (nBuckets >= MAXDWORD/sizeof(HASH_NODE<_Record> *)) + { + hr = E_INVALIDARG; + goto Failed; + } + + _ASSERTE(_ppBuckets == NULL ); + if ( _ppBuckets != NULL ) + { + hr = E_INVALIDARG; + goto Failed; + } + + hr = _tableLock.Init(); + if ( FAILED( hr ) ) + { + goto Failed; + } + + _ppBuckets = (HASH_NODE<_Record> **)HeapAlloc( + GetProcessHeap(), + HEAP_ZERO_MEMORY, + nBuckets*sizeof(HASH_NODE<_Record> *)); + if (_ppBuckets == NULL) + { + hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); + goto Failed; + } + _nBuckets = nBuckets; + + return S_OK; + +Failed: + + if (_ppBuckets) + { + HeapFree(GetProcessHeap(), + 0, + _ppBuckets); + _ppBuckets = NULL; + } + + return hr; +} + + +template +HASH_TABLE<_Record,_Key>::~HASH_TABLE() +{ + if (_ppBuckets == NULL) + { + return; + } + + _ASSERTE(_nItems == 0); + + HeapFree(GetProcessHeap(), + 0, + _ppBuckets); + _ppBuckets = NULL; + _nBuckets = 0; +} + +template< class _Record, class _Key> +DWORD +HASH_TABLE<_Record,_Key>::Count() const +{ + return _nItems; +} + +template< class _Record, class _Key> +bool +HASH_TABLE<_Record,_Key>::IsInitialized( + VOID +) const +{ + return _ppBuckets != NULL; +} + + +template +VOID +HASH_TABLE<_Record,_Key>::Clear() +{ + HASH_NODE<_Record> *pCurrent; + HASH_NODE<_Record> *pNext; + + // This is here in the off cases where someone instantiates a hashtable + // and then does an automatic "clear" before its destruction WITHOUT + // ever initializing it. + if ( ! _tableLock.QueryInited() ) + { + return; + } + + _tableLock.ExclusiveAcquire(); + + for (DWORD i=0; i<_nBuckets; i++) + { + pCurrent = _ppBuckets[i]; + _ppBuckets[i] = NULL; + while (pCurrent != NULL) + { + pNext = pCurrent->_pNext; + DeleteNode(pCurrent); + pCurrent = pNext; + } + } + + _nItems = 0; + _tableLock.ExclusiveRelease(); +} + +template +__success(*ppNode != NULL && return != FALSE) +BOOL +HASH_TABLE<_Record,_Key>::FindNodeInternal( + _Key key, + DWORD dwHash, + __deref_out + HASH_NODE<_Record> ** ppNode, + __deref_opt_out + HASH_NODE<_Record> *** pppPreviousNodeNextPointer +) +/*++ + Return value indicates whether the item is found + key, dwHash - key and hash for the node to find + ppNode - on successful return, the node found, on failed return, the first + node with hash value greater than the node to be found + pppPreviousNodeNextPointer - the pointer to previous node's _pNext + + This routine may be called under either read or write lock +--*/ +{ + HASH_NODE<_Record> **ppPreviousNodeNextPointer; + HASH_NODE<_Record> *pNode; + BOOL fFound = FALSE; + + ppPreviousNodeNextPointer = _ppBuckets + (dwHash % _nBuckets); + pNode = *ppPreviousNodeNextPointer; + while (pNode != NULL) + { + if (pNode->_dwHash == dwHash) + { + if (EqualKeys(key, + ExtractKey(pNode->_pRecord))) + { + fFound = TRUE; + break; + } + } + else if (pNode->_dwHash > dwHash) + { + break; + } + + ppPreviousNodeNextPointer = &(pNode->_pNext); + pNode = *ppPreviousNodeNextPointer; + } + + __analysis_assume( (pNode == NULL && fFound == FALSE) || + (pNode != NULL && fFound == TRUE ) ); + *ppNode = pNode; + if (pppPreviousNodeNextPointer != NULL) + { + *pppPreviousNodeNextPointer = ppPreviousNodeNextPointer; + } + return fFound; +} + +template +VOID +HASH_TABLE<_Record,_Key>::FindKey( + _Key key, + _Record ** ppRecord +) +{ + HASH_NODE<_Record> *pNode; + + *ppRecord = NULL; + + DWORD dwHash = CalcKeyHash(key); + + _tableLock.SharedAcquire(); + + if (FindNodeInternal(key, dwHash, &pNode) && + pNode->_pRecord != NULL) + { + ReferenceRecord(pNode->_pRecord); + *ppRecord = pNode->_pRecord; + } + + _tableLock.SharedRelease(); +} + +template +HRESULT +HASH_TABLE<_Record,_Key>::InsertRecord( + _Record * pRecord +) +/*++ + This method inserts a node for this record and also empty nodes for paths + in the heirarchy leading upto this path + + The insert is done under only a read-lock - this is possible by keeping + the hashes in a bucket in increasing order and using interlocked operations + to actually insert the item in the hash-bucket lookaside list and the parent + children list + + Returns HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS) if the record already exists. + Never leak this error to the end user because "*file* already exists" may be confusing. +--*/ +{ + BOOL fLocked = FALSE; + _Key key = ExtractKey(pRecord); + DWORD dwHash = CalcKeyHash(key); + HRESULT hr = S_OK; + HASH_NODE<_Record> * pNewNode; + HASH_NODE<_Record> * pNextNode; + HASH_NODE<_Record> ** ppPreviousNodeNextPointer; + + // + // Ownership of pRecord is not transferred to pNewNode yet, so remember + // to either set it to null before deleting pNewNode or add an extra + // reference later - this is to make sure we do not do an extra ref/deref + // which users may view as getting flushed out of the hash-table + // + pNewNode = new HASH_NODE<_Record>(pRecord, dwHash); + if (pNewNode == NULL) + { + hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); + goto Finished; + } + + _tableLock.SharedAcquire(); + fLocked = TRUE; + + do + { + // + // Find the right place to add this node + // + if (FindNodeInternal(key, dwHash, &pNextNode, &ppPreviousNodeNextPointer)) + { + // + // If node already there, return error + // + pNewNode->_pRecord = NULL; + DeleteNode(pNewNode); + + // + // We should never leak this error to the end user + // because "file already exists" may be confusing. + // + hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS); + goto Finished; + } + + // + // If another node got inserted in between, we will have to retry + // + pNewNode->_pNext = pNextNode; + } while (InterlockedCompareExchangePointer((PVOID *)ppPreviousNodeNextPointer, + pNewNode, + pNextNode) != pNextNode); + // pass ownership of pRecord now + if (pRecord != NULL) + { + ReferenceRecord(pRecord); + pRecord = NULL; + } + InterlockedIncrement((LONG *)&_nItems); + +Finished: + + if (fLocked) + { + _tableLock.SharedRelease(); + } + + if (SUCCEEDED(hr)) + { + RehashTableIfNeeded(); + } + + return hr; +} + +template +VOID +HASH_TABLE<_Record,_Key>::DeleteKey( + _Key key +) +{ + HASH_NODE<_Record> *pNode; + HASH_NODE<_Record> **ppPreviousNodeNextPointer; + + DWORD dwHash = CalcKeyHash(key); + + _tableLock.ExclusiveAcquire(); + + if (FindNodeInternal(key, dwHash, &pNode, &ppPreviousNodeNextPointer)) + { + *ppPreviousNodeNextPointer = pNode->_pNext; + DeleteNode(pNode); + _nItems--; + } + + _tableLock.ExclusiveRelease(); +} + +template +VOID +HASH_TABLE<_Record,_Key>::DeleteIf( + PFN_DELETE_IF pfnDeleteIf, + PVOID pvContext +) +{ + HASH_NODE<_Record> *pNode; + HASH_NODE<_Record> **ppPreviousNodeNextPointer; + + _tableLock.ExclusiveAcquire(); + + for (DWORD i=0; i<_nBuckets; i++) + { + ppPreviousNodeNextPointer = _ppBuckets + i; + pNode = *ppPreviousNodeNextPointer; + while (pNode != NULL) + { + // + // Non empty nodes deleted based on DeleteIf, empty nodes deleted + // if they have no children + // + if (pfnDeleteIf(pNode->_pRecord, pvContext)) + { + *ppPreviousNodeNextPointer = pNode->_pNext; + DeleteNode(pNode); + _nItems--; + } + else + { + ppPreviousNodeNextPointer = &pNode->_pNext; + } + + pNode = *ppPreviousNodeNextPointer; + } + } + + _tableLock.ExclusiveRelease(); +} + +template +VOID +HASH_TABLE<_Record,_Key>::Apply( + PFN_APPLY pfnApply, + PVOID pvContext +) +{ + HASH_NODE<_Record> *pNode; + + _tableLock.SharedAcquire(); + + for (DWORD i=0; i<_nBuckets; i++) + { + pNode = _ppBuckets[i]; + while (pNode != NULL) + { + if (pNode->_pRecord != NULL) + { + pfnApply(pNode->_pRecord, pvContext); + } + + pNode = pNode->_pNext; + } + } + + _tableLock.SharedRelease(); +} + +template +VOID +HASH_TABLE<_Record,_Key>::RehashTableIfNeeded( + VOID +) +{ + HASH_NODE<_Record> **ppBuckets; + DWORD nBuckets; + HASH_NODE<_Record> *pNode; + HASH_NODE<_Record> *pNextNode; + HASH_NODE<_Record> **ppNextPointer; + HASH_NODE<_Record> *pNewNextNode; + DWORD nNewBuckets; + + // + // If number of items has become too many, we will double the hash table + // size (we never reduce it however) + // + if (_nItems <= PRIME::GetPrime(2*_nBuckets)) + { + return; + } + + _tableLock.ExclusiveAcquire(); + + nNewBuckets = PRIME::GetPrime(2*_nBuckets); + + if (_nItems <= nNewBuckets) + { + goto Finished; + } + + nBuckets = nNewBuckets; + if (nBuckets >= 0xffffffff/sizeof(HASH_NODE<_Record> *)) + { + goto Finished; + } + ppBuckets = (HASH_NODE<_Record> **)HeapAlloc( + GetProcessHeap(), + HEAP_ZERO_MEMORY, + nBuckets*sizeof(HASH_NODE<_Record> *)); + if (ppBuckets == NULL) + { + goto Finished; + } + + // + // Take out nodes from the old hash table and insert in the new one, make + // sure to keep the hashes in increasing order + // + for (DWORD i=0; i<_nBuckets; i++) + { + pNode = _ppBuckets[i]; + while (pNode != NULL) + { + pNextNode = pNode->_pNext; + + ppNextPointer = ppBuckets + (pNode->_dwHash % nBuckets); + pNewNextNode = *ppNextPointer; + while (pNewNextNode != NULL && + pNewNextNode->_dwHash <= pNode->_dwHash) + { + ppNextPointer = &pNewNextNode->_pNext; + pNewNextNode = pNewNextNode->_pNext; + } + pNode->_pNext = pNewNextNode; + *ppNextPointer = pNode; + + pNode = pNextNode; + } + } + + HeapFree(GetProcessHeap(), 0, _ppBuckets); + _ppBuckets = ppBuckets; + _nBuckets = nBuckets; + ppBuckets = NULL; + +Finished: + + _tableLock.ExclusiveRelease(); +} diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/http_xp.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/http_xp.h new file mode 100644 index 0000000000..400d8ec855 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/http_xp.h @@ -0,0 +1,2797 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#ifndef __HTTP_H__ +#define __HTTP_H__ + +#pragma once + +#if _WIN32_WINNT >= 0x0501 + +// +// HTTPAPI is available on +// +// a) WinXP SP2 and higher +// b) Windows 2003 and higher +// c) Vista and higher. +// + + + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + + +// +// Flags for HttpInitialize() and HttpTerminate(). +// + +// +// HTTP_INITIALIZE_SERVER - Initializes the HTTP API layer and driver for +// applications using server APIs. +// +// HTTP_INITIALIZE_CONFIG - Initializes the HTTP API layer and driver for +// applications using HTTP configuration APIs. +// +// +// Notes - +// +// 1. These flags can be used in combination. +// +// 2. HttpTerminate() must be called for each call to HttpInitialize() made +// with each flag set when invoking HttpInitialize. For example, one +// could make two calls to HttpInitialize() setting HTTP_INITIALIZE_SERVER +// the first time and HTTP_INITIALIZE_CONFIG the second time. One call +// to HttpTerminate() with both flags set suffices to clean up both +// calls to HttpInitialize(). +// + +#define HTTP_INITIALIZE_SERVER 0x00000001 +#define HTTP_INITIALIZE_CONFIG 0x00000002 + +#if _WIN32_WINNT <= 0x0501 +#define BUILD_IIS_FOR_XP 1 +#endif + +#if _WIN32_WINNT >= 0x0600 || BUILD_IIS_FOR_XP + +// +// Following section defines the properties supported by the +// server side HTTP API. +// + +typedef enum _HTTP_SERVER_PROPERTY +{ + // + // Used for enabling server side authentication. + // + + HttpServerAuthenticationProperty, + + // + // Used for enabling logging. + // + + HttpServerLoggingProperty, + + // + // Used for setting QoS properties. + // + + HttpServerQosProperty, + + // + // Used for configuring timeouts. + // + + HttpServerTimeoutsProperty, + + // + // Used for limiting request queue lengths. + // + + HttpServerQueueLengthProperty, + + // + // Used for manipulating the state. + // + + HttpServerStateProperty, + + // + // Used for modifying the verbosity level of 503 type responses + // generated by server side API. + // + + HttpServer503VerbosityProperty, + + // + // Used for manipulating Url Group to Request Queue association. + // + + HttpServerBindingProperty, + + // + // Extended authentication property. + // + + HttpServerExtendedAuthenticationProperty, + + // + // Listening endpoint property. + // + + HttpServerListenEndpointProperty + + // + // Authentication channel binding property + // + +#endif +#if _WIN32_WINNT >= _WIN32_WINNT_WIN7 || BUILD_IIS_FOR_XP + + ,HttpServerChannelBindProperty + + // + // IP Protection level policy for a Url Group. + // + + ,HttpServerProtectionLevelProperty +#endif +#if _WIN32_WINNT >= 0x0600 || BUILD_IIS_FOR_XP + + +} HTTP_SERVER_PROPERTY, *PHTTP_SERVER_PROPERTY; + + +#define HTTP_MAX_SERVER_QUEUE_LENGTH 0x7FFFFFFF +#define HTTP_MIN_SERVER_QUEUE_LENGTH 1 + +// +// Generic property flags. Each structure defining a property info typically +// contain an element of this type. +// + +typedef struct _HTTP_PROPERTY_FLAGS +{ + ULONG Present:1; + +} HTTP_PROPERTY_FLAGS, *PHTTP_PROPERTY_FLAGS; + +// +// Enabled state. +// + +typedef enum _HTTP_ENABLED_STATE +{ + HttpEnabledStateActive, + HttpEnabledStateInactive, + +} HTTP_ENABLED_STATE, *PHTTP_ENABLED_STATE; + + +typedef struct _HTTP_STATE_INFO +{ + HTTP_PROPERTY_FLAGS Flags; + HTTP_ENABLED_STATE State; + +} HTTP_STATE_INFO, *PHTTP_STATE_INFO; + +// +// Defines the verbosity level for a request queue which will be used +// when sending "503 - Service Unavailable" type error responses. Note that +// this setting only affects the error responses generated internally +// by HTTPAPI. +// + +typedef enum _HTTP_503_RESPONSE_VERBOSITY +{ + // + // Instead of sending a 503 response, the connection will be reset. + // This is the default behavior. + // + Http503ResponseVerbosityBasic, + + // + // Will send a 503 w/ a generic reason phrase. + // + Http503ResponseVerbosityLimited, + + // + // Will send a 503 w/ a detailed reason phrase. + // + Http503ResponseVerbosityFull + +} HTTP_503_RESPONSE_VERBOSITY, *PHTTP_503_RESPONSE_VERBOSITY; + +// +// Network QoS related. +// + +typedef enum _HTTP_QOS_SETTING_TYPE +{ + HttpQosSettingTypeBandwidth, + HttpQosSettingTypeConnectionLimit, + HttpQosSettingTypeFlowRate + +} HTTP_QOS_SETTING_TYPE, *PHTTP_QOS_SETTING_TYPE; + +typedef struct _HTTP_QOS_SETTING_INFO +{ + HTTP_QOS_SETTING_TYPE QosType; + PVOID QosSetting; +} HTTP_QOS_SETTING_INFO, *PHTTP_QOS_SETTING_INFO; + +typedef struct _HTTP_CONNECTION_LIMIT_INFO +{ + HTTP_PROPERTY_FLAGS Flags; + ULONG MaxConnections; + +} HTTP_CONNECTION_LIMIT_INFO, *PHTTP_CONNECTION_LIMIT_INFO; + +typedef struct _HTTP_BANDWIDTH_LIMIT_INFO +{ + HTTP_PROPERTY_FLAGS Flags; + ULONG MaxBandwidth; + +} HTTP_BANDWIDTH_LIMIT_INFO, *PHTTP_BANDWIDTH_LIMIT_INFO; + +typedef struct _HTTP_FLOWRATE_INFO +{ + HTTP_PROPERTY_FLAGS Flags; + ULONG MaxBandwidth; + ULONG MaxPeakBandwidth; + ULONG BurstSize; + +} HTTP_FLOWRATE_INFO, *PHTTP_FLOWRATE_INFO; + +// +// Bandwidth throttling limit can not be set lower than the following +// number. The value is in bytes/sec. +// + +#define HTTP_MIN_ALLOWED_BANDWIDTH_THROTTLING_RATE ((ULONG)1024) + +// +// Distinguished value for bandwidth, connection limits and logging rollover +// size indicating "no limit". +// + +#define HTTP_LIMIT_INFINITE ((ULONG)-1) + +// +// Timeout information. +// + +// +// For manipulating global timeout settings. +// These timers run when connection does not belong to any application. +// Value zero is not allowed for driver wide timeout settings. +// + +typedef enum _HTTP_SERVICE_CONFIG_TIMEOUT_KEY +{ + IdleConnectionTimeout = 0, + HeaderWaitTimeout + +} HTTP_SERVICE_CONFIG_TIMEOUT_KEY, *PHTTP_SERVICE_CONFIG_TIMEOUT_KEY; + +typedef USHORT HTTP_SERVICE_CONFIG_TIMEOUT_PARAM, + *PHTTP_SERVICE_CONFIG_TIMEOUT_PARAM; + +// +// To set a timeout value use the set structure. To query/delete use the key +// directly. When you query a timeout value the output buffer must be exactly +// the sizeof param. +// + +typedef struct _HTTP_SERVICE_CONFIG_TIMEOUT_SET +{ + HTTP_SERVICE_CONFIG_TIMEOUT_KEY KeyDesc; + HTTP_SERVICE_CONFIG_TIMEOUT_PARAM ParamDesc; + +} HTTP_SERVICE_CONFIG_TIMEOUT_SET, *PHTTP_SERVICE_CONFIG_TIMEOUT_SET; + +// +// For manipulating application specific timeout settings. +// These timers run when there's a request being processed on a connection +// and HTTPAPI has already associated the request with an application. +// Setting a timeout value to zero will cause HTTPAPI to revert to default. +// + +typedef struct _HTTP_TIMEOUT_LIMIT_INFO +{ + HTTP_PROPERTY_FLAGS Flags; + + // + // Timeouts configured in seconds. + // + + USHORT EntityBody; + USHORT DrainEntityBody; + USHORT RequestQueue; + + // + // Following two timeouts are only enforced after first request on + // connection is routed to the application. These will not manipulate + // the driver wide timeouts. + // + + USHORT IdleConnection; + USHORT HeaderWait; + + // + // Timeouts configured in bytes/second. + // This timer can be turned off by setting it to MAXULONG. + // + + ULONG MinSendRate; + +} HTTP_TIMEOUT_LIMIT_INFO, *PHTTP_TIMEOUT_LIMIT_INFO; + +// +// Controls whether IP-based URLs should listen on the specific IP or wildcard. +// + +typedef struct _HTTP_LISTEN_ENDPOINT_INFO +{ + HTTP_PROPERTY_FLAGS Flags; + + BOOLEAN EnableSharing; + +} HTTP_LISTEN_ENDPOINT_INFO, *PHTTP_LISTEN_ENDPOINT_INFO; + + +typedef struct _HTTP_SERVER_AUTHENTICATION_DIGEST_PARAMS +{ + USHORT DomainNameLength; + PWSTR DomainName; + USHORT RealmLength; + PWSTR Realm; +} HTTP_SERVER_AUTHENTICATION_DIGEST_PARAMS, + *PHTTP_SERVER_AUTHENTICATION_DIGEST_PARAMS; + +typedef struct _HTTP_SERVER_AUTHENTICATION_BASIC_PARAMS +{ + USHORT RealmLength; + PWSTR Realm; +} HTTP_SERVER_AUTHENTICATION_BASIC_PARAMS, + *PHTTP_SERVER_AUTHENTICATION_BASIC_PARAMS; + +// +// Definitions used for setting server side authentication property. +// + +#define HTTP_AUTH_ENABLE_BASIC (0x00000001) +#define HTTP_AUTH_ENABLE_DIGEST (0x00000002) +#define HTTP_AUTH_ENABLE_NTLM (0x00000004) +#define HTTP_AUTH_ENABLE_NEGOTIATE (0x00000008) +#define HTTP_AUTH_ENABLE_KERBEROS (0x00000010) + +#define HTTP_AUTH_ENABLE_ALL \ + (HTTP_AUTH_ENABLE_BASIC |\ + HTTP_AUTH_ENABLE_DIGEST |\ + HTTP_AUTH_ENABLE_NTLM |\ + HTTP_AUTH_ENABLE_NEGOTIATE |\ + HTTP_AUTH_ENABLE_KERBEROS) + + +C_ASSERT(HTTP_AUTH_ENABLE_NEGOTIATE > HTTP_AUTH_ENABLE_NTLM); +C_ASSERT(HTTP_AUTH_ENABLE_NTLM > HTTP_AUTH_ENABLE_DIGEST); +C_ASSERT(HTTP_AUTH_ENABLE_DIGEST > HTTP_AUTH_ENABLE_BASIC); + +#define HTTP_AUTH_EX_FLAG_ENABLE_KERBEROS_CREDENTIAL_CACHING (0x01) +#define HTTP_AUTH_EX_FLAG_CAPTURE_CREDENTIAL (0x02) + +typedef struct _HTTP_SERVER_AUTHENTICATION_INFO +{ + HTTP_PROPERTY_FLAGS Flags; + + ULONG AuthSchemes; + + BOOLEAN ReceiveMutualAuth; + BOOLEAN ReceiveContextHandle; + BOOLEAN DisableNTLMCredentialCaching; + + UCHAR ExFlags; + + HTTP_SERVER_AUTHENTICATION_DIGEST_PARAMS DigestParams; + HTTP_SERVER_AUTHENTICATION_BASIC_PARAMS BasicParams; + +} HTTP_SERVER_AUTHENTICATION_INFO, *PHTTP_SERVER_AUTHENTICATION_INFO; + +#if _WIN32_WINNT >= _WIN32_WINNT_WIN7 || BUILD_IIS_FOR_XP + +// +// Definitions for setting authentication channel binding properties +// + +typedef enum _HTTP_SERVICE_BINDING_TYPE +{ + HttpServiceBindingTypeNone = 0, + HttpServiceBindingTypeW, + HttpServiceBindingTypeA + +} HTTP_SERVICE_BINDING_TYPE; + +typedef struct _HTTP_SERVICE_BINDING_BASE +{ + HTTP_SERVICE_BINDING_TYPE Type; + +} HTTP_SERVICE_BINDING_BASE, *PHTTP_SERVICE_BINDING_BASE; + +typedef struct _HTTP_SERVICE_BINDING_A +{ + HTTP_SERVICE_BINDING_BASE Base; + PCHAR Buffer; + ULONG BufferSize; + +} HTTP_SERVICE_BINDING_A, *PHTTP_SERVICE_BINDING_A; + +typedef struct _HTTP_SERVICE_BINDING_W +{ + HTTP_SERVICE_BINDING_BASE Base; + PWCHAR Buffer; + ULONG BufferSize; + +} HTTP_SERVICE_BINDING_W, *PHTTP_SERVICE_BINDING_W; + +typedef enum _HTTP_AUTHENTICATION_HARDENING_LEVELS +{ + HttpAuthenticationHardeningLegacy = 0, + HttpAuthenticationHardeningMedium, + HttpAuthenticationHardeningStrict + +} HTTP_AUTHENTICATION_HARDENING_LEVELS; + +// +// Channel binding token verification flags. +// + +#define HTTP_CHANNEL_BIND_PROXY 0x1 +#define HTTP_CHANNEL_BIND_PROXY_COHOSTING 0x20 + +// +// Service bind verification flags +// + +#define HTTP_CHANNEL_BIND_NO_SERVICE_NAME_CHECK 0x2 +#define HTTP_CHANNEL_BIND_DOTLESS_SERVICE 0x4 + +// +// Flags triggering channel bind parameters retrieval +// + +#define HTTP_CHANNEL_BIND_SECURE_CHANNEL_TOKEN 0x8 +#define HTTP_CHANNEL_BIND_CLIENT_SERVICE 0x10 + +// +// All valid flags (mask for internal checks) +// + +typedef struct _HTTP_CHANNEL_BIND_INFO +{ + HTTP_AUTHENTICATION_HARDENING_LEVELS Hardening; + ULONG Flags; + PHTTP_SERVICE_BINDING_BASE * ServiceNames; + ULONG NumberOfServiceNames; + +} HTTP_CHANNEL_BIND_INFO, *PHTTP_CHANNEL_BIND_INFO; + +typedef struct _HTTP_REQUEST_CHANNEL_BIND_STATUS +{ + PHTTP_SERVICE_BINDING_BASE ServiceName; + PUCHAR ChannelToken; + ULONG ChannelTokenSize; + ULONG Flags; + +} HTTP_REQUEST_CHANNEL_BIND_STATUS, *PHTTP_REQUEST_CHANNEL_BIND_STATUS; + +#endif + +// +// Definitions used for setting logging property. +// + +// +// The known log fields recognized/supported by HTTPAPI. Following fields +// are used for W3C logging. Subset of them are also used for error +// logging. +// + +#define HTTP_LOG_FIELD_DATE 0x00000001 +#define HTTP_LOG_FIELD_TIME 0x00000002 +#define HTTP_LOG_FIELD_CLIENT_IP 0x00000004 +#define HTTP_LOG_FIELD_USER_NAME 0x00000008 +#define HTTP_LOG_FIELD_SITE_NAME 0x00000010 +#define HTTP_LOG_FIELD_COMPUTER_NAME 0x00000020 +#define HTTP_LOG_FIELD_SERVER_IP 0x00000040 +#define HTTP_LOG_FIELD_METHOD 0x00000080 +#define HTTP_LOG_FIELD_URI_STEM 0x00000100 +#define HTTP_LOG_FIELD_URI_QUERY 0x00000200 +#define HTTP_LOG_FIELD_STATUS 0x00000400 +#define HTTP_LOG_FIELD_WIN32_STATUS 0x00000800 +#define HTTP_LOG_FIELD_BYTES_SENT 0x00001000 +#define HTTP_LOG_FIELD_BYTES_RECV 0x00002000 +#define HTTP_LOG_FIELD_TIME_TAKEN 0x00004000 +#define HTTP_LOG_FIELD_SERVER_PORT 0x00008000 +#define HTTP_LOG_FIELD_USER_AGENT 0x00010000 +#define HTTP_LOG_FIELD_COOKIE 0x00020000 +#define HTTP_LOG_FIELD_REFERER 0x00040000 +#define HTTP_LOG_FIELD_VERSION 0x00080000 +#define HTTP_LOG_FIELD_HOST 0x00100000 +#define HTTP_LOG_FIELD_SUB_STATUS 0x00200000 + +// +// Fields that are used only for error logging. +// + +#define HTTP_LOG_FIELD_CLIENT_PORT 0x00400000 +#define HTTP_LOG_FIELD_URI 0x00800000 +#define HTTP_LOG_FIELD_SITE_ID 0x01000000 +#define HTTP_LOG_FIELD_REASON 0x02000000 +#define HTTP_LOG_FIELD_QUEUE_NAME 0x04000000 + +// +// Defines the logging type. +// + +typedef enum _HTTP_LOGGING_TYPE +{ + HttpLoggingTypeW3C, + HttpLoggingTypeIIS, + HttpLoggingTypeNCSA, + HttpLoggingTypeRaw + ,HttpLoggingTypeMaximum + +} HTTP_LOGGING_TYPE, *PHTTP_LOGGING_TYPE; + +// +// Defines the rollover type for log files. +// + +typedef enum _HTTP_LOGGING_ROLLOVER_TYPE +{ + HttpLoggingRolloverSize, + HttpLoggingRolloverDaily, + HttpLoggingRolloverWeekly, + HttpLoggingRolloverMonthly, + HttpLoggingRolloverHourly + +} HTTP_LOGGING_ROLLOVER_TYPE, *PHTTP_LOGGING_ROLLOVER_TYPE; + +// +// Log file rollover size can not be set lower than the following +// limit. The value is in bytes. +// + +#define HTTP_MIN_ALLOWED_LOG_FILE_ROLLOVER_SIZE ((ULONG)(1 * 1024 * 1024)) + +// +// Logging option flags. When used in the logging configuration alters +// some default logging behaviour. +// +// HTTP_LOGGING_FLAG_LOCAL_TIME_ROLLOVER - This flag is used to change +// the log file rollover to happen by local time based. By default +// log file rollovers happen by GMT time. +// +// HTTP_LOGGING_FLAG_USE_UTF8_CONVERSION - When set the unicode fields +// will be converted to UTF8 multibytes when writting to the log +// files. When this flag is not present, the local code page +// conversion happens. +// +// HTTP_LOGGING_FLAG_LOG_ERRORS_ONLY - +// HTTP_LOGGING_FLAG_LOG_SUCCESS_ONLY - These two flags are used to +// to do selective logging. If neither of them are present both +// types of requests will be logged. Only one these flags can be +// set at a time. They are mutually exclusive. +// + +#define HTTP_LOGGING_FLAG_LOCAL_TIME_ROLLOVER (0x00000001) +#define HTTP_LOGGING_FLAG_USE_UTF8_CONVERSION (0x00000002) +#define HTTP_LOGGING_FLAG_LOG_ERRORS_ONLY (0x00000004) +#define HTTP_LOGGING_FLAG_LOG_SUCCESS_ONLY (0x00000008) + +// +// Configuration structure used for setting the logging property. +// + +typedef struct _HTTP_LOGGING_INFO +{ + // + // Specifies whether this property exists or not. + // + + HTTP_PROPERTY_FLAGS Flags; + + // + // Optional logging flags. + // + + ULONG LoggingFlags; + + // + // Optional informatonal software directive string for W3C type logging. Not + // used for other types of logging. If nothing is provided here HTTPAPI will + // log a default string. Any arbitrary string could be used here to identify + // the application. Length cannot be greater than MAX_PATH. Lenght is in + // bytes. + // + + PCWSTR SoftwareName; + USHORT SoftwareNameLength; + + // + // Log file directory must be a fully qualified path. + // Length must be in number of bytes. + // + + USHORT DirectoryNameLength; + PCWSTR DirectoryName; + + // + // Specifies the format for the log files. + // + + HTTP_LOGGING_TYPE Format; + + // + // Bitmask value indicates which fields to be logged + // if the log format is set to W3C. This must be the 'bitwise or' + // of the HTTP_LOG_FIELD_... values. + // + + ULONG Fields; + + // + // Following fields are reserved they must be NULL and zero.. + // + + PVOID pExtFields; + USHORT NumOfExtFields; + + // + // Reserved must be zero. + // + + USHORT MaxRecordSize; + + // + // Defines the rollover type for the log files. + // + + HTTP_LOGGING_ROLLOVER_TYPE RolloverType; + + // + // Indicates the maximum size (in bytes) after which + // the log files should be rolled over. A value of -1 + // (HTTP_LIMIT_INFINITE) indicates an unlimited size. + // This value is discarded if rollover type is not set to + // HttpLoggingRolloverSize. + // + + ULONG RolloverSize; + + // + // Specifies the security descriptor to be applied to + // the log files and the sub-directories. If null we will + // inherit the system default. This security descriptor must + // be self-relative. + // + + PSECURITY_DESCRIPTOR pSecurityDescriptor; + +} HTTP_LOGGING_INFO, *PHTTP_LOGGING_INFO; + +// +// Binding information. +// + +typedef struct _HTTP_BINDING_INFO +{ + HTTP_PROPERTY_FLAGS Flags; + HANDLE RequestQueueHandle; + +} HTTP_BINDING_INFO, *PHTTP_BINDING_INFO; + +#endif +#if _WIN32_WINNT >= _WIN32_WINNT_WIN7 || BUILD_IIS_FOR_XP + +// +// Defines the protection level types for UrlGroups. +// + +typedef enum _HTTP_PROTECTION_LEVEL_TYPE +{ + // + // This option will allow edge (NAT) traversed traffic, i.e. Teredo + // for the UrlGroup, unless there is an admin rule that overwrites the + // application's intend. + // + + HttpProtectionLevelUnrestricted, + + // + // This setting will ensure that edge (NAT) traversed traffic + // will not be allowed. + // + + HttpProtectionLevelEdgeRestricted, + + // + // Below type is not supported by HTTP API. + // + + HttpProtectionLevelRestricted + + +} HTTP_PROTECTION_LEVEL_TYPE, *PHTTP_PROTECTION_LEVEL_TYPE; + +// +// Controls whether the associated UrlGroup Namespace should receive +// edge traversed traffic. By default this parameter is unspecified. +// + +typedef struct _HTTP_PROTECTION_LEVEL_INFO +{ + HTTP_PROPERTY_FLAGS Flags; + HTTP_PROTECTION_LEVEL_TYPE Level; + +} HTTP_PROTECTION_LEVEL_INFO, *PHTTP_PROTECTION_LEVEL_INFO; + +#endif +#if _WIN32_WINNT >= 0x0600 || BUILD_IIS_FOR_XP + + +// +// Definitions for request queue manipulation. +// +// These flags are used with HttpCreateRequestQueue() API. +// +// HTTP_CREATE_REQUEST_QUEUE_FLAG_OPEN_EXISTING - To open an existing request +// queue. The request queue name must be supplied. +// +// HTTP_CREATE_REQUEST_QUEUE_FLAG_CONTROLLER - Creates the request queue and +// marks that the caller process is not willing to do send/receive (HTTP I/O)on +// the handle directly. +// + +#define HTTP_CREATE_REQUEST_QUEUE_FLAG_OPEN_EXISTING (0x00000001) +#define HTTP_CREATE_REQUEST_QUEUE_FLAG_CONTROLLER (0x00000002) + +#endif // _WIN32_WINNT >= 0x0600 + +// +// Flags for HttpReceiveHttpRequest(). +// +// HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY - Specifies that the caller would like +// any available entity body to be copied along with the protocol headers. +// +// HTTP_RECEIVE_REQUEST_FLAG_FLUSH_BODY - Specifies that the caller would like +// all of the entity bodies to be copied along with the protocol headers. +// + +#define HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY 0x00000001 +#define HTTP_RECEIVE_REQUEST_FLAG_FLUSH_BODY 0x00000002 + + +#if _WIN32_WINNT >= 0x0600 || BUILD_IIS_FOR_XP + +// +// Flags for HttpReceiveRequestEntityBody(). +// +// HTTP_RECEIVE_REQUEST_ENTITY_BODY_FLAG_FILL_BUFFER - Specifies that the +// caller would like the buffer to get filled up with entity bodies unless +// there are no more entity bodies to be copied. +// + +#define HTTP_RECEIVE_REQUEST_ENTITY_BODY_FLAG_FILL_BUFFER 0x00000001 + +#endif // _WIN32_WINNT >= 0x0600 + + +// +// Flags for HttpSendHttpResponse() and HttpSendResponseEntityBody(). +// +// HTTP_SEND_RESPONSE_FLAG_DISCONNECT - Specifies that the network connection +// should be disconnected immediately after sending the response, overriding +// the HTTP protocol's persistent connection features, such as +// "Connection: keep-alive". +// +// HTTP_SEND_RESPONSE_FLAG_MORE_DATA - Specifies that additional entity body +// data will be sent by the caller. +// +// HTTP_SEND_RESPONSE_FLAG_BUFFER_DATA - Specifies that a caller wants the +// response to complete as soon as possible at the cost of buffering partial +// or the entire response. +// +// HTTP_SEND_RESPONSE_FLAG_ENABLE_NAGLING - Specifies that a caller wants to +// enable the TCP nagling algorithm for this particular send. +// +// HTTP_SEND_RESPONSE_FLAG_PROCESS_RANGES - Specifies that for a range request +// a full response content is passed and a caller wants HTTP API to process +// ranges properly. +// + +#define HTTP_SEND_RESPONSE_FLAG_DISCONNECT 0x00000001 +#define HTTP_SEND_RESPONSE_FLAG_MORE_DATA 0x00000002 +#define HTTP_SEND_RESPONSE_FLAG_BUFFER_DATA 0x00000004 +#define HTTP_SEND_RESPONSE_FLAG_ENABLE_NAGLING 0x00000008 +#define HTTP_SEND_RESPONSE_FLAG_PROCESS_RANGES 0x00000020 + + +// +// Flags for HttpFlushResponseCache(). +// +// HTTP_FLUSH_RESPONSE_FLAG_RECURSIVE - Flushes the specified URL and all +// hierarchally-related sub-URLs from the response or fragment cache. +// + +#define HTTP_FLUSH_RESPONSE_FLAG_RECURSIVE 0x00000001 + + +// +// Opaque identifiers for various HTTPAPI objects. +// + +typedef ULONGLONG HTTP_OPAQUE_ID, *PHTTP_OPAQUE_ID; + +typedef HTTP_OPAQUE_ID HTTP_REQUEST_ID, *PHTTP_REQUEST_ID; +typedef HTTP_OPAQUE_ID HTTP_CONNECTION_ID, *PHTTP_CONNECTION_ID; +typedef HTTP_OPAQUE_ID HTTP_RAW_CONNECTION_ID, *PHTTP_RAW_CONNECTION_ID; + +#if _WIN32_WINNT >= 0x0600 || BUILD_IIS_FOR_XP + +typedef HTTP_OPAQUE_ID HTTP_URL_GROUP_ID, *PHTTP_URL_GROUP_ID; +typedef HTTP_OPAQUE_ID HTTP_SERVER_SESSION_ID, *PHTTP_SERVER_SESSION_ID; + +#endif // _WIN32_WINNT >= 0x0600 + +// +// Macros for opaque identifier manipulations. +// + +#define HTTP_NULL_ID (0ui64) +#define HTTP_IS_NULL_ID(pid) (HTTP_NULL_ID == *(pid)) +#define HTTP_SET_NULL_ID(pid) (*(pid) = HTTP_NULL_ID) + +// +// This structure defines a file byte range. +// +// If the Length field is HTTP_BYTE_RANGE_TO_EOF then the remainder of the +// file (everything after StartingOffset) is sent. +// + +#define HTTP_BYTE_RANGE_TO_EOF ((ULONGLONG)-1) + +typedef struct _HTTP_BYTE_RANGE +{ + ULARGE_INTEGER StartingOffset; + ULARGE_INTEGER Length; + +} HTTP_BYTE_RANGE, *PHTTP_BYTE_RANGE; + +// +// The type for HTTP protocol version numbers. +// + +typedef struct _HTTP_VERSION +{ + USHORT MajorVersion; + USHORT MinorVersion; + +} HTTP_VERSION, *PHTTP_VERSION; + +// +// Some useful macros for HTTP protocol version manipulation. +// + +#define HTTP_VERSION_UNKNOWN { 0, 0 } +#define HTTP_VERSION_0_9 { 0, 9 } +#define HTTP_VERSION_1_0 { 1, 0 } +#define HTTP_VERSION_1_1 { 1, 1 } + +#define HTTP_SET_VERSION(version, major, minor) \ +do { \ + (version).MajorVersion = (major); \ + (version).MinorVersion = (minor); \ +} while (0, 0) + +#define HTTP_EQUAL_VERSION(version, major, minor) \ + ((version).MajorVersion == (major) && \ + (version).MinorVersion == (minor)) + +#define HTTP_GREATER_VERSION(version, major, minor) \ + ((version).MajorVersion > (major) || \ + ((version).MajorVersion == (major) && \ + (version).MinorVersion > (minor))) + +#define HTTP_LESS_VERSION(version, major, minor) \ + ((version).MajorVersion < (major) || \ + ((version).MajorVersion == (major) && \ + (version).MinorVersion < (minor))) + +#define HTTP_NOT_EQUAL_VERSION(version, major, minor) \ + (!HTTP_EQUAL_VERSION(version, major, minor)) + +#define HTTP_GREATER_EQUAL_VERSION(version, major, minor) \ + (!HTTP_LESS_VERSION(version, major, minor)) + +#define HTTP_LESS_EQUAL_VERSION(version, major, minor) \ + (!HTTP_GREATER_VERSION(version, major, minor)) + +// +// The enum type for HTTP verbs. +// + +typedef enum _HTTP_VERB +{ + HttpVerbUnparsed, + HttpVerbUnknown, + HttpVerbInvalid, + HttpVerbOPTIONS, + HttpVerbGET, + HttpVerbHEAD, + HttpVerbPOST, + HttpVerbPUT, + HttpVerbDELETE, + HttpVerbTRACE, + HttpVerbCONNECT, + HttpVerbTRACK, // used by Microsoft Cluster Server for a non-logged trace + HttpVerbMOVE, + HttpVerbCOPY, + HttpVerbPROPFIND, + HttpVerbPROPPATCH, + HttpVerbMKCOL, + HttpVerbLOCK, + HttpVerbUNLOCK, + HttpVerbSEARCH, + + HttpVerbMaximum + +} HTTP_VERB, *PHTTP_VERB; + +// +// Symbols for all HTTP/1.1 headers and other tokens. Notice request + +// response values overlap. Make sure you know which type of header array +// you are indexing. +// +// These values are used as offsets into arrays and as token values in +// HTTP_KNOWN_HEADER arrays in HTTP_REQUEST_HEADERS and HTTP_RESPONSE_HEADERS. +// +// See RFC 2616, HTTP/1.1, for further explanation of most of these headers. +// + +typedef enum _HTTP_HEADER_ID +{ + HttpHeaderCacheControl = 0, // general-header [section 4.5] + HttpHeaderConnection = 1, // general-header [section 4.5] + HttpHeaderDate = 2, // general-header [section 4.5] + HttpHeaderKeepAlive = 3, // general-header [not in rfc] + HttpHeaderPragma = 4, // general-header [section 4.5] + HttpHeaderTrailer = 5, // general-header [section 4.5] + HttpHeaderTransferEncoding = 6, // general-header [section 4.5] + HttpHeaderUpgrade = 7, // general-header [section 4.5] + HttpHeaderVia = 8, // general-header [section 4.5] + HttpHeaderWarning = 9, // general-header [section 4.5] + + HttpHeaderAllow = 10, // entity-header [section 7.1] + HttpHeaderContentLength = 11, // entity-header [section 7.1] + HttpHeaderContentType = 12, // entity-header [section 7.1] + HttpHeaderContentEncoding = 13, // entity-header [section 7.1] + HttpHeaderContentLanguage = 14, // entity-header [section 7.1] + HttpHeaderContentLocation = 15, // entity-header [section 7.1] + HttpHeaderContentMd5 = 16, // entity-header [section 7.1] + HttpHeaderContentRange = 17, // entity-header [section 7.1] + HttpHeaderExpires = 18, // entity-header [section 7.1] + HttpHeaderLastModified = 19, // entity-header [section 7.1] + + + // Request Headers + + HttpHeaderAccept = 20, // request-header [section 5.3] + HttpHeaderAcceptCharset = 21, // request-header [section 5.3] + HttpHeaderAcceptEncoding = 22, // request-header [section 5.3] + HttpHeaderAcceptLanguage = 23, // request-header [section 5.3] + HttpHeaderAuthorization = 24, // request-header [section 5.3] + HttpHeaderCookie = 25, // request-header [not in rfc] + HttpHeaderExpect = 26, // request-header [section 5.3] + HttpHeaderFrom = 27, // request-header [section 5.3] + HttpHeaderHost = 28, // request-header [section 5.3] + HttpHeaderIfMatch = 29, // request-header [section 5.3] + + HttpHeaderIfModifiedSince = 30, // request-header [section 5.3] + HttpHeaderIfNoneMatch = 31, // request-header [section 5.3] + HttpHeaderIfRange = 32, // request-header [section 5.3] + HttpHeaderIfUnmodifiedSince = 33, // request-header [section 5.3] + HttpHeaderMaxForwards = 34, // request-header [section 5.3] + HttpHeaderProxyAuthorization = 35, // request-header [section 5.3] + HttpHeaderReferer = 36, // request-header [section 5.3] + HttpHeaderRange = 37, // request-header [section 5.3] + HttpHeaderTe = 38, // request-header [section 5.3] + HttpHeaderTranslate = 39, // request-header [webDAV, not in rfc 2518] + + HttpHeaderUserAgent = 40, // request-header [section 5.3] + + HttpHeaderRequestMaximum = 41, + + + // Response Headers + + HttpHeaderAcceptRanges = 20, // response-header [section 6.2] + HttpHeaderAge = 21, // response-header [section 6.2] + HttpHeaderEtag = 22, // response-header [section 6.2] + HttpHeaderLocation = 23, // response-header [section 6.2] + HttpHeaderProxyAuthenticate = 24, // response-header [section 6.2] + HttpHeaderRetryAfter = 25, // response-header [section 6.2] + HttpHeaderServer = 26, // response-header [section 6.2] + HttpHeaderSetCookie = 27, // response-header [not in rfc] + HttpHeaderVary = 28, // response-header [section 6.2] + HttpHeaderWwwAuthenticate = 29, // response-header [section 6.2] + + HttpHeaderResponseMaximum = 30, + + + HttpHeaderMaximum = 41 + +} HTTP_HEADER_ID, *PHTTP_HEADER_ID; + + +// +// Structure defining format of a known HTTP header. +// Name is from HTTP_HEADER_ID. +// + +typedef struct _HTTP_KNOWN_HEADER +{ + USHORT RawValueLength; // in bytes not including the NUL + PCSTR pRawValue; + +} HTTP_KNOWN_HEADER, *PHTTP_KNOWN_HEADER; + +// +// Structure defining format of an unknown header. +// + +typedef struct _HTTP_UNKNOWN_HEADER +{ + USHORT NameLength; // in bytes not including the NUL + USHORT RawValueLength; // in bytes not including the NUL + PCSTR pName; // The header name (minus the ':' character) + PCSTR pRawValue; // The header value + +} HTTP_UNKNOWN_HEADER, *PHTTP_UNKNOWN_HEADER; + +#if _WIN32_WINNT >= 0x0600 || BUILD_IIS_FOR_XP + +// +// Log fields data structure is used for logging a request. This structure must +// be provided along with an HttpSendHttpResponse or HttpSendResponseEntityBody +// call that concludes the send. +// + +// Base structure is for future versioning. + +typedef enum _HTTP_LOG_DATA_TYPE +{ + HttpLogDataTypeFields = 0 + +} HTTP_LOG_DATA_TYPE, *PHTTP_LOG_DATA_TYPE; + +// should we DECLSPEC_ALIGN(4 or 8) == DECLSPEC_POINTERALIGN? +typedef struct _HTTP_LOG_DATA +{ + HTTP_LOG_DATA_TYPE Type; + +} HTTP_LOG_DATA, *PHTTP_LOG_DATA; + +// Current log fields data structure for of type HttpLogDataTypeFields. + +typedef struct _HTTP_LOG_FIELDS_DATA +{ + HTTP_LOG_DATA Base; + + USHORT UserNameLength; + USHORT UriStemLength; + USHORT ClientIpLength; + USHORT ServerNameLength; + USHORT ServiceNameLength; + USHORT ServerIpLength; + USHORT MethodLength; + USHORT UriQueryLength; + USHORT HostLength; + USHORT UserAgentLength; + USHORT CookieLength; + USHORT ReferrerLength; + + PWCHAR UserName; + PWCHAR UriStem; + PCHAR ClientIp; + PCHAR ServerName; + PCHAR ServiceName; + PCHAR ServerIp; + PCHAR Method; + PCHAR UriQuery; + PCHAR Host; + PCHAR UserAgent; + PCHAR Cookie; + PCHAR Referrer; + + USHORT ServerPort; + USHORT ProtocolStatus; + + ULONG Win32Status; + + HTTP_VERB MethodNum; + + USHORT SubStatus; + +} HTTP_LOG_FIELDS_DATA, *PHTTP_LOG_FIELDS_DATA; + +#endif // _WIN32_WINNT >= 0x0600 + +// +// This enum defines a data source for a particular chunk of data. +// + +typedef enum _HTTP_DATA_CHUNK_TYPE +{ + HttpDataChunkFromMemory, + HttpDataChunkFromFileHandle, + HttpDataChunkFromFragmentCache, + HttpDataChunkFromFragmentCacheEx, + + HttpDataChunkMaximum + +} HTTP_DATA_CHUNK_TYPE, *PHTTP_DATA_CHUNK_TYPE; + + +// +// This structure describes an individual data chunk. +// + +typedef struct _HTTP_DATA_CHUNK +{ + // + // The type of this data chunk. + // + + HTTP_DATA_CHUNK_TYPE DataChunkType; + + // + // The data chunk structures, one per supported data chunk type. + // + + union + { + // + // From-memory data chunk. + // + + struct + { + PVOID pBuffer; + ULONG BufferLength; + + } FromMemory; + + // + // From-file handle data chunk. + // + + struct + { + HTTP_BYTE_RANGE ByteRange; + HANDLE FileHandle; + + } FromFileHandle; + + // + // From-fragment cache data chunk. + // + + struct + { + USHORT FragmentNameLength; // in bytes not including the NUL + PCWSTR pFragmentName; + + } FromFragmentCache; + + // + // From-fragment cache data chunk that specifies a byte range. + // + + struct + { + HTTP_BYTE_RANGE ByteRange; + PCWSTR pFragmentName; // NULL-terminated string + + } FromFragmentCacheEx; + + }; + +} HTTP_DATA_CHUNK, *PHTTP_DATA_CHUNK; + +// +// HTTP API doesn't support 16 bit applications. +// Neither WIN32 nor _WIN64 was defined. +// + +C_ASSERT(TYPE_ALIGNMENT(HTTP_DATA_CHUNK) == sizeof(ULONGLONG)); + +// +// Structure defining format of request headers. +// + +typedef struct _HTTP_REQUEST_HEADERS +{ + // + // The array of unknown HTTP headers and the number of + // entries in the array. + // + + USHORT UnknownHeaderCount; + PHTTP_UNKNOWN_HEADER pUnknownHeaders; + + // + // Trailers - we don't use these currently, reserved for a future release + // + USHORT TrailerCount; // Reserved, must be 0 + PHTTP_UNKNOWN_HEADER pTrailers; // Reserved, must be NULL + + + // + // Known headers. + // + + HTTP_KNOWN_HEADER KnownHeaders[HttpHeaderRequestMaximum]; + +} HTTP_REQUEST_HEADERS, *PHTTP_REQUEST_HEADERS; + +// +// Structure defining format of response headers. +// + +typedef struct _HTTP_RESPONSE_HEADERS +{ + // + // The array of unknown HTTP headers and the number of + // entries in the array. + // + + USHORT UnknownHeaderCount; + PHTTP_UNKNOWN_HEADER pUnknownHeaders; + + // + // Trailers - we don't use these currently, reserved for a future release + // + USHORT TrailerCount; // Reserved, must be 0 + PHTTP_UNKNOWN_HEADER pTrailers; // Reserved, must be NULL + + // + // Known headers. + // + + HTTP_KNOWN_HEADER KnownHeaders[HttpHeaderResponseMaximum]; + +} HTTP_RESPONSE_HEADERS, *PHTTP_RESPONSE_HEADERS; + +// +// Structure defining format of transport address. Use pLocalAddress->sa_family +// to determine whether this is an IPv4 address (AF_INET) or IPv6 (AF_INET6). +// +// pRemoteAddress->sa_family will be the same as pLocalAddress->sa_family. +// +// SOCKADDRs are always in network order, not host order. +// + +typedef struct _HTTP_TRANSPORT_ADDRESS +{ + PSOCKADDR pRemoteAddress; + PSOCKADDR pLocalAddress; + +} HTTP_TRANSPORT_ADDRESS, *PHTTP_TRANSPORT_ADDRESS; + +// +// Structure defining format of cooked URL. +// + +typedef struct _HTTP_COOKED_URL +{ + // + // Pointers overlap and point into pFullUrl. NULL if not present. + // + + USHORT FullUrlLength; // in bytes not including the NUL + USHORT HostLength; // in bytes (no NUL) + USHORT AbsPathLength; // in bytes (no NUL) + USHORT QueryStringLength; // in bytes (no NUL) + + PCWSTR pFullUrl; // points to "http://hostname:port/abs/.../path?query" + PCWSTR pHost; // points to the first char in the hostname + PCWSTR pAbsPath; // Points to the 3rd '/' char + PCWSTR pQueryString; // Points to the 1st '?' char or NULL + +} HTTP_COOKED_URL, *PHTTP_COOKED_URL; + +// +// An opaque context for URL manipulation. +// + +typedef ULONGLONG HTTP_URL_CONTEXT; + + +#if _WIN32_WINNT >= 0x0600 || BUILD_IIS_FOR_XP + +// +// Optional flags for URL manipulation functions. +// +// HTTP_URL_FLAG_REMOVE_ALL : When this flag is used +// when removing a Url from a url group, regardless of +// the passed URL, all of the Urls from the url group +// will be removed. +// + +#define HTTP_URL_FLAG_REMOVE_ALL 0x00000001 + + +// +// Request Authentication related. +// + +typedef enum _HTTP_AUTH_STATUS +{ + HttpAuthStatusSuccess, + HttpAuthStatusNotAuthenticated, + HttpAuthStatusFailure + +} HTTP_AUTH_STATUS, *PHTTP_AUTH_STATUS; + + +typedef enum _HTTP_REQUEST_AUTH_TYPE +{ + HttpRequestAuthTypeNone = 0, + HttpRequestAuthTypeBasic, + HttpRequestAuthTypeDigest, + HttpRequestAuthTypeNTLM, + HttpRequestAuthTypeNegotiate, + HttpRequestAuthTypeKerberos + + +} HTTP_REQUEST_AUTH_TYPE, *PHTTP_REQUEST_AUTH_TYPE; + +#endif // _WIN32_WINNT >= 0x0600 + +// +// SSL Client certificate information. +// + +typedef struct _HTTP_SSL_CLIENT_CERT_INFO +{ + ULONG CertFlags; + ULONG CertEncodedSize; + PUCHAR pCertEncoded; + HANDLE Token; + BOOLEAN CertDeniedByMapper; + +} HTTP_SSL_CLIENT_CERT_INFO, *PHTTP_SSL_CLIENT_CERT_INFO; + +#if _WIN32_WINNT >= _WIN32_WINNT_WIN7 || BUILD_IIS_FOR_XP + +// +// Flag to retrieve secure channel binding with HttpReceiveClientCertificate +// + +#define HTTP_RECEIVE_SECURE_CHANNEL_TOKEN 0x1 + +#endif + +// +// Data computed during SSL handshake. +// + +typedef struct _HTTP_SSL_INFO +{ + USHORT ServerCertKeySize; + USHORT ConnectionKeySize; + ULONG ServerCertIssuerSize; + ULONG ServerCertSubjectSize; + + PCSTR pServerCertIssuer; + PCSTR pServerCertSubject; + + PHTTP_SSL_CLIENT_CERT_INFO pClientCertInfo; + ULONG SslClientCertNegotiated; + +} HTTP_SSL_INFO, *PHTTP_SSL_INFO; + + +#if _WIN32_WINNT >= 0x0600 || BUILD_IIS_FOR_XP + +// +// Generic request information type. +// + +typedef enum _HTTP_REQUEST_INFO_TYPE +{ + HttpRequestInfoTypeAuth + +#if _WIN32_WINNT >= _WIN32_WINNT_WIN7 + ,HttpRequestInfoTypeChannelBind +#endif + + +} HTTP_REQUEST_INFO_TYPE, *PHTTP_REQUEST_INFO_TYPE; + +typedef struct _HTTP_REQUEST_INFO +{ + HTTP_REQUEST_INFO_TYPE InfoType; + ULONG InfoLength; + PVOID pInfo; + +} HTTP_REQUEST_INFO, *PHTTP_REQUEST_INFO; + +#ifndef __SECSTATUS_DEFINED__ +typedef LONG SECURITY_STATUS; +#define __SECSTATUS_DEFINED__ +#endif // __SECSTATUS_DEFINED__ + +// +// Authentication request info structure +// + +#define HTTP_REQUEST_AUTH_FLAG_TOKEN_FOR_CACHED_CRED (0x00000001) + +typedef struct _HTTP_REQUEST_AUTH_INFO +{ + HTTP_AUTH_STATUS AuthStatus; + SECURITY_STATUS SecStatus; + + ULONG Flags; + + HTTP_REQUEST_AUTH_TYPE AuthType; + + HANDLE AccessToken; + ULONG ContextAttributes; + + // + // Optional serialized context. + // + + ULONG PackedContextLength; + ULONG PackedContextType; + PVOID PackedContext; + + // + // Optional mutual authentication data and its length in bytes. + // + + ULONG MutualAuthDataLength; + PCHAR pMutualAuthData; + + // + // For SSPI based schemes the package name is returned. Length does + // not include the terminating null and it is in bytes. + // + + USHORT PackageNameLength; + PWSTR pPackageName; + +} HTTP_REQUEST_AUTH_INFO, *PHTTP_REQUEST_AUTH_INFO; + +#endif // _WIN32_WINNT >= 0x0600 + +// +// The structure of an HTTP request for downlevel OS +// + +typedef struct _HTTP_REQUEST_V1 +{ + // + // Request flags (see HTTP_REQUEST_FLAG_* definitions below). + // + + ULONG Flags; + + // + // An opaque request identifier. These values are used by the driver + // to correlate outgoing responses with incoming requests. + // + + HTTP_CONNECTION_ID ConnectionId; + HTTP_REQUEST_ID RequestId; + + // + // The context associated with the URL prefix. + // + + HTTP_URL_CONTEXT UrlContext; + + // + // The HTTP version number. + // + + HTTP_VERSION Version; + + // + // The request verb. + // + + HTTP_VERB Verb; + + // + // The length of the verb string if the Verb field is HttpVerbUnknown. + // + + USHORT UnknownVerbLength; // in bytes not including the NUL + + // + // The length of the raw (uncooked) URL + // + + USHORT RawUrlLength; // in bytes not including the NUL + + // + // Pointer to the verb string if the Verb field is HttpVerbUnknown. + // + + PCSTR pUnknownVerb; + + // + // Pointer to the raw (uncooked) URL + // + + PCSTR pRawUrl; + + // + // The canonicalized Unicode URL + // + + HTTP_COOKED_URL CookedUrl; + + // + // Local and remote transport addresses for the connection. + // + + HTTP_TRANSPORT_ADDRESS Address; + + // + // The request headers. + // + + HTTP_REQUEST_HEADERS Headers; + + // + // The total number of bytes received from network for this request. + // + + ULONGLONG BytesReceived; + + // + // pEntityChunks is an array of EntityChunkCount HTTP_DATA_CHUNKs. The + // entity body is copied only if HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY + // was passed to HttpReceiveHttpRequest(). + // + + USHORT EntityChunkCount; + PHTTP_DATA_CHUNK pEntityChunks; + + // + // SSL connection information. + // + + HTTP_RAW_CONNECTION_ID RawConnectionId; + PHTTP_SSL_INFO pSslInfo; + +} HTTP_REQUEST_V1, *PHTTP_REQUEST_V1; + +#if _WIN32_WINNT >= 0x0600 || BUILD_IIS_FOR_XP + +// Vista + +// +// Version 2.0 members are defined here +// N.B. One must define V2 elements in two places :( +// This is due to the fact that C++ doesn't allow anonymous +// structure declarations and one must use structure +// inheritance instead. +// + +#ifdef __cplusplus + +typedef struct _HTTP_REQUEST_V2 : _HTTP_REQUEST_V1 +{ + // + // Version 1.0 members are inherited + // Version 2.0 members are declared below + // + + // + // Additional Request Informations. + // + + USHORT RequestInfoCount; + PHTTP_REQUEST_INFO pRequestInfo; +} HTTP_REQUEST_V2, *PHTTP_REQUEST_V2; + +#else // __cplusplus + +typedef struct _HTTP_REQUEST_V2 +{ + struct _HTTP_REQUEST_V1; // Anonymous structure + + // + // Version 2.0 members are declared below + // + + // + // Additional Request Informations. + // + + USHORT RequestInfoCount; + PHTTP_REQUEST_INFO pRequestInfo; +} HTTP_REQUEST_V2, *PHTTP_REQUEST_V2; + +#endif // __cplusplus + +typedef HTTP_REQUEST_V2 HTTP_REQUEST; + +#else // _WIN32_WINNT >= 0x0600 + +typedef HTTP_REQUEST_V1 HTTP_REQUEST; + +#endif // _WIN32_WINNT >= 0x0600 + +typedef HTTP_REQUEST * PHTTP_REQUEST; + + +// +// Values for HTTP_REQUEST::Flags. Zero or more of these may be ORed together. +// +// HTTP_REQUEST_FLAG_MORE_ENTITY_BODY_EXISTS - there is more entity body +// to be read for this request. Otherwise, there is no entity body or +// all of the entity body was copied into pEntityChunks. +// HTTP_REQUEST_FLAG_IP_ROUTED - This flag indicates that the request has been +// routed based on host plus ip or ip binding.This is a hint for the application +// to include the local ip while flushing kernel cache entries build for this +// request if any. +// + +#define HTTP_REQUEST_FLAG_MORE_ENTITY_BODY_EXISTS 0x00000001 +#define HTTP_REQUEST_FLAG_IP_ROUTED 0x00000002 + + +// +// This structure describes an HTTP response. +// + +typedef struct _HTTP_RESPONSE_V1 +{ + // + // Response flags (see HTTP_RESPONSE_FLAG_* definitions below). + // + + ULONG Flags; + + // + // The raw HTTP protocol version number. + // + + HTTP_VERSION Version; + + // + // The HTTP status code (e.g., 200). + // + + USHORT StatusCode; + + // + // The HTTP reason (e.g., "OK"). This MUST not contain + // non-ASCII characters (i.e., all chars must be in range 0x20-0x7E). + // + + USHORT ReasonLength; // in bytes not including the '\0' + PCSTR pReason; + + // + // The response headers. + // + + HTTP_RESPONSE_HEADERS Headers; + + // + // pEntityChunks points to an array of EntityChunkCount HTTP_DATA_CHUNKs. + // + + USHORT EntityChunkCount; + PHTTP_DATA_CHUNK pEntityChunks; + +} HTTP_RESPONSE_V1, *PHTTP_RESPONSE_V1; + +#if _WIN32_WINNT >= 0x0600 || BUILD_IIS_FOR_XP + +// +// Values for HTTP_RESPONSE::Flags. +// +// HTTP_RESPONSE_FLAG_MULTIPLE_ENCODINGS_AVAILABLE - Set this flag if encodings +// other than identity form are available for this resource.This flag is ignored +// if application has not asked for response to be cached. It's used as a hint +// to the Http Server API for content negotiation used when serving from the +// the kernel response cache. +// + +#define HTTP_RESPONSE_FLAG_MULTIPLE_ENCODINGS_AVAILABLE 0x00000001 + + +// Vista + +typedef enum _HTTP_RESPONSE_INFO_TYPE +{ + HttpResponseInfoTypeMultipleKnownHeaders, + HttpResponseInfoTypeAuthenticationProperty, + HttpResponseInfoTypeQoSProperty + +#if _WIN32_WINNT >= _WIN32_WINNT_WIN7 || BUILD_IIS_FOR_XP + ,HttpResponseInfoTypeChannelBind +#endif + +} HTTP_RESPONSE_INFO_TYPE, PHTTP_RESPONSE_INFO_TYPE; + +typedef struct _HTTP_RESPONSE_INFO +{ + HTTP_RESPONSE_INFO_TYPE Type; + ULONG Length; + PVOID pInfo; +} HTTP_RESPONSE_INFO, *PHTTP_RESPONSE_INFO; + +#define HTTP_RESPONSE_INFO_FLAGS_PRESERVE_ORDER 0x00000001 + +// +// This structure allows the provision of providing multiple known headers. +// + +typedef struct _HTTP_MULTIPLE_KNOWN_HEADERS +{ + // + // Known header id. + // + + HTTP_HEADER_ID HeaderId; + + ULONG Flags; + + // + // Number of headers of the same category. + // + + USHORT KnownHeaderCount; + + // + // Array of known header structures. + // + + PHTTP_KNOWN_HEADER KnownHeaders; + +} HTTP_MULTIPLE_KNOWN_HEADERS, *PHTTP_MULTIPLE_KNOWN_HEADERS; + +// +// Version 2.0 members are defined here +// N.B. One must define V2 elements in two places :( +// This is due to the fact that C++ doesn't allow anonymous +// structure declarations and one must use structure +// inheritance instead. +// + +#ifdef __cplusplus + +typedef struct _HTTP_RESPONSE_V2 : _HTTP_RESPONSE_V1 +{ + // + // Version 1.0 members are inherited + // Version 2.0 members are declared below + // + + USHORT ResponseInfoCount; + PHTTP_RESPONSE_INFO pResponseInfo; + +} HTTP_RESPONSE_V2, *PHTTP_RESPONSE_V2; + +#else // __cplusplus + +typedef struct _HTTP_RESPONSE_V2 +{ + struct _HTTP_RESPONSE_V1; + + // + // Version 2.0 members are declared below + // + + USHORT ResponseInfoCount; + PHTTP_RESPONSE_INFO pResponseInfo; +} HTTP_RESPONSE_V2, *PHTTP_RESPONSE_V2; + +#endif // __cplusplus + +typedef HTTP_RESPONSE_V2 HTTP_RESPONSE; + +#else // _WIN32_WINNT >= 0x0600 + +typedef HTTP_RESPONSE_V1 HTTP_RESPONSE; + +#endif // _WIN32_WINNT >= 0x0600 + +typedef HTTP_RESPONSE *PHTTP_RESPONSE; + +// +// Api Version. This is used to ensure compatibility between applications and +// httpapi.dll and http.sys. +// +// This must not be confused with the HTTP Protocol version. +// + +typedef struct _HTTPAPI_VERSION +{ + USHORT HttpApiMajorVersion; + USHORT HttpApiMinorVersion; + +} HTTPAPI_VERSION, *PHTTPAPI_VERSION; + + +#if _WIN32_WINNT >= 0x0600 || BUILD_IIS_FOR_XP + +// Vista + +#define HTTPAPI_VERSION_2 { 2, 0 } + +#endif // _WIN32_WINNT >= 0x0600 + +#define HTTPAPI_VERSION_1 { 1, 0 } + +#define HTTPAPI_EQUAL_VERSION(version, major, minor) \ + ((version).HttpApiMajorVersion == (major) && \ + (version).HttpApiMinorVersion == (minor)) + +#define HTTPAPI_GREATER_VERSION(version, major, minor) \ + ((version).HttpApiMajorVersion > (major) || \ + ((version).HttpApiMajorVersion == (major) && \ + (version).HttpApiMinorVersion > (minor))) + +#define HTTPAPI_LESS_VERSION(version, major, minor) \ + ((version).HttpApiMajorVersion < (major) || \ + ((version).HttpApiMajorVersion == (major) && \ + (version).HttpApiMinorVersion < (minor))) + +#define HTTPAPI_VERSION_GREATER_OR_EQUAL( version, major, minor) \ + (!HTTPAPI_LESS_VERSION(version, major, minor)) + + +// +// Cache control. +// + +// +// This enum defines the available cache policies. +// + +typedef enum _HTTP_CACHE_POLICY_TYPE +{ + HttpCachePolicyNocache, + HttpCachePolicyUserInvalidates, + HttpCachePolicyTimeToLive, + + HttpCachePolicyMaximum + +} HTTP_CACHE_POLICY_TYPE, *PHTTP_CACHE_POLICY_TYPE; + + +// +// Only cache unauthorized GETs + HEADs. +// + +typedef struct _HTTP_CACHE_POLICY +{ + HTTP_CACHE_POLICY_TYPE Policy; + ULONG SecondsToLive; + +} HTTP_CACHE_POLICY, *PHTTP_CACHE_POLICY; + +// +// Enum that is used with HttpSetServiceConfiguration(), +// HttpQueryServiceConfiguration(), and HttpDeleteServiceConfiguration() APIs. +// + +typedef enum _HTTP_SERVICE_CONFIG_ID +{ + HttpServiceConfigIPListenList, // Set, Query & Delete. + HttpServiceConfigSSLCertInfo, // Set, Query & Delete. + HttpServiceConfigUrlAclInfo, // Set, Query & Delete. + HttpServiceConfigTimeout, // Set, Query & Delete. + HttpServiceConfigCache, // Set, Query & Delete. + HttpServiceConfigMax + +} HTTP_SERVICE_CONFIG_ID, *PHTTP_SERVICE_CONFIG_ID; + +// +// Generic Query enum that can be used with HttpQueryServiceConfiguration() +// + +typedef enum _HTTP_SERVICE_CONFIG_QUERY_TYPE +{ + HttpServiceConfigQueryExact, + HttpServiceConfigQueryNext, + HttpServiceConfigQueryMax + +} HTTP_SERVICE_CONFIG_QUERY_TYPE, *PHTTP_SERVICE_CONFIG_QUERY_TYPE; + +// +// This data structure is used to define a key of the SSL certificate hash +// store. +// + +typedef struct _HTTP_SERVICE_CONFIG_SSL_KEY +{ + PSOCKADDR pIpPort; +} HTTP_SERVICE_CONFIG_SSL_KEY, *PHTTP_SERVICE_CONFIG_SSL_KEY; + +// +// This defines a record for the SSL config store. +// + +typedef struct _HTTP_SERVICE_CONFIG_SSL_PARAM +{ + ULONG SslHashLength; // Length of the SSL hash (in bytes) + PVOID pSslHash; // Pointer to the SSL hash + GUID AppId; // A unique identifier that can be used to + // identify the app that has set this parameter + + PWSTR pSslCertStoreName; // Store name to read the server certificate + // from; defaults to "MY". Certificate must be + // stored in the LOCAL_MACHINE context. + + // + // The following settings are used only for client certificates + // + + // + // DefaultCertCheckMode is a bit flag with the following semantics + // 0x1 - Client certificate will not be verified for revocation + // 0x2 - Only cached certificate revocation will be used. + // 0x4 - Enable use of the DefaultRevocationFreshnessTime setting + // 0x10000 - No usage check. + + DWORD DefaultCertCheckMode; + + // + // DefaultRevocationFreshnessTime (seconds) - How often to check for + // an updated Certificate revocation list (CRL). If this value is 0 + // then the new CRL is updated only if the previous one expires + // + + DWORD DefaultRevocationFreshnessTime; + + // + // DefaultRevocationUrlRetrievalTimeout (milliseconds) - Timeout on + // attempt to retrieve certificate revocation list from the remote URL. + // + + DWORD DefaultRevocationUrlRetrievalTimeout; + + // + // pDefaultSslCtlIdentifier - Restrict the certificate issuers that you + // want to trust. Can be a subset of the certificate issuers that are + // trusted by the machine. + // + + PWSTR pDefaultSslCtlIdentifier; + + // + // Store name under LOCAL_MACHINE where Ctl identified by + // pDefaultSslCtlIdentifier is stored. + // + + PWSTR pDefaultSslCtlStoreName; + + // + // Default Flags - see HTTP_SERVICE_CONFIG_SSL_FLAG* below. + // + + DWORD DefaultFlags; + +} HTTP_SERVICE_CONFIG_SSL_PARAM, *PHTTP_SERVICE_CONFIG_SSL_PARAM; + +#define HTTP_SERVICE_CONFIG_SSL_FLAG_USE_DS_MAPPER 0x00000001 +#define HTTP_SERVICE_CONFIG_SSL_FLAG_NEGOTIATE_CLIENT_CERT 0x00000002 +#if _WIN32_WINNT < 0x0600 +#define HTTP_SERVICE_CONFIG_SSL_FLAG_NO_RAW_FILTER 0x00000004 +#endif // _WIN32_WINNT < 0x0600 + +// +// This data structure is used by HttpSetServiceConfiguration() for the +// config ID HttpServiceConfigSSLCertInfo. It's used to add a new record +// to the SSL store. +// + +typedef struct _HTTP_SERVICE_CONFIG_SSL_SET +{ + HTTP_SERVICE_CONFIG_SSL_KEY KeyDesc; + HTTP_SERVICE_CONFIG_SSL_PARAM ParamDesc; +} HTTP_SERVICE_CONFIG_SSL_SET, *PHTTP_SERVICE_CONFIG_SSL_SET; + +// +// This data structure is used by HttpQueryServiceConfiguration() for the +// config ID HttpServiceConfigSSLCertInfo. It's used to query a particular +// record from the SSL store. +// +// If QueryType is HttpServiceConfigQueryExact, then one particular record of +// the type HTTP_SERVICE_CONFIG_SSL_SET is returned. If the QueryType is +// HttpServiceConfigQueryNext, then the next instance of +// HTTP_SERVICE_CONFIG_SSL_SET is returned. In such cases, the dwToken field +// represents the cursor. For the first item, dwToken has to be 0. +// For subsequent items, dwToken has to be incremented by 1, +// until ERROR_NO_MORE_ITEMS is returned. +// + +typedef struct _HTTP_SERVICE_CONFIG_SSL_QUERY +{ + HTTP_SERVICE_CONFIG_QUERY_TYPE QueryDesc; + HTTP_SERVICE_CONFIG_SSL_KEY KeyDesc; + DWORD dwToken; +} HTTP_SERVICE_CONFIG_SSL_QUERY, *PHTTP_SERVICE_CONFIG_SSL_QUERY; + +// +// Set/Delete IP Listen-Only List record +// +// Used as a parameter to both HttpSetServiceConfiguration() and +// HttpDeleteServiceConfiguration() functions. +// + +typedef struct _HTTP_SERVICE_CONFIG_IP_LISTEN_PARAM +{ + USHORT AddrLength; + PSOCKADDR pAddress; +} HTTP_SERVICE_CONFIG_IP_LISTEN_PARAM, *PHTTP_SERVICE_CONFIG_IP_LISTEN_PARAM; + +// +// Query IP Listen-Only List record. +// +// Parameter to HttpQueryServiceConfiguration() for the config ID +// HttpServiceConfigIPListenList. On successful return, AddrList +// contains an array of AddrCount elements. Caller must provide a +// large enough buffer to hold all elements in one call. +// +// Caller may determine the type of each returned element by examining +// AddrList[i].ss_family. If it's AF_INET, use ((PSOCKADDR_IN) &AddrList[i]); +// otherwise, for AF_INET6, use ((PSOCKADDR_IN6) &AddrList[i]) +// to select the appropriate address type. +// + +typedef struct _HTTP_SERVICE_CONFIG_IP_LISTEN_QUERY +{ + ULONG AddrCount; + SOCKADDR_STORAGE AddrList[ANYSIZE_ARRAY]; +} HTTP_SERVICE_CONFIG_IP_LISTEN_QUERY, *PHTTP_SERVICE_CONFIG_IP_LISTEN_QUERY; + +// +// URL ACL +// +// +typedef struct _HTTP_SERVICE_CONFIG_URLACL_KEY +{ + PWSTR pUrlPrefix; + +} HTTP_SERVICE_CONFIG_URLACL_KEY, *PHTTP_SERVICE_CONFIG_URLACL_KEY; + +// +// This defines a record for the SSL config store. +// + +typedef struct _HTTP_SERVICE_CONFIG_URLACL_PARAM +{ + PWSTR pStringSecurityDescriptor; +} HTTP_SERVICE_CONFIG_URLACL_PARAM, *PHTTP_SERVICE_CONFIG_URLACL_PARAM; + + +// +// This data structure is used by HttpSetServiceConfiguration for the config ID +// HttpServiceConfigUrlAclInfo. It is used to add a new record to the URL ACL +// store. +// + +typedef struct _HTTP_SERVICE_CONFIG_URLACL_SET +{ + HTTP_SERVICE_CONFIG_URLACL_KEY KeyDesc; + HTTP_SERVICE_CONFIG_URLACL_PARAM ParamDesc; +} HTTP_SERVICE_CONFIG_URLACL_SET, *PHTTP_SERVICE_CONFIG_URLACL_SET; + + +// +// This data structure is used by HttpQueryServiceConfiguration() for the +// config ID HttpServiceConfigUrlAclInfo. It's used to query a particular +// record from the URL ACL store. +// +// If QueryType is HttpServiceConfigQueryExact, then one particular record of +// the type HTTP_SERVICE_CONFIG_URLACL_SET is returned. If the QueryType is +// HttpServiceConfigQueryNext, then the next instance of +// HTTP_SERVICE_CONFIG_URLACL_SET is returned. In such cases, the dwToken field +// represents the cursor. For the first item, dwToken has to be 0. +// For subsequent items, dwToken has to be incremented by 1, +// until ERROR_NO_MORE_ITEMS is returned. +// + +typedef struct _HTTP_SERVICE_CONFIG_URLACL_QUERY +{ + HTTP_SERVICE_CONFIG_QUERY_TYPE QueryDesc; + HTTP_SERVICE_CONFIG_URLACL_KEY KeyDesc; + DWORD dwToken; +} HTTP_SERVICE_CONFIG_URLACL_QUERY, *PHTTP_SERVICE_CONFIG_URLACL_QUERY; + +// +// Cache Paramemers +// + +// +// For manipulating global cache parameters. +// The parameters that can be changed or queued are per-uri cache size +// and cached range chunk size. +// + +typedef enum _HTTP_SERVICE_CONFIG_CACHE_KEY +{ + MaxCacheResponseSize = 0, + CacheRangeChunkSize +} HTTP_SERVICE_CONFIG_CACHE_KEY, *PHTTP_SERVICE_CONFIG_CACHE_KEY; + +typedef ULONG HTTP_SERVICE_CONFIG_CACHE_PARAM, + *PHTTP_SERVICE_CONFIG_CACHE_PARAM; + +// +// To set a cache parameter value use the set structure. To query use the key +// directly. When you query a parameter value the output buffer must be exactly +// the sizeof param. +// + +typedef struct { + HTTP_SERVICE_CONFIG_CACHE_KEY KeyDesc; + HTTP_SERVICE_CONFIG_CACHE_PARAM ParamDesc; +} HTTP_SERVICE_CONFIG_CACHE_SET, *PHTTP_SERVICE_CONFIG_CACHE_SET; + + +// +// Define our API linkage. +// + +#if !defined(HTTPAPI_LINKAGE) +#define HTTPAPI_LINKAGE DECLSPEC_IMPORT +#endif // !HTTPAPI_LINKAGE + +// +// Initialize/Terminate APIs. +// + + +// NOTE: MUST be called once before all other APIs + +HTTPAPI_LINKAGE +ULONG +WINAPI +HttpInitialize( + IN HTTPAPI_VERSION Version, + IN ULONG Flags, + __reserved IN OUT PVOID pReserved + ); + +// NOTE: MUST be called after final API call returns. + +HTTPAPI_LINKAGE +ULONG +WINAPI +HttpTerminate( + IN ULONG Flags, + __reserved IN OUT PVOID pReserved + ); + +// +// HTTP Request Queue manipulation APIs. +// +// This API is maintained for backward competibility for the first +// version of the HTTPAPI and should not be used. Instead the new +// HttpCreateRequestQueue() API must be used. +// +// Use CloseHandle() to release the handles returned by +// HttpCreateHttpHandle() API. +// + +HTTPAPI_LINKAGE +ULONG +WINAPI +HttpCreateHttpHandle( + OUT PHANDLE pReqQueueHandle, + __reserved IN ULONG Reserved + ); + +#if _WIN32_WINNT >= 0x0600 + +// +// Extended Request Queue manipulation APIs. +// +// Use HttpCloseRequestQueue() API to close the handles +// created by the HttpCreateRequestQueue API. +// + +HTTPAPI_LINKAGE +ULONG +WINAPI +HttpCreateRequestQueue( + IN HTTPAPI_VERSION Version, + IN PCWSTR pName OPTIONAL, + IN PSECURITY_ATTRIBUTES pSecurityAttributes OPTIONAL, + IN ULONG Flags OPTIONAL, + OUT PHANDLE pReqQueueHandle + ); + +HTTPAPI_LINKAGE +ULONG +WINAPI +HttpCloseRequestQueue( + IN HANDLE ReqQueueHandle + ); + +HTTPAPI_LINKAGE +ULONG +WINAPI +HttpSetRequestQueueProperty( + IN HANDLE Handle, + IN HTTP_SERVER_PROPERTY Property, + __in_bcount(PropertyInformationLength) IN PVOID pPropertyInformation, + IN ULONG PropertyInformationLength, + __reserved IN ULONG Reserved, + __reserved IN PVOID pReserved + ); + +HTTPAPI_LINKAGE +ULONG +WINAPI +HttpQueryRequestQueueProperty( + IN HANDLE Handle, + IN HTTP_SERVER_PROPERTY Property, + __out_bcount_part(PropertyInformationLength, *pReturnLength) + OUT PVOID pPropertyInformation, + IN ULONG PropertyInformationLength, + __reserved IN ULONG Reserved, + __out_opt OUT PULONG pReturnLength OPTIONAL, + __reserved IN PVOID pReserved + ); + +HTTPAPI_LINKAGE +ULONG +WINAPI +HttpShutdownRequestQueue( + IN HANDLE ReqQueueHandle + ); + +#endif // _WIN32_WINNT >= 0x0600 + +// +// SSL APIs. +// + +HTTPAPI_LINKAGE +ULONG +WINAPI +HttpReceiveClientCertificate( + IN HANDLE ReqQueueHandle, + IN HTTP_CONNECTION_ID ConnectionId, + IN ULONG Flags, + __out_bcount_part(SslClientCertInfoSize, *pBytesReceived) + OUT PHTTP_SSL_CLIENT_CERT_INFO pSslClientCertInfo, + IN ULONG SslClientCertInfoSize, + __out_opt OUT PULONG pBytesReceived OPTIONAL, + IN LPOVERLAPPED pOverlapped OPTIONAL + ); + +#if _WIN32_WINNT >= 0x0600 + +// +// Server Session APIs. +// + +HTTPAPI_LINKAGE +ULONG +WINAPI +HttpCreateServerSession( + IN HTTPAPI_VERSION Version, + OUT PHTTP_SERVER_SESSION_ID pServerSessionId, + __reserved IN ULONG Reserved + ); + +HTTPAPI_LINKAGE +ULONG +WINAPI +HttpCloseServerSession( + IN HTTP_SERVER_SESSION_ID ServerSessionId + ); + +HTTPAPI_LINKAGE +ULONG +WINAPI +HttpQueryServerSessionProperty( + IN HTTP_SERVER_SESSION_ID ServerSessionId, + IN HTTP_SERVER_PROPERTY Property, + __out_bcount_part(PropertyInformationLength, *pReturnLength) + OUT PVOID pPropertyInformation, + IN ULONG PropertyInformationLength, + __out_opt OUT PULONG pReturnLength OPTIONAL + ); + +HTTPAPI_LINKAGE +ULONG +WINAPI +HttpSetServerSessionProperty( + IN HTTP_SERVER_SESSION_ID ServerSessionId, + IN HTTP_SERVER_PROPERTY Property, + __in_bcount(PropertyInformationLength) IN PVOID pPropertyInformation, + IN ULONG PropertyInformationLength + ); + +#endif // _WIN32_WINNT >= 0x0600 + +// +// Url Configuration APIs. Can only be used for V1 request queues. +// + +HTTPAPI_LINKAGE +ULONG +WINAPI +HttpAddUrl( + IN HANDLE ReqQueueHandle, + IN PCWSTR pFullyQualifiedUrl, + __reserved IN PVOID pReserved + ); + +HTTPAPI_LINKAGE +ULONG +WINAPI +HttpRemoveUrl( + IN HANDLE ReqQueueHandle, + IN PCWSTR pFullyQualifiedUrl + ); + +#if _WIN32_WINNT >= 0x0600 + +// +// Url Group APIs. +// + +HTTPAPI_LINKAGE +ULONG +WINAPI +HttpCreateUrlGroup( + IN HTTP_SERVER_SESSION_ID ServerSessionId, + OUT PHTTP_URL_GROUP_ID pUrlGroupId, + __reserved IN ULONG Reserved + ); + +HTTPAPI_LINKAGE +ULONG +WINAPI +HttpCloseUrlGroup( + IN HTTP_URL_GROUP_ID UrlGroupId + ); + +HTTPAPI_LINKAGE +ULONG +WINAPI +HttpAddUrlToUrlGroup( + IN HTTP_URL_GROUP_ID UrlGroupId, + IN PCWSTR pFullyQualifiedUrl, + IN HTTP_URL_CONTEXT UrlContext OPTIONAL, + __reserved IN ULONG Reserved + ); + +HTTPAPI_LINKAGE +ULONG +WINAPI +HttpRemoveUrlFromUrlGroup( + IN HTTP_URL_GROUP_ID UrlGroupId, + IN PCWSTR pFullyQualifiedUrl, + IN ULONG Flags + ); + +HTTPAPI_LINKAGE +ULONG +WINAPI +HttpSetUrlGroupProperty( + IN HTTP_URL_GROUP_ID UrlGroupId, + IN HTTP_SERVER_PROPERTY Property, + __in_bcount(PropertyInformationLength) IN PVOID pPropertyInformation, + IN ULONG PropertyInformationLength + ); + +HTTPAPI_LINKAGE +ULONG +WINAPI +HttpQueryUrlGroupProperty( + IN HTTP_URL_GROUP_ID UrlGroupId, + IN HTTP_SERVER_PROPERTY Property, + __out_bcount_part(PropertyInformationLength, *pReturnLength) + OUT PVOID pPropertyInformation, + IN ULONG PropertyInformationLength, + __out_opt OUT PULONG pReturnLength OPTIONAL + ); + +#endif // _WIN32_WINNT >= 0x0600 + +// +// HTTP Server I/O APIs. +// + +HTTPAPI_LINKAGE +ULONG +WINAPI +HttpReceiveHttpRequest( + IN HANDLE ReqQueueHandle, + IN HTTP_REQUEST_ID RequestId, + IN ULONG Flags, + __out_bcount_part(RequestBufferLength, *pBytesReceived) + OUT PHTTP_REQUEST pRequestBuffer, + IN ULONG RequestBufferLength, + __out_opt OUT PULONG pBytesReceived OPTIONAL, + IN LPOVERLAPPED pOverlapped OPTIONAL + ); + +HTTPAPI_LINKAGE +ULONG +WINAPI +HttpReceiveRequestEntityBody( + IN HANDLE ReqQueueHandle, + IN HTTP_REQUEST_ID RequestId, + IN ULONG Flags, + __out_bcount_part(BufferLength, *pBytesReceived) OUT PVOID pBuffer, + IN ULONG BufferLength, + __out_opt OUT PULONG pBytesReceived OPTIONAL, + IN LPOVERLAPPED pOverlapped OPTIONAL + ); + +#if _WIN32_WINNT >= 0x0600 + +HTTPAPI_LINKAGE +ULONG +WINAPI +HttpSendHttpResponse( + IN HANDLE ReqQueueHandle, + IN HTTP_REQUEST_ID RequestId, + IN ULONG Flags, + IN PHTTP_RESPONSE pHttpResponse, + IN PHTTP_CACHE_POLICY pCachePolicy OPTIONAL, + OUT PULONG pBytesSent OPTIONAL, + OUT PVOID pReserved1 OPTIONAL, // must be NULL + IN ULONG Reserved2 OPTIONAL, // must be 0 + IN LPOVERLAPPED pOverlapped OPTIONAL, + IN PHTTP_LOG_DATA pLogData OPTIONAL + ); + +#else // _WIN32_WINNT >= 0x0600 + +HTTPAPI_LINKAGE +ULONG +WINAPI +HttpSendHttpResponse( + IN HANDLE ReqQueueHandle, + IN HTTP_REQUEST_ID RequestId, + IN ULONG Flags, + IN PHTTP_RESPONSE pHttpResponse, + IN PVOID pReserved1 OPTIONAL, // must be NULL + OUT PULONG pBytesSent OPTIONAL, + OUT PVOID pReserved2 OPTIONAL, // must be NULL + IN ULONG Reserved3 OPTIONAL, // must be 0 + IN LPOVERLAPPED pOverlapped OPTIONAL, + IN PVOID pReserved4 OPTIONAL // must be NULL + ); + +#endif // _WIN32_WINNT >= 0x0600 + +#if _WIN32_WINNT >= 0x0600 + +HTTPAPI_LINKAGE +ULONG +WINAPI +HttpSendResponseEntityBody( + IN HANDLE ReqQueueHandle, + IN HTTP_REQUEST_ID RequestId, + IN ULONG Flags, + IN USHORT EntityChunkCount OPTIONAL, + __in_ecount_opt(EntityChunkCount) + IN PHTTP_DATA_CHUNK pEntityChunks OPTIONAL, + OUT PULONG pBytesSent OPTIONAL, + OUT PVOID pReserved1 OPTIONAL, // must be NULL + IN ULONG Reserved2 OPTIONAL, // must be 0 + IN LPOVERLAPPED pOverlapped OPTIONAL, + IN PHTTP_LOG_DATA pLogData OPTIONAL + ); + +#else // _WIN32_WINNT >= 0x0600 + +HTTPAPI_LINKAGE +ULONG +WINAPI +HttpSendResponseEntityBody( + IN HANDLE ReqQueueHandle, + IN HTTP_REQUEST_ID RequestId, + IN ULONG Flags, + IN USHORT EntityChunkCount OPTIONAL, + __in_ecount_opt(EntityChunkCount) + IN PHTTP_DATA_CHUNK pEntityChunks OPTIONAL, + OUT PULONG pBytesSent OPTIONAL, + OUT PVOID pReserved1 OPTIONAL, // must be NULL + IN ULONG Reserved2 OPTIONAL, // must be 0 + IN LPOVERLAPPED pOverlapped OPTIONAL, + IN PVOID pReserved3 OPTIONAL // must be NULL + ); + +#endif // _WIN32_WINNT >= 0x0600 + +HTTPAPI_LINKAGE +ULONG +WINAPI +HttpWaitForDisconnect( + IN HANDLE ReqQueueHandle, + IN HTTP_CONNECTION_ID ConnectionId, + IN LPOVERLAPPED pOverlapped OPTIONAL + ); + +#if _WIN32_WINNT >= 0x0600 + +HTTPAPI_LINKAGE +ULONG +WINAPI +HttpWaitForDisconnectEx( + IN HANDLE ReqQueueHandle, + IN HTTP_CONNECTION_ID ConnectionId, + __reserved IN ULONG Reserved OPTIONAL, + IN LPOVERLAPPED pOverlapped OPTIONAL + ); + +HTTPAPI_LINKAGE +ULONG +WINAPI +HttpCancelHttpRequest( + IN HANDLE ReqQueueHandle, + IN HTTP_REQUEST_ID RequestId, + IN LPOVERLAPPED pOverlapped OPTIONAL + ); + +HTTPAPI_LINKAGE +ULONG +WINAPI +HttpWaitForDemandStart( + IN HANDLE ReqQueueHandle, + IN LPOVERLAPPED pOverlapped OPTIONAL + ); + + +#endif // _WIN32_WINNT >= 0x0600 + +// +// Cache manipulation APIs. +// + +HTTPAPI_LINKAGE +ULONG +WINAPI +HttpFlushResponseCache( + IN HANDLE ReqQueueHandle, + IN PCWSTR pUrlPrefix, + IN ULONG Flags, + IN LPOVERLAPPED pOverlapped OPTIONAL + ); + +HTTPAPI_LINKAGE +ULONG +WINAPI +HttpAddFragmentToCache( + IN HANDLE ReqQueueHandle, + IN PCWSTR pUrlPrefix, + IN PHTTP_DATA_CHUNK pDataChunk, + IN PHTTP_CACHE_POLICY pCachePolicy, + IN LPOVERLAPPED pOverlapped OPTIONAL + ); + +HTTPAPI_LINKAGE +ULONG +WINAPI +HttpReadFragmentFromCache( + IN HANDLE ReqQueueHandle, + IN PCWSTR pUrlPrefix, + IN PHTTP_BYTE_RANGE pByteRange OPTIONAL, + __out_bcount_part(BufferLength, *pBytesRead) OUT PVOID pBuffer, + IN ULONG BufferLength, + OUT PULONG pBytesRead OPTIONAL, + IN LPOVERLAPPED pOverlapped OPTIONAL + ); + +// +// Server configuration APIs +// + +HTTPAPI_LINKAGE +ULONG +WINAPI +HttpSetServiceConfiguration( + __reserved IN HANDLE ServiceHandle, + IN HTTP_SERVICE_CONFIG_ID ConfigId, + __in_bcount(ConfigInformationLength) IN PVOID pConfigInformation, + IN ULONG ConfigInformationLength, + __reserved IN LPOVERLAPPED pOverlapped + ); + +HTTPAPI_LINKAGE +ULONG +WINAPI +HttpDeleteServiceConfiguration( + __reserved IN HANDLE ServiceHandle, + IN HTTP_SERVICE_CONFIG_ID ConfigId, + __in_bcount(ConfigInformationLength) IN PVOID pConfigInformation, + IN ULONG ConfigInformationLength, + __reserved IN LPOVERLAPPED pOverlapped + ); + +HTTPAPI_LINKAGE +ULONG +WINAPI +HttpQueryServiceConfiguration( + __reserved IN HANDLE ServiceHandle, + IN HTTP_SERVICE_CONFIG_ID ConfigId, + __in_bcount_opt(InputConfigInformationLength) + IN PVOID pInputConfigInformation OPTIONAL, + IN ULONG InputConfigInformationLength OPTIONAL, + __out_bcount_part_opt(OutputConfigInformationLength, *pReturnLength) + OUT PVOID pOutputConfigInformation OPTIONAL, + IN ULONG OutputConfigInformationLength OPTIONAL, + __out_opt OUT PULONG pReturnLength OPTIONAL, + __reserved IN LPOVERLAPPED pOverlapped + ); + + +#if BUILD_IIS_FOR_XP + +// part of the httpp.h necessary to build for XP + +// +// Counter Group. +// + +// +// Counter property description. +// + +typedef struct _HTTP_PROP_DESC +{ + ULONG Size; + ULONG Offset; + BOOLEAN WPZeros; + +} HTTP_PROP_DESC, *PHTTP_PROP_DESC; + + +// +// This enum defines the available counter groups. +// + +typedef enum _HTTP_COUNTER_GROUP +{ + HttpCounterGroupSite, + HttpCounterGroupGlobal, + + HttpCounterGroupMaximum + +} HTTP_COUNTER_GROUP, *PHTTP_COUNTER_GROUP; + +// +// Structures for IOCTL_HTTP_GET_COUNTERS. +// + +typedef struct _HTTP_COUNTER_INFO +{ + HTTP_SERVER_SESSION_ID ServerSessionId; + HTTP_COUNTER_GROUP CounterGroup; + +} HTTP_COUNTER_INFO, *PHTTP_COUNTER_INFO; + +// +// This enum defines the type of global couters. +// + +typedef enum _HTTP_GLOBAL_COUNTER_ID +{ + HttpGlobalCounterCurrentUrisCached, + HttpGlobalCounterTotalUrisCached, + HttpGlobalCounterUriCacheHits, + HttpGlobalCounterUriCacheMisses, + HttpGlobalCounterUriCacheFlushes, + HttpGlobalCounterTotalFlushedUris, + + HttpGlobalCounterMaximum + +} HTTP_GLOBAL_COUNTER_ID, *PHTTP_GLOBAL_COUNTER_ID; + + +// +// Global couters. +// + +typedef struct _HTTP_GLOBAL_COUNTERS +{ + ULONG CurrentUrisCached; + ULONG TotalUrisCached; + ULONG UriCacheHits; + ULONG UriCacheMisses; + ULONG UriCacheFlushes; + ULONG TotalFlushedUris; + +} HTTP_GLOBAL_COUNTERS, *PHTTP_GLOBAL_COUNTERS; + + +// +// This enum defines the type of site counters. +// NB: HTTP_SITE_COUNTER_ID and HTTP_SITE_COUNTERS +// must be in the same order +// + +typedef enum _HTTP_SITE_COUNTER_ID +{ + HttpSiteCounterBytesSent, + HttpSiteCounterBytesReceived, + HttpSiteCounterBytesTransfered, + HttpSiteCounterCurrentConns, + HttpSiteCounterMaxConnections, + HttpSiteCounterConnAttempts, + HttpSiteCounterGetReqs, + HttpSiteCounterHeadReqs, + HttpSiteCounterAllReqs, + HttpSiteCounterMeasuredIoBandwidthUsage, + HttpSiteCounterCurrentBlockedBandwidthBytes, + HttpSiteCounterTotalBlockedBandwidthBytes, + + HttpSiteCounterMaximum + +} HTTP_SITE_COUNTER_ID, *PHTTP_SITE_COUNTER_ID; + + +// +// Site counters. +// + +typedef struct _HTTP_SITE_COUNTERS +{ + ULONG SiteId; + ULONGLONG BytesSent; + ULONGLONG BytesReceived; + ULONGLONG BytesTransfered; + ULONG CurrentConns; + ULONG MaxConnections; + ULONG ConnAttempts; + ULONG GetReqs; + ULONG HeadReqs; + ULONG AllReqs; + ULONG MeasuredIoBandwidthUsage; + ULONG CurrentBlockedBandwidthBytes; + ULONG TotalBlockedBandwidthBytes; + +} HTTP_SITE_COUNTERS, *PHTTP_SITE_COUNTERS; + +#endif + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif // _WIN32_WINNT >= 0x0501 + +#endif // __HTTP_H__ + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/httpserv_xp.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/httpserv_xp.h new file mode 100644 index 0000000000..6e9437d7ed --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/httpserv_xp.h @@ -0,0 +1,3404 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#ifndef _HTTPSERV_H_ +#define _HTTPSERV_H_ + +#if (!defined(_WIN64) && !defined(WIN32)) +#error httpserv.h is only supported on WIN32 or WIN64 platforms +#endif + +#include + +#if _WIN32_WINNT >= 0x0600 +#include "http.h" +#else +#include "http_xp.h" +#endif + +// +// Request deterministic notifications +// + +// request is beginning +#define RQ_BEGIN_REQUEST 0x00000001 +// request is being authenticated +#define RQ_AUTHENTICATE_REQUEST 0x00000002 +// request is being authorized +#define RQ_AUTHORIZE_REQUEST 0x00000004 +// satisfy request from cache +#define RQ_RESOLVE_REQUEST_CACHE 0x00000008 +// map handler for request +#define RQ_MAP_REQUEST_HANDLER 0x00000010 +// acquire request state +#define RQ_ACQUIRE_REQUEST_STATE 0x00000020 +// pre-execute handler +#define RQ_PRE_EXECUTE_REQUEST_HANDLER 0x00000040 +// execute handler +#define RQ_EXECUTE_REQUEST_HANDLER 0x00000080 +// release request state +#define RQ_RELEASE_REQUEST_STATE 0x00000100 +// update cache +#define RQ_UPDATE_REQUEST_CACHE 0x00000200 +// log request +#define RQ_LOG_REQUEST 0x00000400 +// end request +#define RQ_END_REQUEST 0x00000800 + +// +// Request non-deterministic notifications +// + +// custom notification +#define RQ_CUSTOM_NOTIFICATION 0x10000000 +// send response +#define RQ_SEND_RESPONSE 0x20000000 +// read entity +#define RQ_READ_ENTITY 0x40000000 +// map a url to a physical path +#define RQ_MAP_PATH 0x80000000 + +// +// Global notifications +// + +// stop accepting new requests +#define GL_STOP_LISTENING 0x00000002 +// cache cleanup before termination +#define GL_CACHE_CLEANUP 0x00000004 +// cache operation +#define GL_CACHE_OPERATION 0x00000010 +// health check +#define GL_HEALTH_CHECK 0x00000020 +// configuration changed +#define GL_CONFIGURATION_CHANGE 0x00000040 +// file changed +#define GL_FILE_CHANGE 0x00000080 +// before request pipeline has started +#define GL_PRE_BEGIN_REQUEST 0x00000100 +// application start +#define GL_APPLICATION_START 0x00000200 +// resolve modules for an application +#define GL_APPLICATION_RESOLVE_MODULES 0x00000400 +// application end +#define GL_APPLICATION_STOP 0x00000800 +// RSCA query +#define GL_RSCA_QUERY 0x00001000 +// trace event was raised +#define GL_TRACE_EVENT 0x00002000 +// custom notification +#define GL_CUSTOM_NOTIFICATION 0x00004000 +// thread cleanup notification +#define GL_THREAD_CLEANUP 0x00008000 +// application preload notification +#define GL_APPLICATION_PRELOAD 0x00010000 + +// +// Request notification return status +// + +typedef enum REQUEST_NOTIFICATION_STATUS +{ + RQ_NOTIFICATION_CONTINUE, // continue processing + // for notification + RQ_NOTIFICATION_PENDING, // suspend processing + // for notification + RQ_NOTIFICATION_FINISH_REQUEST // finish request + // processing +}; + +// +// Out of band return codes +// + +typedef enum GLOBAL_NOTIFICATION_STATUS +{ + GL_NOTIFICATION_CONTINUE, // continue processing + // for notification + GL_NOTIFICATION_HANDLED // finish processing for + // notification +}; + +// +// Priority class aliases +// + +#define PRIORITY_ALIAS_FIRST L"FIRST" +#define PRIORITY_ALIAS_HIGH L"HIGH" +#define PRIORITY_ALIAS_MEDIUM L"MEDIUM" +#define PRIORITY_ALIAS_LOW L"LOW" +#define PRIORITY_ALIAS_LAST L"LAST" + +// +// Cache operations +// + +typedef enum CACHE_OPERATION +{ + CACHE_OPERATION_RETRIEVE, + CACHE_OPERATION_ADD, + CACHE_OPERATION_DELETE, + CACHE_OPERATION_FLUSH_PREFIX, + CACHE_OPERATION_ENUM +}; + +// +// Module identifier +// + +typedef VOID* HTTP_MODULE_ID; + +// +// Flags for IHttpContext->CloneContext() +// + +#define CLONE_FLAG_BASICS 0x01 +#define CLONE_FLAG_HEADERS 0x02 +#define CLONE_FLAG_ENTITY 0x04 +#define CLONE_FLAG_NO_PRECONDITION 0x08 +#define CLONE_FLAG_NO_DAV 0x10 + +// +// Flags for IHttpContext->ExecuteRequest() +// + +#define EXECUTE_FLAG_NO_HEADERS 0x01 +#define EXECUTE_FLAG_IGNORE_CURRENT_INTERCEPTOR 0x02 +#define EXECUTE_FLAG_IGNORE_APPPOOL 0x04 +#define EXECUTE_FLAG_DISABLE_CUSTOM_ERROR 0x08 +#define EXECUTE_FLAG_SAME_URL 0x10 +// do not flush the child response but copy it back to the parent +#define EXECUTE_FLAG_BUFFER_RESPONSE 0x20 +// child response is still eligible for http.sys caching +#define EXECUTE_FLAG_HTTP_CACHE_ELIGIBLE 0x40 + + +// +// forward declarations +// +struct HTTP_TRACE_CONFIGURATION; +struct HTTP_TRACE_EVENT; + +class IWpfSettings; +class IHttpTraceContext; + +// +// Module-specific context descriptor +// +class __declspec(uuid("f1927f76-790e-4ccb-a72e-396bdfdae05d")) +IHttpStoredContext +{ + public: + virtual + VOID + CleanupStoredContext( + VOID + ) = 0; +}; + +// +// Context container +// +class __declspec(uuid("d7fad7c9-aa27-4ab9-bd60-e55ccba3f5dc")) +IHttpModuleContextContainer +{ + public: + virtual + IHttpStoredContext * + GetModuleContext( + IN HTTP_MODULE_ID moduleId + ) = 0; + + virtual + HRESULT + SetModuleContext( + IN IHttpStoredContext * ppStoredContext, + IN HTTP_MODULE_ID moduleId + ) = 0; +}; + +// +// Dispensed context container +// +class __declspec(uuid("2ae49359-95dd-4e48-ae20-c0cb9d0bc03a")) +IDispensedHttpModuleContextContainer : public IHttpModuleContextContainer +{ +public: + virtual + VOID + ReleaseContainer( + VOID + ) = 0; +}; + +// +// Performance counter descriptor +// +class __declspec(uuid("bdfc4c4a-12a4-4744-87d8-765eb320c59f")) +IHttpPerfCounterInfo +{ + public: + virtual + VOID + IncrementCounter( + DWORD dwCounterIndex, + DWORD dwValue = 1 + ) = 0; + + virtual + VOID + DecrementCounter( + DWORD dwCounterIndex, + DWORD dwValue = 1 + ) = 0; +}; + +// +// Application descriptor +// +class __declspec(uuid("3f75d9e6-1075-422c-ad89-93a85f2d7bdc")) +IHttpApplication +{ + public: + virtual + PCWSTR + GetApplicationPhysicalPath( + VOID + ) const = 0; + + virtual + PCWSTR + GetApplicationId( + VOID + ) const = 0; + + virtual + PCWSTR + GetAppConfigPath( + VOID + ) const = 0; + + virtual + IHttpModuleContextContainer * + GetModuleContextContainer( + VOID + ) = 0; +}; + +// +// URI cache entry descriptor +// +class __declspec(uuid("7e0e6167-0094-49a1-8287-ecf6dc6e73a6")) +IHttpUrlInfo +{ + public: + virtual + IHttpModuleContextContainer * + GetModuleContextContainer( + VOID + ) = 0; + + virtual + BOOL + IsFrequentlyHit( + VOID + ) const = 0; +}; + +// +// Script map descriptor +// +class __declspec(uuid("d7fe3d77-68bc-4d4a-851f-eec9fb68017c")) +IScriptMapInfo +{ + public: + virtual + PCWSTR + GetPath( + VOID + ) const = 0; + + virtual + PCSTR + GetAllowedVerbs( + VOID + ) const = 0; + + virtual + PCWSTR + GetModules( + OUT DWORD * pcchModules = NULL + ) const = 0; + + virtual + PCWSTR + GetScriptProcessor( + OUT DWORD * pcchScriptProcessor = NULL + ) const = 0; + + virtual + PCWSTR + GetManagedType( + OUT DWORD * pcchManagedType = NULL + ) const = 0; + + virtual + BOOL + GetAllowPathInfoForScriptMappings( + VOID + ) const = 0; + + virtual + DWORD + GetRequiredAccess( + VOID + ) const = 0; + + virtual + DWORD + GetResourceType( + VOID + ) const = 0; + + virtual + BOOL + GetIsStarScriptMap( + VOID + ) const = 0; + + virtual + DWORD + GetResponseBufferLimit( + VOID + ) const = 0; + + virtual + PCWSTR + GetName( + VOID + ) const = 0; +}; + +class __declspec(uuid("fd86e6de-fb0e-47dd-820a-e0da12be46e9")) +IHttpTokenEntry; + +// +// Metadata descriptor +// +class __declspec(uuid("48b10633-825d-495e-93b0-225380053e8e")) +IMetadataInfo +{ + public: + virtual + PCWSTR + GetMetaPath( + VOID + ) const = 0; + + virtual + PCWSTR + GetVrPath( + VOID + ) const = 0; + + virtual + IHttpTokenEntry * + GetVrToken( + VOID + ) = 0; + + virtual + IHttpModuleContextContainer * + GetModuleContextContainer( + VOID + ) = 0; +}; + +// +// Provides an interface to an HTTP request object. The methods on this +// class can be used to inspect and modify request data. +// +class __declspec(uuid("e8698f7e-576e-4cac-a309-67435355faef")) +IHttpRequest +{ + public: + virtual + HTTP_REQUEST * + GetRawHttpRequest( + VOID + ) = 0; + + virtual + const HTTP_REQUEST * + GetRawHttpRequest( + VOID + ) const = 0; + + virtual + PCSTR + GetHeader( + IN PCSTR pszHeaderName, + OUT USHORT * pcchHeaderValue = NULL + ) const = 0; + + virtual + PCSTR + GetHeader( + IN HTTP_HEADER_ID ulHeaderIndex, + OUT USHORT * pcchHeaderValue = NULL + ) const = 0; + + virtual + HRESULT + SetHeader( + IN PCSTR pszHeaderName, + IN PCSTR pszHeaderValue, + IN USHORT cchHeaderValue, + IN BOOL fReplace + ) = 0; + + virtual + HRESULT + SetHeader( + IN HTTP_HEADER_ID ulHeaderIndex, + IN PCSTR pszHeaderValue, + IN USHORT cchHeaderValue, + IN BOOL fReplace + ) = 0; + + virtual + HRESULT + DeleteHeader( + IN PCSTR pszHeaderName + ) = 0; + + virtual + HRESULT + DeleteHeader( + IN HTTP_HEADER_ID ulHeaderIndex + ) = 0; + + virtual + PCSTR + GetHttpMethod( + VOID + ) const = 0; + + virtual + HRESULT + SetHttpMethod( + IN PCSTR pszHttpMethod + ) = 0; + + virtual + HRESULT + SetUrl( + IN PCWSTR pszUrl, + IN DWORD cchUrl, + IN BOOL fResetQueryString + ) = 0; + + virtual + HRESULT + SetUrl( + IN PCSTR pszUrl, + IN DWORD cchUrl, + IN BOOL fResetQueryString + ) = 0; + + virtual + BOOL + GetUrlChanged( + VOID + ) const = 0; + + virtual + PCWSTR + GetForwardedUrl( + VOID + ) const = 0; + + virtual + PSOCKADDR + GetLocalAddress( + VOID + ) const = 0; + + virtual + PSOCKADDR + GetRemoteAddress( + VOID + ) const = 0; + + virtual + HRESULT + ReadEntityBody( + OUT VOID * pvBuffer, + IN DWORD cbBuffer, + IN BOOL fAsync, + OUT DWORD * pcbBytesReceived, + OUT BOOL * pfCompletionPending = NULL + ) = 0; + + virtual + HRESULT + InsertEntityBody( + IN VOID * pvBuffer, + IN DWORD cbBuffer + ) = 0; + + virtual + DWORD + GetRemainingEntityBytes( + VOID + ) = 0; + + virtual + VOID + GetHttpVersion( + OUT USHORT * pMajorVersion, + OUT USHORT * pMinorVersion + ) const = 0; + + virtual + HRESULT + GetClientCertificate( + OUT HTTP_SSL_CLIENT_CERT_INFO ** ppClientCertInfo, + OUT BOOL * pfClientCertNegotiated + ) = 0; + + virtual + HRESULT + NegotiateClientCertificate( + IN BOOL fAsync, + OUT BOOL * pfCompletionPending = NULL + ) = 0; + + virtual + DWORD + GetSiteId( + VOID + ) const = 0; + + virtual + HRESULT + GetHeaderChanges( + IN DWORD dwOldChangeNumber, + OUT DWORD * pdwNewChangeNumber, + IN OUT PCSTR knownHeaderSnapshot[HttpHeaderRequestMaximum], + IN OUT DWORD * pdwUnknownHeaderSnapshot, + IN OUT PCSTR **ppUnknownHeaderNameSnapshot, + IN OUT PCSTR **ppUnknownHeaderValueSnapshot, + __out_ecount(HttpHeaderRequestMaximum+1) + DWORD diffedKnownHeaderIndices[HttpHeaderRequestMaximum+1], + OUT DWORD * pdwDiffedUnknownHeaders, + OUT DWORD **ppDiffedUnknownHeaderIndices + ) = 0; +}; + +class __declspec(uuid("d9244ae1-51f8-4aa1-a66d-19277c33e610")) +IHttpRequest2 : public IHttpRequest +{ + public: + virtual + HRESULT + GetChannelBindingToken( + __deref_out_bcount_part(*pTokenSize, *pTokenSize) + PBYTE * ppToken, + DWORD * pTokenSize + ) = 0; +}; + +class __declspec(uuid("cb1c40ca-70f2-41a0-add2-881f5ef57388")) +IHttpCachePolicy +{ + public: + virtual + HTTP_CACHE_POLICY * + GetKernelCachePolicy( + VOID + ) = 0; + + virtual + VOID + SetKernelCacheInvalidatorSet( + VOID + ) = 0; + + virtual + HTTP_CACHE_POLICY * + GetUserCachePolicy( + VOID + ) = 0; + + virtual + HRESULT + AppendVaryByHeader( + PCSTR pszHeader + ) = 0; + + virtual + PCSTR + GetVaryByHeaders( + VOID + ) const = 0; + + virtual + HRESULT + AppendVaryByQueryString( + PCSTR pszParam + ) = 0; + + virtual + PCSTR + GetVaryByQueryStrings( + VOID + ) const = 0; + + virtual + HRESULT + SetVaryByValue( + PCSTR pszValue + ) = 0; + + virtual + PCSTR + GetVaryByValue( + VOID + ) const = 0; + + virtual + BOOL + IsUserCacheEnabled( + VOID + ) const = 0; + + virtual + VOID + DisableUserCache( + VOID + ) = 0; + + virtual + BOOL + IsCached( + VOID + ) const = 0; + + virtual + VOID + SetIsCached( + VOID + ) = 0; + + virtual + BOOL + GetKernelCacheInvalidatorSet( + VOID + ) const = 0; +}; + +class __declspec(uuid("9f4ba807-050e-4495-ae55-8870f7e9194a")) +IHttpCachePolicy2 : public IHttpCachePolicy +{ + public: + virtual + BOOL + IsForceUpdateSet( + VOID + ) const = 0; + + virtual + VOID + SetForceUpdate( + VOID + ) = 0; +}; + +// +// Response descriptor +// +class __declspec(uuid("7e1c6b38-628f-4e6c-95dc-41237eb7f95e")) +IHttpResponse +{ + public: + virtual + HTTP_RESPONSE * + GetRawHttpResponse( + VOID + ) = 0; + + virtual + const HTTP_RESPONSE * + GetRawHttpResponse( + VOID + ) const = 0; + + virtual + IHttpCachePolicy * + GetCachePolicy( + VOID + ) = 0; + + virtual + HRESULT + SetStatus( + IN USHORT statusCode, + IN PCSTR pszReason, + IN USHORT uSubStatus = 0, + IN HRESULT hrErrorToReport = S_OK, + IN IAppHostConfigException *pException = NULL, + IN BOOL fTrySkipCustomErrors = FALSE + ) = 0; + + virtual + HRESULT + SetHeader( + IN PCSTR pszHeaderName, + IN PCSTR pszHeaderValue, + IN USHORT cchHeaderValue, + IN BOOL fReplace + ) = 0; + + virtual + HRESULT + SetHeader( + IN HTTP_HEADER_ID ulHeaderIndex, + IN PCSTR pszHeaderValue, + IN USHORT cchHeaderValue, + IN BOOL fReplace + ) = 0; + + virtual + HRESULT + DeleteHeader( + IN PCSTR pszHeaderName + ) = 0; + + virtual + HRESULT + DeleteHeader( + IN HTTP_HEADER_ID ulHeaderIndex + ) = 0; + + virtual + PCSTR + GetHeader( + IN PCSTR pszHeaderName, + OUT USHORT * pcchHeaderValue = NULL + ) const = 0; + + virtual + PCSTR + GetHeader( + IN HTTP_HEADER_ID ulHeaderIndex, + OUT USHORT * pcchHeaderValue = NULL + ) const = 0; + + virtual + VOID + Clear( + VOID + ) = 0; + + virtual + VOID + ClearHeaders( + VOID + ) = 0; + + virtual + VOID + SetNeedDisconnect( + VOID + ) = 0; + + virtual + VOID + ResetConnection( + VOID + ) = 0; + + virtual + VOID + DisableKernelCache( + ULONG reason = 9 + ) = 0; + + virtual + BOOL + GetKernelCacheEnabled( + VOID + ) const = 0; + + virtual + VOID + SuppressHeaders( + VOID + ) = 0; + + virtual + BOOL + GetHeadersSuppressed( + VOID + ) const = 0; + + virtual + HRESULT + Flush( + IN BOOL fAsync, + IN BOOL fMoreData, + OUT DWORD * pcbSent, + OUT BOOL * pfCompletionExpected = NULL + ) = 0; + + virtual + HRESULT + Redirect( + IN PCSTR pszUrl, + IN BOOL fResetStatusCode = TRUE, + IN BOOL fIncludeParameters = FALSE + ) = 0; + + virtual + HRESULT + WriteEntityChunkByReference( + IN HTTP_DATA_CHUNK * pDataChunk, + IN LONG lInsertPosition = -1 + ) = 0; + + virtual + HRESULT + WriteEntityChunks( + IN HTTP_DATA_CHUNK * pDataChunks, + IN DWORD nChunks, + IN BOOL fAsync, + IN BOOL fMoreData, + OUT DWORD * pcbSent, + OUT BOOL * pfCompletionExpected = NULL + ) = 0; + + virtual + VOID + DisableBuffering( + VOID + ) = 0; + + virtual + VOID + GetStatus( + OUT USHORT * pStatusCode, + OUT USHORT * pSubStatus = NULL, + OUT PCSTR * ppszReason = NULL, + OUT USHORT * pcchReason = NULL, + OUT HRESULT * phrErrorToReport = NULL, + OUT PCWSTR * ppszModule = NULL, + OUT DWORD * pdwNotification = NULL, + OUT IAppHostConfigException ** ppException = NULL, + OUT BOOL * pfTrySkipCustomErrors = NULL + ) = 0; + + virtual + HRESULT + SetErrorDescription( + IN PCWSTR pszDescription, + IN DWORD cchDescription, + IN BOOL fHtmlEncode = TRUE + ) = 0; + + virtual + PCWSTR + GetErrorDescription( + OUT DWORD * pcchDescription = NULL + ) = 0; + + virtual + HRESULT + GetHeaderChanges( + IN DWORD dwOldChangeNumber, + OUT DWORD * pdwNewChangeNumber, + IN OUT PCSTR knownHeaderSnapshot[HttpHeaderResponseMaximum], + IN OUT DWORD * pdwUnknownHeaderSnapshot, + IN OUT PCSTR **ppUnknownHeaderNameSnapshot, + IN OUT PCSTR **ppUnknownHeaderValueSnapshot, + __out_ecount(HttpHeaderResponseMaximum+1) + DWORD diffedKnownHeaderIndices[HttpHeaderResponseMaximum+1], + OUT DWORD * pdwDiffedUnknownHeaders, + OUT DWORD **ppDiffedUnknownHeaderIndices + ) = 0; + + virtual + VOID + CloseConnection( + VOID + ) = 0; +}; + +// +// User descriptor +// +class __declspec(uuid("8059e6f8-10ce-4d61-b47e-5a1d8d9a8b67")) +IHttpUser +{ + public: + virtual + PCWSTR + GetRemoteUserName( + VOID + ) = 0; + + virtual + PCWSTR + GetUserName( + VOID + ) = 0; + + virtual + PCWSTR + GetAuthenticationType( + VOID + ) = 0; + + virtual + PCWSTR + GetPassword( + VOID + ) = 0; + + virtual + HANDLE + GetImpersonationToken( + VOID + ) = 0; + + virtual + HANDLE + GetPrimaryToken( + VOID + ) = 0; + + virtual + VOID + ReferenceUser( + VOID + ) = 0; + + virtual + VOID + DereferenceUser( + VOID + ) = 0; + + virtual + BOOL + SupportsIsInRole( + VOID + ) = 0; + + virtual + HRESULT + IsInRole( + IN PCWSTR pszRoleName, + OUT BOOL * pfInRole + ) = 0; + + virtual + PVOID + GetUserVariable( + IN PCSTR pszVariableName + ) = 0; +}; + +#define HTTP_USER_VARIABLE_SID "SID" +#define HTTP_USER_VARIABLE_CTXT_HANDLE "CtxtHandle" +#define HTTP_USER_VARIABLE_CRED_HANDLE "CredHandle" + +class __declspec(uuid("841d9a71-75f4-4626-8b97-66046ca7e45b")) +IHttpConnectionStoredContext : public IHttpStoredContext +{ + public: + virtual + VOID + NotifyDisconnect( + VOID + ) = 0; +}; + +class __declspec(uuid("f3dd2fb3-4d11-4295-b8ab-4cb667add1fe")) +IHttpConnectionModuleContextContainer : public IHttpModuleContextContainer +{ + public: + virtual + IHttpConnectionStoredContext * + GetConnectionModuleContext( + IN HTTP_MODULE_ID moduleId + ) = 0; + + virtual + HRESULT + SetConnectionModuleContext( + IN IHttpConnectionStoredContext * ppStoredContext, + IN HTTP_MODULE_ID moduleId + ) = 0; +}; + +// +// Connection descriptor +// +class __declspec(uuid("d9a5de00-3346-4599-9826-fe88565e1226")) +IHttpConnection +{ + public: + virtual + BOOL + IsConnected( + VOID + ) const = 0; + + virtual + VOID * + AllocateMemory( + DWORD cbAllocation + ) = 0; + + virtual + IHttpConnectionModuleContextContainer * + GetModuleContextContainer( + VOID + ) = 0; +}; + +// +// Forward declarations +// +class __declspec(uuid("71e95595-8c74-44d9-88a9-f5112d5f5900")) +IHttpFileInfo; + +class __declspec(uuid("eb16a6ec-ba5d-436f-bf24-3ede13906450")) +IHttpSite; + +class __declspec(uuid("671e6d34-9380-4df4-b453-91129df02b24")) +ICustomNotificationProvider; + +class __declspec(uuid("6f3f657d-2fb8-43c6-a096-5064b41f0580")) +IHttpEventProvider; + +class CHttpModule; + +// +// IHttpContext extended interface versions (deprecated) +// +enum HTTP_CONTEXT_INTERFACE_VERSION +{ +}; + +// +// Context object representing the processing of an HTTP request +// +class __declspec(uuid("424c1b8c-a1ba-44d7-ac98-9f8f457701a5")) +IHttpContext +{ + public: + virtual + IHttpSite * + GetSite( + VOID + ) = 0; + + virtual + IHttpApplication * + GetApplication( + VOID + ) = 0; + + virtual + IHttpConnection * + GetConnection( + VOID + ) = 0; + + virtual + IHttpRequest * + GetRequest( + VOID + ) = 0; + + virtual + IHttpResponse * + GetResponse( + VOID + ) = 0; + + virtual + BOOL + GetResponseHeadersSent( + VOID + ) const = 0; + + virtual + IHttpUser * + GetUser( + VOID + ) const = 0; + + virtual + IHttpModuleContextContainer * + GetModuleContextContainer( + VOID + ) = 0; + + virtual + VOID + IndicateCompletion( + IN REQUEST_NOTIFICATION_STATUS notificationStatus + ) = 0; + + virtual + HRESULT + PostCompletion( + IN DWORD cbBytes + ) = 0; + + virtual + VOID + DisableNotifications( + IN DWORD dwNotifications, + IN DWORD dwPostNotifications + ) = 0; + + virtual + BOOL + GetNextNotification( + IN REQUEST_NOTIFICATION_STATUS status, + OUT DWORD * pdwNotification, + OUT BOOL * pfIsPostNotification, + OUT CHttpModule ** ppModuleInfo, + OUT IHttpEventProvider ** ppRequestOutput + ) = 0; + + virtual + BOOL + GetIsLastNotification( + IN REQUEST_NOTIFICATION_STATUS status + ) = 0; + + virtual + HRESULT + ExecuteRequest( + IN BOOL fAsync, + IN IHttpContext * pHttpContext, + IN DWORD dwExecuteFlags, + IN IHttpUser * pHttpUser, + OUT BOOL * pfCompletionExpected = NULL + ) = 0; + + virtual + DWORD + GetExecuteFlags( + VOID + ) const = 0; + + virtual + HRESULT + GetServerVariable( + PCSTR pszVariableName, + __deref_out_ecount(*pcchValueLength) PCWSTR * ppszValue, + __out DWORD * pcchValueLength + ) = 0; + + virtual + HRESULT + GetServerVariable( + PCSTR pszVariableName, + __deref_out_ecount(*pcchValueLength) PCSTR * ppszValue, + __out DWORD * pcchValueLength + ) = 0; + + virtual + HRESULT + SetServerVariable( + PCSTR pszVariableName, + PCWSTR pszVariableValue + ) = 0; + + virtual + VOID * + AllocateRequestMemory( + IN DWORD cbAllocation + ) = 0; + + virtual + IHttpUrlInfo * + GetUrlInfo( + VOID + ) = 0; + + virtual + IMetadataInfo * + GetMetadata( + VOID + ) = 0; + + virtual + PCWSTR + GetPhysicalPath( + OUT DWORD * pcchPhysicalPath = NULL + ) = 0; + + virtual + PCWSTR + GetScriptName( + OUT DWORD * pcchScriptName = NULL + ) const = 0; + + virtual + PCWSTR + GetScriptTranslated( + OUT DWORD * pcchScriptTranslated = NULL + ) = 0; + + virtual + IScriptMapInfo * + GetScriptMap( + VOID + ) const = 0; + + virtual + VOID + SetRequestHandled( + VOID + ) = 0; + + virtual + IHttpFileInfo * + GetFileInfo( + VOID + ) const = 0; + + virtual + HRESULT + MapPath( + PCWSTR pszUrl, + __out_bcount_opt(*pcbPhysicalPath) PWSTR pszPhysicalPath, + IN OUT DWORD * pcbPhysicalPath + ) = 0; + + virtual + HRESULT + NotifyCustomNotification( + ICustomNotificationProvider * pCustomOutput, + OUT BOOL * pfCompletionExpected + ) = 0; + + virtual + IHttpContext * + GetParentContext( + VOID + ) const = 0; + + virtual + IHttpContext * + GetRootContext( + VOID + ) const = 0; + + virtual + HRESULT + CloneContext( + IN DWORD dwCloneFlags, + OUT IHttpContext ** ppHttpContext + ) = 0; + + virtual + HRESULT + ReleaseClonedContext( + VOID + ) = 0; + + virtual + HRESULT + GetCurrentExecutionStats( + OUT DWORD * pdwNotification, + OUT DWORD * pdwNotificationStartTickCount = NULL, + OUT PCWSTR * ppszModule = NULL, + OUT DWORD * pdwModuleStartTickCount = NULL, + OUT DWORD * pdwAsyncNotification = NULL, + OUT DWORD * pdwAsyncNotificationStartTickCount = NULL + ) const = 0; + + virtual + IHttpTraceContext * + GetTraceContext( + VOID + ) const = 0; + + virtual + HRESULT + GetServerVarChanges( + IN DWORD dwOldChangeNumber, + OUT DWORD * pdwNewChangeNumber, + IN OUT DWORD * pdwVariableSnapshot, + IN OUT PCSTR ** ppVariableNameSnapshot, + IN OUT PCWSTR ** ppVariableValueSnapshot, + OUT DWORD * pdwDiffedVariables, + OUT DWORD ** ppDiffedVariableIndices + ) = 0; + + virtual + HRESULT + CancelIo( + VOID + ) = 0; + + virtual + HRESULT + MapHandler( + IN DWORD dwSiteId, + IN PCWSTR pszSiteName, + IN PCWSTR pszUrl, + IN PCSTR pszVerb, + OUT IScriptMapInfo ** ppScriptMap, + IN BOOL fIgnoreWildcardMappings = FALSE + ) = 0; + + __declspec(deprecated("This method is deprecated. Use the HttpGetExtendedInterface helper function instead.")) + virtual + HRESULT + GetExtendedInterface( + IN HTTP_CONTEXT_INTERFACE_VERSION version, + OUT PVOID * ppInterface + ) = 0; +}; + +class __declspec(uuid("9f9098d5-915c-4294-a52e-66532a232bc9")) +IHttpTraceContext +{ +public: + virtual + HRESULT + GetTraceConfiguration( + IN OUT HTTP_TRACE_CONFIGURATION * pHttpTraceConfiguration + ) = 0; + + virtual + HRESULT + SetTraceConfiguration( + IN HTTP_MODULE_ID moduleId, + IN HTTP_TRACE_CONFIGURATION * pHttpTraceConfiguration, + IN DWORD cHttpTraceConfiguration = 1 + ) = 0; + + virtual + HRESULT + RaiseTraceEvent( + IN HTTP_TRACE_EVENT * pTraceEvent + ) = 0; + + virtual + LPCGUID + GetTraceActivityId( + ) = 0; + + virtual + HRESULT + QuickTrace( + IN PCWSTR pszData1, + IN PCWSTR pszData2 = NULL, + IN HRESULT hrLastError = S_OK, + // + // 4 == TRACE_LEVEL_INFORMATION + // + IN UCHAR Level = 4 + ) = 0; +}; + +class __declspec(uuid("37776aff-852e-4eec-93a5-b85a285a95b8")) +IHttpCacheSpecificData; + +// +// Cache helpers +// +class __declspec(uuid("cdef2aad-20b3-4512-b1b1-094b3844aeb2")) +IHttpCacheKey +{ + public: + virtual + DWORD + GetHash( + VOID + ) const = 0; + + virtual + PCWSTR + GetCacheName( + VOID + ) const = 0; + + virtual + bool + GetIsEqual( + IHttpCacheKey * pCacheCompareKey + ) const = 0; + + virtual + bool + GetIsPrefix( + IHttpCacheKey * pCacheCompareKey + ) const = 0; + + virtual + VOID + Enum( + IHttpCacheSpecificData * + ) = 0; +}; + +class __declspec(uuid("37776aff-852e-4eec-93a5-b85a285a95b8")) +IHttpCacheSpecificData +{ + public: + virtual + IHttpCacheKey * + GetCacheKey( + VOID + ) const = 0; + + virtual + VOID + ReferenceCacheData( + VOID + ) = 0; + + virtual + VOID + DereferenceCacheData( + VOID + ) = 0; + + virtual + VOID + ResetTTL( + VOID + ) = 0; + + virtual + VOID + DecrementTTL( + OUT BOOL *pfTTLExpired + ) = 0; + + virtual + VOID + SetFlushed( + VOID + ) = 0; + + virtual + BOOL + GetFlushed( + VOID + ) const = 0; +}; + +// +// Site descriptor +// +class __declspec(uuid("eb16a6ec-ba5d-436f-bf24-3ede13906450")) +IHttpSite +{ + public: + virtual + DWORD + GetSiteId( + VOID + ) const = 0; + + virtual + PCWSTR + GetSiteName( + VOID + ) const = 0; + + virtual + IHttpModuleContextContainer * + GetModuleContextContainer( + VOID + ) = 0; + + virtual + IHttpPerfCounterInfo * + GetPerfCounterInfo( + VOID + ) = 0; +}; + +// +// File change monitor +// +// +class __declspec(uuid("985422da-b0cf-473b-ba9e-8148ceb3e240")) +IHttpFileMonitor +{ + public: + virtual + IHttpModuleContextContainer * + GetModuleContextContainer( + VOID + ) = 0; + + virtual + VOID + DereferenceFileMonitor( + VOID + ) = 0; +}; + +// +// File descriptor +// +// +class __declspec(uuid("71e95595-8c74-44d9-88a9-f5112d5f5900")) +IHttpFileInfo : public IHttpCacheSpecificData +{ + public: + virtual + DWORD + GetAttributes( + VOID + ) const = 0; + + virtual + VOID + GetSize( + OUT ULARGE_INTEGER * pliSize + ) const = 0; + + virtual + const BYTE * + GetFileBuffer( + VOID + ) const = 0; + + virtual + HANDLE + GetFileHandle( + VOID + ) const = 0; + + virtual + PCWSTR + GetFilePath( + VOID + ) const = 0; + + virtual + PCSTR + GetETag( + OUT USHORT * pcchETag = NULL + ) const = 0; + + virtual + VOID + GetLastModifiedTime( + OUT FILETIME * pFileTime + ) const = 0; + + virtual + PCSTR + GetLastModifiedString( + VOID + ) const = 0; + + virtual + BOOL + GetHttpCacheAllowed( + OUT DWORD * pSecondsToLive + ) const = 0; + + virtual + HRESULT + AccessCheck( + IN HANDLE hUserToken, + IN PSID pUserSid + ) = 0; + + virtual + HANDLE + GetVrToken( + VOID + ) const = 0; + + virtual + PCWSTR + GetVrPath( + VOID + ) const = 0; + + virtual + IHttpModuleContextContainer * + GetModuleContextContainer( + VOID + ) = 0; + + virtual + BOOL + CheckIfFileHasChanged( + IN HANDLE hUserToken + ) = 0; +}; + + +// +// Token-cache entry +// +class __declspec(uuid("fd86e6de-fb0e-47dd-820a-e0da12be46e9")) +IHttpTokenEntry : public IHttpCacheSpecificData +{ + public: + virtual + HANDLE + GetImpersonationToken( + VOID + ) = 0; + + virtual + HANDLE + GetPrimaryToken( + VOID + ) = 0; + + virtual + PSID + GetSid( + VOID + ) = 0; +}; + + +// +// IHttpServer extended interface versions +// +enum HTTP_SERVER_INTERFACE_VERSION +{ + HTTP_SERVER_INTERFACE_V2 +}; + + +// +// Global utility descriptor +// +class __declspec(uuid("eda2a40f-fb92-4d6d-b52b-c8c207380b4e")) +IHttpServer +{ + public: + virtual + BOOL + IsCommandLineLaunch( + VOID + ) const = 0; + + virtual + PCWSTR + GetAppPoolName( + VOID + ) const = 0; + + virtual + HRESULT + AssociateWithThreadPool( + IN HANDLE hHandle, + IN LPOVERLAPPED_COMPLETION_ROUTINE completionRoutine + ) = 0; + + virtual + VOID + IncrementThreadCount( + VOID + ) = 0; + + virtual + VOID + DecrementThreadCount( + VOID + ) = 0; + + virtual + VOID + ReportUnhealthy( + IN PCWSTR pszReasonString, + IN HRESULT hrReason + ) = 0; + + virtual + VOID + RecycleProcess( + PCWSTR pszReason + ) = 0; + + virtual + IAppHostAdminManager * + GetAdminManager( + VOID + ) const = 0; + + virtual + HRESULT + GetFileInfo( + IN PCWSTR pszPhysicalPath, + IN HANDLE hUserToken, + IN PSID pSid, + IN PCWSTR pszChangeNotificationPath, + IN HANDLE hChangeNotificationToken, + IN BOOL fCache, + OUT IHttpFileInfo ** ppFileInfo, + IN IHttpTraceContext * pHttpTraceContext = NULL + ) = 0; + + virtual + HRESULT + FlushKernelCache( + IN PCWSTR pszUrl + ) = 0; + + virtual + HRESULT + DoCacheOperation( + IN CACHE_OPERATION cacheOperation, + IN IHttpCacheKey * pCacheKey, + OUT IHttpCacheSpecificData ** ppCacheSpecificData, + IN IHttpTraceContext * pHttpTraceContext = NULL + ) = 0; + + virtual + GLOBAL_NOTIFICATION_STATUS + NotifyCustomNotification( + ICustomNotificationProvider * pCustomOutput + ) = 0; + + virtual + IHttpPerfCounterInfo * + GetPerfCounterInfo( + VOID + ) = 0; + + virtual + VOID + RecycleApplication( + PCWSTR pszAppConfigPath + ) = 0; + + virtual + VOID + NotifyConfigurationChange( + PCWSTR pszPath + ) = 0; + + virtual + VOID + NotifyFileChange( + PCWSTR pszFileName + ) = 0; + + virtual + IDispensedHttpModuleContextContainer * + DispenseContainer( + VOID + ) = 0; + + virtual + HRESULT + AddFragmentToCache( + IN HTTP_DATA_CHUNK * pDataChunk, + PCWSTR pszFragmentName + ) = 0; + + virtual + HRESULT + ReadFragmentFromCache( + PCWSTR pszFragmentName, + OUT BYTE * pvBuffer, + DWORD cbSize, + OUT DWORD * pcbCopied + ) = 0; + + virtual + HRESULT + RemoveFragmentFromCache( + PCWSTR pszFragmentName + ) = 0; + + virtual + HRESULT + GetWorkerProcessSettings( + OUT IWpfSettings ** ppWorkerProcessSettings + ) = 0; + + virtual + HRESULT + GetProtocolManagerCustomInterface( + IN PCWSTR pProtocolManagerDll, + IN PCWSTR pProtocolManagerDllInitFunction, + IN DWORD dwCustomInterfaceId, + OUT PVOID* ppCustomInterface + ) = 0; + + virtual + BOOL + SatisfiesPrecondition( + PCWSTR pszPrecondition, + BOOL * pfUnknownPrecondition = NULL + ) const = 0; + + virtual + IHttpTraceContext * + GetTraceContext( + VOID + ) const = 0; + + virtual + HRESULT + RegisterFileChangeMonitor( + PCWSTR pszPath, + HANDLE hToken, + IHttpFileMonitor ** ppFileMonitor + ) = 0; + + virtual + HRESULT + GetExtendedInterface( + IN HTTP_SERVER_INTERFACE_VERSION version, + OUT PVOID * ppInterface + ) = 0; +}; + +class __declspec(uuid("34af637e-afe8-4556-bcc1-767f8e0b4a4e")) +IHttpServer2 : public IHttpServer +{ + public: + + virtual + HRESULT + GetToken( + PCWSTR pszUserName, + PCWSTR pszPassword, + DWORD dwLogonMethod, + IHttpTokenEntry ** ppTokenEntry, + PCWSTR pszDefaultDomain = NULL, + PSOCKADDR pSockAddr = NULL, + IHttpTraceContext * pHttpTraceContext = NULL + ) = 0; + + virtual + PCWSTR + GetAppPoolConfigFile( + __out DWORD * pcchConfigFilePath = NULL + ) const = 0; + + virtual + HRESULT + GetExtendedInterface( + __in const GUID & Version1, + __in PVOID pInput, + __in const GUID & Version2, + __deref_out PVOID * ppOutput + ) = 0; +}; + +// +// Helper function to get extended HTTP interfaces. +// +// Template parameters (HttpType1 and HttpType2) +// can be deduced from the arguments to the function. +// +// Example: +// +// IHttpRequest * pHttpRequest = pHttpContext->GetRequest(); +// IHttpRequest2 * pHttpRequest2; +// HRESULT hr = HttpGetExtendedInterface(g_pHttpServer, pHttpRequest, &pHttpRequest2); +// if( SUCCEEDED(hr) ) +// { +// // Use pHttpRequest2. +// } +// +// Where pHttpContext is an IHttpContext pointer and +// g_pHttpServer is an IHttpServer pointer. +// + +template +HRESULT +HttpGetExtendedInterface( + __in IHttpServer * pHttpServer, + __in HttpType1 * pInput, + __deref_out HttpType2 ** ppOutput +) +{ + HRESULT hr; + IHttpServer2 * pHttpServer2; + hr = pHttpServer->GetExtendedInterface(HTTP_SERVER_INTERFACE_V2, + reinterpret_cast(&pHttpServer2) ); + if (SUCCEEDED(hr)) + { + hr = pHttpServer2->GetExtendedInterface(__uuidof(HttpType1), + pInput, + __uuidof(HttpType2), + reinterpret_cast(ppOutput) ); + } + return hr; +} + +// +// Notification specific output for notifications +// +class __declspec(uuid("6f3f657d-2fb8-43c6-a096-5064b41f0580")) +IHttpEventProvider +{ + public: + virtual + VOID + SetErrorStatus( + HRESULT hrError + ) = 0; +}; + +// +// Completion information for notifications +// +class __declspec(uuid("49dd20e3-d9c0-463c-8821-f3413b55cc00")) +IHttpCompletionInfo +{ + public: + virtual + DWORD + GetCompletionBytes( + VOID + ) const = 0; + + virtual + HRESULT + GetCompletionStatus( + VOID + ) const = 0; +}; + +// +// RQ_ and GL_ CUSTOM_NOTIFICATION outputs +// +class __declspec(uuid("671e6d34-9380-4df4-b453-91129df02b24")) +ICustomNotificationProvider : public IHttpEventProvider +{ + public: + virtual + PCWSTR + QueryNotificationType( + VOID + ) = 0; +}; + +// +// RQ_REQUEST_AUTHENTICATE descriptor +// +class __declspec(uuid("304d51d0-0307-45ed-83fd-dd3fc032fdfc")) +IAuthenticationProvider : public IHttpEventProvider +{ + public: + virtual + VOID + SetUser( + IN IHttpUser * pUser + ) = 0; +}; + +// +// RQ_MAP_REQUEST_HANDLER +// +class __declspec(uuid("fea3ce6b-e346-47e7-b2a6-ad265baeff2c")) +IMapHandlerProvider : public IHttpEventProvider +{ + public: + virtual + HRESULT + SetScriptName( + PCWSTR pszScriptName, + DWORD cchScriptName + ) = 0; + + virtual + VOID + SetScriptMap( + IN IScriptMapInfo * pScriptMap + ) = 0; + + virtual + VOID + SetFileInfo( + IN IHttpFileInfo * pFileInfo + ) = 0; +}; + +// +// RQ_MAP_PATH +// +class __declspec(uuid("8efdf557-a8f1-4bc9-b462-6df3b038a59a")) +IMapPathProvider : public IHttpEventProvider +{ + public: + virtual + PCWSTR + GetUrl( + ) const = 0; + + virtual + PCWSTR + GetPhysicalPath( + ) const = 0; + + virtual + HRESULT + SetPhysicalPath( + PCWSTR pszPhysicalPath, + DWORD cchPhysicalPath + ) = 0; +}; + +// +// RQ_SEND_RESPONSE +// +class __declspec(uuid("57f2e7bc-0bcf-4a9f-94a4-10e55c6e5b51")) +ISendResponseProvider : public IHttpEventProvider +{ + public: + virtual + BOOL + GetHeadersBeingSent( + VOID + ) const = 0; + + virtual + DWORD + GetFlags( + VOID + ) const = 0; + + virtual + VOID + SetFlags( + DWORD dwFlags + ) = 0; + + virtual + HTTP_LOG_DATA * + GetLogData( + VOID + ) const = 0; + + virtual + HRESULT + SetLogData( + IN HTTP_LOG_DATA *pLogData + ) = 0; + + virtual + BOOL + GetReadyToLogData( + VOID + ) const = 0; +}; + +// +// RQ_READ_ENTITY +// +class __declspec(uuid("fe6d905a-99b8-49fd-b389-cfc809562b81")) +IReadEntityProvider : public IHttpEventProvider +{ + public: + virtual + VOID + GetEntity( + OUT PVOID * ppBuffer, + OUT DWORD * pcbData, + OUT DWORD * pcbBuffer + ) = 0; + + virtual + VOID + SetEntity( + IN PVOID pBuffer, + DWORD cbData, + DWORD cbBuffer + ) = 0; +}; + +// +// GL_PRE_BEGIN_REQUEST provider +// +class __declspec(uuid("fb715d26-aff9-476a-8fc0-6b1acb3d1098")) +IPreBeginRequestProvider : public IHttpEventProvider +{ + public: + virtual + IHttpContext * + GetHttpContext( + VOID + ) = 0; +}; + +// +// GL_APPLICATION_START provider +// +class __declspec(uuid("1de2c71c-c126-4512-aed3-f4f885e14997")) +IHttpApplicationProvider : public IHttpEventProvider +{ + public: + virtual + IHttpApplication * + GetApplication( + VOID + ) = 0; +}; + +typedef IHttpApplicationProvider IHttpApplicationStartProvider; + +class __declspec(uuid("ba32d330-9ea8-4b9e-89f1-8c76a323277f")) +IHttpModuleFactory; + +// +// GL_APPLICATION_RESOLVE_MODULES provider +// +class __declspec(uuid("0617d9b9-e20f-4a9f-94f9-35403b3be01e")) +IHttpApplicationResolveModulesProvider : public IHttpApplicationProvider +{ + public: + virtual + HRESULT + RegisterModule( + IN HTTP_MODULE_ID parentModuleId, + IN IHttpModuleFactory * pModuleFactory, + IN PCWSTR pszModuleName, + IN PCWSTR pszModuleType, + IN PCWSTR pszModulePreCondition, + IN DWORD dwRequestNotifications, + IN DWORD dwPostRequestNotifications + ) = 0; + + virtual + HRESULT + SetPriorityForRequestNotification( + IN PCWSTR pszModuleName, + IN DWORD dwRequestNotification, + IN PCWSTR pszPriorityAlias + ) = 0; +}; + +// +// GL_APPLICATION_STOP provider +// +typedef IHttpApplicationProvider IHttpApplicationStopProvider; + +// +// GL_RSCA_QUERY provider +// +class __declspec(uuid("63fdc43f-934a-4ee5-bcd8-7e7b50b75605")) +IGlobalRSCAQueryProvider : public IHttpEventProvider +{ + public: + virtual + PCWSTR + GetFunctionName( + VOID + ) const = 0; + + virtual + PCWSTR + GetFunctionParameters( + VOID + ) const = 0; + + virtual + HRESULT + GetOutputBuffer( + DWORD cbBuffer, + OUT BYTE ** ppbBuffer + ) = 0; + + virtual + HRESULT + ResizeOutputBuffer( + DWORD cbNewBuffer, + DWORD cbBytesToCopy, + IN OUT BYTE ** ppbBuffer + ) = 0; + + virtual + VOID + SetResult( + DWORD cbData, + HRESULT hr + ) = 0; +}; + +// +// GL_STOP_LISTENING +// +class __declspec(uuid("41f9a601-e25d-4ac8-8a1f-635698a30ab9")) +IGlobalStopListeningProvider : public IHttpEventProvider +{ + public: + virtual + BOOL + DrainRequestsGracefully( + VOID + ) const = 0; +}; + +// +// GL_CACHE_OPERATION +// +class __declspec(uuid("58925fb9-7c5e-4684-833b-4a04e1286690")) +ICacheProvider : public IHttpEventProvider +{ + public: + virtual + CACHE_OPERATION + GetCacheOperation( + VOID + ) const = 0; + + virtual + IHttpCacheKey * + GetCacheKey( + VOID + ) const = 0; + + virtual + IHttpCacheSpecificData * + GetCacheRecord( + VOID + ) const = 0; + + virtual + VOID + SetCacheRecord( + IHttpCacheSpecificData * pCacheRecord + ) = 0; + + virtual + IHttpTraceContext * + GetTraceContext( + VOID + ) const = 0; +}; + +// +// GL_CONFIGURATION_CHANGE +// +class __declspec(uuid("3405f3b4-b3d6-4b73-b5f5-4d8a3cc642ce")) +IGlobalConfigurationChangeProvider : public IHttpEventProvider +{ + public: + virtual + PCWSTR + GetChangePath( + VOID + ) const = 0; +}; + +// +// GL_FILE_CHANGE +// +class __declspec(uuid("ece31ee5-0486-4fb0-a875-6739a2d7daf5")) +IGlobalFileChangeProvider : public IHttpEventProvider +{ +public: + virtual + PCWSTR + GetFileName( + VOID + ) const = 0; + + virtual + IHttpFileMonitor * + GetFileMonitor( + VOID + ) = 0; +}; + +// +// GL_TRACE_EVENT +// +class __declspec(uuid("7c6bb150-0310-4718-a01f-6faceb62dc1d")) +IGlobalTraceEventProvider : public IHttpEventProvider +{ + public: + virtual + HRESULT + GetTraceEvent( + OUT HTTP_TRACE_EVENT ** ppTraceEvent + ) = 0; + + virtual + BOOL + CheckSubscription( + IN HTTP_MODULE_ID ModuleId + ) = 0; + + virtual + HRESULT + GetCurrentHttpRequestContext( + OUT IHttpContext ** ppHttpContext + ) = 0; +}; + +// +// GL_THREAD_CLEANUP +// +class __declspec(uuid("6b36a149-8620-45a0-8197-00814a706e2e")) +IGlobalThreadCleanupProvider : public IHttpEventProvider +{ +public: + virtual + IHttpApplication * + GetApplication( + VOID + ) = 0; +}; + +// +// GL_APPLICATION_PRELOAD +// +class __declspec(uuid("2111f8d6-0c41-4ff7-bd45-5c04c7e91a73")) +IGlobalApplicationPreloadProvider : public IHttpEventProvider +{ +public: + virtual + HRESULT + CreateContext( + OUT IHttpContext ** ppHttpContext + ) = 0; + + virtual + HRESULT + ExecuteRequest( + IN IHttpContext * pHttpContext, + IN IHttpUser * pHttpUser + ) = 0; +}; + +class CHttpModule +{ +public: + // RQ_BEGIN_REQUEST + + virtual + REQUEST_NOTIFICATION_STATUS + OnBeginRequest( + IN IHttpContext * pHttpContext, + IN IHttpEventProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pHttpContext ); + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CHttpModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return RQ_NOTIFICATION_CONTINUE; + } + + virtual + REQUEST_NOTIFICATION_STATUS + OnPostBeginRequest( + IN IHttpContext * pHttpContext, + IN IHttpEventProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pHttpContext ); + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CHttpModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return RQ_NOTIFICATION_CONTINUE; + } + + + // RQ_AUTHENTICATE_REQUEST + + virtual + REQUEST_NOTIFICATION_STATUS + OnAuthenticateRequest( + IN IHttpContext * pHttpContext, + IN IAuthenticationProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pHttpContext ); + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CHttpModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return RQ_NOTIFICATION_CONTINUE; + } + + + virtual + REQUEST_NOTIFICATION_STATUS + OnPostAuthenticateRequest( + IN IHttpContext * pHttpContext, + IN IHttpEventProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pHttpContext ); + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CHttpModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return RQ_NOTIFICATION_CONTINUE; + } + + + // RQ_AUTHORIZE_REQUEST + + virtual + REQUEST_NOTIFICATION_STATUS + OnAuthorizeRequest( + IN IHttpContext * pHttpContext, + IN IHttpEventProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pHttpContext ); + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CHttpModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return RQ_NOTIFICATION_CONTINUE; + } + + + virtual + REQUEST_NOTIFICATION_STATUS + OnPostAuthorizeRequest( + IN IHttpContext * pHttpContext, + IN IHttpEventProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pHttpContext ); + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CHttpModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return RQ_NOTIFICATION_CONTINUE; + } + + + // RQ_RESOLVE_REQUEST_CACHE + + virtual + REQUEST_NOTIFICATION_STATUS + OnResolveRequestCache( + IN IHttpContext * pHttpContext, + IN IHttpEventProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pHttpContext ); + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CHttpModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return RQ_NOTIFICATION_CONTINUE; + } + + + virtual + REQUEST_NOTIFICATION_STATUS + OnPostResolveRequestCache( + IN IHttpContext * pHttpContext, + IN IHttpEventProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pHttpContext ); + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CHttpModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return RQ_NOTIFICATION_CONTINUE; + } + + + // RQ_MAP_REQUEST_HANDLER + + virtual + REQUEST_NOTIFICATION_STATUS + OnMapRequestHandler( + IN IHttpContext * pHttpContext, + IN IMapHandlerProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pHttpContext ); + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CHttpModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return RQ_NOTIFICATION_CONTINUE; + } + + + virtual + REQUEST_NOTIFICATION_STATUS + OnPostMapRequestHandler( + IN IHttpContext * pHttpContext, + IN IHttpEventProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pHttpContext ); + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CHttpModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return RQ_NOTIFICATION_CONTINUE; + } + + + // RQ_ACQUIRE_REQUEST_STATE + + virtual + REQUEST_NOTIFICATION_STATUS + OnAcquireRequestState( + IN IHttpContext * pHttpContext, + IN IHttpEventProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pHttpContext ); + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CHttpModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return RQ_NOTIFICATION_CONTINUE; + } + + + virtual + REQUEST_NOTIFICATION_STATUS + OnPostAcquireRequestState( + IN IHttpContext * pHttpContext, + IN IHttpEventProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pHttpContext ); + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CHttpModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return RQ_NOTIFICATION_CONTINUE; + } + + + // RQ_PRE_EXECUTE_REQUEST_HANDLER + + virtual + REQUEST_NOTIFICATION_STATUS + OnPreExecuteRequestHandler( + IN IHttpContext * pHttpContext, + IN IHttpEventProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pHttpContext ); + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CHttpModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return RQ_NOTIFICATION_CONTINUE; + } + + + virtual + REQUEST_NOTIFICATION_STATUS + OnPostPreExecuteRequestHandler( + IN IHttpContext * pHttpContext, + IN IHttpEventProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pHttpContext ); + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CHttpModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return RQ_NOTIFICATION_CONTINUE; + } + + + // RQ_EXECUTE_REQUEST_HANDLER + + virtual + REQUEST_NOTIFICATION_STATUS + OnExecuteRequestHandler( + IN IHttpContext * pHttpContext, + IN IHttpEventProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pHttpContext ); + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CHttpModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return RQ_NOTIFICATION_CONTINUE; + } + + + virtual + REQUEST_NOTIFICATION_STATUS + OnPostExecuteRequestHandler( + IN IHttpContext * pHttpContext, + IN IHttpEventProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pHttpContext ); + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CHttpModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return RQ_NOTIFICATION_CONTINUE; + } + + // RQ_RELEASE_REQUEST_STATE + + virtual + REQUEST_NOTIFICATION_STATUS + OnReleaseRequestState( + IN IHttpContext * pHttpContext, + IN IHttpEventProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pHttpContext ); + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CHttpModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return RQ_NOTIFICATION_CONTINUE; + } + + + virtual + REQUEST_NOTIFICATION_STATUS + OnPostReleaseRequestState( + IN IHttpContext * pHttpContext, + IN IHttpEventProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pHttpContext ); + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CHttpModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return RQ_NOTIFICATION_CONTINUE; + } + + + // RQ_UPDATE_REQUEST_CACHE + + virtual + REQUEST_NOTIFICATION_STATUS + OnUpdateRequestCache( + IN IHttpContext * pHttpContext, + IN IHttpEventProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pHttpContext ); + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CHttpModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return RQ_NOTIFICATION_CONTINUE; + } + + + virtual + REQUEST_NOTIFICATION_STATUS + OnPostUpdateRequestCache( + IN IHttpContext * pHttpContext, + IN IHttpEventProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pHttpContext ); + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CHttpModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return RQ_NOTIFICATION_CONTINUE; + } + + // RQ_LOG_REQUEST + + virtual + REQUEST_NOTIFICATION_STATUS + OnLogRequest( + IN IHttpContext * pHttpContext, + IN IHttpEventProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pHttpContext ); + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CHttpModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return RQ_NOTIFICATION_CONTINUE; + } + + virtual + REQUEST_NOTIFICATION_STATUS + OnPostLogRequest( + IN IHttpContext * pHttpContext, + IN IHttpEventProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pHttpContext ); + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CHttpModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return RQ_NOTIFICATION_CONTINUE; + } + + // RQ_END_REQUEST + + virtual + REQUEST_NOTIFICATION_STATUS + OnEndRequest( + IN IHttpContext * pHttpContext, + IN IHttpEventProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pHttpContext ); + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CHttpModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return RQ_NOTIFICATION_CONTINUE; + } + + virtual + REQUEST_NOTIFICATION_STATUS + OnPostEndRequest( + IN IHttpContext * pHttpContext, + IN IHttpEventProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pHttpContext ); + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CHttpModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return RQ_NOTIFICATION_CONTINUE; + } + + // RQ_SEND_RESPONSE + + virtual + REQUEST_NOTIFICATION_STATUS + OnSendResponse( + IN IHttpContext * pHttpContext, + IN ISendResponseProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pHttpContext ); + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CHttpModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return RQ_NOTIFICATION_CONTINUE; + } + + // RQ_MAP_PATH + + virtual + REQUEST_NOTIFICATION_STATUS + OnMapPath( + IN IHttpContext * pHttpContext, + IN IMapPathProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pHttpContext ); + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CHttpModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return RQ_NOTIFICATION_CONTINUE; + } + + // RQ_READ_ENTITY + + virtual + REQUEST_NOTIFICATION_STATUS + OnReadEntity( + IN IHttpContext * pHttpContext, + IN IReadEntityProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pHttpContext ); + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CHttpModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return RQ_NOTIFICATION_CONTINUE; + } + + // RQ_CUSTOM_NOTIFICATION + + virtual + REQUEST_NOTIFICATION_STATUS + OnCustomRequestNotification( + IN IHttpContext * pHttpContext, + IN ICustomNotificationProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pHttpContext ); + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CHttpModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return RQ_NOTIFICATION_CONTINUE; + } + + // Completion + + virtual + REQUEST_NOTIFICATION_STATUS + OnAsyncCompletion( + IN IHttpContext * pHttpContext, + IN DWORD dwNotification, + IN BOOL fPostNotification, + IN IHttpEventProvider * pProvider, + IN IHttpCompletionInfo * pCompletionInfo + ) + { + UNREFERENCED_PARAMETER( pHttpContext ); + UNREFERENCED_PARAMETER( dwNotification ); + UNREFERENCED_PARAMETER( fPostNotification ); + UNREFERENCED_PARAMETER( pProvider ); + UNREFERENCED_PARAMETER( pCompletionInfo ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CHttpModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return RQ_NOTIFICATION_CONTINUE; + } + + virtual + VOID + Dispose( + VOID + ) + { + delete this; + } + + protected: + + CHttpModule() + {} + + virtual + ~CHttpModule() + {} +}; + +class CGlobalModule +{ + public: + + // GL_STOP_LISTENING + + virtual + GLOBAL_NOTIFICATION_STATUS + OnGlobalStopListening( + IN IGlobalStopListeningProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CGlobalModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return GL_NOTIFICATION_CONTINUE; + } + + // GL_CACHE_CLEANUP + + virtual + GLOBAL_NOTIFICATION_STATUS + OnGlobalCacheCleanup( + VOID + ) + { + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CGlobalModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return GL_NOTIFICATION_CONTINUE; + } + + // GL_CACHE_OPERATION + + virtual + GLOBAL_NOTIFICATION_STATUS + OnGlobalCacheOperation( + IN ICacheProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CGlobalModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return GL_NOTIFICATION_CONTINUE; + } + + // GL_HEALTH_CHECK + + virtual + GLOBAL_NOTIFICATION_STATUS + OnGlobalHealthCheck( + VOID + ) + { + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CGlobalModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return GL_NOTIFICATION_CONTINUE; + } + + // GL_CONFIGURATION_CHANGE + + virtual + GLOBAL_NOTIFICATION_STATUS + OnGlobalConfigurationChange( + IN IGlobalConfigurationChangeProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CGlobalModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return GL_NOTIFICATION_CONTINUE; + } + + // GL_FILE_CHANGE + + virtual + GLOBAL_NOTIFICATION_STATUS + OnGlobalFileChange( + IN IGlobalFileChangeProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CGlobalModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return GL_NOTIFICATION_CONTINUE; + } + + // GL_PRE_BEGIN_REQUEST + + virtual + GLOBAL_NOTIFICATION_STATUS + OnGlobalPreBeginRequest( + IN IPreBeginRequestProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CGlobalModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return GL_NOTIFICATION_CONTINUE; + } + + // GL_APPLICATION_START + + virtual + GLOBAL_NOTIFICATION_STATUS + OnGlobalApplicationStart( + IN IHttpApplicationStartProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CGlobalModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return GL_NOTIFICATION_CONTINUE; + } + + // GL_APPLICATION_RESOLVE_MODULES + + virtual + GLOBAL_NOTIFICATION_STATUS + OnGlobalApplicationResolveModules( + IN IHttpApplicationResolveModulesProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CGlobalModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return GL_NOTIFICATION_CONTINUE; + } + + // GL_APPLICATION_STOP + + virtual + GLOBAL_NOTIFICATION_STATUS + OnGlobalApplicationStop( + IN IHttpApplicationStopProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CGlobalModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return GL_NOTIFICATION_CONTINUE; + } + + // GL_RSCA_QUERY + + virtual + GLOBAL_NOTIFICATION_STATUS + OnGlobalRSCAQuery( + IN IGlobalRSCAQueryProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CGlobalModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return GL_NOTIFICATION_CONTINUE; + } + + // GL_TRACE_EVENT + + virtual + GLOBAL_NOTIFICATION_STATUS + OnGlobalTraceEvent( + IN IGlobalTraceEventProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CGlobalModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return GL_NOTIFICATION_CONTINUE; + } + + // GL_CUSTOM_NOTIFICATION + + virtual + GLOBAL_NOTIFICATION_STATUS + OnGlobalCustomNotification( + IN ICustomNotificationProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CGlobalModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return GL_NOTIFICATION_CONTINUE; + } + + virtual + VOID + Terminate( + VOID + ) = 0; + + // GL_THREAD_CLEANUP + + virtual + GLOBAL_NOTIFICATION_STATUS + OnGlobalThreadCleanup( + IN IGlobalThreadCleanupProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CGlobalModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return GL_NOTIFICATION_CONTINUE; + } + + // GL_APPLICATION_PRELOAD + + virtual + GLOBAL_NOTIFICATION_STATUS + OnGlobalApplicationPreload( + IN IGlobalApplicationPreloadProvider * pProvider + ) + { + UNREFERENCED_PARAMETER( pProvider ); + OutputDebugStringA( + "This module subscribed to event " + __FUNCTION__ + " but did not override the method in its CGlobalModule implementation." + " Please check the method signature to make sure it matches the corresponding method.\n"); + DebugBreak(); + + return GL_NOTIFICATION_CONTINUE; + } + +}; + +class __declspec(uuid("85c1679c-0b21-491c-afb5-c7b5c86464c4")) +IModuleAllocator +{ + public: + virtual + VOID * + AllocateMemory( + IN DWORD cbAllocation + ) = 0; +}; + +class __declspec(uuid("ba32d330-9ea8-4b9e-89f1-8c76a323277f")) +IHttpModuleFactory +{ + public: + virtual + HRESULT + GetHttpModule( + OUT CHttpModule ** ppModule, + IN IModuleAllocator * pAllocator + ) = 0; + + virtual + VOID + Terminate( + VOID + ) = 0; +}; + +// +// Register-module descriptor +// +class __declspec(uuid("07e5beb3-b798-459d-a98a-e6c485b2b3bc")) +IHttpModuleRegistrationInfo +{ + public: + virtual + PCWSTR + GetName( + VOID + ) const = 0; + + virtual + HTTP_MODULE_ID + GetId( + VOID + ) const = 0; + + virtual + HRESULT + SetRequestNotifications( + IN IHttpModuleFactory * pModuleFactory, + IN DWORD dwRequestNotifications, + IN DWORD dwPostRequestNotifications + ) = 0; + + virtual + HRESULT + SetGlobalNotifications( + IN CGlobalModule * pGlobalModule, + IN DWORD dwGlobalNotifications + ) = 0; + + virtual + HRESULT + SetPriorityForRequestNotification( + IN DWORD dwRequestNotification, + IN PCWSTR pszPriority + ) = 0; + + virtual + HRESULT + SetPriorityForGlobalNotification( + IN DWORD dwGlobalNotification, + IN PCWSTR pszPriority + ) = 0; +}; + + +// +// Register Module entry point +// + +typedef +HRESULT +(WINAPI * PFN_REGISTERMODULE)( + DWORD dwServerVersion, + IHttpModuleRegistrationInfo * pModuleInfo, + IHttpServer * pGlobalInfo +); + +#define MODULE_REGISTERMODULE "RegisterModule" + +#endif diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/hybrid_array.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/hybrid_array.h new file mode 100644 index 0000000000..4d0d5735bc --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/hybrid_array.h @@ -0,0 +1,243 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +template +class HYBRID_ARRAY +{ +public: + + HYBRID_ARRAY( + VOID + ) : m_pArray(m_InlineArray), + m_Capacity(ARRAYSIZE(m_InlineArray)) + { + } + + ~HYBRID_ARRAY() + { + if ( !QueryUsesInlineArray() ) + { + delete [] m_pArray; + m_pArray = NULL; + } + } + + SIZE_T + QueryCapacity( + VOID + ) const + { + // + // Number of elements available in the array. + // + return m_Capacity; + } + + TYPE * + QueryArray( + VOID + ) const + { + // + // Raw pointer to the current array. + // + return m_pArray; + } + + TYPE & + QueryItem( + __in const SIZE_T Index + ) + { + // + // Gets the array item giving the index. + // + return m_pArray[Index]; + } + + TYPE & + operator [] (const SIZE_T Index) + { + // + // Operator override for convenience. + // Please don't add other overloads like '++' '--' + // in order to keep it simple. + // + return m_pArray[Index]; + } + + const TYPE & + operator [] (const SIZE_T Index) const + { + return m_pArray[Index]; + } + + template + HRESULT + Copy( + __in TYPE const (&SourceArray)[SourceSize], + __in bool fHasTrivialAssign = false + ) + /*++ + + Routine Description: + + Copies a source array like: + + int source[] = { 1, 2, 3 }; + hr = hybridArray.Copy( source ); + + It will statically determinate the length of the source array. + + Arguments: + + SourceArray - The array to copy. + SourceSize - The number of array elements. + fHasTrivialAssign - True if safe to perform buffer copy. + + Return Value: + + HRESULT + + --*/ + { + return Copy( SourceArray, SourceSize, fHasTrivialAssign ); + } + + HRESULT + Copy( + __in_ecount(SourceSize) + const TYPE * pSourceArray, + __in const SIZE_T SourceSize, + __in bool fHasTrivialAssign = false + ) + /*++ + + Routine Description: + + Copies a source array. + + Arguments: + + pSourceArray - The array to copy. + SourceSize - The number of array elements. + fHasTrivialAssign - True if safe to perform buffer copy. + + Return Value: + + HRESULT + + --*/ + { + HRESULT hr; + + hr = EnsureCapacity( SourceSize, + FALSE, // fCopyPrevious + FALSE ); // fHasTrivialAssign + if ( FAILED( hr ) ) + { + return hr; + } + + if ( fHasTrivialAssign ) // Future Work: use std::tr1::has_trivial_assign + { + CopyMemory(m_pArray, pSourceArray, m_Capacity * sizeof(TYPE)); + } + else + { + for ( SIZE_T Index = 0; Index < SourceSize; ++Index ) + { + m_pArray[Index] = pSourceArray[Index]; + } + } + + return S_OK; + } + + HRESULT + EnsureCapacity( + __in const SIZE_T MinimumCapacity, + __in bool fCopyPrevious, + __in bool fHasTrivialAssign = false + ) + /*++ + + Routine Description: + + Copies a source array. + + Arguments: + + MinimumCapacity - The expected length of the array. + fCopyPrevious - Must be always explicit parameter. + True if copy previous array data. + fHasTrivialAssign - True if safe to perform buffer copy. + + Return Value: + + HRESULT + + --*/ + { + // + // Caller is responsible for calculating a length that won't cause + // too many reallocations in the future. + // + + if ( MinimumCapacity <= ARRAYSIZE(m_InlineArray) ) + { + return S_OK; + } + + TYPE * pNewArray; + + pNewArray = new TYPE[ MinimumCapacity ]; + if ( pNewArray == NULL ) + { + return E_OUTOFMEMORY; + } + + if ( fCopyPrevious ) + { + if ( fHasTrivialAssign ) + { + CopyMemory(pNewArray, m_pArray, m_Capacity * sizeof(TYPE)); + } + else + { + for ( SIZE_T Index = 0; Index < m_Capacity; ++Index ) + { + pNewArray[Index] = m_pArray[Index]; + } + } + } + + if ( QueryUsesInlineArray() ) + { + m_pArray = pNewArray; + } + else + { + delete [] m_pArray; + m_pArray = pNewArray; + } + + m_Capacity = MinimumCapacity; + + return S_OK; + } + +private: + + bool + QueryUsesInlineArray( + VOID + ) const + { + return m_pArray == m_InlineArray; + } + + TYPE m_InlineArray[SIZE]; + TYPE * m_pArray; + SIZE_T m_Capacity; +}; \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/listentry.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/listentry.h new file mode 100644 index 0000000000..04c1d1ab46 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/listentry.h @@ -0,0 +1,163 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#pragma once + +#ifndef _LIST_ENTRY_H +#define _LIST_ENTRY_H + +// +// Doubly-linked list manipulation routines. +// + + +#define InitializeListHead32(ListHead) (\ + (ListHead)->Flink = (ListHead)->Blink = PtrToUlong((ListHead))) + + +FORCEINLINE +VOID +InitializeListHead( + IN PLIST_ENTRY ListHead + ) +{ + ListHead->Flink = ListHead->Blink = ListHead; +} + +FORCEINLINE +BOOLEAN +IsListEmpty( + IN const LIST_ENTRY * ListHead + ) +{ + return (BOOLEAN)(ListHead->Flink == ListHead); +} + +FORCEINLINE +BOOLEAN +RemoveEntryList( + IN PLIST_ENTRY Entry + ) +{ + PLIST_ENTRY Blink; + PLIST_ENTRY Flink; + + Flink = Entry->Flink; + Blink = Entry->Blink; + Blink->Flink = Flink; + Flink->Blink = Blink; + return (BOOLEAN)(Flink == Blink); +} + +FORCEINLINE +PLIST_ENTRY +RemoveHeadList( + IN PLIST_ENTRY ListHead + ) +{ + PLIST_ENTRY Flink; + PLIST_ENTRY Entry; + + Entry = ListHead->Flink; + Flink = Entry->Flink; + ListHead->Flink = Flink; + Flink->Blink = ListHead; + return Entry; +} + + + +FORCEINLINE +PLIST_ENTRY +RemoveTailList( + IN PLIST_ENTRY ListHead + ) +{ + PLIST_ENTRY Blink; + PLIST_ENTRY Entry; + + Entry = ListHead->Blink; + Blink = Entry->Blink; + ListHead->Blink = Blink; + Blink->Flink = ListHead; + return Entry; +} + + +FORCEINLINE +VOID +InsertTailList( + IN PLIST_ENTRY ListHead, + IN PLIST_ENTRY Entry + ) +{ + PLIST_ENTRY Blink; + + Blink = ListHead->Blink; + Entry->Flink = ListHead; + Entry->Blink = Blink; + Blink->Flink = Entry; + ListHead->Blink = Entry; +} + + +FORCEINLINE +VOID +InsertHeadList( + IN PLIST_ENTRY ListHead, + IN PLIST_ENTRY Entry + ) +{ + PLIST_ENTRY Flink; + + Flink = ListHead->Flink; + Entry->Flink = Flink; + Entry->Blink = ListHead; + Flink->Blink = Entry; + ListHead->Flink = Entry; +} + +FORCEINLINE +VOID +AppendTailList( + IN PLIST_ENTRY ListHead, + IN PLIST_ENTRY ListToAppend + ) +{ + PLIST_ENTRY ListEnd = ListHead->Blink; + + ListHead->Blink->Flink = ListToAppend; + ListHead->Blink = ListToAppend->Blink; + ListToAppend->Blink->Flink = ListHead; + ListToAppend->Blink = ListEnd; +} + +FORCEINLINE +PSINGLE_LIST_ENTRY +PopEntryList( + PSINGLE_LIST_ENTRY ListHead + ) +{ + PSINGLE_LIST_ENTRY FirstEntry; + FirstEntry = ListHead->Next; + if (FirstEntry != NULL) { + ListHead->Next = FirstEntry->Next; + } + + return FirstEntry; +} + + +FORCEINLINE +VOID +PushEntryList( + PSINGLE_LIST_ENTRY ListHead, + PSINGLE_LIST_ENTRY Entry + ) +{ + Entry->Next = ListHead->Next; + ListHead->Next = Entry; +} + + +#endif diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/macros.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/macros.h new file mode 100644 index 0000000000..56a67eb1c4 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/macros.h @@ -0,0 +1,63 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#ifndef _MACROS_H +#define _MACROS_H + +// +// The DIFF macro should be used around an expression involving pointer +// subtraction. The expression passed to DIFF is cast to a size_t type, +// allowing the result to be easily assigned to any 32-bit variable or +// passed to a function expecting a 32-bit argument. +// + +#define DIFF(x) ((size_t)(x)) + +// Change a hexadecimal digit to its numerical equivalent +#define TOHEX( ch ) \ + ((ch) > L'9' ? \ + (ch) >= L'a' ? \ + (ch) - L'a' + 10 : \ + (ch) - L'A' + 10 \ + : (ch) - L'0') + + +// Change a number to its Hexadecimal equivalent + +#define TODIGIT( nDigit ) \ + (CHAR)((nDigit) > 9 ? \ + (nDigit) - 10 + 'A' \ + : (nDigit) + '0') + + +inline int +SAFEIsSpace(UCHAR c) +{ + return isspace( c ); +} + +inline int +SAFEIsAlNum(UCHAR c) +{ + return isalnum( c ); +} + +inline int +SAFEIsAlpha(UCHAR c) +{ + return isalpha( c ); +} + +inline int +SAFEIsXDigit(UCHAR c) +{ + return isxdigit( c ); +} + +inline int +SAFEIsDigit(UCHAR c) +{ + return isdigit( c ); +} + +#endif // _MACROS_H diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/multisz.hxx b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/multisz.hxx new file mode 100644 index 0000000000..dd891b3252 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/multisz.hxx @@ -0,0 +1,225 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#ifndef _MULTISZ_HXX_ +#define _MULTISZ_HXX_ + +# include + + +/*++ + class MULTISZ: + + Intention: + A light-weight multi-string class supporting encapsulated string class. + + This object is derived from BUFFER class. + It maintains following state: + + m_fValid - whether this object is valid - + used only by MULTISZ() init functions + * NYI: I need to kill this someday * + m_cchLen - string length cached when we update the string. + m_cStrings - number of strings. + + Member Functions: + There are two categories of functions: + 1) Safe Functions - which do integrity checking of state + 2) UnSafe Functions - which do not do integrity checking, but + enable writing to the data stream freely. + (someday this will be enabled as Safe versions without + problem for users) + +--*/ +class MULTISZ : public BUFFER +{ +public: + + MULTISZ() + : BUFFER (), + m_cchLen ( 0), + m_cStrings(0) + { Reset(); } + + // creates a stack version of the MULTISZ object - uses passed in stack buffer + // MULTISZ does not free this pbInit on its own. + MULTISZ( __in_bcount(cbInit) WCHAR * pbInit, DWORD cbInit) + : BUFFER( (BYTE *) pbInit, cbInit), + m_cchLen (0), + m_cStrings(0) + {} + + MULTISZ( const WCHAR * pchInit ) + : BUFFER (), + m_cchLen ( 0), + m_cStrings(0) + { AuxInit(pchInit); } + + MULTISZ( const MULTISZ & str ) + : BUFFER (), + m_cchLen ( 0), + m_cStrings(0) + { AuxInit( str.QueryStr()); } + +// BOOL IsValid(VOID) const { return ( BUFFER::IsValid()) ; } + // + // Checks and returns TRUE if this string has no valid data else FALSE + // + BOOL IsEmpty( VOID) const { return ( *QueryStr() == L'\0'); } + + BOOL Append( const WCHAR * pchInit ) { + return ((pchInit != NULL) ? (AuxAppend( pchInit, + (DWORD) (::wcslen(pchInit)) * sizeof(WCHAR) + )) : + TRUE); + } + + + BOOL Append( const WCHAR * pchInit, DWORD cchLen ) { + return ((pchInit != NULL) ? (AuxAppend( pchInit, + cchLen * sizeof(WCHAR))) : + TRUE); + } + + BOOL Append( STRU & str ) + { return AuxAppend( str.QueryStr(), + (str.QueryCCH()) * sizeof(WCHAR)); } + + // Resets the internal string to be NULL string. Buffer remains cached. + VOID Reset( VOID) + { DBG_ASSERT( QueryPtr() != NULL); + QueryStr()[0] = L'\0'; + QueryStr()[1] = L'\0'; + m_cchLen = 2; + m_cStrings = 0; + } + + BOOL Copy( const WCHAR * pchInit, IN DWORD cbLen ) { + if ( QueryPtr() ) { Reset(); } + return ( (pchInit != NULL) ? + AuxAppend( pchInit, cbLen, FALSE ): + TRUE); + } + + BOOL Copy( const MULTISZ & str ) + { return ( Copy(str.QueryStr(), str.QueryCB())); } + + // + // Returns the number of bytes in the string including the terminating + // NULLs + // + UINT QueryCB( VOID ) const + { return ( m_cchLen * sizeof(WCHAR)); } + + // + // Returns # of characters in the string including the terminating NULLs + // + UINT QueryCCH( VOID ) const { return (m_cchLen); } + + // + // Returns # of strings in the multisz. + // + + DWORD QueryStringCount( VOID ) const { return m_cStrings; } + + // + // Makes a copy of the stored string in given buffer + // + BOOL CopyToBuffer( __out_ecount_opt(*lpcch) WCHAR * lpszBuffer, LPDWORD lpcch) const; + + // + // Return the string buffer + // + WCHAR * QueryStrA( VOID ) const { return ( QueryStr()); } + WCHAR * QueryStr( VOID ) const { return ((WCHAR *) QueryPtr()); } + + // + // Makes a clone of the current string in the string pointer passed in. + // + BOOL + Clone( OUT MULTISZ * pstrClone) const + { + return ((pstrClone == NULL) ? + (SetLastError(ERROR_INVALID_PARAMETER), FALSE) : + (pstrClone->Copy( *this)) + ); + } // MULTISZ::Clone() + + // + // Recalculates the length of *this because we've modified the buffers + // directly + // + + VOID RecalcLen( VOID ) + { m_cchLen = MULTISZ::CalcLength( QueryStr(), &m_cStrings ); } + + // + // Calculate total character length of a MULTI_SZ, including the + // terminating NULLs. + // + + static DWORD CalcLength( const WCHAR * str, + LPDWORD pcStrings = NULL ); + + // + // Determine if the MULTISZ contains a specific string. + // + + BOOL FindString( const WCHAR * str ); + + BOOL FindString( STRU & str ) + { return FindString( str.QueryStr() ); } + + // + // Determine if the MULTISZ contains a specific string - case-insensitive + // + + BOOL FindStringNoCase( const WCHAR * str ); + + BOOL FindStringNoCase( STRU & str ) + { return FindStringNoCase( str.QueryStr() ); } + + // + // Used for scanning a multisz. + // + + const WCHAR * First( VOID ) const + { return *QueryStr() == L'\0' ? NULL : QueryStr(); } + + const WCHAR * Next( const WCHAR * Current ) const + { Current += ::wcslen( Current ) + 1; + return *Current == L'\0' ? NULL : Current; } + + BOOL + Equals( + MULTISZ* pmszRhs + ); + +private: + + DWORD m_cchLen; + DWORD m_cStrings; + VOID AuxInit( const WCHAR * pInit ); + BOOL AuxAppend( const WCHAR * pInit, + UINT cbStr, BOOL fAddSlop = TRUE ); + +}; + +// +// Quick macro for declaring a MULTISZ that will use stack memory of +// bytes. If the buffer overflows then a heap buffer will be allocated +// + +#define STACK_MULTISZ( name, size ) WCHAR __ach##name[size]; \ + MULTISZ name( __ach##name, sizeof( __ach##name )) + +HRESULT +SplitCommaDelimitedString( + PCWSTR pszList, + BOOL fTrimEntries, + BOOL fRemoveEmptyEntries, + MULTISZ * pmszList +); + +#endif // !_MULTISZ_HXX_ + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/multisza.hxx b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/multisza.hxx new file mode 100644 index 0000000000..44aa802563 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/multisza.hxx @@ -0,0 +1,225 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#ifndef _MULTISZA_HXX_ +#define _MULTISZA_HXX_ + +# include + + +/*++ + class MULTISZ: + + Intention: + A light-weight multi-string class supporting encapsulated string class. + + This object is derived from BUFFER class. + It maintains following state: + + m_fValid - whether this object is valid - + used only by MULTISZ() init functions + * NYI: I need to kill this someday * + m_cchLen - string length cached when we update the string. + m_cStrings - number of strings. + + Member Functions: + There are two categories of functions: + 1) Safe Functions - which do integrity checking of state + 2) UnSafe Functions - which do not do integrity checking, but + enable writing to the data stream freely. + (someday this will be enabled as Safe versions without + problem for users) + +--*/ +class MULTISZA : public BUFFER +{ +public: + + MULTISZA() + : BUFFER (), + m_cchLen ( 0), + m_cStrings(0) + { Reset(); } + + // creates a stack version of the MULTISZA object - uses passed in stack buffer + // MULTISZA does not free this pbInit on its own. + MULTISZA( __in_bcount(cbInit) CHAR * pbInit, DWORD cbInit) + : BUFFER( (BYTE *) pbInit, cbInit), + m_cchLen (0), + m_cStrings(0) + {} + + MULTISZA( const CHAR * pchInit ) + : BUFFER (), + m_cchLen ( 0), + m_cStrings(0) + { AuxInit(pchInit); } + + MULTISZA( const MULTISZA & str ) + : BUFFER (), + m_cchLen ( 0), + m_cStrings(0) + { AuxInit( str.QueryStr()); } + +// BOOL IsValid(VOID) const { return ( BUFFER::IsValid()) ; } + // + // Checks and returns TRUE if this string has no valid data else FALSE + // + BOOL IsEmpty( VOID) const { return ( *QueryStr() == L'\0'); } + + BOOL Append( const CHAR * pchInit ) { + return ((pchInit != NULL) ? (AuxAppend( pchInit, + (DWORD) (::strlen(pchInit)) * sizeof(CHAR) + )) : + TRUE); + } + + + BOOL Append( const CHAR * pchInit, DWORD cchLen ) { + return ((pchInit != NULL) ? (AuxAppend( pchInit, + cchLen * sizeof(CHAR))) : + TRUE); + } + + BOOL Append( STRA & str ) + { return AuxAppend( str.QueryStr(), + (str.QueryCCH()) * sizeof(CHAR)); } + + // Resets the internal string to be NULL string. Buffer remains cached. + VOID Reset( VOID) + { DBG_ASSERT( QueryPtr() != NULL); + QueryStr()[0] = L'\0'; + QueryStr()[1] = L'\0'; + m_cchLen = 2; + m_cStrings = 0; + } + + BOOL Copy( const CHAR * pchInit, IN DWORD cbLen ) { + if ( QueryPtr() ) { Reset(); } + return ( (pchInit != NULL) ? + AuxAppend( pchInit, cbLen, FALSE ): + TRUE); + } + + BOOL Copy( const MULTISZA & str ) + { return ( Copy(str.QueryStr(), str.QueryCB())); } + + // + // Returns the number of bytes in the string including the terminating + // NULLs + // + UINT QueryCB( VOID ) const + { return ( m_cchLen * sizeof(CHAR)); } + + // + // Returns # of characters in the string including the terminating NULLs + // + UINT QueryCCH( VOID ) const { return (m_cchLen); } + + // + // Returns # of strings in the MULTISZA. + // + + DWORD QueryStringCount( VOID ) const { return m_cStrings; } + + // + // Makes a copy of the stored string in given buffer + // + BOOL CopyToBuffer( __out_ecount_opt(*lpcch) CHAR * lpszBuffer, LPDWORD lpcch) const; + + // + // Return the string buffer + // + CHAR * QueryStrA( VOID ) const { return ( QueryStr()); } + CHAR * QueryStr( VOID ) const { return ((CHAR *) QueryPtr()); } + + // + // Makes a clone of the current string in the string pointer passed in. + // + BOOL + Clone( OUT MULTISZA * pstrClone) const + { + return ((pstrClone == NULL) ? + (SetLastError(ERROR_INVALID_PARAMETER), FALSE) : + (pstrClone->Copy( *this)) + ); + } // MULTISZA::Clone() + + // + // Recalculates the length of *this because we've modified the buffers + // directly + // + + VOID RecalcLen( VOID ) + { m_cchLen = MULTISZA::CalcLength( QueryStr(), &m_cStrings ); } + + // + // Calculate total character length of a MULTI_SZ, including the + // terminating NULLs. + // + + static DWORD CalcLength( const CHAR * str, + LPDWORD pcStrings = NULL ); + + // + // Determine if the MULTISZA contains a specific string. + // + + BOOL FindString( const CHAR * str ); + + BOOL FindString( STRA & str ) + { return FindString( str.QueryStr() ); } + + // + // Determine if the MULTISZA contains a specific string - case-insensitive + // + + BOOL FindStringNoCase( const CHAR * str ); + + BOOL FindStringNoCase( STRA & str ) + { return FindStringNoCase( str.QueryStr() ); } + + // + // Used for scanning a MULTISZA. + // + + const CHAR * First( VOID ) const + { return *QueryStr() == L'\0' ? NULL : QueryStr(); } + + const CHAR * Next( const CHAR * Current ) const + { Current += ::strlen( Current ) + 1; + return *Current == L'\0' ? NULL : Current; } + + BOOL + Equals( + MULTISZA* pmszRhs + ); + +private: + + DWORD m_cchLen; + DWORD m_cStrings; + VOID AuxInit( const CHAR * pInit ); + BOOL AuxAppend( const CHAR * pInit, + UINT cbStr, BOOL fAddSlop = TRUE ); + +}; + +// +// Quick macro for declaring a MULTISZA that will use stack memory of +// bytes. If the buffer overflows then a heap buffer will be allocated +// + +#define STACK_MULTISZA( name, size ) CHAR __ach##name[size]; \ + MULTISZA name( __ach##name, sizeof( __ach##name )) + +HRESULT +SplitCommaDelimitedString( + PCSTR pszList, + BOOL fTrimEntries, + BOOL fRemoveEmptyEntries, + MULTISZA * pmszList +); + +#endif // !_MULTISZA_HXX_ + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/normalize.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/normalize.h new file mode 100644 index 0000000000..411c3660a4 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/normalize.h @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#ifndef __NORMALIZE_URL__H__ +#define __NORMALIZE_URL__H__ + +HRESULT +NormalizeUrl( + __inout LPSTR pszUrl +); + + +HRESULT +NormalizeUrlW( + __inout LPWSTR pszUrl +); + + + +HRESULT +UlCleanAndCopyUrl( + __in LPSTR pSource, + IN ULONG SourceLength, + OUT PULONG pBytesCopied, + __inout PWSTR pDestination, + __deref_opt_out_opt PWSTR * ppQueryString OPTIONAL +); + +HRESULT +UlInitializeParsing( + VOID +); + +HRESULT +InitializeNormalizeUrl( + VOID +); + + +#endif \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/ntassert.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/ntassert.h new file mode 100644 index 0000000000..8a8d656f21 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/ntassert.h @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#pragma once + +#ifdef _ASSERTE + #undef _ASSERTE +#endif + +#ifdef ASSERT + #undef ASSERT +#endif + +#if defined( DBG ) && DBG + #define SX_ASSERT( _x ) ( (VOID)( ( ( _x ) ) ? TRUE : ( __annotation( L"Debug", L"AssertFail", L#_x ), DbgRaiseAssertionFailure(), FALSE ) ) ) + #define SX_ASSERTMSG( _m, _x ) ( (VOID)( ( ( _x ) ) ? TRUE : ( __annotation( L"Debug", L"AssertFail", L##_m ), DbgRaiseAssertionFailure(), FALSE ) ) ) + #define SX_VERIFY( _x ) SX_ASSERT( _x ) + #define _ASSERTE( _x ) SX_ASSERT( _x ) + #define ASSERT( _x ) SX_ASSERT( _x ) + #define assert( _x ) SX_ASSERT( _x ) + #define DBG_ASSERT( _x ) SX_ASSERT( _x ) + #define DBG_REQUIRE( _x ) SX_ASSERT( _x ) +#else + #define SX_ASSERT( _x ) ( (VOID)0 ) + #define SX_ASSERTMSG( _m, _x ) ( (VOID)0 ) + #define SX_VERIFY( _x ) ( (VOID)( ( _x ) ? TRUE : FALSE ) ) + #define _ASSERTE( _x ) ( (VOID)0 ) + #define assert( _x ) ( (VOID)0 ) + #define DBG_ASSERT( _x ) ( (VOID)0 ) + #define DBG_REQUIRE( _x ) ((VOID)(_x)) +#endif + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/percpu.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/percpu.h new file mode 100644 index 0000000000..ae59b1c805 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/percpu.h @@ -0,0 +1,305 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#pragma once + +template +class PER_CPU +{ +public: + + template + inline + static + HRESULT + Create( + FunctionInitializer Initializer, + __deref_out PER_CPU ** ppInstance + ); + + inline + T * + GetLocal( + VOID + ); + + template + inline + VOID + ForEach( + FunctionForEach Function + ); + + inline + VOID + Dispose( + VOID + ); + +private: + + PER_CPU( + VOID + ) + { + // + // Don't perform any operation during constructor. + // Constructor will never be called. + // + } + + ~PER_CPU( + VOID + ) + { + // + // Don't perform any operation during destructor. + // Constructor will never be called. + // + } + + template + HRESULT + Initialize( + FunctionInitializer Initializer, + DWORD NumberOfVariables, + DWORD Alignment + ); + + T * + GetObject( + DWORD Index + ); + + static + HRESULT + GetProcessorInformation( + __out DWORD * pCacheLineSize, + __out DWORD * pNumberOfProcessors + ); + + // + // Pointer to the begining of the inlined array. + // + PVOID m_pVariables; + SIZE_T m_Alignment; + SIZE_T m_VariablesCount; +}; + +template +template +inline +// static +HRESULT +PER_CPU::Create( + FunctionInitializer Initializer, + __deref_out PER_CPU ** ppInstance +) +{ + HRESULT hr = S_OK; + DWORD CacheLineSize = 0; + DWORD ObjectCacheLineSize = 0; + DWORD NumberOfProcessors = 0; + PER_CPU * pInstance = NULL; + + hr = GetProcessorInformation(&CacheLineSize, + &NumberOfProcessors); + if (FAILED(hr)) + { + goto Finished; + } + + if (sizeof(T) > CacheLineSize) + { + // + // Round to the next multiple of the cache line size. + // + ObjectCacheLineSize = (sizeof(T) + CacheLineSize-1) & (CacheLineSize-1); + } + else + { + ObjectCacheLineSize = CacheLineSize; + } + + // + // Calculate the size of the PER_CPU object, including the array. + // The first cache line is for the member variables and the array + // starts in the next cache line. + // + SIZE_T Size = CacheLineSize + NumberOfProcessors * ObjectCacheLineSize; + + pInstance = (PER_CPU*) _aligned_malloc(Size, CacheLineSize); + if (pInstance == NULL) + { + hr = E_OUTOFMEMORY; + goto Finished; + } + ZeroMemory(pInstance, Size); + + // + // The array start in the 2nd cache line. + // + pInstance->m_pVariables = reinterpret_cast(pInstance) + CacheLineSize; + + // + // Pass a disposer for disposing initialized items in case of failure. + // + hr = pInstance->Initialize(Initializer, + NumberOfProcessors, + ObjectCacheLineSize); + if (FAILED(hr)) + { + goto Finished; + } + + *ppInstance = pInstance; + pInstance = NULL; + +Finished: + + if (pInstance != NULL) + { + // + // Free the instance without disposing it. + // + pInstance->Dispose(); + pInstance = NULL; + } + + return hr; +} + +template +inline +T * +PER_CPU::GetLocal( + VOID +) +{ + // Use GetCurrentProcessorNumber (up to 64 logical processors) instead of + // GetCurrentProcessorNumberEx (more than 64 logical processors) because + // the number of processors are not densely packed per group. + // The idea of distributing variables per CPU is to have + // a scalability multiplier (could be NUMA node instead). + // + // Make sure the index don't go beyond the array size, if that happens, + // there won't be even distribution, but still better + // than one single variable. + // + return GetObject(GetCurrentProcessorNumber()); +} + +template +inline +T * +PER_CPU::GetObject( + DWORD Index +) +{ + return reinterpret_cast(static_cast(m_pVariables) + Index * m_Alignment); +} + +template +template +inline +VOID +PER_CPU::ForEach( + FunctionForEach Function +) +{ + for(DWORD Index = 0; Index < m_VariablesCount; ++Index) + { + T * pObject = GetObject(Index); + Function(pObject); + } +} + +template +VOID +PER_CPU::Dispose( + VOID +) +{ + _aligned_free(this); +} + +template +template +inline +HRESULT +PER_CPU::Initialize( + FunctionInitializer Initializer, + DWORD NumberOfVariables, + DWORD Alignment +) +/*++ + +Routine Description: + + Initialize each object using the initializer function. + If initialization for any object fails, it dispose the + objects that were successfully initialized. + +Arguments: + + Initializer - Function for initialize one object. + Signature: HRESULT Func(T*) + Dispose - Function for disposing initialized objects in case of failure. + Signature: void Func(T*) + NumberOfVariables - The length of the array of variables. + Alignment - Alignment to use for avoiding false sharing. + +Return: + + HRESULT - E_OUTOFMEMORY + +--*/ +{ + HRESULT hr = S_OK; + DWORD Index = 0; + + m_VariablesCount = NumberOfVariables; + m_Alignment = Alignment; + + for (; Index < m_VariablesCount; ++Index) + { + T * pObject = GetObject(Index); + Initializer(pObject); + } + + return hr; +} + +template +// static +HRESULT +PER_CPU::GetProcessorInformation( + __out DWORD * pCacheLineSize, + __out DWORD * pNumberOfProcessors +) +/*++ + +Routine Description: + + Gets the CPU cache-line size for the current system. + This information is used for avoiding CPU false sharing. + +Arguments: + + pCacheLineSize - The processor cache-line size. + pNumberOfProcessors - Maximum number of processors per group. + +Return: + + HRESULT - E_OUTOFMEMORY + +--*/ +{ + SYSTEM_INFO SystemInfo = { }; + + GetSystemInfo(&SystemInfo); + *pNumberOfProcessors = SystemInfo.dwNumberOfProcessors; + *pCacheLineSize = SYSTEM_CACHE_ALIGNMENT_SIZE; + + return S_OK; +} \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/prime.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/prime.h new file mode 100644 index 0000000000..77fcb75b8a --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/prime.h @@ -0,0 +1,85 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#pragma once + +#include +#include + +// +// Pre-calculated prime numbers (up to 10,049,369). +// +extern __declspec(selectany) const DWORD g_Primes [] = { + 3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, + 761, 919, 1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, + 12143, 14591, 17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, + 130363, 156437, 187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, + 968897, 1162687, 1395263, 1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559, + 5999471, 7199369, 7849369, 8649369, 9249369, 10049369 +}; + +class PRIME +{ +public: + + static + DWORD + GetPrime( + DWORD dwMinimum + ) + { + // + // Try to use the precalculated numbers. + // + for ( DWORD Index = 0; Index < _countof( g_Primes ); Index++ ) + { + DWORD dwCandidate = g_Primes[Index]; + if ( dwCandidate >= dwMinimum ) + { + return dwCandidate; + } + } + + // + // Do calculation. + // + for ( DWORD dwCandidate = dwMinimum | 1; + dwCandidate < MAXDWORD; + dwCandidate += 2 ) + { + if ( IsPrime( dwCandidate ) ) + { + return dwCandidate; + } + } + return dwMinimum; + } + +private: + + static + BOOL + IsPrime( + DWORD dwCandidate + ) + { + if ((dwCandidate & 1) == 0) + { + return ( dwCandidate == 2 ); + } + + DWORD dwMax = static_cast(sqrt(static_cast(dwCandidate))); + + for ( DWORD Index = 3; Index <= dwMax; Index += 2 ) + { + if ( (dwCandidate % Index) == 0 ) + { + return FALSE; + } + } + return TRUE; + } + + PRIME() {} + ~PRIME() {} +}; \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/reftrace.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/reftrace.h new file mode 100644 index 0000000000..ace85dcde2 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/reftrace.h @@ -0,0 +1,88 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#ifndef _REFTRACE_H_ +#define _REFTRACE_H_ + + +#if defined(__cplusplus) +extern "C" { +#endif // __cplusplus + + +#include + + +// +// This is the number of stack backtrace values captured in each +// trace log entry. This value is chosen to make the log entry +// exactly twelve dwords long, making it a bit easier to interpret +// from within the debugger without the debugger extension. +// + +#define REF_TRACE_LOG_STACK_DEPTH 9 + +// No-op value for the Context1,2,3 parameters of WriteRefTraceLogEx +//#define REF_TRACE_EMPTY_CONTEXT ((PVOID) -1) +#define REF_TRACE_EMPTY_CONTEXT NULL + + +// +// This defines the entry written to the trace log. +// + +typedef struct _REF_TRACE_LOG_ENTRY { + + LONG NewRefCount; + CONST VOID * Context; + CONST VOID * Context1; + CONST VOID * Context2; + CONST VOID * Context3; + DWORD Thread; + PVOID Stack[REF_TRACE_LOG_STACK_DEPTH]; + +} REF_TRACE_LOG_ENTRY, *PREF_TRACE_LOG_ENTRY; + + +// +// Manipulators. +// + +PTRACE_LOG +CreateRefTraceLog( + IN LONG LogSize, + IN LONG ExtraBytesInHeader + ); + +VOID +DestroyRefTraceLog( + IN PTRACE_LOG Log + ); + +LONG +__cdecl +WriteRefTraceLog( + IN PTRACE_LOG Log, + IN LONG NewRefCount, + IN CONST VOID * Context + ); + +LONG +__cdecl +WriteRefTraceLogEx( + IN PTRACE_LOG Log, + IN LONG NewRefCount, + IN CONST VOID * Context, + IN CONST VOID * Context1, + IN CONST VOID * Context2, + IN CONST VOID * Context3 + ); + + +#if defined(__cplusplus) +} // extern "C" +#endif // __cplusplus + + +#endif // _REFTRACE_H_ + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/rwlock.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/rwlock.h new file mode 100644 index 0000000000..50b9b1ca11 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/rwlock.h @@ -0,0 +1,193 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#pragma once + +#if (_WIN32_WINNT < 0x600) + +// +// XP implementation. +// +class CWSDRWLock +{ +public: + + CWSDRWLock() + : m_bInited(FALSE) + { + } + + ~CWSDRWLock() + { + if (m_bInited) + { + DeleteCriticalSection(&m_rwLock.critsec); + CloseHandle(m_rwLock.ReadersDoneEvent); + } + } + + BOOL QueryInited() const + { + return m_bInited; + } + + HRESULT Init() + { + HRESULT hr = S_OK; + + if (FALSE == m_bInited) + { + m_rwLock.fWriterWaiting = FALSE; + m_rwLock.LockCount = 0; + if ( !InitializeCriticalSectionAndSpinCount( &m_rwLock.critsec, 0 )) + { + DWORD dwError = GetLastError(); + hr = HRESULT_FROM_WIN32(dwError); + return hr; + } + + m_rwLock.ReadersDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + if( NULL == m_rwLock.ReadersDoneEvent ) + { + DWORD dwError = GetLastError(); + hr = HRESULT_FROM_WIN32(dwError); + DeleteCriticalSection(&m_rwLock.critsec); + return hr; + } + m_bInited = TRUE; + } + + return hr; + } + + void SharedAcquire() + { + EnterCriticalSection(&m_rwLock.critsec); + InterlockedIncrement(&m_rwLock.LockCount); + LeaveCriticalSection(&m_rwLock.critsec); + } + + void SharedRelease() + { + ReleaseRWLock(); + } + + void ExclusiveAcquire() + { + EnterCriticalSection( &m_rwLock.critsec ); + + m_rwLock.fWriterWaiting = TRUE; + + // check if there are any readers active + if ( InterlockedExchangeAdd( &m_rwLock.LockCount, 0 ) > 0 ) + { + // + // Wait for all the readers to get done.. + // + WaitForSingleObject( m_rwLock.ReadersDoneEvent, INFINITE ); + } + m_rwLock.LockCount = -1; + } + + void ExclusiveRelease() + { + ReleaseRWLock(); + } + +private: + + BOOL m_bInited; + + typedef struct _RW_LOCK + { + BOOL fWriterWaiting; // Is a writer waiting on the lock? + LONG LockCount; + CRITICAL_SECTION critsec; + HANDLE ReadersDoneEvent; + } RW_LOCK, *PRW_LOCK; + + RW_LOCK m_rwLock; + +private: + + void ReleaseRWLock() + { + LONG Count = InterlockedDecrement( &m_rwLock.LockCount ); + + if ( 0 <= Count ) + { + // releasing a read lock + if (( m_rwLock.fWriterWaiting ) && ( 0 == Count )) + { + SetEvent( m_rwLock.ReadersDoneEvent ); + } + } + else + { + // Releasing a write lock + m_rwLock.LockCount = 0; + m_rwLock.fWriterWaiting = FALSE; + LeaveCriticalSection(&m_rwLock.critsec); + } + } +}; + +#else + +// +// Implementation for Windows Vista or greater. +// +class CWSDRWLock +{ +public: + + CWSDRWLock() + { + InitializeSRWLock(&m_rwLock); + } + + BOOL QueryInited() + { + return TRUE; + } + + + HRESULT Init() + { + // + // Method defined to keep compatibility with CWSDRWLock class for XP. + // + return S_OK; + } + + void SharedAcquire() + { + AcquireSRWLockShared(&m_rwLock); + } + + void SharedRelease() + { + ReleaseSRWLockShared(&m_rwLock); + } + + void ExclusiveAcquire() + { + AcquireSRWLockExclusive(&m_rwLock); + } + + void ExclusiveRelease() + { + ReleaseSRWLockExclusive(&m_rwLock); + } + +private: + + SRWLOCK m_rwLock; +}; + +#endif + +// +// Rename the lock class to a more clear name. +// +typedef CWSDRWLock READ_WRITE_LOCK; \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/statichash.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/statichash.h new file mode 100644 index 0000000000..f2c7980405 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/statichash.h @@ -0,0 +1,730 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#ifndef __STATIC_HASH__H_ +#define __STATIC_HASH__H_ + +#define STATIC_STRING_HASH_BUCKETS 131 + +// +// SERVER_VARIABLE_HASH maps server variable string to routines to eval them +// + +struct STATIC_STRING_HASH_RECORD +{ + CHAR * _pszName; + STATIC_STRING_HASH_RECORD * _pNext; + USHORT _cchName; +}; + +struct STATIC_STRING_HASH_ITER +{ + STATIC_STRING_HASH_RECORD *_pCursor; + DWORD _dwBucket; + BOOL _fRemove; +}; + +class STATIC_STRING_HASH +{ + public: + + STATIC_STRING_HASH( + BOOL fCaseSensitive = FALSE + ) : _fCaseSensitive( fCaseSensitive ) + { + Reset(); + } + + VOID + Reset() + { + ZeroMemory( &_rgBuckets, sizeof( _rgBuckets ) ); + } + + static + PCSTR + ExtractKey( + __in const STATIC_STRING_HASH_RECORD * pRecord + ) + /*++ + + Routine Description: + + Get the key out of the record + + Arguments: + + record to fetch the key from + + Return Value: + + key + + --*/ + { + DBG_ASSERT( pRecord != NULL ); + return pRecord->_pszName; + } + + VOID + InsertRecord( + __in STATIC_STRING_HASH_RECORD * pRecord + ) + /*++ + + Routine Description: + + Insert record to hash table + + Note: remember this is static hash table + There is no synchronization on the table + Exclusive acess must be assured by caller + + Arguments: + + record to fetch the key from + + Return Value: + + VOID + + --*/ + { + DWORD dwIndex; + STATIC_STRING_HASH_RECORD* pCursor; + + DBG_ASSERT( pRecord != NULL ); + DBG_ASSERT( pRecord->_pszName != NULL ); + + if(NULL == pRecord->_pszName) + { + return; + } + + if (_fCaseSensitive) + { + dwIndex = HashString( pRecord->_pszName ) % STATIC_STRING_HASH_BUCKETS; + } + else + { + dwIndex = HashStringNoCase( pRecord->_pszName ) % STATIC_STRING_HASH_BUCKETS; + } + + pCursor = _rgBuckets[ dwIndex ]; + + pRecord->_pNext = pCursor; + _rgBuckets[ dwIndex ] = pRecord; + } + + STATIC_STRING_HASH_RECORD * + FindKey( + __in PCSTR pszName, + BOOL fRemove = FALSE + ) + /*++ + + Routine Description: + + Find key in the table (and remove it optionally) + + Arguments: + + key + + Return Value: + + record containing the key + + --*/ + { + DWORD dwIndex; + STATIC_STRING_HASH_RECORD* pRecord; + STATIC_STRING_HASH_RECORD* pLastRecord = NULL; + + DBG_ASSERT( pszName != NULL ); + + if (_fCaseSensitive) + { + dwIndex = HashString( pszName ) % STATIC_STRING_HASH_BUCKETS; + } + else + { + dwIndex = HashStringNoCase( pszName ) % STATIC_STRING_HASH_BUCKETS; + } + + pRecord = _rgBuckets[ dwIndex ]; + while ( pRecord != NULL ) + { + if (_fCaseSensitive) + { + if ( strcmp( pszName, pRecord->_pszName ) == 0 ) + { + break; + } + } + else if ( _stricmp( pszName, pRecord->_pszName ) == 0 ) + { + break; + } + + pLastRecord = pRecord; + pRecord = pRecord->_pNext; + } + + if (fRemove && + pRecord != NULL) + { + if (pLastRecord != NULL) + { + pLastRecord->_pNext = pRecord->_pNext; + } + else + { + _rgBuckets[dwIndex] = pRecord->_pNext; + } + } + + return pRecord; + } + + BOOL + CheckDistribution( + IN DWORD dwConflictThreshold, + IN BOOL fToDebugger + ) + /*++ + + Routine Description: + + Simple verification on conflicts within the table + + Arguments: + + dwConflictThreshold - max number of entries tolerated per bucket + fToDebbuger - spew the entries exceeding threshold into debugger + + Return Value: + + FALSE it threshold was reached (means hash funcion may not be optimal) + + --*/ + { + BOOL fThresholdReached = FALSE; + STATIC_STRING_HASH_RECORD* pRecord; + for ( DWORD dwIndex = 0; dwIndex < STATIC_STRING_HASH_BUCKETS; dwIndex++) + { + pRecord = _rgBuckets[ dwIndex ]; + DWORD countInBucket = 0; + while ( pRecord != NULL ) + { + countInBucket++; + pRecord = pRecord->_pNext; + } + // + // print out the list of multiple entries in bucket + // + if ( countInBucket > dwConflictThreshold && fToDebugger ) + { + fThresholdReached = TRUE; + + pRecord = _rgBuckets[ dwIndex ]; + while ( pRecord != NULL ) + { + pRecord = pRecord->_pNext; + } + } + } + return fThresholdReached; + } + + STATIC_STRING_HASH_RECORD * + FindFirst( + STATIC_STRING_HASH_ITER *pIterator, + BOOL fRemove = FALSE + ) + /*++ + + Routine Description: + + Begins a new hash item enumeration. + + Arguments: + + pIterator - Supplies the context for the enumeration. + + fRemove - Supplies TRUE if the items should be removed + from the hash as they are enumerated. + + Return Value: + + The first entry in the hash if successful, NULL otherwise. + + --*/ + { + pIterator->_dwBucket = 0; + pIterator->_fRemove = fRemove; + pIterator->_pCursor = FindNextBucket(&pIterator->_dwBucket); + + if (pIterator->_fRemove && pIterator->_pCursor != NULL) + { + _rgBuckets[pIterator->_dwBucket] = pIterator->_pCursor->_pNext; + } + + return pIterator->_pCursor; + } + + STATIC_STRING_HASH_RECORD * + FindNext( + STATIC_STRING_HASH_ITER *pIterator + ) + /*++ + + Routine Description: + + Continues a hash item enumeration. + + Arguments: + + pIterator - Supplies the context for the enumeration. + + Return Value: + + The next entry in the hash if successful, NULL otherwise. + + --*/ + { + if (pIterator->_pCursor != NULL) + { + if (pIterator->_fRemove) + { + pIterator->_pCursor = _rgBuckets[pIterator->_dwBucket]; + } + else + { + pIterator->_pCursor = pIterator->_pCursor->_pNext; + } + + if (pIterator->_pCursor == NULL) + { + pIterator->_dwBucket++; + pIterator->_pCursor = FindNextBucket(&pIterator->_dwBucket); + } + } + + if (pIterator->_fRemove && pIterator->_pCursor != NULL) + { + _rgBuckets[pIterator->_dwBucket] = pIterator->_pCursor->_pNext; + } + + return pIterator->_pCursor; + } + + protected: + + STATIC_STRING_HASH_RECORD * _rgBuckets[ STATIC_STRING_HASH_BUCKETS ]; + + private: + + BOOL _fCaseSensitive; + + STATIC_STRING_HASH_RECORD * + FindNextBucket( + DWORD *pdwStartingBucket + ) + /*++ + + Routine Description: + + Scan for the next non-empty bucket. + + Arguments: + + pdwStartingBucket - Supplies a pointer to the starting + bucket index. This value is updated with the index + of the next non-empty bucket if successful. + + Return Value: + + The first entry in the next non-empty bucket if successful, + NULL otherwise. + + --*/ + { + DWORD i; + STATIC_STRING_HASH_RECORD *pScan = NULL; + + for (i = *pdwStartingBucket ; i < STATIC_STRING_HASH_BUCKETS ; i++) + { + pScan = _rgBuckets[i]; + + if (pScan != NULL) + { + break; + } + } + + *pdwStartingBucket = i; + return pScan; + } +}; + + + + +struct STATIC_WSTRING_HASH_RECORD +{ + WCHAR * _pszName; + STATIC_WSTRING_HASH_RECORD * _pNext; + USHORT _cchName; +}; + + +struct STATIC_WSTRING_HASH_ITER +{ + STATIC_WSTRING_HASH_RECORD *_pCursor; + DWORD _dwBucket; + BOOL _fRemove; +}; + + +class STATIC_WSTRING_HASH +{ + public: + STATIC_WSTRING_HASH( + BOOL fCaseSensitive = FALSE + ) : _fCaseSensitive( fCaseSensitive ) + { + Reset(); + } + + VOID + Reset() + { + ZeroMemory( &_rgBuckets, sizeof( _rgBuckets ) ); + } + + static + PCWSTR + ExtractKey( + __in const STATIC_WSTRING_HASH_RECORD * pRecord + ) + /*++ + + Routine Description: + + Get the key out of the record + + Arguments: + + record to fetch the key from + + Return Value: + + key + + --*/ + { + DBG_ASSERT( pRecord != NULL ); + return pRecord->_pszName; + } + + VOID + InsertRecord( + __in STATIC_WSTRING_HASH_RECORD * pRecord + ) + /*++ + + Routine Description: + + Insert record to hash table + + Note: remember this is static hash table + There is no synchronization on the table + Exclusive acess must be assured by caller + + Arguments: + + record to fetch the key from + + Return Value: + + VOID + + --*/ + { + DWORD dwIndex; + STATIC_WSTRING_HASH_RECORD* pCursor; + + DBG_ASSERT( pRecord != NULL ); + DBG_ASSERT( pRecord->_pszName != NULL ); + + if (_fCaseSensitive) + { + dwIndex = HashString( pRecord->_pszName ) % STATIC_STRING_HASH_BUCKETS; + } + else + { + dwIndex = HashStringNoCase( pRecord->_pszName ) % STATIC_STRING_HASH_BUCKETS; + } + + pCursor = _rgBuckets[ dwIndex ]; + + pRecord->_pNext = pCursor; + _rgBuckets[ dwIndex ] = pRecord; + } + + STATIC_WSTRING_HASH_RECORD * + FindKey( + __in PCWSTR pszName, + BOOL fRemove = FALSE + ) + /*++ + + Routine Description: + + Find key in the table (and remove it optionally) + + Arguments: + + key + + Return Value: + + record containing the key + + --*/ + { + DWORD dwIndex; + STATIC_WSTRING_HASH_RECORD* pRecord; + STATIC_WSTRING_HASH_RECORD* pLastRecord = NULL; + + DBG_ASSERT( pszName != NULL ); + + if (_fCaseSensitive) + { + dwIndex = HashString( pszName ) % STATIC_STRING_HASH_BUCKETS; + } + else + { + dwIndex = HashStringNoCase( pszName ) % STATIC_STRING_HASH_BUCKETS; + } + + pRecord = _rgBuckets[ dwIndex ]; + while ( pRecord != NULL ) + { + if ( _fCaseSensitive ) + { + if ( wcscmp( pszName, pRecord->_pszName ) == 0 ) + { + break; + } + } + else if ( _wcsicmp( pszName, pRecord->_pszName ) == 0 ) + { + break; + } + + pLastRecord = pRecord; + pRecord = pRecord->_pNext; + } + + if (fRemove && + pRecord != NULL) + { + if (pLastRecord != NULL) + { + pLastRecord->_pNext = pRecord->_pNext; + } + else + { + _rgBuckets[dwIndex] = pRecord->_pNext; + } + } + + return pRecord; + } + + BOOL + CheckDistribution( + IN DWORD dwConflictThreshold, + IN BOOL fToDebugger + ) + /*++ + + Routine Description: + + Simple verification on conflicts within the table + + Arguments: + + dwConflictThreshold - max number of entries tolerated per bucket + fToDebbuger - spew the entries exceeding threshold into debugger + + Return Value: + + FALSE it threshold was reached (means hash funcion may not be optimal) + + --*/ + { + BOOL fThresholdReached = FALSE; + STATIC_WSTRING_HASH_RECORD* pRecord; + for ( DWORD dwIndex = 0; dwIndex < STATIC_STRING_HASH_BUCKETS; dwIndex++) + { + pRecord = _rgBuckets[ dwIndex ]; + DWORD countInBucket = 0; + while ( pRecord != NULL ) + { + countInBucket++; + pRecord = pRecord->_pNext; + } + // + // print out the list of multiple entries in bucket + // + if ( countInBucket > dwConflictThreshold && fToDebugger ) + { + fThresholdReached = TRUE; + + pRecord = _rgBuckets[ dwIndex ]; + while ( pRecord != NULL ) + { + pRecord = pRecord->_pNext; + } + } + } + return fThresholdReached; + } + + STATIC_WSTRING_HASH_RECORD * + FindFirst( + STATIC_WSTRING_HASH_ITER *pIterator, + BOOL fRemove = FALSE + ) + /*++ + + Routine Description: + + Begins a new hash item enumeration. + + Arguments: + + pIterator - Supplies the context for the enumeration. + + fRemove - Supplies TRUE if the items should be removed + from the hash as they are enumerated. + + Return Value: + + The first entry in the hash if successful, NULL otherwise. + + --*/ + { + pIterator->_dwBucket = 0; + pIterator->_fRemove = fRemove; + pIterator->_pCursor = FindNextBucket(&pIterator->_dwBucket); + + if (pIterator->_fRemove && pIterator->_pCursor != NULL) + { + _rgBuckets[pIterator->_dwBucket] = pIterator->_pCursor->_pNext; + } + + return pIterator->_pCursor; + } + + STATIC_WSTRING_HASH_RECORD * + FindNext( + STATIC_WSTRING_HASH_ITER *pIterator + ) + /*++ + + Routine Description: + + Continues a hash item enumeration. + + Arguments: + + pIterator - Supplies the context for the enumeration. + + Return Value: + + The next entry in the hash if successful, NULL otherwise. + + --*/ + { + if (pIterator->_pCursor != NULL) + { + if (pIterator->_fRemove) + { + pIterator->_pCursor = _rgBuckets[pIterator->_dwBucket]; + } + else + { + pIterator->_pCursor = pIterator->_pCursor->_pNext; + } + + if (pIterator->_pCursor == NULL) + { + pIterator->_dwBucket++; + pIterator->_pCursor = FindNextBucket(&pIterator->_dwBucket); + } + } + + if (pIterator->_fRemove && pIterator->_pCursor != NULL) + { + _rgBuckets[pIterator->_dwBucket] = pIterator->_pCursor->_pNext; + } + + return pIterator->_pCursor; + } + + protected: + + STATIC_WSTRING_HASH_RECORD * _rgBuckets[ STATIC_STRING_HASH_BUCKETS ]; + + private: + + BOOL _fCaseSensitive; + + STATIC_WSTRING_HASH_RECORD * + FindNextBucket( + DWORD *pdwStartingBucket + ) + /*++ + + Routine Description: + + Scan for the next non-empty bucket. + + Arguments: + + pdwStartingBucket - Supplies a pointer to the starting + bucket index. This value is updated with the index + of the next non-empty bucket if successful. + + Return Value: + + The first entry in the next non-empty bucket if successful, + NULL otherwise. + + --*/ + { + DWORD i; + STATIC_WSTRING_HASH_RECORD *pScan = NULL; + + for (i = *pdwStartingBucket ; i < STATIC_STRING_HASH_BUCKETS ; i++) + { + pScan = _rgBuckets[i]; + + if (pScan != NULL) + { + break; + } + } + + *pdwStartingBucket = i; + return pScan; + } +}; + + +#endif //__STATIC_HASH__H_ + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/stdtypes.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/stdtypes.h new file mode 100644 index 0000000000..53a631b036 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/stdtypes.h @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#pragma once + +// +// Use C++ standard 'nullptr' +// + +#ifdef NULL +#undef NULL +#endif + +#ifdef __cplusplus +#ifdef _NATIVE_NULLPTR_SUPPORTED +#define NULL nullptr +#else +#define NULL 0 +#define nullptr 0 +#endif +#else +#define NULL ((void *)0) +//#define nullptr ((void *)0) +#endif diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/stringa.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/stringa.h new file mode 100644 index 0000000000..d38604014e --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/stringa.h @@ -0,0 +1,515 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#pragma once + +#include "buffer.h" +#include "macros.h" +#include + +class STRA +{ + +public: + + STRA( + VOID + ); + + STRA( + __inout_ecount(cchInit) CHAR* pbInit, + __in DWORD cchInit + ); + + BOOL + IsEmpty( + VOID + ) const; + + BOOL + Equals( + __in PCSTR pszRhs, + __in BOOL fIgnoreCase = FALSE + ) const; + + BOOL + Equals( + __in const STRA * pstrRhs, + __in BOOL fIgnoreCase = FALSE + ) const; + + BOOL + Equals( + __in const STRA & strRhs, + __in BOOL fIgnoreCase = FALSE + ) const; + + static + BOOL + Equals( + __in PCSTR pszLhs, + __in PCSTR pszRhs, + __in bool fIgnoreCase = false + ) + { + // Return FALSE if either or both strings are NULL. + if (!pszLhs || !pszRhs) return FALSE; + + if( fIgnoreCase ) + { + return ( 0 == _stricmp( pszLhs, pszRhs ) ); + } + + return ( 0 == strcmp( pszLhs, pszRhs ) ); + } + + VOID + Trim(); + + BOOL + StartsWith( + __in const STRA * pStraPrefix, + __in bool fIgnoreCase = FALSE + ) const; + + BOOL + StartsWith( + __in const STRA & straPrefix, + __in bool fIgnoreCase = FALSE + ) const; + + BOOL + StartsWith( + __in PCSTR pszPrefix, + __in bool fIgnoreCase = FALSE + ) const; + + BOOL + EndsWith( + __in const STRA * pStraSuffix, + __in bool fIgnoreCase = FALSE + ) const; + + BOOL + EndsWith( + __in const STRA & straSuffix, + __in bool fIgnoreCase = FALSE + ) const; + + BOOL + EndsWith( + __in PCSTR pszSuffix, + __in bool fIgnoreCase = FALSE + ) const; + + INT + IndexOf( + __in CHAR charValue, + __in DWORD dwStartIndex = 0 + ) const; + + INT + IndexOf( + __in PCSTR pszValue, + __in DWORD dwStartIndex = 0 + ) const; + + INT + LastIndexOf( + __in CHAR charValue, + __in DWORD dwStartIndex = 0 + ) const; + + DWORD + QueryCB( + VOID + ) const; + + DWORD + QueryCCH( + VOID + ) const; + + DWORD + QuerySizeCCH( + VOID + ) const; + + DWORD + QuerySize( + VOID + ) const; + + __nullterminated + __bcount(this->m_cchLen) + CHAR * + QueryStr( + VOID + ) const; + + VOID + Reset( + VOID + ); + + HRESULT + Resize( + __in DWORD cchSize + ); + + HRESULT + SyncWithBuffer( + VOID + ); + + HRESULT + Copy( + __in PCSTR pszCopy + ); + + HRESULT + Copy( + __in_ecount(cbLen) + PCSTR pszCopy, + __in SIZE_T cbLen + ); + + HRESULT + Copy( + __in const STRA * pstrRhs + ); + + HRESULT + Copy( + __in const STRA & strRhs + ); + + HRESULT + CopyW( + __in PCWSTR pszCopyW + ); + + HRESULT + CopyW( + __in_ecount(cchLen) + PCWSTR pszCopyW, + __in SIZE_T cchLen, + __in UINT CodePage = CP_UTF8, + __in BOOL fFailIfNoTranslation = FALSE + ) + { + _ASSERTE( cchLen <= MAXDWORD ); + + return AuxAppendW( + pszCopyW, + static_cast(cchLen), + 0, + CodePage, + fFailIfNoTranslation + ); + } + + HRESULT + CopyWTruncate( + __in PCWSTR pszCopyWTruncate + ); + + HRESULT + CopyWTruncate( + __in_ecount(cchLen) + PCWSTR pszCopyWTruncate, + __in SIZE_T cchLen + ); + + HRESULT + Append( + __in PCSTR pszAppend + ); + + HRESULT + Append( + __in_ecount(cbLen) + PCSTR pszAppend, + __in SIZE_T cbLen + ); + + HRESULT + Append( + __in const STRA * pstrRhs + ); + + HRESULT + Append( + __in const STRA & strRhs + ); + + HRESULT + AppendW( + __in PCWSTR pszAppendW + ) + { + HRESULT hr; + size_t cchLen; + hr = StringCchLengthW( pszAppendW, + STRSAFE_MAX_CCH, + &cchLen ); + if ( FAILED( hr ) ) + { + return hr; + } + return AppendW( pszAppendW, cchLen ); + } + + HRESULT + AppendW( + __in_ecount(cchLen) + PCWSTR pszAppendW, + __in SIZE_T cchLen, + __in UINT CodePage = CP_UTF8, + __in BOOL fFailIfNoTranslation = FALSE + ) + { + _ASSERTE( cchLen <= MAXDWORD ); + if ( cchLen == 0 ) + { + return S_OK; + } + return AuxAppendW( + pszAppendW, + static_cast(cchLen), + QueryCB(), + CodePage, + fFailIfNoTranslation + ); + } + + HRESULT + AppendWTruncate( + __in PCWSTR pszAppendWTruncate + ); + + HRESULT + AppendWTruncate( + __in_ecount(cchLen) + PCWSTR pszAppendWTruncate, + __in SIZE_T cchLen + ); + + HRESULT + CopyToBuffer( + __out_bcount(*pcb) CHAR* pszBuffer, + __inout DWORD * pcb + ) const; + + HRESULT + SetLen( + __in DWORD cchLen + ); + + HRESULT + SafeSnprintf( + __in __format_string + PCSTR pszFormatString, + ... + ); + + HRESULT + SafeVsnprintf( + __in __format_string + PCSTR pszFormatString, + va_list argsList + ); + + HRESULT + Escape( + VOID + ); + + HRESULT + EscapeUtf8( + VOID + ); + + VOID + Unescape( + VOID + ); + + HRESULT + CopyWToUTF8Unescaped( + __in LPCWSTR cpchStr + ); + + HRESULT + CopyWToUTF8Unescaped( + __in_ecount(cch) + LPCWSTR cpchStr, + __in DWORD cch + ); + + HRESULT + CopyWToUTF8Escaped( + __in LPCWSTR cpchStr + ); + + HRESULT + CopyWToUTF8Escaped( + __in_ecount(cch) + LPCWSTR cpchStr, + __in DWORD cch + ); + +private: + + // + // Avoid C++ errors. This object should never go through a copy + // constructor, unintended cast or assignment. + // + STRA( const STRA &); + STRA & operator = (const STRA &); + + HRESULT + AuxAppend( + __in_ecount(cbLen) + LPCSTR pStr, + __in DWORD cbLen, + __in DWORD cbOffset + ); + + HRESULT + AuxAppendW( + __in_ecount(cchAppendW) + PCWSTR pszAppendW, + __in DWORD cchAppendW, + __in DWORD cbOffset, + __in UINT CodePage, + __in BOOL fFailIfNoTranslation + ) + { + DWORD dwFlags = 0; + + if( CP_ACP == CodePage ) + { + dwFlags = WC_NO_BEST_FIT_CHARS; + } + else if( fFailIfNoTranslation && CodePage == CP_UTF8 ) + { + // + // WC_ERR_INVALID_CHARS is only supported in Longhorn or greater. + // +#if defined( NTDDI_VERSION ) && NTDDI_VERSION >= NTDDI_LONGHORN + dwFlags |= WC_ERR_INVALID_CHARS; +#else + UNREFERENCED_PARAMETER(fFailIfNoTranslation); +#endif + } + + return AuxAppendW( pszAppendW, + cchAppendW, + cbOffset, + CodePage, + fFailIfNoTranslation, + dwFlags ); + } + + HRESULT + AuxAppendW( + __in_ecount(cchAppendW) + PCWSTR pszAppendW, + __in DWORD cchAppendW, + __in DWORD cbOffset, + __in UINT CodePage, + __in BOOL fFailIfNoTranslation, + __in DWORD dwFlags + ); + + HRESULT + AuxAppendWTruncate( + __in_ecount(cchAppendW) + __in PCWSTR pszAppendW, + __in DWORD cchAppendW, + __in DWORD cbOffset + ); + + static + int + ConvertUnicodeToCodePage( + __in_ecount(dwStringLen) + LPCWSTR pszSrcUnicodeString, + __inout BUFFER_T * pbufDstAnsiString, + __in DWORD dwStringLen, + __in UINT uCodePage + ); + + static + HRESULT + ConvertUnicodeToMultiByte( + __in_ecount(dwStringLen) + LPCWSTR pszSrcUnicodeString, + __in BUFFER_T * pbufDstAnsiString, + __in DWORD dwStringLen + ); + + static + HRESULT + ConvertUnicodeToUTF8( + __in_ecount(dwStringLen) + LPCWSTR pszSrcUnicodeString, + __in BUFFER_T * pbufDstAnsiString, + __in DWORD dwStringLen + ); + + typedef bool (* PFN_F_SHOULD_ESCAPE)(BYTE ch); + + HRESULT + EscapeInternal( + PFN_F_SHOULD_ESCAPE pfnFShouldEscape + ); + + // + // Buffer with an inline buffer of 1, + // enough to hold null-terminating character. + // + BUFFER_T m_Buff; + DWORD m_cchLen; +}; + +inline +HRESULT +AppendToString( + ULONGLONG Number, + STRA & String +) +{ + // prefast complains Append requires input + // to be null terminated, so zero initialize + // and pass the size of the buffer minus one + // to _ui64toa_s + CHAR chNumber[32] = {0}; + if (_ui64toa_s(Number, + chNumber, + sizeof(chNumber) - sizeof(CHAR), + 10) != 0) + { + return E_INVALIDARG; + } + return String.Append(chNumber); +} + +template +CHAR* InitHelper(__out CHAR (&psz)[size]) +{ + psz[0] = '\0'; + return psz; +} + +// +// Heap operation reduction macros +// +#define STACK_STRA(name, size) CHAR __ach##name[size];\ + STRA name(InitHelper(__ach##name), sizeof(__ach##name)) + +#define INLINE_STRA(name, size) CHAR __ach##name[size];\ + STRA name; + +#define INLINE_STRA_INIT(name) name(InitHelper(__ach##name), sizeof(__ach##name)) diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/stringu.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/stringu.h new file mode 100644 index 0000000000..6c8f8f755b --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/stringu.h @@ -0,0 +1,433 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#pragma once + +#include "buffer.h" +#include + +class STRU +{ + +public: + + STRU( + VOID + ); + + STRU( + __inout_ecount(cchInit) WCHAR* pbInit, + __in DWORD cchInit + ); + + BOOL + IsEmpty( + VOID + ) const; + + BOOL + Equals( + __in const STRU * pstrRhs, + __in BOOL fIgnoreCase = FALSE + ) const + { + _ASSERTE( pstrRhs != NULL ); + return Equals( pstrRhs->QueryStr(), fIgnoreCase ); + } + + BOOL + Equals( + __in const STRU & strRhs, + __in BOOL fIgnoreCase = FALSE + ) const + { + return Equals( strRhs.QueryStr(), fIgnoreCase ); + } + + BOOL + Equals( + __in PCWSTR pszRhs, + __in BOOL fIgnoreCase = FALSE + ) const + { + _ASSERTE( NULL != pszRhs ); + if ( NULL == pszRhs ) + { + return FALSE; + } + + #if defined( NTDDI_VERSION ) && NTDDI_VERSION >= NTDDI_LONGHORN + + return ( CSTR_EQUAL == CompareStringOrdinal( QueryStr(), + QueryCCH(), + pszRhs, + -1, + fIgnoreCase ) ); + #else + + if( fIgnoreCase ) + { + return ( 0 == _wcsicmp( QueryStr(), pszRhs ) ); + } + return ( 0 == wcscmp( QueryStr(), pszRhs ) ); + + #endif + } + + + static + BOOL + Equals( + __in PCWSTR pwszLhs, + __in PCWSTR pwszRhs, + __in bool fIgnoreCase = false + ) + { + // Return FALSE if either or both strings are NULL. + if (!pwszLhs || !pwszRhs) return FALSE; + + // + // This method performs a ordinal string comparison when OS is Vista or + // greater and a culture sensitive comparison if not (XP). This is + // consistent with the existing Equals implementation (see above). + // +#if defined( NTDDI_VERSION ) && NTDDI_VERSION >= NTDDI_LONGHORN + + return ( CSTR_EQUAL == CompareStringOrdinal( pwszLhs, + -1, + pwszRhs, + -1, + fIgnoreCase ) ); +#else + + if( fIgnoreCase ) + { + return ( 0 == _wcsicmp( pwszLhs, pwszRhs ) ); + } + else + { + return ( 0 == wcscmp( pwszLhs, pwszRhs ) ); + } + +#endif + } + + VOID + Trim(); + + BOOL + StartsWith( + __in const STRU * pStruPrefix, + __in bool fIgnoreCase = FALSE + ) const + { + _ASSERTE( pStruPrefix != NULL ); + return StartsWith( pStruPrefix->QueryStr(), fIgnoreCase ); + } + + BOOL + StartsWith( + __in const STRU & struPrefix, + __in bool fIgnoreCase = FALSE + ) const + { + return StartsWith( struPrefix.QueryStr(), fIgnoreCase ); + } + + BOOL + StartsWith( + __in PCWSTR pwszPrefix, + __in bool fIgnoreCase = FALSE + ) const; + + BOOL + EndsWith( + __in const STRU * pStruSuffix, + __in bool fIgnoreCase = FALSE + ) const + { + _ASSERTE( pStruSuffix != NULL ); + return EndsWith( pStruSuffix->QueryStr(), fIgnoreCase ); + } + + BOOL + EndsWith( + __in const STRU & struSuffix, + __in bool fIgnoreCase = FALSE + ) const + { + return EndsWith( struSuffix.QueryStr(), fIgnoreCase ); + } + + BOOL + EndsWith( + __in PCWSTR pwszSuffix, + __in bool fIgnoreCase = FALSE + ) const; + + INT + IndexOf( + __in WCHAR charValue, + __in DWORD dwStartIndex = 0 + ) const; + + INT + IndexOf( + __in PCWSTR pwszValue, + __in DWORD dwStartIndex = 0 + ) const; + + INT + LastIndexOf( + __in WCHAR charValue, + __in DWORD dwStartIndex = 0 + ) const; + + DWORD + QueryCB( + VOID + ) const; + + DWORD + QueryCCH( + VOID + ) const; + + DWORD + QuerySizeCCH( + VOID + ) const; + + __nullterminated + __ecount(this->m_cchLen) + WCHAR* + QueryStr( + VOID + ) const; + + VOID + Reset( + VOID + ); + + HRESULT + Resize( + DWORD cchSize + ); + + HRESULT + SyncWithBuffer( + VOID + ); + + template + HRESULT + Copy( + __in PCWSTR const (&rgpszStrings)[size] + ) + // + // Copies an array of strings declared as stack array. For example: + // + // LPCWSTR rgExample[] { L"one", L"two" }; + // hr = str.Copy( rgExample ); + // + { + Reset(); + + return AuxAppend( rgpszStrings, _countof( rgpszStrings ) ); + } + + HRESULT + Copy( + __in PCWSTR pszCopy + ); + + HRESULT + Copy( + __in_ecount(cchLen) + PCWSTR pszCopy, + SIZE_T cchLen + ); + + HRESULT + Copy( + __in const STRU * pstrRhs + ); + + HRESULT + Copy( + __in const STRU & str + ); + + HRESULT + CopyAndExpandEnvironmentStrings( + __in PCWSTR pszSource + ); + + HRESULT + CopyA( + __in PCSTR pszCopyA + ); + + HRESULT + CopyA( + __in_bcount(cchLen) + PCSTR pszCopyA, + SIZE_T cchLen, + UINT CodePage = CP_UTF8 + ); + + template + HRESULT + Append( + __in PCWSTR const (&rgpszStrings)[size] + ) + // + // Appends an array of strings declared as stack array. For example: + // + // LPCWSTR rgExample[] { L"one", L"two" }; + // hr = str.Append( rgExample ); + // + { + return AuxAppend( rgpszStrings, _countof( rgpszStrings ) ); + } + + HRESULT + Append( + __in PCWSTR pszAppend + ); + + HRESULT + Append( + __in_ecount(cchLen) + PCWSTR pszAppend, + SIZE_T cchLen + ); + + HRESULT + Append( + __in const STRU * pstrRhs + ); + + HRESULT + Append( + __in const STRU & strRhs + ); + + HRESULT + AppendA( + __in PCSTR pszAppendA + ); + + HRESULT + AppendA( + __in_bcount(cchLen) + PCSTR pszAppendA, + SIZE_T cchLen, + UINT CodePage = CP_UTF8 + ); + + HRESULT + CopyToBuffer( + __out_bcount(*pcb) WCHAR* pszBuffer, + PDWORD pcb + ) const; + + HRESULT + CopyToBufferA( + __out_bcount(*pcb) CHAR* pszBuffer, + __inout PDWORD pcb + ) const; + + HRESULT + SetLen( + __in DWORD cchLen + ); + + HRESULT + SafeSnwprintf( + __in PCWSTR pwszFormatString, + ... + ); + + HRESULT + SafeVsnwprintf( + __in PCWSTR pwszFormatString, + va_list argsList + ); + + static + HRESULT ExpandEnvironmentVariables( + __in PCWSTR pszString, + __out STRU * pstrExpandedString + ); + +private: + + // + // Avoid C++ errors. This object should never go through a copy + // constructor, unintended cast or assignment. + // + STRU( const STRU & ); + STRU & operator = ( const STRU & ); + + HRESULT + AuxAppend( + __in_ecount(cNumStrings) + PCWSTR const rgpszStrings[], + SIZE_T cNumStrings + ); + + HRESULT + AuxAppend( + __in_bcount(cbStr) + const WCHAR* pStr, + SIZE_T cbStr, + DWORD cbOffset + ); + + HRESULT + AuxAppendA( + __in_bcount(cbStr) + const CHAR* pStr, + SIZE_T cbStr, + DWORD cbOffset, + UINT CodePage + ); + + // + // Buffer with an inline buffer of 1, + // enough to hold null-terminating character. + // + BUFFER_T m_Buff; + DWORD m_cchLen; +}; + +// +// Helps to initialize an external buffer before +// constructing the STRU object. +// +template +WCHAR* InitHelper(__out WCHAR (&psz)[size]) +{ + psz[0] = L'\0'; + return psz; +} + +// +// Heap operation reduction macros +// +#define STACK_STRU(name, size) WCHAR __ach##name[size];\ + STRU name(InitHelper(__ach##name), sizeof(__ach##name)/sizeof(*__ach##name)) + +#define INLINE_STRU(name, size) WCHAR __ach##name[size];\ + STRU name; + +#define INLINE_STRU_INIT(name) name(InitHelper(__ach##name), sizeof(__ach##name)/sizeof(*__ach##name)) + + +HRESULT +MakePathCanonicalizationProof( + IN PCWSTR pszName, + OUT STRU * pstrPath +); diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/sttimer.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/sttimer.h new file mode 100644 index 0000000000..b0fba23559 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/sttimer.h @@ -0,0 +1,243 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#ifndef _STTIMER_H +#define _STTIMER_H + +class STTIMER +{ +public: + + STTIMER() + : _pTimer( NULL ) + { + fInCanel = FALSE; + } + + virtual + ~STTIMER() + { + if ( _pTimer ) + { + CancelTimer(); + + CloseThreadpoolTimer( _pTimer ); + + _pTimer = NULL; + } + } + + HRESULT + InitializeTimer( + PTP_TIMER_CALLBACK pfnCallback, + VOID * pContext, + DWORD dwInitialWait = 0, + DWORD dwPeriod = 0 + ) + { + _pTimer = CreateThreadpoolTimer( pfnCallback, + pContext, + NULL ); + + if ( !_pTimer ) + { + return HRESULT_FROM_WIN32( GetLastError() ); + } + + if ( dwInitialWait ) + { + SetTimer( dwInitialWait, + dwPeriod ); + } + + return S_OK; + } + + VOID + SetTimer( + DWORD dwInitialWait, + DWORD dwPeriod = 0 + ) + { + FILETIME ftInitialWait; + + if ( dwInitialWait == 0 && dwPeriod == 0 ) + { + // + // Special case. We are preventing new callbacks + // from being queued. Any existing callbacks in the + // queue will still run. + // + // This effectively disables the timer. It can be + // re-enabled by setting non-zero initial wait or + // period values. + // + if (_pTimer != NULL) + { + SetThreadpoolTimer(_pTimer, NULL, 0, 0); + } + + return; + } + + InitializeRelativeFileTime( &ftInitialWait, dwInitialWait ); + + SetThreadpoolTimer( _pTimer, + &ftInitialWait, + dwPeriod, + 0 ); + } + + VOID + CancelTimer() + { + // + // Disable the timer + // + if (fInCanel) + return; + + fInCanel = TRUE; + SetTimer( 0 ); + + // + // Wait until any callbacks queued prior to disabling + // have completed. + // + if (_pTimer != NULL) + WaitForThreadpoolTimerCallbacks( _pTimer, TRUE ); + + _pTimer = NULL; + fInCanel = FALSE; + } + +private: + + VOID + InitializeRelativeFileTime( + FILETIME * pft, + DWORD dwMilliseconds + ) + { + LARGE_INTEGER li; + + // + // The pftDueTime parameter expects the time to be + // expressed as the number of 100 nanosecond intervals + // times -1. + // + // To convert from milliseconds, we'll multiply by + // -10000 + // + + li.QuadPart = (LONGLONG)dwMilliseconds * -10000; + + pft->dwHighDateTime = li.HighPart; + pft->dwLowDateTime = li.LowPart; + }; + + TP_TIMER * _pTimer; + BOOL fInCanel; +}; + +class STELAPSED +{ +public: + + STELAPSED() + : _dwInitTime( 0 ), + _dwInitTickCount( 0 ), + _dwPerfCountsPerMillisecond( 0 ), + _fUsingHighResolution( FALSE ) + { + LARGE_INTEGER li; + BOOL fResult; + + _dwInitTickCount = GetTickCount64(); + + fResult = QueryPerformanceFrequency( &li ); + + if ( !fResult ) + { + goto Finished; + } + + _dwPerfCountsPerMillisecond = li.QuadPart / 1000; + + fResult = QueryPerformanceCounter( &li ); + + if ( !fResult ) + { + goto Finished; + } + + _dwInitTime = li.QuadPart / _dwPerfCountsPerMillisecond; + + _fUsingHighResolution = TRUE; + +Finished: + + return; + } + + virtual + ~STELAPSED() + { + } + + LONGLONG + QueryElapsedTime() + { + LARGE_INTEGER li; + + if ( _fUsingHighResolution && QueryPerformanceCounter( &li ) ) + { + DWORD64 dwCurrentTime = li.QuadPart / _dwPerfCountsPerMillisecond; + + if ( dwCurrentTime < _dwInitTime ) + { + // + // It's theoretically possible that QueryPerformanceCounter + // may return slightly different values on different CPUs. + // In this case, we don't want to return an unexpected value + // so we'll return zero. This is acceptable because + // presumably such a case would only happen for a very short + // time window. + // + // It would be possible to prevent this by ensuring processor + // affinity for all calls to QueryPerformanceCounter, but that + // would be undesirable in the general case because it could + // introduce unnecessary context switches and potentially a + // CPU bottleneck. + // + // Note that this issue also applies to callers doing rapid + // calls to this function. If a caller wants to mitigate + // that, they could enforce the affinitization, or they + // could implement a similar sanity check when comparing + // returned values from this function. + // + + return 0; + } + + return dwCurrentTime - _dwInitTime; + } + + return GetTickCount64() - _dwInitTickCount; + } + + BOOL + QueryUsingHighResolution() + { + return _fUsingHighResolution; + } + +private: + + DWORD64 _dwInitTime; + DWORD64 _dwInitTickCount; + DWORD64 _dwPerfCountsPerMillisecond; + BOOL _fUsingHighResolution; +}; + +#endif // _STTIMER_H \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/tracelog.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/tracelog.h new file mode 100644 index 0000000000..1caff82ce3 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/tracelog.h @@ -0,0 +1,105 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#ifndef _TRACELOG_H_ +#define _TRACELOG_H_ + + +#if defined(__cplusplus) +extern "C" { +#endif // __cplusplus + + +typedef struct _TRACE_LOG { + + // + // Signature. + // + + LONG Signature; + + // + // The total number of entries available in the log. + // + + LONG LogSize; + + // + // The index of the next entry to use. + // + + LONG NextEntry; + + // + // The byte size of each entry. + // + + LONG EntrySize; + + // + // Pointer to the start of the circular buffer. + // + + PUCHAR LogBuffer; + + // + // The extra header bytes and actual log entries go here. + // + // BYTE ExtraHeaderBytes[ExtraBytesInHeader]; + // BYTE Entries[LogSize][EntrySize]; + // + +} TRACE_LOG, *PTRACE_LOG; + + +// +// Log header signature. +// + +#define TRACE_LOG_SIGNATURE ((DWORD)'gOlT') +#define TRACE_LOG_SIGNATURE_X ((DWORD)'golX') + + +// +// This macro maps a TRACE_LOG pointer to a pointer to the 'extra' +// data associated with the log. +// + +#define TRACE_LOG_TO_EXTRA_DATA(log) (PVOID)( (log) + 1 ) + + +// +// Manipulators. +// + +PTRACE_LOG +CreateTraceLog( + IN LONG LogSize, + IN LONG ExtraBytesInHeader, + IN LONG EntrySize + ); + +VOID +DestroyTraceLog( + IN PTRACE_LOG Log + ); + +LONG +WriteTraceLog( + IN PTRACE_LOG Log, + IN PVOID Entry + ); + +VOID +ResetTraceLog( + IN PTRACE_LOG Log + ); + + +#if defined(__cplusplus) +} // extern "C" +#endif // __cplusplus + + +#endif // _TRACELOG_H_ + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/treehash.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/treehash.h new file mode 100644 index 0000000000..79f5a83ead --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Include/treehash.h @@ -0,0 +1,850 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#pragma once + +#include +#include "rwlock.h" +#include "prime.h" + +template +class TREE_HASH_NODE +{ + template + friend class TREE_HASH_TABLE; + + private: + // Next node in the hash table look-aside + TREE_HASH_NODE<_Record> *_pNext; + + // links in the tree structure + TREE_HASH_NODE * _pParentNode; + TREE_HASH_NODE * _pFirstChild; + TREE_HASH_NODE * _pNextSibling; + + // actual record + _Record * _pRecord; + + // hash value + PCWSTR _pszPath; + DWORD _dwHash; +}; + +template +class TREE_HASH_TABLE +{ +protected: + typedef BOOL + (PFN_DELETE_IF)( + _Record * pRecord, + PVOID pvContext + ); + + typedef VOID + (PFN_APPLY)( + _Record * pRecord, + PVOID pvContext + ); + +public: + TREE_HASH_TABLE( + BOOL fCaseSensitive + ) : _ppBuckets( NULL ), + _nBuckets( 0 ), + _nItems( 0 ), + _fCaseSensitive( fCaseSensitive ) + { + } + + virtual + ~TREE_HASH_TABLE(); + + virtual + VOID + ReferenceRecord( + _Record * pRecord + ) = 0; + + virtual + VOID + DereferenceRecord( + _Record * pRecord + ) = 0; + + virtual + PCWSTR + GetKey( + _Record * pRecord + ) = 0; + + DWORD + Count() + { + return _nItems; + } + + virtual + VOID + Clear(); + + HRESULT + Initialize( + DWORD nBucketSize + ); + + DWORD + CalcHash( + PCWSTR pszKey + ) + { + return _fCaseSensitive ? HashString(pszKey) : HashStringNoCase(pszKey); + } + + virtual + VOID + FindKey( + PCWSTR pszKey, + _Record ** ppRecord + ); + + virtual + HRESULT + InsertRecord( + _Record * pRecord + ); + + virtual + VOID + DeleteKey( + PCWSTR pszKey + ); + + virtual + VOID + DeleteIf( + PFN_DELETE_IF pfnDeleteIf, + PVOID pvContext + ); + + VOID + Apply( + PFN_APPLY pfnApply, + PVOID pvContext + ); + +private: + + BOOL + FindNodeInternal( + PCWSTR pszKey, + DWORD dwHash, + TREE_HASH_NODE<_Record> ** ppNode, + TREE_HASH_NODE<_Record> *** pppPreviousNodeNextPointer = NULL + ); + + HRESULT + AddNodeInternal( + PCWSTR pszPath, + DWORD dwHash, + _Record * pRecord, + TREE_HASH_NODE<_Record> * pParentNode, + TREE_HASH_NODE<_Record> ** ppNewNode + ); + + HRESULT + AllocateNode( + PCWSTR pszPath, + DWORD dwHash, + _Record * pRecord, + TREE_HASH_NODE<_Record> * pParentNode, + TREE_HASH_NODE<_Record> ** ppNewNode + ); + + VOID + DeleteNode( + TREE_HASH_NODE<_Record> * pNode + ) + { + if (pNode->_pRecord != NULL) + { + DereferenceRecord(pNode->_pRecord); + pNode->_pRecord = NULL; + } + + HeapFree(GetProcessHeap(), + 0, + pNode); + } + + VOID + DeleteNodeInternal( + TREE_HASH_NODE<_Record> ** ppPreviousNodeNextPointer, + TREE_HASH_NODE<_Record> * pNode + ); + + VOID + RehashTableIfNeeded( + VOID + ); + + TREE_HASH_NODE<_Record> ** _ppBuckets; + DWORD _nBuckets; + DWORD _nItems; + BOOL _fCaseSensitive; + CWSDRWLock _tableLock; +}; + +template +HRESULT +TREE_HASH_TABLE<_Record>::AllocateNode( + PCWSTR pszPath, + DWORD dwHash, + _Record * pRecord, + TREE_HASH_NODE<_Record> * pParentNode, + TREE_HASH_NODE<_Record> ** ppNewNode +) +{ + // + // Allocate enough extra space for pszPath + // + DWORD cchPath = (DWORD) wcslen(pszPath); + if (cchPath >= ((0xffffffff - sizeof(TREE_HASH_NODE<_Record>))/sizeof(WCHAR) - 1)) + { + return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); + } + TREE_HASH_NODE<_Record> *pNode = (TREE_HASH_NODE<_Record> *)HeapAlloc( + GetProcessHeap(), + HEAP_ZERO_MEMORY, + sizeof(TREE_HASH_NODE<_Record>) + (cchPath+1)*sizeof(WCHAR)); + if (pNode == NULL) + { + return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); + } + + memcpy(pNode+1, pszPath, (cchPath+1)*sizeof(WCHAR)); + pNode->_pszPath = (PCWSTR)(pNode+1); + pNode->_dwHash = dwHash; + pNode->_pNext = pNode->_pNextSibling = pNode->_pFirstChild = NULL; + pNode->_pParentNode = pParentNode; + pNode->_pRecord = pRecord; + + *ppNewNode = pNode; + return S_OK; +} + +template +HRESULT +TREE_HASH_TABLE<_Record>::Initialize( + DWORD nBuckets +) +{ + HRESULT hr = S_OK; + + if ( nBuckets == 0 ) + { + hr = E_INVALIDARG; + goto Failed; + } + + hr = _tableLock.Init(); + if ( FAILED( hr ) ) + { + goto Failed; + } + + if (nBuckets >= 0xffffffff/sizeof(TREE_HASH_NODE<_Record> *)) + { + hr = E_INVALIDARG; + goto Failed; + } + + _ppBuckets = (TREE_HASH_NODE<_Record> **)HeapAlloc( + GetProcessHeap(), + HEAP_ZERO_MEMORY, + nBuckets*sizeof(TREE_HASH_NODE<_Record> *)); + if (_ppBuckets == NULL) + { + hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); + goto Failed; + } + _nBuckets = nBuckets; + + return S_OK; + +Failed: + + if (_ppBuckets) + { + HeapFree(GetProcessHeap(), + 0, + _ppBuckets); + _ppBuckets = NULL; + } + + return hr; +} + + +template +TREE_HASH_TABLE<_Record>::~TREE_HASH_TABLE() +{ + if (_ppBuckets == NULL) + { + return; + } + + _ASSERTE(_nItems == 0); + + HeapFree(GetProcessHeap(), + 0, + _ppBuckets); + _ppBuckets = NULL; + _nBuckets = 0; +} + +template +VOID +TREE_HASH_TABLE<_Record>::Clear() +{ + TREE_HASH_NODE<_Record> *pCurrent; + TREE_HASH_NODE<_Record> *pNext; + + _tableLock.ExclusiveAcquire(); + + for (DWORD i=0; i<_nBuckets; i++) + { + pCurrent = _ppBuckets[i]; + _ppBuckets[i] = NULL; + while (pCurrent != NULL) + { + pNext = pCurrent->_pNext; + DeleteNode(pCurrent); + pCurrent = pNext; + } + } + + _nItems = 0; + _tableLock.ExclusiveRelease(); +} + +template +BOOL +TREE_HASH_TABLE<_Record>::FindNodeInternal( + PCWSTR pszKey, + DWORD dwHash, + TREE_HASH_NODE<_Record> ** ppNode, + TREE_HASH_NODE<_Record> *** pppPreviousNodeNextPointer +) +/*++ + Return value indicates whether the item is found + key, dwHash - key and hash for the node to find + ppNode - on successful return, the node found, on failed return, the first + node with hash value greater than the node to be found + pppPreviousNodeNextPointer - the pointer to previous node's _pNext + + This routine may be called under either read or write lock +--*/ +{ + TREE_HASH_NODE<_Record> **ppPreviousNodeNextPointer; + TREE_HASH_NODE<_Record> *pNode; + BOOL fFound = FALSE; + + ppPreviousNodeNextPointer = _ppBuckets + (dwHash % _nBuckets); + pNode = *ppPreviousNodeNextPointer; + while (pNode != NULL) + { + if (pNode->_dwHash == dwHash) + { + if (CompareStringOrdinal(pszKey, + -1, + pNode->_pszPath, + -1, + !_fCaseSensitive) == CSTR_EQUAL) + { + fFound = TRUE; + break; + } + } + else if (pNode->_dwHash > dwHash) + { + break; + } + + ppPreviousNodeNextPointer = &(pNode->_pNext); + pNode = *ppPreviousNodeNextPointer; + } + + *ppNode = pNode; + if (pppPreviousNodeNextPointer != NULL) + { + *pppPreviousNodeNextPointer = ppPreviousNodeNextPointer; + } + return fFound; +} + +template +VOID +TREE_HASH_TABLE<_Record>::FindKey( + PCWSTR pszKey, + _Record ** ppRecord +) +{ + TREE_HASH_NODE<_Record> *pNode; + + *ppRecord = NULL; + + DWORD dwHash = CalcHash(pszKey); + + _tableLock.SharedAcquire(); + + if (FindNodeInternal(pszKey, dwHash, &pNode) && + pNode->_pRecord != NULL) + { + ReferenceRecord(pNode->_pRecord); + *ppRecord = pNode->_pRecord; + } + + _tableLock.SharedRelease(); +} + +template +HRESULT +TREE_HASH_TABLE<_Record>::AddNodeInternal( + PCWSTR pszPath, + DWORD dwHash, + _Record * pRecord, + TREE_HASH_NODE<_Record> * pParentNode, + TREE_HASH_NODE<_Record> ** ppNewNode +) +/*++ + Return value is HRESULT indicating sucess or failure + pszPath, dwHash, pRecord - path, hash value and record to be inserted + pParentNode - this will be the parent of the node being inserted + ppNewNode - on successful return, the new node created and inserted + + This function may be called under a read or write lock +--*/ +{ + TREE_HASH_NODE<_Record> *pNewNode; + TREE_HASH_NODE<_Record> *pNextNode; + TREE_HASH_NODE<_Record> **ppNextPointer; + HRESULT hr; + + // + // Ownership of pRecord is not transferred to pNewNode yet, so remember + // to either set it to null before deleting pNewNode or add an extra + // reference later - this is to make sure we do not do an extra ref/deref + // which users may view as getting flushed out of the hash-table + // + hr = AllocateNode(pszPath, + dwHash, + pRecord, + pParentNode, + &pNewNode); + if (FAILED(hr)) + { + return hr; + } + + do + { + // + // Find the right place to add this node + // + + if (FindNodeInternal(pszPath, dwHash, &pNextNode, &ppNextPointer)) + { + // + // If node already there, record may still need updating + // + if (pRecord != NULL && + InterlockedCompareExchangePointer((PVOID *)&pNextNode->_pRecord, + pRecord, + NULL) == NULL) + { + ReferenceRecord(pRecord); + hr = S_OK; + } + else + { + hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS); + } + + // ownership of pRecord has either passed to existing record or + // not to anyone at all + pNewNode->_pRecord = NULL; + DeleteNode(pNewNode); + *ppNewNode = pNextNode; + return hr; + } + + // + // If another node got inserted in betwen, we will have to retry + // + pNewNode->_pNext = pNextNode; + } while (InterlockedCompareExchangePointer((PVOID *)ppNextPointer, + pNewNode, + pNextNode) != pNextNode); + // pass ownership of pRecord now + if (pRecord != NULL) + { + ReferenceRecord(pRecord); + pRecord = NULL; + } + InterlockedIncrement((LONG *)&_nItems); + + // + // update the parent + // + if (pParentNode != NULL) + { + ppNextPointer = &pParentNode->_pFirstChild; + do + { + pNextNode = *ppNextPointer; + pNewNode->_pNextSibling = pNextNode; + } while (InterlockedCompareExchangePointer((PVOID *)ppNextPointer, + pNewNode, + pNextNode) != pNextNode); + } + + *ppNewNode = pNewNode; + return S_OK; +} + +template +HRESULT +TREE_HASH_TABLE<_Record>::InsertRecord( + _Record * pRecord +) +/*++ + This method inserts a node for this record and also empty nodes for paths + in the heirarchy leading upto this path + + The insert is done under only a read-lock - this is possible by keeping + the hashes in a bucket in increasing order and using interlocked operations + to actually insert the item in the hash-bucket lookaside list and the parent + children list + + Returns HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS) if the record already exists. + Never leak this error to the end user because "*file* already exists" may be confusing. +--*/ +{ + PCWSTR pszKey = GetKey(pRecord); + STACK_STRU( strPartialPath, 256); + PWSTR pszPartialPath; + DWORD dwHash; + DWORD cchEnd; + HRESULT hr; + TREE_HASH_NODE<_Record> *pParentNode = NULL; + + hr = strPartialPath.Copy(pszKey); + if (FAILED(hr)) + { + goto Finished; + } + pszPartialPath = strPartialPath.QueryStr(); + + _tableLock.SharedAcquire(); + + // + // First find the lowest parent node present + // + for (cchEnd = strPartialPath.QueryCCH() - 1; cchEnd > 0; cchEnd--) + { + if (pszPartialPath[cchEnd] == L'/' || pszPartialPath[cchEnd] == L'\\') + { + pszPartialPath[cchEnd] = L'\0'; + + dwHash = CalcHash(pszPartialPath); + if (FindNodeInternal(pszPartialPath, dwHash, &pParentNode)) + { + pszPartialPath[cchEnd] = pszKey[cchEnd]; + break; + } + pParentNode = NULL; + } + } + + // + // Now go ahead and add the rest of the tree (including our record) + // + for (; cchEnd <= strPartialPath.QueryCCH(); cchEnd++) + { + if (pszPartialPath[cchEnd] == L'\0') + { + dwHash = CalcHash(pszPartialPath); + hr = AddNodeInternal( + pszPartialPath, + dwHash, + (cchEnd == strPartialPath.QueryCCH()) ? pRecord : NULL, + pParentNode, + &pParentNode); + if (FAILED(hr) && + hr != HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS)) + { + goto Finished; + } + + pszPartialPath[cchEnd] = pszKey[cchEnd]; + } + } + +Finished: + _tableLock.SharedRelease(); + + if (SUCCEEDED(hr)) + { + RehashTableIfNeeded(); + } + + return hr; +} + +template +VOID +TREE_HASH_TABLE<_Record>::DeleteNodeInternal( + TREE_HASH_NODE<_Record> ** ppNextPointer, + TREE_HASH_NODE<_Record> * pNode +) +/*++ + pNode is the node to be deleted + ppNextPointer is the pointer to the previous node's next pointer pointing + to this node + + This function should be called under write-lock +--*/ +{ + // + // First remove this node from hash table + // + *ppNextPointer = pNode->_pNext; + + // + // Now fixup parent + // + if (pNode->_pParentNode != NULL) + { + ppNextPointer = &pNode->_pParentNode->_pFirstChild; + while (*ppNextPointer != pNode) + { + ppNextPointer = &(*ppNextPointer)->_pNextSibling; + } + *ppNextPointer = pNode->_pNextSibling; + } + + // + // Now remove all children recursively + // + TREE_HASH_NODE<_Record> *pChild = pNode->_pFirstChild; + TREE_HASH_NODE<_Record> *pNextChild; + while (pChild != NULL) + { + pNextChild = pChild->_pNextSibling; + + ppNextPointer = _ppBuckets + (pChild->_dwHash % _nBuckets); + while (*ppNextPointer != pChild) + { + ppNextPointer = &(*ppNextPointer)->_pNext; + } + pChild->_pParentNode = NULL; + DeleteNodeInternal(ppNextPointer, pChild); + + pChild = pNextChild; + } + + DeleteNode(pNode); + _nItems--; +} + +template +VOID +TREE_HASH_TABLE<_Record>::DeleteKey( + PCWSTR pszKey +) +{ + TREE_HASH_NODE<_Record> *pNode; + TREE_HASH_NODE<_Record> **ppPreviousNodeNextPointer; + + DWORD dwHash = CalcHash(pszKey); + + _tableLock.ExclusiveAcquire(); + + if (FindNodeInternal(pszKey, dwHash, &pNode, &ppPreviousNodeNextPointer)) + { + DeleteNodeInternal(ppPreviousNodeNextPointer, pNode); + } + + _tableLock.ExclusiveRelease(); +} + +template +VOID +TREE_HASH_TABLE<_Record>::DeleteIf( + PFN_DELETE_IF pfnDeleteIf, + PVOID pvContext +) +{ + TREE_HASH_NODE<_Record> *pNode; + TREE_HASH_NODE<_Record> **ppPreviousNodeNextPointer; + BOOL fDelete; + + _tableLock.ExclusiveAcquire(); + + for (DWORD i=0; i<_nBuckets; i++) + { + ppPreviousNodeNextPointer = _ppBuckets + i; + pNode = *ppPreviousNodeNextPointer; + while (pNode != NULL) + { + // + // Non empty nodes deleted based on DeleteIf, empty nodes deleted + // if they have no children + // + fDelete = FALSE; + if (pNode->_pRecord != NULL) + { + if (pfnDeleteIf(pNode->_pRecord, pvContext)) + { + fDelete = TRUE; + } + } + else if (pNode->_pFirstChild == NULL) + { + fDelete = TRUE; + } + + if (fDelete) + { + if (pNode->_pFirstChild == NULL) + { + DeleteNodeInternal(ppPreviousNodeNextPointer, pNode); + } + else + { + DereferenceRecord(pNode->_pRecord); + pNode->_pRecord = NULL; + } + } + else + { + ppPreviousNodeNextPointer = &pNode->_pNext; + } + + pNode = *ppPreviousNodeNextPointer; + } + } + + _tableLock.ExclusiveRelease(); +} + +template +VOID +TREE_HASH_TABLE<_Record>::Apply( + PFN_APPLY pfnApply, + PVOID pvContext +) +{ + TREE_HASH_NODE<_Record> *pNode; + + _tableLock.SharedAcquire(); + + for (DWORD i=0; i<_nBuckets; i++) + { + pNode = _ppBuckets[i]; + while (pNode != NULL) + { + if (pNode->_pRecord != NULL) + { + pfnApply(pNode->_pRecord, pvContext); + } + + pNode = pNode->_pNext; + } + } + + _tableLock.SharedRelease(); +} + +template +VOID +TREE_HASH_TABLE<_Record>::RehashTableIfNeeded( + VOID +) +{ + TREE_HASH_NODE<_Record> **ppBuckets; + DWORD nBuckets; + TREE_HASH_NODE<_Record> *pNode; + TREE_HASH_NODE<_Record> *pNextNode; + TREE_HASH_NODE<_Record> **ppNextPointer; + TREE_HASH_NODE<_Record> *pNewNextNode; + DWORD nNewBuckets; + + // + // If number of items has become too many, we will double the hash table + // size (we never reduce it however) + // + if (_nItems <= PRIME::GetPrime(2*_nBuckets)) + { + return; + } + + _tableLock.ExclusiveAcquire(); + + nNewBuckets = PRIME::GetPrime(2*_nBuckets); + + if (_nItems <= nNewBuckets) + { + goto Finished; + } + + nBuckets = nNewBuckets; + if (nBuckets >= 0xffffffff/sizeof(TREE_HASH_NODE<_Record> *)) + { + goto Finished; + } + ppBuckets = (TREE_HASH_NODE<_Record> **)HeapAlloc( + GetProcessHeap(), + HEAP_ZERO_MEMORY, + nBuckets*sizeof(TREE_HASH_NODE<_Record> *)); + if (ppBuckets == NULL) + { + goto Finished; + } + + // + // Take out nodes from the old hash table and insert in the new one, make + // sure to keep the hashes in increasing order + // + for (DWORD i=0; i<_nBuckets; i++) + { + pNode = _ppBuckets[i]; + while (pNode != NULL) + { + pNextNode = pNode->_pNext; + + ppNextPointer = ppBuckets + (pNode->_dwHash % nBuckets); + pNewNextNode = *ppNextPointer; + while (pNewNextNode != NULL && + pNewNextNode->_dwHash <= pNode->_dwHash) + { + ppNextPointer = &pNewNextNode->_pNext; + pNewNextNode = pNewNextNode->_pNext; + } + pNode->_pNext = pNewNextNode; + *ppNextPointer = pNode; + + pNode = pNextNode; + } + } + + HeapFree(GetProcessHeap(), 0, _ppBuckets); + _ppBuckets = ppBuckets; + _nBuckets = nBuckets; + ppBuckets = NULL; + +Finished: + + _tableLock.ExclusiveRelease(); +} + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/LICENSE b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/LICENSE new file mode 100644 index 0000000000..21071075c2 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/LICENSE @@ -0,0 +1,21 @@ + MIT License + + Copyright (c) Microsoft Corporation. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/MySQL/MySqlConnector.cs b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/MySQL/MySqlConnector.cs new file mode 100644 index 0000000000..ee607e28c7 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/MySQL/MySqlConnector.cs @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using System; + +namespace Microsoft.Web.Utility +{ + internal static class MySqlConnector + { + public static string[] HardCodedAssemblyVersions + { + get + { + return new string[] + { + "MySql.Data, Version=6.5.4.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d", + "MySql.Data, Version=6.4.4.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d", + "MySql.Data, Version=6.3.7.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d", + "MySql.Data, Version=6.2.3.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d", + "MySql.Data, Version=6.0.4.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d", + "MySql.Data, Version=6.0.3.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d", + "MySql.Data, Version=5.2.6.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d", + "MySql.Data, Version=5.2.5.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d", + }; + } + } + } +} \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/NativeMethods/AdvApi32.cs b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/NativeMethods/AdvApi32.cs new file mode 100644 index 0000000000..9dc6dbfc23 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/NativeMethods/AdvApi32.cs @@ -0,0 +1,386 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using System; +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; +using System.Text; +using System.Security; +using System.Runtime.Versioning; +using System.Runtime.ConstrainedExecution; +using Microsoft.Win32.SafeHandles; + +namespace Microsoft.Web.Management.PInvoke.AdvApi32 +{ + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct TOKEN_PRIVILEGES + { + public UInt32 PrivilegeCount; + public long Luid; + public UInt32 Attributes; + } + + internal enum TOKEN_INFORMATION_CLASS + { + /// + /// The buffer receives a TOKEN_USER structure that contains the user account of the token. + /// + TokenUser = 1, + + /// + /// The buffer receives a TOKEN_GROUPS structure that contains the group accounts associated with the token. + /// + TokenGroups, + + /// + /// The buffer receives a TOKEN_PRIVILEGES structure that contains the privileges of the token. + /// + TokenPrivileges, + + /// + /// The buffer receives a TOKEN_OWNER structure that contains the default owner security identifier (SID) for newly created objects. + /// + TokenOwner, + + /// + /// The buffer receives a TOKEN_PRIMARY_GROUP structure that contains the default primary group SID for newly created objects. + /// + TokenPrimaryGroup, + + /// + /// The buffer receives a TOKEN_DEFAULT_DACL structure that contains the default DACL for newly created objects. + /// + TokenDefaultDacl, + + /// + /// The buffer receives a TOKEN_SOURCE structure that contains the source of the token. TOKEN_QUERY_SOURCE access is needed to retrieve this information. + /// + TokenSource, + + /// + /// The buffer receives a TOKEN_TYPE value that indicates whether the token is a primary or impersonation token. + /// + TokenType, + + /// + /// The buffer receives a SECURITY_IMPERSONATION_LEVEL value that indicates the impersonation level of the token. If the access token is not an impersonation token, the function fails. + /// + TokenImpersonationLevel, + + /// + /// The buffer receives a TOKEN_STATISTICS structure that contains various token statistics. + /// + TokenStatistics, + + /// + /// The buffer receives a TOKEN_GROUPS structure that contains the list of restricting SIDs in a restricted token. + /// + TokenRestrictedSids, + + /// + /// The buffer receives a DWORD value that indicates the Terminal Services session identifier that is associated with the token. + /// + TokenSessionId, + + /// + /// The buffer receives a TOKEN_GROUPS_AND_PRIVILEGES structure that contains the user SID, the group accounts, the restricted SIDs, and the authentication ID associated with the token. + /// + TokenGroupsAndPrivileges, + + /// + /// Reserved. + /// + TokenSessionReference, + + /// + /// The buffer receives a DWORD value that is nonzero if the token includes the SANDBOX_INERT flag. + /// + TokenSandBoxInert, + + /// + /// Reserved. + /// + TokenAuditPolicy, + + /// + /// The buffer receives a TOKEN_ORIGIN value. + /// + TokenOrigin, + + /// + /// The buffer receives a TOKEN_ELEVATION_TYPE value that specifies the elevation level of the token. + /// + TokenElevationType, + + /// + /// The buffer receives a TOKEN_LINKED_TOKEN structure that contains a handle to another token that is linked to this token. + /// + TokenLinkedToken, + + /// + /// The buffer receives a TOKEN_ELEVATION structure that specifies whether the token is elevated. + /// + TokenElevation, + + /// + /// The buffer receives a DWORD value that is nonzero if the token has ever been filtered. + /// + TokenHasRestrictions, + + /// + /// The buffer receives a TOKEN_ACCESS_INFORMATION structure that specifies security information contained in the token. + /// + TokenAccessInformation, + + /// + /// The buffer receives a DWORD value that is nonzero if virtualization is allowed for the token. + /// + TokenVirtualizationAllowed, + + /// + /// The buffer receives a DWORD value that is nonzero if virtualization is enabled for the token. + /// + TokenVirtualizationEnabled, + + /// + /// The buffer receives a TOKEN_MANDATORY_LABEL structure that specifies the token's integrity level. + /// + TokenIntegrityLevel, + + /// + /// The buffer receives a DWORD value that is nonzero if the token has the UIAccess flag set. + /// + TokenUIAccess, + + /// + /// The buffer receives a TOKEN_MANDATORY_POLICY structure that specifies the token's mandatory integrity policy. + /// + TokenMandatoryPolicy, + + /// + /// The buffer receives the token's logon security identifier (SID). + /// + TokenLogonSid, + + /// + /// The maximum value for this enumeration + /// + MaxTokenInfoClass + } + + internal enum TOKEN_ELEVATION_TYPE + { + TokenElevationTypeDefault = 1, + TokenElevationTypeFull, + TokenElevationTypeLimited + } + + [Flags] + internal enum AccessTokenRights : uint + { + STANDARD_RIGHTS_REQUIRED = 0x000F0000, + STANDARD_RIGHTS_READ = 0x00020000, + TOKEN_ASSIGN_PRIMARY = 0x0001, + TOKEN_DUPLICATE = 0x0002, + TOKEN_IMPERSONATE = 0x0004, + TOKEN_QUERY = 0x0008, + TOKEN_QUERY_SOURCE = 0x0010, + TOKEN_ADJUST_PRIVILEGES = 0x0020, + TOKEN_ADJUST_GROUPS = 0x0040, + TOKEN_ADJUST_DEFAULT = 0x0080, + TOKEN_ADJUST_SESSIONID = 0x0100, + TOKEN_READ = STANDARD_RIGHTS_READ | TOKEN_QUERY, + TOKEN_ALL_ACCESS = + STANDARD_RIGHTS_REQUIRED | + TOKEN_ASSIGN_PRIMARY | + TOKEN_DUPLICATE | + TOKEN_IMPERSONATE | + TOKEN_QUERY | + TOKEN_QUERY_SOURCE | + TOKEN_ADJUST_PRIVILEGES | + TOKEN_ADJUST_GROUPS | + TOKEN_ADJUST_DEFAULT | + TOKEN_ADJUST_SESSIONID + } + + internal static class NativeMethods + { + private const String ADVAPI32 = "advapi32.dll"; + + // TODO: Should be moved into enums? + internal const int READ_CONTROL = 0x00020000; + internal const int SYNCHRONIZE = 0x00100000; + internal const int STANDARD_RIGHTS_READ = READ_CONTROL; + internal const int STANDARD_RIGHTS_WRITE = READ_CONTROL; + + internal const int KEY_QUERY_VALUE = 0x0001; + internal const int KEY_SET_VALUE = 0x0002; + internal const int KEY_CREATE_SUB_KEY = 0x0004; + internal const int KEY_ENUMERATE_SUB_KEYS = 0x0008; + internal const int KEY_NOTIFY = 0x0010; + + internal const int KEY_READ = ((STANDARD_RIGHTS_READ | + KEY_QUERY_VALUE | + KEY_ENUMERATE_SUB_KEYS | + KEY_NOTIFY) + & + (~SYNCHRONIZE)); + + internal const int KEY_WRITE = ((STANDARD_RIGHTS_WRITE | + KEY_SET_VALUE | + KEY_CREATE_SUB_KEY) + & + (~SYNCHRONIZE)); + + internal const int KEY_WOW64_64KEY = 0x0100; + internal const int KEY_WOW64_32KEY = 0x0200; + + internal const int ERROR_MORE_DATA = 0xEA; + internal const int ERROR_ACCESS_DENIED = 0x5; + + internal const int REG_OPTION_NON_VOLATILE = 0x0000; // (default) keys are persisted beyond reboot/unload + internal const int REG_OPTION_VOLATILE = 0x0001; // All keys created by the function are volatile + internal const int REG_OPTION_CREATE_LINK = 0x0002; // They key is a symbolic link + internal const int REG_OPTION_BACKUP_RESTORE = 0x0004; // Use SE_BACKUP_NAME process special privileges + internal const int REG_NONE = 0; // No value type + internal const int REG_SZ = 1; // Unicode nul terminated string + internal const int REG_EXPAND_SZ = 2; // Unicode nul terminated string + internal const int REG_BINARY = 3; // Free form binary + internal const int REG_DWORD = 4; // 32-bit number + internal const int REG_DWORD_LITTLE_ENDIAN = 4; // 32-bit number (same as REG_DWORD) + internal const int REG_DWORD_BIG_ENDIAN = 5; // 32-bit number + internal const int REG_LINK = 6; // Symbolic Link (unicode) + internal const int REG_MULTI_SZ = 7; // Multiple Unicode strings + internal const int REG_RESOURCE_LIST = 8; // Resource list in the resource map + internal const int REG_FULL_RESOURCE_DESCRIPTOR = 9; // Resource list in the hardware description + internal const int REG_RESOURCE_REQUIREMENTS_LIST = 10; + internal const int REG_QWORD = 11; // 64-bit number + + [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool AdjustTokenPrivileges( + SafeHandleZeroIsInvalid TokenHandle, + [MarshalAs(UnmanagedType.Bool)] + bool DisableAllPrivileges, + ref TOKEN_PRIVILEGES NewState, + int len, + IntPtr prev, + IntPtr relen); + + [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool LookupPrivilegeValue(string host, string name, ref long pluid); + + [DllImport("advapi32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetTokenInformation( + SafeHandleZeroIsInvalid TokenHandle, + TOKEN_INFORMATION_CLASS TokenInformationClass, + HGlobalBuffer TokenInformation, + int TokenInformationLength, + out int ReturnLength); + + [DllImport("advapi32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool OpenProcessToken( + SafeHandleZeroIsInvalid ProcessHandle, + AccessTokenRights DesiredAccess, + out SafeHandleZeroIsInvalid TokenHandle); + + [DllImport("ADVAPI32.DLL"), + SuppressUnmanagedCodeSecurity, + ResourceExposure(ResourceScope.None), + ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + internal static extern int RegCloseKey(IntPtr hKey); + + [DllImport(ADVAPI32, CharSet = CharSet.Auto, BestFitMapping = false)] + internal static extern int RegOpenKeyEx(SafeRegistryHandle hKey, String lpSubKey, + int ulOptions, int samDesired, out SafeRegistryHandle hkResult); + + [DllImport(ADVAPI32, CharSet = CharSet.Auto, BestFitMapping = false)] + internal static extern int RegQueryValueEx(SafeRegistryHandle hKey, String lpValueName, + int[] lpReserved, ref int lpType, [Out] byte[] lpData, + ref int lpcbData); + + [DllImport(ADVAPI32, CharSet = CharSet.Auto, BestFitMapping = false)] + internal static extern int RegQueryValueEx(SafeRegistryHandle hKey, String lpValueName, + int[] lpReserved, ref int lpType, ref int lpData, + ref int lpcbData); + + [DllImport(ADVAPI32, CharSet = CharSet.Auto, BestFitMapping = false)] + internal static extern int RegQueryValueEx(SafeRegistryHandle hKey, String lpValueName, + int[] lpReserved, ref int lpType, ref long lpData, + ref int lpcbData); + + [DllImport(ADVAPI32, CharSet = CharSet.Auto, BestFitMapping = false)] + internal static extern int RegQueryValueEx(SafeRegistryHandle hKey, String lpValueName, + int[] lpReserved, ref int lpType, [Out] char[] lpData, + ref int lpcbData); + + [DllImport(ADVAPI32, CharSet = CharSet.Auto, BestFitMapping = false)] + internal static extern int RegQueryValueEx(SafeRegistryHandle hKey, String lpValueName, + int[] lpReserved, ref int lpType, StringBuilder lpData, + ref int lpcbData); + + public static void EnableShutdownPrivilege() + { + const int SE_PRIVILEGE_ENABLED = 0x00000002; + const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege"; + + bool retVal; + + using (SafeHandleZeroIsInvalid hproc = Kernel32.NativeMethods.GetCurrentProcess()) + { + TOKEN_PRIVILEGES tp; + SafeHandleZeroIsInvalid htok; + retVal = OpenProcessToken(hproc, AccessTokenRights.TOKEN_ADJUST_PRIVILEGES | AccessTokenRights.TOKEN_QUERY, out htok); + if (!retVal) + { + throw new Win32Exception(Marshal.GetLastWin32Error()); + } + + using (htok) + { + tp.PrivilegeCount = 1; + tp.Luid = 0; + tp.Attributes = SE_PRIVILEGE_ENABLED; + retVal = LookupPrivilegeValue(null, SE_SHUTDOWN_NAME, ref tp.Luid); + if (!retVal) + { + throw new Win32Exception(Marshal.GetLastWin32Error()); + } + + retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero); + if (!retVal) + { + throw new Win32Exception(Marshal.GetLastWin32Error()); + } + } + } + } + } + + [SecurityCritical] + internal sealed class SafeRegistryHandle : SafeHandleZeroOrMinusOneIsInvalid + { + [SecurityCritical] + internal SafeRegistryHandle() + : base(true) + { + } + + [SecurityCritical] + public SafeRegistryHandle(IntPtr preexistingHandle, bool ownsHandle) + : base(ownsHandle) + { + SetHandle(preexistingHandle); + } + + [SecurityCritical] + override protected bool ReleaseHandle() + { + return (Microsoft.Web.Management.PInvoke.AdvApi32.NativeMethods.RegCloseKey(handle) == 0); + } + } +} \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/NativeMethods/Common.cs b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/NativeMethods/Common.cs new file mode 100644 index 0000000000..6d6a3209a7 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/NativeMethods/Common.cs @@ -0,0 +1,111 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using System; +using System.Runtime.InteropServices; + +// Any reference to Common.cs should also include Kernel32.cs because +// SafeHandleZeroIsInvalid (from Common.cs) uses CloseHandle (from Kernel32.cs) +namespace Microsoft.Web.Management.PInvoke +{ + internal enum Win32ErrorCode + { + ERROR_FILE_NOT_FOUND = 2, + ERROR_PATH_NOT_FOUND = 3, + ERROR_ACCESS_DENIED = 5, + ERROR_INVALID_HANDLE = 6, + ERROR_INVALID_DRIVE = 15, + ERROR_NO_MORE_FILES = 18, + ERROR_NOT_READY = 21, + ERROR_SHARING_VIOLATION = 32, + ERROR_FILE_EXISTS = 80, + ERROR_INVALID_PARAMETER = 87, // 0x57 + ERROR_INVALID_NAME = 123, // 0x7b + ERROR_BAD_PATHNAME = 161, + ERROR_ALREADY_EXISTS = 183, + ERROR_FILENAME_EXCED_RANGE = 206, + ERROR_OPERATION_ABORTED = 995, + ELEMENT_NOT_FOUND = 0x490 + } + + internal static class Extension + { + public static int AsHRESULT(Win32ErrorCode errorCode) + { + return (int)((uint)errorCode | 0x80070000); + } + } + + internal class SafeHandleZeroIsInvalid : SafeHandle + { + public SafeHandleZeroIsInvalid() + : base(IntPtr.Zero, true) + { + } + + public SafeHandleZeroIsInvalid(IntPtr newHandle) + : base(IntPtr.Zero, true) + { + this.SetHandle(newHandle); + } + + public override bool IsInvalid + { + get + { + return this.handle == IntPtr.Zero; + } + } + + protected override bool ReleaseHandle() + { + return Kernel32.NativeMethods.CloseHandle(this.handle); + } + } + + internal class HGlobalBuffer : SafeHandle + { + private int _size; + + public HGlobalBuffer(int size) + : base(IntPtr.Zero, true) + { + _size = size; + this.handle = Marshal.AllocHGlobal(size); + } + + protected override bool ReleaseHandle() + { + if (!this.IsInvalid) + { + Marshal.FreeHGlobal(this.handle); + this.handle = IntPtr.Zero; + } + + return true; + } + + public override bool IsInvalid + { + get + { + return this.handle == IntPtr.Zero; + } + } + + public T GetCopyAs() + { + return (T)Marshal.PtrToStructure(this.handle, typeof(T)); + } + + public int Size + { + get + { + return _size; + } + } + + public static readonly HGlobalBuffer NULL = new HGlobalBuffer(0); + } +} diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/NativeMethods/Fusion.cs b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/NativeMethods/Fusion.cs new file mode 100644 index 0000000000..dd3391ff94 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/NativeMethods/Fusion.cs @@ -0,0 +1,179 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using System; +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; +using System.Text; + +namespace Microsoft.Web.Utility.PInvoke.Fusion +{ + [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("CD193BC0-B4BC-11d2-9833-00C04FC31D2E")] + internal interface IAssemblyName + { + [PreserveSig()] + int SetProperty( + int PropertyId, + IntPtr pvProperty, + int cbProperty); + + [PreserveSig()] + int GetProperty( + int PropertyId, + IntPtr pvProperty, + ref int pcbProperty); + + [PreserveSig()] + int Finalize(); + + [PreserveSig()] + int GetDisplayName( + StringBuilder pDisplayName, + ref int pccDisplayName, + int displayFlags); + + [PreserveSig()] + int Reserved(ref Guid guid, + Object obj1, + Object obj2, + String string1, + Int64 llFlags, + IntPtr pvReserved, + int cbReserved, + out IntPtr ppv); + + [PreserveSig()] + int GetName( + ref int pccBuffer, + StringBuilder pwzName); + + [PreserveSig()] + int GetVersion( + out int versionHi, + out int versionLow); + [PreserveSig()] + int IsEqual( + IAssemblyName pAsmName, + int cmpFlags); + + [PreserveSig()] + int Clone(out IAssemblyName pAsmName); + }// IAssemblyName + + [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("e707dcde-d1cd-11d2-bab9-00c04f8eceae")] + internal interface IAssemblyCache + { + [PreserveSig()] + int UninstallAssembly( + int flags, + [MarshalAs(UnmanagedType.LPWStr)] + string assemblyName, + IntPtr refData, + out int disposition); + + [PreserveSig()] + int QueryAssemblyInfo( + int flags, + [MarshalAs(UnmanagedType.LPWStr)] + string assemblyName, + ref AssemblyInfo assemblyInfo); + [PreserveSig()] + int Reserved( + int flags, + IntPtr pvReserved, + out object ppAsmItem, + [MarshalAs(UnmanagedType.LPWStr)] + string assemblyName); + [PreserveSig()] + int Reserved(out object ppAsmScavenger); + + [PreserveSig()] + int InstallAssembly( + int flags, + [MarshalAs(UnmanagedType.LPWStr)] + string assemblyFilePath, + IntPtr refData); + }// IAssemblyCache + + [StructLayout(LayoutKind.Sequential)] + internal struct AssemblyInfo + { + public int cbAssemblyInfo; // size of this structure for future expansion + public int assemblyFlags; + public long assemblySizeInKB; + [MarshalAs(UnmanagedType.LPWStr)] + public string currentAssemblyPath; + public int cchBuf; // size of path buf. + } + + [Flags] + internal enum AssemblyCacheFlags + { + GAC = 2, + } + + [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("21b8916c-f28e-11d2-a473-00c04f8ef448")] + internal interface IAssemblyEnum + { + [PreserveSig()] + int GetNextAssembly( + IntPtr pvReserved, + out IAssemblyName ppName, + int flags); + + [PreserveSig()] + int Reset(); + [PreserveSig()] + int Clone(out IAssemblyEnum ppEnum); + } + + [Flags] + internal enum AssemblyNameDisplayFlags + { + VERSION = 0x01, + CULTURE = 0x02, + PUBLIC_KEY_TOKEN = 0x04, + PROCESSORARCHITECTURE = 0x20, + RETARGETABLE = 0x80, + + // This enum might change in the future to include + // more attributes. + ALL = + VERSION + | CULTURE + | PUBLIC_KEY_TOKEN + | PROCESSORARCHITECTURE + | RETARGETABLE + } + + internal enum CreateAssemblyNameObjectFlags + { + CANOF_DEFAULT = 0, + CANOF_PARSE_DISPLAY_NAME = 1, + } + + internal static class NativeMethods + { + [DllImport("fusion.dll")] + public static extern int CreateAssemblyCache( + out IAssemblyCache ppAsmCache, + int reserved); + + [DllImport("fusion.dll")] + public static extern int CreateAssemblyEnum( + out IAssemblyEnum ppEnum, + IntPtr pUnkReserved, + IAssemblyName pName, + AssemblyCacheFlags flags, + IntPtr pvReserved); + + [DllImport("fusion.dll")] + public static extern int CreateAssemblyNameObject( + out IAssemblyName ppAssemblyNameObj, + [MarshalAs(UnmanagedType.LPWStr)] + String szAssemblyName, + CreateAssemblyNameObjectFlags flags, + IntPtr pvReserved); + } +} diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/NativeMethods/Kernel32.cs b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/NativeMethods/Kernel32.cs new file mode 100644 index 0000000000..91265956b5 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/NativeMethods/Kernel32.cs @@ -0,0 +1,99 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using System; +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; + +// Any reference to Common.cs should also include Kernel32.cs because +// SafeHandleZeroIsInvalid (from Common.cs) uses CloseHandle (from Kernel32.cs) +namespace Microsoft.Web.Management.PInvoke.Kernel32 +{ + internal enum OSProductType : byte + { + VER_NT_WORKSTATION = 0x0000001, + VER_NT_SERVER = 0x0000003, + VER_NT_DOMAIN_CONTROLLER = 0x0000002, + } + + [StructLayout(LayoutKind.Sequential)] + internal struct OSVERSIONINFOEX + { + public int dwOSVersionInfoSize; + public int dwMajorVersion; + public int dwMinorVersion; + public int dwBuildNumber; + public int dwPlatformId; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] + public string szCSDVersion; + public short wServicePackMajor; + public short wServicePackMinor; + public short wSuiteMask; + public OSProductType wProductType; + public byte wReserved; + + public bool IsServer + { + get + { + return + wProductType == OSProductType.VER_NT_SERVER || + wProductType == OSProductType.VER_NT_DOMAIN_CONTROLLER; + } + } + + public bool IsClient + { + get + { + return + wProductType == OSProductType.VER_NT_WORKSTATION; + } + } + } + + internal static class NativeMethods + { + public static OSVERSIONINFOEX GetVersionEx() + { + OSVERSIONINFOEX osVersionInfo = new OSVERSIONINFOEX(); + osVersionInfo.dwOSVersionInfoSize = Marshal.SizeOf(typeof(OSVERSIONINFOEX)); + if (!GetVersionEx(ref osVersionInfo)) + { + throw new Win32Exception(); + } + + return osVersionInfo; + } + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool CloseHandle(IntPtr hHandle); + + [DllImport("kernel32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + [SuppressMessage("Microsoft.Usage", "CA2205:UseManagedEquivalentsOfWin32Api", Justification = "GetVersionEx returns more information")] + private static extern bool GetVersionEx(ref OSVERSIONINFOEX osVersionInfo); + + [DllImport("kernel32.dll", ExactSpelling = true)] + internal static extern SafeHandleZeroIsInvalid GetCurrentProcess(); + + // WARNING: Vista+ ONLY + [DllImport("kernel32.dll", CharSet = CharSet.Auto)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool GetProductInfo(uint dwOSMajorVersion, uint dwOSMinorVersion, uint dwSpMajorVersion, uint spMinorVersion, out uint pdwReturnedProductType); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool Wow64DisableWow64FsRedirection(ref IntPtr ptr); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool Wow64RevertWow64FsRedirection(IntPtr ptr); + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool WritePrivateProfileString(string applicationName, string keyName, string stringValue, string fileName); + } +} diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/NativeMethods/Mlang.cs b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/NativeMethods/Mlang.cs new file mode 100644 index 0000000000..e6e1ff51bd --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/NativeMethods/Mlang.cs @@ -0,0 +1,768 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.ComTypes; + +namespace Microsoft.Web.Management.PInvoke.MLang +{ + internal enum HRESULT : uint + { + S_OK = 0x0, + S_FALSE = 0x1, + E_FAIL = 0x80004005, + } + + internal static class NativeMethods + { + [StructLayout(LayoutKind.Explicit, Pack = 4)] + public struct __MIDL_IWinTypes_0009 + { + // Fields + [FieldOffset(0)] + public int hInproc; + [FieldOffset(0)] + public int hRemote; + } + + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct _RemotableHandle + { + public int fContext; + public __MIDL_IWinTypes_0009 u; + } + + [ComImport, CoClass(typeof(CMLangConvertCharsetClass)), Guid("D66D6F98-CDAA-11D0-B822-00C04FC9B31F")] + public interface CMLangConvertCharset : IMLangConvertCharset + { + } + + [ComImport, TypeLibType((short)2), Guid("D66D6F99-CDAA-11D0-B822-00C04FC9B31F"), ClassInterface((short)0)] + public class CMLangConvertCharsetClass : IMLangConvertCharset, CMLangConvertCharset + { + // Methods + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void DoConversion([In] ref byte pSrcStr, [In, Out] ref uint pcSrcSize, out byte pDstStr, [In, Out] ref uint pcDstSize); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void DoConversionFromUnicode([In] ref ushort pSrcStr, [In, Out] ref uint pcSrcSize, out sbyte pDstStr, [In, Out] ref uint pcDstSize); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void DoConversionToUnicode([In] ref sbyte pSrcStr, [In, Out] ref uint pcSrcSize, out ushort pDstStr, [In, Out] ref uint pcDstSize); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void GetDestinationCodePage(out uint puiDstCodePage); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void GetProperty(out uint pdwProperty); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void GetSourceCodePage(out uint puiSrcCodePage); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void Initialize([In] uint uiSrcCodePage, [In] uint uiDstCodePage, [In] uint dwProperty); + } + + [ComImport, Guid("C04D65CE-B70D-11D0-B188-00AA0038C969"), CoClass(typeof(CMLangStringClass))] + public interface CMLangString : IMLangString + { + } + + [ComImport, TypeLibType((short)2), Guid("C04D65CF-B70D-11D0-B188-00AA0038C969"), ClassInterface((short)0)] + public class CMLangStringClass : IMLangString, CMLangString, IMLangStringWStr, IMLangStringAStr + { + // Methods + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void GetAStr([In] int lSrcPos, [In] int lSrcLen, [In] uint uCodePageIn, out uint puCodePageOut, [Out, MarshalAs(UnmanagedType.LPStr)] string pszDest, [In] int cchDest, out int pcchActual, out int plActualLen); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern int GetLength(); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void GetLocale([In] int lSrcPos, [In] int lSrcMaxLen, out uint plocale, out int plLocalePos, out int plLocaleLen); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void GetMLStr([In] int lSrcPos, [In] int lSrcLen, [In, MarshalAs(UnmanagedType.IUnknown)] object pUnkOuter, [In] uint dwClsContext, [In] ref Guid piid, [MarshalAs(UnmanagedType.IUnknown)] out object ppDestMLStr, out int plDestPos, out int plDestLen); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void GetStrBufA([In] int lSrcPos, [In] int lSrcMaxLen, out uint puDestCodePage, [MarshalAs(UnmanagedType.Interface)] out IMLangStringBufA ppDestBuf, out int plDestLen); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void GetStrBufW([In] int lSrcPos, [In] int lSrcMaxLen, [MarshalAs(UnmanagedType.Interface)] out IMLangStringBufW ppDestBuf, out int plDestLen); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void GetWStr([In] int lSrcPos, [In] int lSrcLen, [Out, MarshalAs(UnmanagedType.LPWStr)] string pszDest, [In] int cchDest, out int pcchActual, out int plActualLen); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern int IMLangStringAStr_GetLength(); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMLangStringAStr_GetLocale([In] int lSrcPos, [In] int lSrcMaxLen, out uint plocale, out int plLocalePos, out int plLocaleLen); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMLangStringAStr_GetMLStr([In] int lSrcPos, [In] int lSrcLen, [In, MarshalAs(UnmanagedType.IUnknown)] object pUnkOuter, [In] uint dwClsContext, [In] ref Guid piid, [MarshalAs(UnmanagedType.IUnknown)] out object ppDestMLStr, out int plDestPos, out int plDestLen); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMLangStringAStr_SetLocale([In] int lDestPos, [In] int lDestLen, [In] uint locale); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMLangStringAStr_SetMLStr([In] int lDestPos, [In] int lDestLen, [In, MarshalAs(UnmanagedType.IUnknown)] object pSrcMLStr, [In] int lSrcPos, [In] int lSrcLen); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMLangStringAStr_Sync([In] int fNoAccess); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern int IMLangStringWStr_GetLength(); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMLangStringWStr_GetMLStr([In] int lSrcPos, [In] int lSrcLen, [In, MarshalAs(UnmanagedType.IUnknown)] object pUnkOuter, [In] uint dwClsContext, [In] ref Guid piid, [MarshalAs(UnmanagedType.IUnknown)] out object ppDestMLStr, out int plDestPos, out int plDestLen); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMLangStringWStr_SetMLStr([In] int lDestPos, [In] int lDestLen, [In, MarshalAs(UnmanagedType.IUnknown)] object pSrcMLStr, [In] int lSrcPos, [In] int lSrcLen); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMLangStringWStr_Sync([In] int fNoAccess); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void LockAStr([In] int lSrcPos, [In] int lSrcLen, [In] int lFlags, [In] uint uCodePageIn, [In] int cchRequest, out uint puCodePageOut, [MarshalAs(UnmanagedType.LPStr)] out string ppszDest, out int pcchDest, out int plDestLen); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void LockWStr([In] int lSrcPos, [In] int lSrcLen, [In] int lFlags, [In] int cchRequest, [MarshalAs(UnmanagedType.LPWStr)] out string ppszDest, out int pcchDest, out int plDestLen); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void SetAStr([In] int lDestPos, [In] int lDestLen, [In] uint uCodePage, [In, MarshalAs(UnmanagedType.LPStr)] string pszSrc, [In] int cchSrc, out int pcchActual, out int plActualLen); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void SetLocale([In] int lDestPos, [In] int lDestLen, [In] uint locale); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void SetMLStr([In] int lDestPos, [In] int lDestLen, [In, MarshalAs(UnmanagedType.IUnknown)] object pSrcMLStr, [In] int lSrcPos, [In] int lSrcLen); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void SetStrBufA([In] int lDestPos, [In] int lDestLen, [In] uint uCodePage, [In, MarshalAs(UnmanagedType.Interface)] IMLangStringBufA pSrcBuf, out int pcchActual, out int plActualLen); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void SetStrBufW([In] int lDestPos, [In] int lDestLen, [In, MarshalAs(UnmanagedType.Interface)] IMLangStringBufW pSrcBuf, out int pcchActual, out int plActualLen); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void SetWStr([In] int lDestPos, [In] int lDestLen, [In, MarshalAs(UnmanagedType.LPWStr)] string pszSrc, [In] int cchSrc, out int pcchActual, out int plActualLen); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void Sync([In] int fNoAccess); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void UnlockAStr([In, MarshalAs(UnmanagedType.LPStr)] string pszSrc, [In] int cchSrc, out int pcchActual, out int plActualLen); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void UnlockWStr([In, MarshalAs(UnmanagedType.LPWStr)] string pszSrc, [In] int cchSrc, out int pcchActual, out int plActualLen); + } + + [ComImport, Guid("275C23E1-3747-11D0-9FEA-00AA003F8646"), CoClass(typeof(CMultiLanguageClass))] + public interface CMultiLanguage : IMultiLanguage + { + } + + [ComImport, TypeLibType(TypeLibTypeFlags.FCanCreate), ClassInterface(ClassInterfaceType.None), Guid("275C23E2-3747-11D0-9FEA-00AA003F8646")] + public class CMultiLanguageClass : IMultiLanguage, CMultiLanguage, IMLangCodePages, IMLangFontLink, IMLangLineBreakConsole, IMultiLanguage2, IMLangFontLink2, IMultiLanguage3 + { + // Methods + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void BreakLineA([In] uint locale, [In] uint uCodePage, [In] ref sbyte pszSrc, [In] int cchSrc, [In] int cMaxColumns, out int pcchLine, out int pcchSkip); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void BreakLineML([In, MarshalAs(UnmanagedType.Interface)] CMLangString pSrcMLStr, [In] int lSrcPos, [In] int lSrcLen, [In] int cMinColumns, [In] int cMaxColumns, out int plLineLen, out int plSkipLen); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void BreakLineW([In] uint locale, [In] ref ushort pszSrc, [In] int cchSrc, [In] int cMaxColumns, out int pcchLine, out int pcchSkip); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void CodePagesToCodePage([In] uint dwCodePages, [In] uint uDefaultCodePage, out uint puCodePage); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void CodePageToCodePages([In] uint uCodePage, out uint pdwCodePages); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void CodePageToScriptID([In] uint uiCodePage, out byte pSid); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void ConvertString([In, Out] ref uint pdwMode, [In] uint dwSrcEncoding, [In] uint dwDstEncoding, [In] ref byte pSrcStr, [In, Out] ref uint pcSrcSize, out byte pDstStr, [In, Out] ref uint pcDstSize); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void ConvertStringFromUnicode([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref ushort pSrcStr, [In, Out] ref uint pcSrcSize, out sbyte pDstStr, [In, Out] ref uint pcDstSize); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void ConvertStringFromUnicodeEx([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref ushort pSrcStr, [In, Out] ref uint pcSrcSize, out sbyte pDstStr, [In, Out] ref uint pcDstSize, [In] uint dwFlag, [In] ref ushort lpFallBack); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void ConvertStringInIStream([In, Out] ref uint pdwMode, [In] uint dwFlag, [In] ref ushort lpFallBack, [In] uint dwSrcEncoding, [In] uint dwDstEncoding, [In, MarshalAs(UnmanagedType.Interface)] IStream pstmIn, [In, MarshalAs(UnmanagedType.Interface)] IStream pstmOut); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void ConvertStringReset(); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void ConvertStringToUnicode([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref sbyte pSrcStr, [In, Out] ref uint pcSrcSize, out ushort pDstStr, [In, Out] ref uint pcDstSize); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void ConvertStringToUnicodeEx([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref sbyte pSrcStr, [In, Out] ref uint pcSrcSize, out ushort pDstStr, [In, Out] ref uint pcDstSize, [In] uint dwFlag, [In] ref ushort lpFallBack); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void CreateConvertCharset([In] uint uiSrcCodePage, [In] uint uiDstCodePage, [In] uint dwProperty, [MarshalAs(UnmanagedType.Interface)] out CMLangConvertCharset ppMLangConvertCharset); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void DetectCodepageInIStream([In] uint dwFlag, [In] uint dwPrefWinCodePage, [In, MarshalAs(UnmanagedType.Interface)] IStream pstmIn, out DetectEncodingInfo lpEncoding, [In, Out] ref int pnScores); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + [PreserveSig] + public virtual extern HRESULT DetectInputCodepage([In] MLDETECTCP dwFlag, [In] uint dwPrefWinCodePage, [In] ref byte pSrcStr, [In, Out] ref int pcSrcSize, ref DetectEncodingInfo lpEncoding, [In, Out] ref int pnScores); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void DetectOutboundCodePage([In] uint dwFlags, [In, MarshalAs(UnmanagedType.LPWStr)] string lpWideCharStr, [In] uint cchWideChar, [In] ref uint puiPreferredCodePages, [In] uint nPreferredCodePages, out uint puiDetectedCodePages, [In, Out] ref uint pnDetectedCodePages, [In, MarshalAs(UnmanagedType.LPWStr)] string lpSpecialChar); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void DetectOutboundCodePageInIStream([In] uint dwFlags, [In, MarshalAs(UnmanagedType.Interface)] IStream pStrIn, [In] ref uint puiPreferredCodePages, [In] uint nPreferredCodePages, out uint puiDetectedCodePages, [In, Out] ref uint pnDetectedCodePages, [In, MarshalAs(UnmanagedType.LPWStr)] string lpSpecialChar); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + [return: MarshalAs(UnmanagedType.Interface)] + public virtual extern IEnumCodePage EnumCodePages([In] NativeMethods.MIMECONTF grfFlags); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void EnumCodePages([In] uint grfFlags, [In] ushort LangId, [MarshalAs(UnmanagedType.Interface)] out IEnumCodePage ppEnumCodePage); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void EnumRfc1766([MarshalAs(UnmanagedType.Interface)] out IEnumRfc1766 ppEnumRfc1766); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void EnumRfc1766([In] ushort LangId, [MarshalAs(UnmanagedType.Interface)] out IEnumRfc1766 ppEnumRfc1766); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void EnumScripts([In] uint dwFlags, [In] ushort LangId, [MarshalAs(UnmanagedType.Interface)] out IEnumScript ppEnumScript); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void GetCharCodePages([In] ushort chSrc, out uint pdwCodePages); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void GetCharsetInfo([In, MarshalAs(UnmanagedType.BStr)] string Charset, out MIMECSETINFO pCharsetInfo); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void GetCodePageDescription([In] uint uiCodePage, [In] uint lcid, [Out, MarshalAs(UnmanagedType.LPWStr)] string lpWideCharStr, [In] int cchWideChar); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void GetCodePageInfo([In] uint uiCodePage, out MIMECPINFO pCodePageInfo); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void GetCodePageInfo([In] uint uiCodePage, [In] ushort LangId, out MIMECPINFO pCodePageInfo); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void GetFamilyCodePage([In] uint uiCodePage, out uint puiFamilyCodePage); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void GetFontCodePages([In, ComAliasName("MultiLanguage.wireHDC")] ref _RemotableHandle hDC, [In, ComAliasName("MultiLanguage.wireHFONT")] ref _RemotableHandle hFont, out uint pdwCodePages); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void GetFontUnicodeRanges([In, ComAliasName("MultiLanguage.wireHDC")] ref _RemotableHandle hDC, [In, Out] ref uint puiRanges, out UNICODERANGE pUranges); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void GetLcidFromRfc1766(out uint plocale, [In, MarshalAs(UnmanagedType.BStr)] string bstrRfc1766); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void GetNumberOfCodePageInfo(out uint pcCodePage); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void GetNumberOfScripts(out uint pnScripts); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void GetRfc1766FromLcid([In] uint locale, [MarshalAs(UnmanagedType.BStr)] out string pbstrRfc1766); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void GetRfc1766Info([In] uint locale, out RFC1766INFO pRfc1766Info); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void GetRfc1766Info([In] uint locale, [In] ushort LangId, out RFC1766INFO pRfc1766Info); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void GetScriptFontInfo([In] byte sid, [In] uint dwFlags, [In, Out] ref uint puiFonts, out SCRIPFONTINFO pScriptFont); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void GetStrCodePages([In] ref ushort pszSrc, [In] int cchSrc, [In] uint dwPriorityCodePages, out uint pdwCodePages, out int pcchCodePages); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMLangFontLink_CodePagesToCodePage([In] uint dwCodePages, [In] uint uDefaultCodePage, out uint puCodePage); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMLangFontLink_CodePageToCodePages([In] uint uCodePage, out uint pdwCodePages); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMLangFontLink_GetCharCodePages([In] ushort chSrc, out uint pdwCodePages); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMLangFontLink_GetStrCodePages([In] ref ushort pszSrc, [In] int cchSrc, [In] uint dwPriorityCodePages, out uint pdwCodePages, out int pcchCodePages); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMLangFontLink2_CodePagesToCodePage([In] uint dwCodePages, [In] uint uDefaultCodePage, out uint puCodePage); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMLangFontLink2_CodePageToCodePages([In] uint uCodePage, out uint pdwCodePages); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMLangFontLink2_GetCharCodePages([In] ushort chSrc, out uint pdwCodePages); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMLangFontLink2_GetFontCodePages([In, ComAliasName("MultiLanguage.wireHDC")] ref _RemotableHandle hDC, [In, ComAliasName("MultiLanguage.wireHFONT")] ref _RemotableHandle hFont, out uint pdwCodePages); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMLangFontLink2_GetStrCodePages([In] ref ushort pszSrc, [In] int cchSrc, [In] uint dwPriorityCodePages, out uint pdwCodePages, out int pcchCodePages); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMLangFontLink2_ReleaseFont([In, ComAliasName("MultiLanguage.wireHFONT")] ref _RemotableHandle hFont); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMLangFontLink2_ResetFontMapping(); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMultiLanguage2_ConvertString([In, Out] ref uint pdwMode, [In] uint dwSrcEncoding, [In] uint dwDstEncoding, [In] ref byte pSrcStr, [In, Out] ref uint pcSrcSize, out byte pDstStr, [In, Out] ref uint pcDstSize); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMultiLanguage2_ConvertStringFromUnicode([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref ushort pSrcStr, [In, Out] ref uint pcSrcSize, out sbyte pDstStr, [In, Out] ref uint pcDstSize); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMultiLanguage2_ConvertStringReset(); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMultiLanguage2_ConvertStringToUnicode([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref sbyte pSrcStr, [In, Out] ref uint pcSrcSize, out ushort pDstStr, [In, Out] ref uint pcDstSize); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMultiLanguage2_CreateConvertCharset([In] uint uiSrcCodePage, [In] uint uiDstCodePage, [In] uint dwProperty, [MarshalAs(UnmanagedType.Interface)] out CMLangConvertCharset ppMLangConvertCharset); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMultiLanguage2_GetCharsetInfo([In, MarshalAs(UnmanagedType.BStr)] string Charset, out MIMECSETINFO pCharsetInfo); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMultiLanguage2_GetFamilyCodePage([In] uint uiCodePage, out uint puiFamilyCodePage); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMultiLanguage2_GetLcidFromRfc1766(out uint plocale, [In, MarshalAs(UnmanagedType.BStr)] string bstrRfc1766); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMultiLanguage2_GetNumberOfCodePageInfo(out uint pcCodePage); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMultiLanguage2_GetRfc1766FromLcid([In] uint locale, [MarshalAs(UnmanagedType.BStr)] out string pbstrRfc1766); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMultiLanguage2_IsConvertible([In] uint dwSrcEncoding, [In] uint dwDstEncoding); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMultiLanguage3_ConvertString([In, Out] ref uint pdwMode, [In] uint dwSrcEncoding, [In] uint dwDstEncoding, [In] ref byte pSrcStr, [In, Out] ref uint pcSrcSize, out byte pDstStr, [In, Out] ref uint pcDstSize); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMultiLanguage3_ConvertStringFromUnicode([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref ushort pSrcStr, [In, Out] ref uint pcSrcSize, out sbyte pDstStr, [In, Out] ref uint pcDstSize); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMultiLanguage3_ConvertStringFromUnicodeEx([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref ushort pSrcStr, [In, Out] ref uint pcSrcSize, out sbyte pDstStr, [In, Out] ref uint pcDstSize, [In] uint dwFlag, [In] ref ushort lpFallBack); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMultiLanguage3_ConvertStringInIStream([In, Out] ref uint pdwMode, [In] uint dwFlag, [In] ref ushort lpFallBack, [In] uint dwSrcEncoding, [In] uint dwDstEncoding, [In, MarshalAs(UnmanagedType.Interface)] IStream pstmIn, [In, MarshalAs(UnmanagedType.Interface)] IStream pstmOut); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMultiLanguage3_ConvertStringReset(); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMultiLanguage3_ConvertStringToUnicode([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref sbyte pSrcStr, [In, Out] ref uint pcSrcSize, out ushort pDstStr, [In, Out] ref uint pcDstSize); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMultiLanguage3_ConvertStringToUnicodeEx([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref sbyte pSrcStr, [In, Out] ref uint pcSrcSize, out ushort pDstStr, [In, Out] ref uint pcDstSize, [In] uint dwFlag, [In] ref ushort lpFallBack); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMultiLanguage3_CreateConvertCharset([In] uint uiSrcCodePage, [In] uint uiDstCodePage, [In] uint dwProperty, [MarshalAs(UnmanagedType.Interface)] out CMLangConvertCharset ppMLangConvertCharset); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMultiLanguage3_DetectCodepageInIStream([In] uint dwFlag, [In] uint dwPrefWinCodePage, [In, MarshalAs(UnmanagedType.Interface)] IStream pstmIn, out DetectEncodingInfo lpEncoding, [In, Out] ref int pnScores); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMultiLanguage3_DetectInputCodepage([In] uint dwFlag, [In] uint dwPrefWinCodePage, [In] ref sbyte pSrcStr, [In, Out] ref int pcSrcSize, out DetectEncodingInfo lpEncoding, [In, Out] ref int pnScores); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMultiLanguage3_EnumCodePages([In] NativeMethods.MIMECONTF grfFlags, [In] ushort LangId, [MarshalAs(UnmanagedType.Interface)] out IEnumCodePage ppEnumCodePage); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMultiLanguage3_EnumRfc1766([In] ushort LangId, [MarshalAs(UnmanagedType.Interface)] out IEnumRfc1766 ppEnumRfc1766); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMultiLanguage3_EnumScripts([In] uint dwFlags, [In] ushort LangId, [MarshalAs(UnmanagedType.Interface)] out IEnumScript ppEnumScript); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMultiLanguage3_GetCharsetInfo([In, MarshalAs(UnmanagedType.BStr)] string Charset, out MIMECSETINFO pCharsetInfo); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMultiLanguage3_GetCodePageDescription([In] uint uiCodePage, [In] uint lcid, [Out, MarshalAs(UnmanagedType.LPWStr)] string lpWideCharStr, [In] int cchWideChar); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMultiLanguage3_GetCodePageInfo([In] uint uiCodePage, [In] ushort LangId, out MIMECPINFO pCodePageInfo); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMultiLanguage3_GetFamilyCodePage([In] uint uiCodePage, out uint puiFamilyCodePage); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMultiLanguage3_GetLcidFromRfc1766(out uint plocale, [In, MarshalAs(UnmanagedType.BStr)] string bstrRfc1766); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMultiLanguage3_GetNumberOfCodePageInfo(out uint pcCodePage); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMultiLanguage3_GetNumberOfScripts(out uint pnScripts); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMultiLanguage3_GetRfc1766FromLcid([In] uint locale, [MarshalAs(UnmanagedType.BStr)] out string pbstrRfc1766); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMultiLanguage3_GetRfc1766Info([In] uint locale, [In] ushort LangId, out RFC1766INFO pRfc1766Info); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMultiLanguage3_IsCodePageInstallable([In] uint uiCodePage); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMultiLanguage3_IsConvertible([In] uint dwSrcEncoding, [In] uint dwDstEncoding); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMultiLanguage3_SetMimeDBSource([In] MIMECONTF dwSource); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMultiLanguage3_ValidateCodePage([In] uint uiCodePage, [In, ComAliasName("MultiLanguage.wireHWND")] ref _RemotableHandle hwnd); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IMultiLanguage3_ValidateCodePageEx([In] uint uiCodePage, [In, ComAliasName("MultiLanguage.wireHWND")] ref _RemotableHandle hwnd, [In] uint dwfIODControl); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IsCodePageInstallable([In] uint uiCodePage); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void IsConvertible([In] uint dwSrcEncoding, [In] uint dwDstEncoding); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void MapFont([In, ComAliasName("MultiLanguage.wireHDC")] ref _RemotableHandle hDC, [In] uint dwCodePages, [In] ushort chSrc, [Out, ComAliasName("MultiLanguage.wireHFONT")] IntPtr pFont); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void MapFont([In, ComAliasName("MultiLanguage.wireHDC")] ref _RemotableHandle hDC, [In] uint dwCodePages, [In, ComAliasName("MultiLanguage.wireHFONT")] ref _RemotableHandle hSrcFont, [Out, ComAliasName("MultiLanguage.wireHFONT")] IntPtr phDestFont); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void ReleaseFont([In, ComAliasName("MultiLanguage.wireHFONT")] ref _RemotableHandle hFont); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void ResetFontMapping(); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void SetMimeDBSource([In] MIMECONTF dwSource); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void ValidateCodePage([In] uint uiCodePage, [In, ComAliasName("MultiLanguage.wireHWND")] ref _RemotableHandle hwnd); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void ValidateCodePageEx([In] uint uiCodePage, [In, ComAliasName("MultiLanguage.wireHWND")] ref _RemotableHandle hwnd, [In] uint dwfIODControl); + } + + [ComImport, Guid("275C23E3-3747-11D0-9FEA-00AA003F8646"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface IEnumCodePage + { + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void Clone([MarshalAs(UnmanagedType.Interface)] out IEnumCodePage ppEnum); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + [PreserveSig] + HRESULT Next([In] uint celt, out MIMECPINFO rgelt, out uint pceltFetched); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void Reset(); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void Skip([In] uint celt); + } + + [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("3DC39D1D-C030-11D0-B81B-00C04FC9B31F")] + public interface IEnumRfc1766 + { + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void Clone([MarshalAs(UnmanagedType.Interface)] out IEnumRfc1766 ppEnum); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void Next([In] uint celt, out RFC1766INFO rgelt, out uint pceltFetched); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void Reset(); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void Skip([In] uint celt); + } + + [ComImport, Guid("AE5F1430-388B-11D2-8380-00C04F8F5DA1"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface IEnumScript + { + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void Clone([MarshalAs(UnmanagedType.Interface)] out IEnumScript ppEnum); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void Next([In] uint celt, out SCRIPTINFO rgelt, out uint pceltFetched); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void Reset(); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void Skip([In] uint celt); + } + + [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("359F3443-BD4A-11D0-B188-00AA0038C969")] + public interface IMLangCodePages + { + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetCharCodePages([In] ushort chSrc, out uint pdwCodePages); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetStrCodePages([In] ref ushort pszSrc, [In] int cchSrc, [In] uint dwPriorityCodePages, out uint pdwCodePages, out int pcchCodePages); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void CodePageToCodePages([In] uint uCodePage, out uint pdwCodePages); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void CodePagesToCodePage([In] uint dwCodePages, [In] uint uDefaultCodePage, out uint puCodePage); + } + + [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("D66D6F98-CDAA-11D0-B822-00C04FC9B31F")] + public interface IMLangConvertCharset + { + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void Initialize([In] uint uiSrcCodePage, [In] uint uiDstCodePage, [In] uint dwProperty); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetSourceCodePage(out uint puiSrcCodePage); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetDestinationCodePage(out uint puiDstCodePage); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetProperty(out uint pdwProperty); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void DoConversion([In] ref byte pSrcStr, [In, Out] ref uint pcSrcSize, out byte pDstStr, [In, Out] ref uint pcDstSize); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void DoConversionToUnicode([In] ref sbyte pSrcStr, [In, Out] ref uint pcSrcSize, out ushort pDstStr, [In, Out] ref uint pcDstSize); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void DoConversionFromUnicode([In] ref ushort pSrcStr, [In, Out] ref uint pcSrcSize, out sbyte pDstStr, [In, Out] ref uint pcDstSize); + } + + [ComImport, Guid("359F3441-BD4A-11D0-B188-00AA0038C969"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), ComConversionLoss] + public interface IMLangFontLink : IMLangCodePages + { + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetFontCodePages([In, ComAliasName("MultiLanguage.wireHDC")] ref _RemotableHandle hDC, [In, ComAliasName("MultiLanguage.wireHFONT")] ref _RemotableHandle hFont, out uint pdwCodePages); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void MapFont([In, ComAliasName("MultiLanguage.wireHDC")] ref _RemotableHandle hDC, [In] uint dwCodePages, [In, ComAliasName("MultiLanguage.wireHFONT")] ref _RemotableHandle hSrcFont, [Out, ComAliasName("MultiLanguage.wireHFONT")] IntPtr phDestFont); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void ReleaseFont([In, ComAliasName("MultiLanguage.wireHFONT")] ref _RemotableHandle hFont); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void ResetFontMapping(); + } + + [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("DCCFC162-2B38-11D2-B7EC-00C04F8F5D9A"), ComConversionLoss] + public interface IMLangFontLink2 : IMLangCodePages + { + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetFontCodePages([In, ComAliasName("MultiLanguage.wireHDC")] ref _RemotableHandle hDC, [In, ComAliasName("MultiLanguage.wireHFONT")] ref _RemotableHandle hFont, out uint pdwCodePages); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void ReleaseFont([In, ComAliasName("MultiLanguage.wireHFONT")] ref _RemotableHandle hFont); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void ResetFontMapping(); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void MapFont([In, ComAliasName("MultiLanguage.wireHDC")] ref _RemotableHandle hDC, [In] uint dwCodePages, [In] ushort chSrc, [Out, ComAliasName("MultiLanguage.wireHFONT")] IntPtr pFont); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetFontUnicodeRanges([In, ComAliasName("MultiLanguage.wireHDC")] ref _RemotableHandle hDC, [In, Out] ref uint puiRanges, out UNICODERANGE pUranges); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetScriptFontInfo([In] byte sid, [In] uint dwFlags, [In, Out] ref uint puiFonts, out SCRIPFONTINFO pScriptFont); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void CodePageToScriptID([In] uint uiCodePage, out byte pSid); + } + + [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("F5BE2EE1-BFD7-11D0-B188-00AA0038C969")] + public interface IMLangLineBreakConsole + { + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void BreakLineML([In, MarshalAs(UnmanagedType.Interface)] CMLangString pSrcMLStr, [In] int lSrcPos, [In] int lSrcLen, [In] int cMinColumns, [In] int cMaxColumns, out int plLineLen, out int plSkipLen); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void BreakLineW([In] uint locale, [In] ref ushort pszSrc, [In] int cchSrc, [In] int cMaxColumns, out int pcchLine, out int pcchSkip); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void BreakLineA([In] uint locale, [In] uint uCodePage, [In] ref sbyte pszSrc, [In] int cchSrc, [In] int cMaxColumns, out int pcchLine, out int pcchSkip); + } + + [ComImport, Guid("C04D65CE-B70D-11D0-B188-00AA0038C969"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface IMLangString + { + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void Sync([In] int fNoAccess); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + int GetLength(); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void SetMLStr([In] int lDestPos, [In] int lDestLen, [In, MarshalAs(UnmanagedType.IUnknown)] object pSrcMLStr, [In] int lSrcPos, [In] int lSrcLen); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetMLStr([In] int lSrcPos, [In] int lSrcLen, [In, MarshalAs(UnmanagedType.IUnknown)] object pUnkOuter, [In] uint dwClsContext, [In] ref Guid piid, [MarshalAs(UnmanagedType.IUnknown)] out object ppDestMLStr, out int plDestPos, out int plDestLen); + } + + [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("C04D65D2-B70D-11D0-B188-00AA0038C969")] + public interface IMLangStringAStr : IMLangString + { + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void SetAStr([In] int lDestPos, [In] int lDestLen, [In] uint uCodePage, [In, MarshalAs(UnmanagedType.LPStr)] string pszSrc, [In] int cchSrc, out int pcchActual, out int plActualLen); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void SetStrBufA([In] int lDestPos, [In] int lDestLen, [In] uint uCodePage, [In, MarshalAs(UnmanagedType.Interface)] IMLangStringBufA pSrcBuf, out int pcchActual, out int plActualLen); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetAStr([In] int lSrcPos, [In] int lSrcLen, [In] uint uCodePageIn, out uint puCodePageOut, [Out, MarshalAs(UnmanagedType.LPStr)] string pszDest, [In] int cchDest, out int pcchActual, out int plActualLen); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetStrBufA([In] int lSrcPos, [In] int lSrcMaxLen, out uint puDestCodePage, [MarshalAs(UnmanagedType.Interface)] out IMLangStringBufA ppDestBuf, out int plDestLen); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void LockAStr([In] int lSrcPos, [In] int lSrcLen, [In] int lFlags, [In] uint uCodePageIn, [In] int cchRequest, out uint puCodePageOut, [MarshalAs(UnmanagedType.LPStr)] out string ppszDest, out int pcchDest, out int plDestLen); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void UnlockAStr([In, MarshalAs(UnmanagedType.LPStr)] string pszSrc, [In] int cchSrc, out int pcchActual, out int plActualLen); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void SetLocale([In] int lDestPos, [In] int lDestLen, [In] uint locale); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetLocale([In] int lSrcPos, [In] int lSrcMaxLen, out uint plocale, out int plLocalePos, out int plLocaleLen); + } + + [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), ComConversionLoss, Guid("D24ACD23-BA72-11D0-B188-00AA0038C969")] + public interface IMLangStringBufA + { + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetStatus(out int plFlags, out int pcchBuf); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void LockBuf([In] int cchOffset, [In] int cchMaxLock, [Out] IntPtr ppszBuf, out int pcchBuf); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void UnlockBuf([In] ref sbyte pszBuf, [In] int cchOffset, [In] int cchWrite); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void Insert([In] int cchOffset, [In] int cchMaxInsert, out int pcchActual); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void Delete([In] int cchOffset, [In] int cchDelete); + } + + [ComImport, ComConversionLoss, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("D24ACD21-BA72-11D0-B188-00AA0038C969")] + public interface IMLangStringBufW + { + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetStatus(out int plFlags, out int pcchBuf); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void LockBuf([In] int cchOffset, [In] int cchMaxLock, [Out] IntPtr ppszBuf, out int pcchBuf); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void UnlockBuf([In] ref ushort pszBuf, [In] int cchOffset, [In] int cchWrite); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void Insert([In] int cchOffset, [In] int cchMaxInsert, out int pcchActual); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void Delete([In] int cchOffset, [In] int cchDelete); + } + + [ComImport, Guid("C04D65D0-B70D-11D0-B188-00AA0038C969"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface IMLangStringWStr : IMLangString + { + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void SetWStr([In] int lDestPos, [In] int lDestLen, [In, MarshalAs(UnmanagedType.LPWStr)] string pszSrc, [In] int cchSrc, out int pcchActual, out int plActualLen); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void SetStrBufW([In] int lDestPos, [In] int lDestLen, [In, MarshalAs(UnmanagedType.Interface)] IMLangStringBufW pSrcBuf, out int pcchActual, out int plActualLen); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetWStr([In] int lSrcPos, [In] int lSrcLen, [Out, MarshalAs(UnmanagedType.LPWStr)] string pszDest, [In] int cchDest, out int pcchActual, out int plActualLen); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetStrBufW([In] int lSrcPos, [In] int lSrcMaxLen, [MarshalAs(UnmanagedType.Interface)] out IMLangStringBufW ppDestBuf, out int plDestLen); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void LockWStr([In] int lSrcPos, [In] int lSrcLen, [In] int lFlags, [In] int cchRequest, [MarshalAs(UnmanagedType.LPWStr)] out string ppszDest, out int pcchDest, out int plDestLen); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void UnlockWStr([In, MarshalAs(UnmanagedType.LPWStr)] string pszSrc, [In] int cchSrc, out int pcchActual, out int plActualLen); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void SetLocale([In] int lDestPos, [In] int lDestLen, [In] uint locale); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetLocale([In] int lSrcPos, [In] int lSrcMaxLen, out uint plocale, out int plLocalePos, out int plLocaleLen); + } + + [ComImport, Guid("275C23E1-3747-11D0-9FEA-00AA003F8646"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface IMultiLanguage + { + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetNumberOfCodePageInfo(out uint pcCodePage); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetCodePageInfo([In] uint uiCodePage, out MIMECPINFO pCodePageInfo); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetFamilyCodePage([In] uint uiCodePage, out uint puiFamilyCodePage); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + [return: MarshalAs(UnmanagedType.Interface)] + IEnumCodePage EnumCodePages([In] NativeMethods.MIMECONTF grfFlags); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetCharsetInfo([In, MarshalAs(UnmanagedType.BStr)] string Charset, out MIMECSETINFO pCharsetInfo); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void IsConvertible([In] uint dwSrcEncoding, [In] uint dwDstEncoding); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void ConvertString([In, Out] ref uint pdwMode, [In] uint dwSrcEncoding, [In] uint dwDstEncoding, [In] ref byte pSrcStr, [In, Out] ref uint pcSrcSize, out byte pDstStr, [In, Out] ref uint pcDstSize); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void ConvertStringToUnicode([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref sbyte pSrcStr, [In, Out] ref uint pcSrcSize, out ushort pDstStr, [In, Out] ref uint pcDstSize); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void ConvertStringFromUnicode([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref ushort pSrcStr, [In, Out] ref uint pcSrcSize, out sbyte pDstStr, [In, Out] ref uint pcDstSize); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void ConvertStringReset(); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetRfc1766FromLcid([In] uint locale, [MarshalAs(UnmanagedType.BStr)] out string pbstrRfc1766); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetLcidFromRfc1766(out uint plocale, [In, MarshalAs(UnmanagedType.BStr)] string bstrRfc1766); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void EnumRfc1766([MarshalAs(UnmanagedType.Interface)] out IEnumRfc1766 ppEnumRfc1766); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetRfc1766Info([In] uint locale, out RFC1766INFO pRfc1766Info); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void CreateConvertCharset([In] uint uiSrcCodePage, [In] uint uiDstCodePage, [In] uint dwProperty, [MarshalAs(UnmanagedType.Interface)] out CMLangConvertCharset ppMLangConvertCharset); + } + + [ComImport, Guid("DCCFC164-2B38-11D2-B7EC-00C04F8F5D9A"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface IMultiLanguage2 + { + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetNumberOfCodePageInfo(out uint pcCodePage); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetCodePageInfo([In] uint uiCodePage, [In] ushort LangId, out MIMECPINFO pCodePageInfo); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetFamilyCodePage([In] uint uiCodePage, out uint puiFamilyCodePage); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void EnumCodePages([In] uint grfFlags, [In] ushort LangId, [MarshalAs(UnmanagedType.Interface)] out IEnumCodePage ppEnumCodePage); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetCharsetInfo([In, MarshalAs(UnmanagedType.BStr)] string Charset, out MIMECSETINFO pCharsetInfo); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void IsConvertible([In] uint dwSrcEncoding, [In] uint dwDstEncoding); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void ConvertString([In, Out] ref uint pdwMode, [In] uint dwSrcEncoding, [In] uint dwDstEncoding, [In] ref byte pSrcStr, [In, Out] ref uint pcSrcSize, out byte pDstStr, [In, Out] ref uint pcDstSize); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void ConvertStringToUnicode([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref sbyte pSrcStr, [In, Out] ref uint pcSrcSize, out ushort pDstStr, [In, Out] ref uint pcDstSize); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void ConvertStringFromUnicode([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref ushort pSrcStr, [In, Out] ref uint pcSrcSize, out sbyte pDstStr, [In, Out] ref uint pcDstSize); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void ConvertStringReset(); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetRfc1766FromLcid([In] uint locale, [MarshalAs(UnmanagedType.BStr)] out string pbstrRfc1766); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetLcidFromRfc1766(out uint plocale, [In, MarshalAs(UnmanagedType.BStr)] string bstrRfc1766); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void EnumRfc1766([In] ushort LangId, [MarshalAs(UnmanagedType.Interface)] out IEnumRfc1766 ppEnumRfc1766); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetRfc1766Info([In] uint locale, [In] ushort LangId, out RFC1766INFO pRfc1766Info); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void CreateConvertCharset([In] uint uiSrcCodePage, [In] uint uiDstCodePage, [In] uint dwProperty, [MarshalAs(UnmanagedType.Interface)] out CMLangConvertCharset ppMLangConvertCharset); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void ConvertStringInIStream([In, Out] ref uint pdwMode, [In] uint dwFlag, [In] ref ushort lpFallBack, [In] uint dwSrcEncoding, [In] uint dwDstEncoding, [In, MarshalAs(UnmanagedType.Interface)] IStream pstmIn, [In, MarshalAs(UnmanagedType.Interface)] IStream pstmOut); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void ConvertStringToUnicodeEx([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref sbyte pSrcStr, [In, Out] ref uint pcSrcSize, out ushort pDstStr, [In, Out] ref uint pcDstSize, [In] uint dwFlag, [In] ref ushort lpFallBack); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void ConvertStringFromUnicodeEx([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref ushort pSrcStr, [In, Out] ref uint pcSrcSize, out sbyte pDstStr, [In, Out] ref uint pcDstSize, [In] uint dwFlag, [In] ref ushort lpFallBack); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void DetectCodepageInIStream([In] uint dwFlag, [In] uint dwPrefWinCodePage, [In, MarshalAs(UnmanagedType.Interface)] IStream pstmIn, out DetectEncodingInfo lpEncoding, [In, Out] ref int pnScores); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + [PreserveSig] + HRESULT DetectInputCodepage([In] MLDETECTCP dwFlag, [In] uint dwPrefWinCodePage, [In] ref byte pSrcStr, [In, Out] ref int pcSrcSize, [In, Out] ref DetectEncodingInfo lpEncoding, [In, Out] ref int pnScores); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void ValidateCodePage([In] uint uiCodePage, [In, ComAliasName("MultiLanguage.wireHWND")] ref _RemotableHandle hwnd); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetCodePageDescription([In] uint uiCodePage, [In] uint lcid, [Out, MarshalAs(UnmanagedType.LPWStr)] string lpWideCharStr, [In] int cchWideChar); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void IsCodePageInstallable([In] uint uiCodePage); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void SetMimeDBSource([In] MIMECONTF dwSource); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetNumberOfScripts(out uint pnScripts); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void EnumScripts([In] uint dwFlags, [In] ushort LangId, [MarshalAs(UnmanagedType.Interface)] out IEnumScript ppEnumScript); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void ValidateCodePageEx([In] uint uiCodePage, [In, ComAliasName("MultiLanguage.wireHWND")] ref _RemotableHandle hwnd, [In] uint dwfIODControl); + } + + [ComImport, Guid("4E5868AB-B157-4623-9ACC-6A1D9CAEBE04"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface IMultiLanguage3 : IMultiLanguage2 + { + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void DetectOutboundCodePage([In] uint dwFlags, [In, MarshalAs(UnmanagedType.LPWStr)] string lpWideCharStr, [In] uint cchWideChar, [In] ref uint puiPreferredCodePages, [In] uint nPreferredCodePages, out uint puiDetectedCodePages, [In, Out] ref uint pnDetectedCodePages, [In, MarshalAs(UnmanagedType.LPWStr)] string lpSpecialChar); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void DetectOutboundCodePageInIStream([In] uint dwFlags, [In, MarshalAs(UnmanagedType.Interface)] IStream pStrIn, [In] ref uint puiPreferredCodePages, [In] uint nPreferredCodePages, out uint puiDetectedCodePages, [In, Out] ref uint pnDetectedCodePages, [In, MarshalAs(UnmanagedType.LPWStr)] string lpSpecialChar); + } + + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct DetectEncodingInfo + { + public uint nLangID; + public uint nCodePage; + public int nDocPercent; + public int nConfidence; + } + + public enum MIMECONTF + { + MIMECONTF_BROWSER = 2, + MIMECONTF_EXPORT = 0x400, + MIMECONTF_IMPORT = 8, + MIMECONTF_MAILNEWS = 1, + MIMECONTF_MIME_IE4 = 0x10000000, + MIMECONTF_MIME_LATEST = 0x20000000, + MIMECONTF_MIME_REGISTRY = 0x40000000, + MIMECONTF_MINIMAL = 4, + MIMECONTF_PRIVCONVERTER = 0x10000, + MIMECONTF_SAVABLE_BROWSER = 0x200, + MIMECONTF_SAVABLE_MAILNEWS = 0x100, + MIMECONTF_VALID = 0x20000, + MIMECONTF_VALID_NLS = 0x40000 + } + + [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)] + public struct MIMECPINFO + { + public uint dwFlags; + public uint uiCodePage; + public uint uiFamilyCodePage; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x40)] + public string wszDescription; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)] + public string wszWebCharset; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)] + public string wszHeaderCharset; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)] + public string wszBodyCharset; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x20)] + public string wszFixedWidthFont; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x20)] + public string wszProportionalFont; + public byte bGDICharset; + } + + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct MIMECSETINFO + { + public uint uiCodePage; + public uint uiInternetEncoding; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 50)] + public ushort[] wszCharset; + } + + public enum MLSTR_FLAGS + { + MLSTR_READ = 1, + MLSTR_WRITE = 2 + } + + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct RFC1766INFO + { + public uint lcid; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] + public ushort[] wszRfc1766; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)] + public ushort[] wszLocaleName; + } + + [StructLayout(LayoutKind.Sequential, Pack = 8)] + public struct SCRIPFONTINFO + { + public long scripts; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)] + public ushort[] wszFont; + } + + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct SCRIPTINFO + { + public byte ScriptId; + public uint uiCodePage; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x30)] + public ushort[] wszDescription; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)] + public ushort[] wszFixedWidthFont; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)] + public ushort[] wszProportionalFont; + } + + public enum MLDETECTCP + { + MLDETECTCP_NONE = 0, + MLDETECTCP_7BIT = 1, + MLDETECTCP_8BIT = 2, + MLDETECTCP_DBCS = 4, + MLDETECTCP_HTML = 8, + MLDETECTCP_NUMBER = 16 + } + + [StructLayout(LayoutKind.Sequential, Pack = 8)] + public struct STATSTG + { + [MarshalAs(UnmanagedType.LPWStr)] + public string pwcsName; + public uint type; + public ulong cbSize; + public System.Runtime.InteropServices.ComTypes.FILETIME mtime; + public System.Runtime.InteropServices.ComTypes.FILETIME ctime; + public System.Runtime.InteropServices.ComTypes.FILETIME atime; + public uint grfMode; + public uint grfLocksSupported; + public Guid clsid; + public uint grfStateBits; + public uint reserved; + } + + [StructLayout(LayoutKind.Sequential, Pack = 2)] + public struct UNICODERANGE + { + public ushort wcFrom; + public ushort wcTo; + } + } +} diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/NativeMethods/User32.cs b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/NativeMethods/User32.cs new file mode 100644 index 0000000000..b158632572 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/NativeMethods/User32.cs @@ -0,0 +1,88 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using System; +using System.Runtime.InteropServices; + +namespace Microsoft.Web.Management.PInvoke.User32 +{ + internal enum WindowMessage + { + PBS_SMOOTH = 0x1, + PBS_MARQUEE = 0x8, + WM_SETREDRAW = 0xB, + PBM_SETMARQUEE = 0x400 + 10, + } + + [Flags] + internal enum ExitWindows : uint + { + // + // ONE of the following five: + // + LogOff = 0x00, + ShutDown = 0x01, + Reboot = 0x02, + PowerOff = 0x08, + RestartApps = 0x40, + + // + // plus AT MOST ONE of the following two: + // + Force = 0x04, + ForceIfHung = 0x10, + } + + [Flags] + internal enum ShutdownReason : uint + { + MajorApplication = 0x00040000, + MajorHardware = 0x00010000, + MajorLegacyApi = 0x00070000, + MajorOperatingSystem = 0x00020000, + MajorOther = 0x00000000, + MajorPower = 0x00060000, + MajorSoftware = 0x00030000, + MajorSystem = 0x00050000, + + MinorBlueScreen = 0x0000000F, + MinorCordUnplugged = 0x0000000b, + MinorDisk = 0x00000007, + MinorEnvironment = 0x0000000c, + MinorHardwareDriver = 0x0000000d, + MinorHotfix = 0x00000011, + MinorHung = 0x00000005, + MinorInstallation = 0x00000002, + MinorMaintenance = 0x00000001, + MinorMMC = 0x00000019, + MinorNetworkConnectivity = 0x00000014, + MinorNetworkCard = 0x00000009, + MinorOther = 0x00000000, + MinorOtherDriver = 0x0000000e, + MinorPowerSupply = 0x0000000a, + MinorProcessor = 0x00000008, + MinorReconfig = 0x00000004, + MinorSecurity = 0x00000013, + MinorSecurityFix = 0x00000012, + MinorSecurityFixUninstall = 0x00000018, + MinorServicePack = 0x00000010, + MinorServicePackUninstall = 0x00000016, + MinorTermSrv = 0x00000020, + MinorUnstable = 0x00000006, + MinorUpgrade = 0x00000003, + MinorWMI = 0x00000015, + + FlagUserDefined = 0x40000000, + FlagPlanned = 0x80000000 + } + + internal static class NativeMethods + { + [DllImport("User32.dll", CharSet = CharSet.Auto)] + public static extern IntPtr SendMessage(IntPtr hWnd, WindowMessage msg, int wParam, int lParam); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool ExitWindowsEx(ExitWindows uFlags, ShutdownReason dwReason); + } +} \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/NativeMethods/UxTheme.cs b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/NativeMethods/UxTheme.cs new file mode 100644 index 0000000000..520c923505 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/NativeMethods/UxTheme.cs @@ -0,0 +1,46 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using System; +using System.Runtime.InteropServices; +using System.Text; +using System.Diagnostics; + +namespace Microsoft.Web.Management.PInvoke.UxTheme +{ + internal static class NativeMethods + { + [DllImport("UxTheme.dll", ExactSpelling = true, CharSet = CharSet.Unicode)] + public extern static void SetWindowTheme(IntPtr hWnd, string textSubAppName, string textSubIdList); + + [DllImport("uxtheme.dll", CharSet = CharSet.Unicode, PreserveSig = true)] + private static extern int GetCurrentThemeName(StringBuilder pszThemeFileName, int dwMaxNameChars, StringBuilder pszColorBuff, int dwMaxColorChars, StringBuilder pszSizeBuff, int cchMaxSizeChars); + + public static bool TryGetCurrentThemeName(out string themeName, out string color, out string size) + { + StringBuilder nameBuilder = new StringBuilder(512); + StringBuilder colorBuilder = new StringBuilder(512); + StringBuilder sizeBuilder = new StringBuilder(512); + int hr = GetCurrentThemeName(nameBuilder, nameBuilder.Capacity, colorBuilder, colorBuilder.Capacity, sizeBuilder, sizeBuilder.Capacity); + if (hr == 0) + { + themeName = nameBuilder.ToString(); + color = colorBuilder.ToString(); + size = sizeBuilder.ToString(); + return true; + } + else + { + themeName = null; + color = null; + size = null; + if (hr != Extension.AsHRESULT(Win32ErrorCode.ELEMENT_NOT_FOUND)) + { + Debug.Fail("GetCurrentThemeName returned: " + hr.ToString()); + } + + return false; + } + } + } +} \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/PseudoLoc/PseudoLoc.targets b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/PseudoLoc/PseudoLoc.targets new file mode 100644 index 0000000000..0222289f2c --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/PseudoLoc/PseudoLoc.targets @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/PseudoLoc/PseudoLocalizer.cs b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/PseudoLoc/PseudoLocalizer.cs new file mode 100644 index 0000000000..fccf038061 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/PseudoLoc/PseudoLocalizer.cs @@ -0,0 +1,456 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Reflection; +using System.Resources; + +namespace Microsoft.Web.Utility +{ +#if PSEUDOLOCALIZER_ENABLED || DEBUG + + /// + /// Class that pseudo-localizes resources from a RESX file by intercepting calls to the managed wrapper class. + /// + internal static class PseudoLocalizer + { + private static bool _shouldPseudoLocalize; + private static double _plocPaddingLengthRatio; + + static PseudoLocalizer() + { + _shouldPseudoLocalize = false; + int plocLengthPaddingPercentage = 50; +#if DEBUG + string plocValue = Environment.GetEnvironmentVariable("PSEUDOLOCALIZE"); + if (!string.IsNullOrEmpty(plocValue)) + { + _shouldPseudoLocalize = true; + int.TryParse(plocValue, out plocLengthPaddingPercentage); + if (plocLengthPaddingPercentage < 10) + { + plocLengthPaddingPercentage = 50; + } + } +#endif // DEBUG + + _plocPaddingLengthRatio = plocLengthPaddingPercentage * 0.01; + if (_plocPaddingLengthRatio < 0.1) + { + DebugTrace("ploc should be at least 10% padded"); + } + +#if PSEUDOLOCALIZER_ENABLED + _shouldPseudoLocalize = true; +#endif // PSEUDOLOCALIZER_ENABLED + } + + public static bool ShouldPseudoLocalize + { + get + { + return _shouldPseudoLocalize; + } + } + + // Need to use this method instead of tracing/debugging directly otherwise + // the application will not be able to disable asserts from the exe.config file. + // this is because this code is run very early on in the app before the + // default trace listener has had a chance to initialize its settings + // correctly + private static void DebugTrace(string format, params object[] args) + { + ////only uncomment these lines when actually debugging something + ////otherwise the application wont be able to toggle the assert ui + ////if (args == null || args.Length == 0) + ////{ + //// Debug.WriteLine(format); + ////} + ////else + ////{ + //// Debug.WriteLine(format, args); + ////} + } + + /// + /// Enables pseudo-localization on any type that is of the form {AssemblyName}.Resources + /// + /// + /// true if succeeded, false if failed. + public static bool TryEnableAssembly(Assembly assembly) + { + bool retVal = false; + if (assembly != null) + { + AssemblyName assemblyName = assembly.GetName(); + string resourceTypeName = assemblyName.Name + ".Resources"; + try + { + Type resourceType = assembly.GetType(resourceTypeName, false); + if (resourceType != null) + { + Enable(resourceType); + retVal = true; + } + else + { + DebugTrace("PLOC: no type {0} found in the assembly {1}", + resourceTypeName, + assembly.FullName); + } + } + catch (Exception ex) + { + DebugTrace(ex.ToString()); + } + } + else + { + DebugTrace("assembly should not be null"); + } + + return retVal; + } + + /// + /// Enables pseudo-localization for the specified RESX managed wrapper class. + /// + /// Type of the RESX managed wrapper class. + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "ResourceManager", Justification = "Name of property.")] + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "resourceMan", Justification = "Name of field.")] + public static void Enable(Type resourcesType) + { + if (null == resourcesType) + { + throw new ArgumentNullException("resourcesType"); + } + + // Get the ResourceManager property + var resourceManagerProperty = resourcesType.GetProperty("ResourceManager", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); + if (null == resourceManagerProperty) + { + throw new NotSupportedException("RESX managed wrapper class does not contain the expected internal/public static ResourceManager property."); + } + + // Get the ResourceManager value (ensures the resourceMan field gets initialized) + var resourceManagerValue = resourceManagerProperty.GetValue(null, null) as ResourceManager; + if (null == resourceManagerValue) + { + throw new NotSupportedException("RESX managed wrapper class returned null for the ResourceManager property getter."); + } + + // Get the resourceMan field + var resourceManField = resourcesType.GetField("resourceMan", BindingFlags.Static | BindingFlags.NonPublic); + if (null == resourceManField) + { + throw new NotSupportedException("RESX managed wrapper class does not contain the expected private static resourceMan field."); + } + + // Create a substitute ResourceManager to do the pseudo-localization + var resourceManSubstitute = new PseudoLocalizerResourceManager( + _plocPaddingLengthRatio, + resourceManagerValue.BaseName, + resourcesType.Assembly); + + // Replace the resourceMan field value + resourceManField.SetValue(null, resourceManSubstitute); + } + + /// + /// Enables Pseudo-localization for all assemblies that get loaded from the current + /// host. Within the assemblie, only types that are of the form {AssemblyName}.Resources + /// will get pseudo-localization enabled. + /// + public static void EnableAutoPseudoLocalizationFromHostExecutable() + { + if (ShouldPseudoLocalize) + { + //set up pseudo-localization for ourselves + TryEnableAssembly(Assembly.GetExecutingAssembly()); + + //set up pseudo-localization for anything that gets loaded later + AppDomain.CurrentDomain.AssemblyLoad += + new AssemblyLoadEventHandler(OnCurrentDomainAssemblyLoad); + } + } + + public static string PseudoLocalizeString(string str) + { + return PseudoLocalizerResourceManager.PseudoLocalizeString( + _plocPaddingLengthRatio, + str); + } + + private static void OnCurrentDomainAssemblyLoad(object sender, + AssemblyLoadEventArgs args) + { + Assembly assembly = args.LoadedAssembly; + bool isThisMyAssembly; + if (!assembly.GlobalAssemblyCache) + { + isThisMyAssembly = true; + } + else if (assembly.FullName.StartsWith("Microsoft.Web", + StringComparison.OrdinalIgnoreCase)) + { + isThisMyAssembly = true; + } + else + { + isThisMyAssembly = false; + } + + if (isThisMyAssembly) + { + TryEnableAssembly(assembly); + } + } + + /// + /// Class that overrides default ResourceManager behavior by pseudo-localizing its content. + /// + private class PseudoLocalizerResourceManager : ResourceManager + { + /// + /// Stores a Dictionary for character translations. + /// + private static Dictionary _translations = CreateTranslationsMap(); + + private static Dictionary CreateTranslationsMap() + { + // Map standard "English" characters to similar-looking counterparts from other languages + Dictionary translations = new Dictionary + { + { 'a', 'ä' }, + { 'b', 'ƃ' }, + { 'c', 'č' }, + { 'd', 'ƌ' }, + { 'e', 'ë' }, + { 'f', 'ƒ' }, + { 'g', 'ğ' }, + { 'h', 'ħ' }, + { 'i', 'ï' }, + { 'j', 'ĵ' }, + { 'k', 'ƙ' }, + { 'l', 'ł' }, + { 'm', 'ɱ' }, + { 'n', 'ň' }, + { 'o', 'ö' }, + { 'p', 'þ' }, + { 'q', 'ɋ' }, + { 'r', 'ř' }, + { 's', 'š' }, + { 't', 'ŧ' }, + { 'u', 'ü' }, + { 'v', 'ṽ' }, + { 'w', 'ŵ' }, + { 'x', 'ӿ' }, + { 'y', 'ŷ' }, + { 'z', 'ž' }, + { 'A', 'Ä' }, + { 'B', 'Ɓ' }, + { 'C', 'Č' }, + { 'D', 'Đ' }, + { 'E', 'Ë' }, + { 'F', 'Ƒ' }, + { 'G', 'Ğ' }, + { 'H', 'Ħ' }, + { 'I', 'Ï' }, + { 'J', 'Ĵ' }, + { 'K', 'Ҟ' }, + { 'L', 'Ł' }, + { 'M', 'Ӎ' }, + { 'N', 'Ň' }, + { 'O', 'Ö' }, + { 'P', 'Ҏ' }, + { 'Q', 'Ǫ' }, + { 'R', 'Ř' }, + { 'S', 'Š' }, + { 'T', 'Ŧ' }, + { 'U', 'Ü' }, + { 'V', 'Ṽ' }, + { 'W', 'Ŵ' }, + { 'X', 'Ӿ' }, + { 'Y', 'Ŷ' }, + { 'Z', 'Ž' }, + }; + + return translations; + } + + private double _paddingLengthRatio; + + /// + /// Initializes a new instance of the PseudoLocalizerResourceManager class. + /// + /// The root name of the resource file without its extension but including any fully qualified namespace name. + /// The main assembly for the resources. + public PseudoLocalizerResourceManager(double paddingLengthRatio, + string baseName, + Assembly assembly) + : base(baseName, assembly) + { + _paddingLengthRatio = paddingLengthRatio; + } + + /// + /// Returns the value of the specified String resource. + /// + /// The name of the resource to get. + /// The value of the resource localized for the caller's current culture settings. + public override string GetString(string name) + { + return PseudoLocalizeString(base.GetString(name)); + } + + /// + /// Gets the value of the String resource localized for the specified culture. + /// + /// The name of the resource to get. + /// The CultureInfo object that represents the culture for which the resource is localized. + /// The value of the resource localized for the specified culture. + public override string GetString(string name, CultureInfo culture) + { + return PseudoLocalizeString(base.GetString(name, culture)); + } + + private string PseudoLocalizeString(string str) + { + return PseudoLocalizeString(_paddingLengthRatio, str); + } + + /// + /// Pseudo-localizes a string. + /// + /// Input string. + /// Pseudo-localized string. + internal static string PseudoLocalizeString(double paddingLengthRatio, string str) + { + const string minprefix = "["; + const string minsuffix = "]"; + + // Create a new string with the "translated" values of each character + var translatedChars = new char[str.Length]; + if (IsXamlString(str)) + { + DoCaseTranslation(str, translatedChars); + } + else + { + DoFunkyCharacterTranslation(str, translatedChars); + } + + string mungedString = new string(translatedChars); + + int padLengthPerSide = GetPaddingLengthPerSide( + str.Length, + paddingLengthRatio, + minprefix.Length + minsuffix.Length); + + string extraPadding = new string('=', padLengthPerSide); + string finalString = string.Concat(minprefix, extraPadding, mungedString, extraPadding, minsuffix); + + return finalString; + } + + private static int GetPaddingLengthPerSide(int originalStringLength, double paddingRatio, int minPadLength) + { + int padLengthPerSide; + double exactTotalPadding = (originalStringLength * paddingRatio); + padLengthPerSide = (int)(exactTotalPadding + 1) / 2; + if (padLengthPerSide < 1) + { + padLengthPerSide = 1; + } + + return padLengthPerSide; + } + + private static void DoCaseTranslation(string str, char[] translatedChars) + { + bool inXamlTag = false; + for (var i = 0; i < str.Length; i++) + { + var c = str[i]; + + if (inXamlTag) + { + translatedChars[i] = c; + if (c == '>') + { + inXamlTag = false; + } + } + else + { + translatedChars[i] = (i % 2) == 0 ? char.ToUpper(c) : char.ToLower(c); + if (c == '<' && str.IndexOf('>', i) > -1) + { + inXamlTag = true; + } + } + } + } + + private static void DoFunkyCharacterTranslation(string str, char[] translatedChars) + { + for (var i = 0; i < str.Length; i++) + { + var c = str[i]; + translatedChars[i] = _translations.ContainsKey(c) ? _translations[c] : c; + } + } + + private static bool IsXamlString(string str) + { + // check if this string has a '<' followed by a '>' and assume it's a xaml string if so + int lessThanIndex = str.IndexOf('<'); + if (lessThanIndex > -1) + { + if (str.IndexOf('>', lessThanIndex) > -1) + { + return true; + } + } + + return false; + } + } + } +#else + /// + /// Dummy class needed to keep the public interface be identical in debug and retail builds + /// + internal static class PseudoLocalizer + { + public static bool ShouldPseudoLocalize + { + get + { + return false; + } + } + + public static bool TryEnableAssembly(Assembly assembly) + { + return true; + } + + public static void Enable(Type resourcesType) + { + } + + public static void EnableAutoPseudoLocalizationFromHostExecutable() + { + } + + public static string PseudoLocalizeString(string str) + { + return str; + } + } +#endif +} \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/References/v7Sp1/Microsoft.Web.administration.dll b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/References/v7Sp1/Microsoft.Web.administration.dll new file mode 100644 index 0000000000000000000000000000000000000000..5c786c3d92915cb26236846e500b6a03876a9c54 GIT binary patch literal 126976 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%0D@F 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 literal 0 HcmV?d00001 diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/References/v7Sp1/Microsoft.Web.management.dll b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/References/v7Sp1/Microsoft.Web.management.dll new file mode 100644 index 0000000000000000000000000000000000000000..cbae9ccf9225b6c3dc4c417edf99a33fb238211a GIT binary patch literal 999424 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:sVDf*w?58|qhsE<{5Ef2Kjhkto2=Gr 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

~~kz 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 literal 0 HcmV?d00001 diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/Util/AuthenticationModule.cs b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/Util/AuthenticationModule.cs new file mode 100644 index 0000000000..f284d02d0e --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/Util/AuthenticationModule.cs @@ -0,0 +1,111 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using System; +using System.Net; +using System.Text; + +namespace Microsoft.WebMatrix.Utility +{ + ///

+ /// This AuthenticationModule implements basic authentication but uses UTF8 Encoding to support international characters. + /// Unfortunately the System.Net implementation uses the Default encoding which breaks with them. + /// + internal class AuthenticationModule : IAuthenticationModule + { + private const string AuthenticationTypeName = "Basic"; + private static AuthenticationModule _module = null; + private static object _lock = new object(); + + public static void InstantiateIfNeeded() + { + lock (_lock) + { + if (_module == null) + { + _module = new AuthenticationModule(); + } + } + } + + private AuthenticationModule() + { + AuthenticationManager.Unregister(AuthenticationTypeName); + AuthenticationManager.Register(this); + } + + string IAuthenticationModule.AuthenticationType + { + get + { + return AuthenticationTypeName; + } + } + + bool IAuthenticationModule.CanPreAuthenticate + { + get + { + return true; + } + } + + Authorization IAuthenticationModule.Authenticate(string challenge, WebRequest request, ICredentials credentials) + { + HttpWebRequest httpWebRequest = request as HttpWebRequest; + if (httpWebRequest == null) + { + return null; + } + + // Verify that the challenge is a Basic Challenge + if (challenge == null || !challenge.StartsWith(AuthenticationTypeName, StringComparison.OrdinalIgnoreCase)) + { + return null; + } + + return Authenticate(httpWebRequest, credentials); + } + + Authorization IAuthenticationModule.PreAuthenticate(WebRequest request, ICredentials credentials) + { + HttpWebRequest httpWebRequest = request as HttpWebRequest; + + if (httpWebRequest == null) + { + return null; + } + + return Authenticate(httpWebRequest, credentials); + } + + private Authorization Authenticate(HttpWebRequest httpWebRequest, ICredentials credentials) + { + if (credentials == null) + { + return null; + } + + // Get the username and password from the credentials + NetworkCredential nc = credentials.GetCredential(httpWebRequest.RequestUri, AuthenticationTypeName); + if (nc == null) + { + return null; + } + + ICredentialPolicy policy = AuthenticationManager.CredentialPolicy; + if (policy != null && !policy.ShouldSendCredential(httpWebRequest.RequestUri, httpWebRequest, nc, this)) + { + return null; + } + + string domain = nc.Domain; + + string basicTicket = (!String.IsNullOrEmpty(domain) ? (domain + "\\") : "") + nc.UserName + ":" + nc.Password; + byte[] bytes = Encoding.UTF8.GetBytes(basicTicket); + + string header = AuthenticationTypeName + " " + Convert.ToBase64String(bytes); + return new Authorization(header, true); + } + } +} \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/Util/ExceptionHelper.cs b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/Util/ExceptionHelper.cs new file mode 100644 index 0000000000..b3a6c24c2e --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/Util/ExceptionHelper.cs @@ -0,0 +1,122 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Reflection; + +namespace Microsoft.WebMatrix.Utility +{ + internal class ExceptionHelper + { + private const int PublicKeyTokenLength = 8; + + /// + /// This will return a list of assemblies that are present in the call stack for + /// the input exception. The list CAN have duplicates. + /// + /// + /// + public static IEnumerable GetAssembliesInCallStack(Exception exception) + { + // an AggregateException might have multiple inner exceptions, so we handle it specially + AggregateException aggregateException = exception as AggregateException; + if (exception == null) + { + return Enumerable.Empty(); + } + else if (aggregateException == null) + { + return GetAssembliesInSingleException(exception).Concat(GetAssembliesInCallStack(exception.InnerException)); + } + else + { + return aggregateException.Flatten().InnerExceptions.SelectMany(ex => GetAssembliesInCallStack(ex)); + } + } + + private static IEnumerable GetAssembliesInSingleException(Exception exception) + { + // some exceptions (like AggregateException) don't have an associated stacktrace + if (exception != null && exception.StackTrace != null) + { + StackTrace stackTrace = new StackTrace(exception, false); + foreach (StackFrame frame in stackTrace.GetFrames()) + { + // DeclaringType can be null for lambdas created by Reflection.Emit + Type declaringType = frame.GetMethod().DeclaringType; + if (declaringType != null) + { + Assembly currentAssembly = declaringType.Assembly; + Debug.Assert(currentAssembly != null, "currentAssembly must not be null"); + if (currentAssembly != null) + { + yield return currentAssembly; + } + } + } + } + } + + public static IEnumerable RemoveAssembliesThatAreIntheGAC(IEnumerable input) + { + foreach (Assembly assembly in input) + { + if (!assembly.GlobalAssemblyCache) + { + yield return assembly; + } + } + } + + public static IEnumerable RemoveAssembliesThatAreSignedWithToken(IEnumerable input, byte[] publicKeyToken) + { + Debug.Assert(publicKeyToken.Length == PublicKeyTokenLength, "public key tokens should be 8 bytes"); + foreach (Assembly assembly in input) + { + byte[] currentToken = assembly.GetName().GetPublicKeyToken(); + bool shouldReturn; + if (currentToken.Length == 0) + { + // unsigned assembly + shouldReturn = true; + } + else if (AreTokensTheSame(currentToken, publicKeyToken)) + { + // tokens are the same skip the assembly + shouldReturn = false; + } + else + { + // didnt match anything, return it + shouldReturn = true; + } + + if (shouldReturn) + { + yield return assembly; + } + } + } + + private static bool AreTokensTheSame(byte[] token1, byte[] token2) + { + Debug.Assert( + token1.Length == PublicKeyTokenLength && + token2.Length == PublicKeyTokenLength, + "public key tokens should be 8 bytes"); + + for (int i = 0; i < PublicKeyTokenLength; i++) + { + if (token1[i] != token2[i]) + { + return false; + } + } + + return true; + } + } +} diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/Util/GACManagedAccess.cs b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/Util/GACManagedAccess.cs new file mode 100644 index 0000000000..2dbd5c8ff1 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/Util/GACManagedAccess.cs @@ -0,0 +1,192 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using System.Diagnostics; + +namespace Microsoft.Web.Utility +{ + // need to include \common\Managed\NativeMethods\Fusion.cs in your project to use this class + internal static class GACManagedAccess + { + public static List GetAssemblyList(string assemblyName) + { + return GetAssemblyList(assemblyName, true); + } + + public static List GetAssemblyList(string assemblyName, bool getPhysicalPath) + { + if (string.IsNullOrEmpty(assemblyName)) + { + throw new ArgumentNullException("assemblyName"); + } + + List assemblyList = new List(); + using (GacAssembly gacAssembly = new GacAssembly(assemblyName)) + { + while (true) + { + if (gacAssembly.GetNextAssembly()) + { + if (getPhysicalPath) + { + using (GACAssemblyCache gacAssemblyCache = new GACAssemblyCache(assemblyName, gacAssembly.FullAssemblyName)) + { + assemblyList.Add(gacAssemblyCache.AssemblyPath); + } + } + else + { + assemblyList.Add(gacAssembly.FullAssemblyName); + } + } + else + { + break; + } + } + } + + return assemblyList; + } + } + + internal class GacAssembly : IDisposable + { + internal GacAssembly(string assemblyName) + { + _assemblyName = assemblyName; + int hResult = PInvoke.Fusion.NativeMethods.CreateAssemblyNameObject( + out _fusionName, + _assemblyName, + PInvoke.Fusion.CreateAssemblyNameObjectFlags.CANOF_PARSE_DISPLAY_NAME, + IntPtr.Zero); + + if (hResult >= 0) + { + hResult = PInvoke.Fusion.NativeMethods.CreateAssemblyEnum( + out _assemblyEnum, + IntPtr.Zero, + _fusionName, + PInvoke.Fusion.AssemblyCacheFlags.GAC, + IntPtr.Zero); + } + + if (hResult < 0 || _assemblyEnum == null) + { + throw Marshal.GetExceptionForHR(hResult); + } + } + + internal bool GetNextAssembly() + { + int hResult = _assemblyEnum.GetNextAssembly((IntPtr)0, out _fusionName, 0); + + if (hResult < 0 || _fusionName == null) + { + return false; + } + + return true; + } + + internal string FullAssemblyName + { + get + { + StringBuilder sDisplayName = new StringBuilder(1024); + int iLen = 1024; + + int hrLocal = _fusionName.GetDisplayName( + sDisplayName, + ref iLen, + (int)PInvoke.Fusion.AssemblyNameDisplayFlags.ALL); + + if (hrLocal < 0) + { + throw Marshal.GetExceptionForHR(hrLocal); + } + + return sDisplayName.ToString(); + } + } + + internal PInvoke.Fusion.IAssemblyName FusionName + { + get + { + return _fusionName; + } + } + + public void Dispose() + { + PInvoke.Fusion.IAssemblyName tempName = _fusionName; + if (tempName != null) + { + _fusionName = null; + Marshal.ReleaseComObject(tempName); + } + + PInvoke.Fusion.IAssemblyEnum tempEnum = _assemblyEnum; + if (tempEnum != null) + { + _assemblyEnum = null; + Marshal.ReleaseComObject(tempEnum); + } + } + + private string _assemblyName; + private PInvoke.Fusion.IAssemblyEnum _assemblyEnum; + private PInvoke.Fusion.IAssemblyName _fusionName; + } + + internal class GACAssemblyCache : IDisposable + { + internal GACAssemblyCache(string assemblyName, string fullAssemblyName) + { + PInvoke.Fusion.AssemblyInfo aInfo = new PInvoke.Fusion.AssemblyInfo(); + aInfo.cchBuf = 1024; + aInfo.currentAssemblyPath = new string('\0', aInfo.cchBuf); + + int hResult = PInvoke.Fusion.NativeMethods.CreateAssemblyCache(out _assemblyCache, 0); + + if (hResult == 0) + { + hResult = _assemblyCache.QueryAssemblyInfo(0, fullAssemblyName, ref aInfo); + } + + if (hResult != 0) + { + Marshal.GetExceptionForHR(hResult); + } + + _assemblyPath = aInfo.currentAssemblyPath; + } + + internal string AssemblyPath + { + get + { + return _assemblyPath; + } + } + + public void Dispose() + { + PInvoke.Fusion.IAssemblyCache temp = _assemblyCache; + if (temp != null) + { + _assemblyCache = null; + Marshal.ReleaseComObject(temp); + } + } + + private string _assemblyPath; + private PInvoke.Fusion.IAssemblyCache _assemblyCache; + } +} \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/Util/WebUtility.cs b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/Util/WebUtility.cs new file mode 100644 index 0000000000..2f5a9c93c4 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/Managed/Util/WebUtility.cs @@ -0,0 +1,65 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Collections; +using System.Net; + +namespace Microsoft.Web.Utility +{ + internal static class WebUtility + { + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification="We want to count any error as host doesn't exist")] + public static bool IsLocalMachine(string serverName, bool useDns) + { + if (String.Equals(serverName, Environment.MachineName, StringComparison.CurrentCultureIgnoreCase) || + String.Equals(serverName, "localhost", StringComparison.OrdinalIgnoreCase) || + String.Equals(serverName, "127.0.0.1") || + String.Equals(serverName, "::1")) + { + return true; + } + + if (useDns) + { + try + { + ArrayList serverAddressesList = new ArrayList(); + ArrayList currentMachineAddressesList = new ArrayList(); + + IPAddress ownAddress = IPAddress.Parse("127.0.0.1"); + + // All the IP addresses of the hostname specified by the user + IPAddress[] serverAddress = Dns.GetHostAddresses(serverName); + serverAddressesList.AddRange(serverAddress); + + /// All the IP addresses of the current machine + IPAddress[] currentMachineAddress = Dns.GetHostAddresses(Environment.MachineName); + currentMachineAddressesList.AddRange(currentMachineAddress); + + // The address 127.0.0.1 also refers to the current machine + currentMachineAddressesList.Add(ownAddress); + + // If any of the addresses for the current machine is the same + // as the address for the hostname specified by the user + // then use a local connection + foreach (IPAddress address in currentMachineAddressesList) + { + if (serverAddressesList.Contains(address)) + { + return true; + } + } + } + catch + { + // If the Dns class throws an exception the host propbably does not + // exist so we return false + } + } + + return false; + } + } +} diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/README.md b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/README.md new file mode 100644 index 0000000000..77fc8404c4 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/README.md @@ -0,0 +1,18 @@ +Microsoft IIS Common +-------------------------------- + +The repository contains common resources shared by IIS Out-Of-Band (OOB) products. + +### Contributing + +This project welcomes contributions and suggestions. Most contributions require you to agree to a +Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us +the rights to use your contribution. For details, visit https://cla.microsoft.com. + +When you submit a pull request, a CLA-bot will automatically determine whether you need to provide +a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions +provided by the bot. You will only need to do this once across all repos using our CLA. + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). +For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or +contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/UnitTests/common_tests.rc b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/UnitTests/common_tests.rc new file mode 100644 index 0000000000..98b1593b3b --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/UnitTests/common_tests.rc @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#define RC_VERSION_INTERNAL_NAME "Common.UnitTests\0" +#define RC_VERSION_ORIGINAL_FILE_NAME "Common.UnitTests.dll\0" +#define RC_VERSION_FILE_DESCRIPTION "Common.UnitTests0" +#include diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/UnitTests/dbgutil_tests.cpp b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/UnitTests/dbgutil_tests.cpp new file mode 100644 index 0000000000..2fc97d6f95 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/UnitTests/dbgutil_tests.cpp @@ -0,0 +1,72 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#include "precomp.hxx" +#include "dbgutil.h" +#include + +DECLARE_DEBUG_PRINT_OBJECT( "test" ); + +VOID PrintLevel( DWORD level ) +{ + DWORD old = DEBUG_FLAGS_VAR; + DEBUG_FLAGS_VAR = level; + + DBGPRINTF(( DBG_CONTEXT, "Some Data %d\n", 47 )); + DBGINFO(( DBG_CONTEXT, "Some Info %s\n", "info" )); + DBGWARN(( DBG_CONTEXT, "Some Info %s\n", "warning" )); + DBGERROR(( DBG_CONTEXT, "Some Info %s\n", "error" )); + + DEBUG_FLAGS_VAR = old; +} + + +#pragma managed + +using namespace Microsoft::VisualStudio::TestTools::UnitTesting; + +[TestClass] +public ref class DebugUtilitiesTests +{ +public: + + [ClassInitialize] + static void InitializeDebugObjects(TestContext) + { + CREATE_DEBUG_PRINT_OBJECT; + + _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE ); + _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR ); + } + + [TestMethod] + void TestDbgError() + { + PrintLevel( DEBUG_FLAGS_ERROR ); + } + + [TestMethod] + void TestPrintAny() + { + PrintLevel( DEBUG_FLAGS_ANY ); + } + + [TestMethod] + void TestPrintError() + { + DBGERROR_HR( E_FAIL ); + DBGERROR_STATUS( 47 ); + } + + [TestMethod] + void TestPrintWarn() + { + PrintLevel( DEBUG_FLAGS_WARN ); + } + + [TestMethod] + void TestPrintInfo() + { + PrintLevel( DEBUG_FLAGS_INFO ); + } +}; \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/UnitTests/hash_tests.cpp b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/UnitTests/hash_tests.cpp new file mode 100644 index 0000000000..c0fb29f5a2 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/UnitTests/hash_tests.cpp @@ -0,0 +1,52 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#include "precomp.hxx" +#include "hashtable.h" +#include "hashfn.h" +#include "my_hash.h" + +VOID +CountHash( + MY_OBJ * , //pRecord, + PVOID pVoid +) +{ + DWORD * pActualCount = (DWORD*) pVoid; + ++(*pActualCount); +} + + +#pragma managed + +using namespace Microsoft::VisualStudio::TestTools::UnitTesting; + +[TestClass] +public ref class HashTableTests +{ +public: + + [TestMethod] + void AddTwoRecordsTest() + { + MY_HASH hash; + HRESULT hr; + hr = hash.Initialize(32); + + Assert::AreEqual(S_OK, hr, L"Invalid hash table initialization"); + + MY_OBJ one(L"one"); + hr = hash.InsertRecord(&one); + Assert::AreEqual(S_OK, hr, L"Cannot add element 'one'"); + + MY_OBJ two(L"two"); + hr = hash.InsertRecord(&two); + Assert::AreEqual(S_OK, hr, L"Cannot add element 'two'"); + + DWORD ActualCount = 0; + hash.Apply(CountHash, &ActualCount); + Assert::AreEqual((DWORD)2, ActualCount, L"ActualCount != 2"); + + hash.Clear(); + } +}; diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/UnitTests/hybrid_array_tests.cpp b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/UnitTests/hybrid_array_tests.cpp new file mode 100644 index 0000000000..9f54467e77 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/UnitTests/hybrid_array_tests.cpp @@ -0,0 +1,95 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#include "precomp.hxx" +#include "hybrid_array.h" + +// +// Cannot support mixed native/managed code for BUFFER class +// because of alignment. We need to run the test as native. +// +#include + + +void HybridArrayTest() +{ + HRESULT hr; + + { + HYBRID_ARRAY arrPointers; + Assert::AreEqual(32, arrPointers.QueryCapacity(), L"Invalid initial length"); + } + + { + HYBRID_ARRAY arrIntegers; + int SourceArray[] = {1, 2, 3, 4}; + hr = arrIntegers.Copy( SourceArray ); + Assert::AreEqual(S_OK, hr, L"Copy failed."); + Assert::AreEqual(_countof(SourceArray), arrIntegers.QueryCapacity()); + } + + { + HYBRID_ARRAY arrIntegers; + int* pOriginal = arrIntegers.QueryArray(); + int SourceArray[] = {1, 2, 3, 4}; + hr = arrIntegers.Copy( SourceArray ); + int* pNew = arrIntegers.QueryArray(); + Assert::AreEqual(S_OK, hr, L"Copy failed."); + Assert::AreEqual(_countof(SourceArray), arrIntegers.QueryCapacity(), L"Size should be like source"); + Assert::AreNotEqual((__int64)pNew, (__int64)pOriginal, L"Pointer should be different"); + + Assert::AreEqual(1, arrIntegers[0], L"Index 0 failed."); + Assert::AreEqual(2, arrIntegers.QueryItem(1), L"Index 1 failed."); + Assert::AreEqual(3, arrIntegers.QueryItem(2), L"Index 2 failed."); + Assert::AreEqual(4, arrIntegers[3], L"Index 3 failed."); + } + + { + HYBRID_ARRAY arrIntegers; + hr = arrIntegers.EnsureCapacity(100, false); + Assert::AreEqual(S_OK, hr, L"Copy failed."); + Assert::AreEqual(100, arrIntegers.QueryCapacity()); + } + + { + HYBRID_ARRAY arrIntegers; + arrIntegers[0] = 123; + arrIntegers[1] = 999; + hr = arrIntegers.EnsureCapacity(100, true /*copy previous*/); + Assert::AreEqual(S_OK, hr, L"Copy failed."); + Assert::AreEqual(100, arrIntegers.QueryCapacity()); + Assert::AreEqual(123, arrIntegers[0], L"Index resize 0 failed."); + Assert::AreEqual(999, arrIntegers[1], L"Index resize 1 failed."); + + } + + { + HYBRID_ARRAY arrIntegers; + arrIntegers[0] = 123; + arrIntegers[1] = 999; + hr = arrIntegers.EnsureCapacity(100, true /*copy previous*/, true /*trivial assign*/); + Assert::AreEqual(S_OK, hr, L"Copy failed."); + Assert::AreEqual(100, arrIntegers.QueryCapacity()); + Assert::AreEqual(123, arrIntegers[0], L"Index resize trivial 0 failed."); + Assert::AreEqual(999, arrIntegers[1], L"Index resize trivial 1 failed."); + + } +} + + +#pragma managed + +using namespace Microsoft::VisualStudio::TestTools::UnitTesting; + +[TestClass] +public ref class ArrayTests +{ +public: + + [TestMethod] + void HybridArrayTest() + { + ::HybridArrayTest(); + } + +}; diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/UnitTests/my_hash.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/UnitTests/my_hash.h new file mode 100644 index 0000000000..71417dc77b --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/UnitTests/my_hash.h @@ -0,0 +1,63 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#pragma once + +class MY_OBJ +{ + public: + MY_OBJ(PCWSTR pstr) + : _pstr(pstr) + {} + + PCWSTR GetString() + { + return _pstr; + } + + private: + PCWSTR _pstr; +}; + +class MY_HASH : public HASH_TABLE +{ + public: + VOID + ReferenceRecord( + MY_OBJ * //pRecord + ) + {} + + VOID + DereferenceRecord( + MY_OBJ * //pRecord + ) + {} + + PCWSTR + ExtractKey( + MY_OBJ * pRecord + ) + { + return pRecord->GetString(); + } + + DWORD + CalcKeyHash( + PCWSTR key + ) + { + return HashString(key); + } + + BOOL + EqualKeys( + PCWSTR key1, + PCWSTR key2 + ) + { + return (wcscmp(key1, key2) == 0); + } +}; + +void TestHash(); \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/UnitTests/precomp.hxx b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/UnitTests/precomp.hxx new file mode 100644 index 0000000000..16c76d9540 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/UnitTests/precomp.hxx @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#pragma once +// Native-only by default +#pragma unmanaged +#include diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/UnitTests/string_tests.cpp b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/UnitTests/string_tests.cpp new file mode 100644 index 0000000000..0b987e9b58 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/UnitTests/string_tests.cpp @@ -0,0 +1,680 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#include "precomp.hxx" +#include "buffer.h" +#include "stringu.h" +#include "stringa.h" + +// +// Cannot support mixed native/managed code for BUFFER class +// because of alignment. We need to run the test as native. +// +#include + +void TestBuffer() +{ + // + // 104 == 8 byte size rounded, why is this needed? + // + STACK_BUFFER( bufStack, 104 ); + BUFFER bufReg; + BUFFER* pBuf = new BUFFER; + + // + // QueryPtr + // + Assert::IsNotNull( bufStack.QueryPtr( ) ); + Assert::IsNotNull( bufReg.QueryPtr( ) ); + Assert::IsNotNull( pBuf->QueryPtr( ) ); + + // + // QuerySize + // + Assert::IsTrue( 104 == bufStack.QuerySize( ) ); + Assert::IsTrue( INLINED_BUFFER_LEN == bufReg.QuerySize( ) ); + Assert::IsTrue( INLINED_BUFFER_LEN == pBuf->QuerySize( ) ); + + // + // Resize + // + Assert::IsTrue( bufStack.Resize( 64 ) ); + Assert::IsTrue( bufReg.Resize( 128) ); + Assert::IsTrue( pBuf->Resize( 256 ) ); + + // + // Resize again + // + Assert::IsTrue( bufStack.Resize( 512, true ) ); + Assert::IsTrue( bufReg.Resize( 512, true ) ); + Assert::IsTrue( pBuf->Resize( 512, true ) ); + + // + // Resize again + // + Assert::IsTrue( bufStack.Resize( 1024, false ) ); + Assert::IsTrue( bufReg.Resize( 1024, false ) ); + Assert::IsTrue( pBuf->Resize( 1024, false ) ); + + // + // write to mem + // + ZeroMemory( bufStack.QueryPtr( ), bufStack.QuerySize( ) ); + ZeroMemory( bufReg.QueryPtr( ), bufReg.QuerySize( ) ); + ZeroMemory( pBuf->QueryPtr( ), pBuf->QuerySize( ) ); + + delete pBuf; +} + +void TestStraOverrun() +{ + STACK_STRA( straStack, 3 ); + wchar_t Input[] = {0x65f6, 0x0}; + HRESULT hr; + + hr = straStack.CopyW(Input); + Assert::IsTrue( SUCCEEDED(hr) ); + Assert::AreEqual( 3, straStack.QueryCCH(), L"Invalid string length." ); + Assert::AreEqual( 4, straStack.QuerySizeCCH(), L"Invalid buffer length." ); +} + +#define LOWER_A_THING L"ä" +#define UPPER_A_THING L"Ä" + +void TestStru() +{ + STACK_STRU( struStack, 104 ); + STRU struReg; + wchar_t buf[100]; + DWORD cbBuf = sizeof( buf ); + + // + // IsEmpty + // + Assert::IsTrue( struStack.IsEmpty( ) ); + Assert::IsTrue( L'\0' == struStack.QueryStr()[0] ); + Assert::IsTrue( struReg.IsEmpty( ) ); + + // + // Copy psz + // CopyA psz + // + Assert::IsTrue( SUCCEEDED( struStack.Copy( L"hello" ) ) ); + Assert::IsTrue( SUCCEEDED( struReg.CopyA( "hello" ) ) ); + + // + // Equal + // + Assert::IsTrue( struStack.Equals( L"hello" ) ); + Assert::IsTrue( !struStack.Equals( L"goodbye" ) ); + Assert::IsTrue( !struStack.Equals( L"" ) ); + + STRU strHELLO; + Assert::IsTrue( SUCCEEDED( strHELLO.Copy( L"HELLO" ) ) ); + + Assert::IsTrue( struStack.Equals( &struReg ) ); + Assert::IsTrue( struStack.Equals( struReg ) ); + + Assert::IsTrue( !struStack.Equals( &strHELLO ) ); + Assert::IsTrue( !struStack.Equals( strHELLO ) ); + + Assert::IsTrue( struStack.Equals( &strHELLO, TRUE ) ); + Assert::IsTrue( struStack.Equals( strHELLO, TRUE ) ); + + Assert::IsTrue( struStack.Equals( L"helLO", TRUE ) ); + + + Assert::IsTrue( STRU::Equals( L"Hello", L"Hello" ) ); + Assert::IsTrue( STRU::Equals( L"Hello", L"Hello", FALSE ) ); + Assert::IsTrue( STRU::Equals( L"Hello", L"Hello", TRUE ) ); + + Assert::IsFalse( STRU::Equals( L"hello", L"Hello" ) ); + Assert::IsFalse( STRU::Equals( L"hello", L"Hello", FALSE ) ); + Assert::IsTrue( STRU::Equals( L"hello", L"Hello", TRUE ) ); + + Assert::IsFalse( STRU::Equals( L"hello", L"goodbye" ) ); + Assert::IsFalse( STRU::Equals( L"hello", L"goodbye", FALSE ) ); + Assert::IsFalse( STRU::Equals( L"hello", L"goodbye", TRUE ) ); + + Assert::IsFalse( STRU::Equals( (PCWSTR)NULL, (PCWSTR)NULL ) ); + Assert::IsFalse( STRU::Equals( L"hello", (PCWSTR)NULL ) ); + Assert::IsFalse( STRU::Equals( (PCWSTR)NULL, L"hello" ) ); + + + + // + // Query* + // + Assert::IsTrue( 5 * sizeof( wchar_t ) == struStack.QueryCB( ) ); + Assert::IsTrue( 5 == struStack.QueryCCH( ) ); + Assert::IsTrue( 6 <= struStack.QuerySizeCCH( ) ); + Assert::IsTrue( L'h' == *( struStack.QueryStr( ) ) ); + + // + // Resize + // + Assert::IsTrue( SUCCEEDED( struReg.Resize( 7 ) ) ); + Assert::IsTrue( 7 == struReg.QuerySizeCCH( ) ); + + // + // SyncWithBuffer + // + *(struStack.QueryStr() + 5) = L'\0'; + Assert::AreEqual(S_OK, struStack.SyncWithBuffer( )); + Assert::IsTrue( 5 == struStack.QueryCCH( ) ); + + // + // Reset + // + struStack.Reset( ); + Assert::IsTrue( 0 == wcslen( struStack.QueryStr( ) ) ); + + // + // Append* + // + Assert::IsTrue( SUCCEEDED( struStack.Append( L"hell" ) ) ); + Assert::IsTrue( SUCCEEDED( struStack.Append( L"o", 1 ) ) ); + Assert::IsTrue( SUCCEEDED( struStack.Append( &struReg ) ) ); + Assert::IsTrue( SUCCEEDED( struStack.AppendA( "hell" ) ) ); + Assert::IsTrue( SUCCEEDED( struStack.AppendA( "0", 1, CP_ACP ) ) ); + Assert::IsTrue( 15 == wcslen( struStack.QueryStr( ) ) ); + + // + // CopyToBuffer + // + Assert::IsTrue( SUCCEEDED( struStack.CopyToBuffer( buf, &cbBuf ) ) ); + Assert::IsTrue( 15 == wcslen( buf ) ); + Assert::IsTrue( 16 * sizeof( wchar_t ) == cbBuf ); + + // + // Trim + // + Assert::IsTrue( SUCCEEDED( struStack.Copy(L" \n\tHello World! \n\t ") ) ); + struStack.Trim(); + Assert::IsTrue( struStack.Equals(L"Hello World!")); + + Assert::IsTrue( SUCCEEDED( struStack.Copy(L" Test test") ) ); + struStack.Trim(); + Assert::IsTrue( struStack.Equals(L"Test test")); + + Assert::IsTrue( SUCCEEDED( struStack.Copy(L"Test test ") ) ); + struStack.Trim(); + Assert::IsTrue( struStack.Equals(L"Test test")); + + Assert::IsTrue( SUCCEEDED( struStack.Copy(L" Test test ") ) ); + struStack.Trim(); + Assert::IsTrue( struStack.Equals(L"Test test")); + + Assert::IsTrue( SUCCEEDED( struStack.Copy(L" ") ) ); + struStack.Trim(); + Assert::IsTrue( struStack.Equals(L"")); + + Assert::IsTrue( SUCCEEDED( struStack.Copy(L" ") ) ); + struStack.Trim(); + Assert::IsTrue( struStack.Equals(L"")); + + Assert::IsTrue( SUCCEEDED( struStack.Copy(L"") ) ); + struStack.Trim(); + Assert::IsTrue( struStack.Equals(L"")); + + // + // StartsWith + // + Assert::IsTrue( SUCCEEDED( struStack.Copy(L"Just the facts, please.") ) ); + Assert::IsTrue( struStack.StartsWith(L"Just the facts, please.") ); + Assert::IsTrue( struStack.StartsWith(L"Just") ); + Assert::IsTrue( struStack.StartsWith(L"Just the") ); + Assert::IsTrue( !struStack.StartsWith(L"just the") ); + Assert::IsTrue( struStack.StartsWith(L"just The", TRUE) ); + Assert::IsTrue( !struStack.StartsWith((LPCWSTR) NULL, TRUE) ); + Assert::IsTrue( !struStack.StartsWith(L"Just the facts, please...") ); + + // + // EndsWith + // + Assert::IsTrue( SUCCEEDED( struStack.Copy(L"The beginning of the end of the beginning.") ) ); + Assert::IsTrue( struStack.EndsWith(L"The beginning of the end of the beginning.") ); + Assert::IsTrue( struStack.EndsWith(L".") ); + Assert::IsTrue( struStack.EndsWith(L"of the beginning.") ); + Assert::IsTrue( !struStack.EndsWith(L"Beginning.") ); + Assert::IsTrue( struStack.EndsWith(L"Beginning.", TRUE) ); + Assert::IsTrue( struStack.EndsWith(L"tHe BeGiNnIng.", TRUE) ); + Assert::IsTrue( !struStack.EndsWith((LPCWSTR) NULL, TRUE) ); + Assert::IsTrue( !struStack.EndsWith(L" The beginning of the end of the beginning.") ); + + // + // IndexOf + // + Assert::IsTrue( SUCCEEDED( struStack.Copy(L"01234567890") ) ); + Assert::IsTrue( 0 == struStack.IndexOf( L'0' ) ); + Assert::IsTrue( 1 == struStack.IndexOf( L'1' ) ); + Assert::IsTrue( 2 == struStack.IndexOf( L'2', 1 ) ); + Assert::IsTrue( 10 == struStack.IndexOf( L'0', 1 ) ); + Assert::IsTrue( -1 == struStack.IndexOf( L'A' ) ); + Assert::IsTrue( -1 == struStack.IndexOf( L'0', 20 ) ); + + Assert::IsTrue( 0 == struStack.IndexOf( L"0123" ) ); + Assert::IsTrue( -1 == struStack.IndexOf( L"0123", 1 ) ); + Assert::IsTrue( 0 == struStack.IndexOf( L"01234567890" ) ); + Assert::IsTrue( -1 == struStack.IndexOf( L"012345678901" ) ); + Assert::IsTrue( 1 == struStack.IndexOf( L"1234" ) ); + Assert::IsTrue( 1 == struStack.IndexOf( L"1234", 1 ) ); + Assert::IsTrue( -1 == struStack.IndexOf( (PCWSTR)NULL ) ); + Assert::IsTrue( 0 == struStack.IndexOf( L"" ) ); + Assert::IsTrue( -1 == struStack.IndexOf( L"", 20 ) ); + + // + // LastIndexOf + // + Assert::IsTrue( 10 == struStack.LastIndexOf( L'0' ) ); + Assert::IsTrue( 1 == struStack.LastIndexOf( L'1' ) ); + Assert::IsTrue( 2 == struStack.LastIndexOf( L'2', 1 ) ); + Assert::IsTrue( 10 == struStack.LastIndexOf( L'0', 1 ) ); + Assert::IsTrue( -1 == struStack.LastIndexOf( L'A' ) ); + Assert::IsTrue( -1 == struStack.LastIndexOf( L'0', 20 ) ); + + // + // SetLen + // + Assert::IsTrue( SUCCEEDED( struStack.SetLen( 2 ) ) ); + Assert::IsTrue( 2 == struStack.QueryCCH( ) ); + +#if defined( NTDDI_VERSION ) && NTDDI_VERSION >= NTDDI_LONGHORN + + // + // OS-locale case-insensitive compare + // Note how the two case-insensitive comparisons have different expected results + // + Assert::IsTrue( SUCCEEDED( struStack.Copy( LOWER_A_THING ) ) ); + Assert::IsTrue( SUCCEEDED( struReg.Copy( UPPER_A_THING ) ) ); + Assert::IsTrue( !struStack.Equals( &struReg ) ); + Assert::IsTrue( struStack.Equals( &struReg, TRUE ) ); + Assert::IsTrue( 0 != _wcsicmp( LOWER_A_THING, UPPER_A_THING ) ); + +#endif + + Assert::IsTrue( SUCCEEDED( struReg.SafeSnwprintf( L"%s%d", L"Hello", 10 ) ) ); + + // + // Fail since there is no null-terminating char. + // + struStack.Reset(); + struStack.Resize(200); + memset(struStack.QueryStr(), 'x', 200 * sizeof(WCHAR)); + Assert::AreNotEqual(S_OK, struStack.SyncWithBuffer()); +} + +void TestStra() +{ + STACK_STRA( straStack, 104 ); + STRA straReg; + char buf[100]; + DWORD cbBuf = sizeof( buf ); + + // + // IsEmpty + // + Assert::IsTrue( straStack.IsEmpty( ) ); + Assert::IsTrue( '\0' == straStack.QueryStr()[0] ); + Assert::IsTrue( straReg.IsEmpty( ) ); + + // + // Copy psz + // CopyW psz + // + Assert::IsTrue( SUCCEEDED( straStack.Copy( "hello" ) ) ); + Assert::IsTrue( SUCCEEDED( straReg.CopyW( L"hello" ) ) ); + + // + // Equal + // + Assert::IsTrue( straStack.Equals( "hello" ) ); + Assert::IsTrue( straStack.Equals( &straReg ) ); + Assert::IsTrue( straStack.Equals( "helLO", TRUE ) ); + + + Assert::IsTrue( STRA::Equals( "Hello", "Hello" ) ); + Assert::IsTrue( STRA::Equals( "Hello", "Hello", FALSE ) ); + Assert::IsTrue( STRA::Equals( "Hello", "Hello", TRUE ) ); + + Assert::IsFalse( STRA::Equals( "hello", "Hello" ) ); + Assert::IsFalse( STRA::Equals( "hello", "Hello", FALSE ) ); + Assert::IsTrue( STRA::Equals( "hello", "Hello", TRUE ) ); + + Assert::IsFalse( STRA::Equals( "hello", "goodbye" ) ); + Assert::IsFalse( STRA::Equals( "hello", "goodbye", FALSE ) ); + Assert::IsFalse( STRA::Equals( "hello", "goodbye", TRUE ) ); + + Assert::IsFalse( STRA::Equals( (PCSTR)NULL, (PCSTR)NULL ) ); + Assert::IsFalse( STRA::Equals( "hello", (PCSTR)NULL ) ); + Assert::IsFalse( STRA::Equals( (PCSTR)NULL, "hello" ) ); + + // + // Query* + // + Assert::IsTrue( 5 * sizeof( char ) == straStack.QueryCB( ) ); + Assert::IsTrue( 5 == straStack.QueryCCH( ) ); + Assert::IsTrue( 6 <= straStack.QuerySizeCCH( ) ); + Assert::IsTrue( 'h' == *( straStack.QueryStr( ) ) ); + + // + // Resize + // + Assert::IsTrue( SUCCEEDED( straReg.Resize( 7 ) ) ); + Assert::IsTrue( 7 == straReg.QuerySizeCCH( ) ); + + // + // SyncWithBuffer + // + *(straStack.QueryStr() + 5) = L'\0'; + Assert::AreEqual(S_OK, straStack.SyncWithBuffer( )); + Assert::IsTrue( 5 == straStack.QueryCCH( ) ); + + // + // Reset + // + straStack.Reset( ); + Assert::IsTrue( 0 == strlen( straStack.QueryStr( ) ) ); + + // + // Append* + // + Assert::IsTrue( SUCCEEDED( straStack.Append( "hell" ) ) ); + Assert::IsTrue( SUCCEEDED( straStack.Append( "o", 1 ) ) ); + Assert::IsTrue( SUCCEEDED( straStack.Append( &straReg ) ) ); + Assert::IsTrue( SUCCEEDED( straStack.AppendW( L"hell" ) ) ); + Assert::IsTrue( SUCCEEDED( straStack.AppendW( L"0", 1, CP_ACP ) ) ); + Assert::IsTrue( 15 == strlen( straStack.QueryStr( ) ) ); + + // + // CopyToBuffer + // + Assert::IsTrue( SUCCEEDED( straStack.CopyToBuffer( buf, &cbBuf ) ) ); + Assert::IsTrue( 15 == strlen( buf ) ); + Assert::IsTrue( 16 * sizeof( char ) == cbBuf ); + + // + // Trim + // + Assert::IsTrue( SUCCEEDED( straStack.Copy(" \n\tHello World! \n\t ") ) ); + straStack.Trim(); + Assert::IsTrue( straStack.Equals("Hello World!")); + + Assert::IsTrue( SUCCEEDED( straStack.Copy(" Test test") ) ); + straStack.Trim(); + Assert::IsTrue( straStack.Equals("Test test")); + + Assert::IsTrue( SUCCEEDED( straStack.Copy("Test test ") ) ); + straStack.Trim(); + Assert::IsTrue( straStack.Equals("Test test")); + + Assert::IsTrue( SUCCEEDED( straStack.Copy(" Test test ") ) ); + straStack.Trim(); + Assert::IsTrue( straStack.Equals("Test test")); + + Assert::IsTrue( SUCCEEDED( straStack.Copy(" ") ) ); + straStack.Trim(); + Assert::IsTrue( straStack.Equals("")); + + Assert::IsTrue( SUCCEEDED( straStack.Copy(" ") ) ); + straStack.Trim(); + Assert::IsTrue( straStack.Equals("")); + + Assert::IsTrue( SUCCEEDED( straStack.Copy("") ) ); + straStack.Trim(); + Assert::IsTrue( straStack.Equals("")); + + // + // StartsWith + // + Assert::IsTrue( SUCCEEDED( straStack.Copy("Just the facts, please.") ) ); + Assert::IsTrue( straStack.StartsWith("Just the facts, please.") ); + Assert::IsTrue( straStack.StartsWith("Just") ); + Assert::IsTrue( straStack.StartsWith("Just the") ); + Assert::IsTrue( !straStack.StartsWith("just the") ); + Assert::IsTrue( straStack.StartsWith("just The", TRUE) ); + Assert::IsTrue( !straStack.StartsWith((LPCSTR) NULL, TRUE) ); + Assert::IsTrue( !straStack.StartsWith("Just the facts, please...") ); + + // + // EndsWith + // + Assert::IsTrue( SUCCEEDED( straStack.Copy("The beginning of the end of the beginning.") ) ); + Assert::IsTrue( straStack.EndsWith("The beginning of the end of the beginning.") ); + Assert::IsTrue( straStack.EndsWith(".") ); + Assert::IsTrue( straStack.EndsWith("of the beginning.") ); + Assert::IsTrue( !straStack.EndsWith("Beginning.") ); + Assert::IsTrue( straStack.EndsWith("Beginning.", TRUE) ); + Assert::IsTrue( straStack.EndsWith("tHe BeGiNnIng.", TRUE) ); + Assert::IsTrue( !straStack.EndsWith((LPCSTR) NULL, TRUE) ); + Assert::IsTrue( !straStack.EndsWith(" The beginning of the end of the beginning.") ); + + // + // IndexOf + // + Assert::IsTrue( SUCCEEDED( straStack.Copy("01234567890") ) ); + Assert::IsTrue( 0 == straStack.IndexOf( '0' ) ); + Assert::IsTrue( 1 == straStack.IndexOf( '1' ) ); + Assert::IsTrue( 2 == straStack.IndexOf( '2', 1 ) ); + Assert::IsTrue( 10 == straStack.IndexOf( '0', 1 ) ); + Assert::IsTrue( -1 == straStack.IndexOf( 'A' ) ); + Assert::IsTrue( -1 == straStack.IndexOf( '0', 20 ) ); + + Assert::IsTrue( 0 == straStack.IndexOf( "0123" ) ); + Assert::IsTrue( -1 == straStack.IndexOf( "0123", 1 ) ); + Assert::IsTrue( 0 == straStack.IndexOf( "01234567890" ) ); + Assert::IsTrue( -1 == straStack.IndexOf( "012345678901" ) ); + Assert::IsTrue( 1 == straStack.IndexOf( "1234" ) ); + Assert::IsTrue( 1 == straStack.IndexOf( "1234", 1 ) ); + Assert::IsTrue( -1 == straStack.IndexOf( (PCSTR)NULL ) ); + Assert::IsTrue( 0 == straStack.IndexOf( "" ) ); + Assert::IsTrue( -1 == straStack.IndexOf( "", 20 ) ); + + // + // LastIndexOf + // + Assert::IsTrue( 10 == straStack.LastIndexOf( '0' ) ); + Assert::IsTrue( 1 == straStack.LastIndexOf( '1' ) ); + Assert::IsTrue( 2 == straStack.LastIndexOf( '2', 1 ) ); + Assert::IsTrue( 10 == straStack.LastIndexOf( '0', 1 ) ); + Assert::IsTrue( -1 == straStack.LastIndexOf( 'A' ) ); + Assert::IsTrue( -1 == straStack.LastIndexOf( '0', 20 ) ); + + // + // SetLen + // + Assert::IsTrue( SUCCEEDED( straStack.SetLen( 2 ) ) ); + Assert::IsTrue( 2 == straStack.QueryCCH( ) ); + + + // + // Convert. + // + { + STRA str; + wchar_t psz[] = {0x41, L'Ã', 0x0}; + char pszA[] = {0x41, 'Ã', 0x0}; + Assert::IsTrue( SUCCEEDED(str.CopyW((LPCWSTR)psz, 2, CP_ACP )) ); + Assert::IsTrue( 0 == strcmp( pszA, str.QueryStr() ) ); + } + // + // Empty + // + { + STRA str; + wchar_t psz[] = {0x0}; + char pszA[] = {0x0}; + Assert::IsTrue( SUCCEEDED(str.CopyW((LPCWSTR)psz, 0, CP_ACP )) ); + Assert::IsTrue( 0 == strcmp( pszA, str.QueryStr() ) ); + } + + // + // Fail since there is no null-terminating char. + // + straStack.Reset(); + straStack.Resize(200); + memset(straStack.QueryStr(), 'x', 200); + Assert::AreNotEqual(S_OK, straStack.SyncWithBuffer()); +} + +VOID +AsciiAssert(char * str1, char * str2, size_t length) +{ + for ( size_t index = 0; index < length; ++index ) + { + Assert::AreEqual(str1[index], str2[index]); + } +} + +void +TestStraUnicode() +{ + STRA str; + HRESULT hr = S_OK; + + // + // Tool used to convert unicode to UTF-8 code points and hexadecimal code points: + // http://rishida.net/scripts/uniview/conversion.php + // + + // + // Input values to play with. + // + + // Real unicode string. + LPCWSTR InputRealUnicode = L"?q=世加"; + + // This is the same value than InputRealUnicode, but represented as an array. + wchar_t InputRealUnicodeArray[] = + { + 0x3F, // ? + 0x71, // q + 0x3D, // = + 0x4E16, // 世 + 0x52A0, // 加 + 0x00 // L'\0' + }; + + wchar_t InputAscii[] = + { + 0x3F, // ? + 0x71, // q + 0x3D, // = + 0x7F, // 127 + 0x00 // L'\0' + }; + + // Fake unicode + // UTF-8 code units in 'wchar_t' chars instead of 'char' chars. + // This is how WinHttp returns the query string. + wchar_t InputFakeUnicode[] = + { + 0x3F, // ? + 0x71, // q + 0x3D, // = + 0xE4, // 1st code unit for '世' + 0xB8, // 2nd code unit for '世' + 0x96, // 3rd code unit for '世' + 0xE5, // 1st code unit for '加' + 0x8A, // 2nd code unit for '加' + 0xA0, // 3rd code unit for '加' + 0x00 // L'\0' + }; + + // + // Expected values after translation. + // + + unsigned char ExpectedAsciiCodeUnits[] = + { + 0x3F, // ? + 0x71, // q + 0x3D, // = + 0xE4, // 1st code unit for '世' + 0xB8, // 2nd code unit for '世' + 0x96, // 3rd code unit for '世' + 0xE5, // 1st code unit for '加' + 0x8A, // 2nd code unit for '加' + 0xA0, // 3rd code unit for '加' + 0x00 // L'\0' + }; + + char ExpectedAscii[] = + { + 0x3F, // ? + 0x71, // q + 0x3D, // = + 0x7F, // 127 + 0x00 // L'\0' + }; + + // + // Act and Assert. + // + + hr = str.CopyW(InputRealUnicode); + Assert::AreEqual(S_OK, hr); + Assert::AreEqual(9UL, str.QueryCCH(), L"Invalid real unicode query string length."); + AsciiAssert( (char*)ExpectedAsciiCodeUnits, str.QueryStr(), str.QueryCCH() ); + + hr = str.CopyW(InputRealUnicodeArray); + Assert::AreEqual(S_OK, hr); + Assert::AreEqual(9UL, str.QueryCCH(), L"Invalid real unicode query string length."); + AsciiAssert( (char*)ExpectedAsciiCodeUnits, str.QueryStr(), str.QueryCCH() ); + + hr = str.CopyWTruncate(InputFakeUnicode); + Assert::AreEqual(S_OK, hr); + Assert::AreEqual(9UL, str.QueryCCH(), L"Invalid truncated fake unicode query string length."); + AsciiAssert( (char*)ExpectedAsciiCodeUnits, str.QueryStr(), str.QueryCCH() ); + + hr = str.CopyWTruncate(InputAscii); + Assert::AreEqual(S_OK, hr); + Assert::AreEqual(4UL, str.QueryCCH(), L"Invalid truncated ASCII query string length."); + AsciiAssert( ExpectedAscii, str.QueryStr(), str.QueryCCH() ); + + hr = str.CopyW(InputAscii); + Assert::AreEqual(S_OK, hr); + Assert::AreEqual(4UL, str.QueryCCH(), L"Invalid CopyW ASCII query string length."); + AsciiAssert( ExpectedAscii, str.QueryStr(), str.QueryCCH() ); + +} + +#pragma managed + +using namespace Microsoft::VisualStudio::TestTools::UnitTesting; + +[TestClass] +public ref class StringTests +{ +public: + + [TestMethod] + void BufferTest() + { + ::TestBuffer(); + } + + [TestMethod] + void StruTest() + { + ::TestStru(); + } + + [TestMethod] + void StraTest() + { + ::TestStra(); + } + + [TestMethod] + void TestStraOverrun() + { + ::TestStraOverrun(); + } + + [TestMethod] + void StraUnicodeTest() + { + ::TestStraUnicode(); + } +}; diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/CommonLib.vcxproj b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/CommonLib.vcxproj new file mode 100644 index 0000000000..908ef42d1a --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/CommonLib.vcxproj @@ -0,0 +1,79 @@ + + + + + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {B54A8F61-60DE-4AD9-87CA-D102F230678E} + Win32Proj + Lib + CommonLib + + + + StaticLibrary + v141 + + + false + + + + $(ProjectDir)..\include;$(IncludePath) + iiscommon + + + + true + precomp.h + _LIB;%(PreprocessorDefinitions) + + + Windows + + + + + + + + + + + + + + + + + + + + + + This project is trying to import a missing file: {0}. + + + + + + \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/acache.cxx b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/acache.cxx new file mode 100644 index 0000000000..262c010a2a --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/acache.cxx @@ -0,0 +1,443 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#include "precomp.h" + +LONG ALLOC_CACHE_HANDLER::sm_nFillPattern = 0xACA50000; +HANDLE ALLOC_CACHE_HANDLER::sm_hHeap; + +// +// This class is used to implement the free list. We cast the free'd +// memory block to a FREE_LIST_HEADER*. The signature is used to guard against +// double deletion. We also fill memory with a pattern. +// +class FREE_LIST_HEADER +{ +public: + SLIST_ENTRY ListEntry; + DWORD dwSignature; + + enum + { + FREE_SIGNATURE = (('A') | ('C' << 8) | ('a' << 16) | (('$' << 24) | 0x80)), + }; +}; + +ALLOC_CACHE_HANDLER::ALLOC_CACHE_HANDLER( + VOID +) : m_nThreshold(0), + m_cbSize(0), + m_pFreeLists(NULL), + m_nTotal(0) +{ +} + +ALLOC_CACHE_HANDLER::~ALLOC_CACHE_HANDLER( + VOID +) +{ + if (m_pFreeLists != NULL) + { + CleanupLookaside(); + m_pFreeLists->Dispose(); + m_pFreeLists = NULL; + } +} + +HRESULT +ALLOC_CACHE_HANDLER::Initialize( + DWORD cbSize, + LONG nThreshold +) +{ + HRESULT hr = S_OK; + + m_nThreshold = nThreshold; + if ( m_nThreshold > 0xffff) + { + // + // This will be compared against QueryDepthSList return value (USHORT). + // + m_nThreshold = 0xffff; + } + + if ( IsPageheapEnabled() ) + { + // + // Disable acache. + // + m_nThreshold = 0; + } + + // + // Make sure the block is big enough to hold a FREE_LIST_HEADER. + // + m_cbSize = cbSize; + m_cbSize = max(m_cbSize, sizeof(FREE_LIST_HEADER)); + + // + // Round up the block size to a multiple of the size of a LONG (for + // the fill pattern in Free()). + // + m_cbSize = (m_cbSize + sizeof(LONG) - 1) & ~(sizeof(LONG) - 1); + +#if defined(_MSC_VER) && _MSC_VER >= 1600 // VC10 + auto Init = [] (SLIST_HEADER* pHead) + { + InitializeSListHead(pHead); + }; +#else + class Functor + { + public: + void operator()(SLIST_HEADER* pHead) + { + InitializeSListHead(pHead); + } + } Init; +#endif + + hr = PER_CPU::Create(Init, + &m_pFreeLists ); + if (FAILED(hr)) + { + goto Finished; + } + + m_nFillPattern = InterlockedIncrement(&sm_nFillPattern); + +Finished: + + return hr; +} + +// static +HRESULT +ALLOC_CACHE_HANDLER::StaticInitialize( + VOID +) +{ + // + // Since the memory allocated is fixed size, + // a heap is not really needed, allocations can be done + // using VirtualAllocEx[Numa]. For now use Windows Heap. + // + // Be aware that creating one private heap consumes more + // virtual address space for the worker process. + // + sm_hHeap = GetProcessHeap(); + return S_OK; +} + + +// static +VOID +ALLOC_CACHE_HANDLER::StaticTerminate( + VOID +) +{ + sm_hHeap = NULL; +} + +VOID +ALLOC_CACHE_HANDLER::CleanupLookaside( + VOID +) +/*++ + Description: + This function cleans up the lookaside list by removing storage space. + + Arguments: + None. + + Returns: + None +--*/ +{ + // + // Free up all the entries in the list. + // Don't use InterlockedFlushSList, in order to work + // memory must be 16 bytes aligned and currently it is 64. + // + +#if defined(_MSC_VER) && _MSC_VER >= 1600 // VC10 + auto Predicate = [=] (SLIST_HEADER * pListHeader) + { + PSLIST_ENTRY pl; + LONG NodesToDelete = QueryDepthSList( pListHeader ); + + pl = InterlockedPopEntrySList( pListHeader ); + while ( pl != NULL && --NodesToDelete >= 0 ) + { + InterlockedDecrement( &m_nTotal); + + ::HeapFree( sm_hHeap, 0, pl ); + + pl = InterlockedPopEntrySList(pListHeader); + } + }; +#else + class Functor + { + public: + explicit Functor(ALLOC_CACHE_HANDLER * pThis) : _pThis(pThis) + { + } + void operator()(SLIST_HEADER * pListHeader) + { + PSLIST_ENTRY pl; + LONG NodesToDelete = QueryDepthSList( pListHeader ); + + pl = InterlockedPopEntrySList( pListHeader ); + while ( pl != NULL && --NodesToDelete >= 0 ) + { + InterlockedDecrement( &_pThis->m_nTotal); + + ::HeapFree( sm_hHeap, 0, pl ); + + pl = InterlockedPopEntrySList(pListHeader); + } + } + private: + ALLOC_CACHE_HANDLER * _pThis; + } Predicate(this); +#endif + + m_pFreeLists ->ForEach(Predicate); +} + +LPVOID +ALLOC_CACHE_HANDLER::Alloc( + VOID +) +{ + LPVOID pMemory = NULL; + + if ( m_nThreshold > 0 ) + { + SLIST_HEADER * pListHeader = m_pFreeLists ->GetLocal(); + pMemory = (LPVOID) InterlockedPopEntrySList(pListHeader); // get the real object + + if (pMemory != NULL) + { + FREE_LIST_HEADER* pfl = (FREE_LIST_HEADER*) pMemory; + // + // If the signature is wrong then somebody's been scribbling + // on memory that they've freed. + // + DBG_ASSERT(pfl->dwSignature == FREE_LIST_HEADER::FREE_SIGNATURE); + } + } + + if ( pMemory == NULL ) + { + // + // No free entry. Need to alloc a new object. + // + pMemory = (LPVOID) ::HeapAlloc( sm_hHeap, + 0, + m_cbSize ); + + if ( pMemory != NULL ) + { + // + // Update counters. + // + m_nTotal++; + } + } + + if ( pMemory == NULL ) + { + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + } + else + { + FREE_LIST_HEADER* pfl = (FREE_LIST_HEADER*) pMemory; + pfl->dwSignature = 0; // clear; just in case caller never overwrites + } + + return pMemory; +} + +VOID +ALLOC_CACHE_HANDLER::Free( + __in LPVOID pMemory +) +{ + // + // Assume that this is allocated using the Alloc() function. + // + DBG_ASSERT(NULL != pMemory); + + // + // Use a signature to check against double deletions. + // + FREE_LIST_HEADER* pfl = (FREE_LIST_HEADER*) pMemory; + DBG_ASSERT(pfl->dwSignature != FREE_LIST_HEADER::FREE_SIGNATURE); + + // + // Start filling the space beyond the portion overlaid by the initial + // FREE_LIST_HEADER. Fill at most 6 DWORDS. + // + LONG* pl = (LONG*) (pfl+1); + + for (LONG cb = (LONG)min(6 * sizeof(LONG),m_cbSize) - sizeof(FREE_LIST_HEADER); + cb > 0; + cb -= sizeof(LONG)) + { + *pl++ = m_nFillPattern; + } + + // + // Now, set the signature. + // + pfl->dwSignature = FREE_LIST_HEADER::FREE_SIGNATURE; + + // + // Store the items in the alloc cache. + // + SLIST_HEADER * pListHeader = m_pFreeLists ->GetLocal(); + + if ( QueryDepthSList(pListHeader) >= m_nThreshold ) + { + // + // Threshold for free entries is exceeded. Free the object to + // process pool. + // + ::HeapFree( sm_hHeap, 0, pMemory ); + } + else + { + // + // Store the given pointer in the single linear list + // + InterlockedPushEntrySList(pListHeader, &pfl->ListEntry); + } +} + +DWORD +ALLOC_CACHE_HANDLER::QueryDepthForAllSLists( + VOID +) +/*++ + +Description: + + Aggregates the total count of elements in all lists. + +Arguments: + + None. + +Return Value: + + Total count (snapshot). + +--*/ +{ + DWORD Count = 0; + + if (m_pFreeLists != NULL) + { +#if defined(_MSC_VER) && _MSC_VER >= 1600 // VC10 + auto Predicate = [&Count] (SLIST_HEADER * pListHeader) + { + Count += QueryDepthSList(pListHeader); + }; +#else + class Functor + { + public: + explicit Functor(DWORD& Count) : _Count(Count) + { + } + void operator()(SLIST_HEADER * pListHeader) + { + _Count += QueryDepthSList(pListHeader); + } + private: + DWORD& _Count; + } Predicate(Count); +#endif + // + // [&Count] means that the method can modify local variable Count. + // + m_pFreeLists ->ForEach(Predicate); + } + + return Count; +} + +// static +BOOL +ALLOC_CACHE_HANDLER::IsPageheapEnabled( + VOID +) +{ + BOOL fRet = FALSE; + BOOL fLockedHeap = FALSE; + HMODULE hModule = NULL; + HANDLE hHeap = NULL; + PROCESS_HEAP_ENTRY heapEntry = {0}; + + // + // If verifier.dll is loaded - we are running under app verifier == pageheap is enabled + // + hModule = GetModuleHandle( L"verifier.dll" ); + if ( hModule != NULL ) + { + hModule = NULL; + fRet = TRUE; + goto Finished; + } + + // + // Create a heap for calling heapwalk + // otherwise HeapWalk turns off lookasides for a useful heap + // + hHeap = ::HeapCreate( 0, 0, 0 ); + if ( hHeap == NULL ) + { + fRet = FALSE; + goto Finished; + } + + fRet = ::HeapLock( hHeap ); + if ( !fRet ) + { + goto Finished; + } + fLockedHeap = TRUE; + + // + // If HeapWalk is unsupported -> then running page heap + // + fRet = ::HeapWalk( hHeap, &heapEntry ); + if ( !fRet ) + { + if ( GetLastError() == ERROR_INVALID_FUNCTION ) + { + fRet = TRUE; + goto Finished; + } + } + + fRet = FALSE; + +Finished: + + if ( fLockedHeap ) + { + fLockedHeap = FALSE; + DBG_REQUIRE( ::HeapUnlock( hHeap ) ); + } + + if ( hHeap ) + { + DBG_REQUIRE( ::HeapDestroy( hHeap ) ); + hHeap = NULL; + } + + return fRet; +} \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/ahutil.cpp b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/ahutil.cpp new file mode 100644 index 0000000000..9685b233c8 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/ahutil.cpp @@ -0,0 +1,1734 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#include "precomp.h" + +HRESULT +SetElementProperty( + IN IAppHostElement * pElement, + IN CONST WCHAR * szPropName, + IN CONST VARIANT * varPropValue + ) +{ + HRESULT hr = NOERROR; + + CComPtr pPropElement; + + BSTR bstrPropName = SysAllocString( szPropName ); + + if( !bstrPropName ) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR( hr ); + goto exit; + } + + hr = pElement->GetPropertyByName( bstrPropName, + &pPropElement ); + if( FAILED(hr) ) + { + DBGERROR_HR( hr ); + goto exit; + } + + hr = pPropElement->put_Value( *varPropValue ); + if( FAILED(hr) ) + { + DBGERROR_HR( hr ); + goto exit; + } + +exit: + + if( bstrPropName ) + { + SysFreeString( bstrPropName ); + bstrPropName = NULL; + } + + return hr; +} + +HRESULT +SetElementStringProperty( + IN IAppHostElement * pElement, + IN CONST WCHAR * szPropName, + IN CONST WCHAR * szPropValue + ) +{ + HRESULT hr; + VARIANT varPropValue; + VariantInit(&varPropValue); + + hr = VariantAssign(&varPropValue, szPropValue); + + if (FAILED(hr)) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = SetElementProperty(pElement, szPropName, &varPropValue); + + if (FAILED(hr)) + { + DBGERROR_HR(hr); + goto exit; + } + +exit: + + VariantClear(&varPropValue); + return hr; +} + +HRESULT +GetElementStringProperty( + IN IAppHostElement * pElement, + IN CONST WCHAR * szPropName, + OUT BSTR * pbstrPropValue + ) +{ + HRESULT hr = S_OK; + BSTR bstrPropName = SysAllocString( szPropName ); + IAppHostProperty* pProperty = NULL; + + *pbstrPropValue = NULL; + + if (!bstrPropName) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR( hr ); + goto exit; + } + + hr = pElement->GetPropertyByName( bstrPropName, &pProperty ); + if (FAILED(hr)) + { + DBGERROR_HR( hr ); + goto exit; + } + + hr = pProperty->get_StringValue( pbstrPropValue ); + if (FAILED(hr)) + { + DBGERROR_HR( hr ); + goto exit; + } + +exit: + + if (pProperty) + { + pProperty->Release(); + } + + if (bstrPropName) + { + SysFreeString( bstrPropName ); + } + + return hr; +} + + +HRESULT +GetElementStringProperty( + IN IAppHostElement * pElement, + IN CONST WCHAR * szPropName, + OUT STRU * pstrPropValue + ) +{ + HRESULT hr = S_OK; + BSTR bstrPropName = SysAllocString( szPropName ); + IAppHostProperty* pProperty = NULL; + BSTR bstrPropValue = NULL; + + if (!bstrPropName) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR( hr ); + goto exit; + } + + hr = pElement->GetPropertyByName( bstrPropName, &pProperty ); + if (FAILED(hr)) + { + DBGERROR_HR( hr ); + goto exit; + } + + hr = pProperty->get_StringValue( &bstrPropValue ); + if (FAILED(hr)) + { + DBGERROR_HR( hr ); + goto exit; + } + + hr = pstrPropValue->Copy(bstrPropValue); + if (FAILED(hr)) + { + DBGERROR_HR( hr ); + goto exit; + } + +exit: + + if (pProperty) + { + pProperty->Release(); + } + + if (bstrPropValue) + { + SysFreeString( bstrPropValue ); + } + + if (bstrPropName) + { + SysFreeString( bstrPropName ); + } + + return hr; +} + +HRESULT +GetElementChildByName( + IN IAppHostElement * pElement, + IN LPCWSTR pszElementName, + OUT IAppHostElement ** ppChildElement +) +{ + BSTR bstrElementName = SysAllocString(pszElementName); + if (bstrElementName == NULL) + { + return E_OUTOFMEMORY; + } + HRESULT hr = pElement->GetElementByName(bstrElementName, + ppChildElement); + SysFreeString(bstrElementName); + return hr; +} + +HRESULT +GetElementBoolProperty( + IN IAppHostElement * pElement, + IN LPCWSTR pszPropertyName, + OUT bool * pBool +) +{ + BOOL fValue; + HRESULT hr = GetElementBoolProperty(pElement, + pszPropertyName, + &fValue); + if (SUCCEEDED(hr)) + { + *pBool = !!fValue; + } + return hr; +} + +HRESULT +GetElementBoolProperty( + IN IAppHostElement * pElement, + IN LPCWSTR pszPropertyName, + OUT BOOL * pBool +) +{ + HRESULT hr = S_OK; + BSTR bstrPropertyName = NULL; + IAppHostProperty * pProperty = NULL; + VARIANT varValue; + + VariantInit( &varValue ); + + bstrPropertyName = SysAllocString( pszPropertyName ); + if ( bstrPropertyName == NULL ) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR(hr); + goto exit; + } + + // Now ask for the property and if it succeeds it is returned directly back. + hr = pElement->GetPropertyByName( bstrPropertyName, &pProperty ); + if ( FAILED ( hr ) ) + { + goto exit; + } + + // Now let's get the property and then extract it from the Variant. + hr = pProperty->get_Value( &varValue ); + if ( FAILED ( hr ) ) + { + goto exit; + } + + hr = VariantChangeType( &varValue, &varValue, 0, VT_BOOL ); + if ( FAILED ( hr ) ) + { + goto exit; + } + + // extract the value + *pBool = ( V_BOOL( &varValue ) == VARIANT_TRUE ); + +exit: + + VariantClear( &varValue ); + + if ( bstrPropertyName != NULL ) + { + SysFreeString( bstrPropertyName ); + bstrPropertyName = NULL; + } + + if ( pProperty != NULL ) + { + pProperty->Release(); + pProperty = NULL; + } + + return hr; + +} + +HRESULT +GetElementDWORDProperty( + IN IAppHostElement * pSitesCollectionEntry, + IN LPCWSTR pwszName, + OUT DWORD * pdwValue +) +{ + HRESULT hr = S_OK; + IAppHostProperty * pProperty = NULL; + BSTR bstrName = NULL; + VARIANT varValue; + + VariantInit( &varValue ); + + bstrName = SysAllocString( pwszName ); + if ( bstrName == NULL ) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR(hr); + goto error; + } + + hr = pSitesCollectionEntry->GetPropertyByName( bstrName, + &pProperty ); + if ( FAILED ( hr ) ) + { + goto error; + } + + hr = pProperty->get_Value( &varValue ); + if ( FAILED ( hr ) ) + { + goto error; + } + + hr = VariantChangeType( &varValue, &varValue, 0, VT_UI4 ); + if ( FAILED ( hr ) ) + { + goto error; + } + + // extract the value + *pdwValue = varValue.ulVal; + +error: + + VariantClear( &varValue ); + + if ( pProperty != NULL ) + { + pProperty->Release(); + pProperty = NULL; + } + + if ( bstrName != NULL ) + { + SysFreeString( bstrName ); + bstrName = NULL; + } + + return hr; +} + +HRESULT +GetElementINTProperty( + IN IAppHostElement * pElement, + IN LPCWSTR pszPropertyName, + OUT INT * pintValue +) +{ + HRESULT hr = S_OK; + IAppHostProperty * pProperty = NULL; + BSTR bstrName = NULL; + VARIANT varValue; + + VariantInit( &varValue ); + + bstrName = SysAllocString( pszPropertyName ); + if ( bstrName == NULL ) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR( hr ); + goto error; + } + + hr = pElement->GetPropertyByName( bstrName, + &pProperty ); + if ( FAILED( hr ) ) + { + goto error; + } + + hr = pProperty->get_Value( &varValue ); + if ( FAILED( hr ) ) + { + goto error; + } + + hr = VariantChangeType( &varValue, &varValue, 0, VT_I4 ); + if ( FAILED( hr ) ) + { + goto error; + } + + // extract the value + *pintValue = varValue.intVal; + +error: + + VariantClear( &varValue ); + + if ( pProperty != NULL ) + { + pProperty->Release(); + pProperty = NULL; + } + + if ( bstrName != NULL ) + { + SysFreeString( bstrName ); + bstrName = NULL; + } + + return hr; +} + +HRESULT +GetElementLONGLONGProperty( + IN IAppHostElement * pSitesCollectionEntry, + IN LPCWSTR pwszName, + OUT LONGLONG * pllValue +) +{ + HRESULT hr = S_OK; + IAppHostProperty * pProperty = NULL; + BSTR bstrName = NULL; + VARIANT varValue; + + VariantInit( &varValue ); + + bstrName = SysAllocString( pwszName ); + if ( bstrName == NULL ) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR(hr); + goto error; + } + + hr = pSitesCollectionEntry->GetPropertyByName( bstrName, + &pProperty ); + if ( FAILED ( hr ) ) + { + goto error; + } + + hr = pProperty->get_Value( &varValue ); + if ( FAILED ( hr ) ) + { + goto error; + } + + hr = VariantChangeType( &varValue, &varValue, 0, VT_I8 ); + if ( FAILED ( hr ) ) + { + goto error; + } + + // extract the value + *pllValue = varValue.ulVal; + +error: + + VariantClear( &varValue ); + + if ( pProperty != NULL ) + { + pProperty->Release(); + pProperty = NULL; + } + + if ( bstrName != NULL ) + { + SysFreeString( bstrName ); + bstrName = NULL; + } + + return hr; +} + +HRESULT +GetElementRawTimeSpanProperty( + IN IAppHostElement * pElement, + IN LPCWSTR pszPropertyName, + OUT ULONGLONG * pulonglong +) +{ + HRESULT hr = S_OK; + BSTR bstrPropertyName = NULL; + IAppHostProperty * pProperty = NULL; + VARIANT varValue; + + VariantInit( &varValue ); + + bstrPropertyName = SysAllocString( pszPropertyName ); + if ( bstrPropertyName == NULL ) + { + hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY ); + goto Finished; + } + + // Now ask for the property and if it succeeds it is returned directly back + hr = pElement->GetPropertyByName( bstrPropertyName, &pProperty ); + if ( FAILED ( hr ) ) + { + goto Finished; + } + + // Now let's get the property and then extract it from the Variant. + hr = pProperty->get_Value( &varValue ); + if ( FAILED ( hr ) ) + { + goto Finished; + } + + hr = VariantChangeType( &varValue, &varValue, 0, VT_UI8 ); + if ( FAILED ( hr ) ) + { + goto Finished; + } + + // extract the value + *pulonglong = varValue.ullVal; + + +Finished: + + VariantClear( &varValue ); + + if ( bstrPropertyName != NULL ) + { + SysFreeString( bstrPropertyName ); + bstrPropertyName = NULL; + } + + if ( pProperty != NULL ) + { + pProperty->Release(); + pProperty = NULL; + } + + return hr; + +} // end of Config_GetRawTimeSpanProperty + +HRESULT +DeleteElementFromCollection( + IAppHostElementCollection *pCollection, + CONST WCHAR * szKeyName, + CONST WCHAR * szKeyValue, + ULONG BehaviorFlags, + BOOL * pfDeleted + ) +{ + HRESULT hr = NOERROR; + ULONG index; + + VARIANT varIndex; + VariantInit( &varIndex ); + + *pfDeleted = FALSE; + + hr = FindElementInCollection( + pCollection, + szKeyName, + szKeyValue, + BehaviorFlags, + &index + ); + + if (FAILED(hr)) + { + DBGERROR_HR(hr); + goto exit; + } + + if (hr == S_FALSE) + { + // + // Not found. + // + + goto exit; + } + + varIndex.vt = VT_UI4; + varIndex.ulVal = index; + + hr = pCollection->DeleteElement( varIndex ); + + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + *pfDeleted = TRUE; + +exit: + + return hr; +} + +HRESULT +DeleteAllElementsFromCollection( + IAppHostElementCollection *pCollection, + CONST WCHAR * szKeyName, + CONST WCHAR * szKeyValue, + ULONG BehaviorFlags, + UINT * pNumDeleted + ) +{ + HRESULT hr = S_OK; + UINT numDeleted = 0; + BOOL fDeleted = TRUE; + + while (fDeleted) + { + hr = DeleteElementFromCollection( + pCollection, + szKeyName, + szKeyValue, + BehaviorFlags, + &fDeleted + ); + + if (hr == S_FALSE) + { + hr = S_OK; + break; + } + + if (FAILED(hr)) + { + DBGERROR_HR(hr); + break; + } + + if (fDeleted) + { + numDeleted++; + } + } + + *pNumDeleted = numDeleted; + return hr; +} + +BOOL +FindCompareCaseSensitive( + CONST WCHAR * szLookupValue, + CONST WCHAR * szKeyValue + ) +{ + return !wcscmp(szLookupValue, szKeyValue); +} + +BOOL +FindCompareCaseInsensitive( + CONST WCHAR * szLookupValue, + CONST WCHAR * szKeyValue + ) +{ + return !_wcsicmp(szLookupValue, szKeyValue); +} + +typedef +BOOL +(*PFN_FIND_COMPARE_PROC)( + CONST WCHAR *szLookupValue, + CONST WCHAR *szKeyValue + ); + +HRESULT +FindElementInCollection( + IAppHostElementCollection *pCollection, + CONST WCHAR * szKeyName, + CONST WCHAR * szKeyValue, + ULONG BehaviorFlags, + OUT ULONG * pIndex + ) +{ + HRESULT hr = NOERROR; + + CComPtr pElement; + CComPtr pKeyProperty; + + VARIANT varIndex; + VariantInit( &varIndex ); + + VARIANT varKeyValue; + VariantInit( &varKeyValue ); + + DWORD count; + DWORD i; + + BSTR bstrKeyName = NULL; + PFN_FIND_COMPARE_PROC compareProc; + + compareProc = (BehaviorFlags & FIND_ELEMENT_CASE_INSENSITIVE) + ? &FindCompareCaseInsensitive + : &FindCompareCaseSensitive; + + bstrKeyName = SysAllocString( szKeyName ); + if( !bstrKeyName ) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR(hr); + goto exit; + } + + hr = pCollection->get_Count( &count ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + for( i = 0; i < count; i++ ) + { + varIndex.vt = VT_UI4; + varIndex.ulVal = i; + + hr = pCollection->get_Item( varIndex, + &pElement ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto tryNext; + } + + hr = pElement->GetPropertyByName( bstrKeyName, + &pKeyProperty ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto tryNext; + } + + hr = pKeyProperty->get_Value( &varKeyValue ); + + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto tryNext; + } + + if ((compareProc)(szKeyValue, varKeyValue.bstrVal)) + { + *pIndex = i; + break; + } + +tryNext: + + pElement.Release(); + pKeyProperty.Release(); + + VariantClear( &varKeyValue ); + } + + if (i >= count) + { + hr = S_FALSE; + } + +exit: + + SysFreeString( bstrKeyName ); + VariantClear( &varKeyValue ); + + return hr; +} + +HRESULT +VariantAssign( + IN OUT VARIANT * pv, + IN CONST WCHAR * sz + ) +{ + if( !pv || !sz ) + { + return E_INVALIDARG; + } + + HRESULT hr = NOERROR; + + BSTR bstr = SysAllocString( sz ); + if( !bstr ) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR( hr ); + goto exit; + } + + hr = VariantClear( pv ); + if( FAILED(hr) ) + { + DBGERROR_HR( hr ); + goto exit; + } + + pv->vt = VT_BSTR; + pv->bstrVal = bstr; + bstr = NULL; + +exit: + + SysFreeString( bstr ); + + return hr; +} + +HRESULT +GetLocationFromFile( + IN IAppHostAdminManager * pAdminMgr, + IN CONST WCHAR * szConfigPath, + IN CONST WCHAR * szLocationPath, + OUT IAppHostConfigLocation ** ppLocation, + OUT BOOL * pFound + ) +{ + HRESULT hr = NOERROR; + + CComPtr pLocationCollection; + CComPtr pLocation; + + BSTR bstrLocationPath = NULL; + + *ppLocation = NULL; + *pFound = FALSE; + + hr = GetLocationCollection( pAdminMgr, + szConfigPath, + &pLocationCollection ); + + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + DWORD count; + DWORD i; + VARIANT varIndex; + VariantInit( &varIndex ); + + hr = pLocationCollection->get_Count( &count ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + for( i = 0; i < count; i++ ) + { + varIndex.vt = VT_UI4; + varIndex.ulVal = i; + + hr = pLocationCollection->get_Item( varIndex, + &pLocation ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pLocation->get_Path( &bstrLocationPath ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + if( 0 == wcscmp ( szLocationPath, bstrLocationPath ) ) + { + *pFound = TRUE; + *ppLocation = pLocation.Detach(); + break; + } + + + pLocation.Release(); + + SysFreeString( bstrLocationPath ); + bstrLocationPath = NULL; + } + +exit: + + SysFreeString( bstrLocationPath ); + + return hr; +} + +HRESULT +GetSectionFromLocation( + IN IAppHostConfigLocation * pLocation, + IN CONST WCHAR * szSectionName, + OUT IAppHostElement ** ppSectionElement, + OUT BOOL * pFound + ) +{ + HRESULT hr = NOERROR; + + CComPtr pSectionElement; + + DWORD count; + DWORD i; + + VARIANT varIndex; + VariantInit( &varIndex ); + + BSTR bstrSectionName = NULL; + + *pFound = FALSE; + *ppSectionElement = NULL; + + hr = pLocation->get_Count( &count ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + for( i = 0; i < count; i++ ) + { + varIndex.vt = VT_UI4; + varIndex.ulVal = i; + + + hr = pLocation->get_Item( varIndex, + &pSectionElement ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pSectionElement->get_Name( &bstrSectionName ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + if( 0 == wcscmp ( szSectionName, bstrSectionName ) ) + { + *pFound = TRUE; + *ppSectionElement = pSectionElement.Detach(); + break; + } + + pSectionElement.Release(); + + SysFreeString( bstrSectionName ); + bstrSectionName = NULL; + } + +exit: + + SysFreeString( bstrSectionName ); + + return hr; +} + + +HRESULT +GetAdminElement( + IN IAppHostAdminManager * pAdminMgr, + IN CONST WCHAR * szConfigPath, + IN CONST WCHAR * szElementName, + OUT IAppHostElement ** pElement +) +{ + HRESULT hr = S_OK; + BSTR bstrConfigPath = NULL; + BSTR bstrElementName = NULL; + + bstrConfigPath = SysAllocString(szConfigPath); + bstrElementName = SysAllocString(szElementName); + + if (bstrConfigPath == NULL || bstrElementName == NULL) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR(hr); + goto exit; + } + + hr = pAdminMgr->GetAdminSection( bstrElementName, + bstrConfigPath, + pElement ); + + if (FAILED(hr)) + { + DBGERROR_HR(hr); + goto exit; + } + +exit: + + if ( bstrElementName != NULL ) + { + SysFreeString(bstrElementName); + bstrElementName = NULL; + } + if ( bstrConfigPath != NULL ) + { + SysFreeString(bstrConfigPath); + bstrConfigPath = NULL; + } + + return hr; +} + + +HRESULT +ClearAdminElement( + IN IAppHostAdminManager * pAdminMgr, + IN CONST WCHAR * szConfigPath, + IN CONST WCHAR * szElementName + ) +{ + HRESULT hr; + CComPtr pElement; + + hr = GetAdminElement( + pAdminMgr, + szConfigPath, + szElementName, + &pElement + ); + + if (FAILED(hr)) + { + if (hr == HRESULT_FROM_WIN32(ERROR_NOT_FOUND)) + { + hr = S_OK; + } + else + { + DBGERROR_HR(hr); + } + + goto exit; + } + + hr = pElement->Clear(); + + if (FAILED(hr)) + { + DBGERROR_HR(hr); + goto exit; + } + +exit: + + return hr; +} + + +HRESULT +ClearElementFromAllSites( + IN IAppHostAdminManager * pAdminMgr, + IN CONST WCHAR * szConfigPath, + IN CONST WCHAR * szElementName + ) +{ + HRESULT hr; + CComPtr pSitesCollection; + CComPtr pSiteElement; + CComPtr pChildCollection; + ENUM_INDEX index; + BOOL found; + + // + // Enumerate the sites, remove the specified elements. + // + + hr = GetSitesCollection( + pAdminMgr, + szConfigPath, + &pSitesCollection + ); + + if (FAILED(hr)) + { + DBGERROR_HR(hr); + goto exit; + } + + for (hr = FindFirstElement(pSitesCollection, &index, &pSiteElement) ; + SUCCEEDED(hr) ; + hr = FindNextElement(pSitesCollection, &index, &pSiteElement)) + { + if (hr == S_FALSE) + { + hr = S_OK; + break; + } + + hr = pSiteElement->get_ChildElements(&pChildCollection); + + if (FAILED(hr)) + { + DBGERROR_HR(hr); + goto exit; + } + + if (pChildCollection) + { + hr = ClearChildElementsByName( + pChildCollection, + szElementName, + &found + ); + + if (FAILED(hr)) + { + DBGERROR_HR(hr); + goto exit; + } + } + + pSiteElement.Release(); + } + +exit: + + return hr; + +} + + +HRESULT +ClearElementFromAllLocations( + IN IAppHostAdminManager * pAdminMgr, + IN CONST WCHAR * szConfigPath, + IN CONST WCHAR * szElementName + ) +{ + HRESULT hr; + CComPtr pLocationCollection; + CComPtr pLocation; + CComPtr pChildCollection; + ENUM_INDEX index; + + // + // Enum the tags, remove the specified elements. + // + + hr = GetLocationCollection( + pAdminMgr, + szConfigPath, + &pLocationCollection + ); + + if (FAILED(hr)) + { + DBGERROR_HR(hr); + goto exit; + } + + for (hr = FindFirstLocation(pLocationCollection, &index, &pLocation) ; + SUCCEEDED(hr) ; + hr = FindNextLocation(pLocationCollection, &index, &pLocation)) + { + if (hr == S_FALSE) + { + hr = S_OK; + break; + } + + hr = ClearLocationElements(pLocation, szElementName); + + if (FAILED(hr)) + { + DBGERROR_HR(hr); + goto exit; + } + + pLocation.Release(); + } + +exit: + + return hr; + +} + +HRESULT +ClearLocationElements( + IN IAppHostConfigLocation * pLocation, + IN CONST WCHAR * szElementName + ) +{ + HRESULT hr; + CComPtr pElement; + ENUM_INDEX index; + BOOL matched; + + for (hr = FindFirstLocationElement(pLocation, &index, &pElement) ; + SUCCEEDED(hr) ; + hr = FindNextLocationElement(pLocation, &index, &pElement)) + { + if (hr == S_FALSE) + { + hr = S_OK; + break; + } + + hr = CompareElementName(pElement, szElementName, &matched); + + if (FAILED(hr)) + { + DBGERROR_HR(hr); + goto exit; + } + + if (matched) + { + pElement->Clear(); + } + + pElement.Release(); + } + +exit: + + return hr; +} + +HRESULT +CompareElementName( + IN IAppHostElement * pElement, + IN CONST WCHAR * szNameToMatch, + OUT BOOL * pMatched + ) +{ + HRESULT hr; + BSTR bstrElementName = NULL; + + *pMatched = FALSE; // until proven otherwise + + hr = pElement->get_Name(&bstrElementName); + + if (FAILED(hr)) + { + DBGERROR_HR(hr); + goto exit; + } + + if( 0 == wcscmp ( szNameToMatch, bstrElementName ) ) + { + *pMatched = TRUE; + } + +exit: + + SysFreeString(bstrElementName); + return hr; +} + + +HRESULT +ClearChildElementsByName( + IN IAppHostChildElementCollection * pCollection, + IN CONST WCHAR * szElementName, + OUT BOOL * pFound + ) +{ + HRESULT hr; + CComPtr pElement; + ENUM_INDEX index; + BOOL matched; + + *pFound = FALSE; + + for (hr = FindFirstChildElement(pCollection, &index, &pElement) ; + SUCCEEDED(hr) ; + hr = FindNextChildElement(pCollection, &index, &pElement)) + { + if (hr == S_FALSE) + { + hr = S_OK; + break; + } + + hr = CompareElementName(pElement, szElementName, &matched); + + if (FAILED(hr)) + { + DBGERROR_HR(hr); + goto exit; + } + + if (matched) + { + hr = pElement->Clear(); + + if (FAILED(hr)) + { + DBGERROR_HR(hr); + goto exit; + } + + *pFound = TRUE; + } + + pElement.Release(); + } + +exit: + + return hr; +} + + +HRESULT +GetSitesCollection( + IN IAppHostAdminManager * pAdminMgr, + IN CONST WCHAR * szConfigPath, + OUT IAppHostElementCollection ** pSitesCollection + ) +{ + HRESULT hr; + CComPtr pSitesElement; + BSTR bstrConfigPath; + BSTR bstrSitesSectionName; + + bstrConfigPath = SysAllocString(szConfigPath); + bstrSitesSectionName = SysAllocString(L"system.applicationHost/sites"); + *pSitesCollection = NULL; + + if (bstrConfigPath == NULL || bstrSitesSectionName == NULL) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR(hr); + goto exit; + } + + // + // Chase down the sites collection. + // + + hr = pAdminMgr->GetAdminSection( bstrSitesSectionName, + bstrConfigPath, + &pSitesElement ); + + if (FAILED(hr)) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pSitesElement->get_Collection(pSitesCollection); + + if (FAILED(hr)) + { + DBGERROR_HR(hr); + goto exit; + } + +exit: + + SysFreeString(bstrSitesSectionName); + SysFreeString(bstrConfigPath); + return hr; +} + + +HRESULT +GetLocationCollection( + IN IAppHostAdminManager * pAdminMgr, + IN CONST WCHAR * szConfigPath, + OUT IAppHostConfigLocationCollection ** pLocationCollection + ) +{ + HRESULT hr; + BSTR bstrConfigPath; + CComPtr pConfigMgr; + CComPtr pConfigFile; + + bstrConfigPath = SysAllocString(szConfigPath); + *pLocationCollection = NULL; + + if (bstrConfigPath == NULL) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR(hr); + goto exit; + } + + hr = pAdminMgr->get_ConfigManager(&pConfigMgr); + + if (FAILED(hr)) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pConfigMgr->GetConfigFile(bstrConfigPath, &pConfigFile); + + if (FAILED(hr)) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pConfigFile->get_Locations(pLocationCollection); + + if (FAILED(hr)) + { + DBGERROR_HR(hr); + goto exit; + } + +exit: + + SysFreeString(bstrConfigPath); + return hr; +} + + +HRESULT +FindFirstElement( + IN IAppHostElementCollection * pCollection, + OUT ENUM_INDEX * pIndex, + OUT IAppHostElement ** pElement + ) +{ + HRESULT hr; + + hr = pCollection->get_Count(&pIndex->Count); + + if (FAILED(hr)) + { + DBGERROR_HR(hr); + return hr; + } + + VariantInit(&pIndex->Index); + pIndex->Index.vt = VT_UI4; + pIndex->Index.ulVal = 0; + + return FindNextElement(pCollection, pIndex, pElement); +} + +HRESULT +FindNextElement( + IN IAppHostElementCollection * pCollection, + IN OUT ENUM_INDEX * pIndex, + OUT IAppHostElement ** pElement + ) +{ + HRESULT hr; + + *pElement = NULL; + + if (pIndex->Index.ulVal >= pIndex->Count) + { + return S_FALSE; + } + + hr = pCollection->get_Item(pIndex->Index, pElement); + + if (SUCCEEDED(hr)) + { + pIndex->Index.ulVal++; + } + + return hr; +} + +HRESULT +FindFirstChildElement( + IN IAppHostChildElementCollection * pCollection, + OUT ENUM_INDEX * pIndex, + OUT IAppHostElement ** pElement + ) +{ + HRESULT hr; + + hr = pCollection->get_Count(&pIndex->Count); + + if (FAILED(hr)) + { + DBGERROR_HR(hr); + return hr; + } + + VariantInit(&pIndex->Index); + pIndex->Index.vt = VT_UI4; + pIndex->Index.ulVal = 0; + + return FindNextChildElement(pCollection, pIndex, pElement); +} + +HRESULT +FindNextChildElement( + IN IAppHostChildElementCollection * pCollection, + IN OUT ENUM_INDEX * pIndex, + OUT IAppHostElement ** pElement + ) +{ + HRESULT hr; + + *pElement = NULL; + + if (pIndex->Index.ulVal >= pIndex->Count) + { + return S_FALSE; + } + + hr = pCollection->get_Item(pIndex->Index, pElement); + + if (SUCCEEDED(hr)) + { + pIndex->Index.ulVal++; + } + + return hr; +} + +HRESULT +FindFirstLocation( + IN IAppHostConfigLocationCollection * pCollection, + OUT ENUM_INDEX * pIndex, + OUT IAppHostConfigLocation ** pLocation + ) +{ + HRESULT hr; + + hr = pCollection->get_Count(&pIndex->Count); + + if (FAILED(hr)) + { + DBGERROR_HR(hr); + return hr; + } + + VariantInit(&pIndex->Index); + pIndex->Index.vt = VT_UI4; + pIndex->Index.ulVal = 0; + + return FindNextLocation(pCollection, pIndex, pLocation); +} + +HRESULT +FindNextLocation( + IN IAppHostConfigLocationCollection * pCollection, + IN OUT ENUM_INDEX * pIndex, + OUT IAppHostConfigLocation ** pLocation + ) +{ + HRESULT hr; + + *pLocation = NULL; + + if (pIndex->Index.ulVal >= pIndex->Count) + { + return S_FALSE; + } + + hr = pCollection->get_Item(pIndex->Index, pLocation); + + if (SUCCEEDED(hr)) + { + pIndex->Index.ulVal++; + } + + return hr; +} + +HRESULT +FindFirstLocationElement( + IN IAppHostConfigLocation * pLocation, + OUT ENUM_INDEX * pIndex, + OUT IAppHostElement ** pElement + ) +{ + HRESULT hr; + + hr = pLocation->get_Count(&pIndex->Count); + + if (FAILED(hr)) + { + DBGERROR_HR(hr); + return hr; + } + + VariantInit(&pIndex->Index); + pIndex->Index.vt = VT_UI4; + pIndex->Index.ulVal = 0; + + return FindNextLocationElement(pLocation, pIndex, pElement); +} + +HRESULT +FindNextLocationElement( + IN IAppHostConfigLocation * pLocation, + IN OUT ENUM_INDEX * pIndex, + OUT IAppHostElement ** pElement + ) +{ + HRESULT hr; + + *pElement = NULL; + + if (pIndex->Index.ulVal >= pIndex->Count) + { + return S_FALSE; + } + + hr = pLocation->get_Item(pIndex->Index, pElement); + + if (SUCCEEDED(hr)) + { + pIndex->Index.ulVal++; + } + + return hr; +} + +HRESULT +GetSharedConfigEnabled( + BOOL * pfIsSharedConfig +) +/*++ + +Routine Description: + Search the configuration for the shared configuration property. + +Arguments: + + pfIsSharedConfig - true if shared configuration is enabled + +Return Value: + HRESULT + +--*/ +{ + HRESULT hr = S_OK; + IAppHostAdminManager *pAdminManager = NULL; + + BSTR bstrSectionName = NULL; + BSTR bstrConfigPath = NULL; + + IAppHostElement * pConfigRedirSection = NULL; + + + bstrSectionName = SysAllocString( L"configurationRedirection" ); + + if ( bstrSectionName == NULL ) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR(hr); + goto exit; + } + + bstrConfigPath = SysAllocString( L"MACHINE/REDIRECTION" ); + if ( bstrConfigPath == NULL ) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR(hr); + goto exit; + } + + hr = CoCreateInstance( CLSID_AppHostAdminManager, + NULL, + CLSCTX_INPROC_SERVER, + IID_IAppHostAdminManager, + (VOID **)&pAdminManager ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pAdminManager->GetAdminSection( bstrSectionName, + bstrConfigPath, + &pConfigRedirSection ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = GetElementBoolProperty( pConfigRedirSection, + L"enabled", + pfIsSharedConfig ); + + if ( FAILED( hr ) ) + { + DBGERROR_HR(hr); + goto exit; + } + + pConfigRedirSection->Release(); + pConfigRedirSection = NULL; + + +exit: + + // + // dump config exception to setup log file (if available) + // + + if ( pConfigRedirSection != NULL ) + { + pConfigRedirSection->Release(); + } + + if ( pAdminManager != NULL ) + { + pAdminManager->Release(); + } + + if ( bstrConfigPath != NULL ) + { + SysFreeString( bstrConfigPath ); + } + + if ( bstrSectionName != NULL ) + { + SysFreeString( bstrSectionName ); + } + + return hr; +} diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/base64.cxx b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/base64.cxx new file mode 100644 index 0000000000..26e601fac4 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/base64.cxx @@ -0,0 +1,482 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#include "precomp.h" + +DWORD +Base64Encode( + __in_bcount(cbDecodedBufferSize) VOID * pDecodedBuffer, + IN DWORD cbDecodedBufferSize, + __out_ecount_opt(cchEncodedStringSize) PWSTR pszEncodedString, + IN DWORD cchEncodedStringSize, + __out_opt DWORD * pcchEncoded + ) +/*++ + +Routine Description: + + Decode a base64-encoded string. + +Arguments: + + pDecodedBuffer (IN) - buffer to encode. + cbDecodedBufferSize (IN) - size of buffer to encode. + cchEncodedStringSize (IN) - size of the buffer for the encoded string. + pszEncodedString (OUT) = the encoded string. + pcchEncoded (OUT) - size in characters of the encoded string. + +Return Values: + + 0 - success. + E_OUTOFMEMORY + +--*/ +{ + static WCHAR rgchEncodeTable[64] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' + }; + + DWORD ib; + DWORD ich; + DWORD cchEncoded; + BYTE b0, b1, b2; + BYTE * pbDecodedBuffer = (BYTE *) pDecodedBuffer; + + // Calculate encoded string size. + cchEncoded = 1 + (cbDecodedBufferSize + 2) / 3 * 4; + + if (NULL != pcchEncoded) { + *pcchEncoded = cchEncoded; + } + + if (cchEncodedStringSize == 0 && pszEncodedString == NULL) { + return ERROR_SUCCESS; + } + + if (cchEncodedStringSize < cchEncoded) { + // Given buffer is too small to hold encoded string. + return ERROR_INSUFFICIENT_BUFFER; + } + + // Encode data byte triplets into four-byte clusters. + ib = ich = 0; + while (ib < cbDecodedBufferSize) { + b0 = pbDecodedBuffer[ib++]; + b1 = (ib < cbDecodedBufferSize) ? pbDecodedBuffer[ib++] : 0; + b2 = (ib < cbDecodedBufferSize) ? pbDecodedBuffer[ib++] : 0; + + // + // The checks below for buffer overflow seems redundant to me. + // But it's the only way I can find to keep OACR quiet so it + // will have to do. + // + + pszEncodedString[ich++] = rgchEncodeTable[b0 >> 2]; + if ( ich >= cchEncodedStringSize ) + { + DBG_ASSERT( FALSE ); + return ERROR_BUFFER_OVERFLOW; + } + + pszEncodedString[ich++] = rgchEncodeTable[((b0 << 4) & 0x30) | ((b1 >> 4) & 0x0f)]; + if ( ich >= cchEncodedStringSize ) + { + DBG_ASSERT( FALSE ); + return ERROR_BUFFER_OVERFLOW; + } + + pszEncodedString[ich++] = rgchEncodeTable[((b1 << 2) & 0x3c) | ((b2 >> 6) & 0x03)]; + if ( ich >= cchEncodedStringSize ) + { + DBG_ASSERT( FALSE ); + return ERROR_BUFFER_OVERFLOW; + } + + pszEncodedString[ich++] = rgchEncodeTable[b2 & 0x3f]; + if ( ich >= cchEncodedStringSize ) + { + DBG_ASSERT( FALSE ); + return ERROR_BUFFER_OVERFLOW; + } + } + + // Pad the last cluster as necessary to indicate the number of data bytes + // it represents. + switch (cbDecodedBufferSize % 3) { + case 0: + break; + case 1: + pszEncodedString[ich - 2] = '='; + __fallthrough; + case 2: + pszEncodedString[ich - 1] = '='; + break; + } + + // Null-terminate the encoded string. + pszEncodedString[ich++] = '\0'; + + DBG_ASSERT(ich == cchEncoded); + + return ERROR_SUCCESS; +} + + +DWORD +Base64Decode( + __in PCWSTR pszEncodedString, + __out_opt VOID * pDecodeBuffer, + __in DWORD cbDecodeBufferSize, + __out_opt DWORD * pcbDecoded + ) +/*++ + +Routine Description: + + Decode a base64-encoded string. + +Arguments: + + pszEncodedString (IN) - base64-encoded string to decode. + cbDecodeBufferSize (IN) - size in bytes of the decode buffer. + pbDecodeBuffer (OUT) - holds the decoded data. + pcbDecoded (OUT) - number of data bytes in the decoded data (if success or + STATUS_BUFFER_TOO_SMALL). + +Return Values: + + 0 - success. + E_OUTOFMEMORY + E_INVALIDARG + +--*/ +{ +#define NA (255) +#define DECODE(x) (((ULONG)(x) < sizeof(rgbDecodeTable)) ? rgbDecodeTable[x] : NA) + + static BYTE rgbDecodeTable[128] = { + NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, // 0-15 + NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, // 16-31 + NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 62, NA, NA, NA, 63, // 32-47 + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, NA, NA, NA, 0, NA, NA, // 48-63 + NA, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 64-79 + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, NA, NA, NA, NA, NA, // 80-95 + NA, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 96-111 + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, NA, NA, NA, NA, NA, // 112-127 + }; + + DWORD cbDecoded; + DWORD cchEncodedSize; + DWORD ich; + DWORD ib; + BYTE b0, b1, b2, b3; + BYTE * pbDecodeBuffer = (BYTE *) pDecodeBuffer; + + cchEncodedSize = (DWORD)wcslen(pszEncodedString); + if (NULL != pcbDecoded) { + *pcbDecoded = 0; + } + + if ((0 == cchEncodedSize) || (0 != (cchEncodedSize % 4))) { + // Input string is not sized correctly to be base64. + return ERROR_INVALID_PARAMETER; + } + + // Calculate decoded buffer size. + cbDecoded = (cchEncodedSize + 3) / 4 * 3; + if (pszEncodedString[cchEncodedSize-1] == '=') { + if (pszEncodedString[cchEncodedSize-2] == '=') { + // Only one data byte is encoded in the last cluster. + cbDecoded -= 2; + } + else { + // Only two data bytes are encoded in the last cluster. + cbDecoded -= 1; + } + } + + if (NULL != pcbDecoded) { + *pcbDecoded = cbDecoded; + } + + if (cbDecodeBufferSize == 0 && pDecodeBuffer == NULL) { + return ERROR_SUCCESS; + } + + if (cbDecoded > cbDecodeBufferSize) { + // Supplied buffer is too small. + return ERROR_INSUFFICIENT_BUFFER; + } + + // Decode each four-byte cluster into the corresponding three data bytes. + ich = ib = 0; + while (ich < cchEncodedSize) { + b0 = DECODE(pszEncodedString[ich]); ich++; + b1 = DECODE(pszEncodedString[ich]); ich++; + b2 = DECODE(pszEncodedString[ich]); ich++; + b3 = DECODE(pszEncodedString[ich]); ich++; + + if ((NA == b0) || (NA == b1) || (NA == b2) || (NA == b3)) { + // Contents of input string are not base64. + return ERROR_INVALID_PARAMETER; + } + + pbDecodeBuffer[ib++] = (b0 << 2) | (b1 >> 4); + + if (ib < cbDecoded) { + pbDecodeBuffer[ib++] = (b1 << 4) | (b2 >> 2); + + if (ib < cbDecoded) { + pbDecodeBuffer[ib++] = (b2 << 6) | b3; + } + } + } + + DBG_ASSERT(ib == cbDecoded); + + return ERROR_SUCCESS; +} + + +DWORD +Base64Encode( + __in_bcount(cbDecodedBufferSize) VOID * pDecodedBuffer, + IN DWORD cbDecodedBufferSize, + __out_ecount_opt(cchEncodedStringSize) PSTR pszEncodedString, + IN DWORD cchEncodedStringSize, + __out_opt DWORD * pcchEncoded + ) +/*++ + +Routine Description: + + Decode a base64-encoded string. + +Arguments: + + pDecodedBuffer (IN) - buffer to encode. + cbDecodedBufferSize (IN) - size of buffer to encode. + cchEncodedStringSize (IN) - size of the buffer for the encoded string. + pszEncodedString (OUT) = the encoded string. + pcchEncoded (OUT) - size in characters of the encoded string. + +Return Values: + + 0 - success. + E_OUTOFMEMORY + +--*/ +{ + static CHAR rgchEncodeTable[64] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' + }; + + DWORD ib; + DWORD ich; + DWORD cchEncoded; + BYTE b0, b1, b2; + BYTE * pbDecodedBuffer = (BYTE *) pDecodedBuffer; + + // Calculate encoded string size. + cchEncoded = 1 + (cbDecodedBufferSize + 2) / 3 * 4; + + if (NULL != pcchEncoded) { + *pcchEncoded = cchEncoded; + } + + if (cchEncodedStringSize == 0 && pszEncodedString == NULL) { + return ERROR_SUCCESS; + } + + if (cchEncodedStringSize < cchEncoded) { + // Given buffer is too small to hold encoded string. + return ERROR_INSUFFICIENT_BUFFER; + } + + // Encode data byte triplets into four-byte clusters. + ib = ich = 0; + while (ib < cbDecodedBufferSize) { + b0 = pbDecodedBuffer[ib++]; + b1 = (ib < cbDecodedBufferSize) ? pbDecodedBuffer[ib++] : 0; + b2 = (ib < cbDecodedBufferSize) ? pbDecodedBuffer[ib++] : 0; + + // + // The checks below for buffer overflow seems redundant to me. + // But it's the only way I can find to keep OACR quiet so it + // will have to do. + // + + pszEncodedString[ich++] = rgchEncodeTable[b0 >> 2]; + if ( ich >= cchEncodedStringSize ) + { + DBG_ASSERT( FALSE ); + return ERROR_BUFFER_OVERFLOW; + } + + pszEncodedString[ich++] = rgchEncodeTable[((b0 << 4) & 0x30) | ((b1 >> 4) & 0x0f)]; + if ( ich >= cchEncodedStringSize ) + { + DBG_ASSERT( FALSE ); + return ERROR_BUFFER_OVERFLOW; + } + + pszEncodedString[ich++] = rgchEncodeTable[((b1 << 2) & 0x3c) | ((b2 >> 6) & 0x03)]; + if ( ich >= cchEncodedStringSize ) + { + DBG_ASSERT( FALSE ); + return ERROR_BUFFER_OVERFLOW; + } + + pszEncodedString[ich++] = rgchEncodeTable[b2 & 0x3f]; + if ( ich >= cchEncodedStringSize ) + { + DBG_ASSERT( FALSE ); + return ERROR_BUFFER_OVERFLOW; + } + } + + // Pad the last cluster as necessary to indicate the number of data bytes + // it represents. + switch (cbDecodedBufferSize % 3) { + case 0: + break; + case 1: + pszEncodedString[ich - 2] = '='; + __fallthrough; + case 2: + pszEncodedString[ich - 1] = '='; + break; + } + + // Null-terminate the encoded string. + pszEncodedString[ich++] = '\0'; + + DBG_ASSERT(ich == cchEncoded); + + return ERROR_SUCCESS; +} + + +DWORD +Base64Decode( + __in PCSTR pszEncodedString, + __out_opt VOID * pDecodeBuffer, + __in DWORD cbDecodeBufferSize, + __out_opt DWORD * pcbDecoded + ) +/*++ + +Routine Description: + + Decode a base64-encoded string. + +Arguments: + + pszEncodedString (IN) - base64-encoded string to decode. + cbDecodeBufferSize (IN) - size in bytes of the decode buffer. + pbDecodeBuffer (OUT) - holds the decoded data. + pcbDecoded (OUT) - number of data bytes in the decoded data (if success or + STATUS_BUFFER_TOO_SMALL). + +Return Values: + + 0 - success. + E_OUTOFMEMORY + E_INVALIDARG + +--*/ +{ +#define NA (255) +#define DECODE(x) (((ULONG)(x) < sizeof(rgbDecodeTable)) ? rgbDecodeTable[x] : NA) + + static BYTE rgbDecodeTable[128] = { + NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, // 0-15 + NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, // 16-31 + NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 62, NA, NA, NA, 63, // 32-47 + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, NA, NA, NA, 0, NA, NA, // 48-63 + NA, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 64-79 + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, NA, NA, NA, NA, NA, // 80-95 + NA, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 96-111 + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, NA, NA, NA, NA, NA, // 112-127 + }; + + DWORD cbDecoded; + DWORD cchEncodedSize; + DWORD ich; + DWORD ib; + BYTE b0, b1, b2, b3; + BYTE * pbDecodeBuffer = (BYTE *) pDecodeBuffer; + + cchEncodedSize = (DWORD)strlen(pszEncodedString); + if (NULL != pcbDecoded) { + *pcbDecoded = 0; + } + + if ((0 == cchEncodedSize) || (0 != (cchEncodedSize % 4))) { + // Input string is not sized correctly to be base64. + return ERROR_INVALID_PARAMETER; + } + + // Calculate decoded buffer size. + cbDecoded = (cchEncodedSize + 3) / 4 * 3; + if (pszEncodedString[cchEncodedSize-1] == '=') { + if (pszEncodedString[cchEncodedSize-2] == '=') { + // Only one data byte is encoded in the last cluster. + cbDecoded -= 2; + } + else { + // Only two data bytes are encoded in the last cluster. + cbDecoded -= 1; + } + } + + if (NULL != pcbDecoded) { + *pcbDecoded = cbDecoded; + } + + if (cbDecodeBufferSize == 0 && pDecodeBuffer == NULL) { + return ERROR_SUCCESS; + } + + if (cbDecoded > cbDecodeBufferSize) { + // Supplied buffer is too small. + return ERROR_INSUFFICIENT_BUFFER; + } + + // Decode each four-byte cluster into the corresponding three data bytes. + ich = ib = 0; + while (ich < cchEncodedSize) { + b0 = DECODE(pszEncodedString[ich]); ich++; + b1 = DECODE(pszEncodedString[ich]); ich++; + b2 = DECODE(pszEncodedString[ich]); ich++; + b3 = DECODE(pszEncodedString[ich]); ich++; + + if ((NA == b0) || (NA == b1) || (NA == b2) || (NA == b3)) { + // Contents of input string are not base64. + return ERROR_INVALID_PARAMETER; + } + + pbDecodeBuffer[ib++] = (b0 << 2) | (b1 >> 4); + + if (ib < cbDecoded) { + pbDecodeBuffer[ib++] = (b1 << 4) | (b2 >> 2); + + if (ib < cbDecoded) { + pbDecodeBuffer[ib++] = (b2 << 6) | b3; + } + } + } + + DBG_ASSERT(ib == cbDecoded); + + return ERROR_SUCCESS; +} + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/datetime.cxx b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/datetime.cxx new file mode 100644 index 0000000000..a856b997f1 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/datetime.cxx @@ -0,0 +1,247 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#include "precomp.h" + +static const CHAR* s_rgchMonths[] = { + "Jan", "Feb", "Mar", "Apr", + "May", "Jun", "Jul", "Aug", + "Sep", "Oct", "Nov", "Dec" +}; + +// Custom hash table for make_month() for mapping "Apr" to 4 +static const CHAR MonthIndexTable[64] = { + -1,'A', 2, 12, -1, -1, -1, 8, // A to G + -1, -1, -1, -1, 7, -1,'N', -1, // F to O + 9, -1,'R', -1, 10, -1, 11, -1, // P to W + -1, 5, -1, -1, -1, -1, -1, -1, // X to Z + -1,'A', 2, 12, -1, -1, -1, 8, // a to g + -1, -1, -1, -1, 7, -1,'N', -1, // f to o + 9, -1,'R', -1, 10, -1, 11, -1, // p to w + -1, 5, -1, -1, -1, -1, -1, -1 // x to z +}; + +static const BYTE TensDigit[10] = { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90 }; + +WORD +iis_2atoi( + __in_ecount(2) PCHAR s + ) +/*++ + + Converts a 2 character string to integer + + Arguments: + s String to convert + + Returns: + numeric equivalent, 0 on failure. +--*/ +{ + + DWORD tens = s[0] - '0'; + DWORD ones = s[1] - '0'; + + if ( (tens <= 9) && (ones <= 9) ) { + return((WORD)(TensDigit[tens] + ones)); + } + return(0); +} + +WORD +make_month( + __in_ecount(3) PCHAR s + ) +{ + UCHAR monthIndex; + UCHAR c; + LPCSTR monthString; + + // + // use the third character as the index + // + + c = (s[2] - 0x40) & 0x3F; + + monthIndex = MonthIndexTable[c]; + + if ( monthIndex < 13 ) { + goto verify; + } + + // + // ok, we need to look at the second character + // + + if ( monthIndex == 'N' ) { + + // + // we got an N which we need to resolve further + // + + // + // if s[1] is 'u' then Jun, if 'a' then Jan + // + + if ( MonthIndexTable[(s[1]-0x40) & 0x3f] == 'A' ) { + monthIndex = 1; + } else { + monthIndex = 6; + } + + } else if ( monthIndex == 'R' ) { + + // + // if s[1] is 'a' then March, if 'p' then April + // + + if ( MonthIndexTable[(s[1]-0x40) & 0x3f] == 'A' ) { + monthIndex = 3; + } else { + monthIndex = 4; + } + } else { + goto error_exit; + } + +verify: + + monthString = s_rgchMonths[monthIndex-1]; + + if ( (s[0] == monthString[0]) && + (s[1] == monthString[1]) && + (s[2] == monthString[2]) ) { + + return(monthIndex); + + } else if ( (toupper(s[0]) == monthString[0]) && + (tolower(s[1]) == monthString[1]) && + (tolower(s[2]) == monthString[2]) ) { + + return monthIndex; + } + +error_exit: + return(0); + +} // make_month + +BOOL +StringTimeToFileTime( + IN const CHAR * pszTime, + OUT ULONGLONG * pulTime + ) +/*++ + + Converts a string representation of a GMT time (three different + varieties) to an NT representation of a file time. + + We handle the following variations: + + Sun, 06 Nov 1994 08:49:37 GMT (RFC 822 updated by RFC 1123) + Sunday, 06-Nov-94 08:49:37 GMT (RFC 850) + Sun Nov 6 08:49:37 1994 (ANSI C's asctime() format + + Arguments: + pszTime String representation of time field + pliTime large integer containing the time in NT format. + + Returns: + TRUE on success and FALSE on failure. + + History: + + Johnl 24-Jan-1995 Modified from WWW library + +--*/ +{ + + CHAR * s; + SYSTEMTIME st; + + if (pszTime == NULL) { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + st.wMilliseconds = 0; + + if ((s = (CHAR*) strchr(pszTime, ','))) { + + DWORD len; + + // + // Thursday, 10-Jun-93 01:29:59 GMT + // or: Thu, 10 Jan 1993 01:29:59 GMT */ + // + + s++; + + while (*s && *s==' ') s++; + len = (DWORD)strlen(s); + + if (len < 18) { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + if ( *(s+2) == '-' ) { /* First format */ + + st.wDay = (WORD) atoi(s); + st.wMonth = (WORD) make_month(s+3); + st.wYear = (WORD) atoi(s+7); + st.wHour = (WORD) atoi(s+10); + st.wMinute = (WORD) atoi(s+13); + st.wSecond = (WORD) atoi(s+16); + + } else { /* Second format */ + + if (len < 20) { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + st.wDay = iis_2atoi(s); + st.wMonth = make_month(s+3); + st.wYear = iis_2atoi(s+7) * 100 + iis_2atoi(s+9); + st.wHour = iis_2atoi(s+12); + st.wMinute = iis_2atoi(s+15); + st.wSecond = iis_2atoi(s+18); + + } + } else { /* Try the other format: Wed Jun 9 01:29:59 1993 GMT */ + + s = (CHAR *) pszTime; + while (*s && *s==' ') s++; + + if ((int)strlen(s) < 24) { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + st.wDay = (WORD) atoi(s+8); + st.wMonth = (WORD) make_month(s+4); + st.wYear = (WORD) atoi(s+20); + st.wHour = (WORD) atoi(s+11); + st.wMinute = (WORD) atoi(s+14); + st.wSecond = (WORD) atoi(s+17); + } + + // + // Adjust for dates with only two digits + // + + if ( st.wYear < 1000 ) { + if ( st.wYear < 50 ) { + st.wYear += 2000; + } else { + st.wYear += 1900; + } + } + + if (!SystemTimeToFileTime(&st, (FILETIME *)pulTime)) { + return FALSE; + } + return(TRUE); +} + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/multisz.cxx b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/multisz.cxx new file mode 100644 index 0000000000..26eacdb244 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/multisz.cxx @@ -0,0 +1,480 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#include "precomp.h" + + +//#include +#include +//# include + +#include + +// +// Private Definitions +// + +#define MAXULONG 4294967295 +#define ISWHITE( ch ) ((ch) == L' ' || (ch) == L'\t' || (ch) == L'\r') + +// +// When appending data, this is the extra amount we request to avoid +// reallocations +// +#define STR_SLOP 128 + + +DWORD +MULTISZ::CalcLength( const WCHAR * str, + LPDWORD pcStrings ) +{ + DWORD count = 0; + DWORD total = 1; + DWORD len; + + while( *str ) { + len = (DWORD)(::wcslen( str ) + 1); + total += len; + str += len; + count++; + } + + if( pcStrings != NULL ) { + *pcStrings = count; + } + + return total; + +} // MULTISZ::CalcLength + + +BOOL +MULTISZ::FindString( const WCHAR * str ) +{ + + WCHAR * multisz; + + // + // Sanity check. + // + + DBG_ASSERT( QueryStr() != NULL ); + DBG_ASSERT( str != NULL ); + DBG_ASSERT( *str != '\0' ); + + // + // Scan it. + // + + multisz = QueryStr(); + + while( *multisz != '\0' ) { + + if( !::wcscmp( multisz, str ) ) { + + return TRUE; + + } + + multisz += ::wcslen( multisz ) + 1; + + } + + return FALSE; + +} // MULTISZ::FindString + + +BOOL +MULTISZ::FindStringNoCase( const WCHAR * str ) +{ + + WCHAR * multisz; + + // + // Sanity check. + // + + DBG_ASSERT( QueryStr() != NULL ); + DBG_ASSERT( str != NULL ); + DBG_ASSERT( *str != '\0' ); + + // + // Scan it. + // + + multisz = QueryStr(); + + while( *multisz != '\0' ) { + + if( !_wcsicmp( multisz, str ) ) { + + return TRUE; + + } + + multisz += wcslen( multisz ) + 1; + + } + + return FALSE; + +} // MULTISZ::FindStringNoCase + + +VOID +MULTISZ::AuxInit( const WCHAR * pInit ) +{ + BOOL fRet; + + if ( pInit ) + { + DWORD cStrings; + int cbCopy = CalcLength( pInit, &cStrings ) * sizeof(WCHAR); + fRet = Resize( cbCopy ); + + if ( fRet ) { + CopyMemory( QueryPtr(), pInit, cbCopy ); + m_cchLen = (cbCopy)/sizeof(WCHAR); + m_cStrings = cStrings; + } else { +// BUFFER::SetValid( FALSE); + } + + } else { + + Reset(); + + } + +} // MULTISZ::AuxInit() + + +/******************************************************************* + + NAME: MULTISZ::AuxAppend + + SYNOPSIS: Appends the string onto the multisz. + + ENTRY: Object to append +********************************************************************/ + +BOOL MULTISZ::AuxAppend( const WCHAR * pStr, UINT cbStr, BOOL fAddSlop ) +{ + DBG_ASSERT( pStr != NULL ); + + UINT cbThis = QueryCB(); + + DBG_ASSERT( cbThis >= 2 ); + + if( cbThis == 4 ) { + + // + // It's empty, so start at the beginning. + // + + cbThis = 0; + + } else { + + // + // It's not empty, so back up over the final terminating NULL. + // + + cbThis -= sizeof(WCHAR); + + } + + // + // Only resize when we have to. When we do resize, we tack on + // some extra space to avoid extra reallocations. + // + // Note: QuerySize returns the requested size of the string buffer, + // *not* the strlen of the buffer + // + + //AcIncrement( CacMultiszAppend); + + // + // Check for the arithmetic overflow + // + // ( 2 * sizeof( WCHAR ) ) is for the double terminator + // + ULONGLONG cb64Required = (ULONGLONG)cbThis + cbStr + 2 * sizeof(WCHAR); + if ( cb64Required > MAXULONG ) + { + SetLastError( ERROR_ARITHMETIC_OVERFLOW ); + return FALSE; + } + if ( QuerySize() < (DWORD) cb64Required ) + { + ULONGLONG cb64AllocSize = cb64Required + (fAddSlop ? STR_SLOP : 0 ); + // + // Check for the arithmetic overflow + // + if ( cb64AllocSize > MAXULONG ) + { + SetLastError( ERROR_ARITHMETIC_OVERFLOW ); + return FALSE; + } + if ( !Resize( (DWORD) cb64AllocSize ) ) + return FALSE; + } + + // copy the exact string and tack on the double terminator + memcpy( (BYTE *) QueryPtr() + cbThis, + pStr, + cbStr); + *(WCHAR *)((BYTE *)QueryPtr() + cbThis + cbStr) = L'\0'; + *(WCHAR *)((BYTE *)QueryPtr() + cbThis + cbStr + sizeof(WCHAR) ) = L'\0'; + + m_cchLen = CalcLength( (const WCHAR *)QueryPtr(), &m_cStrings ); + return TRUE; + +} // MULTISZ::AuxAppend() + + +#if 0 + +BOOL +MULTISZ::CopyToBuffer( WCHAR * lpszBuffer, LPDWORD lpcch) const +/*++ + Description: + Copies the string into the WCHAR buffer passed in if the buffer + is sufficient to hold the translated string. + If the buffer is small, the function returns small and sets *lpcch + to contain the required number of characters. + + Arguments: + lpszBuffer pointer to WCHAR buffer which on return contains + the UNICODE version of string on success. + lpcch pointer to DWORD containing the length of the buffer. + If *lpcch == 0 then the function returns TRUE with + the count of characters required stored in *lpcch. + Also in this case lpszBuffer is not affected. + Returns: + TRUE on success. + FALSE on failure. Use GetLastError() for further details. + + History: + MuraliK 11-30-94 +--*/ +{ + BOOL fReturn = TRUE; + + if ( lpcch == NULL) { + SetLastError( ERROR_INVALID_PARAMETER); + return ( FALSE); + } + + if ( *lpcch == 0) { + + // + // Inquiring the size of buffer alone + // + *lpcch = QueryCCH() + 1; // add one character for terminating null + } else { + + // + // Copy after conversion from ANSI to Unicode + // + int iRet; + iRet = MultiByteToWideChar( CP_ACP, + MB_PRECOMPOSED | MB_ERR_INVALID_CHARS, + QueryStrA(), QueryCCH() + 1, + lpszBuffer, (int )*lpcch); + + if ( iRet == 0 || iRet != (int ) *lpcch) { + + // + // Error in conversion. + // + fReturn = FALSE; + } + } + + return ( fReturn); +} // MULTISZ::CopyToBuffer() +#endif + +BOOL +MULTISZ::CopyToBuffer( __out_ecount_opt(*lpcch) WCHAR * lpszBuffer, LPDWORD lpcch) const +/*++ + Description: + Copies the string into the WCHAR buffer passed in if the buffer + is sufficient to hold the translated string. + If the buffer is small, the function returns small and sets *lpcch + to contain the required number of characters. + + Arguments: + lpszBuffer pointer to WCHAR buffer which on return contains + the string on success. + lpcch pointer to DWORD containing the length of the buffer. + If *lpcch == 0 then the function returns TRUE with + the count of characters required stored in lpcch. + Also in this case lpszBuffer is not affected. + Returns: + TRUE on success. + FALSE on failure. Use GetLastError() for further details. + + History: + MuraliK 20-Nov-1996 +--*/ +{ + BOOL fReturn = TRUE; + + if ( lpcch == NULL) { + SetLastError( ERROR_INVALID_PARAMETER); + return ( FALSE); + } + + register DWORD cch = QueryCCH(); + + if ( *lpcch >= cch) { + + DBG_ASSERT( lpszBuffer); + memcpy( lpszBuffer, QueryStr(), cch * sizeof(WCHAR)); + } else { + DBG_ASSERT( *lpcch < cch); + SetLastError( ERROR_INSUFFICIENT_BUFFER); + fReturn = FALSE; + } + + *lpcch = cch; + + return ( fReturn); +} // MULTISZ::CopyToBuffer() + +BOOL +MULTISZ::Equals( + MULTISZ* pmszRhs +) +// +// Compares this to pmszRhs, returns TRUE if equal +// +{ + DBG_ASSERT( NULL != pmszRhs ); + + PCWSTR pszLhs = First( ); + PCWSTR pszRhs = pmszRhs->First( ); + + if( m_cStrings != pmszRhs->m_cStrings ) + { + return FALSE; + } + + while( NULL != pszLhs ) + { + DBG_ASSERT( NULL != pszRhs ); + + if( 0 != wcscmp( pszLhs, pszRhs ) ) + { + return FALSE; + } + + pszLhs = Next( pszLhs ); + pszRhs = pmszRhs->Next( pszRhs ); + } + + return TRUE; +} + +HRESULT +SplitCommaDelimitedString( + PCWSTR pszList, + BOOL fTrimEntries, + BOOL fRemoveEmptyEntries, + MULTISZ * pmszList +) +/*++ + +Routine Description: + + Split comma delimited string into a multisz. Additional leading empty + entries after the first are discarded. + +Arguments: + + pszList - List to split up + fTrimEntries - Whether each entry should be trimmed before added to multisz + fRemoveEmptyEntries - Whether empty entires should be discarded + pmszList - Filled with MULTISZ list + +Return Value: + + HRESULT + +--*/ +{ + HRESULT hr = S_OK; + + if ( pszList == NULL || + pmszList == NULL ) + { + DBG_ASSERT( FALSE ); + hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); + goto Finished; + } + + pmszList->Reset(); + + /* + pszCurrent: start of the current entry which may be the comma that + precedes the next entry if the entry is empty + + pszNext: the comma that precedes the next entry. If + pszCurrent == pszNext, then the entry is empty + + pszEnd: just past the end of the current entry + */ + + for ( PCWSTR pszCurrent = pszList, + pszNext = wcschr( pszCurrent, L',' ) + ; + ; + pszCurrent = pszNext + 1, + pszNext = wcschr( pszCurrent, L',' ) ) + { + PCWSTR pszEnd = NULL; + + if ( pszNext != NULL ) + { + pszEnd = pszNext; + } + else + { + pszEnd = pszCurrent + wcslen( pszCurrent ); + } + + if ( fTrimEntries ) + { + while ( pszCurrent < pszEnd && ISWHITE( pszCurrent[ 0 ] ) ) + { + pszCurrent++; + } + + while ( pszEnd > pszCurrent && ISWHITE( pszEnd[ -1 ] ) ) + { + pszEnd--; + } + } + + if ( pszCurrent != pszEnd || !fRemoveEmptyEntries ) + { + if ( !pmszList->Append( pszCurrent, (DWORD) ( pszEnd - pszCurrent ) ) ) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + goto Finished; + } + } + + if ( pszNext == NULL ) + { + break; + } + } + +Finished: + + return hr; +} diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/multisza.cxx b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/multisza.cxx new file mode 100644 index 0000000000..e6972534bb --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/multisza.cxx @@ -0,0 +1,414 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#include "precomp.h" + + +//#include +#include +//# include + +#include + +// +// Private Definitions +// + +#define MAXULONG 4294967295 +#define ISWHITE( ch ) ((ch) == L' ' || (ch) == L'\t' || (ch) == L'\r') + +// +// When appending data, this is the extra amount we request to avoid +// reallocations +// +#define STR_SLOP 128 + + +DWORD +MULTISZA::CalcLength( const CHAR * str, + LPDWORD pcStrings ) +{ + DWORD count = 0; + DWORD total = 1; + DWORD len; + + while( *str ) { + len = (DWORD)(::strlen( str ) + 1); + total += len; + str += len; + count++; + } + + if( pcStrings != NULL ) { + *pcStrings = count; + } + + return total; + +} // MULTISZA::CalcLength + + +BOOL +MULTISZA::FindString( const CHAR * str ) +{ + + CHAR * multisz; + + // + // Sanity check. + // + + DBG_ASSERT( QueryStr() != NULL ); + DBG_ASSERT( str != NULL ); + DBG_ASSERT( *str != '\0' ); + + // + // Scan it. + // + + multisz = QueryStr(); + + while( *multisz != '\0' ) { + + if( !::strcmp( multisz, str ) ) { + + return TRUE; + + } + + multisz += ::strlen( multisz ) + 1; + + } + + return FALSE; + +} // MULTISZA::FindString + + +BOOL +MULTISZA::FindStringNoCase( const CHAR * str ) +{ + + CHAR * multisz; + + // + // Sanity check. + // + + DBG_ASSERT( QueryStr() != NULL ); + DBG_ASSERT( str != NULL ); + DBG_ASSERT( *str != '\0' ); + + // + // Scan it. + // + + multisz = QueryStr(); + + while( *multisz != '\0' ) { + + if( !_stricmp( multisz, str ) ) { + + return TRUE; + + } + + multisz += strlen( multisz ) + 1; + + } + + return FALSE; + +} // MULTISZA::FindStringNoCase + + +VOID +MULTISZA::AuxInit( const CHAR * pInit ) +{ + BOOL fRet; + + if ( pInit ) + { + DWORD cStrings; + int cbCopy = CalcLength( pInit, &cStrings ) * sizeof(CHAR); + fRet = Resize( cbCopy ); + + if ( fRet ) { + CopyMemory( QueryPtr(), pInit, cbCopy ); + m_cchLen = (cbCopy)/sizeof(CHAR); + m_cStrings = cStrings; + } else { +// BUFFER::SetValid( FALSE); + } + + } else { + + Reset(); + + } + +} // MULTISZA::AuxInit() + + +/******************************************************************* + + NAME: MULTISZA::AuxAppend + + SYNOPSIS: Appends the string onto the MULTISZA. + + ENTRY: Object to append +********************************************************************/ + +BOOL MULTISZA::AuxAppend( const CHAR * pStr, UINT cbStr, BOOL fAddSlop ) +{ + DBG_ASSERT( pStr != NULL ); + + UINT cbThis = QueryCB(); + + if( cbThis == 2 ) { + + // + // It's empty, so start at the beginning. + // + + cbThis = 0; + + } else { + + // + // It's not empty, so back up over the final terminating NULL. + // + + cbThis -= sizeof(CHAR); + + } + + // + // Only resize when we have to. When we do resize, we tack on + // some extra space to avoid extra reallocations. + // + // Note: QuerySize returns the requested size of the string buffer, + // *not* the strlen of the buffer + // + + //AcIncrement( CacMultiszAppend); + + // + // Check for the arithmetic overflow + // + // ( 2 * sizeof( CHAR ) ) is for the double terminator + // + ULONGLONG cb64Required = (ULONGLONG)cbThis + cbStr + 2 * sizeof(CHAR); + if ( cb64Required > MAXULONG ) + { + SetLastError( ERROR_ARITHMETIC_OVERFLOW ); + return FALSE; + } + if ( QuerySize() < (DWORD) cb64Required ) + { + ULONGLONG cb64AllocSize = cb64Required + (fAddSlop ? STR_SLOP : 0 ); + // + // Check for the arithmetic overflow + // + if ( cb64AllocSize > MAXULONG ) + { + SetLastError( ERROR_ARITHMETIC_OVERFLOW ); + return FALSE; + } + if ( !Resize( (DWORD) cb64AllocSize ) ) + return FALSE; + } + + // copy the exact string and tack on the double terminator + memcpy( (BYTE *) QueryPtr() + cbThis, + pStr, + cbStr); + *(CHAR *)((BYTE *)QueryPtr() + cbThis + cbStr) = L'\0'; + *(CHAR *)((BYTE *)QueryPtr() + cbThis + cbStr + sizeof(CHAR) ) = L'\0'; + + m_cchLen = CalcLength( (const CHAR *)QueryPtr(), &m_cStrings ); + return TRUE; + +} // MULTISZA::AuxAppend() + +BOOL +MULTISZA::CopyToBuffer( __out_ecount_opt(*lpcch) CHAR * lpszBuffer, LPDWORD lpcch) const +/*++ + Description: + Copies the string into the CHAR buffer passed in if the buffer + is sufficient to hold the translated string. + If the buffer is small, the function returns small and sets *lpcch + to contain the required number of characters. + + Arguments: + lpszBuffer pointer to CHAR buffer which on return contains + the string on success. + lpcch pointer to DWORD containing the length of the buffer. + If *lpcch == 0 then the function returns TRUE with + the count of characters required stored in lpcch. + Also in this case lpszBuffer is not affected. + Returns: + TRUE on success. + FALSE on failure. Use GetLastError() for further details. + + History: + MuraliK 20-Nov-1996 +--*/ +{ + BOOL fReturn = TRUE; + + if ( lpcch == NULL) { + SetLastError( ERROR_INVALID_PARAMETER); + return ( FALSE); + } + + register DWORD cch = QueryCCH(); + + if ( *lpcch >= cch) { + + DBG_ASSERT( lpszBuffer); + memcpy( lpszBuffer, QueryStr(), cch * sizeof(CHAR)); + } else { + DBG_ASSERT( *lpcch < cch); + SetLastError( ERROR_INSUFFICIENT_BUFFER); + fReturn = FALSE; + } + + *lpcch = cch; + + return ( fReturn); +} // MULTISZA::CopyToBuffer() + +BOOL +MULTISZA::Equals( + MULTISZA* pmszRhs +) +// +// Compares this to pmszRhs, returns TRUE if equal +// +{ + DBG_ASSERT( NULL != pmszRhs ); + + PCSTR pszLhs = First( ); + PCSTR pszRhs = pmszRhs->First( ); + + if( m_cStrings != pmszRhs->m_cStrings ) + { + return FALSE; + } + + while( NULL != pszLhs ) + { + DBG_ASSERT( NULL != pszRhs ); + + if( 0 != strcmp( pszLhs, pszRhs ) ) + { + return FALSE; + } + + pszLhs = Next( pszLhs ); + pszRhs = pmszRhs->Next( pszRhs ); + } + + return TRUE; +} + +HRESULT +SplitCommaDelimitedString( + PCSTR pszList, + BOOL fTrimEntries, + BOOL fRemoveEmptyEntries, + MULTISZA * pmszList +) +/*++ + +Routine Description: + + Split comma delimited string into a MULTISZA. Additional leading empty + entries after the first are discarded. + +Arguments: + + pszList - List to split up + fTrimEntries - Whether each entry should be trimmed before added to MULTISZA + fRemoveEmptyEntries - Whether empty entires should be discarded + pmszList - Filled with MULTISZA list + +Return Value: + + HRESULT + +--*/ +{ + HRESULT hr = S_OK; + + if ( pszList == NULL || + pmszList == NULL ) + { + DBG_ASSERT( FALSE ); + hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); + goto Finished; + } + + pmszList->Reset(); + + /* + pszCurrent: start of the current entry which may be the comma that + precedes the next entry if the entry is empty + + pszNext: the comma that precedes the next entry. If + pszCurrent == pszNext, then the entry is empty + + pszEnd: just past the end of the current entry + */ + + for ( PCSTR pszCurrent = pszList, + pszNext = strchr( pszCurrent, L',' ) + ; + ; + pszCurrent = pszNext + 1, + pszNext = strchr( pszCurrent, L',' ) ) + { + PCSTR pszEnd = NULL; + + if ( pszNext != NULL ) + { + pszEnd = pszNext; + } + else + { + pszEnd = pszCurrent + strlen( pszCurrent ); + } + + if ( fTrimEntries ) + { + while ( pszCurrent < pszEnd && ISWHITE( pszCurrent[ 0 ] ) ) + { + pszCurrent++; + } + + while ( pszEnd > pszCurrent && ISWHITE( pszEnd[ -1 ] ) ) + { + pszEnd--; + } + } + + if ( pszCurrent != pszEnd || !fRemoveEmptyEntries ) + { + if ( !pmszList->Append( pszCurrent, (DWORD) ( pszEnd - pszCurrent ) ) ) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + goto Finished; + } + } + + if ( pszNext == NULL ) + { + break; + } + } + +Finished: + + return hr; +} diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/normalize.cxx b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/normalize.cxx new file mode 100644 index 0000000000..48b41fdd1c --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/normalize.cxx @@ -0,0 +1,890 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#include "precomp.h" +#include "normalize.h" +#include "stringa.h" + +BOOL g_fEnableNonUTF8; +BOOL g_fEnableDBCS; +BOOL g_fIsSystemDBCS; +static BOOL g_fFavorDBCS; + +#ifndef STACK_STRA +#define STACK_STRA(name, size) CHAR __ach##name[size]; \ + STRA name(__ach##name, sizeof(__ach##name) / sizeof(CHAR)) +#endif + +HRESULT +InitializeNormalizeUrl( + VOID +) +{ + HKEY hKey; + DWORD dwType; + DWORD dwData; + DWORD cbData; + WORD wPrimaryLangID; + + // + // Read the registry settings on how to handle URLs + // + + g_fEnableNonUTF8 = TRUE; + g_fEnableDBCS = FALSE; + g_fFavorDBCS = FALSE; + + if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, + L"System\\CurrentControlSet\\Services\\http\\Parameters", + 0, + KEY_READ, + &hKey ) == ERROR_SUCCESS ) + { + cbData = sizeof( dwData ); + if ( RegQueryValueEx( hKey, + L"EnableNonUTF8", + NULL, + &dwType, + (LPBYTE) &dwData, + &cbData ) == ERROR_SUCCESS && + dwType == REG_DWORD ) + { + g_fEnableNonUTF8 = !!dwData; + } + + if ( g_fEnableNonUTF8 ) + { + cbData = sizeof( dwData ); + + if ( RegQueryValueEx( hKey, + L"EnableDBCS", + NULL, + &dwType, + (LPBYTE) &dwData, + &cbData ) == ERROR_SUCCESS && + dwType == REG_DWORD ) + { + g_fEnableDBCS = !!dwData; + } + } + else + { + g_fEnableDBCS = FALSE; + } + + if ( g_fEnableDBCS ) + { + cbData = sizeof( dwData ); + + if ( RegQueryValueEx( hKey, + L"FavorDBCS", + NULL, + &dwType, + (LPBYTE) &dwData, + &cbData ) == ERROR_SUCCESS && + dwType == REG_DWORD ) + { + g_fFavorDBCS = !!dwData; + } + } + else + { + g_fFavorDBCS = FALSE; + } + + RegCloseKey( hKey ); + } + + + wPrimaryLangID = PRIMARYLANGID( GetSystemDefaultLangID() ); + + g_fIsSystemDBCS = ( wPrimaryLangID == LANG_JAPANESE || + wPrimaryLangID == LANG_CHINESE || + wPrimaryLangID == LANG_KOREAN ); + + return NO_ERROR; +} + +// +// Private constants. +// + +#define ACTION_NOTHING 0x00000000 +#define ACTION_EMIT_CH 0x00010000 +#define ACTION_EMIT_DOT_CH 0x00020000 +#define ACTION_EMIT_DOT_DOT_CH 0x00030000 +#define ACTION_BACKUP 0x00040000 +#define ACTION_MASK 0xFFFF0000 + + +// +// Private globals. +// + +INT p_StateTable[16] = + { + // state 0 + 0 , // other + 0 , // "." + 4 , // EOS + 1 , // "\" + + // state 1 + 0 , // other + 2 , // "." + 4 , // EOS + 1 , // "\" + + // state 2 + 0 , // other + 3 , // "." + 4 , // EOS + 1 , // "\" + + // state 3 + 0 , // other + 0 , // "." + 4 , // EOS + 1 // "\" + }; + + + +INT p_ActionTable[16] = + { + // state 0 + ACTION_EMIT_CH, // other + ACTION_EMIT_CH, // "." + ACTION_EMIT_CH, // EOS + ACTION_EMIT_CH, // "\" + + // state 1 + ACTION_EMIT_CH, // other + ACTION_NOTHING, // "." + ACTION_EMIT_CH, // EOS + ACTION_NOTHING, // "\" + + // state 2 + ACTION_EMIT_DOT_CH, // other + ACTION_NOTHING, // "." + ACTION_EMIT_CH, // EOS + ACTION_NOTHING, // "\" + + // state 3 + ACTION_EMIT_DOT_DOT_CH, // other + ACTION_EMIT_DOT_DOT_CH, // "." + ACTION_BACKUP, // EOS + ACTION_BACKUP // "\" + }; + +// since max states = 4, we calculat the index by multiplying with 4. +# define IndexFromState( st) ( (st) * 4) + + +// the following table provides the index for various ISA Latin1 characters +// in the incoming URL. +// It assumes that the URL is ISO Latin1 == ASCII +INT p_rgIndexForChar[] = { + + 2, // null char + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 thru 10 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 11 thru 20 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 21 thru 30 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 31 thru 40 + 0, 0, 0, 0, 0, 1, 3, 0, 0, 0, // 41 thru 50 46 = '.' 47 = '/' + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 51 thru 60 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 61 thru 70 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 71 thru 80 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 81 thru 90 + 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, // 91 thru 100 92 = '\\' + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 101 thru 110 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 111 thru 120 + 0, 0, 0, 0, 0, 0, 0, 0 // 121 thru 128 +}; + +#define IS_UTF8_TRAILBYTE(ch) (((ch) & 0xc0) == 0x80) + + +/******************************************************************* + + NAME: IsUTF8URL + + ENTRY: pszPath - The path to sanitize. + + HISTORY: + atsusk 06-Jan-1998 Created. + +********************************************************************/ + +BOOL IsUTF8URL(__in LPSTR pszPath) +{ + CHAR ch; + + if ( g_fFavorDBCS ) + { + return ( MultiByteToWideChar( CP_ACP, + MB_ERR_INVALID_CHARS, + pszPath, + -1, + NULL, + 0) == 0); + } + + while (ch = *pszPath++) { + + if (ch & 0x80) { + wchar_t wch; + int iLen; + BOOL bDefault = FALSE; + char chTrail1; + char chTrail2; + + chTrail1 = *pszPath++; + if (chTrail1) { + chTrail2 = *pszPath; + } else { + chTrail2 = 0; + } + + if ( ((ch & 0xF0) == 0xE0) && + IS_UTF8_TRAILBYTE(chTrail1) && + IS_UTF8_TRAILBYTE(chTrail2) ) { + + // handle three byte case + // 1110xxxx 10xxxxxx 10xxxxxx + wch = (wchar_t) (((ch & 0x0f) << 12) | + ((chTrail1 & 0x3f) << 6) | + (chTrail2 & 0x3f)); + pszPath++; + + } else + if ( ((ch & 0xE0) == 0xC0) && + IS_UTF8_TRAILBYTE(chTrail1) ) { + + // handle two byte case + // 110xxxxx 10xxxxxx + + wch = (wchar_t) (((ch & 0x1f) << 6) | (chTrail1 & 0x3f)); + + } else + return FALSE; + + iLen = WideCharToMultiByte( CP_ACP, + WC_NO_BEST_FIT_CHARS, + &wch, + 1, + NULL, + 0, + NULL, + &bDefault ); + + if (bDefault == TRUE || iLen == 0 || iLen > 2) + return FALSE; + } + } + + return TRUE; +} // IsUTF8URL() + + +/******************************************************************* + + NAME: CanonURL + + SYNOPSIS: Sanitizes a path by removing bogus path elements. + + As expected, "/./" entries are simply removed, and + "/../" entries are removed along with the previous + path element. + + To maintain compatibility with URL path semantics + additional transformations are required. All backward + slashes "\\" are converted to forward slashes. Any + repeated forward slashes (such as "///") are mapped to + single backslashes. + + A state table (see the p_StateTable global at the + beginning of this file) is used to perform most of + the transformations. The table's rows are indexed + by current state, and the columns are indexed by + the current character's "class" (either slash, dot, + NULL, or other). Each entry in the table consists + of the new state tagged with an action to perform. + See the ACTION_* constants for the valid action + codes. + + ENTRY: pszPath - The path to sanitize. + fIsDBCSLocale - Indicates the server is in a + locale that uses DBCS. + + HISTORY: + KeithMo 07-Sep-1994 Created. + MuraliK 28-Apr-1995 Adopted this for symbolic paths + +********************************************************************/ +INT +CanonURL( + __inout LPSTR pszPath, + BOOL fIsDBCSLocale + ) +{ + UCHAR * pszSrc; + UCHAR * pszDest; + DWORD ch; + INT index; + BOOL fDBCS = FALSE; + DWORD cchMultiByte = 0; + + DBG_ASSERT( pszPath != NULL ); + + // + // Always look for UTF8 except when DBCS characters are detected + // + BOOL fScanForUTF8 = IsUTF8URL(pszPath); + + // If fScanForUTF8 is true, this URL is UTF8. don't recognize DBCS. + if (fIsDBCSLocale && fScanForUTF8) { + fIsDBCSLocale = FALSE; + } + + // + // Start our scan at the first character + // + + pszSrc = pszDest = (UCHAR *) pszPath; + + // + // State 0 is the initial state. + // + index = 0; // State = 0 + + // + // Loop until we enter state 4 (the final, accepting state). + // + + do { + + // + // Grab the next character from the path and compute its + // next state. While we're at it, map any forward + // slashes to backward slashes. + // + + index = IndexFromState( p_StateTable[index]); // 4 = # states + ch = (DWORD ) *pszSrc++; + + // + // If this is a DBCS trailing byte - skip it + // + + if ( !fIsDBCSLocale ) + { + index += (( ch >= 0x80) ? 0 : p_rgIndexForChar[ch]); + } + else + { + if ( fDBCS ) + { + // + // If this is a 0 terminator, we need to set next + // state accordingly + // + + if ( ch == 0 ) + { + index += p_rgIndexForChar[ ch ]; + } + + // + // fDBCS == TRUE means this byte was a trail byte. + // index is implicitly set to zero. + // + fDBCS = FALSE; + } + else + { + index += (( ch >= 0x80) ? 0 : p_rgIndexForChar[ch]); + + if ( IsDBCSLeadByte( (UCHAR)ch ) ) + { + // + // This is a lead byte, so the next is a trail. + // + fDBCS = TRUE; + } + } + } + + // + // Interesting UTF8 characters always have the top bit set + // + + if ( (ch & 0x80) && fScanForUTF8 ) + { + wchar_t wch; + UCHAR mbstr[2]; + + // + // This is a UTF8 character, convert it here. + // index is implicitly set to zero. + // + if ( cchMultiByte < 2 ) + { + char chTrail1; + char chTrail2; + + chTrail1 = *pszSrc; + if (chTrail1) { + chTrail2 = *(pszSrc+1); + } else { + chTrail2 = 0; + } + wch = 0; + + if ((ch & 0xf0) == 0xe0) + { + // handle three byte case + // 1110xxxx 10xxxxxx 10xxxxxx + + wch = (wchar_t) (((ch & 0x0f) << 12) | + ((chTrail1 & 0x3f) << 6) | + (chTrail2 & 0x3f)); + + cchMultiByte = WideCharToMultiByte( CP_ACP, + WC_NO_BEST_FIT_CHARS, + &wch, + 1, + (LPSTR) mbstr, + 2, + NULL, + NULL ); + + ch = mbstr[0]; + pszSrc += (3 - cchMultiByte); + + // WinSE 12843: Security Fix, Index should be updated for this character + index += (( ch >= 0x80) ? 0 : p_rgIndexForChar[ch]); + + } else if ((ch & 0xe0) == 0xc0) + { + // handle two byte case + // 110xxxxx 10xxxxxx + + wch = (wchar_t) (((ch & 0x1f) << 6) | (chTrail1 & 0x3f)); + + cchMultiByte = WideCharToMultiByte( CP_ACP, + WC_NO_BEST_FIT_CHARS, + &wch, + 1, + (LPSTR) mbstr, + 2, + NULL, + NULL ); + + ch = mbstr[0]; + pszSrc += (2 - cchMultiByte); + + // WinSE 12843: Security Fix, Index should be updated for this character + index += (( ch >= 0x80) ? 0 : p_rgIndexForChar[ch]); + } + + } else { + // + // get ready to emit 2nd byte of converted character + // + ch = mbstr[1]; + cchMultiByte = 0; + } + } + + + // + // Perform the action associated with the state. + // + + switch( p_ActionTable[index] ) + { + case ACTION_EMIT_DOT_DOT_CH : + *pszDest++ = '.'; + /* fall through */ + + case ACTION_EMIT_DOT_CH : + *pszDest++ = '.'; + /* fall through */ + + case ACTION_EMIT_CH : + *pszDest++ = (CHAR ) ch; + /* fall through */ + + case ACTION_NOTHING : + break; + + case ACTION_BACKUP : + if( (pszDest > ( (UCHAR *) pszPath + 1 ) ) && (*pszPath == '/')) + { + pszDest--; + DBG_ASSERT( *pszDest == '/' ); + + *pszDest = '\0'; + pszDest = (UCHAR *) strrchr( pszPath, '/') + 1; + } + + *pszDest = '\0'; + break; + + default : + DBG_ASSERT( !"Invalid action code in state table!" ); + index = IndexFromState(0) + 2; // move to invalid state + DBG_ASSERT( p_StateTable[index] == 4); + *pszDest++ = '\0'; + break; + } + + } while( p_StateTable[index] != 4 ); + + // + // point to terminating nul + // only do the check if we aren't about to go outside of the number + // of elements in the table. + // + if ( ( index < ( sizeof(p_ActionTable) / sizeof(p_ActionTable[0]) ) ) + && p_ActionTable[index] == ACTION_EMIT_CH ) + { + pszDest--; + } + + DBG_ASSERT(*pszDest == '\0' && pszDest > (UCHAR*) pszPath); + + return (INT)DIFF(pszDest - (UCHAR*)pszPath); +} // CanonURL() + + + +HRESULT +NormalizeUrl( + __inout LPSTR pszStart + ) +/*++ + +Routine Description: + + Normalize URL + +Arguments: + + strUrl - URL to be updated to a canonical URI + +Return value: + + TRUE if no error, otherwise FALSE + +--*/ +{ + CHAR * pchParams; + LPSTR pszSlash; + LPSTR pszURL; + LPSTR pszValue; + STACK_STRA( strChgUrl, MAX_PATH ); + HRESULT hr; + DWORD cchInput; + + if ( pszStart == NULL ) + { + return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); + } + + cchInput = (DWORD)strlen( pszStart ); + + if ( *pszStart != '/' ) + { + // + // assume HTTP URL, skip protocol & host name by + // searching for 1st '/' following "//" + // + // We handle this information as a "Host:" header. + // It will be overwritten by the real header if it is + // present. + // + // We do not check for a match in this case. + // + + if ( (pszSlash = strchr( pszStart, '/' )) && pszSlash[1] == '/' ) + { + pszSlash += 2; + if ( pszURL = strchr( pszSlash, '/' ) ) + { + // + // update pointer to URL to point to the 1st slash + // following host name + // + + pszValue = pszURL; + } + else + { + // + // if no single slash following host name + // consider the URL to be empty. + // + + pszValue = pszSlash + strlen( pszSlash ); + } + + memmove( pszStart, pszValue, strlen(pszValue)+1 ); + } + + // + // if no double slash, this is not a fully qualified URL + // and we leave it alone. + // + } + + // + // Check for a question mark which indicates this URL contains some + // parameters and break the two apart if found + // + + if ( (pchParams = strchr( pszStart, '?' )) ) + { + *pchParams = '\0'; + } + + // + // Unescape wants a STR ( sigh ) + // + + hr = strChgUrl.Copy( (CHAR*)pszStart ); + + if ( FAILED( hr ) ) + { + return hr; + } + + strChgUrl.Unescape(); + + hr = StringCchCopyNA( pszStart, cchInput + 1, strChgUrl.QueryStr(), cchInput ); + if ( FAILED( hr ) ) + { + return hr; + } + + // + // Canonicalize the URL + // + + CanonURL( pszStart, g_fIsSystemDBCS ); + + return NO_ERROR; +} + + + + +HRESULT +NormalizeUrlOld( + __inout LPSTR pszUrl +) +/*++ + +Routine Description: + + NormalizeUrl wrapper (used by ISAPI filter and extension support functions) + +Parameters: + + pszUrl - On entry, the URL to be normalized + On return, the normalized URL + (size of normalized URL is always <= not normalized URL) + +Return Value: + + HRESULT + +--*/ +{ + HRESULT hr = NO_ERROR; + + if ( pszUrl ) + { + STACK_BUFFER( buffUrlOutput, MAX_PATH ); + STACK_STRA( strUrlA, MAX_PATH ); + LPWSTR szQueryString; + DWORD cchData; + DWORD cbOutput; + + cchData = (DWORD)strlen( pszUrl ); + + // + // Prepare the Output string + // + + if ( !buffUrlOutput.Resize( ( cchData + 1 ) *sizeof( WCHAR ) ) ) + { + return HRESULT_FROM_WIN32( GetLastError() ); + } + + // + // Normalize it + // + + hr = UlCleanAndCopyUrl( + pszUrl, + cchData, + &cbOutput, + (WCHAR *) buffUrlOutput.QueryPtr(), + &szQueryString + ); + + if ( FAILED( hr ) ) + { + return hr; + } + + // + // Terminate the string at the query so that the + // query string doesn't appear in the output. IIS 5 + // truncated in this way. + // + + if ( szQueryString != NULL ) + { + ((WCHAR *) buffUrlOutput.QueryPtr())[ cbOutput - wcslen( szQueryString )] = 0; + } + + // + // Write the normalized URL over the input data + // + + hr = strUrlA.CopyW( (WCHAR *) buffUrlOutput.QueryPtr() ); + + if ( FAILED( hr ) ) + { + return hr; + } + + // + // Normalized string will never be longer than the original one + // + + DBG_ASSERT( strUrlA.QueryCCH() <= cchData ); + + hr = StringCchCopyA( pszUrl, cchData + 1, strUrlA.QueryStr() ); + if ( FAILED( hr ) ) + { + return hr; + } + + hr = NO_ERROR; + } + else + { + hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); + } + return hr; +} + + +HRESULT +NormalizeUrlW( + __inout LPWSTR pszUrl +) +/*++ + +Routine Description: + + unicode version of NormalizeUrl wrapper (used by ISAPI filter and extension support functions) + +Parameters: + + pszUrl - On entry, the URL to be normalized + On return, the normalized URL + (size of normalized URL is always <= not normalized URL) + +Return Value: + + HRESULT + +--*/ +{ + + HRESULT hr = NO_ERROR; + + if ( pszUrl ) + { + STACK_BUFFER( buffUrlOutput, MAX_PATH ); + STACK_STRA( strUrlA, MAX_PATH ); + LPWSTR szQueryString; + DWORD cchData; + DWORD cbOutput; + + cchData = (DWORD)wcslen( pszUrl ); + + hr = strUrlA.CopyWToUTF8Escaped( pszUrl ); + + if ( FAILED( hr ) ) + { + return hr; + } + + // + // Prepare Output string + // + + if ( !buffUrlOutput.Resize( ( cchData + 1 ) *sizeof( WCHAR ) ) ) + { + return HRESULT_FROM_WIN32( GetLastError() ); + } + + // + // Normalize it + // + + hr = UlCleanAndCopyUrl( + strUrlA.QueryStr(), + strUrlA.QueryCB(), + &cbOutput, + (WCHAR *) buffUrlOutput.QueryPtr(), + &szQueryString + ); + + if ( FAILED( hr ) ) + { + return hr; + } + + + // + // Terminate the string at the query so that the + // query string doesn't appear in the output. IIS 5 + // truncated in this way. + // + + if ( szQueryString != NULL ) + { + ((WCHAR *) buffUrlOutput.QueryPtr())[ cbOutput - wcslen( szQueryString )] = 0; + } + + // + // normalized string will never be longer than the original one + // + + DBG_ASSERT( cbOutput <= cchData * sizeof( WCHAR ) ); + + // + // Write the normalized URL over the input data + // + + hr = StringCchCopyW( pszUrl, cchData+1, (WCHAR *) buffUrlOutput.QueryPtr() ); + if ( FAILED( hr ) ) + { + return hr; + } + + hr = NO_ERROR; + } + else + { + hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); + } + return hr; +} diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/packages.config b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/packages.config new file mode 100644 index 0000000000..21d9344493 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/packages.config @@ -0,0 +1,4 @@ + + + + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/precomp.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/precomp.h new file mode 100644 index 0000000000..8f578b2ad3 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/precomp.h @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#include +#include +#pragma warning( disable:4127 ) +#include +#include +#include + +#include "macros.h" +#include "stringu.h" +#include "stringa.h" +#include "dbgutil.h" +#include "ntassert.h" +#include "ahutil.h" +#include "acache.h" +#include "base64.hxx" diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/stringa.cpp b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/stringa.cpp new file mode 100644 index 0000000000..6380535473 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/stringa.cpp @@ -0,0 +1,1767 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#include "precomp.h" + +STRA::STRA( + VOID +) : m_cchLen( 0 ) +{ + *( QueryStr() ) = '\0'; +} + +STRA::STRA( + __inout_ecount(cchInit) CHAR* pbInit, + __in DWORD cchInit +) : m_Buff( pbInit, cchInit * sizeof( CHAR ) ), + m_cchLen(0) +/*++ + Description: + + Used by STACK_STRA. Initially populates underlying buffer with pbInit. + + pbInit is not freed. + + Arguments: + + pbInit - initial memory to use + cchInit - count, in characters, of pbInit + + Returns: + + None. + +--*/ +{ + _ASSERTE( NULL != pbInit ); + _ASSERTE( cchInit > 0 ); + _ASSERTE( pbInit[0] == '\0' ); +} + +BOOL +STRA::IsEmpty( + VOID +) const +{ + return ( m_cchLen == 0 ); +} + +BOOL +STRA::Equals( + __in PCSTR pszRhs, + __in BOOL fIgnoreCase /*= FALSE*/ +) const +{ + _ASSERTE( NULL != pszRhs ); + + if( fIgnoreCase ) + { + return ( 0 == _stricmp( QueryStr(), pszRhs ) ); + } + + return ( 0 == strcmp( QueryStr(), pszRhs ) ); +} + +BOOL +STRA::Equals( + __in const STRA * pstrRhs, + __in BOOL fIgnoreCase /*= FALSE*/ +) const +{ + _ASSERTE( NULL != pstrRhs ); + return Equals( pstrRhs->QueryStr(), fIgnoreCase ); +} + +BOOL +STRA::Equals( + __in const STRA & strRhs, + __in BOOL fIgnoreCase /*= FALSE*/ +) const +{ + return Equals( strRhs.QueryStr(), fIgnoreCase ); +} + +DWORD +STRA::QueryCB( + VOID +) const +// +// Returns the number of bytes in the string excluding the terminating NULL +// +{ + return m_cchLen * sizeof( CHAR ); +} + +DWORD +STRA::QueryCCH( + VOID +) const +// +// Returns the number of characters in the string excluding the terminating NULL +// +{ + return m_cchLen; +} + +DWORD +STRA::QuerySizeCCH( + VOID +) const +// +// Returns size of the underlying storage buffer, in characters +// +{ + return m_Buff.QuerySize() / sizeof( CHAR ); +} + +DWORD +STRA::QuerySize( + VOID +) const +// +// Returns the size of the storage buffer in bytes +// +{ + return m_Buff.QuerySize(); +} + +__nullterminated +__bcount(this->m_cchLen) +CHAR * +STRA::QueryStr( + VOID +) const +// +// Return the string buffer +// +{ + return m_Buff.QueryPtr(); +} + +VOID +STRA::Reset( + VOID +) +// +// Resets the internal string to be NULL string. Buffer remains cached. +// +{ + _ASSERTE( QueryStr() != NULL ); + *(QueryStr()) = '\0'; + m_cchLen = 0; +} + +HRESULT +STRA::Resize( + __in DWORD cchSize +) +{ + if( !m_Buff.Resize( cchSize * sizeof( CHAR ) ) ) + { + return E_OUTOFMEMORY; + } + + return S_OK; +} + +HRESULT +STRA::SyncWithBuffer( + VOID +) +// +// Recalculate the length of the string, etc. because we've modified +// the buffer directly. +// +{ + HRESULT hr; + size_t size; + hr = StringCchLengthA( QueryStr(), + QuerySizeCCH(), + &size ); + if ( SUCCEEDED( hr ) ) + { + m_cchLen = static_cast(size); + } + return hr; +} + +HRESULT +STRA::Copy( + __in PCSTR pszCopy +) +{ + HRESULT hr; + size_t cbLen; + hr = StringCbLengthA( pszCopy, + STRSAFE_MAX_CCH, + &cbLen ); + if ( FAILED( hr ) ) + { + return hr; + } + return Copy( pszCopy, cbLen ); +} + + +HRESULT +STRA::Copy( + __in_ecount(cchLen) + PCSTR pszCopy, + __in SIZE_T cbLen +) +// +// Copy the contents of another string to this one +// +{ + _ASSERTE( cbLen <= MAXDWORD ); + + return AuxAppend( + pszCopy, + static_cast(cbLen), + 0 + ); +} + +HRESULT +STRA::Copy( + __in const STRA * pstrRhs +) +{ + _ASSERTE( pstrRhs != NULL ); + return Copy( pstrRhs->QueryStr(), pstrRhs->QueryCCH() ); +} + +HRESULT +STRA::Copy( + __in const STRA & strRhs +) +{ + return Copy( strRhs.QueryStr(), strRhs.QueryCCH() ); +} + +HRESULT +STRA::CopyW( + __in PCWSTR pszCopyW +) +{ + HRESULT hr; + size_t cchLen; + hr = StringCchLengthW( pszCopyW, + STRSAFE_MAX_CCH, + &cchLen ); + if ( FAILED( hr ) ) + { + return hr; + } + return CopyW( pszCopyW, cchLen ); +} + +HRESULT +STRA::CopyWTruncate( + __in PCWSTR pszCopyWTruncate +) +{ + HRESULT hr; + size_t cchLen; + hr = StringCchLengthW( pszCopyWTruncate, + STRSAFE_MAX_CCH, + &cchLen ); + if ( FAILED( hr ) ) + { + return hr; + } + return CopyWTruncate( pszCopyWTruncate, cchLen ); +} + +HRESULT +STRA::CopyWTruncate( + __in_ecount(cchLen) + PCWSTR pszCopyWTruncate, + __in SIZE_T cchLen +) +// +// The "Truncate" methods do not do proper conversion. They do a (CHAR) caste +// +{ + _ASSERTE( cchLen <= MAXDWORD ); + + return AuxAppendWTruncate( + pszCopyWTruncate, + static_cast(cchLen), + 0 + ); +} + +HRESULT +STRA::Append( + __in PCSTR pszAppend +) +{ + HRESULT hr; + size_t cbLen; + hr = StringCbLengthA( pszAppend, + STRSAFE_MAX_CCH, + &cbLen ); + if ( FAILED( hr ) ) + { + return hr; + } + return Append( pszAppend, cbLen ); +} + +HRESULT +STRA::Append( + __in_ecount(cchLen) + PCSTR pszAppend, + __in SIZE_T cbLen +) +{ + _ASSERTE( cbLen <= MAXDWORD ); + if ( cbLen == 0 ) + { + return S_OK; + } + return AuxAppend( + pszAppend, + static_cast(cbLen), + QueryCB() + ); +} + +HRESULT +STRA::Append( + __in const STRA * pstrRhs +) +{ + _ASSERTE( pstrRhs != NULL ); + return Append( pstrRhs->QueryStr(), pstrRhs->QueryCCH() ); +} + +HRESULT +STRA::Append( + __in const STRA & strRhs +) +{ + return Append( strRhs.QueryStr(), strRhs.QueryCCH() ); +} + +HRESULT +STRA::AppendWTruncate( + __in PCWSTR pszAppendWTruncate +) +{ + HRESULT hr; + size_t cchLen; + hr = StringCchLengthW( pszAppendWTruncate, + STRSAFE_MAX_CCH, + &cchLen ); + if ( FAILED( hr ) ) + { + return hr; + } + return AppendWTruncate( pszAppendWTruncate, cchLen ); +} + +HRESULT +STRA::AppendWTruncate( + __in_ecount(cchLen) + PCWSTR pszAppendWTruncate, + __in SIZE_T cchLen +) +// +// The "Truncate" methods do not do proper conversion. They do a (CHAR) caste +// +{ + _ASSERTE( cchLen <= MAXDWORD ); + if ( cchLen == 0 ) + { + return S_OK; + } + return AuxAppendWTruncate( + pszAppendWTruncate, + static_cast(cchLen), + QueryCB() + ); +} + +HRESULT +STRA::CopyToBuffer( + __out_bcount(*pcb) CHAR* pszBuffer, + __inout DWORD * pcb +) const +// +// Makes a copy of the stored string into the given buffer +// +{ + _ASSERTE( NULL != pszBuffer ); + _ASSERTE( NULL != pcb ); + + HRESULT hr = S_OK; + DWORD cbNeeded = QueryCB() + sizeof( CHAR ); + + if( *pcb < cbNeeded ) + { + hr = HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER ); + goto Finished; + } + + memcpy( pszBuffer, QueryStr(), cbNeeded ); + +Finished: + + *pcb = cbNeeded; + + return hr; +} + +HRESULT +STRA::SetLen( + __in DWORD cchLen +) +/*++ + * +Routine Description: + + Set the length of the string and null terminate, if there + is sufficient buffer already allocated. Will not reallocate. + +Arguments: + + cchLen - The number of characters in the new string. + +Return Value: + + HRESULT + +--*/ +{ + if( cchLen >= QuerySizeCCH() ) + { + return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); + } + + *( QueryStr() + cchLen ) = '\0'; + m_cchLen = cchLen; + + return S_OK; +} + + +HRESULT +STRA::SafeSnprintf( + __in __format_string + PCSTR pszFormatString, + ... +) +/*++ + +Routine Description: + + Writes to a STRA, growing it as needed. It arbitrarily caps growth at 64k chars. + +Arguments: + + pszFormatString - printf format + ... - printf args + +Return Value: + + HRESULT + +--*/ +{ + HRESULT hr = S_OK; + va_list argsList; + va_start( argsList, pszFormatString ); + + hr = SafeVsnprintf(pszFormatString, argsList); + + va_end( argsList ); + return hr; +} + +HRESULT +STRA::SafeVsnprintf( + __in __format_string + PCSTR pszFormatString, + va_list argsList +) +/*++ + +Routine Description: + + Writes to a STRA, growing it as needed. It arbitrarily caps growth at 64k chars. + +Arguments: + + pszFormatString - printf format + argsList - printf va_list + +Return Value: + + HRESULT + +--*/ +{ + HRESULT hr = S_OK; + int cchOutput; + int cchNeeded; + + // + // Format the incoming message using vsnprintf() + // so that the overflows are captured + // + cchOutput = _vsnprintf_s( + QueryStr(), + QuerySizeCCH(), + QuerySizeCCH() - 1, + pszFormatString, + argsList + ); + + if( cchOutput == -1 ) + { + // + // Couldn't fit this in the original STRU size. + // + cchNeeded = _vscprintf( pszFormatString, argsList ); + if( cchNeeded > 64 * 1024 ) + { + // + // If we're trying to produce a string > 64k chars, then + // there is probably a problem + // + hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA ); + goto Finished; + } + + // + // _vscprintf doesn't include terminating null character + // + cchNeeded++; + + hr = Resize( cchNeeded ); + if( FAILED( hr ) ) + { + goto Finished; + } + + cchOutput = _vsnprintf_s( + QueryStr(), + QuerySizeCCH(), + QuerySizeCCH() - 1, + pszFormatString, + argsList + ); + if( -1 == cchOutput ) + { + // + // This should never happen, cause we should already have correctly sized memory + // + _ASSERTE( FALSE ); + + hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA ); + goto Finished; + } + } + + // + // always null terminate at the last WCHAR + // + QueryStr()[ QuerySizeCCH() - 1 ] = L'\0'; + + // + // we directly touched the buffer - therefore: + // + hr = SyncWithBuffer(); + if( FAILED( hr ) ) + { + goto Finished; + } + +Finished: + + if( FAILED( hr ) ) + { + Reset(); + } + + return hr; +} + +bool +FShouldEscapeUtf8( + BYTE ch + ) +{ + if ( ( ch >= 128 ) ) + { + return true; + } + + return false; +} + +bool +FShouldEscapeUrl( + BYTE ch + ) +{ + if ( ( ch >= 128 || + ch <= 32 || + ch == '<' || + ch == '>' || + ch == '%' || + ch == '?' || + ch == '#' ) && + !( ch == '\n' || ch == '\r' ) ) + { + return true; + } + + return false; +} + +HRESULT +STRA::Escape( + VOID +) +/*++ + +Routine Description: + + Escapes a STRA + +Arguments: + + None + +Return Value: + + None + +--*/ +{ + return EscapeInternal( FShouldEscapeUrl ); +} + +HRESULT +STRA::EscapeUtf8( + VOID +) +/*++ + +Routine Description: + + Escapes the high-bit chars in a STRA. LWS, CR, LF & controls are untouched. + +Arguments: + + None + +Return Value: + + None + +--*/ +{ + return EscapeInternal( FShouldEscapeUtf8 ); +} + + +HRESULT +STRA::EscapeInternal( + PFN_F_SHOULD_ESCAPE pfnFShouldEscape +) +/*++ + +Routine Description: + + Escapes a STRA according to the predicate function passed in + +Arguments: + + None + +Return Value: + + None + +--*/ +{ + LPCSTR pch = QueryStr(); + __analysis_assume( pch != NULL ); + int i = 0; + BYTE ch; + HRESULT hr = S_OK; + BOOL fRet = FALSE; + SIZE_T NewSize = 0; + + // Set to true if any % escaping occurs + BOOL fEscapingDone = FALSE; + + // + // If there are any characters that need to be escaped we copy the entire string + // character by character into straTemp, escaping as we go, then at the end + // copy all of straTemp over. Don't modify InlineBuffer directly. + // + CHAR InlineBuffer[512]; + InlineBuffer[0] = '\0'; + STRA straTemp(InlineBuffer, sizeof(InlineBuffer)/sizeof(*InlineBuffer)); + + _ASSERTE( pch ); + + while (ch = pch[i]) + { + // + // Escape characters that are in the non-printable range + // but ignore CR and LF + // + + if ( pfnFShouldEscape( ch ) ) + { + if (FALSE == fEscapingDone) + { + // first character in the string that needed escaping + fEscapingDone = TRUE; + + // guess that the size needs to be larger than + // what we used to have times two + NewSize = QueryCCH() * 2; + if ( NewSize > MAXDWORD ) + { + hr = HRESULT_FROM_WIN32( ERROR_ARITHMETIC_OVERFLOW ); + return hr; + } + + hr = straTemp.Resize( static_cast(NewSize) ); + + if (FAILED(hr)) + { + return hr; + } + + // Copy all of the previous buffer into buffTemp, only if it is not the first character: + + if ( i > 0) + { + hr = straTemp.Copy(QueryStr(), + i * sizeof(CHAR)); + if (FAILED(hr)) + { + return hr; + } + } + } + + // resize the temporary (if needed) with the slop of the entire buffer length + // this fixes constant reallocation if the entire string needs to be escaped + NewSize = QueryCCH() + 2 * sizeof(CHAR) + 1 * sizeof(CHAR); + if ( NewSize > MAXDWORD ) + { + hr = HRESULT_FROM_WIN32( ERROR_ARITHMETIC_OVERFLOW ); + return hr; + } + + fRet = straTemp.m_Buff.Resize( NewSize ); + if ( !fRet ) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + return hr; + } + + // + // Create the string to append for the current character + // + + CHAR chHex[3]; + chHex[0] = '%'; + + // + // Convert the low then the high character to hex + // + + UINT nLowDigit = (UINT)(ch % 16); + chHex[2] = TODIGIT( nLowDigit ); + + ch /= 16; + + UINT nHighDigit = (UINT)(ch % 16); + + chHex[1] = TODIGIT( nHighDigit ); + + // + // Actually append the converted character to the end of the temporary + // + hr = straTemp.Append(chHex, 3); + if (FAILED(hr)) + { + return hr; + } + } + else + { + // if no escaping done, no need to copy + if (fEscapingDone) + { + // if ANY escaping done, copy current character into new buffer + straTemp.Append(&pch[i], 1); + } + } + + // inspect the next character in the string + i++; + } + + if (fEscapingDone) + { + // the escaped string is now in straTemp + hr = Copy(straTemp); + } + + return hr; + +} // EscapeInternal() + +VOID +STRA::Unescape( + VOID +) +/*++ + +Routine Description: + + Unescapes a STRA + + Supported escape sequences are: + %uxxxx unescapes Unicode character xxxx into system codepage + %xx unescapes character xx + % without following hex digits is ignored + +Arguments: + + None + +Return Value: + + None + +--*/ +{ + CHAR *pScan; + CHAR *pDest; + CHAR *pNextScan; + WCHAR wch; + DWORD dwLen; + BOOL fChanged = FALSE; + + // + // Now take care of any escape characters + // + pDest = pScan = strchr(QueryStr(), '%'); + + while (pScan) + { + if ((pScan[1] == 'u' || pScan[1] == 'U') && + SAFEIsXDigit(pScan[2]) && + SAFEIsXDigit(pScan[3]) && + SAFEIsXDigit(pScan[4]) && + SAFEIsXDigit(pScan[5])) + { + wch = TOHEX(pScan[2]) * 4096 + TOHEX(pScan[3]) * 256 + + TOHEX(pScan[4]) * 16 + TOHEX(pScan[5]); + + dwLen = WideCharToMultiByte(CP_ACP, + WC_NO_BEST_FIT_CHARS, + &wch, + 1, + (LPSTR) pDest, + 6, + NULL, + NULL); + + pDest += dwLen; + pScan += 6; + fChanged = TRUE; + } + else if (SAFEIsXDigit(pScan[1]) && SAFEIsXDigit(pScan[2])) + { + *pDest = TOHEX(pScan[1]) * 16 + TOHEX(pScan[2]); + + pDest ++; + pScan += 3; + fChanged = TRUE; + } + else // Not an escaped char, just a '%' + { + if (fChanged) + { + *pDest = *pScan; + } + + pDest++; + pScan++; + } + + // + // Copy all the information between this and the next escaped char + // + pNextScan = strchr(pScan, '%'); + + if (fChanged) // pScan!=pDest, so we have to copy the char's + { + if (!pNextScan) // That was the last '%' in the string + { + memmove(pDest, + pScan, + QueryCCH() - DIFF(pScan - QueryStr()) + 1); + } + else + { + // There is another '%', move intermediate chars + if ((dwLen = (DWORD)DIFF(pNextScan - pScan)) != 0) + { + memmove(pDest, + pScan, + dwLen); + pDest += dwLen; + } + } + } + + pScan = pNextScan; + } + + if (fChanged) + { + m_cchLen = (DWORD)strlen(QueryStr()); // for safety recalc the length + } + + return; +} + +HRESULT +STRA::CopyWToUTF8Unescaped( + __in LPCWSTR cpchStr +) +{ + return STRA::CopyWToUTF8Unescaped(cpchStr, (DWORD) wcslen(cpchStr)); +} + +HRESULT +STRA::CopyWToUTF8Unescaped( + __in_ecount(cch) + LPCWSTR cpchStr, + __in DWORD cch +) +{ + HRESULT hr = S_OK; + int iRet; + + if (cch == 0) + { + Reset(); + return S_OK; + } + + iRet = ConvertUnicodeToUTF8(cpchStr, + &m_Buff, + cch); + if (-1 == iRet) + { + // could not convert + hr = HRESULT_FROM_WIN32(GetLastError()); + goto Finished; + } + + m_cchLen = iRet; + + _ASSERTE(strlen(m_Buff.QueryPtr()) == m_cchLen); +Finished: + return hr; +} + +HRESULT +STRA::CopyWToUTF8Escaped( + __in LPCWSTR cpchStr +) +{ + return STRA::CopyWToUTF8Escaped(cpchStr, (DWORD) wcslen(cpchStr)); +} + +HRESULT +STRA::CopyWToUTF8Escaped( + __in_ecount(cch) + LPCWSTR cpchStr, + __in DWORD cch +) +{ + HRESULT hr = S_OK; + + hr = CopyWToUTF8Unescaped(cpchStr, cch); + if (FAILED(hr)) + { + goto Finished; + } + + hr = Escape(); + if (FAILED(hr)) + { + goto Finished; + } + + hr = S_OK; +Finished: + return hr; +} + +HRESULT +STRA::AuxAppend( + __in_ecount(cbLen) + LPCSTR pStr, + __in DWORD cbLen, + __in DWORD cbOffset +) +{ + _ASSERTE( NULL != pStr ); + _ASSERTE( cbOffset <= QueryCB() ); + + ULONGLONG cb64NewSize = (ULONGLONG)cbOffset + cbLen + sizeof( CHAR ); + if( cb64NewSize > MAXDWORD ) + { + return HRESULT_FROM_WIN32( ERROR_ARITHMETIC_OVERFLOW ); + } + + if( m_Buff.QuerySize() < cb64NewSize ) + { + if( !m_Buff.Resize( static_cast(cb64NewSize) ) ) + { + return E_OUTOFMEMORY; + } + } + + memcpy( reinterpret_cast(m_Buff.QueryPtr()) + cbOffset, pStr, cbLen ); + + m_cchLen = cbLen + cbOffset; + + *( QueryStr() + m_cchLen ) = '\0'; + + return S_OK; +} + +HRESULT +STRA::AuxAppendW( + __in_ecount(cchAppendW) + PCWSTR pszAppendW, + __in DWORD cchAppendW, + __in DWORD cbOffset, + __in UINT CodePage, + __in BOOL fFailIfNoTranslation, + __in DWORD dwFlags +) +{ + HRESULT hr = S_OK; + DWORD cbAvailable = 0; + DWORD cbRet = 0; + + // + // There are only two expect places to append + // + _ASSERTE( 0 == cbOffset || QueryCB() == cbOffset ); + + if ( cchAppendW == 0 ) + { + goto Finished; + } + + // + // start by assuming 1 char to 1 char will be enough space + // + if( !m_Buff.Resize( cbOffset + cchAppendW + sizeof( CHAR ) ) ) + { + hr = E_OUTOFMEMORY; + goto Finished; + } + + cbAvailable = m_Buff.QuerySize() - cbOffset; + + cbRet = WideCharToMultiByte( + CodePage, + dwFlags, + pszAppendW, + cchAppendW, + QueryStr() + cbOffset, + cbAvailable, + NULL, + NULL + ); + if( 0 != cbRet ) + { + if(!m_Buff.Resize(cbOffset + cbRet + 1)) + { + hr = E_OUTOFMEMORY; + } + + // + // not zero --> success, so we're done + // + goto Finished; + } + + // + // We only know how to handle ERROR_INSUFFICIENT_BUFFER + // + hr = HRESULT_FROM_WIN32( GetLastError() ); + if( hr != HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER ) ) + { + goto Finished; + } + + // + // Reset HResult because we need to get the number of bytes needed + // + hr = S_OK; + cbRet = WideCharToMultiByte( + CodePage, + dwFlags, + pszAppendW, + cchAppendW, + NULL, + 0, + NULL, + NULL + ); + if( 0 == cbRet ) + { + // + // no idea how we could ever reach here + // + hr = HRESULT_FROM_WIN32( GetLastError() ); + goto Finished; + } + + if( !m_Buff.Resize( cbOffset + cbRet + 1) ) + { + hr = E_OUTOFMEMORY; + goto Finished; + } + + cbAvailable = m_Buff.QuerySize() - cbOffset; + + cbRet = WideCharToMultiByte( + CodePage, + dwFlags, + pszAppendW, + cchAppendW, + QueryStr() + cbOffset, + cbAvailable, + NULL, + NULL + ); + if( 0 == cbRet ) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + goto Finished; + } + +Finished: + + if( SUCCEEDED( hr ) && 0 != cbRet ) + { + m_cchLen = cbRet + cbOffset; + } + + // + // ensure we're still NULL terminated in the right spot + // (regardless of success or failure) + // + QueryStr()[m_cchLen] = '\0'; + + return hr; +} + +HRESULT +STRA::AuxAppendWTruncate( + __in_ecount(cchAppendW) + __in PCWSTR pszAppendW, + __in DWORD cchAppendW, + __in DWORD cbOffset +) +// +// Cheesey WCHAR --> CHAR conversion +// +{ + HRESULT hr = S_OK; + CHAR* pszBuffer; + + _ASSERTE( NULL != pszAppendW ); + _ASSERTE( 0 == cbOffset || cbOffset == QueryCB() ); + + if( !pszAppendW ) + { + hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); + goto Finished; + } + + ULONGLONG cbNeeded = (ULONGLONG)cbOffset + cchAppendW + sizeof( CHAR ); + if( cbNeeded > MAXDWORD ) + { + hr = HRESULT_FROM_WIN32( ERROR_ARITHMETIC_OVERFLOW ); + goto Finished; + } + + if( !m_Buff.Resize( static_cast(cbNeeded) ) ) + { + hr = E_OUTOFMEMORY; + goto Finished; + } + + // + // Copy/convert the UNICODE string over (by making two bytes into one) + // + pszBuffer = QueryStr() + cbOffset; + for( DWORD i = 0; i < cchAppendW; i++ ) + { + pszBuffer[i] = static_cast(pszAppendW[i]); + } + + m_cchLen = cchAppendW + cbOffset; + *( QueryStr() + m_cchLen ) = '\0'; + +Finished: + + return hr; +} + +// static +int +STRA::ConvertUnicodeToCodePage( + __in_ecount(dwStringLen) + LPCWSTR pszSrcUnicodeString, + __inout BUFFER_T * pbufDstAnsiString, + __in DWORD dwStringLen, + __in UINT uCodePage +) +{ + _ASSERTE(NULL != pszSrcUnicodeString); + _ASSERTE(NULL != pbufDstAnsiString); + + BOOL bTemp; + int iStrLen = 0; + DWORD dwFlags; + + if (uCodePage == CP_ACP) + { + dwFlags = WC_NO_BEST_FIT_CHARS; + } + else + { + dwFlags = 0; + } + + iStrLen = WideCharToMultiByte(uCodePage, + dwFlags, + pszSrcUnicodeString, + dwStringLen, + (LPSTR)pbufDstAnsiString->QueryPtr(), + (int)pbufDstAnsiString->QuerySize(), + NULL, + NULL); + if ((iStrLen == 0) && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) { + iStrLen = WideCharToMultiByte(uCodePage, + dwFlags, + pszSrcUnicodeString, + dwStringLen, + NULL, + 0, + NULL, + NULL); + if (iStrLen != 0) { + // add one just for the extra NULL + bTemp = pbufDstAnsiString->Resize(iStrLen + 1); + if (!bTemp) + { + iStrLen = 0; + } + else + { + iStrLen = WideCharToMultiByte(uCodePage, + dwFlags, + pszSrcUnicodeString, + dwStringLen, + (LPSTR)pbufDstAnsiString->QueryPtr(), + (int)pbufDstAnsiString->QuerySize(), + NULL, + NULL); + } + + } + } + + if (0 != iStrLen && + pbufDstAnsiString->Resize(iStrLen + 1)) + { + // insert a terminating NULL into buffer for the dwStringLen+1 in the case that the dwStringLen+1 was not a NULL. + ((CHAR*)pbufDstAnsiString->QueryPtr())[iStrLen] = '\0'; + } + else + { + iStrLen = -1; + } + + return iStrLen; +} + +// static +HRESULT +STRA::ConvertUnicodeToMultiByte( + __in_ecount(dwStringLen) + LPCWSTR pszSrcUnicodeString, + __in BUFFER_T * pbufDstAnsiString, + __in DWORD dwStringLen +) +{ + return ConvertUnicodeToCodePage( pszSrcUnicodeString, + pbufDstAnsiString, + dwStringLen, + CP_ACP ); +} + +// static +HRESULT +STRA::ConvertUnicodeToUTF8( + __in_ecount(dwStringLen) + LPCWSTR pszSrcUnicodeString, + __in BUFFER_T * pbufDstAnsiString, + __in DWORD dwStringLen +) +{ + return ConvertUnicodeToCodePage( pszSrcUnicodeString, + pbufDstAnsiString, + dwStringLen, + CP_UTF8 ); +} + +/*++ + +Routine Description: + + Removes leading and trailing whitespace + +--*/ + +VOID +STRA::Trim() +{ + PSTR pszString = QueryStr(); + DWORD cchNewLength = m_cchLen; + DWORD cchLeadingWhitespace = 0; + DWORD cchTempLength = 0; + + for (LONG ixString = m_cchLen - 1; ixString >= 0; ixString--) + { + if (isspace((unsigned char) pszString[ixString]) != 0) + { + pszString[ixString] = '\0'; + cchNewLength--; + } + else + { + break; + } + } + + cchTempLength = cchNewLength; + for (DWORD ixString = 0; ixString < cchTempLength; ixString++) + { + if (isspace((unsigned char) pszString[ixString]) != 0) + { + cchLeadingWhitespace++; + cchNewLength--; + } + else + { + break; + } + } + + if (cchNewLength == 0) + { + + Reset(); + } + else if (cchLeadingWhitespace > 0) + { + memmove(pszString, pszString + cchLeadingWhitespace, cchNewLength * sizeof(CHAR)); + pszString[cchNewLength] = '\0'; + } + + SyncWithBuffer(); +} + +/*++ + +Routine Description: + + Compares the string to the provided prefix to check for equality + +Arguments: + + pStraPrefix - string to compare with + fIgnoreCase - indicates whether the string comparison should be case-sensitive + +Return Value: + + TRUE if prefix string matches with internal string, FALSE otherwise + +--*/ +BOOL +STRA::StartsWith( + __in const STRA * pStraPrefix, + __in bool fIgnoreCase) const +{ + _ASSERTE( pStraPrefix != NULL ); + return StartsWith(pStraPrefix->QueryStr(), fIgnoreCase); +} + +/*++ + +Routine Description: + + Compares the string to the provided prefix to check for equality + +Arguments: + + straPrefix - string to compare with + fIgnoreCase - indicates whether the string comparison should be case-sensitive + +Return Value: + + TRUE if prefix string matches with internal string, FALSE otherwise + +--*/ +BOOL +STRA::StartsWith( + __in const STRA & straPrefix, + __in bool fIgnoreCase) const +{ + return StartsWith(straPrefix.QueryStr(), fIgnoreCase); +} + +/*++ + +Routine Description: + + Compares the string to the provided prefix to check for equality + +Arguments: + + pszPrefix - string to compare with + fIgnoreCase - indicates whether the string comparison should be case-sensitive + +Return Value: + + TRUE if prefix string matches with internal string, FALSE otherwise + +--*/ +BOOL +STRA::StartsWith( + __in PCSTR pszPrefix, + __in bool fIgnoreCase) const +{ + HRESULT hr = S_OK; + BOOL fMatch = FALSE; + size_t cchPrefix = 0; + + if (pszPrefix == NULL) + { + goto Finished; + } + + hr = StringCchLengthA( pszPrefix, + STRSAFE_MAX_CCH, + &cchPrefix ); + if (FAILED(hr)) + { + goto Finished; + } + + _ASSERTE( cchPrefix <= MAXDWORD ); + + if (cchPrefix > m_cchLen) + { + goto Finished; + } + + if( fIgnoreCase ) + { + fMatch = ( 0 == _strnicmp( QueryStr(), pszPrefix, cchPrefix ) ); + } + else + { + fMatch = ( 0 == strncmp( QueryStr(), pszPrefix, cchPrefix ) ); + } + + +Finished: + + return fMatch; +} + +/*++ + +Routine Description: + + Compares the string to the provided suffix to check for equality + +Arguments: + + pStraSuffix - string to compare with + fIgnoreCase - indicates whether the string comparison should be case-sensitive + +Return Value: + + TRUE if suffix string matches with internal string, FALSE otherwise + +--*/ +BOOL +STRA::EndsWith( + __in const STRA * pStraSuffix, + __in bool fIgnoreCase) const +{ + _ASSERTE( pStraSuffix != NULL ); + return EndsWith(pStraSuffix->QueryStr(), fIgnoreCase); +} + + +/*++ + +Routine Description: + + Compares the string to the provided suffix to check for equality + +Arguments: + + straSuffix - string to compare with + fIgnoreCase - indicates whether the string comparison should be case-sensitive + +Return Value: + + TRUE if suffix string matches with internal string, FALSE otherwise + +--*/ +BOOL +STRA::EndsWith( + __in const STRA & straSuffix, + __in bool fIgnoreCase) const +{ + return EndsWith(straSuffix.QueryStr(), fIgnoreCase); +} + + +/*++ + +Routine Description: + + Compares the string to the provided suffix to check for equality + +Arguments: + + pszSuffix - string to compare with + fIgnoreCase - indicates whether the string comparison should be case-sensitive + +Return Value: + + TRUE if suffix string matches with internal string, FALSE otherwise + +--*/ +BOOL +STRA::EndsWith( + __in PCSTR pszSuffix, + __in bool fIgnoreCase) const +{ + HRESULT hr = S_OK; + PSTR pszString = QueryStr(); + BOOL fMatch = FALSE; + size_t cchSuffix = 0; + ptrdiff_t ixOffset = 0; + + if (pszSuffix == NULL) + { + goto Finished; + } + + hr = StringCchLengthA( pszSuffix, + STRSAFE_MAX_CCH, + &cchSuffix ); + if (FAILED(hr)) + { + goto Finished; + } + + _ASSERTE( cchSuffix <= MAXDWORD ); + + if (cchSuffix > m_cchLen) + { + goto Finished; + } + + ixOffset = m_cchLen - cchSuffix; + _ASSERTE(ixOffset >= 0 && ixOffset <= MAXDWORD); + + if( fIgnoreCase ) + { + fMatch = ( 0 == _strnicmp( pszString + ixOffset, pszSuffix, cchSuffix ) ); + } + else + { + fMatch = ( 0 == strncmp( pszString + ixOffset, pszSuffix, cchSuffix ) ); + } + +Finished: + + return fMatch; +} + + +/*++ + +Routine Description: + + Searches the string for the first occurrence of the specified character. + +Arguments: + + charValue - character to find + dwStartIndex - the initial index. + +Return Value: + + The index for the first character occurence in the string. + + -1 if not found. + +--*/ +INT +STRA::IndexOf( + __in CHAR charValue, + __in DWORD dwStartIndex + ) const +{ + INT nIndex = -1; + + // Make sure that there are no buffer overruns. + if( dwStartIndex >= QueryCCH() ) + { + goto Finished; + } + + const CHAR* pChar = strchr( QueryStr() + dwStartIndex, charValue ); + + // Determine the index if found + if( pChar ) + { + // nIndex will be set to -1 on failure. + (VOID)SizeTToInt( pChar - QueryStr(), &nIndex ); + } + +Finished: + + return nIndex; +} + + +/*++ + +Routine Description: + + Searches the string for the first occurrence of the specified substring. + +Arguments: + + pszValue - substring to find + dwStartIndex - initial index. + +Return Value: + + The index for the first character occurence in the string. + + -1 if not found. + +--*/ +INT +STRA::IndexOf( + __in PCSTR pszValue, + __in DWORD dwStartIndex + ) const +{ + HRESULT hr = S_OK; + INT nIndex = -1; + SIZE_T cchValue = 0; + + // Validate input parameters + if( dwStartIndex >= QueryCCH() || !pszValue ) + { + goto Finished; + } + + const CHAR* pChar = strstr( QueryStr() + dwStartIndex, pszValue ); + + // Determine the index if found + if( pChar ) + { + // nIndex will be set to -1 on failure. + (VOID)SizeTToInt( pChar - QueryStr(), &nIndex ); + } + +Finished: + + return nIndex; +} + + +/*++ + +Routine Description: + + Searches the string for the last occurrence of the specified character. + +Arguments: + + charValue - character to find + dwStartIndex - initial index. + +Return Value: + + The index for the last character occurence in the string. + + -1 if not found. + +--*/ +INT +STRA::LastIndexOf( + __in CHAR charValue, + __in DWORD dwStartIndex + ) const +{ + INT nIndex = -1; + + // Make sure that there are no buffer overruns. + if( dwStartIndex >= QueryCCH() ) + { + goto Finished; + } + + const CHAR* pChar = strrchr( QueryStr() + dwStartIndex, charValue ); + + // Determine the index if found + if( pChar ) + { + // nIndex will be set to -1 on failure. + (VOID)SizeTToInt( pChar - QueryStr(), &nIndex ); + } + +Finished: + + return nIndex; +} diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/stringu.cpp b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/stringu.cpp new file mode 100644 index 0000000000..4fd2a052f2 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/stringu.cpp @@ -0,0 +1,1289 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#include "precomp.h" + +STRU::STRU( + VOID +) : m_cchLen( 0 ) +{ + *(QueryStr()) = L'\0'; +} + +STRU::STRU( + __inout_ecount(cchInit) WCHAR* pbInit, + __in DWORD cchInit +) : m_Buff( pbInit, cchInit * sizeof( WCHAR ) ), + m_cchLen( 0 ) +/*++ + Description: + + Used by STACK_STRU. Initially populates underlying buffer with pbInit. + + pbInit is not freed. + + Arguments: + + pbInit - initial memory to use + cchInit - count, in characters, of pbInit + + Returns: + + None. + +--*/ +{ + _ASSERTE( cchInit <= (MAXDWORD / sizeof( WCHAR )) ); + _ASSERTE( NULL != pbInit ); + _ASSERTE(cchInit > 0 ); + _ASSERTE(pbInit[0] == L'\0'); +} + +BOOL +STRU::IsEmpty( + VOID +) const +{ + return ( m_cchLen == 0 ); +} + +DWORD +STRU::QueryCB( + VOID +) const +// +// Returns the number of bytes in the string excluding the terminating NULL +// +{ + return m_cchLen * sizeof( WCHAR ); +} + +DWORD +STRU::QueryCCH( + VOID +) const +// +// Returns the number of characters in the string excluding the terminating NULL +// +{ + return m_cchLen; +} + +DWORD +STRU::QuerySizeCCH( + VOID +) const +// +// Returns size of the underlying storage buffer, in characters +// +{ + return m_Buff.QuerySize() / sizeof( WCHAR ); +} + +__nullterminated +__ecount(this->m_cchLen) +WCHAR* +STRU::QueryStr( + VOID +) const +// +// Return the string buffer +// +{ + return m_Buff.QueryPtr(); +} + +VOID +STRU::Reset( + VOID +) +// +// Resets the internal string to be NULL string. Buffer remains cached. +// +{ + _ASSERTE( QueryStr() != NULL ); + *(QueryStr()) = L'\0'; + m_cchLen = 0; +} + +HRESULT +STRU::Resize( + DWORD cchSize +) +{ + SIZE_T cbSize = cchSize * sizeof( WCHAR ); + if ( cbSize > MAXDWORD ) + { + return HRESULT_FROM_WIN32( ERROR_ARITHMETIC_OVERFLOW ); + } + if( !m_Buff.Resize( cbSize ) ) + { + return E_OUTOFMEMORY; + } + + return S_OK; +} + +HRESULT +STRU::SyncWithBuffer( + VOID +) +// +// Recalculate the length of the string, etc. because we've modified +// the buffer directly. +// +{ + HRESULT hr; + size_t size; + hr = StringCchLengthW( QueryStr(), + QuerySizeCCH(), + &size ); + if ( SUCCEEDED( hr ) ) + { + m_cchLen = static_cast(size); + } + return hr; +} + +HRESULT +STRU::Copy( + __in PCWSTR pszCopy +) +{ + HRESULT hr; + size_t cbStr; + + hr = StringCchLengthW( pszCopy, + STRSAFE_MAX_CCH, + &cbStr ); + if ( FAILED( hr ) ) + { + return hr; + } + + _ASSERTE( cbStr <= MAXDWORD ); + return Copy( pszCopy, + cbStr ); +} + +HRESULT +STRU::Copy( + __in_ecount(cchLen) + PCWSTR pszCopy, + SIZE_T cchLen +) +// +// Copy the contents of another string to this one +// +{ + return AuxAppend( pszCopy, + cchLen * sizeof(WCHAR), + 0); +} + +HRESULT +STRU::Copy( + __in const STRU * pstrRhs +) +{ + _ASSERTE( NULL != pstrRhs ); + return Copy( pstrRhs->QueryStr(), pstrRhs->QueryCCH() ); +} + +HRESULT +STRU::Copy( + __in const STRU & str +) +{ + return Copy( str.QueryStr(), str.QueryCCH() ); +} + +HRESULT +STRU::CopyAndExpandEnvironmentStrings( + __in PCWSTR pszSource +) +{ + HRESULT hr = S_OK; + DWORD cchDestReqBuff = 0; + + Reset(); + + cchDestReqBuff = ExpandEnvironmentStringsW( pszSource, + QueryStr(), + QuerySizeCCH() ); + if ( cchDestReqBuff == 0 ) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + goto Finished; + } + else if ( cchDestReqBuff > QuerySizeCCH() ) + { + hr = Resize( cchDestReqBuff ); + if ( FAILED( hr ) ) + { + goto Finished; + } + + cchDestReqBuff = ExpandEnvironmentStringsW( pszSource, + QueryStr(), + QuerySizeCCH() ); + + if ( cchDestReqBuff == 0 || cchDestReqBuff > QuerySizeCCH() ) + { + _ASSERTE( FALSE ); + hr = HRESULT_FROM_WIN32( GetLastError() ); + goto Finished; + } + } + + hr = SyncWithBuffer(); + if ( FAILED( hr ) ) + { + goto Finished; + } + +Finished: + + return hr; + +} + +HRESULT +STRU::CopyA( + __in PCSTR pszCopyA +) +{ + HRESULT hr; + size_t cbStr; + + hr = StringCbLengthA( pszCopyA, + STRSAFE_MAX_CCH, + &cbStr ); + if ( FAILED( hr ) ) + { + return hr; + } + + _ASSERTE( cbStr <= MAXDWORD ); + return CopyA( pszCopyA, + cbStr ); +} + +HRESULT +STRU::CopyA( + __in_bcount(cchLen) + PCSTR pszCopyA, + SIZE_T cchLen, + UINT CodePage /*= CP_UTF8*/ +) +{ + return AuxAppendA( + pszCopyA, + cchLen, + 0, + CodePage + ); +} + +HRESULT +STRU::Append( + __in PCWSTR pszAppend +) +{ + HRESULT hr; + size_t cbStr; + + hr = StringCchLengthW( pszAppend, + STRSAFE_MAX_CCH, + &cbStr ); + if ( FAILED( hr ) ) + { + return hr; + } + + _ASSERTE( cbStr <= MAXDWORD ); + return Append( pszAppend, + cbStr ); +} + +HRESULT +STRU::Append( + __in_ecount(cchLen) + PCWSTR pszAppend, + SIZE_T cchLen +) +// +// Append something to the end of the string +// +{ + if ( cchLen == 0 ) + { + return S_OK; + } + return AuxAppend( pszAppend, + cchLen * sizeof(WCHAR), + QueryCB() ); +} + +HRESULT +STRU::Append( + __in const STRU * pstrRhs +) +{ + _ASSERTE( NULL != pstrRhs ); + return Append( pstrRhs->QueryStr(), pstrRhs->QueryCCH() ); +} + +HRESULT +STRU::Append( + __in const STRU & strRhs +) +{ + return Append( strRhs.QueryStr(), strRhs.QueryCCH() ); +} + +HRESULT +STRU::AppendA( + __in PCSTR pszAppendA +) +{ + HRESULT hr; + size_t cbStr; + + hr = StringCbLengthA( pszAppendA, + STRSAFE_MAX_CCH, + &cbStr ); + if ( FAILED( hr ) ) + { + return hr; + } + + _ASSERTE( cbStr <= MAXDWORD ); + return AppendA( pszAppendA, + cbStr ); +} + +HRESULT +STRU::AppendA( + __in_bcount(cchLen) + PCSTR pszAppendA, + SIZE_T cchLen, + UINT CodePage /*= CP_UTF8*/ +) +{ + if ( cchLen == 0 ) + { + return S_OK; + } + return AuxAppendA( + pszAppendA, + cchLen, + QueryCB(), + CodePage + ); +} + +HRESULT +STRU::CopyToBuffer( + __out_bcount(*pcb) WCHAR* pszBuffer, + PDWORD pcb +) const +// +// Makes a copy of the stored string into the given buffer +// +{ + _ASSERTE( NULL != pszBuffer ); + _ASSERTE( NULL != pcb ); + + HRESULT hr = S_OK; + DWORD cbNeeded = QueryCB() + sizeof( WCHAR ); + + if( *pcb < cbNeeded ) + { + hr = HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER ); + goto Finished; + } + + // + // BUGBUG: StringCchCopy? + // + memcpy( pszBuffer, QueryStr(), cbNeeded ); + +Finished: + + *pcb = cbNeeded; + + return hr; +} + +HRESULT +STRU::CopyToBufferA( + __out_bcount(*pcb) CHAR* pszBuffer, + __inout PDWORD pcb +) const +{ + HRESULT hr = S_OK; + STACK_STRA( straBuffer, 256 ); + hr = straBuffer.CopyW( QueryStr() ); + if ( FAILED( hr ) ) + { + goto Finished; + } + hr = straBuffer.CopyToBuffer( pszBuffer, pcb ); + if ( FAILED( hr ) ) + { + goto Finished; + } +Finished: + return hr; +} + +HRESULT +STRU::SetLen( + __in DWORD cchLen +) +/*++ + * +Routine Description: + + Set the length of the string and null terminate, if there + is sufficient buffer already allocated. Will not reallocate. + +Arguments: + + cchLen - The number of characters in the new string. + +Return Value: + + HRESULT + +--*/ +{ + if( cchLen >= QuerySizeCCH() ) + { + return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); + } + + *( QueryStr() + cchLen ) = L'\0'; + m_cchLen = cchLen; + + return S_OK; +} + +HRESULT +STRU::SafeSnwprintf( + __in PCWSTR pwszFormatString, + ... +) +/*++ + +Routine Description: + + Writes to a STRU, growing it as needed. It arbitrarily caps growth at 64k chars. + +Arguments: + + pwszFormatString - printf format + ... - printf args + +Return Value: + + HRESULT + +--*/ +{ + HRESULT hr = S_OK; + va_list argsList; + va_start( argsList, pwszFormatString ); + + hr = SafeVsnwprintf(pwszFormatString, argsList); + + va_end( argsList ); + return hr; +} + +HRESULT +STRU::SafeVsnwprintf( + __in PCWSTR pwszFormatString, + va_list argsList +) +/*++ + +Routine Description: + + Writes to a STRU, growing it as needed. It arbitrarily caps growth at 64k chars. + +Arguments: + + pwszFormatString - printf format + argsList - printf va_list + +Return Value: + + HRESULT + +--*/ +{ + HRESULT hr = S_OK; + int cchOutput; + int cchNeeded; + + // + // Format the incoming message using vsnprintf() + // so that the overflows are captured + // + cchOutput = _vsnwprintf_s( + QueryStr(), + QuerySizeCCH(), + QuerySizeCCH() - 1, + pwszFormatString, + argsList + ); + + if( cchOutput == -1 ) + { + // + // Couldn't fit this in the original STRU size. + // + cchNeeded = _vscwprintf( pwszFormatString, argsList ); + if( cchNeeded > 64 * 1024 ) + { + // + // If we're trying to produce a string > 64k chars, then + // there is probably a problem + // + hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA ); + goto Finished; + } + + // + // _vscprintf doesn't include terminating null character + // + cchNeeded++; + + hr = Resize( cchNeeded ); + if( FAILED( hr ) ) + { + goto Finished; + } + + cchOutput = _vsnwprintf_s( + QueryStr(), + QuerySizeCCH(), + QuerySizeCCH() - 1, + pwszFormatString, + argsList + ); + if( -1 == cchOutput ) + { + // + // This should never happen, cause we should already have correctly sized memory + // + _ASSERTE( FALSE ); + + hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA ); + goto Finished; + } + } + + // + // always null terminate at the last WCHAR + // + QueryStr()[ QuerySizeCCH() - 1 ] = L'\0'; + + // + // we directly touched the buffer - therefore: + // + hr = SyncWithBuffer(); + if ( FAILED( hr ) ) + { + goto Finished; + } + +Finished: + + if( FAILED( hr ) ) + { + Reset(); + } + + return hr; +} + +HRESULT +STRU::AuxAppend( + __in_ecount(cNumStrings) + PCWSTR const rgpszStrings[], + SIZE_T cNumStrings +) +/*++ + +Routine Description: + + Appends an array of strings of length cNumStrings + +Arguments: + + rgStrings - The array of strings to be appened + cNumStrings - The count of String + +Return Value: + + HRESULT + +--*/ +{ + HRESULT hr = S_OK; + size_t cbStringsTotal = sizeof( WCHAR ); // Account for null-terminator + + // + // Compute total size of the string. + // Resize internal buffer + // Copy each array element one by one to backing buffer + // Update backing buffer string length + // + for ( SIZE_T i = 0; i < cNumStrings; i++ ) + { + _ASSERTE( rgpszStrings[ i ] != NULL ); + if ( NULL == rgpszStrings[ i ] ) + { + return E_INVALIDARG; + } + + size_t cbString = 0; + + hr = StringCbLengthW( rgpszStrings[ i ], + STRSAFE_MAX_CCH * sizeof( WCHAR ), + &cbString ); + if ( FAILED( hr ) ) + { + return hr; + } + + cbStringsTotal += cbString; + + if ( cbStringsTotal > MAXDWORD ) + { + return HRESULT_FROM_WIN32( ERROR_ARITHMETIC_OVERFLOW ); + } + } + + size_t cbBufSizeRequired = QueryCB() + cbStringsTotal; + if ( cbBufSizeRequired > MAXDWORD ) + { + return HRESULT_FROM_WIN32( ERROR_ARITHMETIC_OVERFLOW ); + } + + if( m_Buff.QuerySize() < cbBufSizeRequired ) + { + if( !m_Buff.Resize( cbBufSizeRequired ) ) + { + return E_OUTOFMEMORY; + } + } + + STRSAFE_LPWSTR pszStringEnd = QueryStr() + QueryCCH(); + size_t cchRemaining = QuerySizeCCH() - QueryCCH(); + for ( SIZE_T i = 0; i < cNumStrings; i++ ) + { + hr = StringCchCopyExW( pszStringEnd, // pszDest + cchRemaining, // cchDest + rgpszStrings[ i ], // pszSrc + &pszStringEnd, // ppszDestEnd + &cchRemaining, // pcchRemaining + 0 ); // dwFlags + if ( FAILED( hr ) ) + { + _ASSERTE( FALSE ); + HRESULT hr2 = SyncWithBuffer(); + if ( FAILED( hr2 ) ) + { + return hr2; + } + return hr; + } + } + + m_cchLen = static_cast< DWORD >( cbBufSizeRequired ) / sizeof( WCHAR ) - 1; + + return S_OK; +} + +HRESULT +STRU::AuxAppend( + __in_bcount(cbStr) + const WCHAR* pStr, + SIZE_T cbStr, + DWORD cbOffset +) +/*++ + +Routine Description: + + Appends to the string starting at the (byte) offset cbOffset. + +Arguments: + + pStr - A unicode string to be appended + cbStr - Length, in bytes, of pStr + cbOffset - Offset, in bytes, at which to begin the append + +Return Value: + + HRESULT + +--*/ +{ + _ASSERTE( NULL != pStr ); + _ASSERTE( 0 == cbStr % sizeof( WCHAR ) ); + _ASSERTE( cbOffset <= QueryCB() ); + _ASSERTE( 0 == cbOffset % sizeof( WCHAR ) ); + + ULONGLONG cb64NewSize = (ULONGLONG)cbOffset + cbStr + sizeof( WCHAR ); + if( cb64NewSize > MAXDWORD ) + { + return HRESULT_FROM_WIN32( ERROR_ARITHMETIC_OVERFLOW ); + } + + if( m_Buff.QuerySize() < cb64NewSize ) + { + if( !m_Buff.Resize( static_cast(cb64NewSize) ) ) + { + return E_OUTOFMEMORY; + } + } + + memcpy( reinterpret_cast(m_Buff.QueryPtr()) + cbOffset, pStr, cbStr ); + + m_cchLen = (static_cast(cbStr) + cbOffset) / sizeof(WCHAR); + + *( QueryStr() + m_cchLen ) = L'\0'; + + return S_OK; +} + +HRESULT +STRU::AuxAppendA( + __in_bcount(cbStr) + const CHAR* pStr, + SIZE_T cbStr, + DWORD cbOffset, + UINT CodePage +) +/*++ + +Routine Description: + + Convert and append an ANSI string to the string starting at + the (byte) offset cbOffset + +Arguments: + + pStr - An ANSI string to be appended + cbStr - Length, in bytes, of pStr + cbOffset - Offset, in bytes, at which to begin the append + CodePage - code page to use for conversion + +Return Value: + + HRESULT + +--*/ +{ + WCHAR* pszBuffer; + DWORD cchBuffer; + DWORD cchCharsCopied = 0; + + _ASSERTE( NULL != pStr ); + _ASSERTE( cbOffset <= QueryCB() ); + _ASSERTE( 0 == cbOffset % sizeof( WCHAR ) ); + + if ( NULL == pStr ) + { + return E_INVALIDARG; + } + + if( 0 == cbStr ) + { + return S_OK; + } + + // + // Only resize when we have to. When we do resize, we tack on + // some extra space to avoid extra reallocations. + // + if( m_Buff.QuerySize() < (ULONGLONG)cbOffset + (cbStr * sizeof( WCHAR )) + sizeof(WCHAR) ) + { + ULONGLONG cb64NewSize = (ULONGLONG)( cbOffset + cbStr * sizeof(WCHAR) + sizeof( WCHAR ) ); + + // + // Check for the arithmetic overflow + // + if( cb64NewSize > MAXDWORD ) + { + return HRESULT_FROM_WIN32( ERROR_ARITHMETIC_OVERFLOW ); + } + + if( !m_Buff.Resize( static_cast(cb64NewSize) ) ) + { + return E_OUTOFMEMORY; + } + } + + pszBuffer = reinterpret_cast(reinterpret_cast(m_Buff.QueryPtr()) + cbOffset); + cchBuffer = ( m_Buff.QuerySize() - cbOffset - sizeof( WCHAR ) ) / sizeof( WCHAR ); + + cchCharsCopied = MultiByteToWideChar( + CodePage, + MB_ERR_INVALID_CHARS, + pStr, + static_cast(cbStr), + pszBuffer, + cchBuffer + ); + if( 0 == cchCharsCopied ) + { + return HRESULT_FROM_WIN32( GetLastError() ); + } + + // + // set the new length + // + m_cchLen = cchCharsCopied + cbOffset/sizeof(WCHAR); + + // + // Must be less than, cause still need to add NULL + // + _ASSERTE( m_cchLen < QuerySizeCCH() ); + + // + // append NULL character + // + *(QueryStr() + m_cchLen) = L'\0'; + + return S_OK; +} + + +/*++ + +Routine Description: + + Removes leading and trailing whitespace + +--*/ + +VOID +STRU::Trim() +{ + PWSTR pwszString = QueryStr(); + DWORD cchNewLength = m_cchLen; + DWORD cchLeadingWhitespace = 0; + DWORD cchTempLength = 0; + + for (LONG ixString = m_cchLen - 1; ixString >= 0; ixString--) + { + if (iswspace(pwszString[ixString]) != 0) + { + pwszString[ixString] = L'\0'; + cchNewLength--; + } + else + { + break; + } + } + + cchTempLength = cchNewLength; + for (DWORD ixString = 0; ixString < cchTempLength; ixString++) + { + if (iswspace(pwszString[ixString]) != 0) + { + cchLeadingWhitespace++; + cchNewLength--; + } + else + { + break; + } + } + + if (cchNewLength == 0) + { + + Reset(); + } + else if (cchLeadingWhitespace > 0) + { + memmove(pwszString, pwszString + cchLeadingWhitespace, cchNewLength * sizeof(WCHAR)); + pwszString[cchNewLength] = L'\0'; + } + + SyncWithBuffer(); +} + +/*++ + +Routine Description: + + Compares the string to the provided prefix to check for equality + +Arguments: + + pwszPrefix - wide char string to compare with + fIgnoreCase - indicates whether the string comparison should be case-sensitive + +Return Value: + + TRUE if prefix string matches with internal string, FALSE otherwise + +--*/ + +BOOL +STRU::StartsWith( + __in PCWSTR pwszPrefix, + __in bool fIgnoreCase) const +{ + HRESULT hr = S_OK; + BOOL fMatch = FALSE; + size_t cchPrefix = 0; + + if (pwszPrefix == NULL) + { + goto Finished; + } + + hr = StringCchLengthW( pwszPrefix, + STRSAFE_MAX_CCH, + &cchPrefix ); + if (FAILED(hr)) + { + goto Finished; + } + + _ASSERTE( cchPrefix <= MAXLONG ); + + if (cchPrefix > m_cchLen) + { + goto Finished; + } + + #if defined( NTDDI_VERSION ) && NTDDI_VERSION >= NTDDI_LONGHORN + + fMatch = ( CSTR_EQUAL == CompareStringOrdinal( QueryStr(), + (int)cchPrefix, + pwszPrefix, + (int)cchPrefix, + fIgnoreCase ) ); + #else + + if( fIgnoreCase ) + { + fMatch = ( 0 == _wcsnicmp( QueryStr(), pwszPrefix, cchPrefix ) ); + } + else + { + fMatch = ( 0 == wcsncmp( QueryStr(), pwszPrefix, cchPrefix ) ); + } + + #endif + +Finished: + + return fMatch; +} + +/*++ + +Routine Description: + + Compares the string to the provided suffix to check for equality + +Arguments: + + pwszSuffix - wide char string to compare with + fIgnoreCase - indicates whether the string comparison should be case-sensitive + +Return Value: + + TRUE if suffix string matches with internal string, FALSE otherwise + +--*/ + + +BOOL +STRU::EndsWith( + __in PCWSTR pwszSuffix, + __in bool fIgnoreCase) const +{ + HRESULT hr = S_OK; + PWSTR pwszString = QueryStr(); + BOOL fMatch = FALSE; + size_t cchSuffix = 0; + ptrdiff_t ixOffset = 0; + + if (pwszSuffix == NULL) + { + goto Finished; + } + + hr = StringCchLengthW( pwszSuffix, + STRSAFE_MAX_CCH, + &cchSuffix ); + if (FAILED(hr)) + { + goto Finished; + } + + _ASSERTE( cchSuffix <= MAXLONG ); + + if (cchSuffix > m_cchLen) + { + goto Finished; + } + + ixOffset = m_cchLen - cchSuffix; + _ASSERTE(ixOffset >= 0 && ixOffset <= MAXDWORD); + + #if defined( NTDDI_VERSION ) && NTDDI_VERSION >= NTDDI_LONGHORN + + fMatch = ( CSTR_EQUAL == CompareStringOrdinal( pwszString + ixOffset, + (int)cchSuffix, + pwszSuffix, + (int)cchSuffix, + fIgnoreCase ) ); + #else + + if( fIgnoreCase ) + { + fMatch = ( 0 == _wcsnicmp( pwszString + ixOffset, pwszSuffix, cchSuffix ) ); + } + else + { + fMatch = ( 0 == wcsncmp( pwszString + ixOffset, pwszSuffix, cchSuffix ) ); + } + + #endif + +Finished: + + return fMatch; +} + +/*++ + +Routine Description: + + Searches the string for the first occurrence of the specified character. + +Arguments: + + charValue - character to find + dwStartIndex - the initial index. + +Return Value: + + The index for the first character occurence in the string. + + -1 if not found. + +--*/ +INT +STRU::IndexOf( + __in WCHAR charValue, + __in DWORD dwStartIndex + ) const +{ + INT nIndex = -1; + + // Make sure that there are no buffer overruns. + if( dwStartIndex >= QueryCCH() ) + { + goto Finished; + } + + const WCHAR* pwChar = wcschr( QueryStr() + dwStartIndex, charValue ); + + // Determine the index if found + if( pwChar ) + { + // nIndex will be set to -1 on failure. + (VOID)SizeTToInt( pwChar - QueryStr(), &nIndex ); + } + +Finished: + + return nIndex; +} + + +/*++ + +Routine Description: + + Searches the string for the first occurrence of the specified substring. + +Arguments: + + pwszValue - substring to find + dwStartIndex - initial index. + +Return Value: + + The index for the first character occurence in the string. + + -1 if not found. + +--*/ +INT +STRU::IndexOf( + __in PCWSTR pwszValue, + __in DWORD dwStartIndex + ) const +{ + HRESULT hr = S_OK; + INT nIndex = -1; + SIZE_T cchValue = 0; + + // Validate input parameters + if( dwStartIndex >= QueryCCH() || !pwszValue ) + { + goto Finished; + } + + const WCHAR* pwChar = wcsstr( QueryStr() + dwStartIndex, pwszValue ); + + // Determine the index if found + if( pwChar ) + { + // nIndex will be set to -1 on failure. + (VOID)SizeTToInt( pwChar - QueryStr(), &nIndex ); + } + +Finished: + + return nIndex; +} + + +/*++ + +Routine Description: + + Searches the string for the last occurrence of the specified character. + +Arguments: + + charValue - character to find + dwStartIndex - initial index. + +Return Value: + + The index for the last character occurence in the string. + + -1 if not found. + +--*/ +INT +STRU::LastIndexOf( + __in WCHAR charValue, + __in DWORD dwStartIndex + ) const +{ + INT nIndex = -1; + + // Make sure that there are no buffer overruns. + if( dwStartIndex >= QueryCCH() ) + { + goto Finished; + } + + const WCHAR* pwChar = wcsrchr( QueryStr() + dwStartIndex, charValue ); + + // Determine the index if found + if( pwChar ) + { + // nIndex will be set to -1 on failure. + (VOID)SizeTToInt( pwChar - QueryStr(), &nIndex ); + } + +Finished: + + return nIndex; +} + +//static +HRESULT +STRU::ExpandEnvironmentVariables( + __in PCWSTR pszString, + __out STRU * pstrExpandedString + ) +/*++ + +Routine Description: + + Expand the environment variables in a string + +Arguments: + + pszString - String with environment variables to expand + pstrExpandedString - Receives expanded string on success + +Return Value: + + HRESULT + +--*/ +{ + HRESULT hr = S_OK; + DWORD cchNewSize = 0; + + if ( pszString == NULL || + pstrExpandedString == NULL ) + { + DBG_ASSERT( FALSE ); + hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); + goto Exit; + } + + cchNewSize = ExpandEnvironmentStrings( pszString, + pstrExpandedString->QueryStr(), + pstrExpandedString->QuerySizeCCH() ); + if ( cchNewSize == 0 ) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + goto Exit; + } + + if ( cchNewSize > pstrExpandedString->QuerySizeCCH() ) + { + hr = pstrExpandedString->Resize( + ( cchNewSize + 1 ) * sizeof( WCHAR ) + ); + if ( FAILED( hr ) ) + { + goto Exit; + } + + cchNewSize = ExpandEnvironmentStrings( + pszString, + pstrExpandedString->QueryStr(), + pstrExpandedString->QuerySizeCCH() + ); + + if ( cchNewSize == 0 || + cchNewSize > pstrExpandedString->QuerySizeCCH() ) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + goto Exit; + } + } + + pstrExpandedString->SyncWithBuffer(); + + hr = S_OK; + +Exit: + + return hr; +} diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/ulparse.cxx b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/ulparse.cxx new file mode 100644 index 0000000000..69b42e6250 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/ulparse.cxx @@ -0,0 +1,1416 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#include "precomp.h" + +// +// BUGBUG: Turn off optimization on ia64 builds due to a compiler bug +// +#if (defined(_M_IA64) && (_MSC_FULL_VER == 13009286)) +#pragma optimize("",off) +#endif + +#define LF 0x0A +#define SP 0x20 +#define HT 0x09 + +#define HTTP_CHAR 0x001 +#define HTTP_UPCASE 0x002 +#define HTTP_LOCASE 0x004 +#define HTTP_ALPHA (HTTP_UPCASE | HTTP_LOCASE) +#define HTTP_DIGIT 0x008 +#define HTTP_CTL 0x010 +#define HTTP_LWS 0x020 +#define HTTP_HEX 0x040 +#define HTTP_SEPERATOR 0x080 +#define HTTP_TOKEN 0x100 + +#define URL_LEGAL 0x200 +#define URL_TOKEN (HTTP_ALPHA | HTTP_DIGIT | URL_LEGAL) + +#define IS_HTTP_UPCASE(c) (HttpChars[(UCHAR)(c)] & HTTP_UPCASE) +#define IS_HTTP_LOCASE(c) (HttpChars[(UCHAR)(c)] & HTTP_UPCASE) +#define IS_HTTP_ALPHA(c) (HttpChars[(UCHAR)(c)] & HTTP_ALPHA) +#define IS_HTTP_DIGIT(c) (HttpChars[(UCHAR)(c)] & HTTP_DIGIT) +#define IS_HTTP_HEX(c) (HttpChars[(UCHAR)(c)] & HTTP_HEX) +#define IS_HTTP_CTL(c) (HttpChars[(UCHAR)(c)] & HTTP_CTL) +#define IS_HTTP_LWS(c) (HttpChars[(UCHAR)(c)] & HTTP_LWS) +#define IS_HTTP_SEPERATOR(c) (HttpChars[(UCHAR)(c)] & HTTP_SEPERATOR) +#define IS_HTTP_TOKEN(c) (HttpChars[(UCHAR)(c)] & HTTP_TOKEN) +#define IS_URL_TOKEN(c) (HttpChars[(UCHAR)(c)] & URL_TOKEN) + +// Some stuff not defined in VS SDK +#ifndef NT_SUCCESS +#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) +#endif + +// Copied from ntstatus.h, otherwise we will have double definition for +// number of macros that are both in ntstatus.h and winnt.h +#ifndef STATUS_SUCCESS +#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) // ntsubauth +#endif +#ifndef STATUS_OBJECT_PATH_SYNTAX_BAD +#define STATUS_OBJECT_PATH_SYNTAX_BAD ((NTSTATUS)0xC000003BL) +#endif +#ifndef STATUS_OBJECT_PATH_INVALID +#define STATUS_OBJECT_PATH_INVALID ((NTSTATUS)0xC0000039L) +#endif +// +// Constant Declarations for UTF8 Encoding +// + +#define ASCII 0x007f + +#define UTF8_2_MAX 0x07ff // max UTF8 2-byte sequence (32 * 64 =2048) +#define UTF8_1ST_OF_2 0xc0 // 110x xxxx +#define UTF8_1ST_OF_3 0xe0 // 1110 xxxx +#define UTF8_1ST_OF_4 0xf0 // 1111 xxxx +#define UTF8_TRAIL 0x80 // 10xx xxxx + +#define HIGHER_6_BIT(u) ((u) >> 12) +#define MIDDLE_6_BIT(u) (((u) & 0x0fc0) >> 6) +#define LOWER_6_BIT(u) ((u) & 0x003f) + +#define BIT7(a) ((a) & 0x80) +#define BIT6(a) ((a) & 0x40) + +#define HIGH_SURROGATE_START 0xd800 +#define HIGH_SURROGATE_END 0xdbff +#define LOW_SURROGATE_START 0xdc00 +#define LOW_SURROGATE_END 0xdfff + +#define EMIT_CHAR(ch) \ + do { \ + pDest[0] = (ch); \ + pDest += 1; \ + BytesCopied += 2; \ + } while (0) + +typedef enum _URL_TYPE +{ + UrlTypeUtf8, + UrlTypeAnsi, + UrlTypeDbcs +} URL_TYPE; + +typedef enum _URL_PART +{ + Scheme, + HostName, + AbsPath, + QueryString + +} URL_PART; + +#define IS_UTF8_TRAILBYTE(ch) (((ch) & 0xc0) == 0x80) + +// +// These are copied from RTL NLS routines. +// + +#define DBCS_TABLE_SIZE 256 +extern PUSHORT NlsLeadByteInfo; + +#define LeadByteTable (*(PUSHORT *)NlsLeadByteInfo) +#define IS_LEAD_BYTE(c) (IsDBCSLeadByte(c)) + +ULONG HttpChars[256]; +USHORT FastPopChars[256]; +USHORT DummyPopChars[256]; +WCHAR FastUpcaseChars[256]; +BOOL g_UlEnableNonUTF8; +BOOL g_UlEnableDBCS; +BOOL g_UlFavorDBCS; + +// RtlNtStatusToDosError is nowhere defined, should be used through +// native code "reflection" +typedef ULONG (RTL_NT_STATUS_TO_DOS_ERROR_PROC)(NTSTATUS); +static RTL_NT_STATUS_TO_DOS_ERROR_PROC* rtlNtStatusToDosErrorProc = NULL; +static HMODULE lib = NULL; + +HRESULT +WIN32_FROM_NTSTATUS( + __in NTSTATUS status, + __out DWORD * pResult + ) +{ + HRESULT hr = S_OK; + if (pResult == NULL) + { + hr = E_INVALIDARG; + goto Finished; + } + if (lib == NULL) + { + lib = GetModuleHandle(L"Ntdll.dll"); + if (lib == NULL) + { + hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + goto Finished; + } + } + if (rtlNtStatusToDosErrorProc == NULL) + { + rtlNtStatusToDosErrorProc = + (RTL_NT_STATUS_TO_DOS_ERROR_PROC*)GetProcAddress( + lib, "RtlNtStatusToDosError"); + if (rtlNtStatusToDosErrorProc == NULL) + { + hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + goto Finished; + } + } + *pResult = rtlNtStatusToDosErrorProc(status); + +Finished: + return hr; +} + +NTSTATUS +Unescape( + IN PUCHAR pChar, + OUT PUCHAR pOutChar + ) + +{ + UCHAR Result, Digit; + + if (pChar[0] != '%' || + SAFEIsXDigit(pChar[1]) == FALSE || + SAFEIsXDigit(pChar[2]) == FALSE) + { + return STATUS_OBJECT_PATH_SYNTAX_BAD; + } + + // + // HexToChar() inlined + // + + // uppercase #1 + // + if (SAFEIsAlpha(pChar[1])) + Digit = (UCHAR) toupper(pChar[1]); + else + Digit = pChar[1]; + + Result = ((Digit >= 'A') ? (Digit - 'A' + 0xA) : (Digit - '0')) << 4; + + // uppercase #2 + // + if (SAFEIsAlpha(pChar[2])) + Digit = (UCHAR) toupper(pChar[2]); + else + Digit = pChar[2]; + + Result |= (Digit >= 'A') ? (Digit - 'A' + 0xA) : (Digit - '0'); + + *pOutChar = Result; + + return STATUS_SUCCESS; + +} // Unescape + +// +// PopChar is used only if the string is not UTF-8, or UrlPart != QueryString, +// or the current character is '%' or its high bit is set. In all other cases, +// the FastPopChars table is used for fast conversion. +// + +__inline +NTSTATUS +PopChar( + IN URL_TYPE UrlType, + IN URL_PART UrlPart, + __in LPSTR pChar, + __out WCHAR * pUnicodeChar, + __out WCHAR * pUnicodeChar2, + OUT PULONG pCharToSkip + ) +{ + NTSTATUS Status; + WCHAR UnicodeChar = L'\0'; + WCHAR UnicodeChar2 = L'\0'; + UCHAR Char; + UCHAR Trail1; + UCHAR Trail2; + UCHAR Trail3; + ULONG CharToSkip; + + // + // validate it as a valid url character + // + + if (UrlPart != QueryString) + { + if (IS_URL_TOKEN((UCHAR)pChar[0]) == FALSE) + { + Status = STATUS_OBJECT_PATH_SYNTAX_BAD; + goto end; + } + } + else + { + // + // Allow anything but linefeed in the query string. + // + + if (pChar[0] == LF) + { + Status = STATUS_OBJECT_PATH_SYNTAX_BAD; + goto end; + } + + UnicodeChar = (USHORT) (UCHAR)pChar[0]; + CharToSkip = 1; + + // skip all the decoding stuff + goto slash; + } + + // + // need to unescape ? + // + // can't decode the query string. that would be lossy decodeing + // as '=' and '&' characters might be encoded, but have meaning + // to the usermode parser. + // + + if (pChar[0] == '%') + { + Status = Unescape((PUCHAR)pChar, &Char); + if (NT_SUCCESS(Status) == FALSE) + goto end; + CharToSkip = 3; + } + else + { + Char = pChar[0]; + CharToSkip = 1; + } + + if (UrlType == UrlTypeUtf8) + { + // + // convert to unicode, checking for utf8 . + // + // 3 byte runs are the largest we can have. 16 bits in UCS-2 = + // 3 bytes of (4+4,2+6,2+6) where it's code + char. + // for a total of 6+6+4 char bits = 16 bits. + // + + // + // NOTE: we'll only bother to decode utf if it was escaped + // thus the (CharToSkip == 3) + // + if ((CharToSkip == 3) && ((Char & 0xf8) == 0xf0)) + { + // 4 byte run + // + + // Unescape the next 3 trail bytes + // + + Status = Unescape((PUCHAR)pChar+CharToSkip, &Trail1); + if (NT_SUCCESS(Status) == FALSE) + goto end; + + CharToSkip += 3; // %xx + + Status = Unescape((PUCHAR)pChar+CharToSkip, &Trail2); + if (NT_SUCCESS(Status) == FALSE) + goto end; + + CharToSkip += 3; // %xx + + Status = Unescape((PUCHAR)pChar+CharToSkip, &Trail3); + if (NT_SUCCESS(Status) == FALSE) + goto end; + + CharToSkip += 3; // %xx + + if (IS_UTF8_TRAILBYTE(Trail1) == FALSE || + IS_UTF8_TRAILBYTE(Trail2) == FALSE || + IS_UTF8_TRAILBYTE(Trail3) == FALSE) + { + // bad utf! + // + Status = STATUS_OBJECT_PATH_SYNTAX_BAD; + goto end; + } + + // handle four byte case - convert to utf-16 + // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + + UnicodeChar = ((USHORT) ((Char & 0x07) << 8) | + ((Trail1 & 0x3f) << 2) | + ((Trail2 & 0x30) >> 4)) + 0xD7C0; + UnicodeChar2 = ((USHORT) ((Trail2 & 0x0f) << 6) | + (Trail3 & 0x3f)) | 0xDC00; + } + else if ((CharToSkip == 3) && ((Char & 0xf0) == 0xe0)) + { + // 3 byte run + // + + // Unescape the next 2 trail bytes + // + + Status = Unescape((PUCHAR)pChar+CharToSkip, &Trail1); + if (NT_SUCCESS(Status) == FALSE) + goto end; + + CharToSkip += 3; // %xx + + Status = Unescape((PUCHAR)pChar+CharToSkip, &Trail2); + if (NT_SUCCESS(Status) == FALSE) + goto end; + + CharToSkip += 3; // %xx + + if (IS_UTF8_TRAILBYTE(Trail1) == FALSE || + IS_UTF8_TRAILBYTE(Trail2) == FALSE) + { + // bad utf! + // + Status = STATUS_OBJECT_PATH_SYNTAX_BAD; + goto end; + } + + // handle three byte case + // 1110xxxx 10xxxxxx 10xxxxxx + + UnicodeChar = (USHORT) (((Char & 0x0f) << 12) | + ((Trail1 & 0x3f) << 6) | + (Trail2 & 0x3f)); + + } + else if ((CharToSkip == 3) && ((Char & 0xe0) == 0xc0)) + { + // 2 byte run + // + + // Unescape the next 1 trail byte + // + + Status = Unescape((PUCHAR)pChar+CharToSkip, &Trail1); + if (NT_SUCCESS(Status) == FALSE) + goto end; + + CharToSkip += 3; // %xx + + if (IS_UTF8_TRAILBYTE(Trail1) == FALSE) + { + // bad utf! + // + Status = STATUS_OBJECT_PATH_SYNTAX_BAD; + goto end; + } + + // handle two byte case + // 110xxxxx 10xxxxxx + + UnicodeChar = (USHORT) (((Char & 0x1f) << 6) | + (Trail1 & 0x3f)); + + } + + // now this can either be unescaped high-bit (bad) + // or escaped high-bit. (also bad) + // + // thus not checking CharToSkip + // + + else if ((Char & 0x80) == 0x80) + { + // high bit set ! bad utf! + // + Status = STATUS_OBJECT_PATH_SYNTAX_BAD; + goto end; + + } + // + // Normal character (again either escaped or unescaped) + // + else + { + // + // Simple conversion to unicode, it's 7-bit ascii. + // + + UnicodeChar = (USHORT)Char; + } + + } + else // UrlType != UrlTypeUtf8 + { + UCHAR AnsiChar[2]; + ULONG AnsiCharSize; + + // + // Convert ANSI character to Unicode. + // If the UrlType is UrlTypeDbcs, then we may have + // a DBCS lead/trail pair. + // + + if (UrlType == UrlTypeDbcs && IS_LEAD_BYTE(Char)) + { + UCHAR SecondByte; + + // + // This is a double-byte character. + // + + SecondByte = *(pChar+CharToSkip); + + AnsiCharSize = 2; + AnsiChar[0] = Char; + + if (SecondByte == '%') + { + Status = Unescape((PUCHAR)pChar+CharToSkip, &AnsiChar[1]); + if (!NT_SUCCESS(Status)) + { + goto end; + } + + CharToSkip += 3; // %xx + } + else + { + AnsiChar[1] = SecondByte; + CharToSkip += 1; + } + + } + else + { + // + // This is a single-byte character. + // + + AnsiCharSize = 1; + AnsiChar[0] = Char; + + } + /* + Status = RtlMultiByteToUnicodeN( + &UnicodeChar, + sizeof(WCHAR), + NULL, + (PCHAR) &AnsiChar[0], + AnsiCharSize + ); + */ + Status = MultiByteToWideChar( + CP_ACP, + 0, + (PCHAR) &AnsiChar[0], + AnsiCharSize, + &UnicodeChar, + sizeof(WCHAR) + ); + + if (!NT_SUCCESS(Status)) + { + goto end; + } + } + + +slash: + // + // turn backslashes into forward slashes + // + + if (UrlPart != QueryString && UnicodeChar == L'\\') + { + UnicodeChar = L'/'; + } + else if (UnicodeChar == UNICODE_NULL) + { + // + // we pop'd a NULL. bad! + // + Status = STATUS_OBJECT_PATH_SYNTAX_BAD; + goto end; + } + + *pCharToSkip = CharToSkip; + *pUnicodeChar = UnicodeChar; + *pUnicodeChar2 = UnicodeChar2; + + Status = STATUS_SUCCESS; + +end: + return Status; + +} // PopChar + + +// +// Private constants. +// + +#define ACTION_NOTHING 0x00000000 +#define ACTION_EMIT_CH 0x00010000 +#define ACTION_EMIT_DOT_CH 0x00020000 +#define ACTION_EMIT_DOT_DOT_CH 0x00030000 +#define ACTION_BACKUP 0x00040000 +#define ACTION_MASK 0xFFFF0000 + +// +// Private globals +// + +// +// this table says what to do based on the current state and the current +// character +// +ULONG pActionTable[16] = +{ + // + // state 0 = fresh, seen nothing exciting yet + // + ACTION_EMIT_CH, // other = emit it state = 0 + ACTION_EMIT_CH, // "." = emit it state = 0 + ACTION_NOTHING, // EOS = normal finish state = 4 + ACTION_EMIT_CH, // "/" = we saw the "/", emit it state = 1 + + // + // state 1 = we saw a "/" ! + // + ACTION_EMIT_CH, // other = emit it, state = 0 + ACTION_NOTHING, // "." = eat it, state = 2 + ACTION_NOTHING, // EOS = normal finish state = 4 + ACTION_NOTHING, // "/" = extra slash, eat it, state = 1 + + // + // state 2 = we saw a "/" and ate a "." ! + // + ACTION_EMIT_DOT_CH, // other = emit the dot we ate. state = 0 + ACTION_NOTHING, // "." = eat it, a .. state = 3 + ACTION_NOTHING, // EOS = normal finish state = 4 + ACTION_NOTHING, // "/" = we ate a "/./", swallow it state = 1 + + // + // state 3 = we saw a "/" and ate a ".." ! + // + ACTION_EMIT_DOT_DOT_CH, // other = emit the "..". state = 0 + ACTION_EMIT_DOT_DOT_CH, // "." = 3 dots, emit the ".." state = 0 + ACTION_BACKUP, // EOS = we have a "/..\0", backup! state = 4 + ACTION_BACKUP // "/" = we have a "/../", backup! state = 1 +}; + +// +// this table says which newstate to be in given the current state and the +// character we saw +// +ULONG pNextStateTable[16] = +{ + // state 0 + 0 , // other + 0 , // "." + 4 , // EOS + 1 , // "\" + + // state 1 + 0 , // other + 2 , // "." + 4 , // EOS + 1 , // "\" + + // state 2 + 0 , // other + 3 , // "." + 4 , // EOS + 1 , // "\" + + // state 3 + 0 , // other + 0 , // "." + 4 , // EOS + 1 // "\" +}; + +// +// this says how to index into pNextStateTable given our current state. +// +// since max states = 4, we calculate the index by multiplying with 4. +// +#define IndexFromState( st) ( (st) * 4) + + +/***************************************************************************++ + +Routine Description: + + This function can be told to clean up UTF-8, ANSI, or DBCS URLs. + + Unescape + Convert backslash to forward slash + Remove double slashes (empty directiories names) - e.g. // or \\ + Handle /./ + Handle /../ + Convert to unicode + computes the case insensitive hash + +Arguments: + + +Return Value: + + NTSTATUS - Completion status. + + +--***************************************************************************/ +NTSTATUS +UlpCleanAndCopyUrlByType( + IN URL_TYPE UrlType, + IN URL_PART UrlPart, + __inout PWSTR pDestination, + __in_ecount(SourceLength) LPSTR pSource, + IN ULONG SourceLength, + OUT PULONG pBytesCopied, + __deref_opt_out_opt PWSTR * ppQueryString + ) +{ + NTSTATUS Status; + PWSTR pDest; + PUCHAR pChar; + ULONG CharToSkip; + ULONG BytesCopied; + PWSTR pQueryString; + ULONG StateIndex; + WCHAR UnicodeChar; + WCHAR UnicodeChar2 = L'\0'; + BOOLEAN MakeCanonical; + PUSHORT pFastPopChar; + + pDest = pDestination; + pQueryString = NULL; + BytesCopied = 0; + + pChar = (PUCHAR)pSource; + CharToSkip = 0; + + StateIndex = 0; + + MakeCanonical = (UrlPart == AbsPath) ? TRUE : FALSE; + + if (UrlType == UrlTypeUtf8 && UrlPart != QueryString) + { + pFastPopChar = FastPopChars; + } + else + { + pFastPopChar = DummyPopChars; + } + + while (SourceLength > 0) + { + // + // advance ! it's at the top of the loop to enable ANSI_NULL to + // come through ONCE + // + + pChar += CharToSkip; + SourceLength -= CharToSkip; + + // + // well? have we hit the end? + // + + if (SourceLength == 0) + { + UnicodeChar = UNICODE_NULL; + UnicodeChar2 = UNICODE_NULL; + } + else + { + // + // Nope. Peek briefly to see if we hit the query string + // + + if (UrlPart == AbsPath && pChar[0] == '?') + { + DBG_ASSERT(pQueryString == NULL); + + // + // remember it's location + // + + pQueryString = pDest; + + // + // let it fall through ONCE to the canonical + // in order to handle a trailing "/.." like + // "http://hostname:80/a/b/..?v=1&v2" + // + + UnicodeChar = L'?'; + UnicodeChar2 = UNICODE_NULL; + CharToSkip = 1; + + // + // now we are cleaning the query string + // + + UrlPart = QueryString; + + // + // cannot use fast path for PopChar anymore + // + + pFastPopChar = DummyPopChars; + } + else + { + USHORT NextUnicodeChar = pFastPopChar[*pChar]; + + // + // Grab the next character. Try to be fast for the + // normal character case. Otherwise call PopChar. + // + + if (NextUnicodeChar == 0) + { + Status = PopChar( + UrlType, + UrlPart, + (LPSTR)pChar, + &UnicodeChar, + &UnicodeChar2, + &CharToSkip + ); + + if (NT_SUCCESS(Status) == FALSE) + goto end; + } + else + { +#if DBG + Status = PopChar( + UrlType, + UrlPart, + (LPSTR)pChar, + &UnicodeChar, + &UnicodeChar2, + &CharToSkip + ); + + DBG_ASSERT(NT_SUCCESS(Status)); + DBG_ASSERT(UnicodeChar == NextUnicodeChar); + DBG_ASSERT(CharToSkip == 1); +#endif + UnicodeChar = NextUnicodeChar; + UnicodeChar2 = UNICODE_NULL; + CharToSkip = 1; + } + } + } + + if (MakeCanonical) + { + // + // now use the state machine to make it canonical . + // + + // + // from the old value of StateIndex, figure out our new base StateIndex + // + StateIndex = IndexFromState(pNextStateTable[StateIndex]); + + // + // did we just hit the query string? this will only happen once + // that we take this branch after hitting it, as we stop + // processing after hitting it. + // + + if (UrlPart == QueryString) + { + // + // treat this just like we hit a NULL, EOS. + // + + StateIndex += 2; + } + else + { + // + // otherwise based the new state off of the char we + // just popped. + // + + switch (UnicodeChar) + { + case UNICODE_NULL: StateIndex += 2; break; + case L'.': StateIndex += 1; break; + case L'/': StateIndex += 3; break; + default: StateIndex += 0; break; + } + } + + } + else + { + StateIndex = (UnicodeChar == UNICODE_NULL) ? 2 : 0; + } + + // + // Perform the action associated with the state. + // + + switch (pActionTable[StateIndex]) + { + case ACTION_EMIT_DOT_DOT_CH: + + EMIT_CHAR(L'.'); + + // fall through + + case ACTION_EMIT_DOT_CH: + + EMIT_CHAR(L'.'); + + // fall through + + case ACTION_EMIT_CH: + + EMIT_CHAR(UnicodeChar); + if (UnicodeChar2 != UNICODE_NULL) + { + EMIT_CHAR(UnicodeChar2); + } + + // fall through + + case ACTION_NOTHING: + break; + + case ACTION_BACKUP: + + // + // pDest currently points 1 past the last '/'. backup over it and + // find the preceding '/', set pDest to 1 past that one. + // + + // + // backup to the '/' + // + + pDest -= 1; + BytesCopied -= 2; + + DBG_ASSERT(pDest[0] == L'/'); + + // + // are we at the start of the string? that's bad, can't go back! + // + + if (pDest == pDestination) + { + DBG_ASSERT(BytesCopied == 0); + Status = STATUS_OBJECT_PATH_INVALID; + goto end; + } + + // + // back up over the '/' + // + + pDest -= 1; + BytesCopied -= 2; + + DBG_ASSERT(pDest > pDestination); + + // + // now find the previous slash + // + + while (pDest > pDestination && pDest[0] != L'/') + { + pDest -= 1; + BytesCopied -= 2; + } + + // + // we already have a slash, so don't have to store 1. + // + + DBG_ASSERT(pDest[0] == L'/'); + + // + // simply skip it, as if we had emitted it just now + // + + pDest += 1; + BytesCopied += 2; + + break; + + default: + DBG_ASSERT(!"http!UlpCleanAndCopyUrl: Invalid action code in state table!"); + Status = STATUS_OBJECT_PATH_SYNTAX_BAD; + goto end; + } + + // + // Just hit the query string ? + // + + if (MakeCanonical && UrlPart == QueryString) + { + // + // Stop canonical processing + // + + MakeCanonical = FALSE; + + // + // Need to emit the '?', it wasn't emitted above + // + + DBG_ASSERT(pActionTable[StateIndex] != ACTION_EMIT_CH); + + EMIT_CHAR(L'?'); + + } + + } + + // + // terminate the string, it hasn't been done in the loop + // + + DBG_ASSERT((pDest-1)[0] != UNICODE_NULL); + + pDest[0] = UNICODE_NULL; + *pBytesCopied = BytesCopied; + + if (ppQueryString != NULL) + { + *ppQueryString = pQueryString; + } + + Status = STATUS_SUCCESS; + + +end: + return Status; + +} // UlpCleanAndCopyUrlByType + + +/***************************************************************************++ + +Routine Description: + + + Unescape + Convert backslash to forward slash + Remove double slashes (empty directiories names) - e.g. // or \\ + Handle /./ + Handle /../ + Convert to unicode + +Arguments: + +Return Value: + + HRESULT + + +--***************************************************************************/ +HRESULT +UlCleanAndCopyUrl( + __in LPSTR pSource, + IN ULONG SourceLength, + OUT PULONG pBytesCopied, + __inout PWSTR pDestination, + __deref_opt_out_opt PWSTR * ppQueryString OPTIONAL + ) +{ + NTSTATUS Status; + URL_TYPE AnsiUrlType = g_UlEnableDBCS ? UrlTypeDbcs : UrlTypeAnsi; + + if (!g_UlEnableNonUTF8) + { + // + // Only accept UTF-8 URLs. + // + + Status = UlpCleanAndCopyUrlByType( + UrlTypeUtf8, + AbsPath, + pDestination, + pSource, + SourceLength, + pBytesCopied, + ppQueryString + ); + + } + else if (!g_UlFavorDBCS) + { + // + // The URL may be either UTF-8 or ANSI. First + // try UTF-8, and if that fails go for ANSI. + // + + Status = UlpCleanAndCopyUrlByType( + UrlTypeUtf8, + AbsPath, + pDestination, + pSource, + SourceLength, + pBytesCopied, + ppQueryString + ); + + if (!NT_SUCCESS(Status)) + { + Status = UlpCleanAndCopyUrlByType( + AnsiUrlType, + AbsPath, + pDestination, + pSource, + SourceLength, + pBytesCopied, + ppQueryString + ); + + } + + } + else + { + // + // The URL may be either ANSI or UTF-8. First + // try the ANSI interpretation, and if that fails + // go for UTF-8. + // + Status = UlpCleanAndCopyUrlByType( + AnsiUrlType, + AbsPath, + pDestination, + pSource, + SourceLength, + pBytesCopied, + ppQueryString + ); + + if (!NT_SUCCESS(Status)) + { + Status = UlpCleanAndCopyUrlByType( + UrlTypeUtf8, + AbsPath, + pDestination, + pSource, + SourceLength, + pBytesCopied, + ppQueryString + ); + + } + } + + // + // Convert NTSTATUS to HRESULT + // + + if ( Status == STATUS_SUCCESS ) + { + return S_OK; + } + else + { + DWORD dwErr = 0; + if (SUCCEEDED(WIN32_FROM_NTSTATUS( Status, &dwErr ))) + { + return HRESULT_FROM_WIN32( dwErr ); + } + else + { + return Status; + } + } +} + +HRESULT +UlInitializeParsing( + VOID +) +{ + ULONG i; + UCHAR c; + HKEY hKey; + DWORD dwType; + DWORD dwData; + DWORD cbData; + + // + // First read the HTTP registry settings on how to handle URLs + // + + g_UlEnableNonUTF8 = TRUE; + g_UlEnableDBCS = FALSE; + g_UlFavorDBCS = FALSE; + + if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, + L"System\\CurrentControlSet\\Services\\http\\Parameters", + 0, + KEY_READ, + &hKey ) == ERROR_SUCCESS ) + { + cbData = sizeof( dwData ); + + if ( RegQueryValueEx( hKey, + L"EnableNonUTF8", + NULL, + &dwType, + (LPBYTE) &dwData, + &cbData ) == ERROR_SUCCESS && + dwType == REG_DWORD ) + { + g_UlEnableNonUTF8 = !!dwData; + } + + cbData = sizeof( dwData ); + + if ( g_UlEnableNonUTF8 ) + { + if ( RegQueryValueEx( hKey, + L"EnableDBCS", + NULL, + &dwType, + (LPBYTE) &dwData, + &cbData ) == ERROR_SUCCESS && + dwType == REG_DWORD ) + { + g_UlEnableDBCS = !!dwData; + } + } + else + { + g_UlEnableDBCS = FALSE; + } + + cbData = sizeof( dwData ); + + if ( g_UlEnableDBCS ) + { + if ( RegQueryValueEx( hKey, + L"FavorDBCS", + NULL, + &dwType, + (LPBYTE) &dwData, + &cbData ) == ERROR_SUCCESS && + dwType == REG_DWORD ) + { + g_UlFavorDBCS = !!dwData; + } + } + else + { + g_UlFavorDBCS = FALSE; + } + + RegCloseKey( hKey ); + } + + + // Initialize the HttpChars array appropriately. + + for (i = 0; i < 128; i++) + { + HttpChars[i] = HTTP_CHAR; + } + + for (i = 'A'; i <= 'Z'; i++) + { + HttpChars[i] |= HTTP_UPCASE; + } + + for (i = 'a'; i <= 'z'; i++) + { + HttpChars[i] |= HTTP_LOCASE; + } + + for (i = '0'; i <= '9'; i++) + { + HttpChars[i] |= (HTTP_DIGIT | HTTP_HEX); + } + + + for (i = 0; i <= 31; i++) + { + HttpChars[i] |= HTTP_CTL; + } + + HttpChars[127] |= HTTP_CTL; + + HttpChars[SP] |= HTTP_LWS; + HttpChars[HT] |= HTTP_LWS; + + + for (i = 'A'; i <= 'F'; i++) + { + HttpChars[i] |= HTTP_HEX; + } + + for (i = 'a'; i <= 'f'; i++) + { + HttpChars[i] |= HTTP_HEX; + } + + HttpChars['('] |= HTTP_SEPERATOR; + HttpChars[')'] |= HTTP_SEPERATOR; + HttpChars['<'] |= HTTP_SEPERATOR; + HttpChars['>'] |= HTTP_SEPERATOR; + HttpChars['@'] |= HTTP_SEPERATOR; + HttpChars[','] |= HTTP_SEPERATOR; + HttpChars[';'] |= HTTP_SEPERATOR; + HttpChars[':'] |= HTTP_SEPERATOR; + HttpChars['\\'] |= HTTP_SEPERATOR; + HttpChars['"'] |= HTTP_SEPERATOR; + HttpChars['/'] |= HTTP_SEPERATOR; + HttpChars['['] |= HTTP_SEPERATOR; + HttpChars[']'] |= HTTP_SEPERATOR; + HttpChars['?'] |= HTTP_SEPERATOR; + HttpChars['='] |= HTTP_SEPERATOR; + HttpChars['{'] |= HTTP_SEPERATOR; + HttpChars['}'] |= HTTP_SEPERATOR; + HttpChars[SP] |= HTTP_SEPERATOR; + HttpChars[HT] |= HTTP_SEPERATOR; + + + // + // URL "reserved" characters (rfc2396) + // + + HttpChars[';'] |= URL_LEGAL; + HttpChars['/'] |= URL_LEGAL; + HttpChars['\\'] |= URL_LEGAL; + HttpChars['?'] |= URL_LEGAL; + HttpChars[':'] |= URL_LEGAL; + HttpChars['@'] |= URL_LEGAL; + HttpChars['&'] |= URL_LEGAL; + HttpChars['='] |= URL_LEGAL; + HttpChars['+'] |= URL_LEGAL; + HttpChars['$'] |= URL_LEGAL; + HttpChars[','] |= URL_LEGAL; + + + // + // URL escape character + // + + HttpChars['%'] |= URL_LEGAL; + + // + // URL "mark" characters (rfc2396) + // + + HttpChars['-'] |= URL_LEGAL; + HttpChars['_'] |= URL_LEGAL; + HttpChars['.'] |= URL_LEGAL; + HttpChars['!'] |= URL_LEGAL; + HttpChars['~'] |= URL_LEGAL; + HttpChars['*'] |= URL_LEGAL; + HttpChars['\''] |= URL_LEGAL; + HttpChars['('] |= URL_LEGAL; + HttpChars[')'] |= URL_LEGAL; + + + // + // RFC2396 describes these characters as `unwise' "because gateways and + // other transport agents are known to sometimes modify such characters, + // or they are used as delimiters". However, for compatibility with + // IIS 5.0 and DAV, we must allow these unwise characters in URLs. + // + + HttpChars['{'] |= URL_LEGAL; + HttpChars['}'] |= URL_LEGAL; + HttpChars['|'] |= URL_LEGAL; + HttpChars['^'] |= URL_LEGAL; + HttpChars['['] |= URL_LEGAL; + HttpChars[']'] |= URL_LEGAL; + HttpChars['`'] |= URL_LEGAL; + + // + // '#', '%', and '"' are not considered URL_LEGAL, according to the RFC. + // However, IIS 5.0 allowed them, so we should too. + // + + HttpChars['#'] |= URL_LEGAL; + HttpChars['%'] |= URL_LEGAL; + HttpChars['"'] |= URL_LEGAL; + + // + // In DBCS locales we need to explicitly accept lead bytes which + // we would normally reject. + // + + if (0) // BUGBUG + { + for (i = 0; i < DBCS_TABLE_SIZE; i++) + { + if (IS_LEAD_BYTE((BYTE)i)) + { + HttpChars[i] |= URL_LEGAL; + } + } + } + + // + // These US-ASCII characters are "excluded"; i.e. not URL_LEGAL (see RFC): + // '<' | '>' | ' ' (0x20) + // In addition, control characters (0x00-0x1F and 0x7F) and + // non US-ASCII characters (0x80-0xFF) are not URL_LEGAL. + // + + for (i = 0; i < 128; i++) + { + if (!IS_HTTP_SEPERATOR(i) && !IS_HTTP_CTL(i)) + { + HttpChars[i] |= HTTP_TOKEN; + } + } + + + // + // Fast path for PopChar + // + + RtlZeroMemory(FastPopChars, 256 * sizeof(USHORT)); + RtlZeroMemory(DummyPopChars, 256 * sizeof(USHORT)); + + for (i = 0; i < 256; i++) + { + c = (UCHAR)i; + + if (IS_URL_TOKEN(c) && c != '%' && (c & 0x80) != 0x80) + { + FastPopChars[i] = (USHORT)c; + } + } + + // + // Turn backslashes into forward slashes + // + + FastPopChars['\\'] = L'/'; + + + // + // Fast path for UpcaseUnicodeChar + // + + for (i = 0; i < 256; i++) + { + FastUpcaseChars[i] = towupper((WCHAR)i); + } + + + return S_OK; +} diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/util.cxx b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/util.cxx new file mode 100644 index 0000000000..22c31a0ed2 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/lib/util.cxx @@ -0,0 +1,74 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#include "precomp.h" + +HRESULT +MakePathCanonicalizationProof( + IN PCWSTR pszName, + OUT STRU * pstrPath +) +/*++ + +Routine Description: + + This functions adds a prefix + to the string, which is "\\?\UNC\" for a UNC path, and "\\?\" for + other paths. This prefix tells Windows not to parse the path. + +Arguments: + + IN pszName - The path to be converted + OUT pstrPath - Output path created + +Return Values: + + HRESULT + +--*/ +{ + HRESULT hr; + + if (pszName[0] == L'\\' && pszName[1] == L'\\') + { + // + // If the path is already canonicalized, just return + // + + if ((pszName[2] == '?' || pszName[2] == '.') && + pszName[3] == '\\') + { + hr = pstrPath->Copy(pszName); + + if (SUCCEEDED(hr)) + { + // + // If the path was in DOS form ("\\.\"), + // we need to change it to Win32 from ("\\?\") + // + + pstrPath->QueryStr()[2] = L'?'; + } + + return hr; + } + + pszName += 2; + + + if (FAILED(hr = pstrPath->Copy(L"\\\\?\\UNC\\"))) + { + return hr; + } + } + else + { + if (FAILED(hr = pstrPath->Copy(L"\\\\?\\"))) + { + return hr; + } + } + + return pstrPath->Append(pszName); +} + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/open-inc/stbuff.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/open-inc/stbuff.h new file mode 100644 index 0000000000..04e13789f0 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/open-inc/stbuff.h @@ -0,0 +1,1013 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#ifndef _STBUFF_H +#define _STBUFF_H + +#include +#include + +#define STB_INLINE_SIZE 64 +#define STB_MAX_ALLOC 16*1024 + +#define TO_UPPER(ch) (isupper(ch) ? ch : toupper(ch)) + +class STBUFF +{ +public: + + STBUFF( + BOOL fZeroInit = TRUE + ) : _pData( _Inline ), + _cbData( 0 ), + _cbBuffer( STB_INLINE_SIZE ), + _cbMaxAlloc( STB_MAX_ALLOC ) + { + if ( fZeroInit ) + { + ZeroInit(); + } + + _Inline[STB_INLINE_SIZE] = 0; + _Inline[STB_INLINE_SIZE+1] = 0; + } + + virtual + ~STBUFF() + { + Reset( TRUE ); + } + + VOID + Reset( + BOOL fFreeAlloc = FALSE + ) + { + // + // If we are supposed to free any heap + // allocations, do so now. + // + + if ( fFreeAlloc && + _pData != _Inline ) + { + LocalFree( _pData ); + _pData = _Inline; + _cbBuffer = STB_INLINE_SIZE; + } + + // + // Reset the data size + // + + _cbData = 0; + } + + HRESULT + Resize( + DWORD cbSize + ) + { + HRESULT hr = S_OK; + BYTE * pTemp; + + // + // If the buffer is large enough, just return + // + + if ( cbSize < _cbBuffer ) + { + goto Finished; + } + + // + // If the requested size exceeds our maximum + // allocation, then fail this call. + // + + if ( cbSize > _cbMaxAlloc ) + { + hr = E_OUTOFMEMORY; + goto Finished; + } + + // + // Adjust the allocation size so that we allocate + // in chunks of MINITOOLS_INLINE_SIZE. Don't + // exeed _cbMaxAlloc. + // + + if ( cbSize % STB_INLINE_SIZE ) + { + cbSize = ( cbSize / STB_INLINE_SIZE + 1 ) * + STB_INLINE_SIZE; + } + + if ( cbSize > _cbMaxAlloc ) + { + cbSize = _cbMaxAlloc; + } + + // + // Allocate the new storage and copy any existing + // data into it. + // + // Allocate two extra bytes so that we can guarantee + // NULL termination when someone queries the data + // pointer as a string. + // + + pTemp = (BYTE*)LocalAlloc( LPTR, cbSize + 2 ); + + if ( !pTemp ) + { + hr = E_OUTOFMEMORY; + goto Finished; + } + + if ( _cbData ) + { + CopyMemory( pTemp, _pData, _cbData ); + } + + // + // If the original buffer is not the inline + // storage, then free it. + // + + if ( _pData != _Inline ) + { + LocalFree( _pData ); + } + + // + // Save the new storage pointer + // + + _pData = pTemp; + _cbBuffer = cbSize; + + // + // Set the extra two bytes as 0 + // + + _pData[_cbBuffer] = 0; + _pData[_cbBuffer+1] = 0; + +Finished: + return hr; + } + + HRESULT + AppendData( + VOID * pData, + DWORD cbData, + DWORD Offset = 0xffffffff + ) + { + DWORD cbNeeded; + HRESULT hr = S_OK; + + // + // Resize the buffer if necessary + // + + cbNeeded = Offset + cbData; + + hr = Resize( cbNeeded ); + + if ( FAILED( hr ) ) + { + goto Finished; + } + + // + // Copy the new data + // + + if ( cbData ) + { + CopyMemory( _pData + Offset, pData, cbData ); + } + + _cbData = cbNeeded; + + // + // NULL terminate the data + // + + GuaranteeNullTermination(); + +Finished: + + return hr; + } + + + HRESULT + AppendData( + LPCSTR szData, + DWORD cchData = 0xffffffff, + DWORD Offset = 0xffffffff + ) + { + // + // If cchData is 0xffffffff, then calculate size + // + + if ( cchData == 0xffffffff ) + { + cchData = (DWORD)strlen( szData ); + } + + // + // If offset is 0xffffffff, then assume + // that we are appending to the end of the + // string. + // + + if ( Offset == 0xffffffff ) + { + Offset = _cbData; + } + + return AppendData( (VOID*)szData, + cchData, + Offset ); + } + + HRESULT + AppendData( + LPCWSTR szData, + DWORD cchData = 0xffffffff, + DWORD cchOffset = 0xffffffff + ) + { + DWORD cbData; + DWORD cbOffset; + // + // If cchData is 0xffffffff, then calculate size + // + + if ( cchData == 0xffffffff ) + { + cchData = (DWORD)wcslen( szData ); + } + + cbData = cchData * sizeof(WCHAR); + + // + // If offset is 0xffffffff, then assume + // that we are appending to the end of the + // string. + // + + if ( cchOffset == 0xffffffff ) + { + cchOffset = _cbData; + } + + cbOffset = cchOffset * sizeof(WCHAR); + + return AppendData( (VOID*)szData, + cbData, + cbOffset ); + } + + HRESULT + AppendData( + STBUFF *pbuff + ) + { + return AppendData( pbuff->QueryPtr(), + pbuff->QueryDataSize() ); + } + + HRESULT + SetData( + VOID * pData, + DWORD cbData + ) + { + // + // Set data is just an append to offset zero + // + + return AppendData( pData, + cbData, + 0 ); + } + + HRESULT + SetData( + LPCSTR pData, + DWORD cchData = 0xffffffff + ) + { + // + // If cbData is 0xffffffff, then assume that + // pData is a NULL terminated string. + // + + if ( cchData == 0xffffffff ) + { + cchData = (DWORD)strlen( (LPSTR)pData ); + } + + return SetData( (VOID*)pData, cchData ); + } + + HRESULT + SetData( + LPCWSTR pData, + DWORD cchData = 0xffffffff + ) + { + // + // If cbData is 0xffffffff, then assume that + // pData is a NULL terminated string. + // + + if ( cchData == 0xffffffff ) + { + cchData = (DWORD)wcslen( (LPWSTR)pData ); + } + + return SetData( (VOID*)pData, cchData * sizeof(WCHAR) ); + } + + + HRESULT + SetData( + STBUFF *pbuff + ) + { + return AppendData( pbuff->QueryPtr(), + pbuff->QueryDataSize(), + 0 ); + } + + HRESULT + AnsiToUnicode( + LPCSTR szString, + UINT codepage = CP_UTF8 + ) + { + DWORD cchString = (DWORD)strlen( szString ); + HRESULT hr = S_OK; + + hr = Resize( cchString * sizeof(WCHAR) ); + + if ( FAILED( hr ) ) + { + goto Finished; + } + + if ( !MultiByteToWideChar( codepage, + MB_ERR_INVALID_CHARS, + szString, + cchString, + (LPWSTR)_pData, + cchString ) ) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + goto Finished; + } + + _cbData = cchString * sizeof(WCHAR); + +Finished: + + return hr; + } + + HRESULT + UnicodeToAnsi( + LPCWSTR szStringW, + UINT codepage = CP_UTF8 + ) + { + DWORD cchString = (DWORD)wcslen( szStringW ); + HRESULT hr = S_OK; + + hr = Resize( cchString ); + + if ( FAILED( hr ) ) + { + goto Finished; + } + + if ( !WideCharToMultiByte( codepage, + 0, + szStringW, + cchString, + (LPSTR)_pData, + cchString, + NULL, + NULL ) ) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + goto Finished; + } + + _cbData = cchString; + +Finished: + + return hr; + } + + HRESULT + ExpandEnvironmentStrings( + VOID + ) + { + STBUFF Temp; + DWORD cbNeeded; + HRESULT hr = S_OK; + + cbNeeded = ::ExpandEnvironmentStringsA( QueryStr(), + Temp.QueryStr(), + Temp.QueryBufferSize() ); + + if ( cbNeeded > Temp.QueryBufferSize() ) + { + hr = Temp.Resize ( cbNeeded ); + if ( FAILED (hr) ) + { + goto Finished; + } + + cbNeeded = ::ExpandEnvironmentStringsA( QueryStr(), + Temp.QueryStr(), + Temp.QueryBufferSize() ); + + } + + Temp.CalcDataSize(); + + hr = SetData( &Temp ); + if ( FAILED (hr) ) + { + goto Finished; + } + + Finished: + + return hr; + } + + HRESULT + Vsprintf( + LPCSTR szFormat, + va_list args + ) + { + DWORD cchWritten; + HRESULT hr = S_OK; + + DWORD cbNeeded = _vscprintf( szFormat, args ); + + hr = Resize( cbNeeded + 1 ); + + if ( FAILED( hr ) ) + { + goto Finished; + } + + cchWritten = _vsnprintf_s( QueryStr(), + QueryBufferSize(), + QueryBufferSize(), + szFormat, + args ); + + _cbData = cchWritten; + +Finished: + + return hr; + } + + HRESULT + Vsprintf( + LPCWSTR szFormat, + va_list args + ) + { + DWORD cchWritten; + HRESULT hr = S_OK; + + DWORD cbNeeded = _vscwprintf( szFormat, args ) * sizeof(WCHAR); + + hr = Resize( cbNeeded + 1 ); + + if ( FAILED( hr ) ) + { + goto Finished; + } + + cchWritten = _vsnwprintf_s( QueryStrW(), + QueryBufferSize() / sizeof(WCHAR), + _TRUNCATE, + szFormat, + args ); + + _cbData = cchWritten * sizeof(WCHAR); + +Finished: + + return hr; + } + + HRESULT + Printf( + LPCSTR szFormat, + ... + ) + { + HRESULT hr; + + // + // Let Vsprintf do the work + // + + va_list args; + + va_start( args, szFormat ); + + hr = Vsprintf( szFormat, + args ); + + va_end( args ); + + return hr; + } + + HRESULT + Printf( + LPCWSTR szFormat, + ... + ) + { + HRESULT hr; + + // + // Let Vsprintf do the work + // + + va_list args; + + va_start( args, szFormat ); + + hr = Vsprintf( szFormat, + args ); + + va_end( args ); + + return hr; + } + + VOID * + QueryPtr() + { + return (VOID*)_pData; + } + + LPSTR + QueryStr() + { + GuaranteeNullTermination(); + + return (LPSTR)_pData; + } + + LPWSTR + QueryStrW() + { + GuaranteeNullTermination(); + + return (LPWSTR)_pData; + } + + DWORD + QueryDataSize() + { + return _cbData; + } + + HRESULT + SetDataSize( + DWORD cbData + ) + { + HRESULT hr = S_OK; + + if ( cbData > _cbBuffer ) + { + hr = HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER ); + goto Finished; + } + + _cbData = cbData; + + Finished: + return hr; + } + + VOID + CalcDataSize() + { + _cbData = (DWORD)strlen( (LPSTR)_pData ); + } + + VOID + CalcDataSizeW() + { + _cbData = (DWORD)wcslen( (LPWSTR)_pData ); + } + + DWORD + QueryBufferSize() + { + return _cbBuffer; + } + + DWORD + QueryMaxAlloc() + { + return _cbMaxAlloc; + } + + VOID + SetMaxAlloc( + DWORD cbMaxAlloc + ) + { + _cbMaxAlloc = cbMaxAlloc; + } + + VOID + ZeroInit( + VOID + ) + { + FillMemory( _Inline, STB_INLINE_SIZE, 0x00 ); + + if ( _pData != _Inline ) + { + FillMemory( _pData, _cbBuffer, 0x00 ); + } + } + + HRESULT + Escape( + BOOL fAllowDoubleEscaping = FALSE + ) + { + STBUFF Temp; + DWORD dwNumEscapes = 0; + CHAR szHex[3] = {0}; + BYTE * pRead; + BYTE * pWrite; + HRESULT hr = S_OK; + + // + // Walk through the string once. If there + // are no escapes, then we can just return. + // + + GuaranteeNullTermination(); + + pRead = (BYTE*)_pData; + + while ( *pRead != '\0' ) + { + if ( ( fAllowDoubleEscaping || + !IsEscapeSequence( (CHAR*)pRead ) ) && + ShouldEscape( *pRead ) ) + { + dwNumEscapes++; + } + + pRead++; + } + + if ( dwNumEscapes == 0 ) + { + goto Finished; + } + + // + // Make sure that our cooked string buffer is big enough, so + // we can manipulate its pointer directly. + // + + hr = Temp.Resize( _cbData + dwNumEscapes * 2 ); + if ( FAILED (hr) ) + { + goto Finished; + } + + pRead = (BYTE*)_pData; + pWrite = (BYTE*)Temp.QueryStr(); + + while ( *pRead != '\0' ) + { + if ( ( fAllowDoubleEscaping || + !IsEscapeSequence( (CHAR*)pRead ) ) && + ShouldEscape( *pRead ) ) + { + _snprintf_s( szHex, 3, 2, "%02x", *pRead ); + + *pWrite = '%'; + *(pWrite+1) = szHex[0]; + *(pWrite+2) = szHex[1]; + + pRead++; + pWrite += 3; + + continue; + } + + *pWrite = *pRead; + + pRead++; + pWrite++; + } + + *pWrite = '\0'; + + Temp.CalcDataSize(); + + hr = SetData( Temp.QueryStr() ); + if ( FAILED (hr) ) + { + goto Finished; + } + + Finished: + + return hr; + } + + VOID + Unescape( + VOID + ) + { + CHAR * pRead; + CHAR * pWrite; + CHAR szHex[3] = {0}; + BYTE c; + + pRead = (CHAR*)_pData; + pWrite = pRead; + + while ( *pRead ) + { + if ( IsEscapeSequence( pRead ) ) + { + szHex[0] = *(pRead+1); + szHex[1] = *(pRead+2); + + c = (BYTE)strtoul( szHex, NULL, 16 ); + + *pWrite = c; + + pRead += 3; + pWrite++; + + continue; + } + + *pWrite = *pRead; + + pRead++; + pWrite++; + } + + *pWrite = '\0'; + + CalcDataSize(); + + return; + } + + VOID + MoveToFront( + DWORD cbOffset + ) + { + if ( cbOffset >= _cbData ) + { + Reset(); + + return; + } + + MoveMemory( _pData, _pData + cbOffset, _cbData - cbOffset ); + + _cbData -= cbOffset; + } + + BOOL + IsWildcardMatch( + LPCSTR szExpr + ) + { + LPCSTR pExpr = szExpr; + LPCSTR pString = QueryStr(); + LPCSTR pSubMatch; + DWORD cchSubMatch; + + if ( !pExpr ) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + while ( *pExpr ) + { + switch ( *pExpr ) + { + case '*': + + // + // Eat '*' characters + // + + while ( *pExpr == '*' ) + { + pExpr++; + } + + // + // Find the next wildcard + // + + pSubMatch = strchr( pExpr, '*' ); + + cchSubMatch = (DWORD)(pSubMatch ? + pSubMatch - pExpr : + strlen( pExpr )); + + if ( cchSubMatch == 0 ) + { + // + // No submatch. The rest of + // pString automatically matches + // + + return TRUE; + } + + // + // Ensure that the current submatch exists + // + + while ( _strnicmp( pString, pExpr, cchSubMatch ) ) + { + pString++; + + if ( *pString == '\0' ) + { + // + // Not found + // + + return FALSE; + } + } + + pExpr += cchSubMatch; + pString += cchSubMatch; + + break; + + default: + + if ( TO_UPPER( *pExpr ) != TO_UPPER( *pString ) ) + { + return FALSE; + } + + pExpr++; + pString++; + } + } + + if ( *pString != '\0' ) + { + return FALSE; + } + + return TRUE; + } + +private: + + LPBYTE _pData; + DWORD _cbData; + DWORD _cbBuffer; + DWORD _cbMaxAlloc; + BYTE _Inline[STB_INLINE_SIZE+2]; + + VOID + GuaranteeNullTermination() + { + _pData[_cbData] = 0; + _pData[_cbData+1] = 0; + } + + BOOL + IsEscapeSequence( + CHAR * str + ) + { + if ( *str == '%' && + isxdigit( *(str+1) ) && + isxdigit( *(str+2) ) ) + { + return TRUE; + } + + return FALSE; + } + + BOOL + ShouldEscape( + BYTE c + ) + { + // + // If the character is listed in RFC2396, section + // 2.4.3 as control, space, delims or unwise, we + // should escape it. Also, we should escape characters + // with the high bit set. + // + + if ( c <= 0x1f || + c == 0x7f ) + { + // + // Control character + // + + goto ReturnTrue; + } + + if ( c >= 0x80 ) + { + // + // High bit set + // + + goto ReturnTrue; + } + + switch ( c ) + { + + // + // space + // + case ' ': + + // + // delims + // + case '<': + case '>': + case '#': + case '%': + case '\"': + + // + // unwise + // + case '{': + case '}': + case '|': + case '\\': + case '^': + case '[': + case ']': + case '`': + + goto ReturnTrue; + } + + // + // If we get here, then the character should not be + // escaped + // + + return FALSE; + + ReturnTrue: + + return TRUE; + } +}; + +#endif // _STBUFF_H diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/open-inc/stlist.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/open-inc/stlist.h new file mode 100644 index 0000000000..916c8576a8 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/open-inc/stlist.h @@ -0,0 +1,87 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#ifndef _STLIST_H +#define _STLIST_H + +#ifndef IsListEmpty + +#include + +#define IsListEmpty(ListHead) ((ListHead)->Flink == (ListHead)) + +VOID +inline +InitializeListHead( + LIST_ENTRY * ListHead + ) +{ + ListHead->Flink = ListHead->Blink = ListHead; +} + +BOOL +inline +RemoveEntryList( + LIST_ENTRY * Entry + ) +{ + LIST_ENTRY * Blink; + LIST_ENTRY * Flink; + + Flink = Entry->Flink; + Blink = Entry->Blink; + Blink->Flink = Flink; + Flink->Blink = Blink; + return (Flink == Blink); +} + +PLIST_ENTRY +inline +RemoveHeadList( + LIST_ENTRY * ListHead + ) +{ + LIST_ENTRY * Flink; + LIST_ENTRY * Entry; + + Entry = ListHead->Flink; + Flink = Entry->Flink; + ListHead->Flink = Flink; + Flink->Blink = ListHead; + return Entry; +} + +VOID +inline +InsertHeadList( + LIST_ENTRY * ListHead, + LIST_ENTRY * Entry + ) +{ + LIST_ENTRY * Flink; + + Flink = ListHead->Flink; + Entry->Flink = Flink; + Entry->Blink = ListHead; + Flink->Blink = Entry; + ListHead->Flink = Entry; +} + +VOID +inline +InsertTailList( + LIST_ENTRY * ListHead, + LIST_ENTRY * Entry + ) +{ + LIST_ENTRY * Blink; + + Blink = ListHead->Blink; + Entry->Flink = ListHead; + Entry->Blink = Blink; + Blink->Flink = Entry; + ListHead->Blink = Entry; +} + +#endif // IsListEmpty +#endif // _STLIST_H diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/open-inc/stlock.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/open-inc/stlock.h new file mode 100644 index 0000000000..6571489187 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/open-inc/stlock.h @@ -0,0 +1,149 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#ifndef _STLOCK_H +#define _STLOCK_H + +class STLOCK +{ +public: + + STLOCK() + : _fInitialized( FALSE ) + { + } + + ~STLOCK() + { + if ( _fInitialized ) + { + DeleteCriticalSection( &_cs ); + CloseHandle( _hReadersDone ); + } + } + + HRESULT + Initialize( + VOID + ) + { + HRESULT hr = S_OK; + BOOL fResult = FALSE; + + if ( !_fInitialized ) + { + _fWriterWaiting = FALSE; + _cReaders = 0; + + fResult = InitializeCriticalSectionAndSpinCount( &_cs, 100 ); + + if ( !fResult ) + { + hr = E_FAIL; + goto Finished; + } + + _hReadersDone = CreateEvent( NULL, + FALSE, + FALSE, + NULL ); + + if ( !_hReadersDone ) + { + DeleteCriticalSection( &_cs ); + hr = E_FAIL; + goto Finished; + } + + _fInitialized = TRUE; + } + +Finished: + return hr; + } + + BOOL + QueryInitialized() const + { + return _fInitialized; + } + + void SharedAcquire() + { + EnterCriticalSection( &_cs ); + InterlockedIncrement( &_cReaders ); + LeaveCriticalSection( &_cs ); + } + + void SharedRelease() + { + ReleaseInternal(); + } + + void ExclusiveAcquire() + { + EnterCriticalSection( &_cs ); + + _fWriterWaiting = TRUE; + + // + // If there are any readers, wait for them + // to release + // + + if ( InterlockedExchangeAdd( &_cReaders, 0 ) > 0 ) + { + WaitForSingleObject( _hReadersDone, INFINITE ); + } + + // + // Reader count -1 indicates that a writer has the lock + // + + _cReaders = -1; + } + + void ExclusiveRelease() + { + ReleaseInternal(); + } + +private: + + BOOL _fInitialized; + BOOL _fWriterWaiting; + LONG _cReaders; + CRITICAL_SECTION _cs; + HANDLE _hReadersDone; + + void ReleaseInternal() + { + LONG cReaders = InterlockedDecrement( &_cReaders ); + + if ( cReaders >= 0 ) + { + // + // Released a read lock. If this was the last + // reader and writers are waiting, set the + // readers done event + // + + if ( ( _fWriterWaiting ) && ( cReaders == 0 ) ) + { + SetEvent( _hReadersDone ); + } + } + else + { + // + // Released a write lock + // + + _cReaders = 0; + _fWriterWaiting = FALSE; + LeaveCriticalSection( &_cs ); + } + } +}; + +#endif // _STLOCK_H \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/open-inc/sttable.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/open-inc/sttable.h new file mode 100644 index 0000000000..0fd629af3d --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/open-inc/sttable.h @@ -0,0 +1,599 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#ifndef _STTABLE_H +#define _STTABLE_H + +#include +#include +#include "stbuff.h" +#include "stlock.h" +#include "stlist.h" + +#define DEFAULT_BUCKETS 97 // largest prime under 100 + +class ITEM; +class STTABLE_ITEM; + +typedef DWORD (WINAPI * PFN_HASH)(STBUFF*); +typedef BOOL (WINAPI * PFN_COMPARE_KEYS)(STBUFF*,STBUFF*); +typedef VOID (WINAPI * PFN_ITER)(STTABLE_ITEM*, BOOL*); + +class STTABLE_ITEM +{ +public: + + STTABLE_ITEM() + : _cRefs( 1 ) + { + InitializeListHead( &le ); + } + + VOID + Reference() + { + InterlockedIncrement( &_cRefs ); + } + + VOID + Dereference() + { + LONG cRefs = InterlockedDecrement( &_cRefs ); + + if ( cRefs == 0 ) + { + delete this; + } + } + + HRESULT + Initialize( + STBUFF * pKey + ) + { + return _buffKey.SetData( pKey->QueryPtr(), + pKey->QueryDataSize() ); + } + + STBUFF * + QueryKey() + { + return &_buffKey; + } + + virtual + ~STTABLE_ITEM() + {} + + LIST_ENTRY le; + +private: + + LONG _cRefs; + STBUFF _buffKey; +}; + +class STTABLE_BUCKET +{ +public: + + STTABLE_BUCKET() + : _pfnCompareKeys( NULL ) + {} + + virtual + ~STTABLE_BUCKET() + { + LIST_ENTRY * pEntry; + STTABLE_ITEM * pItem; + + while ( !IsListEmpty( &_Head ) ) + { + pEntry = RemoveHeadList( &_Head ); + + pItem = CONTAINING_RECORD( pEntry, + STTABLE_ITEM, + le ); + + pItem->Dereference(); + pItem = NULL; + } + } + + HRESULT + Initialize( + PFN_COMPARE_KEYS pfnCompareKeys = NULL + ) + { + InitializeListHead( &_Head ); + + _pfnCompareKeys = pfnCompareKeys; + + return _BucketLock.Initialize(); + } + + HRESULT + Insert( + STTABLE_ITEM * pNewItem + ) + { + LIST_ENTRY * pEntry; + STTABLE_ITEM * pItem; + HRESULT hr = S_OK; + + _BucketLock.ExclusiveAcquire(); + + // + // Check to see if the item is already in the list + // + + pEntry = _Head.Flink; + + while ( pEntry != &_Head ) + { + pItem = CONTAINING_RECORD( pEntry, + STTABLE_ITEM, + le ); + + if ( CompareKeys( pNewItem->QueryKey(), + pItem->QueryKey() ) ) + { + hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS); + goto Finished; + } + + pEntry = pEntry->Flink; + } + + // + // It's not in the list. Add it now + // + + pNewItem->Reference(); + InsertTailList( &_Head, &pNewItem->le ); + +Finished: + + _BucketLock.ExclusiveRelease(); + + return hr; + } + + HRESULT + Remove( + STTABLE_ITEM * pItemToRemove + ) + { + LIST_ENTRY * pEntry; + STTABLE_ITEM * pItem; + + _BucketLock.ExclusiveAcquire(); + + // + // Find the item in the list + // + + pEntry = _Head.Flink; + + while ( pEntry != &_Head ) + { + pItem = CONTAINING_RECORD( pEntry, + STTABLE_ITEM, + le ); + + if ( CompareKeys( pItemToRemove->QueryKey(), + pItem->QueryKey() ) ) + { + RemoveEntryList( &pItemToRemove->le ); + pItemToRemove->Dereference(); + pItemToRemove = NULL; + + goto Finished; + } + + pEntry = pEntry->Flink; + } + + // + // Item was not found. Set error code, but + // don't fail function. + // + + SetLastError (ERROR_FILE_NOT_FOUND); + +Finished: + + _BucketLock.ExclusiveRelease(); + + return S_OK; + } + + HRESULT + GetItem( + STBUFF * pKey, + STTABLE_ITEM **ppItem + ) + { + LIST_ENTRY * pEntry; + STTABLE_ITEM * pItem; + HRESULT hr = S_OK; + + _BucketLock.SharedAcquire(); + + // + // Find the item in the list + // + + pEntry = _Head.Flink; + + while ( pEntry != &_Head ) + { + pItem = CONTAINING_RECORD( pEntry, + STTABLE_ITEM, + le ); + + if ( CompareKeys( pKey, + pItem->QueryKey() ) ) + { + pItem->Reference(); + goto Finished; + } + + pEntry = pEntry->Flink; + } + + // + // Item was not found. + // + + pItem = NULL; + + hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); + +Finished: + + _BucketLock.SharedRelease(); + + *ppItem = pItem; + + return hr; + } + + VOID + Iterate( + PFN_ITER pIterFunction + ) + { + LIST_ENTRY * pEntry; + STTABLE_ITEM * pItem; + BOOL fRemoveItem; + + //////////////////////////////////////// + // + // It is assumed that this function will + // be called under a write lock + // + //////////////////////////////////////// + + // + // Walk the list and call the provided + // function on each item + // + + pEntry = _Head.Flink; + + while ( pEntry != &_Head ) + { + pItem = CONTAINING_RECORD( pEntry, + STTABLE_ITEM, + le ); + + // + // The iterator function might remove + // the item from the list, so we need + // to get the next link first + // + + pEntry = pEntry->Flink; + + pItem->Reference(); + pIterFunction( pItem, &fRemoveItem ); + + if ( fRemoveItem ) + { + RemoveEntryList( &pItem->le ); + pItem->Dereference(); + pItem = NULL; + } + } + + } + +private: + + LIST_ENTRY _Head; + STLOCK _BucketLock; + PFN_COMPARE_KEYS _pfnCompareKeys; + + BOOL + CompareKeys( + STBUFF * pKey1, + STBUFF * pKey2 + ) + { + if ( _pfnCompareKeys ) + { + return _pfnCompareKeys( pKey1, + pKey2 ); + } + + return ( strcmp( pKey1->QueryStr(), + pKey2->QueryStr() ) == 0 ); + } +}; + + +class STTABLE +{ +public: + + STTABLE() + : _cBuckets( 0 ), + _pfnHash( NULL ) + {} + + virtual + ~STTABLE() + { + STTABLE_BUCKET ** rgBuckets; + STTABLE_BUCKET * pBucket; + DWORD n; + + rgBuckets = (STTABLE_BUCKET**)_buffBucketPtrs.QueryPtr(); + + for( n = 0; n < _cBuckets; n++ ) + { + pBucket = rgBuckets[n]; + + delete pBucket; + pBucket = NULL; + } + } + + HRESULT + Initialize( + DWORD cBuckets = DEFAULT_BUCKETS, + PFN_HASH pfnHash = NULL, + PFN_COMPARE_KEYS pfnCompareKeys = NULL + ) + { + STTABLE_BUCKET ** rgBuckets; + DWORD n; + HRESULT hr = S_OK; + + // + // Create a buffer for the bucket array + // + + hr = _buffBucketPtrs.Resize( cBuckets * sizeof(STTABLE_BUCKET*) ); + + if ( FAILED (hr) ) + { + goto Finished; + } + + rgBuckets = (STTABLE_BUCKET**)_buffBucketPtrs.QueryPtr(); + + // + // Create the buckets + // + + for ( n = 0; n < cBuckets; n++ ) + { + STTABLE_BUCKET * pNewBucket = new STTABLE_BUCKET; + + if ( !pNewBucket ) + { + hr = E_OUTOFMEMORY; + goto Finished; + } + + hr = pNewBucket->Initialize( pfnCompareKeys ); + + if ( FAILED (hr) ) + { + delete pNewBucket; + pNewBucket = NULL; + + goto Finished; + } + + rgBuckets[n] = pNewBucket; + pNewBucket = NULL; + + _cBuckets++; + } + + // + // Initialize the table lock + // + + _TableLock.Initialize(); + + // + // Set the hash function + // + + _pfnHash = pfnHash; + +Finished: + return hr; + } + + HRESULT + Insert( + STTABLE_ITEM * pNewItem + ) + { + + DWORD dwHash; + STTABLE_BUCKET * pBucket; + HRESULT hr = S_OK; + + dwHash = ComputeHash( pNewItem->QueryKey() ); + + pBucket = GetBucket( dwHash ); + + _TableLock.SharedAcquire(); + + hr = pBucket->Insert( pNewItem ); + + _TableLock.SharedRelease(); + + return hr; + } + + HRESULT + Remove( + STTABLE_ITEM * pItemToRemove + ) + { + DWORD dwHash; + STTABLE_BUCKET * pBucket; + HRESULT hr = S_OK; + + dwHash = ComputeHash( pItemToRemove->QueryKey() ); + + pBucket = GetBucket( dwHash ); + + _TableLock.SharedAcquire(); + + hr = pBucket->Remove( pItemToRemove ); + + _TableLock.SharedRelease(); + + return hr; + } + + HRESULT + GetItem( + STBUFF * pKey, + STTABLE_ITEM **ppItem + ) + { + DWORD dwHash; + STTABLE_BUCKET * pBucket; + STTABLE_ITEM * pRet; + HRESULT hr = S_OK; + + dwHash = ComputeHash( pKey ); + + pBucket = GetBucket( dwHash ); + + _TableLock.SharedAcquire(); + + hr = pBucket->GetItem( pKey, &pRet ); + if(FAILED( hr)) + { + pRet = NULL; + goto Finished; + } + + Finished: + + _TableLock.SharedRelease(); + + *ppItem = pRet; + + return hr; + } + + VOID + Iterate( + PFN_ITER pIterFunction + ) + { + STTABLE_BUCKET ** rgBuckets; + DWORD n; + + _TableLock.ExclusiveAcquire(); + + rgBuckets = (STTABLE_BUCKET**)_buffBucketPtrs.QueryPtr(); + + // + // Iterate each bucket + // + + for ( n = 0; n < _cBuckets; n++ ) + { + STTABLE_BUCKET * pBucket; + + pBucket = rgBuckets[n]; + + pBucket->Iterate( pIterFunction ); + + pBucket = NULL; + } + + _TableLock.ExclusiveRelease(); + } + +private: + + STBUFF _buffBucketPtrs; + DWORD _cBuckets; + STLOCK _TableLock; + PFN_HASH _pfnHash; + + DWORD + ComputeHash( + STBUFF * pKey + ) + { + if ( _pfnHash ) + { + return _pfnHash( pKey ); + } + + return HashString( pKey->QueryStr() ); + } + + STTABLE_BUCKET * + GetBucket( + DWORD dwHash + ) + { + STTABLE_BUCKET ** rgBuckets; + + rgBuckets = (STTABLE_BUCKET**)_buffBucketPtrs.QueryPtr(); + + return rgBuckets[dwHash % _cBuckets]; + } + + DWORD + WINAPI + HashString( + LPCSTR szString + ) + { + DWORD dwRet = 0; + + // + // Create a hash by adding up the ascii values + // of each character in a case-insensitive manner + // + + if ( szString ) + { + while ( *szString ) + { + dwRet += ( (*szString) | 0x20 ); + szString++; + } + } + + return dwRet; + } +}; + +#endif // _STTABLE_H diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/open-inc/sttimer.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/open-inc/sttimer.h new file mode 100644 index 0000000000..f5a10817a5 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/open-inc/sttimer.h @@ -0,0 +1,232 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#ifndef _STTIMER_H +#define _STTIMER_H + +class STTIMER +{ +public: + + STTIMER() + : _pTimer( NULL ) + { + } + + virtual + ~STTIMER() + { + if ( _pTimer ) + { + CancelTimer(); + + CloseThreadpoolTimer( _pTimer ); + + _pTimer = NULL; + } + } + + HRESULT + InitializeTimer( + PTP_TIMER_CALLBACK pfnCallback, + VOID * pContext, + DWORD dwInitialWait = 0, + DWORD dwPeriod = 0 + ) + { + _pTimer = CreateThreadpoolTimer( pfnCallback, + pContext, + NULL ); + + if ( !_pTimer ) + { + return HRESULT_FROM_WIN32( GetLastError() ); + } + + if ( dwInitialWait ) + { + SetTimer( dwInitialWait, + dwPeriod ); + } + + return S_OK; + } + + VOID + SetTimer( + DWORD dwInitialWait, + DWORD dwPeriod = 0 + ) + { + FILETIME ftInitialWait; + + if ( dwInitialWait == 0 && dwPeriod == 0 ) + { + // + // Special case. We are preventing new callbacks + // from being queued. Any existing callbacks in the + // queue will still run. + // + // This effectively disables the timer. It can be + // re-enabled by setting non-zero initial wait or + // period values. + // + + SetThreadpoolTimer( _pTimer, NULL, 0, 0 ); + return; + } + + InitializeRelativeFileTime( &ftInitialWait, dwInitialWait ); + + SetThreadpoolTimer( _pTimer, + &ftInitialWait, + dwPeriod, + 0 ); + } + + VOID + CancelTimer() + { + // + // Disable the timer + // + + SetTimer( 0 ); + + // + // Wait until any callbacks queued prior to disabling + // have completed. + // + + WaitForThreadpoolTimerCallbacks( _pTimer, TRUE ); + } + +private: + + VOID + InitializeRelativeFileTime( + FILETIME * pft, + DWORD dwMilliseconds + ) + { + LARGE_INTEGER li; + + // + // The pftDueTime parameter expects the time to be + // expressed as the number of 100 nanosecond intervals + // times -1. + // + // To convert from milliseconds, we'll multiply by + // -10000 + // + + li.QuadPart = (LONGLONG)dwMilliseconds * -10000; + + pft->dwHighDateTime = li.HighPart; + pft->dwLowDateTime = li.LowPart; + }; + + TP_TIMER * _pTimer; +}; + +class STELAPSED +{ +public: + + STELAPSED() + : _dwInitTime( 0 ), + _dwInitTickCount( 0 ), + _dwPerfCountsPerMillisecond( 0 ), + _fUsingHighResolution( FALSE ) + { + LARGE_INTEGER li; + BOOL fResult; + + _dwInitTickCount = GetTickCount64(); + + fResult = QueryPerformanceFrequency( &li ); + + if ( !fResult ) + { + goto Finished; + } + + _dwPerfCountsPerMillisecond = li.QuadPart / 1000; + + fResult = QueryPerformanceCounter( &li ); + + if ( !fResult ) + { + goto Finished; + } + + _dwInitTime = li.QuadPart / _dwPerfCountsPerMillisecond; + + _fUsingHighResolution = TRUE; + +Finished: + + return; + } + + virtual + ~STELAPSED() + { + } + + LONGLONG + QueryElapsedTime() + { + LARGE_INTEGER li; + + if ( _fUsingHighResolution && QueryPerformanceCounter( &li ) ) + { + DWORD64 dwCurrentTime = li.QuadPart / _dwPerfCountsPerMillisecond; + + if ( dwCurrentTime < _dwInitTime ) + { + // + // It's theoretically possible that QueryPerformanceCounter + // may return slightly different values on different CPUs. + // In this case, we don't want to return an unexpected value + // so we'll return zero. This is acceptable because + // presumably such a case would only happen for a very short + // time window. + // + // It would be possible to prevent this by ensuring processor + // affinity for all calls to QueryPerformanceCounter, but that + // would be undesirable in the general case because it could + // introduce unnecessary context switches and potentially a + // CPU bottleneck. + // + // Note that this issue also applies to callers doing rapid + // calls to this function. If a caller wants to mitigate + // that, they could enforce the affinitization, or they + // could implement a similar sanity check when comparing + // returned values from this function. + // + + return 0; + } + + return dwCurrentTime - _dwInitTime; + } + + return GetTickCount64() - _dwInitTickCount; + } + + BOOL + QueryUsingHighResolution() + { + return _fUsingHighResolution; + } + +private: + + DWORD64 _dwInitTime; + DWORD64 _dwInitTickCount; + DWORD64 _dwPerfCountsPerMillisecond; + BOOL _fUsingHighResolution; +}; + +#endif // _STTIMER_H \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/include/dbgutil2.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/include/dbgutil2.h new file mode 100644 index 0000000000..1c4d2d4381 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/include/dbgutil2.h @@ -0,0 +1,49 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +# ifndef _DBGUTIL_H_ +# define _DBGUTIL_H_ + + +// begin_user_modifiable + +// +// define DEBUG_FLAGS_VAR to assure that DebugFlags will stay private to +// iisutil. This is important in the case when iisutil is linked as static library +// +#define DEBUG_FLAGS_VAR g_dwDebugFlagsIISUtil + +// +// Modify the following flags if necessary +// + +# define DEFAULT_OUTPUT_FLAGS ( DbgOutputKdb ) + + +// end_user_modifiable +// begin_user_unmodifiable + + + +/************************************************************ + * Include Headers + ************************************************************/ + +# include + + +// +// Define the debugging constants +// + +# define DEBUG_ALLOC_CACHE 0x01000000 +# define DEBUG_SCHED 0x02000000 +# define DEBUG_RESOURCE 0x04000000 +# define DEBUG_INET_MONITOR 0x08000000 +# define DEBUG_PIPEDATA 0x10000000 + +// Use the default constants from pudebug.h + +# endif /* _DBGUTIL_H_ */ + +/************************ End of File ***********************/ diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/include/irtldbg.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/include/irtldbg.h new file mode 100644 index 0000000000..3c6c48e7b1 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/include/irtldbg.h @@ -0,0 +1,154 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#ifndef __IRTLDBG_H__ +#define __IRTLDBG_H__ + +#ifndef __IRTLMISC_H__ +# include +#endif + +/* Ensure that MessageBoxes can popup */ +# define RUNNING_AS_SERVICE 1 + + +#ifdef _AFX + /* Assure compatiblity with MFC */ + +# define IRTLASSERT(x) ASSERT(x) +# define IRTLVERIFY(x) VERIFY(x) + +#else /* !_AFX */ + +# if DBG || defined(_DEBUG) +# define IRTLDEBUG +# endif + +# if defined(IRTLDEBUG) +# ifndef USE_DEBUG_CRTS + /* IIS (and NT) do not ship msvcrtD.dll, per the VC license, + * so we can't use the assertion code from . Use similar + * macros from instead. */ +# include + + /* workaround for /W4 warnings about 'constant expressions' */ +# define IRTLASSERT(f) \ + ((void) ((f) || (PuDbgAssertFailed(DBG_CONTEXT, #f, ""), 0) )) + +# elif defined(_MSC_VER) && (_MSC_VER >= 1000) + /* Use the new debugging tools in Visual C++ 4.x */ +# include + /* _ASSERTE will give a more meaningful message, but the string takes + * space. Use _ASSERT if this is an issue. */ +# define IRTLASSERT(f) _ASSERTE(f) +# else +# include +# define IRTLASSERT(f) assert(f) +# endif + +# ifdef _PREFAST_ +# undef IRTLASSERT +# define IRTLASSERT(f) ((void)0) +# endif + +# define IRTLVERIFY(f) IRTLASSERT(f) +# define DEBUG_ONLY(f) (f) +# define TRACE IrtlTrace +# define TRACE0(psz) IrtlTrace(_T("%s"), _T(psz)) +# define TRACE1(psz, p1) IrtlTrace(_T(psz), p1) +# define TRACE2(psz, p1, p2) IrtlTrace(_T(psz), p1, p2) +# define TRACE3(psz, p1, p2, p3) IrtlTrace(_T(psz), p1, p2, p3) +# define ASSERT_VALID(pObj) \ + do {IRTLASSERT((pObj) != NULL); (pObj)->AssertValid();} while (0) +# define DUMP(pObj) \ + do {IRTLASSERT((pObj) != NULL); (pObj)->Dump();} while (0) + +# else /* !_DEBUG */ + + /* These macros should all compile away to nothing */ +# define IRTLASSERT(f) ((void)0) +# define IRTLVERIFY(f) ((void)(f)) +# define DEBUG_ONLY(f) ((void)0) +# define TRACE 1 ? (void)0 : IrtlTrace +# define TRACE0(psz) +# define TRACE1(psz, p1) +# define TRACE2(psz, p1, p2) +# define TRACE3(psz, p1, p2, p3) +# define ASSERT_VALID(pObj) ((void)0) +# define DUMP(pObj) ((void)0) + +# endif /* !_DEBUG */ + + +# define ASSERT_POINTER(p, type) \ + IRTLASSERT((p) != NULL) + +#define ASSERT_STRING(s) \ + IRTLASSERT(((s) != NULL)) + +/* Declarations for non-Windows apps */ + +# ifndef _WINDEF_ +typedef void* LPVOID; +typedef const void* LPCVOID; +typedef unsigned int UINT; +typedef int BOOL; +typedef const char* LPCTSTR; +# endif /* _WINDEF_ */ + +# ifndef TRUE +# define FALSE 0 +# define TRUE 1 +# endif + +#endif /* !_AFX */ + + +#ifdef __cplusplus + +// Compile-time (not run-time) assertion. Code will not compile if +// expr is false. Note: there is no non-debug version of this; we +// want this for all builds. The compiler optimizes the code away. +template struct static_checker; +template <> struct static_checker {}; // specialize only for `true' +#define STATIC_ASSERT(expr) static_checker< (expr) >() + +#endif /* !__cplusplus */ + +/* Writes trace messages to debug stream */ +extern +#ifdef __cplusplus +"C" +#endif /* !__cplusplus */ +IRTL_DLLEXP +void __cdecl +IrtlTrace( + LPCTSTR pszFormat, + ...); + + +#ifdef _DEBUG +# define IRTL_DEBUG_INIT() IrtlDebugInit() +# define IRTL_DEBUG_TERM() IrtlDebugTerm() +#else /* !_DEBUG */ +# define IRTL_DEBUG_INIT() ((void)0) +# define IRTL_DEBUG_TERM() ((void)0) +#endif /* !_DEBUG */ + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* should be called from main(), WinMain(), or DllMain() */ +IRTL_DLLEXP void +IrtlDebugInit(); + +IRTL_DLLEXP void +IrtlDebugTerm(); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __IRTLDBG_H__ */ diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/include/irtlmisc.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/include/irtlmisc.h new file mode 100644 index 0000000000..02bfa2d065 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/include/irtlmisc.h @@ -0,0 +1,131 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#ifndef __IRTLMISC_H__ +#define __IRTLMISC_H__ + +#include + +//-------------------------------------------------------------------- +// These declarations are needed to export the template classes from +// IisRtl.DLL and import them into other modules. + +// DEBGUDEBUG +/** +#ifndef IRTL_DLLEXP +# ifdef DLL_IMPLEMENTATION +# define IRTL_DLLEXP __declspec(dllexport) +# ifdef IMPLEMENTATION_EXPORT +# define IRTL_EXPIMP +# else +# undef IRTL_EXPIMP +# endif +# elif defined LIB_IMPLEMENTATION +# define IRTL_DLLEXP +# define IRTL_EXPIMP extern +# else +# define IRTL_DLLEXP __declspec(dllimport) +# define IRTL_EXPIMP extern +# endif // !DLL_IMPLEMENTATION +#endif // !IRTL_DLLEXP +*/ + +#define IRTL_DLLEXP +#define IRTL_EXPIMP + + + + + +//-------------------------------------------------------------------- +// Miscellaneous functions + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + + +// Heap routines + +// Private IIS heap +HANDLE +WINAPI +IisHeap(); + +// Allocate dwBytes +LPVOID +WINAPI +IisMalloc( + IN SIZE_T dwBytes); + +// Allocate dwBytes. Memory is zeroed +LPVOID +WINAPI +IisCalloc( + IN SIZE_T dwBytes); + +// Reallocate lpMem to dwBytes +LPVOID +WINAPI +IisReAlloc( + IN LPVOID lpMem, + IN SIZE_T dwBytes); + +// Free lpMem +BOOL +WINAPI +IisFree( + IN LPVOID lpMem); + +// additional IISRTL initialization +BOOL +WINAPI +InitializeIISRTL(); + +// call before unloading IISRTL +void +WINAPI +TerminateIISRTL(); + +// case-insensitive strstr +IRTL_DLLEXP const char* stristr(const char* pszString, const char* pszSubString); + +// how many CPUs on this machine? +inline int NumProcessors() +{ + static int s_nCPUs = 0; + + if (s_nCPUs == 0) + { + SYSTEM_INFO si; + GetSystemInfo(&si); + s_nCPUs = si.dwNumberOfProcessors; + } + return s_nCPUs; +} + + +// how many CPUs on this machine? +inline int ProcessorType() +{ + static int s_nProcessorType = 0; + + if (s_nProcessorType == 0) + { + SYSTEM_INFO si; + GetSystemInfo(&si); + s_nProcessorType = si.dwProcessorType; + } + return s_nProcessorType; +} + + +#ifdef __cplusplus +} +#endif // __cplusplus + +#define HRESULT_FROM_GLE() ( GetLastError() != NO_ERROR ) \ + ? HRESULT_FROM_WIN32( GetLastError() ) \ + : E_FAIL + +#endif // __IRTLMISC_H__ diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/include/memorylog.hxx b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/include/memorylog.hxx new file mode 100644 index 0000000000..effa543259 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/include/memorylog.hxx @@ -0,0 +1,67 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#ifndef _MEMORYLOG_HXX_ +#define _MEMORYLOG_HXX_ + +//#include "buffer.hxx" + +class CMemoryLog +{ +public: + CMemoryLog(DWORD dwMaxByteSize); + ~CMemoryLog(); + + // + // Override the new and delete operator to make them + // use LocalAlloc so that CMemoryLog + // can be safely constructed and deleted + // in the DllMain() + // + + VOID * + operator new( + size_t size + ) + { + return LocalAlloc( LPTR, size ); + } + + VOID + operator delete( + VOID * pMemoryLog + ) + { + DBG_ASSERT( pMemoryLog != NULL ); + LocalFree( pMemoryLog ); + } + + // appends to memory log + DWORD Append(LPCSTR pszOutput, + DWORD cchLen + ); +private: + CMemoryLog(); + + // pointer to the beginning of the memory buffer + CHAR *m_pBufferBegin; + // pointer to the byte 1 beyond the end of the last message + CHAR *m_pLastMessageEnd; + // pointer to the end of the memory buffer + CHAR *m_pBufferEnd; + + // Used for storage + BUFFER m_buf; + + // TRUE if storage could be allocated, otherwise FALSE + BOOL m_fValid; + + CRITICAL_SECTION m_cs; + + // to be able to tell if the critsec was initialized successfully + BOOL m_fCritSecInitialized; + +}; + +#endif // _MEMORYLOG_HXX_ + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/include/precomp.hxx b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/include/precomp.hxx new file mode 100644 index 0000000000..d012c7ee29 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/include/precomp.hxx @@ -0,0 +1,9 @@ +#include +#include "tchar.h" +#include "dbgutil.h" +#include "ntassert.h" +#include "buffer.h" +#include "stringa.h" +#include "stringu.h" +#include "stdlib.h" +#include "stdio.h" diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/include/pudebug.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/include/pudebug.h new file mode 100644 index 0000000000..d42153d457 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/include/pudebug.h @@ -0,0 +1,748 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#if !defined(BUILD_PUDEBUG) +// +// if we are not using this header for building the pudebug library +// then better this be used with dbgutil.h +// + # ifndef _DBGUTIL_H_ + // error Please make sure you included dbgutil.h! + // error Do not include pudebug.h directly + #include + # endif // _DBGUTIL_H_ +#endif + +# ifndef _PUDEBUG_H_ +# define _PUDEBUG_H_ + +#ifndef _NO_TRACING_ +# define _NO_TRACING_ +#endif // _NO_TRACING_ + +/************************************************************ + * Include Headers + ************************************************************/ + +# ifdef __cplusplus +extern "C" { +# endif // __cplusplus + +# include + +# ifndef dllexp +# define dllexp __declspec( dllexport) +# endif // dllexp + +#include + +#ifndef IN_OUT +#define IN_OUT __inout +#endif + +/*********************************************************** + * Macros + ************************************************************/ + +enum PRINT_REASONS { + PrintNone = 0x0, // Nothing to be printed + PrintError = 0x1, // An error message + PrintWarning = 0x2, // A warning message + PrintLog = 0x3, // Just logging. Indicates a trace of where ... + PrintMsg = 0x4, // Echo input message + PrintCritical = 0x5, // Print and Exit + PrintAssertion= 0x6 // Printing for an assertion failure + }; + + +enum DEBUG_OUTPUT_FLAGS { + DbgOutputNone = 0x0, // None + DbgOutputKdb = 0x1, // Output to Kernel Debugger + DbgOutputLogFile = 0x2, // Output to LogFile + DbgOutputTruncate = 0x4, // Truncate Log File if necessary + DbgOutputStderr = 0x8, // Send output to std error + DbgOutputBackup = 0x10, // Make backup of debug file ? + DbgOutputMemory = 0x20, // Dump to memory buffer + DbgOutputAll = 0xFFFFFFFF // All the bits set. + }; + + +# define MAX_LABEL_LENGTH ( 100) + + +// The following flags are used internally to track what level of tracing we +// are currently using. Bitmapped for extensibility. +#define DEBUG_FLAG_ODS 0x00000001 +//#define DEBUG_FLAG_INFO 0x00000002 +//#define DEBUG_FLAG_WARN 0x00000004 +//#define DEBUG_FLAG_ERROR 0x00000008 +// The following are used internally to determine whether to log or not based +// on what the current state is +//#define DEBUG_FLAGS_INFO (DEBUG_FLAG_ODS | DEBUG_FLAG_INFO) +//#define DEBUG_FLAGS_WARN (DEBUG_FLAG_ODS | DEBUG_FLAG_INFO | DEBUG_FLAG_WARN) +//#define DEBUG_FLAGS_ERROR (DEBUG_FLAG_ODS | DEBUG_FLAG_INFO | DEBUG_FLAG_WARN | DEBUG_FLAG_ERROR) + +#define DEBUG_FLAGS_ANY (DEBUG_FLAG_INFO | DEBUG_FLAG_WARN | DEBUG_FLAG_ERROR) + +// +// user of DEBUG infrastructure may choose unique variable name for DEBUG_FLAGS +// that's specially useful for cases where DEBUG infrastructure is used within +// static library (static library may prefer to maintain it's own DebugFlags independent +// on the main program it links to +// +#ifndef DEBUG_FLAGS_VAR +#define DEBUG_FLAGS_VAR g_dwDebugFlags +#endif + +extern +#ifdef __cplusplus +"C" +# endif // _cplusplus + DWORD DEBUG_FLAGS_VAR ; // Debugging Flags + +# define DECLARE_DEBUG_VARIABLE() + +# define SET_DEBUG_FLAGS( dwFlags) DEBUG_FLAGS_VAR = dwFlags +# define GET_DEBUG_FLAGS() ( DEBUG_FLAGS_VAR ) + +# define LOAD_DEBUG_FLAGS_FROM_REG(hkey, dwDefault) \ + DEBUG_FLAGS_VAR = PuLoadDebugFlagsFromReg((hkey), (dwDefault)) + +# define LOAD_DEBUG_FLAGS_FROM_REG_STR(pszRegKey, dwDefault) \ + DEBUG_FLAGS_VAR = PuLoadDebugFlagsFromRegStr((pszRegKey), (dwDefault)) + +# define SAVE_DEBUG_FLAGS_IN_REG(hkey, dwDbg) \ + PuSaveDebugFlagsInReg((hkey), (dwDbg)) + +# define DEBUG_IF( arg, s) if ( DEBUG_ ## arg & GET_DEBUG_FLAGS()) { \ + s \ + } else {} + +# define IF_DEBUG( arg) if ( DEBUG_## arg & GET_DEBUG_FLAGS()) + + +/*++ + class DEBUG_PRINTS + + This class is responsible for printing messages to log file / kernel debugger + + Currently the class supports only member functions for char. + ( not unicode-strings). + +--*/ + + +typedef struct _DEBUG_PRINTS { + + CHAR m_rgchLabel[MAX_LABEL_LENGTH]; + CHAR m_rgchLogFilePath[MAX_PATH]; + CHAR m_rgchLogFileName[MAX_PATH]; + HANDLE m_LogFileHandle; + HANDLE m_StdErrHandle; + BOOL m_fInitialized; + BOOL m_fBreakOnAssert; + DWORD m_dwOutputFlags; + VOID *m_pMemoryLog; +} DEBUG_PRINTS, FAR * LPDEBUG_PRINTS; + + +LPDEBUG_PRINTS +PuCreateDebugPrintsObject( + IN const char * pszPrintLabel, + IN DWORD dwOutputFlags); + +// +// frees the debug prints object and closes any file if necessary. +// Returns NULL on success or returns pDebugPrints on failure. +// +LPDEBUG_PRINTS +PuDeleteDebugPrintsObject( + IN_OUT LPDEBUG_PRINTS pDebugPrints); + + +VOID +PuDbgPrint( + IN_OUT LPDEBUG_PRINTS pDebugPrints, + IN const char * pszFilePath, + IN int nLineNum, + IN const char * pszFunctionName, + IN const char * pszFormat, + ...); + // arglist +VOID +PuDbgPrintW( + IN_OUT LPDEBUG_PRINTS pDebugPrints, + IN const char * pszFilePath, + IN int nLineNum, + IN const char * pszFunctionName, + IN const WCHAR * pszFormat, + ...); // arglist + +// PuDbgPrintError is similar to PuDbgPrint() but allows +// one to print error code in friendly manner +VOID +PuDbgPrintError( + IN_OUT LPDEBUG_PRINTS pDebugPrints, + IN const char * pszFilePath, + IN int nLineNum, + IN const char * pszFunctionName, + IN DWORD dwError, + IN const char * pszFormat, + ...); // arglist + +/*++ + PuDbgDump() does not do any formatting of output. + It just dumps the given message onto the debug destinations. +--*/ +VOID +PuDbgDump( + IN_OUT LPDEBUG_PRINTS pDebugPrints, + IN const char * pszFilePath, + IN int nLineNum, + IN const char * pszFunctionName, + IN const char * pszDump + ); + +// +// PuDbgAssertFailed() *must* be __cdecl to properly capture the +// thread context at the time of the failure. +// + +INT +__cdecl +PuDbgAssertFailed( + IN_OUT LPDEBUG_PRINTS pDebugPrints, + IN const char * pszFilePath, + IN int nLineNum, + IN const char * pszFunctionName, + IN const char * pszExpression, + IN const char * pszMessage); + +INT +WINAPI +PuDbgPrintAssertFailed( + IN_OUT LPDEBUG_PRINTS pDebugPrints, + IN const char * pszFilePath, + IN int nLineNum, + IN const char * pszFunctionName, + IN const char * pszExpression, + IN const char * pszMessage); + +VOID +PuDbgCaptureContext ( + OUT PCONTEXT ContextRecord + ); + +VOID +PuDbgPrintCurrentTime( + IN_OUT LPDEBUG_PRINTS pDebugPrints, + IN const char * pszFilePath, + IN int nLineNum, + IN const char * pszFunctionName + ); + +VOID +PuSetDbgOutputFlags( + IN_OUT LPDEBUG_PRINTS pDebugPrints, + IN DWORD dwFlags); + +DWORD +PuGetDbgOutputFlags( + IN const LPDEBUG_PRINTS pDebugPrints); + + +// +// Following functions return Win32 error codes. +// NO_ERROR if success +// + +DWORD +PuOpenDbgPrintFile( + IN_OUT LPDEBUG_PRINTS pDebugPrints, + IN const char * pszFileName, + IN const char * pszPathForFile); + +DWORD +PuReOpenDbgPrintFile( + IN_OUT LPDEBUG_PRINTS pDebugPrints); + +DWORD +PuCloseDbgPrintFile( + IN_OUT LPDEBUG_PRINTS pDebugPrints); + +DWORD +PuOpenDbgMemoryLog( + IN_OUT LPDEBUG_PRINTS pDebugPrints); + +DWORD +PuCloseDbgMemoryLog( + IN_OUT LPDEBUG_PRINTS pDebugPrints); + +DWORD +PuLoadDebugFlagsFromReg(IN HKEY hkey, IN DWORD dwDefault); + +DWORD +PuLoadDebugFlagsFromRegStr(IN LPCSTR pszRegKey, IN DWORD dwDefault); + +DWORD +PuSaveDebugFlagsInReg(IN HKEY hkey, IN DWORD dwDbg); + + +# define PuPrintToKdb( pszOutput) \ + if ( pszOutput != NULL) { \ + OutputDebugString( pszOutput); \ + } else {} + + + +# ifdef __cplusplus +}; +# endif // __cplusplus + +// begin_user_unmodifiable + + + +/*********************************************************** + * Macros + ************************************************************/ + + +extern +#ifdef __cplusplus +"C" +# endif // _cplusplus +DEBUG_PRINTS * g_pDebug; // define a global debug variable + +# if DBG + +// For the CHK build we want ODS enabled. For an explanation of these flags see +// the comment just after the definition of DBG_CONTEXT +# define DECLARE_DEBUG_PRINTS_OBJECT() \ + DEBUG_PRINTS * g_pDebug = NULL; \ + DWORD DEBUG_FLAGS_VAR = DEBUG_FLAG_ERROR; + +#else // !DBG + +# define DECLARE_DEBUG_PRINTS_OBJECT() \ + DEBUG_PRINTS * g_pDebug = NULL; \ + DWORD DEBUG_FLAGS_VAR = 0; + +#endif // !DBG + + +// +// Call the following macro as part of your initialization for program +// planning to use the debugging class. +// +/** DEBUGDEBUG +# define CREATE_DEBUG_PRINT_OBJECT( pszLabel) \ + g_pDebug = PuCreateDebugPrintsObject( pszLabel, DEFAULT_OUTPUT_FLAGS);\ + if ( g_pDebug == NULL) { \ + OutputDebugStringA( "Unable to Create Debug Print Object \n"); \ + } +*/ + +// +// Call the following macro once as part of the termination of program +// which uses the debugging class. +// +# define DELETE_DEBUG_PRINT_OBJECT( ) \ + g_pDebug = PuDeleteDebugPrintsObject( g_pDebug); + + +# define VALID_DEBUG_PRINT_OBJECT() \ + ( ( g_pDebug != NULL) && g_pDebug->m_fInitialized) + + +// +// Use the DBG_CONTEXT without any surrounding braces. +// This is used to pass the values for global DebugPrintObject +// and File/Line information +// +//# define DBG_CONTEXT g_pDebug, __FILE__, __LINE__, __FUNCTION__ + +// The 3 main tracing macros, each one corresponds to a different level of +// tracing + +// The 3 main tracing macros, each one corresponds to a different level of +// tracing +//# define DBGINFO(args) {if (DEBUG_FLAGS_VAR & DEBUG_FLAGS_INFO) { PuDbgPrint args; }} +//# define DBGWARN(args) {if (DEBUG_FLAGS_VAR & DEBUG_FLAGS_WARN) { PuDbgPrint args; }} +//# define DBGERROR(args) {if (DEBUG_FLAGS_VAR & DEBUG_FLAGS_ERROR) { PuDbgPrint args; }} + +# define DBGINFOW(args) {if (DEBUG_FLAGS_VAR & DEBUG_FLAGS_INFO) { PuDbgPrintW args; }} +# define DBGWARNW(args) {if (DEBUG_FLAGS_VAR & DEBUG_FLAGS_WARN) { PuDbgPrintW args; }} +# define DBGERRORW(args) {if (DEBUG_FLAGS_VAR & DEBUG_FLAGS_ERROR) { PuDbgPrintW args; }} + + +// +// DBGPRINTF() is printing function ( much like printf) but always called +// with the DBG_CONTEXT as follows +// DBGPRINTF( ( DBG_CONTEXT, format-string, arguments for format list)); +// +# define DBGPRINTF DBGINFO + +// +// DPERROR() is printing function ( much like printf) but always called +// with the DBG_CONTEXT as follows +// DPERROR( ( DBG_CONTEXT, error, format-string, +// arguments for format list)); +// +# define DPERROR( args) {if (DEBUG_FLAGS_VAR & DEBUG_FLAGS_ERROR) { PuDbgPrintError args; }} + +# if DBG + +# define DBG_CODE(s) s /* echoes code in debugging mode */ + +// The same 3 main tracing macros however in this case the macros are only compiled +// into the CHK build. This is necessary because some tracing info used functions or +// variables which are not compiled into the FRE build. +# define CHKINFO(args) { PuDbgPrint args; } +# define CHKWARN(args) { PuDbgPrint args; } +# define CHKERROR(args) { PuDbgPrint args; } + +# define CHKINFOW(args) { PuDbgPrintW args; } +# define CHKWARNW(args) { PuDbgPrintW args; } +# define CHKERRORW(args) { PuDbgPrintW args; } + + +#ifndef DBG_ASSERT +# ifdef _PREFAST_ +# define DBG_ASSERT(exp) ((void)0) /* Do Nothing */ +# define DBG_ASSERT_MSG(exp, pszMsg) ((void)0) /* Do Nothing */ +# define DBG_REQUIRE( exp) ((void) (exp)) +# else // !_PREFAST_ +# define DBG_ASSERT( exp ) \ + ( (VOID)( ( exp ) || ( DebugBreak(), \ + PuDbgPrintAssertFailed( DBG_CONTEXT, #exp, "" ) ) ) ) + +# define DBG_ASSERT_MSG( exp, pszMsg) \ + ( (VOID)( ( exp ) || ( DebugBreak(), \ + PuDbgPrintAssertFailed( DBG_CONTEXT, #exp, pszMsg ) ) ) ) + +# define DBG_REQUIRE( exp ) \ + DBG_ASSERT( exp ) +# endif // !_PREFAST_ +#endif + + +# define DBG_LOG() PuDbgPrint( DBG_CONTEXT, "\n" ) + +# define DBG_OPEN_LOG_FILE( pszFile, pszPath ) \ + PuOpenDbgPrintFile( g_pDebug, (pszFile), (pszPath) ) + +# define DBG_CLOSE_LOG_FILE( ) \ + PuCloseDbgPrintFile( g_pDebug ) + +# define DBG_OPEN_MEMORY_LOG( ) \ + PuOpenDbgMemoryLog( g_pDebug ) + + +# define DBGDUMP( args ) PuDbgDump args + +# define DBGPRINT_CURRENT_TIME() PuDbgPrintCurrentTime( DBG_CONTEXT ) + +# else // !DBG + +# define DBG_CODE(s) ((void)0) /* Do Nothing */ + +# define CHKINFO(args) ((void)0) /* Do Nothing */ +# define CHKWARN(args) ((void)0) /* Do Nothing */ +# define CHKERROR(args) ((void)0) /* Do Nothing */ + +# define CHKINFOW(args) ((void)0) /* Do Nothing */ +# define CHKWARNW(args) ((void)0) /* Do Nothing */ +# define CHKERRORW(args) ((void)0) /* Do Nothing */ + +#ifndef DBG_ASSERT +# define DBG_ASSERT(exp) ((void)0) /* Do Nothing */ + +# define DBG_ASSERT_MSG(exp, pszMsg) ((void)0) /* Do Nothing */ + +# define DBG_REQUIRE( exp) ((void) (exp)) +#endif // !DBG_ASSERT + +# define DBGDUMP( args) ((void)0) /* Do nothing */ + +# define DBG_LOG() ((void)0) /* Do Nothing */ + +# define DBG_OPEN_LOG_FILE( pszFile, pszPath) ((void)0) /* Do Nothing */ + +# define DBG_OPEN_MEMORY_LOG() ((void)0) /* Do Nothing */ + +# define DBG_CLOSE_LOG_FILE() ((void)0) /* Do Nothing */ + +# define DBGPRINT_CURRENT_TIME() ((void)0) /* Do Nothing */ + +# endif // !DBG + + +// end_user_unmodifiable + +// begin_user_unmodifiable + + +#ifdef ASSERT +# undef ASSERT +#endif + + +# define ASSERT( exp) DBG_ASSERT( exp) + + +// end_user_unmodifiable + +// begin_user_modifiable + +// +// Debugging constants consist of two pieces. +// All constants in the range 0x0 to 0x8000 are reserved +// User extensions may include additional constants (bit flags) +// + +# define DEBUG_API_ENTRY 0x00000001L +# define DEBUG_API_EXIT 0x00000002L +# define DEBUG_INIT_CLEAN 0x00000004L +# define DEBUG_ERROR 0x00000008L + + // End of Reserved Range +# define DEBUG_RESERVED 0x00000FFFL + +// end_user_modifiable + + + +/*********************************************************** + * Platform Type related variables and macros + ************************************************************/ + +// +// Enum for product types +// + +typedef enum _PLATFORM_TYPE { + + PtInvalid = 0, // Invalid + PtNtWorkstation = 1, // NT Workstation + PtNtServer = 2, // NT Server + +} PLATFORM_TYPE; + +// +// IISGetPlatformType is the function used to the platform type +// + +extern +#ifdef __cplusplus +"C" +# endif // _cplusplus +PLATFORM_TYPE +IISGetPlatformType( + VOID + ); + +// +// External Macros +// + +#define InetIsNtServer( _pt ) ((_pt) == PtNtServer) +#define InetIsNtWksta( _pt ) ((_pt) == PtNtWorkstation) +#define InetIsValidPT(_pt) ((_pt) != PtInvalid) + +extern +#ifdef __cplusplus +"C" +# endif // _cplusplus +PLATFORM_TYPE g_PlatformType; + + +// Use the DECLARE_PLATFORM_TYPE macro to declare the platform type +#define DECLARE_PLATFORM_TYPE() \ + PLATFORM_TYPE g_PlatformType = PtInvalid; + +// Use the INITIALIZE_PLATFORM_TYPE to init the platform type +// This should typically go inside the DLLInit or equivalent place. +#define INITIALIZE_PLATFORM_TYPE() \ + g_PlatformType = IISGetPlatformType(); + +// +// Additional Macros to use the Platform Type +// + +#define TsIsNtServer( ) InetIsNtServer(g_PlatformType) +#define TsIsNtWksta( ) InetIsNtWksta(g_PlatformType) +#define IISIsValidPlatform() InetIsValidPT(g_PlatformType) +#define IISPlatformType() (g_PlatformType) + + +/*********************************************************** + * Some utility functions for Critical Sections + ************************************************************/ + +// +// IISSetCriticalSectionSpinCount() provides a thunk for the +// original NT4.0sp3 API SetCriticalSectionSpinCount() for CS with Spin counts +// Users of this function should definitely dynlink with kernel32.dll, +// Otherwise errors will surface to a large extent +// +extern +# ifdef __cplusplus +"C" +# endif // _cplusplus +DWORD +IISSetCriticalSectionSpinCount( + LPCRITICAL_SECTION lpCriticalSection, + DWORD dwSpinCount +); + + +// +// Macro for the calls to SetCriticalSectionSpinCount() +// +# define SET_CRITICAL_SECTION_SPIN_COUNT( lpCS, dwSpins) \ + IISSetCriticalSectionSpinCount( (lpCS), (dwSpins)) + +// +// IIS_DEFAULT_CS_SPIN_COUNT is the default value of spins used by +// Critical sections defined within IIS. +// NYI: We should have to switch the individual values based on experiments! +// Current value is an arbitrary choice +// +# define IIS_DEFAULT_CS_SPIN_COUNT (1000) + +// +// Initializes a critical section and sets its spin count +// to IIS_DEFAULT_CS_SPIN_COUNT. Equivalent to +// InitializeCriticalSectionAndSpinCount(lpCS, IIS_DEFAULT_CS_SPIN_COUNT), +// but provides a safe thunking layer for older systems that don't provide +// this API. +// +extern +# ifdef __cplusplus +"C" +# endif // _cplusplus +BOOL +IISInitializeCriticalSection( + LPCRITICAL_SECTION lpCriticalSection +); + +// +// Macro for the calls to InitializeCriticalSection() +// +# define INITIALIZE_CRITICAL_SECTION(lpCS) IISInitializeCriticalSection(lpCS) + +# endif /* _DEBUG_HXX_ */ + +// +// The following macros allow the automatic naming of certain Win32 objects. +// See IIS\SVCS\IISRTL\WIN32OBJ.C for details on the naming convention. +// +// Set IIS_NAMED_WIN32_OBJECTS to a non-zero value to enable named events, +// semaphores, and mutexes. +// + +#if DBG +#define IIS_NAMED_WIN32_OBJECTS 1 +#else +#define IIS_NAMED_WIN32_OBJECTS 0 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +HANDLE +PuDbgCreateEvent( + __in LPSTR FileName, + IN ULONG LineNumber, + __in LPSTR MemberName, + IN PVOID Address, + IN BOOL ManualReset, + IN BOOL InitialState + ); + +HANDLE +PuDbgCreateSemaphore( + __in LPSTR FileName, + IN ULONG LineNumber, + __in LPSTR MemberName, + IN PVOID Address, + IN LONG InitialCount, + IN LONG MaximumCount + ); + +HANDLE +PuDbgCreateMutex( + __in LPSTR FileName, + IN ULONG LineNumber, + __in LPSTR MemberName, + IN PVOID Address, + IN BOOL InitialOwner + ); + +#ifdef __cplusplus +} // extern "C" +#endif + +#if IIS_NAMED_WIN32_OBJECTS + +#define IIS_CREATE_EVENT( membername, address, manual, state ) \ + PuDbgCreateEvent( \ + (LPSTR)__FILE__, \ + (ULONG)__LINE__, \ + (membername), \ + (PVOID)(address), \ + (manual), \ + (state) \ + ) + +#define IIS_CREATE_SEMAPHORE( membername, address, initial, maximum ) \ + PuDbgCreateSemaphore( \ + (LPSTR)__FILE__, \ + (ULONG)__LINE__, \ + (membername), \ + (PVOID)(address), \ + (initial), \ + (maximum) \ + ) + +#define IIS_CREATE_MUTEX( membername, address, initial ) \ + PuDbgCreateMutex( \ + (LPSTR)__FILE__, \ + (ULONG)__LINE__, \ + (membername), \ + (PVOID)(address), \ + (initial) \ + ) + +#else // !IIS_NAMED_WIN32_OBJECTS + +#define IIS_CREATE_EVENT( membername, address, manual, state ) \ + CreateEventA( \ + NULL, \ + (manual), \ + (state), \ + NULL \ + ) + +#define IIS_CREATE_SEMAPHORE( membername, address, initial, maximum ) \ + CreateSemaphoreA( \ + NULL, \ + (initial), \ + (maximum), \ + NULL \ + ) + +#define IIS_CREATE_MUTEX( membername, address, initial ) \ + CreateMutexA( \ + NULL, \ + (initial), \ + NULL \ + ) + +#endif // IIS_NAMED_WIN32_OBJECTS + + +/************************ End of File ***********************/ + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/reftrace.vcxproj b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/reftrace.vcxproj new file mode 100644 index 0000000000..257df53c47 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/reftrace.vcxproj @@ -0,0 +1,78 @@ + + + + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + + + + + + + + + 15.0 + {A2599642-CBE5-4230-8511-3DC2D81874BE} + Win32Proj + reftrace + + + + StaticLibrary + v141 + + + true + + + + $(ProjectDir)include;$(IIS-Common)Include;$(IncludePath) + + + + true + precomp.hxx + _LIB;%(PreprocessorDefinitions) + + + Windows + + + + + + This project is trying to import a missing file: {0}. + + + + + + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/reftrace.vcxproj.filters b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/reftrace.vcxproj.filters new file mode 100644 index 0000000000..b77ab9c7c1 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/reftrace.vcxproj.filters @@ -0,0 +1,54 @@ + + + + + {aaa5bb99-ba5c-4b8d-9ef9-a406282e05a6} + + + {85a83b74-9536-44d0-a7f7-96e1475f21e9} + + + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + + + include + + + include + + + include + + + include + + + include + + + include + + + \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/src/irtldbg.cpp b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/src/irtldbg.cpp new file mode 100644 index 0000000000..06ce025bbe --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/src/irtldbg.cpp @@ -0,0 +1,150 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#include "precomp.hxx" + +#include +#include +#include +#include +#include + +#define IMPLEMENTATION_EXPORT +#include + + +void __cdecl +IrtlTrace( + LPCTSTR ptszFormat, + ...) +{ + TCHAR tszBuff[2048]; + va_list args; + + va_start(args, ptszFormat); + _vsntprintf_s(tszBuff, sizeof(tszBuff) / sizeof(tszBuff[0]), _TRUNCATE, ptszFormat, args); + va_end(args); + + DBGPRINTF(( DBG_CONTEXT, "%ls", tszBuff )); +} + + + +#ifdef IRTLDEBUG + +# if defined(USE_DEBUG_CRTS) && defined(_MSC_VER) && (_MSC_VER >= 1000) + + +# ifdef IRTLDBG_RUNNING_AS_SERVICE + +// The default assertion mechanism set up by Visual C++ 4 will not +// work with Active Server Pages because it's running inside a service +// and there is no desktop to interact with. + +// Note: for this to work properly, #define _WIN32_WINNT 0x400 before +// including or MB_SERVICE_NOTIFICATION won't be #define'd. + +int __cdecl +AspAssertHandler( + int nReportType, + char* pszErrorText, + int* pnReturn) +{ + const char szInfo[] = " (Press ABORT to terminate IIS," + " RETRY to debug this failure," + " or IGNORE to continue.)"; + char* pszMessageTitle = NULL; + int nResult = FALSE; + + *pnReturn = 0; // nothing for _CrtDbgReport to do + + // These flags enable message boxes to show up on the user's console + switch (nReportType) + { + case _CRT_WARN: + // If using MFC's TRACE macro (AfxTrace), the report hook + // (AspAssertHandler) will get called with _CRT_WARN. Ignore. + pszMessageTitle = "Warning"; + *pnReturn = 0; + return FALSE; + + case _CRT_ERROR: + pszMessageTitle = "Fatal Error"; + break; + + case _CRT_ASSERT: + pszMessageTitle = "Assertion Failed"; + break; + } + + char* pszMessageText = + static_cast(malloc(strlen(pszErrorText) + strlen(szInfo) + 1)); + + if (NULL == pszMessageText) + return FALSE; + + strcpy(pszMessageText, pszErrorText); + strcat(pszMessageText, szInfo); + + const int n = MessageBoxA(NULL, pszMessageText, pszMessageTitle, + (MB_SERVICE_NOTIFICATION | MB_TOPMOST + | MB_ABORTRETRYIGNORE | MB_ICONEXCLAMATION)); + + if (n == IDABORT) + { + exit(1); + } + else if (n == IDRETRY) + { + *pnReturn = 1; // tell _CrtDbgReport to start the debugger + nResult = TRUE; // tell _CrtDbgReport to run + } + + free(pszMessageText); + + return nResult; +} +# endif // IRTLDBG_RUNNING_AS_SERVICE +# endif // _MSC_VER >= 1000 + + + +void +IrtlDebugInit() +{ +# if defined(USE_DEBUG_CRTS) && defined(_MSC_VER) && (_MSC_VER >= 1000) +# ifdef IRTLDBG_RUNNING_AS_SERVICE + // If we end up in _CrtDbgReport, don't put up a message box + // _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG); + _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG); + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG); + + // Use AspAssertHandler to put up a message box instead + _CrtSetReportHook(AspAssertHandler); +# endif // IRTLDBG_RUNNING_AS_SERVICE + + + // Enable debug heap allocations & check for memory leaks at program exit + // The memory leak check will not be performed if inetinfo.exe is + // run directly under a debugger, only if it is run as a service. + _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF + | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)); +# endif // _MSC_VER >= 1000 +} + + + +void +IrtlDebugTerm() +{ +# if defined(USE_DEBUG_CRTS) && defined(_MSC_VER) && (_MSC_VER >= 1000) +# ifdef IRTLDBG_RUNNING_AS_SERVICE + // Turn off AspAssertHandler, so that we don't get numerous message boxes + // if there are memory leaks on shutdown + _CrtSetReportHook(NULL); +# endif // IRTLDBG_RUNNING_AS_SERVICE +# endif // _MSC_VER >= 1000 +} + +#endif //IRTLDEBUG + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/src/isplat.cxx b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/src/isplat.cxx new file mode 100644 index 0000000000..eb13b3edde --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/src/isplat.cxx @@ -0,0 +1,63 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#include "precomp.hxx" +#include "pudebug.h" + +#define IMPLEMENTATION_EXPORT + +extern "C" +PLATFORM_TYPE +IISGetPlatformType( + VOID +) +/*++ + + This function consults the registry and determines the platform type + for this machine. + + Arguments: + + None + + Returns: + Platform type + +--*/ +{ + OSVERSIONINFOEX osVersionInfoEx = { 0 }; + DWORDLONG dwlConditionMask = 0; + BOOL fReturn = FALSE; + + osVersionInfoEx.dwOSVersionInfoSize = sizeof( osVersionInfoEx ); + + // + // If we are not workstation (Client) + // that means that we are a server or domain controller (Server) + // + osVersionInfoEx.wProductType = VER_NT_WORKSTATION; + VER_SET_CONDITION( dwlConditionMask, VER_PRODUCT_TYPE, VER_EQUAL ); + + fReturn = VerifyVersionInfo( + &osVersionInfoEx, + VER_PRODUCT_TYPE, + dwlConditionMask ); + + // + // VerifyVersionInfo fails if the return value is zero + // and GetLastError returns an error code other than ERROR_OLD_WIN_VERSION + // + if ( !fReturn && GetLastError() != ERROR_OLD_WIN_VERSION ) + { + DPERROR(( DBG_CONTEXT, + HRESULT_FROM_WIN32 ( GetLastError() ), + "VerifyVersionInfo failed\n" )); + + return PtInvalid; + } + + return ( fReturn ) ? PtNtWorkstation : PtNtServer; +} + + + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/src/memorylog.cxx b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/src/memorylog.cxx new file mode 100644 index 0000000000..6f303f94e0 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/src/memorylog.cxx @@ -0,0 +1,123 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#include "precomp.hxx" +#include "memorylog.hxx" +#include "pudebug.h" + +CMemoryLog::CMemoryLog(DWORD dwMaxByteSize) : + m_fValid(FALSE), + m_fCritSecInitialized(FALSE) +{ + BOOL fRet; + + fRet = m_buf.Resize(dwMaxByteSize); + if (fRet) + { + m_fValid = TRUE; + } + + m_pBufferBegin = (CHAR*) m_buf.QueryPtr(); + m_pLastMessageEnd = (CHAR*) m_buf.QueryPtr(); + m_pBufferEnd = ((CHAR*) m_buf.QueryPtr()) + m_buf.QuerySize(); + + fRet = InitializeCriticalSectionAndSpinCount(&m_cs, + 0x80000000 /* precreate event */ | + IIS_DEFAULT_CS_SPIN_COUNT ); + if (FALSE != fRet) + { + m_fCritSecInitialized = TRUE; + } + +} + +CMemoryLog::~CMemoryLog() +{ + m_pBufferBegin = NULL; + m_pLastMessageEnd = NULL; + m_pBufferEnd = NULL; + m_fValid = FALSE; + + if (m_fCritSecInitialized) + { + DeleteCriticalSection(&m_cs); + m_fCritSecInitialized = FALSE; + } +} + +// +// Appends to end of the circular memory log. +// +DWORD +CMemoryLog::Append(LPCSTR pszOutput, + DWORD cchLen + ) +{ + // make sure internal state can accept this request + if (FALSE == m_fValid || + FALSE == m_fCritSecInitialized ) + { + return ERROR_NOT_ENOUGH_MEMORY; + } + + // make sure that we won't think we need less + // memory than we do. We are going to add 1 to + // this value next, so if it is MAX_UINT then + // we will wrap on the add. Don't allow strings + // that are that long. + if ( (ULONGLONG)cchLen + 1 > MAXDWORD ) + { + return ERROR_ARITHMETIC_OVERFLOW; + } + + // make sure the string length will fit inside the buffer + if ( cchLen + 1 > m_buf.QuerySize()) + { + return ERROR_NOT_ENOUGH_MEMORY; + } + + CHAR * pWhereToWriteMessage = NULL; + + // need to synchronize access to m_pLastMessageEnd + EnterCriticalSection(&m_cs); + + // check if the new message will fit into the remaining space in the buffer + // previous end (+1) + new length + 1 for NULL + if (m_pLastMessageEnd + cchLen + 1 < m_pBufferEnd) + { + // it will fit in remaining space + pWhereToWriteMessage = m_pLastMessageEnd; + } + else + { + // start over at the beginning + pWhereToWriteMessage = (CHAR*)m_buf.QueryPtr(); + + // don't leave extra old goo sitting around in the buffer + ZeroMemory(m_pLastMessageEnd, m_pBufferEnd - m_pLastMessageEnd); + } + + // set end of message to pWhere + length + 1 for NULL + m_pLastMessageEnd = pWhereToWriteMessage + cchLen + 1; + + LeaveCriticalSection(&m_cs); + + // the following memcpy is outside of the criticalsection - + // this introduces a race between leaving the criticalsection and + // looping back through the buffer before we finish writing. + // how likely is this? Not very. + // + // In addition - moving the memcpy inside of the critsec makes the time spent + // quite a bit larger than some simple load/stores that are currently there. + // + // Plus this is a debugging aid - life isn't fair. + + // actually do the copy + memcpy(pWhereToWriteMessage, pszOutput, cchLen); + + // write out a NULL to indicate end of message + *(pWhereToWriteMessage + cchLen) = NULL; + + return NO_ERROR; +} + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/src/pudebug.cxx b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/src/pudebug.cxx new file mode 100644 index 0000000000..44e42a21b1 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/src/pudebug.cxx @@ -0,0 +1,1164 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +/************************************************************ + * Include Headers + ************************************************************/ +# include "precomp.hxx" + + +# include +# include +# include +# include +# include + + +# include "pudebug.h" +# include "memorylog.hxx" + + +/************************************************************* + * Global Variables and Default Values + *************************************************************/ + +// +// TRUE if we're in a test process. +// There are a few noisy assertions that fire frequently cause of test code issues. These noisy asserts are masking +// real ones, drastically reducing the value of CHK bits. +// +BOOL g_fTestProcess = FALSE; + +// +// HACK HACK +// suppress shutdown asserts under some hosts +// +BOOL g_fAvoidShutdownAsserts = FALSE; + +# define MAX_PRINTF_OUTPUT ( 10240) + +# define DEFAULT_DEBUG_FLAGS_VALUE ( 0) +# define DEBUG_FLAGS_REGISTRY_LOCATION_A "DebugFlags" +# define DEBUG_BREAK_ENABLED_REGKEYNAME_A "BreakOnAssert" + +/************************************************************* + * Functions + *************************************************************/ + +/********************************************************************++ + +Routine Description: + This function creates a new DEBUG_PRINTS object for the required + program. + +Arguments: + pszPrintLabel pointer to null-terminated string containing + the label for program's debugging output + dwOutputFlags DWORD containing the output flags to be used. + +Returns: + pointer to a new DEBUG_PRINTS object on success. + Returns NULL on failure. +--*********************************************************************/ +LPDEBUG_PRINTS +PuCreateDebugPrintsObject( + IN const char * pszPrintLabel, + IN DWORD dwOutputFlags) +{ + + LPDEBUG_PRINTS pDebugPrints; + + pDebugPrints = (LPDEBUG_PRINTS ) GlobalAlloc( GPTR, sizeof( DEBUG_PRINTS)); + + if ( pDebugPrints != NULL) { + + if ( strlen( pszPrintLabel) < MAX_LABEL_LENGTH) { + + strcpy_s( pDebugPrints->m_rgchLabel, + sizeof( pDebugPrints->m_rgchLabel ) / sizeof( pDebugPrints->m_rgchLabel[0]), + pszPrintLabel); + } else { + strncpy_s( pDebugPrints->m_rgchLabel, + sizeof( pDebugPrints->m_rgchLabel ) / sizeof( pDebugPrints->m_rgchLabel[0]), + pszPrintLabel, + MAX_LABEL_LENGTH - 1); + } + + memset( pDebugPrints->m_rgchLogFilePath, 0, MAX_PATH); + memset( pDebugPrints->m_rgchLogFileName, 0, MAX_PATH); + + pDebugPrints->m_LogFileHandle = INVALID_HANDLE_VALUE; + + pDebugPrints->m_dwOutputFlags = dwOutputFlags; + pDebugPrints->m_StdErrHandle = GetStdHandle( STD_ERROR_HANDLE); + + if ( pDebugPrints->m_StdErrHandle == NULL ) + { + pDebugPrints->m_StdErrHandle = INVALID_HANDLE_VALUE; + } + + pDebugPrints->m_fInitialized = TRUE; + pDebugPrints->m_fBreakOnAssert= TRUE; + pDebugPrints->m_pMemoryLog = NULL; + } + + + return ( pDebugPrints); +} // PuCreateDebugPrintsObject() + + + + +/********************************************************************++ + +Routine Description: + This function cleans up the pDebugPrints object and + frees the allocated memory. + + Arguments: + pDebugPrints poitner to the DEBUG_PRINTS object. + + Returns: + NULL on success. + pDebugPrints() if the deallocation failed. + +--*********************************************************************/ +LPDEBUG_PRINTS +PuDeleteDebugPrintsObject( + IN OUT LPDEBUG_PRINTS pDebugPrints) +{ + if ( pDebugPrints != NULL) { + + PuCloseDbgMemoryLog(pDebugPrints); + DWORD dwError = PuCloseDbgPrintFile( pDebugPrints); + + if ( dwError != NO_ERROR) { + + SetLastError( dwError); + } else { + + // returns NULL on success + pDebugPrints = + (LPDEBUG_PRINTS ) GlobalFree( pDebugPrints); + } + } + + return ( pDebugPrints); + +} // PuDeleteDebugPrintsObject() + + + + +VOID +PuSetDbgOutputFlags( + IN OUT LPDEBUG_PRINTS pDebugPrints, + IN DWORD dwFlags) +{ + + if ( pDebugPrints == NULL) { + + SetLastError( ERROR_INVALID_PARAMETER); + } else { + + pDebugPrints->m_dwOutputFlags = dwFlags; + } + + return; +} // PuSetDbgOutputFlags() + + + +DWORD +PuGetDbgOutputFlags( + IN const LPDEBUG_PRINTS pDebugPrints) +{ + return ( pDebugPrints != NULL) ? pDebugPrints->m_dwOutputFlags : 0; + +} // PuGetDbgOutputFlags() + + +static DWORD +PuOpenDbgFileLocal( + IN OUT LPDEBUG_PRINTS pDebugPrints) +{ + if ( pDebugPrints == NULL) + return ERROR_INVALID_PARAMETER; + + if ( pDebugPrints->m_LogFileHandle != INVALID_HANDLE_VALUE) { + + // + // Silently return as a file handle exists. + // + return ( NO_ERROR); + } + + pDebugPrints->m_LogFileHandle = + CreateFileA( pDebugPrints->m_rgchLogFileName, + GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if ( pDebugPrints->m_LogFileHandle == INVALID_HANDLE_VALUE) { + + CHAR pchBuffer[1024]; + DWORD dwError = GetLastError(); + + sprintf_s( pchBuffer, + sizeof( pchBuffer ) / sizeof( pchBuffer[0] ), + " Critical Error: Unable to Open File %s. Error = %d\n", + pDebugPrints->m_rgchLogFileName, dwError); + OutputDebugStringA( pchBuffer); + + return ( dwError); + } + + return ( NO_ERROR); +} // PuOpenDbgFileLocal() + + + + + +DWORD +PuOpenDbgPrintFile( + IN OUT LPDEBUG_PRINTS pDebugPrints, + IN const char * pszFileName, + IN const char * pszPathForFile) +/********************************************************************++ + + Opens a Debugging log file. This function can be called to set path + and name of the debugging file. + + Arguments: + pszFileName pointer to null-terminated string containing + the name of the file. + + pszPathForFile pointer to null-terminated string containing the + path for the given file. + If NULL, then the old place where dbg files were + stored is used or if none, + default windows directory will be used. + + Returns: + Win32 error codes. NO_ERROR on success. + +--*********************************************************************/ + +{ + if ( pszFileName == NULL || pDebugPrints == NULL) { + + return ( ERROR_INVALID_PARAMETER); + } + + // + // Setup the Path information. if necessary. + // + + if ( pszPathForFile != NULL) { + + // Path is being changed. + + if ( strlen( pszPathForFile) < MAX_PATH) { + + strcpy_s( pDebugPrints->m_rgchLogFilePath, + sizeof( pDebugPrints->m_rgchLogFilePath ) / sizeof( pDebugPrints->m_rgchLogFilePath[0] ), + pszPathForFile); + } else { + + return ( ERROR_INVALID_PARAMETER); + } + } else { + + if ( pDebugPrints->m_rgchLogFilePath[0] == '\0' && // no old path + !GetWindowsDirectoryA( pDebugPrints->m_rgchLogFilePath, MAX_PATH)) { + + // + // Unable to get the windows default directory. Use current dir + // + + strcpy_s( pDebugPrints->m_rgchLogFilePath, + sizeof( pDebugPrints->m_rgchLogFilePath ) / sizeof( pDebugPrints->m_rgchLogFilePath[0] ), + "."); + } + } + + // + // Should need be, we need to create this directory for storing file + // + + + // + // Form the complete Log File name and open the file. + // + if ( (strlen( pszFileName) + strlen( pDebugPrints->m_rgchLogFilePath)) + >= MAX_PATH) { + + return ( ERROR_NOT_ENOUGH_MEMORY); + } + + // form the complete path + strcpy_s( pDebugPrints->m_rgchLogFileName, + sizeof( pDebugPrints->m_rgchLogFileName ) / sizeof( pDebugPrints->m_rgchLogFileName[0] ), + pDebugPrints->m_rgchLogFilePath); + + if ( pDebugPrints->m_rgchLogFileName[ strlen(pDebugPrints->m_rgchLogFileName) - 1] + != '\\') { + // Append a \ if necessary + strcat_s( pDebugPrints->m_rgchLogFileName, + sizeof( pDebugPrints->m_rgchLogFileName ) / sizeof( pDebugPrints->m_rgchLogFileName[0] ), + "\\"); + }; + strcat_s( pDebugPrints->m_rgchLogFileName, + sizeof( pDebugPrints->m_rgchLogFileName ) / sizeof( pDebugPrints->m_rgchLogFileName[0] ), + pszFileName); + + return PuOpenDbgFileLocal( pDebugPrints); + +} // PuOpenDbgPrintFile() + + + + +DWORD +PuReOpenDbgPrintFile( + IN OUT LPDEBUG_PRINTS pDebugPrints) +/********************************************************************++ + + This function closes any open log file and reopens a new copy. + If necessary. It makes a backup copy of the file. + +--*********************************************************************/ + +{ + if ( pDebugPrints == NULL) { + return ( ERROR_INVALID_PARAMETER); + } + + PuCloseDbgPrintFile( pDebugPrints); // close any existing file. + + if ( pDebugPrints->m_dwOutputFlags & DbgOutputBackup) { + + // MakeBkupCopy(); + + OutputDebugStringA( " Error: MakeBkupCopy() Not Yet Implemented\n"); + } + + return PuOpenDbgFileLocal( pDebugPrints); + +} // PuReOpenDbgPrintFile() + + + + +DWORD +PuCloseDbgPrintFile( + IN OUT LPDEBUG_PRINTS pDebugPrints) +{ + DWORD dwError = NO_ERROR; + + if ( pDebugPrints == NULL ) { + dwError = ERROR_INVALID_PARAMETER; + } else { + + if ( pDebugPrints->m_LogFileHandle != INVALID_HANDLE_VALUE) { + + FlushFileBuffers( pDebugPrints->m_LogFileHandle); + + if ( !CloseHandle( pDebugPrints->m_LogFileHandle)) { + + CHAR pchBuffer[1024]; + + dwError = GetLastError(); + + sprintf_s( pchBuffer, + sizeof( pchBuffer ) / sizeof( pchBuffer[0] ), + "CloseDbgPrintFile() : CloseHandle( %p) failed." + " Error = %d\n", + pDebugPrints->m_LogFileHandle, + dwError); + OutputDebugStringA( pchBuffer); + } + + pDebugPrints->m_LogFileHandle = INVALID_HANDLE_VALUE; + } + } + + return ( dwError); +} // DEBUG_PRINTS::CloseDbgPrintFile() + +DWORD +PuOpenDbgMemoryLog(IN OUT LPDEBUG_PRINTS pDebugPrints) +{ + DWORD dwError; + CMemoryLog * pLog = NULL; + + if (NULL == pDebugPrints) + { + dwError = ERROR_INVALID_PARAMETER; + goto done; + } + + if (NULL != pDebugPrints->m_pMemoryLog) + { + dwError = ERROR_SUCCESS; + goto done; + } + + pLog = new CMemoryLog(1024 * 512); // max size of 512 K + if (NULL == pLog) + { + dwError = ERROR_NOT_ENOUGH_MEMORY; + goto done; + } + + // save away the pointer + pDebugPrints->m_pMemoryLog = pLog; + + // make sure output gets to the log + pDebugPrints->m_dwOutputFlags |= DbgOutputMemory; + + dwError = NO_ERROR; +done: + return dwError; +} + +DWORD +PuCloseDbgMemoryLog(IN OUT LPDEBUG_PRINTS pDebugPrints) +{ + DWORD dwError; + + if (NULL == pDebugPrints) + { + dwError = ERROR_INVALID_PARAMETER; + goto done; + } + if (NULL != pDebugPrints->m_pMemoryLog) + { + CMemoryLog * pLog = (CMemoryLog*) (pDebugPrints->m_pMemoryLog); + delete pLog; + pDebugPrints->m_pMemoryLog = NULL; + } + + dwError = NO_ERROR; +done: + return dwError; +} + +VOID +PupOutputMessage( + IN LPDEBUG_PRINTS pDebugPrints, + IN STRA *straOutput + ) +{ + if ( pDebugPrints != NULL) + { + if ( ( pDebugPrints->m_dwOutputFlags & DbgOutputStderr) && + ( pDebugPrints->m_StdErrHandle != INVALID_HANDLE_VALUE ) ) { + + DWORD nBytesWritten; + + ( VOID) WriteFile( pDebugPrints->m_StdErrHandle, + straOutput->QueryStr(), + straOutput->QueryCCH(), + &nBytesWritten, + NULL); + } + + if ( pDebugPrints->m_dwOutputFlags & DbgOutputLogFile && + pDebugPrints->m_LogFileHandle != INVALID_HANDLE_VALUE) { + + DWORD nBytesWritten; + + // + // Truncation of log files. Not yet implemented. + + ( VOID) WriteFile( pDebugPrints->m_LogFileHandle, + straOutput->QueryStr(), + straOutput->QueryCCH(), + &nBytesWritten, + NULL); + + } + + if ( (pDebugPrints->m_dwOutputFlags & DbgOutputMemory) && + (NULL != pDebugPrints->m_pMemoryLog) ) + { + CMemoryLog* pLog = (CMemoryLog*) (pDebugPrints->m_pMemoryLog); + pLog->Append(straOutput->QueryStr(), straOutput->QueryCCH()); + } + + } + + + if ( pDebugPrints == NULL || + pDebugPrints->m_dwOutputFlags & DbgOutputKdb) + { + OutputDebugStringA( straOutput->QueryStr() ); + } + + return; +} + +void +FormatMsgToBuffer( IN OUT STRA * pSTRAOutput, + IN LPDEBUG_PRINTS pDebugPrints, + IN LPCSTR pszFilePath, + IN DWORD nLineNum, + IN LPCSTR pszFunctionName, + IN LPCSTR pszFormat, + IN va_list * pargsList) +{ + LPCSTR pszFileName = strrchr( pszFilePath, '\\'); + int cchPrologue = 0; + HRESULT hr = S_OK; + DWORD cchOutput = 0; + + // + // Skip the complete path name and retain file name in pszName + // + + if ( pszFileName== NULL) { + + // if skipping \\ yields nothing use whole path. + pszFileName = pszFilePath; + } + else + { + // skip past the '\' + ++pszFileName; + } + + // Format the message header as: tid label!function [file @ line number]:message + cchPrologue = sprintf_s( pSTRAOutput->QueryStr(), + pSTRAOutput->QuerySize(), + "%lu %hs!%hs [%hs @ %d]:", + GetCurrentThreadId(), + pDebugPrints ? pDebugPrints->m_rgchLabel : "??", + pszFunctionName, + pszFileName, + nLineNum); + + // we directly touched the buffer - however, wait to SyncWithBuffer + // until the rest of the operations are done. Do NOT call QueryCCH() it will be WRONG. + + + // Format the incoming message using vsnprintf() so that the overflows are + // captured + + cchOutput = _vsnprintf_s( pSTRAOutput->QueryStr() + cchPrologue, + pSTRAOutput->QuerySize() - cchPrologue, + pSTRAOutput->QuerySize() - cchPrologue - 1, + pszFormat, *pargsList); + + if ( cchOutput == -1 ) + { + // couldn't fit this in the original STRA size. Try a heap allocation. + hr = pSTRAOutput->Resize(MAX_PRINTF_OUTPUT); + if (FAILED(hr)) + { + // Can't allocate, therefore don't give back half done results + pSTRAOutput->Reset(); + return; + } + + cchOutput = _vsnprintf_s( pSTRAOutput->QueryStr() + cchPrologue, + pSTRAOutput->QuerySize() - cchPrologue, + pSTRAOutput->QuerySize() - cchPrologue - 1, + pszFormat, *pargsList); + if (cchOutput == -1) + { + // we need to NULL terminate, as _vsnprintf failed to do that for us. + pSTRAOutput->QueryStr()[pSTRAOutput->QuerySize() - 1] = '\0'; + } + } + + // we directly touched the buffer - therefore: + pSTRAOutput->SyncWithBuffer(); + + return; +} // FormatMsgToBuffer() + + +/********************************************************************++ +Routine Description: + Main function that examines the incoming message and prints out a header + and the message. + +Arguments: + pDebugPrints - pointer to the debug print object + pszFilePaht - pointer to the file from where this function is called + nLineNum - Line number within the file + pszFormat - formatting string to use. + +Returns: + None +--*********************************************************************/ + +VOID +PuDbgPrint( + IN OUT LPDEBUG_PRINTS pDebugPrints, + IN const char * pszFilePath, + IN int nLineNum, + IN const char * pszFunctionName, + IN const char * pszFormat, + ...) +{ + STACK_STRA(straOutput, 256); + va_list argsList; + DWORD dwErr; + + // get a local copy of the error code so that it is not lost + dwErr = GetLastError(); + + va_start( argsList, pszFormat); + FormatMsgToBuffer( &straOutput, + pDebugPrints, + pszFilePath, + nLineNum, + pszFunctionName, + pszFormat, + &argsList); + + va_end( argsList); + + // + // Send the outputs to respective files. + // + PupOutputMessage( pDebugPrints, &straOutput); + + + SetLastError( dwErr ); + + return; +} // PuDbgPrint() + +void +FormatMsgToBufferW( IN OUT STRU * pSTRUOutput, + IN LPDEBUG_PRINTS pDebugPrints, + IN LPCSTR pszFilePath, + IN DWORD nLineNum, + IN LPCSTR pszFunctionName, + IN LPCWSTR pszFormat, + IN va_list * pargsList) +{ + LPCSTR pszFileName = strrchr( pszFilePath, '\\'); + int cchPrologue = 0; + HRESULT hr = S_OK; + DWORD cchOutput = 0; + + // + // Skip the complete path name and retain file name in pszName + // + + if ( pszFileName== NULL) { + + // if skipping \\ yields nothing use whole path. + pszFileName = pszFilePath; + } + else + { + // skip past the '\' + ++pszFileName; + } + + // Format the message header as: tid label!function [file @ line number]:message + cchPrologue = swprintf_s( pSTRUOutput->QueryStr(), + pSTRUOutput->QuerySizeCCH(), + L"%lu %hs!%hs [%hs @ %d]:", + GetCurrentThreadId(), + pDebugPrints ? pDebugPrints->m_rgchLabel : "??", + pszFunctionName, + pszFileName, + nLineNum); + + // we directly touched the buffer - however, wait to SyncWithBuffer + // until the rest of the operations are done. Do NOT call QueryCCH() it will be WRONG. + + // Format the incoming message using vsnprintf() so that the overflows are + // captured + + cchOutput = _vsnwprintf_s( pSTRUOutput->QueryStr() + cchPrologue, + pSTRUOutput->QuerySizeCCH() - cchPrologue, + // DEBUGDEBUG + //pSTRUOutput->QueryBuffer()->QuerySize() / sizeof(WCHAR) - cchPrologue - 1, // this is a count of characters + pSTRUOutput->QuerySizeCCH() - cchPrologue - 1, + pszFormat, *pargsList); + + if ( cchOutput == -1 ) + { + // couldn't fit this in the original STRA size. Try a heap allocation. + hr = pSTRUOutput->Resize(MAX_PRINTF_OUTPUT); + if (FAILED(hr)) + { + // Can't allocate, therefore don't give back half done results + pSTRUOutput->Reset(); + return; + } + + cchOutput = _vsnwprintf_s( pSTRUOutput->QueryStr() + cchPrologue, + pSTRUOutput->QuerySizeCCH() - cchPrologue, + //DEBUGDEBUG + //pSTRUOutput->QueryBuffer()->QuerySize() / sizeof(WCHAR) - cchPrologue - 1, // this is a count of characters + pSTRUOutput->QuerySizeCCH() - cchPrologue - 1, + pszFormat, *pargsList); + if (cchOutput == -1) + { + // we need to NULL terminate, as _vsnprintf failed to do that for us. + //DEBUGDEBUG + pSTRUOutput->QueryStr()[pSTRUOutput->QuerySizeCCH() - 1] = L'\0'; + + } + } + + // we directly touched the buffer - therefore: + pSTRUOutput->SyncWithBuffer(); + + return; +} // FormatMsgToBuffer() + +extern "C" +VOID +PuDbgPrintW( + IN OUT LPDEBUG_PRINTS pDebugPrints, + IN const char * pszFilePath, + IN int nLineNum, + IN const char * pszFunctionName, + IN const WCHAR * pszFormat, + ... +) +{ + STACK_STRU(struOutput, 256); + va_list argsList; + DWORD dwErr; + HRESULT hr; + // get a local copy of the error code so that it is not lost + dwErr = GetLastError(); + + va_start( argsList, pszFormat); + FormatMsgToBufferW( &struOutput, + pDebugPrints, + pszFilePath, + nLineNum, + pszFunctionName, + pszFormat, + &argsList); + + va_end( argsList); + + // + // Send the outputs to respective files. + // + STACK_STRA(straOutput, 256); + hr = straOutput.CopyWTruncate(struOutput.QueryStr(), struOutput.QueryCCH()); + if (FAILED(hr)) + { + goto done; + } + + PupOutputMessage( pDebugPrints, &straOutput); + +done: + + SetLastError( dwErr ); + + return; +} + +/********************************************************************++ +Routine Description: + This function behaves like PuDbgPrint() but also prints out formatted + Error message indicating what failed. + +Arguments: + pDebugPrints - pointer to the debug print object + pszFilePaht - pointer to the file from where this function is called + nLineNum - Line number within the file + dwError - Error code for which the formatted error message should + be printed + pszFormat - formatting string to use. + +Returns: + None +--*********************************************************************/ +VOID +PuDbgPrintError( + IN OUT LPDEBUG_PRINTS pDebugPrints, + IN const char * pszFilePath, + IN int nLineNum, + IN const char * pszFunctionName, + IN DWORD dwError, + IN const char * pszFormat, + ...) // argsList +{ + STACK_STRA(straOutput, 256); + va_list argsList; + DWORD dwErr; + + // get a local copy of the error code so that it is not lost + dwErr = GetLastError(); + + va_start( argsList, pszFormat); + FormatMsgToBuffer( &straOutput, + pDebugPrints, + pszFilePath, + nLineNum, + pszFunctionName, + pszFormat, + &argsList); + + va_end( argsList); + + + // + // obtain the formatted error message for error code + // + + LPSTR lpErrorBuffer = NULL; + DWORD nRet; +#pragma prefast(suppress: __WARNING_ANSI_APICALL,"debug spew is ansi") + nRet = + FormatMessageA((FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM), + NULL, // lpSource + dwError, + LANG_NEUTRAL, + (LPSTR ) &lpErrorBuffer, // pointer to store buffer allocated + 0, // size of buffer + NULL // lpArguments + ); + + if (lpErrorBuffer) + { + CHAR pszErrorOut[64]; // 64 from: (/t=)4 + (Error(=)7 + (%x=)18 (0x + 16hex on 64 bit systems) + (): =)3 == 32 + some more slop + _snprintf_s( pszErrorOut, + sizeof( pszErrorOut ) / sizeof( pszErrorOut[0] ), + sizeof(pszErrorOut) / sizeof(CHAR) - 1, // leave space for NULL. + "\tError(%x): ", + dwError); + pszErrorOut[63] = '\0'; + + // if these appends fail, nothing to be done about it therefore just ignore the return values + straOutput.Append(pszErrorOut); + + straOutput.Append(lpErrorBuffer); + straOutput.Append("\n"); + } + + // + // Send the outputs to respective files. + // + PupOutputMessage( pDebugPrints, &straOutput); + + // free the buffer if any was allocated + if ( lpErrorBuffer != NULL) { + LocalFree (lpErrorBuffer); + } + + SetLastError( dwErr ); + + return; +} // PuDbgPrintError() + + + +VOID +PuDbgDump( + IN OUT LPDEBUG_PRINTS pDebugPrints, + IN const char * pszFilePath, + IN int nLineNum, + IN const char * pszFunctionName, + IN const char * pszDump + ) +{ + UNREFERENCED_PARAMETER( pszFunctionName ); + UNREFERENCED_PARAMETER( nLineNum ); + + LPCSTR pszFileName = strrchr( pszFilePath, '\\'); + DWORD dwErr; + DWORD cbDump; + + + // + // Skip the complete path name and retain file name in pszName + // + + if ( pszFileName== NULL) { + + pszFileName = pszFilePath; + } + + dwErr = GetLastError(); + + // No message header for this dump + cbDump = (DWORD)strlen( pszDump); + + // + // Send the outputs to respective files. + // + + if ( pDebugPrints != NULL) + { + if ( ( pDebugPrints->m_dwOutputFlags & DbgOutputStderr) && + ( pDebugPrints->m_StdErrHandle != INVALID_HANDLE_VALUE ) ) { + + DWORD nBytesWritten; + + ( VOID) WriteFile( pDebugPrints->m_StdErrHandle, + pszDump, + cbDump, + &nBytesWritten, + NULL); + } + + if ( pDebugPrints->m_dwOutputFlags & DbgOutputLogFile && + pDebugPrints->m_LogFileHandle != INVALID_HANDLE_VALUE) { + + DWORD nBytesWritten; + + // + // Truncation of log files. Not yet implemented. + + ( VOID) WriteFile( pDebugPrints->m_LogFileHandle, + pszDump, + cbDump, + &nBytesWritten, + NULL); + + } + + if ( (pDebugPrints->m_dwOutputFlags & DbgOutputMemory) && + (NULL != pDebugPrints->m_pMemoryLog) ) + { + CMemoryLog * pLog = (CMemoryLog*)(pDebugPrints->m_pMemoryLog); + pLog->Append(pszDump, cbDump); + } + } + + if ( pDebugPrints == NULL + || pDebugPrints->m_dwOutputFlags & DbgOutputKdb) + { + OutputDebugStringA( pszDump); + } + + SetLastError( dwErr ); + + return; +} // PuDbgDump() + +// +// N.B. For PuDbgCaptureContext() to work properly, the calling function +// *must* be __cdecl, and must have a "normal" stack frame. So, we decorate +// PuDbgAssertFailed() with the __cdecl modifier and disable the frame pointer +// omission (FPO) optimization. +// + +// DEBUGDEBUG +//#pragma optimize( "y", off ) // disable frame pointer omission (FPO) +#pragma optimize( "", off ) + +INT +__cdecl +PuDbgAssertFailed( + IN OUT LPDEBUG_PRINTS pDebugPrints, + IN const char * pszFilePath, + IN int nLineNum, + IN const char * pszFunctionName, + IN const char * pszExpression, + IN const char * pszMessage) +/********************************************************************++ + This function calls assertion failure and records assertion failure + in log file. + +--*********************************************************************/ + +{ + PuDbgPrintAssertFailed( pDebugPrints, pszFilePath, nLineNum, pszFunctionName, + pszExpression, + pszMessage ); + if ( !g_fAvoidShutdownAsserts ) + { + DebugBreak(); + } + + return 0; +} // PuDbgAssertFailed() + +#pragma optimize( "", on ) // restore frame pointer omission (FPO) + +INT +WINAPI +PuDbgPrintAssertFailed( + IN OUT LPDEBUG_PRINTS pDebugPrints, + IN const char * pszFilePath, + IN int nLineNum, + IN const char * pszFunctionName, + IN const char * pszExpression, + IN const char * pszMessage) +/********************************************************************++ + This function calls assertion failure and records assertion failure + in log file. + +--*********************************************************************/ + +{ + PuDbgPrint( pDebugPrints, pszFilePath, nLineNum, pszFunctionName, + " Assertion (%s) Failed: %s\n", + pszExpression, + pszMessage ); + return 0; +} // PuDbgPrintAssertFailed() + + + +VOID +PuDbgPrintCurrentTime( + IN OUT LPDEBUG_PRINTS pDebugPrints, + IN const char * pszFilePath, + IN int nLineNum, + IN const char * pszFunctionName + ) +/********************************************************************++ + This function generates the current time and prints it out to debugger + for tracing out the path traversed, if need be. + + Arguments: + pszFile pointer to string containing the name of the file + lineNum line number within the file where this function is called. + + Returns: + NO_ERROR always. +--*********************************************************************/ + +{ + PuDbgPrint( pDebugPrints, pszFilePath, nLineNum, pszFunctionName, + " TickCount = %u\n", + GetTickCount() + ); + + return; +} // PrintOutCurrentTime() + + + + +DWORD +PuLoadDebugFlagsFromReg(IN HKEY hkey, IN DWORD dwDefault) +/********************************************************************++ + This function reads the debug flags assumed to be stored in + the location "DebugFlags" under given key. + If there is any error the default value is returned. +--*********************************************************************/ + +{ + DWORD err; + DWORD dwDebug = dwDefault; + DWORD dwBuffer; + DWORD cbBuffer = sizeof(dwBuffer); + DWORD dwType; + + if( hkey != NULL ) + { + err = RegQueryValueExA( hkey, + DEBUG_FLAGS_REGISTRY_LOCATION_A, + NULL, + &dwType, + (LPBYTE)&dwBuffer, + &cbBuffer ); + + if( ( err == NO_ERROR ) && ( dwType == REG_DWORD ) ) + { + dwDebug = dwBuffer; + } + } + + return dwDebug; +} // PuLoadDebugFlagsFromReg() + + + + +DWORD +PuLoadDebugFlagsFromRegStr(IN LPCSTR pszRegKey, IN DWORD dwDefault) +/********************************************************************++ +Description: + This function reads the debug flags assumed to be stored in + the location "DebugFlags" under given key location in registry. + If there is any error the default value is returned. + +Arguments: + pszRegKey - pointer to registry key location from where to read the key from + dwDefault - default values in case the read from registry fails + +Returns: + Newly read value on success + If there is any error the dwDefault is returned. +--*********************************************************************/ + +{ + HKEY hkey = NULL; + + DWORD dwVal = dwDefault; + + DWORD dwError = RegOpenKeyExA(HKEY_LOCAL_MACHINE, + pszRegKey, + 0, + KEY_READ, + &hkey); + if ( dwError == NO_ERROR) { + dwVal = PuLoadDebugFlagsFromReg( hkey, dwDefault); + RegCloseKey( hkey); + hkey = NULL; + } + + return ( dwVal); +} // PuLoadDebugFlagsFromRegStr() + + + + + +DWORD +PuSaveDebugFlagsInReg(IN HKEY hkey, IN DWORD dwDbg) +/********************************************************************++ + Saves the debug flags in registry. On failure returns the error code for + the operation that failed. + +--*********************************************************************/ +{ + DWORD err; + + if( hkey == NULL ) { + + err = ERROR_INVALID_PARAMETER; + } else { + + err = RegSetValueExA(hkey, + DEBUG_FLAGS_REGISTRY_LOCATION_A, + 0, + REG_DWORD, + (LPBYTE)&dwDbg, + sizeof(dwDbg) ); + } + + return (err); +} // PuSaveDebugFlagsInReg() + + +VOID +PuDbgCaptureContext ( + OUT PCONTEXT ContextRecord + ) +{ + // + // This space intentionally left blank. + // + UNREFERENCED_PARAMETER( ContextRecord ); +} // PuDbgCaptureContext + + +/****************************** End of File ******************************/ + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/src/reftrace.c b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/src/reftrace.c new file mode 100644 index 0000000000..bfb78aa717 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/src/reftrace.c @@ -0,0 +1,232 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +//#include +//#include +//#include +#include +#include +#include +#include + + +PTRACE_LOG +CreateRefTraceLog( + IN LONG LogSize, + IN LONG ExtraBytesInHeader + ) +/*++ + +Routine Description: + + Creates a new (empty) ref count trace log buffer. + +Arguments: + + LogSize - The number of entries in the log. + + ExtraBytesInHeader - The number of extra bytes to include in the + log header. This is useful for adding application-specific + data to the log. + +Return Value: + + PTRACE_LOG - Pointer to the newly created log if successful, + NULL otherwise. + +--*/ +{ + + return CreateTraceLog( + LogSize, + ExtraBytesInHeader, + sizeof(REF_TRACE_LOG_ENTRY) + ); + +} // CreateRefTraceLog + + +VOID +DestroyRefTraceLog( + IN PTRACE_LOG Log + ) +/*++ + +Routine Description: + + Destroys a ref count trace log buffer created with CreateRefTraceLog(). + +Arguments: + + Log - The ref count trace log buffer to destroy. + +Return Value: + + None. + +--*/ +{ + + DestroyTraceLog( Log ); + +} // DestroyRefTraceLog + + +// +// N.B. For RtlCaptureBacktrace() to work properly, the calling function +// *must* be __cdecl, and must have a "normal" stack frame. So, we decorate +// WriteRefTraceLog[Ex]() with the __cdecl modifier and disable the frame +// pointer omission (FPO) optimization. +// + +//#pragma optimize( "y", off ) // disable frame pointer omission (FPO) +#pragma optimize( "", off ) // disable frame pointer omission (FPO) + +LONG +__cdecl +WriteRefTraceLog( + IN PTRACE_LOG Log, + IN LONG NewRefCount, + IN CONST VOID * Context + ) +/*++ + +Routine Description: + + Writes a new entry to the specified ref count trace log. The entry + written contains the updated reference count and a stack backtrace + leading up to the current caller. + +Arguments: + + Log - The log to write to. + + NewRefCount - The updated reference count. + + Context - An uninterpreted context to associate with the log entry. + +Return Value: + + Index of entry in log. + +--*/ +{ + + return WriteRefTraceLogEx( + Log, + NewRefCount, + Context, + REF_TRACE_EMPTY_CONTEXT, // suppress use of optional extra contexts + REF_TRACE_EMPTY_CONTEXT, + REF_TRACE_EMPTY_CONTEXT + ); + +} // WriteRefTraceLog + + + + +LONG +__cdecl +WriteRefTraceLogEx( + IN PTRACE_LOG Log, + IN LONG NewRefCount, + IN CONST VOID * Context, + IN CONST VOID * Context1, // optional extra context + IN CONST VOID * Context2, // optional extra context + IN CONST VOID * Context3 // optional extra context + ) +/*++ + +Routine Description: + + Writes a new "extended" entry to the specified ref count trace log. + The entry written contains the updated reference count, stack backtrace + leading up to the current caller and extra context information. + +Arguments: + + Log - The log to write to. + + NewRefCount - The updated reference count. + + Context - An uninterpreted context to associate with the log entry. + Context1 - An uninterpreted context to associate with the log entry. + Context2 - An uninterpreted context to associate with the log entry. + Context3 - An uninterpreted context to associate with the log entry. + + NOTE Context1/2/3 are "optional" in that the caller may suppress + debug display of these values by passing REF_TRACE_EMPTY_CONTEXT + for each of them. + +Return Value: + + Index of entry in log. + +--*/ +{ + + REF_TRACE_LOG_ENTRY entry; + ULONG hash; + DWORD cStackFramesSkipped; + + // + // Initialize the entry. + // + + RtlZeroMemory( + &entry, + sizeof(entry) + ); + + // + // Set log entry members. + // + + entry.NewRefCount = NewRefCount; + entry.Context = Context; + entry.Thread = GetCurrentThreadId(); + entry.Context1 = Context1; + entry.Context2 = Context2; + entry.Context3 = Context3; + + // + // Capture the stack backtrace. Normally, we skip two stack frames: + // one for this routine, and one for RtlCaptureBacktrace() itself. + // For non-Ex callers who come in via WriteRefTraceLog, + // we skip three stack frames. + // + + if ( entry.Context1 == REF_TRACE_EMPTY_CONTEXT + && entry.Context2 == REF_TRACE_EMPTY_CONTEXT + && entry.Context3 == REF_TRACE_EMPTY_CONTEXT + ) { + + cStackFramesSkipped = 2; + + } else { + + cStackFramesSkipped = 1; + + } + + RtlCaptureStackBackTrace( + cStackFramesSkipped, + REF_TRACE_LOG_STACK_DEPTH, + entry.Stack, + &hash + ); + + // + // Write it to the log. + // + + return WriteTraceLog( + Log, + &entry + ); + +} // WriteRefTraceLogEx + +#pragma optimize( "", on ) // restore frame pointer omission (FPO) + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/src/tracelog.c b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/src/tracelog.c new file mode 100644 index 0000000000..58eeb4863f --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/src/tracelog.c @@ -0,0 +1,239 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +//#include +//#include +//#include +#include +#include +#include +#include +#include + + +#define ALLOC_MEM(cb) (PVOID)LocalAlloc( LPTR, (cb) ) +#define FREE_MEM(ptr) (VOID)LocalFree( (HLOCAL)(ptr) ) + + + +PTRACE_LOG +CreateTraceLog( + IN LONG LogSize, + IN LONG ExtraBytesInHeader, + IN LONG EntrySize + ) +/*++ + +Routine Description: + + Creates a new (empty) trace log buffer. + +Arguments: + + LogSize - The number of entries in the log. + + ExtraBytesInHeader - The number of extra bytes to include in the + log header. This is useful for adding application-specific + data to the log. + + EntrySize - The size (in bytes) of each entry. + +Return Value: + + PTRACE_LOG - Pointer to the newly created log if successful, + NULL otherwise. + +--*/ +{ + + ULONG ulTotalSize = 0; + ULONG ulLogSize = 0; + ULONG ulEntrySize = 0; + ULONG ulTmpResult = 0; + ULONG ulExtraBytesInHeader = 0; + PTRACE_LOG log = NULL; + HRESULT hr = S_OK; + + // + // Sanity check the parameters. + // + + //DBG_ASSERT( LogSize > 0 ); + //DBG_ASSERT( EntrySize > 0 ); + //DBG_ASSERT( ExtraBytesInHeader >= 0 ); + //DBG_ASSERT( ( EntrySize & 3 ) == 0 ); + + // + // converting to unsigned long. Since all these values are positive + // so its safe to cast them to their unsigned equivalent directly. + // + ulLogSize = (ULONG) LogSize; + ulEntrySize = (ULONG) EntrySize; + ulExtraBytesInHeader = (ULONG) ExtraBytesInHeader; + + // + // Check if the multiplication operation will overflow a LONG + // ulTotalSize = LogSize * EntrySize; + // + hr = ULongMult( ulLogSize, ulEntrySize, &ulTotalSize ); + if ( FAILED(hr) ) + { + SetLastError( ERROR_ARITHMETIC_OVERFLOW ); + return NULL; + } + + // + // check for overflow in addition operation. + // ulTmpResult = sizeof(TRACE_LOG) + ulExtraBytesInHeader + // + hr = ULongAdd( (ULONG) sizeof(TRACE_LOG), ulExtraBytesInHeader, &ulTmpResult ); + if ( FAILED(hr) ) + { + SetLastError( ERROR_ARITHMETIC_OVERFLOW ); + return NULL; + } + + // + // check for overflow in addition operation. + // ulTotalSize = ulTotalSize + ulTmpResult; + // + hr = ULongAdd( ulTmpResult, ulTotalSize, &ulTotalSize ); + if ( FAILED(hr) ) + { + SetLastError( ERROR_ARITHMETIC_OVERFLOW ); + return NULL; + } + + if ( ulTotalSize > (ULONG) 0x7FFFFFFF ) + { + SetLastError( ERROR_ARITHMETIC_OVERFLOW ); + return NULL; + } + + // + // Allocate & initialize the log structure. + // + + log = (PTRACE_LOG)ALLOC_MEM( ulTotalSize ); + + // + // Initialize it. + // + + if( log != NULL ) { + + RtlZeroMemory( log, ulTotalSize ); + + log->Signature = TRACE_LOG_SIGNATURE; + log->LogSize = LogSize; + log->NextEntry = -1; + log->EntrySize = EntrySize; + log->LogBuffer = (PUCHAR)( log + 1 ) + ExtraBytesInHeader; + } + + return log; + +} // CreateTraceLog + + +VOID +DestroyTraceLog( + IN PTRACE_LOG Log + ) +/*++ + +Routine Description: + + Destroys a trace log buffer created with CreateTraceLog(). + +Arguments: + + Log - The trace log buffer to destroy. + +Return Value: + + None. + +--*/ +{ + if ( Log != NULL ) { + //DBG_ASSERT( Log->Signature == TRACE_LOG_SIGNATURE ); + + Log->Signature = TRACE_LOG_SIGNATURE_X; + FREE_MEM( Log ); + } + +} // DestroyTraceLog + + +LONG +WriteTraceLog( + IN PTRACE_LOG Log, + IN PVOID Entry + ) +/*++ + +Routine Description: + + Writes a new entry to the specified trace log. + +Arguments: + + Log - The log to write to. + + Entry - Pointer to the data to write. This buffer is assumed to be + Log->EntrySize bytes long. + +Return Value: + + Index of entry in log. This is useful for correlating the output + of !inetdbg.ref to a particular point in the output debug stream + +--*/ +{ + + PUCHAR target; + ULONG index; + + //DBG_ASSERT( Log != NULL ); + //DBG_ASSERT( Log->Signature == TRACE_LOG_SIGNATURE ); + //DBG_ASSERT( Entry != NULL ); + + // + // Find the next slot, copy the entry to the slot. + // + + index = ( (ULONG) InterlockedIncrement( &Log->NextEntry ) ) % (ULONG) Log->LogSize; + + //DBG_ASSERT( index < (ULONG) Log->LogSize ); + + target = Log->LogBuffer + ( index * Log->EntrySize ); + + RtlCopyMemory( + target, + Entry, + Log->EntrySize + ); + + return index; +} // WriteTraceLog + + +VOID +ResetTraceLog( + IN PTRACE_LOG Log + ) +{ + + //DBG_ASSERT( Log != NULL ); + //DBG_ASSERT( Log->Signature == TRACE_LOG_SIGNATURE ); + + RtlZeroMemory( + ( Log + 1 ), + Log->LogSize * Log->EntrySize + ); + + Log->NextEntry = -1; + +} // ResetTraceLog + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/src/win32obj.cxx b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/src/win32obj.cxx new file mode 100644 index 0000000000..cd6987d860 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/reftrace/src/win32obj.cxx @@ -0,0 +1,348 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#include "precomp.hxx" +#include "pudebug.h" + +#define MAX_OBJECT_NAME 256 // chars + + +LONG g_PuDbgEventsCreated = 0; +LONG g_PuDbgSemaphoresCreated = 0; +LONG g_PuDbgMutexesCreated = 0; + + + +LPSTR +PuDbgpBuildObjectName( + __in LPSTR ObjectNameBuffer, + IN ULONG ObjectNameBufferCch, + __in LPSTR FileName, + IN ULONG LineNumber, + __in LPSTR MemberName, + IN PVOID Address + ) + +/*++ + +Routine Description: + + Internal routine that builds an appropriate object name based on + the file name, line number, member name, address, and process ID. + +Arguments: + + ObjectNameBuffer - Pointer to the target buffer for the name. + + FileName - The filename of the source creating the object. This + is __FILE__ of the caller. + + LineNumber - The line number within the source. This is __LINE__ + of the caller. + + MemberName - The member/global variable name where the object handle + is to be stored. + + Address - The address of the containing structure/class or of the + global itself. + +Return Value: + + LPSTR - Pointer to ObjectNameBuffer if successful, NULL otherwise. + + N.B. This routine always returns NULL when running under Win9x. + +--*/ + +{ + + PLATFORM_TYPE platformType; + LPSTR fileNamePart; + LPSTR result; + + // + // We have no convenient way to dump objects w/ names from + // Win9x, so we'll only enable this functionality under NT. + // + + // platformType = IISGetPlatformType(); + + // + // By default IIS-Duct-tape will only run on NT platforms. So + // do not worry about getting the platform types yet. + // + platformType = PtNtServer; + result = NULL; + + if( platformType == PtNtServer || + platformType == PtNtWorkstation ) { + + // + // Find the filename part of the incoming source file name. + // + + fileNamePart = strrchr( FileName, '\\' ); + + if( fileNamePart == NULL ) { + fileNamePart = strrchr( FileName, '/' ); + } + + if( fileNamePart == NULL ) { + fileNamePart = strrchr( FileName, ':' ); + } + + if( fileNamePart == NULL ) { + fileNamePart = FileName; + } else { + fileNamePart++; + } + + // + // Ensure we don't overwrite our object name buffer. + // + + if( ( sizeof(":1234567890 :12345678 PID:1234567890") + + strlen( fileNamePart ) + + strlen( MemberName ) ) < MAX_OBJECT_NAME ) { + + sprintf_s( + ObjectNameBuffer, + ObjectNameBufferCch, + "%s:%lu %s:%08p PID:%lu", + fileNamePart, + LineNumber, + MemberName, + Address, + GetCurrentProcessId() + ); + + result = ObjectNameBuffer; + + } + + } + + return result; + +} // PuDbgpBuildObjectName + + +HANDLE +PuDbgCreateEvent( + __in LPSTR FileName, + IN ULONG LineNumber, + __in LPSTR MemberName, + IN PVOID Address, + IN BOOL ManualReset, + IN BOOL InitialState + ) + +/*++ + +Routine Description: + + Creates a new event object. + +Arguments: + + FileName - The filename of the source creating the object. This + is __FILE__ of the caller. + + LineNumber - The line number within the source. This is __LINE__ + of the caller. + + MemberName - The member/global variable name where the object handle + is to be stored. + + Address - The address of the containing structure/class or of the + global itself. + + ManualReset - TRUE to create a manual reset event, FALSE to create + an automatic reset event. + + InitialState - The intitial state of the event object. + +Return Value: + + HANDLE - Handle to the object if successful, NULL otherwise. + +--*/ + +{ + UNREFERENCED_PARAMETER( Address ); + UNREFERENCED_PARAMETER( MemberName ); + UNREFERENCED_PARAMETER( LineNumber ); + UNREFERENCED_PARAMETER( FileName ); + + LPSTR objName = NULL; + HANDLE objHandle; + //CHAR objNameBuffer[MAX_OBJECT_NAME]; + +/* + disable passing names to event creation + Longhorn forces some security checks that + prevent hostable webcore to work on checked builds + (at least ASP requests are failing when + trying to create event) + + objName = PuDbgpBuildObjectName( + objNameBuffer, + FileName, + LineNumber, + MemberName, + Address + ); +*/ + objHandle = CreateEventA( + NULL, // lpEventAttributes + ManualReset, // bManualReset + InitialState, // bInitialState + objName // lpName + ); + + if( objHandle != NULL ) { + InterlockedIncrement( &g_PuDbgEventsCreated ); + } + + return objHandle; + +} // PuDbgCreateEvent + + +HANDLE +PuDbgCreateSemaphore( + __in LPSTR FileName, + IN ULONG LineNumber, + __in LPSTR MemberName, + IN PVOID Address, + IN LONG InitialCount, + IN LONG MaximumCount + ) + +/*++ + +Routine Description: + + Creates a new semaphore object. + +Arguments: + + FileName - The filename of the source creating the object. This + is __FILE__ of the caller. + + LineNumber - The line number within the source. This is __LINE__ + of the caller. + + MemberName - The member/global variable name where the object handle + is to be stored. + + Address - The address of the containing structure/class or of the + global itself. + + InitialCount - The initial count of the semaphore. + + MaximumCount - The maximum count of the semaphore. + +Return Value: + + HANDLE - Handle to the object if successful, NULL otherwise. + +--*/ + +{ + + LPSTR objName; + HANDLE objHandle; + CHAR objNameBuffer[MAX_OBJECT_NAME]; + + objName = PuDbgpBuildObjectName( + objNameBuffer, + sizeof( objNameBuffer) / sizeof( objNameBuffer[0] ), + FileName, + LineNumber, + MemberName, + Address + ); + + objHandle = CreateSemaphoreA( + NULL, // lpSemaphoreAttributes + InitialCount, // lInitialCount + MaximumCount, // lMaximumCount + objName // lpName + ); + + if( objHandle != NULL ) { + InterlockedIncrement( &g_PuDbgSemaphoresCreated ); + } + + return objHandle; + +} // PuDbgCreateSemaphore + + +HANDLE +PuDbgCreateMutex( + __in LPSTR FileName, + IN ULONG LineNumber, + __in LPSTR MemberName, + IN PVOID Address, + IN BOOL InitialOwner + ) + +/*++ + +Routine Description: + + Creates a new mutex object. + +Arguments: + + FileName - The filename of the source creating the object. This + is __FILE__ of the caller. + + LineNumber - The line number within the source. This is __LINE__ + of the caller. + + MemberName - The member/global variable name where the object handle + is to be stored. + + Address - The address of the containing structure/class or of the + global itself. + + InitialOwner - TRUE if the mutex should be created "owned". + +Return Value: + + HANDLE - Handle to the object if successful, NULL otherwise. + +--*/ + +{ + + LPSTR objName; + HANDLE objHandle; + CHAR objNameBuffer[MAX_OBJECT_NAME]; + + objName = PuDbgpBuildObjectName( + objNameBuffer, + sizeof( objNameBuffer) / sizeof( objNameBuffer[0] ), + FileName, + LineNumber, + MemberName, + Address + ); + + objHandle = CreateMutexA( + NULL, // lpMutexAttributes + InitialOwner, // bInitialOwner, + objName // lpName + ); + + if( objHandle != NULL ) { + InterlockedIncrement( &g_PuDbgMutexesCreated ); + } + + return objHandle; + +} // PuDbgCreateMutex + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/version/bldver.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/version/bldver.h new file mode 100644 index 0000000000..63a67d68f4 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/version/bldver.h @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#ifndef _BLDVER_H_ +#define _BLDVER_H_ + +#define STR_HELPER(x) #x +#define WSTR_HELPER(x) L#x +#define NUM_TO_STR(x) STR_HELPER(x) +#define NUM_TO_WSTR(x) WSTR_HELPER(x) + +// +// Build versions are properties of the build system but can be overwritten below +// +// #define PRODUCT_MAJOR 7 +// #define PRODUCT_MINOR 1 +// #define BUILD_MAJOR 1972 +// #define BUILD_MINOR 0 + +#define PRODUCT_MAJOR_STRING NUM_TO_STR(PRODUCT_MAJOR) +#define PRODUCT_MAJOR_STRING_L NUM_TO_WSTR(PRODUCT_MAJOR) +#define PRODUCT_MAJOR_NUMBER PRODUCT_MAJOR + +#define PRODUCT_MINOR_STRING NUM_TO_STR(PRODUCT_MINOR) +#define PRODUCT_MINOR_STRING_L NUM_TO_WSTR(PRODUCT_MINOR) +#define PRODUCT_MINOR_NUMBER PRODUCT_MINOR + +#define BUILD_MAJOR_STRING NUM_TO_STR(BUILD_MAJOR) +#define BUILD_MAJOR_STRING_L NUM_TO_WSTR(BUILD_MAJOR) +#define BUILD_MAJOR_NUMBER BUILD_MAJOR + +#define BUILD_MINOR_STRING NUM_TO_STR(BUILD_MINOR) +#define BUILD_MINOR_STRING_L NUM_TO_WSTR(BUILD_MINOR) +#define BUILD_MINOR_NUMBER BUILD_MINOR + +#define BUILD_NUMBER BUILD_MAJOR_STRING "." BUILD_MINOR_STRING +#define BUILD_NUM BUILD_MAJOR , BUILD_MINOR +#define PRODUCT_NUMBER PRODUCT_MAJOR_STRING "." PRODUCT_MINOR_STRING +#define PRODUCT_NUM PRODUCT_MAJOR , PRODUCT_MINOR +#define INET_VERSION PRODUCT_MAJOR_STRING "." PRODUCT_MINOR_STRING "." BUILD_MAJOR_STRING "." BUILD_MINOR_STRING +#define INET_VERSION_L PRODUCT_MAJOR_STRING_L L"." PRODUCT_MINOR_STRING_L L"." BUILD_MAJOR_STRING_L L"." BUILD_MINOR_STRING_L +#define INET_VER PRODUCT_MAJOR , PRODUCT_MINOR , BUILD_MAJOR , BUILD_MINOR + +#define BUILD_PRIVATE "Built by IISBLD on IISBLD.\0" + +#undef VER_PRODUCTVERSION +#undef VER_PRODUCTVERSION_STR +#undef VER_PRODUCTMAJORVERSION +#undef VER_PRODUCTMINORVERSION +#undef VER_PRODUCTBUILD +#undef VER_PRODUCTBUILD_QFE +#undef VER_PRODUCTNAME_STR +#undef VER_COMPANYNAME_STR + +#define VER_PRODUCTVERSION PRODUCT_MAJOR,PRODUCT_MINOR,BUILD_MAJOR,BUILD_MINOR +#define VER_PRODUCTVERSION_STR PRODUCT_MAJOR_STRING "." PRODUCT_MINOR_STRING "." BUILD_MAJOR_STRING "." BUILD_MINOR_STRING +#define VER_PRODUCTMAJORVERSION PRODUCT_MAJOR +#define VER_PRODUCTMINORVERSION PRODUCT_MINOR +#define VER_PRODUCTBUILD BUILD_MAJOR +#define VER_PRODUCTBUILD_QFE BUILD_MINOR +#define VER_PRODUCTNAME_STR "Microsoft Web Platform Extensions" +#define VER_COMPANYNAME_STR "Microsoft Corporation" + +#endif diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/version/bldver.rc b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/version/bldver.rc new file mode 100644 index 0000000000..30a96499ec --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Common/version/bldver.rc @@ -0,0 +1,73 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +// BLDVER.RC - Standard version resource for CoreXT applications. + +// Before including this file into your .rc, define the following +// macros for your application (don't forget the \0's): +// #define RC_VERSION_FILE_DESCRIPTION "Test DLL\0" +// #define RC_VERSION_INTERNAL_NAME "Test\0" +// #define RC_VERSION_ORIGINAL_FILE_NAME "Test.DLL\0" + +#include +#include + +VS_VERSION_INFO VERSIONINFO + +FILEVERSION INET_VER +PRODUCTVERSION INET_VER + +FILEFLAGSMASK 0x3fL +#ifdef DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + +// +// Global definitions +// +#ifndef RC_VERSION_COMPANY_NAME + #define RC_VERSION_COMPANY_NAME "Microsoft Corporation\0" +#endif + +#ifndef RC_VERSION_PRODUCT_NAME + #define RC_VERSION_PRODUCT_NAME "Microsoft\256 Web Platform Extensions\0" +#endif + +#ifndef RC_VERSION_LEGAL_COPYRIGHT + #define RC_VERSION_LEGAL_COPYRIGHT "Copyright \251 Microsoft Corporation\0" +#endif + +#ifndef RC_VERSION_LEGAL_TRADEMARKS + #define RC_VERSION_LEGAL_TRADEMARKS "Microsoft\256 is a registered trademark of Microsoft Corporation.\0" +#endif + +FILEOS 0x4L +FILETYPE 0x1L +FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", RC_VERSION_COMPANY_NAME + VALUE "FileDescription", RC_VERSION_FILE_DESCRIPTION + VALUE "InternalName", RC_VERSION_INTERNAL_NAME + VALUE "LegalCopyright", RC_VERSION_LEGAL_COPYRIGHT + VALUE "LegalTrademarks", RC_VERSION_LEGAL_TRADEMARKS + VALUE "OriginalFilename", RC_VERSION_ORIGINAL_FILE_NAME + VALUE "ProductName", RC_VERSION_PRODUCT_NAME + VALUE "FileVersion", INET_VERSION + VALUE "ProductVersion", INET_VERSION + VALUE "PrivateBuild", BUILD_PRIVATE +#ifdef OLEREGISTER + VALUE "OLESelfRegister","\0" +#endif + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Setup.sln b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Setup.sln new file mode 100644 index 0000000000..4ec3c19636 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/IIS-Setup.sln @@ -0,0 +1,41 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26730.12 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iisca", "iisca\lib\iisca.vcxproj", "{7324770C-0871-4D73-BE3D-5E2F3E9E1B1E}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CommonLib", "IIS-Common\lib\CommonLib.vcxproj", "{B54A8F61-60DE-4AD9-87CA-D102F230678E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7324770C-0871-4D73-BE3D-5E2F3E9E1B1E}.Debug|x64.ActiveCfg = Debug|x64 + {7324770C-0871-4D73-BE3D-5E2F3E9E1B1E}.Debug|x64.Build.0 = Debug|x64 + {7324770C-0871-4D73-BE3D-5E2F3E9E1B1E}.Debug|x86.ActiveCfg = Debug|Win32 + {7324770C-0871-4D73-BE3D-5E2F3E9E1B1E}.Debug|x86.Build.0 = Debug|Win32 + {7324770C-0871-4D73-BE3D-5E2F3E9E1B1E}.Release|x64.ActiveCfg = Release|x64 + {7324770C-0871-4D73-BE3D-5E2F3E9E1B1E}.Release|x64.Build.0 = Release|x64 + {7324770C-0871-4D73-BE3D-5E2F3E9E1B1E}.Release|x86.ActiveCfg = Release|Win32 + {7324770C-0871-4D73-BE3D-5E2F3E9E1B1E}.Release|x86.Build.0 = Release|Win32 + {B54A8F61-60DE-4AD9-87CA-D102F230678E}.Debug|x64.ActiveCfg = Debug|x64 + {B54A8F61-60DE-4AD9-87CA-D102F230678E}.Debug|x64.Build.0 = Debug|x64 + {B54A8F61-60DE-4AD9-87CA-D102F230678E}.Debug|x86.ActiveCfg = Debug|Win32 + {B54A8F61-60DE-4AD9-87CA-D102F230678E}.Debug|x86.Build.0 = Debug|Win32 + {B54A8F61-60DE-4AD9-87CA-D102F230678E}.Release|x64.ActiveCfg = Release|x64 + {B54A8F61-60DE-4AD9-87CA-D102F230678E}.Release|x64.Build.0 = Release|x64 + {B54A8F61-60DE-4AD9-87CA-D102F230678E}.Release|x86.ActiveCfg = Release|Win32 + {B54A8F61-60DE-4AD9-87CA-D102F230678E}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {3DC22D38-F38B-420A-9AD1-77F2512B35FF} + EndGlobalSection +EndGlobal diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/LICENSE b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/LICENSE new file mode 100644 index 0000000000..21071075c2 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/LICENSE @@ -0,0 +1,21 @@ + MIT License + + Copyright (c) Microsoft Corporation. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/README.md b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/README.md new file mode 100644 index 0000000000..22e594aa6c --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/README.md @@ -0,0 +1,18 @@ +Microsoft IIS Setup +-------------------------------- + +The repository contains setup resources shared by IIS Out-Of-Band (OOB) products. + +### Contributing + +This project welcomes contributions and suggestions. Most contributions require you to agree to a +Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us +the rights to use your contribution. For details, visit https://cla.microsoft.com. + +When you submit a pull request, a CLA-bot will automatically determine whether you need to provide +a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions +provided by the bot. You will only need to do this once across all repos using our CLA. + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). +For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or +contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/appsearch/appsearch.wxi b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/appsearch/appsearch.wxi new file mode 100644 index 0000000000..820cc86f4e --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/appsearch/appsearch.wxi @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/ConfigShared.cpp b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/ConfigShared.cpp new file mode 100644 index 0000000000..883a228a33 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/ConfigShared.cpp @@ -0,0 +1,59 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#include "precomp.h" + + +HRESULT +CheckInstallToSharedConfig( + IN MSIHANDLE hInstall, + BOOL * pbShouldInstall + ) +{ + HRESULT hr = S_OK; + STRU strShared; + STRU strWriteToShared; + + *pbShouldInstall = FALSE; + + //Check if config is shared + hr = MsiUtilGetProperty( hInstall, L"IISCONFIGISSHARED", &strShared ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + if( 0 != wcscmp( strShared.QueryStr(), L"1" ) ) + { + //config is not shared, tell caller to schedule executeCA for config + IISLogWrite(SETUP_LOG_SEVERITY_INFORMATION, L"IIS Configuration is NOT shared. Setup will schedule the deferred custom action."); + *pbShouldInstall = TRUE; + goto exit; + } + + // + //config is shared lets check IIUSESHAREDCONFIG Property + // + hr = MsiUtilGetProperty( hInstall, L"IIUSESHAREDCONFIG", &strWriteToShared ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + if( 0 == wcscmp( strWriteToShared.QueryStr(), L"1" ) ) + { + //Config is shared but property is set + //tell caller to schedule executeCA for config + // + IISLogWrite(SETUP_LOG_SEVERITY_INFORMATION, L"IIS Configuration IS shared. IIUSESHAREDCONFIG property indicated that setup SHOULD schedule the deferred custom action.."); + *pbShouldInstall = TRUE; + } + else + { + IISLogWrite(SETUP_LOG_SEVERITY_INFORMATION, L"IIS Configuration IS shared. IIUSESHAREDCONFIG property indicated that setup should NOT schedule the deferred custom action."); + } + +exit: + return hr; +} + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/ConfigShared.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/ConfigShared.h new file mode 100644 index 0000000000..0ac0ea9852 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/ConfigShared.h @@ -0,0 +1,8 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +HRESULT +CheckInstallToSharedConfig( + IN MSIHANDLE hInstall, + BOOL * pbShouldInstall + ); diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/CustomAction.def b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/CustomAction.def new file mode 100644 index 0000000000..8ba47da929 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/CustomAction.def @@ -0,0 +1,15 @@ +; Copyright (c) Microsoft Corporation. All rights reserved. +; Licensed under the MIT license. + +LIBRARY iisca + +EXPORTS + + ; IIS Common Config custom actions + + IISScheduleInstallCA + IISScheduleUninstallCA + IISExecuteCA + IISBeginTransactionCA + IISRollbackTransactionCA + IISCommitTransactionCA diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/cgi_restrictions.cpp b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/cgi_restrictions.cpp new file mode 100644 index 0000000000..b57a5d3037 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/cgi_restrictions.cpp @@ -0,0 +1,271 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#include "precomp.h" + +// +// Public functions +// + +HRESULT +RegisterCgiRestriction( + IN IAppHostAdminManager * pAdminMgr, + IN CONST WCHAR * szConfigPath, + IN CONST WCHAR * szPath, + IN BOOL fAllowed, + IN OPTIONAL CONST WCHAR * szGroupId, + IN OPTIONAL CONST WCHAR * szDescription + ) +{ + HRESULT hr = NOERROR; + + CComPtr pCgiRestrictionSection; + CComPtr pCgiRestrictionCollection; + CComPtr pNewCgiRestrictionElement; + + BSTR bstrAppHostConfigPath = SysAllocString(szConfigPath); + BSTR bstrCgiRestriction = SysAllocString( L"system.webServer/security/isapiCgiRestriction" ); + BSTR bstrAdd = SysAllocString( L"add" ); + + if( !bstrAppHostConfigPath || + !bstrCgiRestriction || + !bstrAdd ) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR( hr ); + goto exit; + } + + // + // Remove any existing web service first, + // ignore any resulting errors. + // + + hr = UnRegisterCgiRestriction( + pAdminMgr, + szConfigPath, + szPath, + FALSE // do NOT expand environment strings + ); + + if (FAILED(hr)) + { + DBGERROR_HR(hr); + // press on regardless + } + + hr = UnRegisterCgiRestriction( + pAdminMgr, + szConfigPath, + szPath, + TRUE // DO expand environment strings + ); + + if (FAILED(hr)) + { + DBGERROR_HR(hr); + // press on regardless + } + + // + // Get the ISAPI CGI Restriction collection + // + + hr = pAdminMgr->GetAdminSection( bstrCgiRestriction, + bstrAppHostConfigPath, + &pCgiRestrictionSection ); + + + if( FAILED(hr) ) + { + DBGERROR_HR( hr ); + goto exit; + } + + hr = pCgiRestrictionSection->get_Collection( &pCgiRestrictionCollection ); + + if( FAILED(hr) ) + { + DBGERROR_HR( hr ); + goto exit; + } + + // + // Create a new element + // + + hr = pCgiRestrictionCollection->CreateNewElement( bstrAdd, + &pNewCgiRestrictionElement ); + + if( FAILED(hr) ) + { + DBGERROR_HR( hr ); + goto exit; + } + + hr = SetElementStringProperty( + pNewCgiRestrictionElement, + L"path", + szPath + ); + + if( FAILED(hr) ) + { + DBGERROR_HR( hr ); + goto exit; + } + + hr = SetElementStringProperty( + pNewCgiRestrictionElement, + L"allowed", + fAllowed ? L"true" : L"false" + ); + + if( FAILED(hr) ) + { + DBGERROR_HR( hr ); + goto exit; + } + + if( szGroupId && *szGroupId ) + { + hr = SetElementStringProperty( + pNewCgiRestrictionElement, + L"groupId", + szGroupId + ); + + if( FAILED(hr) ) + { + DBGERROR_HR( hr ); + goto exit; + } + } + + if( szDescription && *szDescription ) + { + hr = SetElementStringProperty( + pNewCgiRestrictionElement, + L"description", + szDescription + ); + + if( FAILED(hr) ) + { + DBGERROR_HR( hr ); + goto exit; + } + } + + // + // Add the new element + // + + hr = pCgiRestrictionCollection->AddElement( pNewCgiRestrictionElement ); + + if( FAILED(hr) ) + { + DBGERROR_HR( hr ); + goto exit; + } + +exit: + + SysFreeString( bstrAppHostConfigPath ); + SysFreeString( bstrCgiRestriction ); + SysFreeString( bstrAdd ); + + return hr; +} + +HRESULT +UnRegisterCgiRestriction( + IN IAppHostAdminManager * pAdminMgr, + IN CONST WCHAR * szConfigPath, + IN CONST WCHAR * szPath, + IN BOOL fExpandPath + ) +{ + HRESULT hr = NOERROR; + + CComPtr pCgiRestrictionSection; + CComPtr pCgiRestrictionCollection; + + BSTR bstrAppHostConfigPath = SysAllocString(szConfigPath); + BSTR bstrCgiRestriction = SysAllocString( L"system.webServer/security/isapiCgiRestriction" ); + + UINT numDeleted; + + STRU expandedPath; + + if( !bstrAppHostConfigPath || + !bstrCgiRestriction ) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR( hr ); + goto exit; + } + + if (fExpandPath) + { + hr = expandedPath.CopyAndExpandEnvironmentStrings(szPath); + + if (FAILED(hr)) + { + DBGERROR_HR(hr); + goto exit; + } + + szPath = expandedPath.QueryStr(); + } + + // + // Remove from the ISAPI CGI Restriction collection + // + + hr = pAdminMgr->GetAdminSection( bstrCgiRestriction, + bstrAppHostConfigPath, + &pCgiRestrictionSection ); + + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pCgiRestrictionSection->get_Collection( &pCgiRestrictionCollection ); + + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = DeleteAllElementsFromCollection( pCgiRestrictionCollection, + L"path", + szPath, + FIND_ELEMENT_CASE_INSENSITIVE, + &numDeleted + ); + + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + if( numDeleted == 0 ) + { + DBGWARN(( DBG_CONTEXT, + "Expected to find %S in ISAPI CGI Restriction collection\n", + szPath )); + } + +exit: + + SysFreeString( bstrAppHostConfigPath ); + SysFreeString( bstrCgiRestriction ); + + return hr; +} + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/cgi_restrictions.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/cgi_restrictions.h new file mode 100644 index 0000000000..68ae838d07 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/cgi_restrictions.h @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + + +#ifndef _CGI_RESTRICTIONS_H_ +#define _CGI_RESTRICTIONS_H_ + + +HRESULT +RegisterCgiRestriction( + IN IAppHostAdminManager * pAdminMgr, + IN CONST WCHAR * szConfigPath, + IN CONST WCHAR * szPath, + IN BOOL fAllowed, + IN OPTIONAL CONST WCHAR * szGroupId, + IN OPTIONAL CONST WCHAR * szDescription + ); + + +HRESULT +UnRegisterCgiRestriction( + IN IAppHostAdminManager * pAdminMgr, + IN CONST WCHAR * szConfigPath, + IN CONST WCHAR * szPath, + IN BOOL fExpandPath = FALSE + ); + + +#endif + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/config_custom.cpp b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/config_custom.cpp new file mode 100644 index 0000000000..8d44a69506 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/config_custom.cpp @@ -0,0 +1,72 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#include "precomp.h" + +UINT +__stdcall +CheckForSharedConfigurationCA( + MSIHANDLE hInstall +) +{ + HRESULT hr = S_OK; + UINT status = ERROR_SUCCESS; + BOOL fIsSharedConfig = FALSE; + STRU strWriteToShared; + + IISLogInitialize(hInstall, UNITEXT(__FUNCTION__)); + + hr = GetSharedConfigEnabled( &fIsSharedConfig ); + if ( FAILED( hr ) ) + { + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Unable to detect whether shared configuration is in use."); + status = LogMsiCustomActionError( hInstall, 30001 ); + goto exit; + } + if ( fIsSharedConfig ) + { + //set config shared property. + //will be used by other CAs via CheckInstallToSharedConfig + hr = MsiSetProperty( hInstall, L"IISCONFIGISSHARED", L"1" ); + if ( FAILED( hr ) ) + { + goto exit; + } + // + //config is shared lets check if user + //set public property IIUSESHAREDCONFIG + // + hr = MsiUtilGetProperty( hInstall, L"IIUSESHAREDCONFIG", &strWriteToShared ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + if( 0 == wcscmp( strWriteToShared.QueryStr(), L"1" ) ) + { + //Config is shared but property is set + //tell caller to schedule executeCA for config + // + IISLogWrite(SETUP_LOG_SEVERITY_INFORMATION, L"IIS Configuration IS shared. IIUSESHAREDCONFIG property indicated that setup SHOULD schedule the deferred custom action.."); + } + else + { + // + //public property not set error-out install + // + IISLogWrite(SETUP_LOG_SEVERITY_INFORMATION, L"Shared Configuration detected."); + status = LogMsiCustomActionError( hInstall, 30002 ); + goto exit; + } + } + else + { + IISLogWrite(SETUP_LOG_SEVERITY_INFORMATION, L"No Shared Configuration detected."); + } + +exit: + + IISLogClose(); + return status; +} + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/config_custom.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/config_custom.h new file mode 100644 index 0000000000..f69b0101c4 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/config_custom.h @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + + +#ifndef _CONFIG_CUSTOM_H_ +#define _CONFIG_CUSTOM_H_ + + +UINT +__stdcall +CheckForSharedConfigurationCA( + MSIHANDLE hInstall +); + +#endif + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/consoleprops.cpp b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/consoleprops.cpp new file mode 100644 index 0000000000..ed39ca6af6 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/consoleprops.cpp @@ -0,0 +1,594 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#include "precomp.h" + +#define CheckAndGoToExit(hr,sev,msg,prop) if (FAILED(hr)) { DBGERROR_HR(hr); IISLogWrite(sev, msg, prop, hr);goto exit;} +#define CheckAndReturnHr(hr,sev,msg,prop) if (FAILED(hr)) { DBGERROR_HR(hr); IISLogWrite(sev, msg, prop, hr);return hr;} + + +HRESULT +GetConsoleIntProperty( + IN MSIHANDLE hRecord, + IN UINT field, + __inout CA_DATA_WRITER * cadata) +{ + HRESULT hr = S_OK; + + UINT dwValue = 0; + hr = MsiUtilRecordGetInteger( hRecord, + field, + &dwValue ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error getting column %d from record, hr=0x%x", field, hr); + return hr; + } + + hr = cadata->Write(dwValue); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error writing custom action data, hr=0x%x", hr); + return hr; + } + + return hr; +} + +HRESULT +GetConsoleProperties( + IN MSIHANDLE hRecord, + __inout CA_DATA_WRITER * cadata) +{ + HRESULT hr = S_OK; + + /*STACK_STRU( strTextColour, 128 ); + STACK_STRU( strBackgroundColour, 128 );*/ + + enum { + CA_CONSOLEPROPS_QUCIKEDIT = 5, + CA_CONSOLEPROPS_INSERTMODE, + CA_CONSOLEPROPS_WINDOWWIDTH, + CA_CONSOLEPROPS_WINDOWHEIGHT, + CA_CONSOLEPROPS_BUFFERWIDTH, + CA_CONSOLEPROPS_BUFFERHEIGHT, + /* CA_CONSOLEPROPS_TEXTCOLOUR, + CA_CONSOLEPROPS_BACKGROUNDCOLOUR*/ + }; + + // GET QuickEdit int + hr = GetConsoleIntProperty( hRecord, + CA_CONSOLEPROPS_QUCIKEDIT, + cadata ); + if ( FAILED(hr) ) { return hr;} + + // GET InsertMode + hr = GetConsoleIntProperty( hRecord, + CA_CONSOLEPROPS_INSERTMODE, + cadata ); + if ( FAILED(hr) ) { return hr;} + + + // GET WindowWidth + hr = GetConsoleIntProperty( hRecord, + CA_CONSOLEPROPS_WINDOWWIDTH, + cadata ); + if ( FAILED(hr) ) { return hr;} + + + // GET WindowHeight + hr = GetConsoleIntProperty( hRecord, + CA_CONSOLEPROPS_WINDOWHEIGHT, + cadata ); + if ( FAILED(hr) ) { return hr;} + + + // GET BufferWidth + hr = GetConsoleIntProperty( hRecord, + CA_CONSOLEPROPS_BUFFERWIDTH, + cadata ); + if ( FAILED(hr) ) { return hr;} + + + // GET BufferHeight + hr = GetConsoleIntProperty( hRecord, + CA_CONSOLEPROPS_BUFFERHEIGHT, + cadata ); + if ( FAILED(hr) ) { return hr;} + + //// Get Text colours + //hr = MsiUtilRecordGetString( hRecord, + // CA_CONSOLEPROPS_TEXTCOLOUR, + // &strTextColour ); + + //CheckAndReturnHr(hr, SETUP_LOG_SEVERITY_ERROR, L"Error getting column %d from record, hr=0x%x", CA_CONSOLEPROPS_TEXTCOLOUR); + + //hr = cadata->Write( strTextColour.QueryStr(), strTextColour.QueryCCH() ); + //if ( FAILED(hr) ) + //{ + // DBGERROR_HR(hr); + // IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error writing custom action data, hr=0x%x", hr); + // return hr; + //} + + //// Get Background colours + //hr = MsiUtilRecordGetString( hRecord, + // CA_CONSOLEPROPS_BACKGROUNDCOLOUR, + // &strBackgroundColour ); + + //CheckAndReturnHr(hr, SETUP_LOG_SEVERITY_ERROR, L"Error getting column %d from record, hr=0x%x", CA_CONSOLEPROPS_TEXTCOLOUR); + + //hr = cadata->Write( strBackgroundColour.QueryStr(), strBackgroundColour.QueryCCH() ); + //if ( FAILED(hr) ) + //{ + // DBGERROR_HR(hr); + // IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error writing custom action data, hr=0x%x", hr); + // return hr; + //} + + return hr; +} + +UINT +WINAPI +ScheduleSetConsolePropertiesCA( + IN MSIHANDLE hInstall + ) +{ + HRESULT hr = S_OK; + UINT status = ERROR_SUCCESS; + + MSIHANDLE hDatabase = NULL; + MSIHANDLE hView = NULL; + MSIHANDLE hRecord = NULL; + + STACK_STRU( strShortcut, 128 ); + STACK_STRU( strDirectoryId, 256 ); // Directory Identifier + STACK_STRU( strDirectoryName, 256 ); + STACK_STRU( strComponent, 128 ); + STACK_STRU( strShortcutName, 256 ); + STACK_STRU( strData, 256); + + + CONST WCHAR * szQuery = + L"SELECT " + L"`IISShortcutConsoleProperties`.`Shortcut_`, " + L"`Shortcut`.`Component_`, " + L"`Shortcut`.`Name`, " + L"`Directory`.`Directory`, " + L"`IISShortcutConsoleProperties`.`QuickEdit`, " + L"`IISShortcutConsoleProperties`.`InsertMode`, " + L"`IISShortcutConsoleProperties`.`WindowWidth`, " + L"`IISShortcutConsoleProperties`.`WindowHeight`, " + L"`IISShortcutConsoleProperties`.`BufferWidth`, " + L"`IISShortcutConsoleProperties`.`BufferHeight` " + /*L"`IISShortcutConsoleProperties`.`TextColor`, " + L"`IISShortcutConsoleProperties`.`BackgroundColor` "*/ + L"FROM `IISShortcutConsoleProperties`, `Shortcut`, `Directory` " + L"WHERE `IISShortcutConsoleProperties`.`Shortcut_`=`Shortcut`.`Shortcut` " + L"AND `Shortcut`.`Directory_`=`Directory`.`Directory`"; + + + CA_DATA_WRITER cadata; + INSTALLSTATE installStateCurrent; + INSTALLSTATE installStateAction; + + BOOL scheduleDefferedCA = FALSE; + + enum { + CA_CONSOLEPROPS_SHORTCUT = 1, + CA_CONSOLEPROPS_COMPONENT, + CA_CONSOLEPROPS_SHORTCUTNAME, + CA_CONSOLEPROPS_DIRECTORY, + }; + + IISLogInitialize(hInstall, UNITEXT(__FUNCTION__)); + + hDatabase = MsiGetActiveDatabase( hInstall ); + if ( !hDatabase ) + { + hr = E_UNEXPECTED; + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error getting MSI database, hr=0x%x", hr); + DBGERROR_HR(hr); + goto exit; + } + + status = MsiDatabaseOpenViewW( hDatabase, szQuery, &hView ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error opening View, hr=0x%x", hr); + DBGERROR_HR(hr); + goto exit; + } + + status = MsiViewExecute( hView, NULL ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error executing view, hr=0x%x", hr); + DBGERROR_HR(hr); + goto exit; + } + + while ( ERROR_SUCCESS == MsiViewFetch( hView, &hRecord ) ) + { + hr = MsiUtilRecordGetString( hRecord, + CA_CONSOLEPROPS_COMPONENT, + &strComponent ); + CheckAndGoToExit(hr, SETUP_LOG_SEVERITY_ERROR, L"Error getting column %d from record, hr=0x%x", CA_CONSOLEPROPS_COMPONENT); + + status = MsiGetComponentStateW( hInstall, + strComponent.QueryStr(), + &installStateCurrent, + &installStateAction ); + + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32(status); + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error getting state for component %s, hr=0x%x", strComponent.QueryStr(), hr); + goto exit; + } + + // Only run if the comonent is installing or reinstalling + if ( MsiUtilIsInstalling( installStateCurrent, installStateAction ) || + MsiUtilIsReInstalling( installStateCurrent, installStateAction ) ) + { + // Get Shortcut location + { + // GET: directory where shortcut is + // Get the directory id for the shortcut + hr = MsiUtilRecordGetString( hRecord, + CA_CONSOLEPROPS_DIRECTORY, + &strDirectoryId ); + + CheckAndGoToExit(hr, SETUP_LOG_SEVERITY_ERROR, L"Error getting column %d from record, hr=0x%x", CA_CONSOLEPROPS_DIRECTORY); + + // Get directory path + hr = MsiUtilGetProperty(hInstall, strDirectoryId.QueryStr(), &strDirectoryName ); + + CheckAndGoToExit(hr, SETUP_LOG_SEVERITY_ERROR, L"Error getting value for directory record %s, hr=0x%x", strDirectoryId.QueryStr()); + + IISLogWrite ( SETUP_LOG_SEVERITY_INFORMATION, + L"Shortcut Directory: '%s'.", + strDirectoryName.QueryStr()); + // ENDGET: directory where shortcut is + + + // GET: Short and Long names of shortcuts + hr = MsiUtilRecordGetString( hRecord, + CA_CONSOLEPROPS_SHORTCUTNAME, + &strShortcutName ); + + CheckAndGoToExit(hr, SETUP_LOG_SEVERITY_ERROR, L"Error getting column %d from record, hr=0x%x", CA_CONSOLEPROPS_SHORTCUTNAME); + + + // strShortcutName contains the short and long file names of the shortcut + PCWSTR pszPrevious = strShortcutName.QueryStr(); + // Append the shortcut name to the directory and write to cadata + // Write the short and long shortcut paths + for ( DWORD i = 0; i < strShortcutName.QueryCCH() + 1; i++ ) + { + if ( strShortcutName.QueryStr()[ i ] == L'|' || + strShortcutName.QueryStr()[ i ] == L'\0' ) + { + strShortcutName.QueryStr()[ i ] = L'\0'; + + strData.Copy( strDirectoryName ); + strData.Append(L"\\"); + strData.Append(pszPrevious); + strData.Append(L".lnk"); + + IISLogWrite ( SETUP_LOG_SEVERITY_INFORMATION, + L"Potential shortcut path: %s", + strData.QueryStr()); + + hr = cadata.Write( strData.QueryStr(), strData.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error writing custom action data, hr=0x%x", hr); + goto exit; + } + + pszPrevious = strShortcutName.QueryStr() + i + 1; + + // Get the console properties + hr = GetConsoleProperties(hRecord, &cadata); + if( FAILED(hr)) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error getting console properties, hr=0x%x", hr); + goto exit; + } + + // Only schedule custom action if needed + scheduleDefferedCA = TRUE; + } + } + // ENDGET: Short and Long names of shortcuts + } + // End OF getting shortcut location + } + + if ( hRecord ) + { + MsiCloseHandle( hRecord ); + hRecord = NULL; + } + + } + + if ( scheduleDefferedCA ) + { + hr = MsiUtilScheduleDeferredAction( hInstall, + L"ExecuteSetConsoleProperties", + cadata.QueryData() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error scheduling custom action, hr=0x%x", hr); + goto exit; + } + + IISLogWrite ( SETUP_LOG_SEVERITY_INFORMATION, + L"Custom action ExecuteSetConsoleProperties scheduled"); + } + +exit: + + if ( hRecord ) + { + MsiCloseHandle( hRecord ); + hRecord = NULL; + } + + if ( hView ) + { + MsiCloseHandle( hView ); + hView = NULL; + } + + if ( hDatabase ) + { + MsiCloseHandle( hDatabase ); + hDatabase = NULL; + } + + IISLogClose(); + + return (SUCCEEDED(hr)) ? ERROR_SUCCESS : ERROR_SUCCESS; +} + +void IntializeConsoleProps( + IN NT_CONSOLE_PROPS* pConsoleProps + ) +{ + if (!pConsoleProps) + { + return; + } + + pConsoleProps->dbh.cbSize = sizeof(NT_CONSOLE_PROPS); + pConsoleProps->dbh.dwSignature = NT_CONSOLE_PROPS_SIG; + pConsoleProps->bFullScreen = false; + pConsoleProps->uHistoryBufferSize = 50; + pConsoleProps->uNumberOfHistoryBuffers = 4; + pConsoleProps->uCursorSize = 25; + + pConsoleProps->ColorTable[0] = RGB(0,0,0); + pConsoleProps->ColorTable[1] = RGB(0,0,128); + pConsoleProps->ColorTable[2] = RGB(0,128,0); + pConsoleProps->ColorTable[3] = RGB(0,128,128); + pConsoleProps->ColorTable[4] = RGB(128,0,0); + pConsoleProps->ColorTable[5] = RGB(128,0,128); + pConsoleProps->ColorTable[6] = RGB(128,128,0); + pConsoleProps->ColorTable[7] = RGB(192,192,192); + pConsoleProps->ColorTable[8] = RGB(128,128,128); + pConsoleProps->ColorTable[9] = RGB(0,0,255); + pConsoleProps->ColorTable[10] = RGB(0,255,0); + pConsoleProps->ColorTable[11] = RGB(0,255,255); + pConsoleProps->ColorTable[12] = RGB(255,0,0); + pConsoleProps->ColorTable[13] = RGB(255,0,255); + pConsoleProps->ColorTable[14] = RGB(255,255,0); + pConsoleProps->ColorTable[15] = RGB(255,255,255); + + pConsoleProps->wPopupFillAttribute = ((15 << 4) | 3); +} + + +UINT +WINAPI +ExecuteSetConsolePropertiesCA( + IN MSIHANDLE hInstall + ) +{ + HRESULT hr = S_OK; + + BOOL fCoInit = FALSE; + + WCHAR * szShortcutFile = NULL; + /*WCHAR * szTextColour = NULL; + WCHAR * szBackgroundColour = NULL;*/ + INT dwQuickEdit = 0; + INT dwInsertMode = 0; + INT dwWindowWidth = 120; + INT dwWindowHeight = 50; + INT dwBufferWidth = 120; + INT dwBufferHeight = 3000; + + + CA_DATA_READER cadata; + + IISLogInitialize(hInstall, UNITEXT(__FUNCTION__)); + + // + // Retrieve parameters from ca data + // + + hr = cadata.LoadDeferredCAData( hInstall ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error retrieving custom action data, hr=0x%x", hr); + goto exit; + } + + if ( SUCCEEDED( hr = CoInitialize(NULL) ) ) + { + fCoInit = TRUE; + } + + while ( SUCCEEDED(hr = cadata.Read( &szShortcutFile )) ) + { + hr = cadata.Read( &dwQuickEdit); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata.Read( &dwInsertMode); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata.Read( &dwWindowWidth); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata.Read( &dwWindowHeight); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata.Read( &dwBufferWidth); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata.Read( &dwBufferHeight); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + /*hr = cadata.Read( &szTextColour); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata.Read( &szBackgroundColour); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + }*/ + + // Check to see if file exists + if(GetFileAttributes(szShortcutFile) != 0xFFFFFFFF) + { + IISLogWrite ( SETUP_LOG_SEVERITY_INFORMATION, + L"Shortcut %s exists", szShortcutFile); + + // Get shell + CComPtr sppf; + + if (FAILED(hr = sppf.CoCreateInstance(L"lnkfile")) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error get ShellLink com object, hr=0x%x", hr); + goto exit; + } + + // Load shortcut file + if (FAILED(hr = sppf->Load(szShortcutFile, STGM_READWRITE))) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error loading shortcut file %s, hr=0x%x", szShortcutFile, hr); + goto exit; + } + + CComQIPtr spdl(sppf); + if (!spdl) + { + DBGERROR_HR(hr); + goto exit; + } + + NT_CONSOLE_PROPS* pConsoleProps = NULL; + + hr = spdl->CopyDataBlock(NT_CONSOLE_PROPS_SIG, (LPVOID*) &pConsoleProps); + if ( FAILED(hr) || (NULL == pConsoleProps) ) + { + // Create new console properties and set defaults + pConsoleProps = (NT_CONSOLE_PROPS *)malloc(sizeof(NT_CONSOLE_PROPS)); + memset(pConsoleProps,0,sizeof(NT_CONSOLE_PROPS)); + IntializeConsoleProps(pConsoleProps); + } + + pConsoleProps->bQuickEdit = dwQuickEdit > 0; + pConsoleProps->bInsertMode = dwInsertMode > 0; + pConsoleProps->dwWindowSize.X = (short) dwWindowWidth; + pConsoleProps->dwWindowSize.Y = (short) dwWindowHeight; + pConsoleProps->dwScreenBufferSize.X = (short) dwBufferWidth; + pConsoleProps->dwScreenBufferSize.Y = (short) dwBufferHeight; + + pConsoleProps->ColorTable[6] = RGB(238, 237, 240); // text color + pConsoleProps->ColorTable[5] = RGB(1, 36, 86); // backgroud color + pConsoleProps->wFillAttribute = ((5 << 4) | 6 ); + + + spdl->RemoveDataBlock(NT_CONSOLE_PROPS_SIG); + if (FAILED(hr = spdl->AddDataBlock((void *)pConsoleProps))) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error setting NT_CONSOLE_PROPS on shortcut file %s, hr=0x%x", szShortcutFile, hr); + goto exit; + } + + if (FAILED(hr = sppf->Save(NULL, TRUE))) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error saving changes to shortcut, hr=0x%x", hr); + goto exit; + } + + IISLogWrite ( SETUP_LOG_SEVERITY_INFORMATION, + L"Successfully added properties to shortcut %s", + szShortcutFile); + + } + } + + + if ( HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr ) + { + hr = S_OK; + } + +exit: + + if ( fCoInit ) + { + CoUninitialize(); + } + + IISLogClose(); + return (SUCCEEDED(hr)) ? ERROR_SUCCESS : ERROR_SUCCESS; +} \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/consoleprops.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/consoleprops.h new file mode 100644 index 0000000000..11692e14b3 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/consoleprops.h @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#pragma once + +UINT +WINAPI +ScheduleSetConsolePropertiesCA( + IN MSIHANDLE hInstall + ); + +UINT +WINAPI +ExecuteSetConsolePropertiesCA( + IN MSIHANDLE hInstall + ); \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/defaults.cpp b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/defaults.cpp new file mode 100644 index 0000000000..51a9831cf7 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/defaults.cpp @@ -0,0 +1,716 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#include "precomp.h" + + +HRESULT +SetElementMetadata( + IAppHostElement * pElement, + CONST WCHAR * szMetaType, + CONST VARIANT * pVarValue + ) +{ + HRESULT hr = NOERROR; + + BSTR bstrMetaType = SysAllocString( szMetaType ); + if( !bstrMetaType ) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR(hr); + goto exit; + } + + hr = pElement->SetMetadata( bstrMetaType, + *pVarValue ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + +exit: + + SysFreeString( bstrMetaType ); + + return hr; +} + +HRESULT +ProcessAttributes( + IAppHostElement * pElement, + IXmlReader * pReader + ) +{ + HRESULT hr = NOERROR; + + VARIANT varPropValue; + VariantInit( &varPropValue ); + + CONST WCHAR * pszName; + CONST WCHAR * pszValue; + + for( hr = pReader->MoveToFirstAttribute(); + ; + hr = pReader->MoveToNextAttribute() ) + { + if (hr == S_FALSE) + { + hr = S_OK; + break; + } + + if (FAILED(hr)) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pReader->GetLocalName( &pszName, NULL ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pReader->GetValue( &pszValue, NULL ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = VariantAssign( &varPropValue, pszValue ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = SetElementProperty( pElement, pszName, &varPropValue ); + + if( HRESULT_FROM_WIN32( ERROR_INVALID_INDEX ) == hr ) + { + // + // Possibly this is a metadata attribute not a property + // + + hr = SetElementMetadata( pElement, pszName, &varPropValue ); + } + + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + VariantClear( &varPropValue ); + } + +exit: + + VariantClear( &varPropValue ); + + return hr; +} + +HRESULT +ProcessSection( + IAppHostWritableAdminManager * pAdminMgr, + CONST WCHAR * szSectionName, + IXmlReader * pReader, + IAppHostElement * pParent, + BOOL fClearSection + ) +{ + HRESULT hr = NOERROR; + + CComPtr pChildElement; + CComPtr pParentElement = pParent; + + CONST WCHAR * pwszLocalName; + + BSTR bstrName = NULL; + BSTR bstrSectionName = NULL; + BSTR bstrRoot = NULL; + BSTR bstrAddElementName = NULL; + + BOOL isEmpty = FALSE; + + bstrSectionName = SysAllocString( szSectionName ); + bstrRoot = SysAllocString( L"MACHINE/WEBROOT/APPHOST" ); + + if( !bstrSectionName || !bstrRoot ) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR(hr); + goto exit; + } + + XmlNodeType nodeType; + + for (;;) + { + hr = pReader->Read(&nodeType); + + if (hr == S_FALSE) + { + hr = S_OK; + break; + } + + if (FAILED(hr)) + { + break; + } + + if( nodeType == XmlNodeType_Element ) + { + hr = pReader->GetLocalName( &pwszLocalName, NULL ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + SysFreeString( bstrName ); + bstrName = NULL; + + bstrName = SysAllocString( pwszLocalName ); + if( !bstrName ) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR(hr); + goto exit; + } + + isEmpty = pReader->IsEmptyElement(); + + if( !pParent ) + { + // + // This is the entry point to resetting the section. Begin by + // clearing. + // + + hr = pAdminMgr->GetAdminSection( bstrSectionName, + bstrRoot, + &pChildElement ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + if (fClearSection) + { + hr = pChildElement->Clear(); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + // Need to commit change after clear + + hr = pAdminMgr->CommitChanges(); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + // Need to reload after commit + + pChildElement.Release(); + + hr = pAdminMgr->GetAdminSection( bstrSectionName, + bstrRoot, + &pChildElement ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + } + + } + else + { + // Test the parent of this node for a collection + + CComPtr pCollection; + hr = pParentElement->get_Collection( &pCollection ); + + if ( SUCCEEDED ( hr ) && ( pCollection != NULL ) ) + { + // Get the schema for the collection + CComPtr pCollectionSchema; + hr = pCollection->get_Schema( &pCollectionSchema ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + SysFreeString( bstrAddElementName ); + bstrAddElementName = NULL; + + // Parent element has a collection. Get the addElement token. + pCollectionSchema->get_AddElementNames(&bstrAddElementName); + + if( 0 == wcscmp( pwszLocalName, bstrAddElementName ) ) + { + hr = pCollection->CreateNewElement( bstrName, &pChildElement ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = ProcessAttributes( pChildElement, pReader ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pCollection->AddElement( pChildElement ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + pCollection.Release(); + } + else + { + // Parent has collection, but this isn't an 'addElement' + hr = pParentElement->GetElementByName( bstrName, + &pChildElement ); + if( FAILED(hr) ) + { + DBGERROR(( DBG_CONTEXT, "Failed to get child element %S, %08x\n", bstrName, hr )); + goto exit; + } + } + + pCollectionSchema.Release(); + } + else + { + // Parent is not a collection. + hr = pParentElement->GetElementByName( bstrName, + &pChildElement ); + if( FAILED(hr) ) + { + DBGERROR(( DBG_CONTEXT, "Failed to get child element %S, %08x\n", bstrName, hr )); + goto exit; + } + } + } + + hr = ProcessAttributes( pChildElement, pReader ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + if( !isEmpty ) + { + hr = ProcessSection( pAdminMgr, + szSectionName, + pReader, + pChildElement, + fClearSection); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + } + + pChildElement.Release(); + } + else if( nodeType == XmlNodeType_EndElement ) + { + break; + } + } + +exit: + + SysFreeString( bstrAddElementName ); + SysFreeString( bstrName ); + SysFreeString( bstrSectionName ); + SysFreeString( bstrRoot ); + + return hr; +} + +HRESULT +ResetConfigSection( + IN IAppHostWritableAdminManager * pAdminMgr, + IN CONST WCHAR * szSectionName, + IN OUT IStream * pStreamDefaults + ) +{ + HRESULT hr = NOERROR; + + CComPtr pReader; + + + hr = CreateXmlReader(__uuidof(IXmlReader), (void**) &pReader, NULL); + if( FAILED(hr) ) + { + DBGERROR(( DBG_CONTEXT, "Error creating xml reader, error is %08.8lx", hr)); + goto exit; + } + + hr = pReader->SetProperty( XmlReaderProperty_DtdProcessing, + DtdProcessing_Prohibit ); + if( FAILED(hr) ) + { + DBGERROR(( DBG_CONTEXT, "Error setting XmlReaderProperty_DtdProcessing, %08x", hr)); + goto exit; + } + + hr = pReader->SetInput( pStreamDefaults ); + if( FAILED(hr) ) + { + DBGERROR(( DBG_CONTEXT, "Error setting input for reader, %08x", hr)); + goto exit; + } + + hr = ProcessSection( pAdminMgr, + szSectionName, + pReader, + NULL, + TRUE); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + +exit: + + return hr; +} + +HRESULT +CreateStreamFromTextResource( + IN HINSTANCE hInstance, + IN CONST WCHAR * szResourceName, + OUT IStream ** ppStream + ) +{ + HRESULT hr = NOERROR; + + HRSRC hResDefaults = NULL; + HGLOBAL hGlobDefaults = NULL; + LPCVOID pDefaults = NULL; + DWORD cbDefaults; + HGLOBAL hDefaultsData = NULL; + LPVOID pDefaultsData = NULL; + + hResDefaults = FindResourceW( g_hinst, + szResourceName, + L"TEXT" ); + if( !hResDefaults ) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + DBGERROR_HR(hr); + goto exit; + } + + hGlobDefaults = LoadResource( hInstance, hResDefaults ); + if( !hGlobDefaults ) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + DBGERROR_HR(hr); + goto exit; + } + + pDefaults = LockResource( hGlobDefaults ); + if( !pDefaults ) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + DBGERROR_HR(hr); + goto exit; + } + + cbDefaults = SizeofResource( g_hinst, hResDefaults ); + if( !cbDefaults ) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + DBGERROR_HR(hr); + goto exit; + } + + hDefaultsData = GlobalAlloc( GMEM_MOVEABLE, cbDefaults ); + if( !hDefaultsData ) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + DBGERROR_HR(hr); + goto exit; + } + + pDefaultsData = GlobalLock( hDefaultsData ); + if( !pDefaultsData ) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + DBGERROR_HR(hr); + goto exit; + } + + #pragma prefast( suppress:26010, "cbDefaults is allocated size for pDefaultsData" ) + CopyMemory( pDefaultsData, pDefaults, cbDefaults ); + + GlobalUnlock( hDefaultsData ); + + hr = CreateStreamOnHGlobal( hDefaultsData, TRUE, ppStream ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + hDefaultsData = NULL; + +exit: + + if( hDefaultsData ) + { + GlobalFree( hDefaultsData ); + } + + return hr; +} + + +HRESULT +ResetConfigSectionFromResource( + IN CONST WCHAR * szResourceName, + IN CONST WCHAR * szSectionName + ) +{ + HRESULT hr = NOERROR; + + CComPtr pAdminMgr; + CComPtr pStream; + + hr = CreateStreamFromTextResource( g_hinst, + szResourceName, + &pStream ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = CoCreateInstance( __uuidof( AppHostWritableAdminManager ), + NULL, + CLSCTX_INPROC_SERVER, + __uuidof( IAppHostWritableAdminManager ), + (VOID **)&pAdminMgr ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = ResetConfigSection( pAdminMgr, + szSectionName, + pStream ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + // + // Save + // + + hr = pAdminMgr->CommitChanges(); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + +exit: + + return ( hr ); +} + +HRESULT +ResetConfigSectionFromFile( + IN CONST WCHAR * szFileName, + IN CONST WCHAR * szSectionName + ) +{ + HRESULT hr = NOERROR; + + CComPtr pAdminMgr; + CComPtr pStream; + + hr = SHCreateStreamOnFileEx( szFileName, + STGM_READ, + FILE_ATTRIBUTE_NORMAL, + FALSE, + NULL, + &pStream); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = CoCreateInstance( __uuidof( AppHostWritableAdminManager ), + NULL, + CLSCTX_INPROC_SERVER, + __uuidof( IAppHostWritableAdminManager ), + (VOID **)&pAdminMgr ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = ResetConfigSection( pAdminMgr, + szSectionName, + pStream ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + // + // Save + // + + hr = pAdminMgr->CommitChanges(); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + +exit: + + return ( hr ); +} + +HRESULT +AppendConfigSectionFromFile( + IN CONST WCHAR * szFileName, + IN CONST WCHAR * szSectionName + ) +{ + HRESULT hr = NOERROR; + + CComPtr pAdminMgr; + CComPtr pStream; + + hr = SHCreateStreamOnFileEx( szFileName, + STGM_READ, + FILE_ATTRIBUTE_NORMAL, + FALSE, + NULL, + &pStream); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = CoCreateInstance( __uuidof( AppHostWritableAdminManager ), + NULL, + CLSCTX_INPROC_SERVER, + __uuidof( IAppHostWritableAdminManager ), + (VOID **)&pAdminMgr ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = AppendConfigSection( pAdminMgr, + szSectionName, + pStream ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + // + // Save + // + + hr = pAdminMgr->CommitChanges(); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + +exit: + + return ( hr ); +} + + +HRESULT +AppendConfigSection( + IN IAppHostWritableAdminManager * pAdminMgr, + IN CONST WCHAR * szSectionName, + IN OUT IStream * pStreamDefaults + ) +{ + HRESULT hr = NOERROR; + + CComPtr pReader; + + + hr = CreateXmlReader(__uuidof(IXmlReader), (void**) &pReader, NULL); + if( FAILED(hr) ) + { + DBGERROR(( DBG_CONTEXT, "Error creating xml reader, error is %08.8lx", hr)); + goto exit; + } + + hr = pReader->SetProperty( XmlReaderProperty_DtdProcessing, + DtdProcessing_Prohibit ); + if( FAILED(hr) ) + { + DBGERROR(( DBG_CONTEXT, "Error setting XmlReaderProperty_DtdProcessing, %08x", hr)); + goto exit; + } + + hr = pReader->SetInput( pStreamDefaults ); + if( FAILED(hr) ) + { + DBGERROR(( DBG_CONTEXT, "Error setting input for reader, %08x", hr)); + goto exit; + } + + hr = ProcessSection( pAdminMgr, + szSectionName, + pReader, + NULL, + FALSE); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + +exit: + + return hr; +} diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/defaults.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/defaults.h new file mode 100644 index 0000000000..491938dfc9 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/defaults.h @@ -0,0 +1,52 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#ifndef _DEFAULTS_H_ +#define _DEFAULTS_H_ + + +// +// Helper routines for setting-up default module config. +// + +HRESULT +CreateStreamFromTextResource( + IN HINSTANCE hInstance, + IN CONST WCHAR * szResourceName, + OUT IStream ** ppStream + ); + +HRESULT +ResetConfigSection( + IN IAppHostWritableAdminManager * pAdminMgr, + IN CONST WCHAR * szSectionName, + IN OUT IStream * pStreamDefaults + ); + +HRESULT +ResetConfigSectionFromResource( + IN CONST WCHAR * szResourceName, + IN CONST WCHAR * szSectionName + ); + +HRESULT +ResetConfigSectionFromFile( + IN CONST WCHAR * szFileName, + IN CONST WCHAR * szSectionName + ); + +HRESULT +AppendConfigSectionFromFile( + IN CONST WCHAR * szFileName, + IN CONST WCHAR * szSectionName + ); + +HRESULT +AppendConfigSection( + IN IAppHostWritableAdminManager * pAdminMgr, + IN CONST WCHAR * szSectionName, + IN OUT IStream * pStreamDefaults + ); + +#endif + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/elevatedsc.cpp b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/elevatedsc.cpp new file mode 100644 index 0000000000..bc9abda798 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/elevatedsc.cpp @@ -0,0 +1,346 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#include "precomp.h" + +UINT +WINAPI +ScheduleMakeShortcutElevatedCA( + IN MSIHANDLE hInstall + ) +{ + HRESULT hr = S_OK; + UINT status = ERROR_SUCCESS; + + MSIHANDLE hDatabase = NULL; + MSIHANDLE hView = NULL; + MSIHANDLE hRecord = NULL; + + STACK_STRU( strShortcut, 128 ); + STACK_STRU( strDirectoryId, 256 ); // Directory Identifier + STACK_STRU( strDirectoryName, 256 ); + STACK_STRU( strComponent, 128 ); + STACK_STRU( strShortcutName, 256 ); + STACK_STRU( strData, 256); + + + CONST WCHAR * szQuery = + L"SELECT " + L"`IISElevatedShortcut`.`Shortcut_`, " + L"`Shortcut`.`Component_`, " + L"`Shortcut`.`Name`, " + L"`Directory`.`Directory` " + L"FROM `IISElevatedShortcut`, `Shortcut`, `Directory` " + L"WHERE `IISElevatedShortcut`.`Shortcut_`=`Shortcut`.`Shortcut` " + L"AND `Shortcut`.`Directory_`=`Directory`.`Directory`"; + + + CA_DATA_WRITER cadata; + INSTALLSTATE installStateCurrent; + INSTALLSTATE installStateAction; + + BOOL scheduleDefferedCA = FALSE; + + enum { + CA_ELEVATESC_SHORTCUT = 1, + CA_ELEVATESC_COMPONENT, + CA_ELEVATESC_SHORTCUTNAME, + CA_ELEVATESC_DIRECTORY, + }; + + IISLogInitialize(hInstall, UNITEXT(__FUNCTION__)); + + hDatabase = MsiGetActiveDatabase( hInstall ); + if ( !hDatabase ) + { + hr = E_UNEXPECTED; + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error getting MSI database, hr=0x%x", hr); + DBGERROR_HR(hr); + goto exit; + } + + status = MsiDatabaseOpenViewW( hDatabase, szQuery, &hView ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error opening View, hr=0x%x", hr); + DBGERROR_HR(hr); + goto exit; + } + + status = MsiViewExecute( hView, NULL ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error executing view, hr=0x%x", hr); + DBGERROR_HR(hr); + goto exit; + } + + while ( ERROR_SUCCESS == MsiViewFetch( hView, &hRecord ) ) + { + hr = MsiUtilRecordGetString( hRecord, + CA_ELEVATESC_COMPONENT, + &strComponent ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error getting column %d from record, hr=0x%x", CA_ELEVATESC_COMPONENT, hr); + goto exit; + } + + status = MsiGetComponentStateW( hInstall, + strComponent.QueryStr(), + &installStateCurrent, + &installStateAction ); + + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32(status); + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error getting state for component %s, hr=0x%x", strComponent.QueryStr(), hr); + goto exit; + } + + // Only run if the comonent is installing or reinstalling + if ( MsiUtilIsInstalling( installStateCurrent, installStateAction ) || + MsiUtilIsReInstalling( installStateCurrent, installStateAction ) ) + { + // GET: directory where shortcut is + // Get the directory id for the shortcut + hr = MsiUtilRecordGetString( hRecord, + CA_ELEVATESC_DIRECTORY, + &strDirectoryId ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error getting column %d from record, hr=0x%x", CA_ELEVATESC_DIRECTORY, hr); + goto exit; + } + + // Get directory path + hr = MsiUtilGetProperty(hInstall, strDirectoryId.QueryStr(), &strDirectoryName ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error getting value for directory record %s, hr=0x%x", strDirectoryId.QueryStr(), hr); + goto exit; + } + + IISLogWrite ( SETUP_LOG_SEVERITY_INFORMATION, + L"Shortcut Directory: '%s'.", + strDirectoryName.QueryStr()); + // ENDGET: directory where shortcut is + + + // GET: Short and Long names of shortcuts + hr = MsiUtilRecordGetString( hRecord, + CA_ELEVATESC_SHORTCUTNAME, + &strShortcutName ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error getting column %d from record, hr=0x%x", CA_ELEVATESC_SHORTCUTNAME, hr); + goto exit; + } + + // strShortcutName contains the short and long file names of the shortcut + + PCWSTR pszPrevious = strShortcutName.QueryStr(); + // Append the shortcut name to the directory and write to cadata + // Write the short and long shortcut paths + for ( DWORD i = 0; i < strShortcutName.QueryCCH() + 1; i++ ) + { + if ( strShortcutName.QueryStr()[ i ] == L'|' || + strShortcutName.QueryStr()[ i ] == L'\0' ) + { + strShortcutName.QueryStr()[ i ] = L'\0'; + + strData.Copy( strDirectoryName ); + strData.Append(L"\\"); + strData.Append(pszPrevious); + strData.Append(L".lnk"); + + IISLogWrite ( SETUP_LOG_SEVERITY_INFORMATION, + L"Potential shortcut path: %s", + strData.QueryStr()); + + hr = cadata.Write( strData.QueryStr(), strData.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error writing custom action data, hr=0x%x", hr); + goto exit; + } + + pszPrevious = strShortcutName.QueryStr() + i + 1; + + // Only schedule custom action if needed + scheduleDefferedCA = TRUE; + } + } + + // ENDGET: Short and Long names of shortcuts + } + + if ( hRecord ) + { + MsiCloseHandle( hRecord ); + hRecord = NULL; + } + + } + + if ( scheduleDefferedCA ) + { + hr = MsiUtilScheduleDeferredAction( hInstall, + L"ExecuteMakeShortcutElevated", + cadata.QueryData() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error scheduling custom action, hr=0x%x", hr); + goto exit; + } + + IISLogWrite ( SETUP_LOG_SEVERITY_INFORMATION, + L"Custom action ExecuteMakeShortcutElevated scheduled"); + } + +exit: + + if ( hRecord ) + { + MsiCloseHandle( hRecord ); + hRecord = NULL; + } + + if ( hView ) + { + MsiCloseHandle( hView ); + hView = NULL; + } + + if ( hDatabase ) + { + MsiCloseHandle( hDatabase ); + hDatabase = NULL; + } + + IISLogClose(); + + return (SUCCEEDED(hr)) ? ERROR_SUCCESS : ERROR_SUCCESS; +} + +UINT +WINAPI +ExecuteMakeShortcutElevatedCA( + IN MSIHANDLE hInstall + ) +{ + HRESULT hr = S_OK; + + BOOL fCoInit = FALSE; + + WCHAR * szShortcutFile = NULL; + + CA_DATA_READER cadata; + + IISLogInitialize(hInstall, UNITEXT(__FUNCTION__)); + + // + // Retrieve parameters from ca data + // + + hr = cadata.LoadDeferredCAData( hInstall ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error retrieving custom action data, hr=0x%x", hr); + goto exit; + } + + if ( SUCCEEDED( hr = CoInitialize(NULL) ) ) + { + fCoInit = TRUE; + } + + while ( SUCCEEDED(hr = cadata.Read( &szShortcutFile )) ) + { + if(GetFileAttributes(szShortcutFile) != 0xFFFFFFFF) + { + IISLogWrite ( SETUP_LOG_SEVERITY_INFORMATION, + L"Shortcut %s exists", szShortcutFile); + + // Get shell + CComPtr sppf; + + if (FAILED(hr = sppf.CoCreateInstance(L"lnkfile")) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error get ShellLink com object, hr=0x%x", hr); + goto exit; + } + + // Load shortcut file + if (FAILED(hr = sppf->Load(szShortcutFile, STGM_READWRITE))) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error loading shortcut file %s, hr=0x%x", szShortcutFile, hr); + goto exit; + } + + CComQIPtr spdl(sppf); + if (!spdl) + { + DBGERROR_HR(hr); + goto exit; + } + + DWORD dwFlags; + if (FAILED(hr = spdl->GetFlags(&dwFlags))) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error getting shortcut flags, hr=0x%x", hr); + goto exit; + } + + // Add "run as ..." flag + dwFlags |= SLDF_RUNAS_USER; + if (FAILED(hr = spdl->SetFlags(dwFlags))) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error setting SLDF_RUNAS_USER flag, hr=0x%x", hr); + goto exit; + } + + // Save file. + if (FAILED(hr = sppf->Save(NULL, TRUE))) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error saving changes to shortcut, hr=0x%x", hr); + goto exit; + } + + IISLogWrite ( SETUP_LOG_SEVERITY_INFORMATION, + L"Successfully added SLDF_RUNAS_USER flag to shortcut %s", + szShortcutFile); + + } + } + + if ( HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr ) + { + hr = S_OK; + } + +exit: + + if ( fCoInit ) + { + CoUninitialize(); + } + + IISLogClose(); + return (SUCCEEDED(hr)) ? ERROR_SUCCESS : ERROR_SUCCESS; +} \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/elevatedsc.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/elevatedsc.h new file mode 100644 index 0000000000..c5f5428510 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/elevatedsc.h @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#pragma once + +UINT +WINAPI +ScheduleMakeShortcutElevatedCA( + IN MSIHANDLE hInstall + ); + +UINT +WINAPI +ExecuteMakeShortcutElevatedCA( + IN MSIHANDLE hInstall + ); \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/handlers.cpp b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/handlers.cpp new file mode 100644 index 0000000000..1e824ae72e --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/handlers.cpp @@ -0,0 +1,472 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#include "precomp.h" + +// +// Local function declarations +// + +// +// Public functions +// + +HRESULT +RegisterHandler( + IN IAppHostAdminManager * pAdminMgr, + IN CONST WCHAR * szConfigPath, + IN ULONG Index, + IN CONST WCHAR * szName, + IN CONST WCHAR * szPath, + IN CONST WCHAR * szVerbs, + IN OPTIONAL CONST WCHAR * szType, + IN OPTIONAL CONST WCHAR * szModules, + IN OPTIONAL CONST WCHAR * szScriptProcessor, + IN OPTIONAL CONST WCHAR * szResourceType, + IN OPTIONAL CONST WCHAR * szRequiredAccess, + IN OPTIONAL CONST WCHAR * szPreCondition + ) +{ + HRESULT hr; + CComPtr pHandlersCollection; + CComPtr pNewElement; + UINT numDeleted; + BSTR bstrAdd; + + bstrAdd = SysAllocString(L"add"); + + if (bstrAdd == NULL) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR(hr); + goto exit; + } + + hr = GetHandlersCollection( + pAdminMgr, + szConfigPath, + &pHandlersCollection + ); + + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + // + // Just in case... delete if it's already there. + // + + hr = DeleteAllElementsFromCollection( + pHandlersCollection, + L"name", + szName, + FIND_ELEMENT_CASE_SENSITIVE, + &numDeleted + ); + + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + if (Index == HANDLER_INDEX_BEFORE_STATICFILE) + { + // + // If the StaticFile handler is installed (and it probably is) + // then install just before it. + // + + hr = FindHandlerByName( + pAdminMgr, + szConfigPath, + HANDLER_STATICFILE_NAME, + &Index + ); + + if (FAILED(hr)) + { + DBGERROR_HR(hr); + goto exit; + } + + if (hr == S_FALSE) + { + // + // Not found. Install at end of list. + // + + Index = HANDLER_INDEX_LAST; + } + } + + // + // If the caller wants this to be the last handler, then + // chase down the current entry count. + // + + if (Index == HANDLER_INDEX_LAST) + { + hr = pHandlersCollection->get_Count(&Index); + + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + } + + hr = pHandlersCollection->CreateNewElement(bstrAdd, &pNewElement); + + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + // + // Required properties. + // + + hr = SetElementStringProperty( + pNewElement, + L"name", + szName + ); + + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = SetElementStringProperty( + pNewElement, + L"path", + szPath + ); + + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = SetElementStringProperty( + pNewElement, + L"verb", + szVerbs + ); + + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + // + // Optional properties. + // + + if (szType != NULL && szType[0] != L'\0') + { + hr = SetElementStringProperty( + pNewElement, + L"type", + szType + ); + + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + } + + if (szModules != NULL && szModules[0] != L'\0') + { + hr = SetElementStringProperty( + pNewElement, + L"modules", + szModules + ); + + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + } + + if (szScriptProcessor != NULL && szScriptProcessor[0] != L'\0') + { + hr = SetElementStringProperty( + pNewElement, + L"scriptProcessor", + szScriptProcessor + ); + + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + } + + if (szResourceType != NULL && szResourceType[0] != L'\0') + { + hr = SetElementStringProperty( + pNewElement, + L"resourceType", + szResourceType + ); + + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + } + + if (szRequiredAccess != NULL && szRequiredAccess[0] != L'\0') + { + hr = SetElementStringProperty( + pNewElement, + L"requireAccess", + szRequiredAccess + ); + + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + } + + if (szPreCondition != NULL && szPreCondition[0] != L'\0') + { + hr = SetElementStringProperty( + pNewElement, + L"preCondition", + szPreCondition + ); + + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + } + + hr = pHandlersCollection->AddElement(pNewElement, Index); + + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + +exit: + + SysFreeString(bstrAdd); + return hr; +} + +HRESULT +UnRegisterHandler( + IN IAppHostAdminManager * pAdminMgr, + IN CONST WCHAR * szConfigPath, + IN CONST WCHAR * szName + ) +{ + HRESULT hr; + CComPtr pHandlersCollection; + CComPtr pLocationCollection; + CComPtr pLocation; + CComPtr pElement; + ENUM_INDEX locationIndex; + BOOL found; + UINT numDeleted; + + // + // Enum the tags, look for any sections, + // and if found, remove the specified handler from each. + // + + hr = GetLocationCollection( + pAdminMgr, + szConfigPath, + &pLocationCollection + ); + + if (FAILED(hr)) + { + DBGERROR_HR(hr); + goto exit; + } + + for (hr = FindFirstLocation(pLocationCollection, &locationIndex, &pLocation) ; + SUCCEEDED(hr) ; + hr = FindNextLocation(pLocationCollection, &locationIndex, &pLocation)) + { + if (hr == S_FALSE) + { + hr = S_OK; + break; + } + + hr = GetSectionFromLocation( + pLocation, + L"system.webServer/handlers", + &pElement, + &found + ); + + if (SUCCEEDED(hr)) + { + if (found) + { + hr = pElement->get_Collection(&pHandlersCollection); + + if (SUCCEEDED(hr)) + { + hr = DeleteAllElementsFromCollection( + pHandlersCollection, + L"name", + szName, + FIND_ELEMENT_CASE_SENSITIVE, + &numDeleted + ); + + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + } + + pHandlersCollection.Release(); + } + else + { + DBGERROR_HR(hr); + } + + pElement.Release(); + } + } + else + { + DBGERROR_HR(hr); + } + + pLocation.Release(); + } + + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + +exit: + + return hr; +} + +HRESULT +FindHandlerByName( + IN IAppHostAdminManager * pAdminMgr, + IN CONST WCHAR * szConfigPath, + IN CONST WCHAR * szName, + OUT ULONG * pIndex + ) +{ + HRESULT hr; + CComPtr pHandlersCollection; + + *pIndex = 0; + + hr = GetHandlersCollection( + pAdminMgr, + szConfigPath, + &pHandlersCollection + ); + + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = FindElementInCollection( + pHandlersCollection, + L"name", + szName, + FIND_ELEMENT_CASE_SENSITIVE, + pIndex + ); + + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + +exit: + + return hr; +} + +HRESULT +GetHandlersCollection( + IN IAppHostAdminManager * pAdminMgr, + IN CONST WCHAR * szConfigPath, + OUT IAppHostElementCollection ** pHandlersCollection + ) +{ + HRESULT hr; + CComPtr pHandlersElement; + BSTR bstrConfigPath; + BSTR bstrHandlersSectionName; + + bstrConfigPath = SysAllocString(szConfigPath); + bstrHandlersSectionName = SysAllocString(L"system.webServer/handlers"); + *pHandlersCollection = NULL; + + if (bstrConfigPath == NULL || bstrHandlersSectionName == NULL) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR(hr); + goto exit; + } + + // + // Chase down the handlers collection. + // + + hr = pAdminMgr->GetAdminSection( bstrHandlersSectionName, + bstrConfigPath, + &pHandlersElement ); + + if (FAILED(hr)) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pHandlersElement->get_Collection(pHandlersCollection); + + if (FAILED(hr)) + { + DBGERROR_HR(hr); + goto exit; + } + +exit: + + SysFreeString(bstrHandlersSectionName); + SysFreeString(bstrConfigPath); + return hr; +} + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/handlers.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/handlers.h new file mode 100644 index 0000000000..3024acf8fd --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/handlers.h @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#ifndef _HANDLERS_H_ +#define _HANDLERS_H_ + + +#define HANDLER_INDEX_FIRST 0 +#define HANDLER_INDEX_LAST ((ULONG)(-1L)) +#define HANDLER_INDEX_BEFORE_STATICFILE ((ULONG)(-2L)) + +#define HANDLER_STATICFILE_NAME L"StaticFile" + +HRESULT +RegisterHandler( + IN IAppHostAdminManager * pAdminMgr, + IN CONST WCHAR * szConfigPath, + IN ULONG Index, + IN CONST WCHAR * szName, + IN CONST WCHAR * szPath, + IN CONST WCHAR * szVerbs, + IN OPTIONAL CONST WCHAR * szType, + IN OPTIONAL CONST WCHAR * szModules, + IN OPTIONAL CONST WCHAR * szScriptProcessor, + IN OPTIONAL CONST WCHAR * szResourceType, + IN OPTIONAL CONST WCHAR * szRequiredAccess, + IN OPTIONAL CONST WCHAR * szPreCondition = NULL + ); + +HRESULT +UnRegisterHandler( + IN IAppHostAdminManager * pAdminMgr, + IN CONST WCHAR * szConfigPath, + IN CONST WCHAR * szName + ); + +HRESULT +FindHandlerByName( + IN IAppHostAdminManager * pAdminMgr, + IN CONST WCHAR * szConfigPath, + IN CONST WCHAR * szName, + OUT ULONG * pIndex + ); + +HRESULT +GetHandlersCollection( + IN IAppHostAdminManager * pAdminMgr, + IN CONST WCHAR * szConfigPath, + OUT IAppHostElementCollection ** pHandlersCollection + ); + + +#endif + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/hotfix.cpp b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/hotfix.cpp new file mode 100644 index 0000000000..a800948b13 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/hotfix.cpp @@ -0,0 +1,766 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#include "precomp.h" +#include "wuerror.h" + +#define REBOOT_REQUIRED_REGKEY L"Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce" +#define REBOOT_REGVALUE L"IIS Extensions Reboot Required" + +HRESULT ExecuteCommandLine( + IN PCWSTR szCommandLine, + IN DWORD dwTimeout, + __out LPDWORD pExitCode + + ) +{ + HRESULT hr = NOERROR; + UINT status = 0; + PROCESS_INFORMATION oProcInfo = {0}; + STARTUPINFOW oStartInfo = {0}; + DWORD dwExitCode = ERROR_SUCCESS; + STACK_STRU( strModifiableCommandLine, MAX_PATH); + + oStartInfo.cb = sizeof ( STARTUPINFOW ); + oProcInfo.hThread = INVALID_HANDLE_VALUE; + oProcInfo.hProcess = INVALID_HANDLE_VALUE; + + _ASSERTE ( szCommandLine ); + _ASSERTE ( pExitCode ); + + hr = strModifiableCommandLine.Copy ( szCommandLine ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error copying command line, hr=0x%x", hr); + goto exit; + } + + IISLogWrite(SETUP_LOG_SEVERITY_INFORMATION, L"Launching process with command line %s", strModifiableCommandLine.QueryStr()); + + status = CreateProcessW(NULL, + strModifiableCommandLine.QueryStr(), // command line + NULL, // security info + NULL, // thread info + TRUE, // inherit handles + GetPriorityClass(GetCurrentProcess()), // creation flags + NULL, // environment + NULL, // cur dir + &oStartInfo, + &oProcInfo); + + if ( 0 == status ) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error creating process, hr=0x%x", hr); + goto exit; + } + + status = WaitForSingleObject( oProcInfo.hProcess, dwTimeout ); + if ( status == WAIT_FAILED ) + { + IISLogWrite(SETUP_LOG_SEVERITY_WARNING, L"Process wait failed, hr=0x%x", HRESULT_FROM_WIN32 ( GetLastError() ) ); + // but we can still continue + } + + status = GetExitCodeProcess ( oProcInfo.hProcess, &dwExitCode ); + if ( 0 == status ) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error getting exit code for process, hr=0x%x", hr); + goto exit; + } + + IISLogWrite(SETUP_LOG_SEVERITY_INFORMATION, L"Process returned with exit code %d", dwExitCode); + *pExitCode = dwExitCode; + +exit: + if ( INVALID_HANDLE_VALUE != oProcInfo.hThread ) + { + CloseHandle ( oProcInfo.hThread ); + oProcInfo.hThread = INVALID_HANDLE_VALUE; + } + + if ( INVALID_HANDLE_VALUE != oProcInfo.hProcess ) + { + CloseHandle ( oProcInfo.hProcess ); + oProcInfo.hProcess = INVALID_HANDLE_VALUE; + } + + if ( FAILED(hr) ) + { + IISLogWrite(SETUP_LOG_SEVERITY_INFORMATION, L"Error in function %s, hr=0x%x", UNITEXT(__FUNCTION__), hr); + } + + return hr; +} + + +HRESULT +InstallWindowsHotfixQuietly( + IN PCWSTR szHotFixPath, + __out BOOL * pbRebootRequired +) +{ + HRESULT hr = NOERROR; + UINT status = 0; + STACK_STRU( strCommandLine, MAX_PATH); + DWORD cch = 0; + DWORD exitCode = 0; + + _ASSERTE(szHotFixPath); + _ASSERTE(pbRebootRequired); + + *pbRebootRequired = FALSE; + cch = strCommandLine.QuerySizeCCH(); + + status = GetSystemDirectoryW(strCommandLine.QueryStr(), cch); + if ( status > cch) + { + cch = status; + hr = strCommandLine.Resize( ++cch ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error resizing buffer, hr=0x%x", hr); + goto exit; + } + + status = GetSystemDirectoryW(strCommandLine.QueryStr(), cch); + } + + if ( 0 == status ) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error getting system folder path, hr=0x%x", hr); + goto exit; + } + + strCommandLine.SyncWithBuffer(); + + hr = strCommandLine.Append(L"\\wusa.exe /quiet /norestart \""); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error apppending wusa, hr=0x%x", hr); + goto exit; + } + + hr = strCommandLine.Append(szHotFixPath); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error apppending hotfixpath, hr=0x%x", hr); + goto exit; + } + + hr = strCommandLine.Append(L"\""); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error apppending end quote, hr=0x%x", hr); + goto exit; + } + + hr = ExecuteCommandLine ( strCommandLine.QueryStr(), INFINITE, &exitCode); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error running the hotfix installer, hr=0x%x", hr); + goto exit; + } + + // + // handle return codes based on WinSE team info regarding WUSA.exe + // + switch ( exitCode ) + { + case ERROR_SUCCESS: + // install succeeded, continue. + hr = S_OK; + break; + case ERROR_SUCCESS_REBOOT_INITIATED: + case ERROR_SUCCESS_REBOOT_REQUIRED: + case WU_S_REBOOT_REQUIRED: + *pbRebootRequired = TRUE; + hr = S_OK; + break; + case WU_S_ALREADY_INSTALLED: + // WUSA.exe can return the above codes if this DWORD registry value is set: + // HKLM\Software\Microsoft\Windows\CurrentVersion\WUSA\ExtendedReturnCode + hr = S_OK; + break; + case S_FALSE: + // WUSA.exe returns this when the MSU is already installed, or when its not applicable, continue. + hr = S_OK; + break; + + // + // need cases to handle new WU_S_ALREADY_INSTALLED and WU_E_NOT_APPLICABLE error codes + // + + default: + // the installation failed, abort + hr = HRESULT_FROM_WIN32 ( ERROR_INSTALL_FAILURE ); + goto exit; + } + +exit: + if ( FAILED(hr) ) + { + IISLogWrite(SETUP_LOG_SEVERITY_INFORMATION, L"Error in function %s, hr=0x%x", UNITEXT(__FUNCTION__), hr); + } + + return hr; +} +UINT +__stdcall +ExecuteCleanUpWindowsHotfixCA( + IN MSIHANDLE hInstall +) +{ + HRESULT hr = NOERROR; + UINT status = 0; + CA_DATA_READER cadata; + WCHAR * szHotFixName = NULL; + + IISLogInitialize(hInstall, UNITEXT(__FUNCTION__)); + + hr = cadata.LoadDeferredCAData( hInstall ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error retrieving custom action data, hr=0x%x", hr); + goto exit; + } + + while ( SUCCEEDED(hr = cadata.Read( &szHotFixName )) ) + { + status = 0; + status = DeleteFileW( szHotFixName ); + + if( FAILED(status) ) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_INFORMATION, L"Error deleting hotfix temp file '%s', hr=0x%x", szHotFixName, hr); + //eat this error and try and delete other temp files + hr = NOERROR; + } + else + { + IISLogWrite(SETUP_LOG_SEVERITY_INFORMATION, L"Success deleting hotfix temp file '%s'", szHotFixName ); + } + } + if ( HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr ) + { + hr = S_OK; + } + +exit: + if ( FAILED(hr) ) + { + IISLogWrite(SETUP_LOG_SEVERITY_INFORMATION, L"Error in function %s, hr=0x%x", UNITEXT(__FUNCTION__), hr); + } + + IISLogClose(); + //do not fail commit or rollback transaction for this + return ERROR_SUCCESS; +} + +UINT +__stdcall +ScheduleInstallWindowsHotfixCA( + IN MSIHANDLE hInstall +) +{ + HRESULT hr = NOERROR; + UINT status = ERROR_SUCCESS; + + OSVERSIONINFOEXW osVersionInfo = {0}; + + PMSIHANDLE hDatabase; + PMSIHANDLE hView; + PMSIHANDLE hRecord; + BOOL bDeferredRequired = FALSE; + + CA_DATA_WRITER cadata; + + CONST WCHAR * szQuery = + L"SELECT " + L"`IISWindowsHotfix`.`Name`, " + L"`IISWindowsHotfix`.`OSMajorVersion`, " + L"`IISWindowsHotfix`.`OSMinorVersion`, " + L"`IISWindowsHotfix`.`SPMajorVersion`, " + L"`IISWindowsHotfix`.`Condition`, " + L"`Binary`.`Data` " + L"FROM `IISWindowsHotfix`, `Binary` " + L"WHERE `IISWindowsHotfix`.`BinaryName_`=`Binary`.`Name`"; + + enum { CA_HOTFIX_NAME = 1, + CA_HOTFIX_OSMAJORVERSION, + CA_HOTFIX_OSMINORVERSION, + CA_HOTFIX_SPMAJORVERSION, + CA_HOTFIX_CONDITION, + CA_HOTFIX_BINARYDATA + }; + + IISLogInitialize(hInstall, UNITEXT(__FUNCTION__)); + + osVersionInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFOEXW ); +#pragma warning( push ) +#pragma warning( disable : 4996) + status = GetVersionEx( (LPOSVERSIONINFOW) &osVersionInfo ); +#pragma warning( pop ) + + if ( !status ) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error getting Windows version, hr=0x%x", hr); + DBGERROR_HR(hr); + goto exit; + } + + hDatabase = MsiGetActiveDatabase( hInstall ); + if ( !hDatabase ) + { + hr = E_UNEXPECTED; + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error getting MSI database, hr=0x%x", hr); + DBGERROR_HR(hr); + goto exit; + } + + status = MsiDatabaseOpenViewW( hDatabase, szQuery, &hView ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error opening View, hr=0x%x", hr); + DBGERROR_HR(hr); + goto exit; + } + + status = MsiViewExecute( hView, NULL ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error executing view, hr=0x%x", hr); + DBGERROR_HR(hr); + goto exit; + } + + while ( ERROR_SUCCESS == MsiViewFetch( hView, &hRecord ) ) + { + UINT dwTargetOSMajorVersion = 0; + UINT dwTargetOSMinorVersion = 0; + UINT dwTargetSPMajorVersion = 0; + STACK_STRU( strHotFixName, 128 ); + BOOL isApplicable = TRUE; // Applicable by default + + hr = MsiUtilRecordGetString( hRecord, + CA_HOTFIX_NAME, + &strHotFixName ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error getting column %d from record, hr=0x%x", CA_HOTFIX_NAME, hr); + goto exit; + } + + IISLogWrite ( SETUP_LOG_SEVERITY_INFORMATION, + L"Checking applicability of Hotfix '%s'.", + strHotFixName.QueryStr()); + + hr = MsiUtilRecordGetInteger( hRecord, + CA_HOTFIX_OSMAJORVERSION, + &dwTargetOSMajorVersion); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_INFORMATION, L"No OS Major Version available.", CA_HOTFIX_OSMAJORVERSION, hr); + // This column may be NULL + hr = S_FALSE; + } + + hr = MsiUtilRecordGetInteger( hRecord, + CA_HOTFIX_OSMINORVERSION, + &dwTargetOSMinorVersion); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_INFORMATION, L"No OS Minor Version available."); + // This column may be NULL + hr = S_FALSE; + } + + hr = MsiUtilRecordGetInteger( hRecord, + CA_HOTFIX_SPMAJORVERSION, + &dwTargetSPMajorVersion); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_INFORMATION, L"No OS SP Major Version available."); + // This column may be NULL + hr = S_FALSE; + } + + if ( hr == S_FALSE ) + { + // No OS Version information available + hr = S_OK; + } + else + { + IISLogWrite ( SETUP_LOG_SEVERITY_INFORMATION, + L"OS Version: Actual '%d.%d'. Hotfix Target '%d.%d'.", + osVersionInfo.dwMajorVersion, + osVersionInfo.dwMinorVersion, + dwTargetOSMajorVersion, + dwTargetOSMinorVersion); + + IISLogWrite ( SETUP_LOG_SEVERITY_INFORMATION, + L"OS Service Pack Level: Actual '%d'. Hotfix Target '%d'.", + osVersionInfo.wServicePackMajor, + dwTargetSPMajorVersion); + + if ( osVersionInfo.dwMajorVersion != dwTargetOSMajorVersion || + osVersionInfo.dwMinorVersion != dwTargetOSMinorVersion) + { + IISLogWrite(SETUP_LOG_SEVERITY_INFORMATION, L"OS Version Mismatch! Will not apply the hotfix."); + isApplicable = FALSE; + } + else if(osVersionInfo.wServicePackMajor != dwTargetSPMajorVersion) + { + IISLogWrite(SETUP_LOG_SEVERITY_INFORMATION, L"OS SP Level Mismatch! Will not apply the hotfix."); + isApplicable = FALSE; + } + else + { + IISLogWrite(SETUP_LOG_SEVERITY_INFORMATION, L"OS Versions match! Will try to apply the hotfix."); + isApplicable = TRUE; + } + } + + if ( isApplicable ) + { + STACK_STRU( strCondition, 128 ); + MSICONDITION Condition; + + hr = MsiUtilRecordGetString( hRecord, + CA_HOTFIX_CONDITION, + &strCondition ); + if ( FAILED(hr) ) + { + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, + L"Error gettting column %d from record, hr=0x%x", + CA_HOTFIX_CONDITION, + hr); + goto exit; + } + + Condition = MsiEvaluateCondition( hInstall, strCondition.QueryStr() ); + + switch( Condition ) + { + case MSICONDITION_ERROR: + hr = E_UNEXPECTED; + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, + L"Cannot evaluate hotfix install condition \"%s\", hr=0x%x", + strCondition.QueryStr(), + hr ); + goto exit; + + case MSICONDITION_FALSE: + IISLogWrite(SETUP_LOG_SEVERITY_INFORMATION, L"Condition evaluation returned false! Will not apply the hotfix."); + isApplicable = FALSE; + break; + + case MSICONDITION_TRUE: + IISLogWrite(SETUP_LOG_SEVERITY_INFORMATION, L"Condition evaluation returned true! Will try to apply the hotfix."); + isApplicable = TRUE; + break; + + case MSICONDITION_NONE: + + IISLogWrite(SETUP_LOG_SEVERITY_INFORMATION, L"No condition available to evaluate."); + + break; + } + } + + if ( isApplicable ) + { + //apply the hotfix + STACK_STRU( hotFixFilePath, MAX_PATH * 2 ); + + hr = GenerateTempFileName ( strHotFixName.QueryStr(), + L"msu", + &hotFixFilePath); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error generating temp file name for the hotfix, hr=0x%x", hr); + goto exit; + } + + hr = MsiUtilRecordReadStreamIntoFile ( hRecord, + CA_HOTFIX_BINARYDATA, + hotFixFilePath.QueryStr()); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error streaming binary data into file, hr=0x%x", hr); + goto exit; + } + else + { + IISLogWrite(SETUP_LOG_SEVERITY_INFORMATION, L"Streamed hotfix '%s' into file '%s'.", strHotFixName.QueryStr(), hotFixFilePath.QueryStr()); + } + + bDeferredRequired = TRUE; + hr = cadata.Write( hotFixFilePath.QueryStr(), hotFixFilePath.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error writing custom action data, hr=0x%x", hr); + goto exit; + } + } + + if ( hRecord ) + { + MsiCloseHandle( hRecord ); + hRecord = NULL; + } + } + + if( bDeferredRequired ) + { + //schedule CA to install the msu files + hr = MsiUtilScheduleDeferredAction( hInstall, + L"ExecuteInstallWindowsHotfix", + cadata.QueryData() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error scheduling custom action ExecuteInstallWindowsHotfix, hr=0x%x", hr); + goto exit; + } + + IISLogWrite ( SETUP_LOG_SEVERITY_INFORMATION, + L"Custom action ExecuteInstallWindowsHotfix scheduled"); + + + //schedule CA to delete the msu files if rollback transaction initiated + hr = MsiUtilScheduleDeferredAction( hInstall, + L"RollbackCleanUpWindowsHotfix", + cadata.QueryData() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error scheduling custom action RollbackCleanUpWindowsHotfix, hr=0x%x", hr); + goto exit; + } + + IISLogWrite ( SETUP_LOG_SEVERITY_INFORMATION, + L"Custom action RollbackCleanUpWindowsHotfix scheduled"); + + //schedule CA to delete the msu files if commit transaction initiated + hr = MsiUtilScheduleDeferredAction( hInstall, + L"CommitCleanUpWindowsHotfix", + cadata.QueryData() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error scheduling custom action CommitCleanUpWindowsHotfix, hr=0x%x", hr); + goto exit; + } + + IISLogWrite ( SETUP_LOG_SEVERITY_INFORMATION, + L"Custom action CommitCleanUpWindowsHotfix scheduled"); + + } + +exit: + if ( FAILED(hr) ) + { + IISLogWrite(SETUP_LOG_SEVERITY_INFORMATION, L"Error in function %s, hr=0x%x", UNITEXT(__FUNCTION__), hr); + } + + IISLogClose(); + + return (SUCCEEDED(hr)) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; +} + + +UINT +__stdcall +ExecuteInstallWindowsHotfixCA( + IN MSIHANDLE hInstall +) +{ + HRESULT hr = NOERROR; + CA_DATA_READER cadata; + WCHAR * szHotFixName = NULL; + BOOL rebootRequired = FALSE; + HKEY regKey = NULL; + LONG status = ERROR_SUCCESS; + + IISLogInitialize(hInstall, UNITEXT(__FUNCTION__)); + + hr = cadata.LoadDeferredCAData( hInstall ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error retrieving custom action data, hr=0x%x", hr); + goto exit; + } + + while ( SUCCEEDED(hr = cadata.Read( &szHotFixName )) ) + { + BOOL requiresReboot = FALSE; + hr = InstallWindowsHotfixQuietly ( szHotFixName , &requiresReboot ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error installing hotfix '%s', hr=0x%x", szHotFixName, hr); + goto exit; + } + if ( requiresReboot ) + { + rebootRequired = TRUE; + } + } + + if ( HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr ) + { + hr = S_OK; + } + + if ( rebootRequired ) + { + status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, + REBOOT_REQUIRED_REGKEY, + 0, + KEY_SET_VALUE, + ®Key); + if(status != ERROR_SUCCESS) + { + hr = HRESULT_FROM_WIN32(status); + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error opening the reboot registry key, hr=0x%x", hr); + goto exit; + } + + status = RegSetValueEx(regKey, + REBOOT_REGVALUE, + 0, + REG_SZ, + (PBYTE)L"", + 4); + if(status != ERROR_SUCCESS) + { + hr = HRESULT_FROM_WIN32(status); + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error creating the reboot registry value, hr=0x%x", hr); + goto exit; + } + + IISLogWrite(SETUP_LOG_SEVERITY_INFORMATION, L"Created a registry key to signal reboot is required"); + } + +exit: + if(regKey != NULL) + { + RegCloseKey(regKey); + regKey = NULL; + } + + if ( FAILED(hr) ) + { + IISLogWrite(SETUP_LOG_SEVERITY_INFORMATION, L"Error in function %s, hr=0x%x", UNITEXT(__FUNCTION__), hr); + } + + IISLogClose(); + return (SUCCEEDED(hr)) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; +} + +UINT +__stdcall +ScheduleRebootIfRequiredCA( + IN MSIHANDLE hInstall +) +{ + HRESULT hr = NOERROR; + HKEY regKey = NULL; + LONG status = ERROR_SUCCESS; + + IISLogInitialize(hInstall, UNITEXT(__FUNCTION__)); + + status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, + REBOOT_REQUIRED_REGKEY, + 0, + KEY_QUERY_VALUE, + ®Key); + if(status != ERROR_SUCCESS) + { + hr = HRESULT_FROM_WIN32(status); + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error opening the reboot registry key, hr=0x%x", hr); + goto exit; + } + + status = RegQueryValueEx(regKey, + REBOOT_REGVALUE, + 0, + NULL, + NULL, + NULL); + switch(status) + { + case ERROR_SUCCESS: + status = MsiSetMode(hInstall, + MSIRUNMODE_REBOOTATEND, + TRUE); + if( status != ERROR_SUCCESS ) + { + hr = HRESULT_FROM_WIN32(status); + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error setting reboot required for the installation, hr=0x%x", hr); + goto exit; + } + IISLogWrite(SETUP_LOG_SEVERITY_INFORMATION, L"Signalled the installer to reboot at the end of the installation."); + break; + + case ERROR_FILE_NOT_FOUND: + IISLogWrite(SETUP_LOG_SEVERITY_INFORMATION, L"No reboot is required by the IIS custom actions."); + hr = S_OK; + break; + + default: + hr = HRESULT_FROM_WIN32(status); + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error getting the IIS registry key reboot value, hr=0x%x", hr); + goto exit; + } + +exit: + if(regKey != NULL) + { + RegCloseKey(regKey); + regKey = NULL; + } + + if ( FAILED(hr) ) + { + IISLogWrite(SETUP_LOG_SEVERITY_INFORMATION, L"Error in function %s, hr=0x%x", UNITEXT(__FUNCTION__), hr); + } + + IISLogClose(); + + //dont report an error here. the install has completed so its too late to report a failure + return (SUCCEEDED(hr)) ? ERROR_SUCCESS : ERROR_SUCCESS; + +} \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/httpapi.cpp b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/httpapi.cpp new file mode 100644 index 0000000000..c3b5d059ba --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/httpapi.cpp @@ -0,0 +1,518 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#include "precomp.h" + + +HRESULT GetSidStringForAccount( + const WCHAR * szAccount, + __inout STRU * pstr + ) +{ + HRESULT hr = NOERROR; + BOOL success = TRUE; + DWORD sidSize = 0; + DWORD domainSize = 0; + PSID psid = NULL; + SID_NAME_USE sidKind; + LPWSTR pszSid = NULL; + LPWSTR pszDomain = NULL; + + LookupAccountNameW(NULL, + szAccount, + NULL, + &sidSize, + NULL, + &domainSize, + &sidKind); + + _ASSERT ( sidSize > 0 ); + + psid = new BYTE[sidSize]; + if( psid == NULL ) + { + hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY ); + DBGERROR_HR(hr); + goto exit; + } + + pszDomain = new WCHAR[domainSize]; + if( pszDomain == NULL ) + { + hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY ); + DBGERROR_HR(hr); + goto exit; + } + + success = LookupAccountNameW(NULL, + szAccount, + psid, + &sidSize, + pszDomain, + &domainSize, + &sidKind); + if( !success ) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + DBGERROR_HR(hr); + goto exit; + } + + success = ConvertSidToStringSidW( psid, &pszSid ); + if( !success ) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + DBGERROR_HR(hr); + goto exit; + } + + _ASSERT(pszSid); + + hr = pstr->Copy(pszSid); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + +exit: + if ( FAILED(hr) ) + { + IISLogWrite(SETUP_LOG_SEVERITY_INFORMATION, L"Error in function %s, hr=0x%x", UNITEXT(__FUNCTION__), hr); + } + + if (pszSid) + { + LocalFree( pszSid ); + pszSid = NULL; + } + + delete [] psid; + psid = NULL; + delete [] pszDomain; + pszDomain = NULL; + + return hr; +} + +UINT +WINAPI +ScheduleHttpListenerCA( + IN MSIHANDLE hInstall, + IN const WCHAR * pszCAName, + IIS_HTTP_LISTENER_CA_TYPE caType + ) +{ + HRESULT hr = S_OK; + UINT status = ERROR_SUCCESS; + BOOL scheduleDefferedCA = FALSE; + + PMSIHANDLE hDatabase; + PMSIHANDLE hView; + PMSIHANDLE hRecord; + + CONST WCHAR * szQuery = + L"SELECT " + L"`IISHttpListener`.`Name`, " + L"`IISHttpListener`.`Component_`, " + L"`IISHttpListener`.`Account`, " + L"`IISHttpListener`.`Prefix` " + L"FROM `IISHttpListener`"; + + enum { CA_HTTP_NAME = 1, + CA_HTTP_COMPONENT, + CA_HTTP_ACCOUNT, + CA_HTTP_PREFIX}; + + CA_DATA_WRITER cadata; + + hDatabase = MsiGetActiveDatabase( hInstall ); + if ( !hDatabase ) + { + hr = E_UNEXPECTED; + DBGERROR_HR(hr); + goto exit; + } + + status = MsiDatabaseOpenViewW( hDatabase, szQuery, &hView ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + DBGERROR_HR(hr); + goto exit; + } + + status = MsiViewExecute( hView, NULL ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + DBGERROR_HR(hr); + goto exit; + } + + while ( ERROR_SUCCESS == MsiViewFetch( hView, &hRecord ) ) + { + STACK_STRU( strName, 128 ); + STACK_STRU( strComponent, 128 ); + STACK_STRU( strAccount, 128 ); + STACK_STRU( strPrefix, 128 ); + INSTALLSTATE installStateCurrent; + INSTALLSTATE installStateAction; + BOOL scheduleThisComponent = FALSE; + + hr = MsiUtilRecordGetString( hRecord, + CA_HTTP_NAME, + &strName ); + if ( FAILED( hr ) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = MsiUtilRecordGetString( hRecord, + CA_HTTP_COMPONENT, + &strComponent ); + if ( FAILED( hr ) ) + { + DBGERROR_HR(hr); + goto exit; + } + + status = MsiGetComponentStateW( hInstall, + strComponent.QueryStr(), + &installStateCurrent, + &installStateAction ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32(status); + DBGERROR_HR(hr); + goto exit; + } + + if (MsiUtilIsInstalling( installStateCurrent, installStateAction ) || + MsiUtilIsReInstalling( installStateCurrent, installStateAction ) ) + { + if (caType == IIS_HTTP_LISTENER_CA_INSTALL) + { + scheduleThisComponent = TRUE; + scheduleDefferedCA = TRUE; + } + } + else if (MsiUtilIsUnInstalling( installStateCurrent, installStateAction)) + { + if (caType == IIS_HTTP_LISTENER_CA_UNINSTALL) + { + scheduleThisComponent = TRUE; + scheduleDefferedCA = TRUE; + } + + } + + if (scheduleThisComponent) + { + hr = MsiUtilRecordGetString( hRecord, + CA_HTTP_ACCOUNT, + &strAccount ); + if ( FAILED( hr ) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = MsiUtilRecordGetString( hRecord, + CA_HTTP_PREFIX, + &strPrefix ); + if ( FAILED( hr ) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata.Write( strName.QueryStr(), strName.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = MsiUtilFormatString( hInstall, &strAccount); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata.Write( strAccount.QueryStr(), strAccount.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = MsiUtilFormatString( hInstall, &strPrefix); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata.Write( strPrefix.QueryStr(), strPrefix.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + } + } + + if ( scheduleDefferedCA ) + { + hr = MsiUtilScheduleDeferredAction( hInstall, + pszCAName, + cadata.QueryData() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + } + +exit: + if ( FAILED(hr) ) + { + IISLogWrite(SETUP_LOG_SEVERITY_INFORMATION, L"Error in function %s, hr=0x%x", UNITEXT(__FUNCTION__), hr); + } + + return (SUCCEEDED(hr)) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; +} + +UINT +__stdcall +ExecuteHttpListenerCA( + IN MSIHANDLE hInstall, + IIS_HTTP_LISTENER_CA_TYPE caType + ) +{ + HRESULT hr = NOERROR; + ULONG status = NO_ERROR; + BOOL bHttpInitialized = FALSE; + CA_DATA_READER cadata; + WCHAR * szName = NULL; + WCHAR * szAccount = NULL; + WCHAR * szPrefix = NULL; + HTTPAPI_VERSION httpVersion1 = HTTPAPI_VERSION_1; + + hr = cadata.LoadDeferredCAData( hInstall ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + status = HttpInitialize( httpVersion1, HTTP_INITIALIZE_CONFIG, NULL ); + if ( status != NO_ERROR ) + { + hr = HRESULT_FROM_WIN32( status ); + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error calling HttpInitialize, hr=0x%x", hr); + goto exit; + } + bHttpInitialized = TRUE; + + while ( SUCCEEDED(hr = cadata.Read( &szName)) ) + { + const WCHAR * securityDescriptorFormat = L"D:(A;;GX;;;%s)"; + HTTP_SERVICE_CONFIG_URLACL_SET inputConfigInfo; + STACK_STRU( strSid, 128 ); + STACK_STRU( strSecurityString, 128 ); + + hr = cadata.Read( &szAccount); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata.Read( &szPrefix); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = GetSidStringForAccount(szAccount, &strSid); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = strSecurityString.SafeSnwprintf(securityDescriptorFormat, strSid.QueryStr()); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + inputConfigInfo.KeyDesc.pUrlPrefix = szPrefix; + inputConfigInfo.ParamDesc.pStringSecurityDescriptor = strSecurityString.QueryStr(); + + status = HttpDeleteServiceConfiguration(NULL, + HttpServiceConfigUrlAclInfo, + &inputConfigInfo, + sizeof(inputConfigInfo), + NULL); + + if (status == E_INVALIDARG) + { + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error calling Http API. Please make sure that the URL and Account information specified is correct."); + } + + if ( (status != NO_ERROR) && (status != ERROR_FILE_NOT_FOUND) ) + { + hr = HRESULT_FROM_WIN32( status ); + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error calling HttpDeleteServiceConfiguration for account '%s', prefix '%s', securityDescriptor '%s', hr=0x%x", + szAccount, + szPrefix, + strSecurityString.QueryStr(), + hr); + goto exit; + } + + if ( caType == IIS_HTTP_LISTENER_CA_INSTALL) + { + status = HttpSetServiceConfiguration(NULL, + HttpServiceConfigUrlAclInfo, + &inputConfigInfo, + sizeof(inputConfigInfo), + NULL); + if (status == E_INVALIDARG) + { + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error calling Http API. Please make sure that the URL and Account information specified is correct."); + } + if ( status != NO_ERROR ) + { + hr = HRESULT_FROM_WIN32( status ); + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error calling HttpSetServiceConfiguration for account '%s', prefix '%s', securityDescriptor '%s', hr=0x%x", + szAccount, + szPrefix, + strSecurityString.QueryStr(), + hr); + goto exit; + } + } + } + if ( HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr ) + { + hr = S_OK; + } + +exit: + if (bHttpInitialized) + { + HttpTerminate ( HTTP_INITIALIZE_CONFIG , NULL); + } + + if ( FAILED(hr) ) + { + IISLogWrite(SETUP_LOG_SEVERITY_INFORMATION, L"Error in function %s, hr=0x%x", UNITEXT(__FUNCTION__), hr); + } + + return (SUCCEEDED(hr)) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; +} + + //for(inputConfigInfo.dwToken = 0; /* condition inside */ ; inputConfigInfo.dwToken++) + //{ + // HTTP_SERVICE_CONFIG_URLACL_SET * pOutputConfigInfo = NULL; + // ULONG outputConfigInfoSize = 0; + + // while (status == ERROR_INSUFFICIENT_BUFFER) + // { + // delete pOutputConfigInfo; + // pOutputConfigInfo = NULL; + // pOutputConfigInfo = new BYTE[outputConfigInfoSize]; + // if (pOutputConfigInfo == NULL) + // { + // hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY ); + // DBGERROR_HR(hr); + // goto exit; + // } + + // status = HttpQueryServiceConfiguration ( NULL, + // HttpServiceConfigUrlAclInfo, + // &inputConfigInfo, + // sizeof(inputConfigInfo), + // pOutputConfigInfo, + // outputConfigInfoSize, + // &outputConfigInfoSize, + // NULL); + // } //end while + + // _ASSERT (status != ERROR_INSUFFICIENT_BUFFER) + // + // if (status == NO_ERROR) + // { + // //lookup output info + + // } + // else if (status == ERROR_NO_MORE_ITEMS) + // { + // //we're done + // break; + // } + // else + // { + // hr = HRESULT_FROM_WIN32( status ); + // DBGERROR_HR(hr); + // IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error calling HttpQueryServiceConfiguration, hr=0x%x", hr); + // goto exit; + // } + //} //end for + +UINT +WINAPI +ScheduleInstallHttpListenerCA( + IN MSIHANDLE hInstall + ) +{ + IISLogInitialize(hInstall, UNITEXT(__FUNCTION__)); + UINT retVal = ScheduleHttpListenerCA(hInstall, L"ExecuteInstallHttpListener", IIS_HTTP_LISTENER_CA_INSTALL); + IISLogClose(); + return retVal; +} + +UINT +WINAPI +ScheduleUnInstallHttpListenerCA( + IN MSIHANDLE hInstall + ) +{ + IISLogInitialize(hInstall, UNITEXT(__FUNCTION__)); + UINT retVal = ScheduleHttpListenerCA(hInstall, L"ExecuteUnInstallHttpListener", IIS_HTTP_LISTENER_CA_UNINSTALL); + IISLogClose(); + return retVal; +} +UINT +__stdcall +ExecuteInstallHttpListenerCA( + IN MSIHANDLE hInstall + ) +{ + IISLogInitialize(hInstall, UNITEXT(__FUNCTION__)); + UINT retVal = ExecuteHttpListenerCA(hInstall, IIS_HTTP_LISTENER_CA_INSTALL); + IISLogClose(); + return retVal; +} + +UINT +__stdcall +ExecuteUnInstallHttpListenerCA( + IN MSIHANDLE hInstall + ) +{ + IISLogInitialize(hInstall, UNITEXT(__FUNCTION__)); + UINT retVal = ExecuteHttpListenerCA(hInstall, IIS_HTTP_LISTENER_CA_UNINSTALL); + IISLogClose(); + return retVal; +} diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/httpapi.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/httpapi.h new file mode 100644 index 0000000000..1783e4ddf8 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/httpapi.h @@ -0,0 +1,55 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#pragma once + + +enum IIS_HTTP_LISTENER_CA_TYPE +{ + IIS_HTTP_LISTENER_CA_INSTALL, + IIS_HTTP_LISTENER_CA_UNINSTALL +}; + +HRESULT GetSidStringForAccount( + const WCHAR * szAccount, + __inout STRU * pstr + ); + +UINT +WINAPI +ScheduleHttpListenerCA( + IN MSIHANDLE hInstall, + IN const WCHAR * pszCAName, + IIS_HTTP_LISTENER_CA_TYPE caType + ); + +UINT +__stdcall +ExecuteHttpListenerCA( + IN MSIHANDLE hInstall, + IIS_HTTP_LISTENER_CA_TYPE caType + ); + +UINT +WINAPI +ScheduleInstallHttpListenerCA( + IN MSIHANDLE hInstall + ); + +UINT +__stdcall +ExecuteInstallHttpListenerCA( + IN MSIHANDLE hInstall + ); + +UINT +WINAPI +ScheduleUnInstallHttpListenerCA( + IN MSIHANDLE hInstall + ); + +UINT +__stdcall +ExecuteUnInstallHttpListenerCA( + IN MSIHANDLE hInstall + ); \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/iisca.cpp b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/iisca.cpp new file mode 100644 index 0000000000..06631ce964 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/iisca.cpp @@ -0,0 +1,4302 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#include "precomp.h" + +#define ROOT_CONFIG_PATH L"MACHINE/WEBROOT/APPHOST" + +#define MAX_NAME 256 +#define _UNITEXT(quote) L##quote +#define UNITEXT(quote) _UNITEXT(quote) + +HRESULT +GetFullTypeFromAssemblyTable( + IN MSIHANDLE hDatabase, + IN CONST WCHAR * szComponent, + IN CONST WCHAR * szTypeName, + IN OUT STRU * pstrFullType + ); + +BOOL IsSectionInAdminConfig( + IN CONST WCHAR * szIsInAdminConfig + ) +{ + if( 0 == _wcsicmp(szIsInAdminConfig, L"yes") ) + { + return TRUE; + } + else + { + return FALSE; + } +} + +HRESULT +ScheduleInstallModuleCA( + IN MSIHANDLE hInstall, + IN CA_DATA_WRITER * cadata + ) +{ + // + // If the module being installed includes the optional TypeName, + // then the we'll test the component to insure that the module + // is a .Net module. If so, then we will not install the module + // in and we'll include the TypeName and strong + // name info when we install in the . + // + + HRESULT hr = NOERROR; + UINT status = ERROR_SUCCESS; + + MSIHANDLE hDatabase = NULL; + MSIHANDLE hView = NULL; + MSIHANDLE hRecord = NULL; + + STACK_STRU( strData, 128 ); + STACK_STRU( strTemp, 128 ); + STACK_STRU( strComponent, 128 ); + STACK_STRU( strTypeName, 128 ); + STACK_STRU( strFullType, 128 ); + + CONST WCHAR * szQuery = + L"SELECT " + L"`IISGlobalModule`.`Name`, " + L"`IISGlobalModule`.`File_`, " + L"`IISGlobalModule`.`PreCondition`, " + L"`File`.`Component_`, " + L"`IISGlobalModule`.`TypeName` " + L"FROM `IISGlobalModule`, `File` " + L"WHERE `File`.`File`=`IISGlobalModule`.`File_`"; + + enum { CA_MODULE_NAME = 1, + CA_MODULE_IMAGE, + CA_MODULE_PRECONDITION, + CA_MODULE_COMPONENT, + CA_MODULE_TYPENAME }; + + INSTALLSTATE installStateCurrent; + INSTALLSTATE installStateAction; + + hDatabase = MsiGetActiveDatabase( hInstall ); + if ( !hDatabase ) + { + hr = E_UNEXPECTED; + DBGERROR_HR(hr); + goto exit; + } + // + // does table exists + // + UINT er = ERROR_SUCCESS; + er = ::MsiDatabaseIsTablePersistentW(hDatabase, L"IISGlobalModule"); + if (MSICONDITION_TRUE != er) + { + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' Table not found, exiting", + UNITEXT(__FUNCTION__) + ); + goto exit; + } + + status = MsiDatabaseOpenViewW( hDatabase, szQuery, &hView ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + DBGERROR_HR(hr); + goto exit; + } + + status = MsiViewExecute( hView, NULL ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + DBGERROR_HR(hr); + goto exit; + } + + while ( ERROR_SUCCESS == MsiViewFetch( hView, &hRecord ) ) + { + hr = MsiUtilRecordGetString( hRecord, + CA_MODULE_COMPONENT, + &strComponent ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + status = MsiGetComponentStateW( hInstall, + strComponent.QueryStr(), + &installStateCurrent, + &installStateAction ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32(status); + DBGERROR_HR(hr); + goto exit; + } + + if ( MsiUtilIsInstalling( installStateCurrent, installStateAction ) || + MsiUtilIsReInstalling( installStateCurrent, installStateAction ) ) + { + + cadata->Write( IIS_INSTALL_MODULE ); + + // Get the module name + hr = MsiUtilRecordGetString( hRecord, + CA_MODULE_NAME, + &strData ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Write( strData.QueryStr(), strData.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + // + // CA_MODULE_IMAGE is the name of the File element, need to + // resolve it to the full path by formatting it as [#ModuleDll] + // + + hr = MsiUtilRecordGetString( hRecord, + CA_MODULE_IMAGE, + &strTemp ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = strData.SafeSnwprintf( L"[#%s]", strTemp.QueryStr() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = MsiUtilFormatString( hInstall, + &strData ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Write( strData.QueryStr(), strData.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = MsiUtilRecordGetString( hRecord, + CA_MODULE_PRECONDITION, + &strData ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Write( strData.QueryStr(), strData.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + // + // Get the type name (optional) + // If the type name is present, then this is a .Net and does not have + // to be registered in the + // + hr = MsiUtilRecordGetString( hRecord, + CA_MODULE_TYPENAME, + &strTypeName ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + if ( strTypeName.QueryCCH() > 0 ) + { + // TypeName is present. Get the assembly info + hr = GetFullTypeFromAssemblyTable( hDatabase, + strComponent.QueryStr(), + strTypeName.QueryStr(), + &strFullType ); + + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + } + else + { + strFullType.Reset(); + } + + hr = cadata->Write( strFullType.QueryStr(), strFullType.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + } + + if ( hRecord ) + { + MsiCloseHandle( hRecord ); + hRecord = NULL; + } + } + +exit: + + if ( hRecord ) + { + MsiCloseHandle( hRecord ); + hRecord = NULL; + } + + if ( hView ) + { + MsiCloseHandle( hView ); + hView = NULL; + } + + if ( hDatabase ) + { + MsiCloseHandle( hDatabase ); + hDatabase = NULL; + } + + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' completed with return code hr=0x%x", + UNITEXT(__FUNCTION__), + hr ); + + return hr; +} + + +HRESULT +ScheduleUnInstallModuleCA( + IN MSIHANDLE hInstall, + IN CA_DATA_WRITER * cadata + ) +{ + HRESULT hr = NOERROR; + UINT status = ERROR_SUCCESS; + + MSIHANDLE hDatabase = NULL; + MSIHANDLE hView = NULL; + MSIHANDLE hRecord = NULL; + + STACK_STRU( strData, 128 ); + + CONST WCHAR * szQuery = + L"SELECT " + L"`IISGlobalModule`.`Name`, " + L"`File`.`Component_`, " + L"`IISGlobalModule`.`TypeName` " + L"FROM `IISGlobalModule`, `File` " + L"WHERE `File`.`File`=`IISGlobalModule`.`File_`"; + + enum { CA_MODULE_NAME = 1, + CA_MODULE_COMPONENT, + CA_MODULE_TYPENAME }; + + INSTALLSTATE installStateCurrent; + INSTALLSTATE installStateAction; + + + + hDatabase = MsiGetActiveDatabase( hInstall ); + if ( !hDatabase ) + { + hr = E_UNEXPECTED; + DBGERROR_HR(hr); + goto exit; + } + // + //Does table exist + // + UINT er = ERROR_SUCCESS; + er = ::MsiDatabaseIsTablePersistentW(hDatabase, L"IISGlobalModule"); + if (MSICONDITION_TRUE != er) + { + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' Table not found, exiting", + UNITEXT(__FUNCTION__) + ); + goto exit; + } + + status = MsiDatabaseOpenViewW( hDatabase, szQuery, &hView ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + DBGERROR_HR(hr); + goto exit; + } + + status = MsiViewExecute( hView, NULL ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + DBGERROR_HR(hr); + goto exit; + } + + while ( ERROR_SUCCESS == MsiViewFetch( hView, &hRecord ) ) + { + hr = MsiUtilRecordGetString( hRecord, + CA_MODULE_COMPONENT, + &strData ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + status = MsiGetComponentStateW( hInstall, + strData.QueryStr(), + &installStateCurrent, + &installStateAction ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32(status); + DBGERROR_HR(hr); + goto exit; + } + + if ( MsiUtilIsUnInstalling( installStateCurrent, installStateAction ) ) + { + + cadata->Write( IIS_UNINSTALL_MODULE ); + + + hr = MsiUtilRecordGetString( hRecord, + CA_MODULE_NAME, + &strData ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Write( strData.QueryStr(), strData.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = MsiUtilRecordGetString( hRecord, + CA_MODULE_TYPENAME, + &strData ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Write( strData.QueryStr(), strData.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + } + + if ( hRecord ) + { + MsiCloseHandle( hRecord ); + hRecord = NULL; + } + } + + +exit: + + if ( hRecord ) + { + MsiCloseHandle( hRecord ); + hRecord = NULL; + } + + if ( hView ) + { + MsiCloseHandle( hView ); + hView = NULL; + } + + if ( hDatabase ) + { + MsiCloseHandle( hDatabase ); + hDatabase = NULL; + } + + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' completed with return code hr=0x%x", + UNITEXT(__FUNCTION__), + hr ); + + return hr; +} + + +HRESULT +ExecuteInstallModuleCA( + IN CA_DATA_READER * cadata + ) +{ + HRESULT hr = NOERROR; + + WCHAR * szName = NULL; + WCHAR * szImage = NULL; + WCHAR * szPreCondition = NULL; + WCHAR * szType = NULL; + + + hr = cadata->Read( &szName ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + hr = cadata->Read( &szImage ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Read( &szPreCondition ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Read( &szType ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + // + // Install the module + // + + hr = InstallModule( szName, + szImage, + szPreCondition, + szType ); + + if ( hr == HRESULT_FROM_WIN32( ERROR_ALREADY_EXISTS ) ) + { + // + // We'll quietly accept a module already exists. + // This will happen if a component has multiple features + // that each have a module. + // If a feature is omitted on the initial install, + // and added later using Change, the features that + // were initially installed will show up in the + // ScheduleInstallModuleCA with install + // INSTALLSTATE_UNKNOWN, which will trigger a reinstall. + // Reinstall will result in ERROR_ALREADY_EXISTS. + // + IISLogWrite(SETUP_LOG_SEVERITY_INFORMATION, + L"Module: '%s' already installed.", + szName); + + hr = S_OK; + } + + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + + if ( HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr ) + { + hr = S_OK; + } + +exit: + + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' completed with return code hr=0x%x", + UNITEXT(__FUNCTION__), + hr ); + + return hr; +} + + +HRESULT +ExecuteUnInstallModuleCA( + IN CA_DATA_READER * cadata + ) +{ + HRESULT hr = NOERROR; + + WCHAR * szName = NULL; + WCHAR * szType = NULL; + + + + hr = cadata->Read( &szName ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + hr = cadata->Read( &szType ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = UnInstallModule( szName, szType ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + if ( HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr ) + { + hr = S_OK; + } + +exit: + + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' completed with return code hr=0x%x", + UNITEXT(__FUNCTION__), + hr ); + + return hr; +} + + +HRESULT +ScheduleRegisterSectionSchemaCA( + IN MSIHANDLE hInstall, + IN CA_DATA_WRITER * cadata + ) +{ + HRESULT hr = NOERROR; + UINT status = ERROR_SUCCESS; + + MSIHANDLE hDatabase = NULL; + MSIHANDLE hView = NULL; + MSIHANDLE hRecord = NULL; + + STACK_STRU( strData, 128 ); + + CONST WCHAR * szQuery = + L"SELECT " + L"`IISConfigSections`.`Name`, " + L"`IISConfigSections`.`File_`, " + L"`IISConfigSections`.`OverrideModeDefault`, " + L"`IISConfigSections`.`AllowDefinition`, " + L"`IISConfigSections`.`Type`, " + L"`IISConfigSections`.`InAdminConfig`, " + L"`File`.`Component_` " + L"FROM `IISConfigSections`, `File` " + L"WHERE `File`.`File`=`IISConfigSections`.`File_`"; + + enum + { + CA_SECTION_NAME = 1, + CA_SCHEMA_FILE, + CA_SECTION_OVERRIDEMODE, + CA_SECTION_ALLOWDEF, + CA_SECTION_TYPE, + CA_SECTION_INADMINCONFIG, + CA_SCHEMA_COMPONENT + }; + + INSTALLSTATE installStateCurrent; + INSTALLSTATE installStateAction; + + hDatabase = MsiGetActiveDatabase( hInstall ); + if ( !hDatabase ) + { + hr = E_UNEXPECTED; + DBGERROR_HR(hr); + goto exit; + } + // + //Does table exists + // + UINT er = ERROR_SUCCESS; + er = ::MsiDatabaseIsTablePersistentW(hDatabase, L"IISConfigSections"); + if (MSICONDITION_TRUE != er) + { + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' Table not found, exiting", + UNITEXT(__FUNCTION__) + ); + goto exit; + } + + status = MsiDatabaseOpenViewW( hDatabase, szQuery, &hView ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + DBGERROR_HR(hr); + goto exit; + } + + status = MsiViewExecute( hView, NULL ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + DBGERROR_HR(hr); + goto exit; + } + + while ( ERROR_SUCCESS == MsiViewFetch( hView, &hRecord ) ) + { + hr = MsiUtilRecordGetString( hRecord, + CA_SCHEMA_COMPONENT, + &strData ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + status = MsiGetComponentStateW( hInstall, + strData.QueryStr(), + &installStateCurrent, + &installStateAction ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32(status); + DBGERROR_HR(hr); + goto exit; + } + + if ( MsiUtilIsInstalling( installStateCurrent, installStateAction ) || + MsiUtilIsReInstalling( installStateCurrent, installStateAction ) ) + { + + cadata->Write( IIS_INSTALL_SECTIONSCHEMA ); + + hr = MsiUtilRecordGetString( hRecord, + CA_SECTION_NAME, + &strData ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Write( strData.QueryStr(), strData.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = MsiUtilRecordGetString( hRecord, + CA_SECTION_OVERRIDEMODE, + &strData ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Write( strData.QueryStr(), strData.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = MsiUtilRecordGetString( hRecord, + CA_SECTION_ALLOWDEF, + &strData ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Write( strData.QueryStr(), strData.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = MsiUtilRecordGetString( hRecord, + CA_SECTION_TYPE, + &strData ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Write( strData.QueryStr(), strData.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = MsiUtilRecordGetString( hRecord, + CA_SECTION_INADMINCONFIG, + &strData ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Write( strData.QueryStr(), strData.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + } + + if ( hRecord ) + { + MsiCloseHandle( hRecord ); + hRecord = NULL; + } + + } + + +exit: + + if ( hRecord ) + { + MsiCloseHandle( hRecord ); + hRecord = NULL; + } + + if ( hView ) + { + MsiCloseHandle( hView ); + hView = NULL; + } + + if ( hDatabase ) + { + MsiCloseHandle( hDatabase ); + hDatabase = NULL; + } + + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' completed with return code hr=0x%x", + UNITEXT(__FUNCTION__), + hr ); + + + return hr; +} + + +HRESULT +ScheduleUnRegisterSectionSchemaCA( + IN MSIHANDLE hInstall, + IN CA_DATA_WRITER * cadata + ) +{ + HRESULT hr = NOERROR; + UINT status = ERROR_SUCCESS; + + MSIHANDLE hDatabase = NULL; + MSIHANDLE hView = NULL; + MSIHANDLE hRecord = NULL; + + STACK_STRU( strData, 128 ); + + CONST WCHAR * szQuery = + L"SELECT " + L"`IISConfigSections`.`Name`, " + L"`IISConfigSections`.`InAdminConfig`, " + L"`File`.`Component_` " + L"FROM `IISConfigSections`, `File` " + L"WHERE `File`.`File`=`IISConfigSections`.`File_`"; + + enum { + CA_SECTION_NAME = 1, + CA_SECTION_INADMINCONFIG, + CA_SCHEMA_COMPONENT }; + + INSTALLSTATE installStateCurrent; + INSTALLSTATE installStateAction; + + + hDatabase = MsiGetActiveDatabase( hInstall ); + if ( !hDatabase ) + { + hr = E_UNEXPECTED; + DBGERROR_HR(hr); + goto exit; + } + // + //Does table exists + // + UINT er = ERROR_SUCCESS; + er = ::MsiDatabaseIsTablePersistentW(hDatabase, L"IISConfigSections"); + if (MSICONDITION_TRUE != er) + { + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' Table not found, exiting", + UNITEXT(__FUNCTION__) + ); + goto exit; + } + + status = MsiDatabaseOpenViewW( hDatabase, szQuery, &hView ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + DBGERROR_HR(hr); + goto exit; + } + + status = MsiViewExecute( hView, NULL ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + DBGERROR_HR(hr); + goto exit; + } + + while ( ERROR_SUCCESS == MsiViewFetch( hView, &hRecord ) ) + { + hr = MsiUtilRecordGetString( hRecord, + CA_SCHEMA_COMPONENT, + &strData ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + status = MsiGetComponentStateW( hInstall, + strData.QueryStr(), + &installStateCurrent, + &installStateAction ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32(status); + DBGERROR_HR(hr); + goto exit; + } + + if ( MsiUtilIsUnInstalling( installStateCurrent, installStateAction ) ) + { + cadata->Write( IIS_UNINSTALL_SECTIONSCHEMA ); + + hr = MsiUtilRecordGetString( hRecord, + CA_SECTION_NAME, + &strData ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Write( strData.QueryStr(), strData.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = MsiUtilRecordGetString( hRecord, + CA_SECTION_INADMINCONFIG, + &strData ); + + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Write( strData.QueryStr(), strData.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + } + + if ( hRecord ) + { + MsiCloseHandle( hRecord ); + hRecord = NULL; + } + } + + +exit: + + if ( hRecord ) + { + MsiCloseHandle( hRecord ); + hRecord = NULL; + } + + if ( hView ) + { + MsiCloseHandle( hView ); + hView = NULL; + } + + if ( hDatabase ) + { + MsiCloseHandle( hDatabase ); + hDatabase = NULL; + } + + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' completed with return code hr=0x%x", + UNITEXT(__FUNCTION__), + hr ); + + return hr; +} + + +HRESULT +ExecuteRegisterSectionSchemaCA( + IN CA_DATA_READER * cadata + ) +{ + HRESULT hr = NOERROR; + + WCHAR * szSectionName = NULL; + WCHAR * szOverrideMode = NULL; + WCHAR * szAllowDefinition = NULL; + WCHAR * szType = NULL; + WCHAR * szIsInAdminConfig = NULL; + + + // + // Retrieve parameters from ca data + // + hr = cadata->Read( &szSectionName ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + hr = cadata->Read( &szOverrideMode ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Read( &szAllowDefinition ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Read( &szType ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Read( &szIsInAdminConfig ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + // + // Register the section + // + + hr = RegisterSectionSchema( IsSectionInAdminConfig(szIsInAdminConfig), + szSectionName, + szOverrideMode, + szAllowDefinition, + szType ); + + if ( hr == HRESULT_FROM_WIN32( ERROR_ALREADY_EXISTS ) ) + { + // + // We'll quietly accept a section name already exists. + // This will happen if a package has multiple features + // that each have a section. + // If a feature is omitted on the initial install, + // and added later using Change, the features that + // were initially installed will show up in the + // ScheduleRegisterSectionSchemaCA with install + // INSTALLSTATE_UNKNOWN, which will trigger a reinstall. + // Reinstall will result in ERROR_ALREADY_EXISTS. + // + IISLogWrite(SETUP_LOG_SEVERITY_INFORMATION, + L"Section name: '%s' already exists.", + szSectionName); + + hr = S_OK; + } + + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + if ( HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr ) + { + hr = S_OK; + } + +exit: + + + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' completed with return code hr=0x%x", + UNITEXT(__FUNCTION__), + hr ); + + + return hr; +} + + +HRESULT +ExecuteUnRegisterSectionSchemaCA( + IN CA_DATA_READER * cadata + ) +{ + HRESULT hr = NOERROR; + + WCHAR * szSectionName = NULL; + WCHAR * szIsInAdminConfig = NULL; + + + hr = cadata->Read( &szSectionName ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + hr = cadata->Read( &szIsInAdminConfig ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = UnRegisterSectionSchema( IsSectionInAdminConfig(szIsInAdminConfig), + szSectionName ); + if ( FAILED(hr) ) + { + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, + L"Failed to unregister section schema for section: '%s', hr=0x%x .", + szSectionName, + hr ); + DBGERROR_HR(hr); + + // + // We need to keep going because this is an uninstall action + // and should be resilient to missing elements. + // + hr = S_OK; + } + + if ( HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr ) + { + hr = S_OK; + } + +exit: + + + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' completed with return code hr=0x%x", + UNITEXT(__FUNCTION__), + hr ); + + + return hr; +} + +HRESULT +CanonicalizeAssemblyVersion( + STRU & strValue +) +{ + // + // Converts 7.1.2.000 to 7.1.2.0 + // + + HRESULT hr = S_OK; + LPCWSTR psz = wcschr( strValue.QueryStr(), L'.' ); + DWORD dwDotCount = 0; + + // + // Find the 3rd '.' + // + while ( psz != NULL ) + { + dwDotCount++; + LPCWSTR psz2 = wcschr( psz + 1, L'.' ); + if ( psz2 == NULL ) + { + break; + } + psz = psz2; + } + + if ( dwDotCount == 3 && psz != NULL ) + { + // + // Convert "000" to integer and then back to string. + // + + psz ++; + DWORD dw = _wtoi( psz ); + STACK_STRU( strTemp, 16 ); + + hr = strTemp.SafeSnwprintf( L"%u", dw ); + if ( SUCCEEDED( hr ) ) + { + ptrdiff_t diff = psz - strValue.QueryStr(); + + _ASSERTE( diff >= 0 ); + + hr = strValue.SetLen( (DWORD) diff ); + if ( FAILED( hr ) ) + { + DBGERROR_HR(hr); + goto exit; + } + hr = strValue.Append(strTemp); + if ( FAILED( hr ) ) + { + DBGERROR_HR(hr); + goto exit; + } + } + } + +exit: + + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' completed with return code hr=0x%x", + UNITEXT(__FUNCTION__), + hr ); + + return hr; +} + +HRESULT +GetFullTypeFromAssemblyTable( + IN MSIHANDLE hDatabase, + IN CONST WCHAR * szComponent, + IN CONST WCHAR * szTypeName, + IN OUT STRU * pstrFullType + ) +{ + HRESULT hr = NOERROR; + UINT status = ERROR_SUCCESS; + BOOL fRecordFound = FALSE; + BOOL fVersion = FALSE; + + MSIHANDLE hView = NULL; + MSIHANDLE hRecord = NULL; + + STACK_STRU( strQuery, 128 ); + STACK_STRU( strPropName, 64 ); + STACK_STRU( strPropValueName, 64 ); + STACK_STRU( strPropVersion, 64 ); + STACK_STRU( strPropCulture, 64 ); + STACK_STRU( strPropKeyToken, 64 ); + + CONST WCHAR * szQueryTemplate = + L"SELECT `Name`, `Value` " + L"FROM `MsiAssemblyName` " + L"WHERE `Component_`='%s'"; + + CONST WCHAR * szFullTypeTempl = L"%s, %s, Version=%s, Culture=%s, PublicKeyToken=%s"; + // szTypeName, name, version, culture, publicKeyToken + + enum { CA_ASSEMBLY_PROP_NAME = 1, CA_ASSEMBLY_PROP_VALUE }; + + hr = strQuery.SafeSnwprintf( szQueryTemplate, szComponent ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + status = MsiDatabaseOpenViewW( hDatabase, strQuery.QueryStr(), &hView ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + DBGERROR_HR(hr); + goto exit; + } + + status = MsiViewExecute( hView, NULL ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + DBGERROR_HR(hr); + goto exit; + } + + STRU * pstr; + + while ( ERROR_SUCCESS == MsiViewFetch( hView, &hRecord ) ) + { + fRecordFound = TRUE; + hr = MsiUtilRecordGetString( hRecord, + CA_ASSEMBLY_PROP_NAME, + &strPropName ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + pstr = NULL; + + if ( 0 == wcscmp( strPropName.QueryStr(), L"name" ) ) + { + pstr = &strPropValueName; + } + else if ( 0 == wcscmp( strPropName.QueryStr(), L"version" ) ) + { + fVersion = TRUE; + pstr = &strPropVersion; + } + else if ( 0 == wcscmp( strPropName.QueryStr(), L"culture" ) ) + { + pstr = &strPropCulture; + } + else if ( 0 == wcscmp( strPropName.QueryStr(), L"publicKeyToken" ) ) + { + pstr = &strPropKeyToken; + } + + if ( pstr ) + { + hr = MsiUtilRecordGetString( hRecord, + CA_ASSEMBLY_PROP_VALUE, + pstr ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + if ( fVersion ) + { + hr = CanonicalizeAssemblyVersion( *pstr ); + if ( FAILED( hr ) ) + { + DBGERROR_HR(hr); + goto exit; + } + fVersion = FALSE; + } + } + + if ( hRecord ) + { + MsiCloseHandle( hRecord ); + hRecord = NULL; + } + } + + hr = pstrFullType->SafeSnwprintf( szFullTypeTempl, + szTypeName, + strPropValueName.QueryStr(), + strPropVersion.QueryStr(), + strPropCulture.QueryStr(), + strPropKeyToken.QueryStr() + ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + +exit: + _ASSERTE( fRecordFound ); + + if ( hRecord ) + { + MsiCloseHandle( hRecord ); + hRecord = NULL; + } + + if ( hView ) + { + MsiCloseHandle( hView ); + hView = NULL; + } + + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' completed with return code hr=0x%x", + UNITEXT(__FUNCTION__), + hr ); + + return hr; +} + + +HRESULT +ScheduleRegisterUIModuleCA( + IN MSIHANDLE hInstall, + IN CA_DATA_WRITER * cadata + ) +{ + HRESULT hr = NOERROR; + UINT status = ERROR_SUCCESS; + + MSIHANDLE hDatabase = NULL; + MSIHANDLE hView = NULL; + MSIHANDLE hRecord = NULL; + + STACK_STRU( strComponent, 128 ); + STACK_STRU( strAssemblyInfoComponent, 128 ); + STACK_STRU( strData, 128 ); + STACK_STRU( strFullType, 128 ); + + const STRU * pstrComponentName = NULL; + + CONST WCHAR * szQuery = + L"SELECT " + L"`IISUIModule`.`Name`, " + L"`IISUIModule`.`TypeName`, " + L"`IISUIModule`.`Component_` ," + L"`IISUIModule`.`AssemblyInfoComponent_` ," + L"`IISUIModule`.`RegisterInModulesSection` ," + L"`IISUIModule`.`PrependToList` " + L"FROM `IISUIModule` "; + + enum { + CA_UIMODULE_NAME = 1, + CA_UIMODULE_TYPE, + CA_UIMODULE_COMPONENT, + CA_UIMODULE_ASSEMBLYINFOCOMPONENT, + CA_UIMODULE_REGISTER, + CA_UIMODULE_PREPEND + }; + + INSTALLSTATE installStateCurrent; + INSTALLSTATE installStateAction; + + + hDatabase = MsiGetActiveDatabase( hInstall ); + if ( !hDatabase ) + { + hr = E_UNEXPECTED; + DBGERROR_HR(hr); + goto exit; + } + // + //Does table exist + // + UINT er = ERROR_SUCCESS; + er = ::MsiDatabaseIsTablePersistentW(hDatabase, L"IISUIModule"); + if (MSICONDITION_TRUE != er) + { + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' Table not found, exiting", + UNITEXT(__FUNCTION__) + ); + goto exit; + } + + status = MsiDatabaseOpenViewW( hDatabase, szQuery, &hView ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + DBGERROR_HR(hr); + goto exit; + } + + status = MsiViewExecute( hView, NULL ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + DBGERROR_HR(hr); + goto exit; + } + + while ( ERROR_SUCCESS == MsiViewFetch( hView, &hRecord ) ) + { + hr = MsiUtilRecordGetString( hRecord, + CA_UIMODULE_COMPONENT, + &strComponent ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + status = MsiGetComponentStateW( hInstall, + strComponent.QueryStr(), + &installStateCurrent, + &installStateAction ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32(status); + DBGERROR_HR(hr); + goto exit; + } + + if ( MsiUtilIsInstalling( installStateCurrent, installStateAction ) || + MsiUtilIsReInstalling( installStateCurrent, installStateAction ) ) + { + + cadata->Write( IIS_INSTALL_UIMODULE ); + + hr = MsiUtilRecordGetString( hRecord, + CA_UIMODULE_NAME, + &strData ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Write( strData.QueryStr(), strData.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = MsiUtilRecordGetString( hRecord, + CA_UIMODULE_ASSEMBLYINFOCOMPONENT, + &strAssemblyInfoComponent ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + // use the AssemblyInfoComponent_ to get the module assembly information + // fall back to using the component if the value is null. + if ( strAssemblyInfoComponent.QueryCCH() > 0 ) + { + pstrComponentName = &strAssemblyInfoComponent; + } + else + { + pstrComponentName = &strComponent; + } + _ASSERTE( pstrComponentName != NULL ); + + hr = MsiUtilRecordGetString( hRecord, + CA_UIMODULE_TYPE, + &strData ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = GetFullTypeFromAssemblyTable( hDatabase, + pstrComponentName->QueryStr(), + strData.QueryStr(), + &strFullType ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Write( strFullType.QueryStr(), strFullType.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = MsiUtilRecordGetString( hRecord, + CA_UIMODULE_REGISTER, + &strData ); + if (FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Write( strData.QueryStr(), strData.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = MsiUtilRecordGetString( hRecord, + CA_UIMODULE_PREPEND, + &strData ); + if (FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Write( strData.QueryStr(), strData.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + } + + if ( hRecord ) + { + MsiCloseHandle( hRecord ); + hRecord = NULL; + } + + } + + +exit: + + if ( hRecord ) + { + MsiCloseHandle( hRecord ); + hRecord = NULL; + } + + if ( hView ) + { + MsiCloseHandle( hView ); + hView = NULL; + } + + if ( hDatabase ) + { + MsiCloseHandle( hDatabase ); + hDatabase = NULL; + } + + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' completed with return code hr=0x%x", + UNITEXT(__FUNCTION__), + hr ); + + + return hr; +} + + +HRESULT +ScheduleUnRegisterUIModuleCA( + IN MSIHANDLE hInstall, + IN CA_DATA_WRITER * cadata + ) +{ + HRESULT hr = NOERROR; + UINT status = ERROR_SUCCESS; + + MSIHANDLE hDatabase = NULL; + MSIHANDLE hView = NULL; + MSIHANDLE hRecord = NULL; + + STACK_STRU( strComponent, 128 ); + STACK_STRU( strAssemblyInfoComponent, 128 ); + STACK_STRU( strData, 128 ); + STACK_STRU( strFullType, 128 ); + + const STRU * pstrComponentName = NULL; + + CONST WCHAR * szQuery = + L"SELECT " + L"`IISUIModule`.`Name`, " + L"`IISUIModule`.`TypeName`, " + L"`IISUIModule`.`Component_` ," + L"`IISUIModule`.`AssemblyInfoComponent_` " + L"FROM `IISUIModule` "; + + enum { + CA_UIMODULE_NAME = 1, + CA_UIMODULE_TYPE, + CA_UIMODULE_COMPONENT, + CA_UIMODULE_ASSEMBLYINFOCOMPONENT, + }; + + INSTALLSTATE installStateCurrent; + INSTALLSTATE installStateAction; + + + hDatabase = MsiGetActiveDatabase( hInstall ); + if ( !hDatabase ) + { + hr = E_UNEXPECTED; + DBGERROR_HR(hr); + goto exit; + } + // + //Does table exist + // + UINT er = ERROR_SUCCESS; + er = ::MsiDatabaseIsTablePersistentW(hDatabase, L"IISUIModule"); + if (MSICONDITION_TRUE != er) + { + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' Table not found, exiting", + UNITEXT(__FUNCTION__) + ); + goto exit; + } + + status = MsiDatabaseOpenViewW( hDatabase, szQuery, &hView ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + DBGERROR_HR(hr); + goto exit; + } + + status = MsiViewExecute( hView, NULL ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + DBGERROR_HR(hr); + goto exit; + } + + while ( ERROR_SUCCESS == MsiViewFetch( hView, &hRecord ) ) + { + hr = MsiUtilRecordGetString( hRecord, + CA_UIMODULE_COMPONENT, + &strComponent ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + status = MsiGetComponentStateW( hInstall, + strComponent.QueryStr(), + &installStateCurrent, + &installStateAction ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32(status); + DBGERROR_HR(hr); + goto exit; + } + + if ( MsiUtilIsUnInstalling( installStateCurrent, installStateAction ) ) + { + + cadata->Write( IIS_UNINSTALL_UIMODULE ); + + hr = MsiUtilRecordGetString( hRecord, + CA_UIMODULE_NAME, + &strData ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Write( strData.QueryStr(), strData.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = MsiUtilRecordGetString( hRecord, + CA_UIMODULE_ASSEMBLYINFOCOMPONENT, + &strAssemblyInfoComponent ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + // use the AssemblyInfoComponent_ to get the module assembly information + // fall back to using the component if the value is null. + if ( strAssemblyInfoComponent.QueryCCH() > 0 ) + { + pstrComponentName = &strAssemblyInfoComponent; + } + else + { + pstrComponentName = &strComponent; + } + _ASSERTE( pstrComponentName != NULL ); + + hr = MsiUtilRecordGetString( hRecord, + CA_UIMODULE_TYPE, + &strData ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = GetFullTypeFromAssemblyTable( hDatabase, + pstrComponentName->QueryStr(), + strData.QueryStr(), + &strFullType ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Write( strFullType.QueryStr(), strFullType.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + } + + if ( hRecord ) + { + MsiCloseHandle( hRecord ); + hRecord = NULL; + } + + } + + +exit: + + if ( hRecord ) + { + MsiCloseHandle( hRecord ); + hRecord = NULL; + } + + if ( hView ) + { + MsiCloseHandle( hView ); + hView = NULL; + } + + if ( hDatabase ) + { + MsiCloseHandle( hDatabase ); + hDatabase = NULL; + } + + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' completed with return code hr=0x%x", + UNITEXT(__FUNCTION__), + hr ); + + + return hr; +} + + +HRESULT +ExecuteRegisterUIModuleCA( + IN CA_DATA_READER * cadata + ) +{ + HRESULT hr = NOERROR; + + WCHAR * szUIModuleName = NULL; + WCHAR * szUIModuleTypeInfo = NULL; + WCHAR * szUIModuleRegister = NULL; + WCHAR * szUIModulePrepend = NULL; + + hr = cadata->Read( &szUIModuleName ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + hr = cadata->Read( &szUIModuleTypeInfo ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Read( &szUIModuleRegister ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Read( &szUIModulePrepend ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + // + // Register the section + // + + hr = RegisterUIModule( szUIModuleName, + szUIModuleTypeInfo, + szUIModuleRegister, + szUIModulePrepend ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + if ( HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr ) + { + hr = S_OK; + } + +exit: + + + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' completed with return code hr=0x%x", + UNITEXT(__FUNCTION__), + hr ); + + return hr; +} + + +HRESULT +ExecuteUnRegisterUIModuleCA( + IN CA_DATA_READER * cadata + ) +{ + HRESULT hr = NOERROR; + + WCHAR * szUIModuleName = NULL; + WCHAR * szUIModuleTypeInfo = NULL; + + hr = cadata->Read( &szUIModuleName ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + hr = cadata->Read( &szUIModuleTypeInfo ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = UnRegisterUIModule( szUIModuleName, szUIModuleTypeInfo ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + if ( HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr ) + { + hr = S_OK; + } + +exit: + + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' completed with return code hr=0x%x", + UNITEXT(__FUNCTION__), + hr ); + + return hr; +} + +HRESULT +ScheduleRegisterTraceAreaCA( + IN MSIHANDLE hInstall, + IN CA_DATA_WRITER * cadata + ) +{ + HRESULT hr = NOERROR; + UINT status = ERROR_SUCCESS; + + MSIHANDLE hDatabase = NULL; + MSIHANDLE hView = NULL; + MSIHANDLE hRecord = NULL; + + STACK_STRU( strData, 128 ); + STACK_STRU( strComponent, 128 ); + + CONST WCHAR * szQuery = + L"SELECT " + L"`IISTraceArea`.`Component_`, " + L"`IISTraceArea`.`ProviderName`, " + L"`IISTraceArea`.`ProviderGuid`, " + L"`IISTraceArea`.`AreaName`, " + L"`IISTraceArea`.`AreaValue` " + L"FROM `IISTraceArea` "; + + enum { CA_COMPONENT = 1, + CA_PROVIDER_NAME, + CA_PROVIDER_GUID, + CA_AREA_NAME, + CA_AREA_VALUE }; + + INSTALLSTATE installStateCurrent; + INSTALLSTATE installStateAction; + + hDatabase = MsiGetActiveDatabase( hInstall ); + if ( !hDatabase ) + { + hr = E_UNEXPECTED; + DBGERROR_HR(hr); + goto exit; + } + // + //Does table exist + // + UINT er = ERROR_SUCCESS; + er = ::MsiDatabaseIsTablePersistentW(hDatabase, L"IISTraceArea"); + if (MSICONDITION_TRUE != er) + { + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' Table not found, exiting", + UNITEXT(__FUNCTION__) + ); + goto exit; + } + + status = MsiDatabaseOpenViewW( hDatabase, szQuery, &hView ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + DBGERROR_HR(hr); + goto exit; + } + + status = MsiViewExecute( hView, NULL ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + DBGERROR_HR(hr); + goto exit; + } + + while ( ERROR_SUCCESS == MsiViewFetch( hView, &hRecord ) ) + { + hr = MsiUtilRecordGetString( hRecord, + CA_COMPONENT, + &strComponent ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + status = MsiGetComponentStateW( hInstall, + strComponent.QueryStr(), + &installStateCurrent, + &installStateAction ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32(status); + DBGERROR_HR(hr); + goto exit; + } + + if ( MsiUtilIsInstalling( installStateCurrent, installStateAction ) || + MsiUtilIsReInstalling( installStateCurrent, installStateAction ) ) + { + cadata->Write( IIS_INSTALL_TRACEAREA ); + + // Get the values + for ( DWORD Index = CA_PROVIDER_NAME; Index <= CA_AREA_VALUE; Index++ ) + { + hr = MsiUtilRecordGetString( hRecord, + Index, + &strData ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Write( strData.QueryStr(), strData.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + } + + } + + if ( hRecord ) + { + MsiCloseHandle( hRecord ); + hRecord = NULL; + } + } + + +exit: + + if ( hRecord ) + { + MsiCloseHandle( hRecord ); + hRecord = NULL; + } + + if ( hView ) + { + MsiCloseHandle( hView ); + hView = NULL; + } + + if ( hDatabase ) + { + MsiCloseHandle( hDatabase ); + hDatabase = NULL; + } + + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' completed with return code hr=0x%x", + UNITEXT(__FUNCTION__), + hr ); + + return hr; +} + + +HRESULT +ExecuteRegisterTraceAreaCA( + IN CA_DATA_READER * cadata +) +{ + HRESULT hr = NOERROR; + + WCHAR * szTraceProviderName = NULL; + WCHAR * szTraceProviderGuid = NULL; + WCHAR * szAreaName = NULL; + WCHAR * szAreaValue = NULL; + + + hr = cadata->Read( &szTraceProviderName ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + hr = cadata->Read( &szTraceProviderGuid ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Read( &szAreaName ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Read( &szAreaValue ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + // + // Register the section + // + hr = RegisterTraceArea( szTraceProviderName, + szTraceProviderGuid, + szAreaName, + szAreaValue ); + if ( FAILED(hr) ) + { + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, + L"Failed to register trace area (Provider: '%s'; " + L"Guid: '%s'; AreaName: '%s'; AreaValue: '%s') hr=0x%x", + szTraceProviderName, + szTraceProviderGuid, + szAreaName, + szAreaValue, + hr ); + DBGERROR_HR(hr); + goto exit; + } + + if ( HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr ) + { + hr = S_OK; + } + +exit: + + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' completed with return code hr=0x%x", + UNITEXT(__FUNCTION__), + hr ); + + + return (SUCCEEDED(hr)) ? ERROR_SUCCESS : ERROR_SUCCESS; +} + +/// The error messages are from setstrings.wxl. +/// The integer parameter is used to to get the string. +UINT +LogMsiCustomActionError( + IN MSIHANDLE hInstall, + UINT messageId + ) +{ + PMSIHANDLE pLogger = MsiCreateRecord(1); + if ( pLogger == NULL ) + { + return ERROR_INSTALL_FAILURE; + } + + MsiRecordSetInteger( pLogger, 1, messageId ); + MsiProcessMessage( hInstall, INSTALLMESSAGE_ERROR, pLogger ); + + if ( pLogger != NULL ) + { + MsiCloseHandle( pLogger ); + pLogger = NULL; + } + + return ERROR_INSTALL_FAILURE; +} + + +HRESULT +ScheduleRegisterMofFileCA( + IN MSIHANDLE hInstall, + IN CA_DATA_WRITER * cadata +) +{ + HRESULT hr = NOERROR; + UINT status = ERROR_SUCCESS; + + MSIHANDLE hDatabase = NULL; + MSIHANDLE hView = NULL; + MSIHANDLE hRecord = NULL; + + STACK_STRU( strData, 128 ); + + CONST WCHAR * szQuery = + L"SELECT " + L"`IISTraceArea`.`BinaryName_`, " + L"`Binary`.`Data`, " + L"`IISTraceArea`.`Component_` " + L"FROM `IISTraceArea`, `Binary` " + L"WHERE `Binary`.`Name`=`IISTraceArea`.`BinaryName_`"; + + enum { CA_BINARY_NAME = 1, + CA_FILE_DATA, + CA_MOF_COMPONENT }; + + INSTALLSTATE installStateCurrent; + INSTALLSTATE installStateAction; + + + hDatabase = MsiGetActiveDatabase( hInstall ); + if ( !hDatabase ) + { + hr = E_UNEXPECTED; + DBGERROR_HR(hr); + goto exit; + } + + // + //Does table exist + // + UINT er = ERROR_SUCCESS; + er = ::MsiDatabaseIsTablePersistentW(hDatabase, L"IISTraceArea"); + if (MSICONDITION_TRUE != er) + { + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' Table not found, exiting", + UNITEXT(__FUNCTION__) + ); + goto exit; + } + + status = MsiDatabaseOpenViewW( hDatabase, szQuery, &hView ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + DBGERROR_HR(hr); + goto exit; + } + + status = MsiViewExecute( hView, NULL ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + DBGERROR_HR(hr); + goto exit; + } + + while ( ERROR_SUCCESS == MsiViewFetch( hView, &hRecord ) ) + { + hr = MsiUtilRecordGetString( hRecord, + CA_MOF_COMPONENT, + &strData ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + status = MsiGetComponentStateW( hInstall, + strData.QueryStr(), + &installStateCurrent, + &installStateAction ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32(status); + DBGERROR_HR(hr); + goto exit; + } + + if ( MsiUtilIsInstalling( installStateCurrent, installStateAction ) || + MsiUtilIsReInstalling( installStateCurrent, installStateAction ) ) + { + + cadata->Write( IIS_INSTALL_MOFFILE ); + + STACK_STRU( strBinaryName, 128 ); + STACK_STRU( strMofFilePath, MAX_PATH ); + + hr = MsiUtilRecordGetString( hRecord, + CA_BINARY_NAME, + &strBinaryName ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = GenerateTempFileName( strBinaryName.QueryStr(), + L"mof", + &strMofFilePath); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = MsiUtilRecordReadStreamIntoFile( hRecord, + CA_FILE_DATA, + strMofFilePath.QueryStr()); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Write( strMofFilePath.QueryStr(), strMofFilePath.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + if ( hRecord ) + { + MsiCloseHandle( hRecord ); + hRecord = NULL; + } + } + } + +exit: + + if ( hRecord ) + { + MsiCloseHandle( hRecord ); + hRecord = NULL; + } + + if ( hView ) + { + MsiCloseHandle( hView ); + hView = NULL; + } + + if ( hDatabase ) + { + MsiCloseHandle( hDatabase ); + hDatabase = NULL; + } + + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' completed with return code hr=0x%x", + UNITEXT(__FUNCTION__), + hr ); + + return hr; +} + +HRESULT +ExecuteRegisterMofFileCA( + IN CA_DATA_READER * cadata +) +{ + HRESULT hr = NOERROR; + + WCHAR * szMofFileName = NULL; + + hr = cadata->Read( &szMofFileName ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + // + // Register the section + // + hr = RegisterMofFile( szMofFileName ); + if ( FAILED(hr) ) + { + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, + L"Failed to register MOF file (File name: '%s') hr=0x%x", + szMofFileName, + hr ); + DBGERROR_HR(hr); + + // + // Continue setup, this is not a fatal error. + // + hr = S_OK; + + goto exit; + } + else + { + IISLogWrite(SETUP_LOG_SEVERITY_INFORMATION, + L"MOF file '%s' registered.", + szMofFileName ); + } + + if ( HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr ) + { + hr = S_OK; + } + +exit: + + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' completed with return code hr=0x%x", + UNITEXT(__FUNCTION__), + hr ); + + return (SUCCEEDED(hr)) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; +} + +HRESULT +ScheduleInstallHandlerCA( + IN MSIHANDLE hInstall, + IN CA_DATA_WRITER * cadata + ) +{ + + HRESULT hr = NOERROR; + UINT status = ERROR_SUCCESS; + + MSIHANDLE hDatabase = NULL; + MSIHANDLE hView = NULL; + MSIHANDLE hRecord = NULL; + + STACK_STRU( strData, 128 ); + STACK_STRU( strComponent, 128 ); + + + CONST WCHAR * szQuery = + L"SELECT " + L"`IISGlobalHandler`.`Name`, " + L"`IISGlobalHandler`.`Component_`, " + L"`IISGlobalHandler`.`Path`, " + L"`IISGlobalHandler`.`Verb`, " + L"`IISGlobalHandler`.`Type`, " + L"`IISGlobalHandler`.`Index`, " + L"`IISGlobalHandler`.`Modules`, " + L"`IISGlobalHandler`.`ScriptProcessor`, " + L"`IISGlobalHandler`.`ResourceType`, " + L"`IISGlobalHandler`.`RequiredAccess`, " + L"`IISGlobalHandler`.`PreCondition` " + L"FROM `IISGlobalHandler` "; + + enum { CA_HANDLER_NAME = 1, + CA_HANDLER_COMPONENT, + CA_HANDLER_PATH, + CA_HANDLER_VERB, + CA_HANDLER_TYPE, + CA_HANDLER_INDEX, + CA_HANDLER_MODULES, + CA_HANDLER_SCRIPTPROCESSOR, + CA_HANDLER_RESOURCETYPE, + CA_HANDLER_REQUIREDACCESS, + CA_HANDLER_PRECONDITION + }; + + INSTALLSTATE installStateCurrent; + INSTALLSTATE installStateAction; + + hDatabase = MsiGetActiveDatabase( hInstall ); + if ( !hDatabase ) + { + hr = E_UNEXPECTED; + DBGERROR_HR(hr); + goto exit; + } + + // + //Does table exist + // + UINT er = ERROR_SUCCESS; + er = ::MsiDatabaseIsTablePersistentW(hDatabase, L"IISGlobalHandler"); + if (MSICONDITION_TRUE != er) + { + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' Table not found, exiting", + UNITEXT(__FUNCTION__) + ); + goto exit; + } + + status = MsiDatabaseOpenViewW( hDatabase, szQuery, &hView ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + DBGERROR_HR(hr); + goto exit; + } + + status = MsiViewExecute( hView, NULL ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + DBGERROR_HR(hr); + goto exit; + } + + while ( ERROR_SUCCESS == MsiViewFetch( hView, &hRecord ) ) + { + hr = MsiUtilRecordGetString( hRecord, + CA_HANDLER_COMPONENT, + &strComponent ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + status = MsiGetComponentStateW( hInstall, + strComponent.QueryStr(), + &installStateCurrent, + &installStateAction ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32(status); + DBGERROR_HR(hr); + goto exit; + } + + if ( MsiUtilIsInstalling( installStateCurrent, installStateAction ) || + MsiUtilIsReInstalling( installStateCurrent, installStateAction ) ) + { + + cadata->Write( IIS_INSTALL_HANDLER ); + + // Get the Handler name + hr = MsiUtilRecordGetString( hRecord, + CA_HANDLER_NAME, + &strData ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Write( strData.QueryStr(), strData.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + // + // Get handler Path + // + + hr = MsiUtilRecordGetString( hRecord, + CA_HANDLER_PATH, + &strData ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Write( strData.QueryStr(), strData.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + // + //Get handler Verb + // + hr = MsiUtilRecordGetString( hRecord, + CA_HANDLER_VERB, + &strData ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Write( strData.QueryStr(), strData.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + // + // Get handler Type + // + hr = MsiUtilRecordGetString( hRecord, + CA_HANDLER_TYPE, + &strData ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Write( strData.QueryStr(), strData.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + // + // Get handler Index + // + hr = MsiUtilRecordGetString( hRecord, + CA_HANDLER_INDEX, + &strData ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Write( strData.QueryStr(), strData.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + // + // Get handler Modules + // + hr = MsiUtilRecordGetString( hRecord, + CA_HANDLER_MODULES, + &strData ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Write( strData.QueryStr(), strData.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + // + // Get handler Script Processor + // + hr = MsiUtilRecordGetString( hRecord, + CA_HANDLER_SCRIPTPROCESSOR, + &strData ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Write( strData.QueryStr(), strData.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + // + // Get handler ResourceType + // + hr = MsiUtilRecordGetString( hRecord, + CA_HANDLER_RESOURCETYPE, + &strData ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Write( strData.QueryStr(), strData.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + // + // Get handler RequiredAccess + // + hr = MsiUtilRecordGetString( hRecord, + CA_HANDLER_REQUIREDACCESS, + &strData ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Write( strData.QueryStr(), strData.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + // + // Get handler PreCondition + // + hr = MsiUtilRecordGetString( hRecord, + CA_HANDLER_PRECONDITION, + &strData ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Write( strData.QueryStr(), strData.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + } + + if ( hRecord ) + { + MsiCloseHandle( hRecord ); + hRecord = NULL; + } + } + + +exit: + + if ( hRecord ) + { + MsiCloseHandle( hRecord ); + hRecord = NULL; + } + + if ( hView ) + { + MsiCloseHandle( hView ); + hView = NULL; + } + + if ( hDatabase ) + { + MsiCloseHandle( hDatabase ); + hDatabase = NULL; + } + + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' completed with return code hr=0x%x", + UNITEXT(__FUNCTION__), + hr ); + + return hr; +} + + +HRESULT +ScheduleUnInstallHandlerCA( + IN MSIHANDLE hInstall, + IN CA_DATA_WRITER * cadata + ) +{ + HRESULT hr = NOERROR; + UINT status = ERROR_SUCCESS; + + MSIHANDLE hDatabase = NULL; + MSIHANDLE hView = NULL; + MSIHANDLE hRecord = NULL; + + STACK_STRU( strData, 128 ); + + CONST WCHAR * szQuery = + L"SELECT " + L"`IISGlobalHandler`.`Name`, " + L"`IISGlobalHandler`.`Component_` " + L"FROM `IISGlobalHandler` "; + + enum { CA_HANDLER_NAME = 1, + CA_HANDLER_COMPONENT + }; + + + INSTALLSTATE installStateCurrent; + INSTALLSTATE installStateAction; + + hDatabase = MsiGetActiveDatabase( hInstall ); + if ( !hDatabase ) + { + hr = E_UNEXPECTED; + DBGERROR_HR(hr); + goto exit; + } + // + //Does table exist + // + UINT er = ERROR_SUCCESS; + er = ::MsiDatabaseIsTablePersistentW(hDatabase, L"IISGlobalHandler"); + if (MSICONDITION_TRUE != er) + { + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' Table not found, exiting", + UNITEXT(__FUNCTION__) + ); + goto exit; + } + + status = MsiDatabaseOpenViewW( hDatabase, szQuery, &hView ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + DBGERROR_HR(hr); + goto exit; + } + + status = MsiViewExecute( hView, NULL ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + DBGERROR_HR(hr); + goto exit; + } + + while ( ERROR_SUCCESS == MsiViewFetch( hView, &hRecord ) ) + { + hr = MsiUtilRecordGetString( hRecord, + CA_HANDLER_COMPONENT, + &strData ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + status = MsiGetComponentStateW( hInstall, + strData.QueryStr(), + &installStateCurrent, + &installStateAction ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32(status); + DBGERROR_HR(hr); + goto exit; + } + + if ( MsiUtilIsUnInstalling( installStateCurrent, installStateAction ) ) + { + + cadata->Write( IIS_UNINSTALL_HANDLER ); + + hr = MsiUtilRecordGetString( hRecord, + CA_HANDLER_NAME, + &strData ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Write( strData.QueryStr(), strData.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + } + + if ( hRecord ) + { + MsiCloseHandle( hRecord ); + hRecord = NULL; + } + } + + +exit: + + if ( hRecord ) + { + MsiCloseHandle( hRecord ); + hRecord = NULL; + } + + if ( hView ) + { + MsiCloseHandle( hView ); + hView = NULL; + } + + if ( hDatabase ) + { + MsiCloseHandle( hDatabase ); + hDatabase = NULL; + } + + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' completed with return code hr=0x%x", + UNITEXT(__FUNCTION__), + hr ); + + + return hr; +} + + +HRESULT +ExecuteInstallHandlerCA( + IN CA_DATA_READER * cadata + ) +{ + HRESULT hr = NOERROR; + + WCHAR * szName = NULL; + WCHAR * szPath = NULL; + WCHAR * szVerb = NULL; + WCHAR * szType = NULL; + WCHAR * szIndex = NULL; + WCHAR * szModules = NULL; + WCHAR * szScriptProcessor = NULL; + WCHAR * szResourceType = NULL; + WCHAR * szRequiredAccess = NULL; + WCHAR * szPreCondition = NULL; + + ULONG ulIndex = HANDLER_INDEX_FIRST; + + CComPtr pAdminMgr; + + + hr = CoCreateInstance(__uuidof(AppHostWritableAdminManager), + NULL, + CLSCTX_INPROC_SERVER, + __uuidof(IAppHostWritableAdminManager), + (VOID **)&pAdminMgr); + if (FAILED(hr)) + { + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, + L"CoCreateInstance failed 0x%08x", hr); + DBGERROR_HR(hr); + goto exit; + } + + + hr = cadata->Read( &szName ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + hr = cadata->Read( &szPath ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Read( &szVerb ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Read( &szType ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Read( &szIndex ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + if( 0 == _wcsicmp( szIndex, L"FIRST" ) ) + { + ulIndex = HANDLER_INDEX_FIRST; + } + else if ( 0 == _wcsicmp( szIndex, L"LAST" ) ) + { + ulIndex = HANDLER_INDEX_FIRST; + } + else if ( 0 == _wcsicmp( szIndex, L"BEFORE_STATICFILE" ) ) + { + ulIndex = HANDLER_INDEX_BEFORE_STATICFILE; + } + + hr = cadata->Read( &szModules ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Read( &szScriptProcessor ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Read( &szResourceType ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Read( &szRequiredAccess ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Read( &szPreCondition ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + // + // Install the Handler + // + hr = RegisterHandler( pAdminMgr, + ROOT_CONFIG_PATH, + ulIndex, + szName, + szPath, + szVerb, + szType, + szModules, + szScriptProcessor, + szResourceType, + szRequiredAccess, + szPreCondition + ); + + if ( hr == HRESULT_FROM_WIN32( ERROR_ALREADY_EXISTS ) ) + { + // + // We'll quietly accept a handler already exists. + // + IISLogWrite(SETUP_LOG_SEVERITY_INFORMATION, + L"Handler: '%s' already installed.", + szName); + + hr = S_OK; + } + + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + if ( HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr ) + { + hr = S_OK; + } + + // + // Update config + // + hr = pAdminMgr->CommitChanges(); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + +exit: + + + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' completed with return code hr=0x%x", + UNITEXT(__FUNCTION__), + hr ); + + + return hr; +} + + +HRESULT +ExecuteUnInstallHandlerCA( + IN CA_DATA_READER * cadata + ) +{ + HRESULT hr = NOERROR; + + WCHAR * szName = NULL; + + CComPtr pAdminMgr; + + + hr = CoCreateInstance(__uuidof(AppHostWritableAdminManager), + NULL, + CLSCTX_INPROC_SERVER, + __uuidof(IAppHostWritableAdminManager), + (VOID **)&pAdminMgr); + if (FAILED(hr)) + { + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, + L"CoCreateInstance failed 0x%08x", hr); + DBGERROR_HR(hr); + goto exit; + } + + + hr = cadata->Read( &szName ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + hr = UnRegisterHandler( pAdminMgr, ROOT_CONFIG_PATH, szName ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + if ( HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr ) + { + hr = S_OK; + } + + // + // Update config + // + hr = pAdminMgr->CommitChanges(); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + +exit: + + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' completed with return code hr=0x%x", + UNITEXT(__FUNCTION__), + hr ); + + + return hr; +} + +HRESULT +ScheduleInstallSectionDefaultsCA( + IN MSIHANDLE hInstall, + IN CA_DATA_WRITER * cadata + ) +{ + + HRESULT hr = NOERROR; + UINT status = ERROR_SUCCESS; + + MSIHANDLE hDatabase = NULL; + MSIHANDLE hView = NULL; + MSIHANDLE hRecord = NULL; + + STACK_STRU( strData, 128 ); + STACK_STRU( strComponent, 128 ); + STACK_STRU( strName, 128 ); + + CONST WCHAR * szQuery = + L"SELECT " + L"`IISConfigSectionDefaults`.`Name`, " + L"`IISConfigSectionDefaults`.`SectionName`, " + L"`IISConfigSectionDefaults`.`Component_`, " + L"`Binary`.`Data` " + L"FROM `IISConfigSectionDefaults`, `Binary` " + L"WHERE `IISConfigSectionDefaults`.`BinaryName_`=`Binary`.`Name`"; + + + enum { CA_DEFAULTS_NAME = 1, + CA_DEFAULTS_SECTIONNAME, + CA_DEFAULTS_COMPONENT, + CA_DEFAULTS_BINARYDATA + }; + + INSTALLSTATE installStateCurrent; + INSTALLSTATE installStateAction; + + + hDatabase = MsiGetActiveDatabase( hInstall ); + if ( !hDatabase ) + { + hr = E_UNEXPECTED; + DBGERROR_HR(hr); + goto exit; + } + // + //Does table exist + // + UINT er = ERROR_SUCCESS; + er = ::MsiDatabaseIsTablePersistentW(hDatabase, L"IISConfigSectionDefaults"); + if (MSICONDITION_TRUE != er) + { + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' Table not found, exiting", + UNITEXT(__FUNCTION__) + ); + goto exit; + } + + + status = MsiDatabaseOpenViewW( hDatabase, szQuery, &hView ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + DBGERROR_HR(hr); + goto exit; + } + + status = MsiViewExecute( hView, NULL ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + DBGERROR_HR(hr); + goto exit; + } + + while ( ERROR_SUCCESS == MsiViewFetch( hView, &hRecord ) ) + { + hr = MsiUtilRecordGetString( hRecord, + CA_DEFAULTS_COMPONENT, + &strComponent ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + status = MsiGetComponentStateW( hInstall, + strComponent.QueryStr(), + &installStateCurrent, + &installStateAction ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32(status); + DBGERROR_HR(hr); + goto exit; + } + + if ( MsiUtilIsInstalling( installStateCurrent, installStateAction ) || + MsiUtilIsReInstalling( installStateCurrent, installStateAction ) ) + { + + cadata->Write( IIS_INSTALL_DEFAULTS ); + + // Get the record name + hr = MsiUtilRecordGetString( hRecord, + CA_DEFAULTS_NAME, + &strName ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + // Get the Section name + hr = MsiUtilRecordGetString( hRecord, + CA_DEFAULTS_SECTIONNAME, + &strData ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Write( strData.QueryStr(), strData.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + // + // Get File from binary, write to temp file + // + STACK_STRU( strFilePath, MAX_PATH * 2 ); + + hr = GenerateTempFileName ( strName.QueryStr(), + L"def", + &strFilePath); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error generating temp file name for the hotfix, hr=0x%x", hr); + goto exit; + } + + hr = MsiUtilRecordReadStreamIntoFile ( hRecord, + CA_DEFAULTS_BINARYDATA, + strFilePath.QueryStr()); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error streaming binary data into file, hr=0x%x", hr); + goto exit; + } + + hr = cadata->Write( strFilePath.QueryStr(), strFilePath.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error writing custom action data, hr=0x%x", hr); + goto exit; + } + } + + if ( hRecord ) + { + MsiCloseHandle( hRecord ); + hRecord = NULL; + } + } + + +exit: + + if ( hRecord ) + { + MsiCloseHandle( hRecord ); + hRecord = NULL; + } + + if ( hView ) + { + MsiCloseHandle( hView ); + hView = NULL; + } + + if ( hDatabase ) + { + MsiCloseHandle( hDatabase ); + hDatabase = NULL; + } + + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' completed with return code hr=0x%x", + UNITEXT(__FUNCTION__), + hr ); + + + return hr; + +} +HRESULT +ExecuteInstallSectionDefaultsCA( + IN CA_DATA_READER * cadata + ) +{ + HRESULT hr = NOERROR; + + WCHAR * szSectionName = NULL; + WCHAR * szTempFileName = NULL; + + CComPtr pAdminMgr; + + + hr = CoCreateInstance(__uuidof(AppHostWritableAdminManager), + NULL, + CLSCTX_INPROC_SERVER, + __uuidof(IAppHostWritableAdminManager), + (VOID **)&pAdminMgr); + if (FAILED(hr)) + { + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, + L"CoCreateInstance failed 0x%08x", hr); + DBGERROR_HR(hr); + goto exit; + } + + + hr = cadata->Read( &szSectionName ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + hr = cadata->Read( &szTempFileName ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + // + // Set Section Defaults from temp file created during schedule + // + hr = ResetConfigSectionFromFile( szTempFileName, szSectionName ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + // + // delete temp file. No error checking. + // + ::DeleteFileW( szTempFileName ); + + if ( HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr ) + { + hr = S_OK; + } + + // + // Update config + // + hr = pAdminMgr->CommitChanges(); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + +exit: + + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' completed with return code hr=0x%x", + UNITEXT(__FUNCTION__), + hr ); + + return hr; + +} + +HRESULT +ScheduleInstallSectionAdditionsCA( + IN MSIHANDLE hInstall, + IN CA_DATA_WRITER * cadata + ) +{ + + HRESULT hr = NOERROR; + UINT status = ERROR_SUCCESS; + + MSIHANDLE hDatabase = NULL; + MSIHANDLE hView = NULL; + MSIHANDLE hRecord = NULL; + + STACK_STRU( strData, 128 ); + STACK_STRU( strComponent, 128 ); + STACK_STRU( strName, 128 ); + + CONST WCHAR * szQuery = + L"SELECT " + L"`IISConfigSectionAdditions`.`Name`, " + L"`IISConfigSectionAdditions`.`SectionName`, " + L"`IISConfigSectionAdditions`.`Component_`, " + L"`Binary`.`Data` " + L"FROM `IISConfigSectionAdditions`, `Binary` " + L"WHERE `IISConfigSectionAdditions`.`BinaryName_`=`Binary`.`Name`"; + + + enum { CA_SECTION_ADDITION_NAME = 1, + CA_SECTION_ADDITION_SECTIONNAME, + CA_SECTION_ADDITION_COMPONENT, + CA_SECTION_ADDITION_BINARYDATA + }; + + INSTALLSTATE installStateCurrent; + INSTALLSTATE installStateAction; + + + hDatabase = MsiGetActiveDatabase( hInstall ); + if ( !hDatabase ) + { + hr = E_UNEXPECTED; + DBGERROR_HR(hr); + goto exit; + } + + // + // Does table exist + // + UINT er = ERROR_SUCCESS; + er = ::MsiDatabaseIsTablePersistentW(hDatabase, L"IISConfigSectionAdditions"); + if (MSICONDITION_TRUE != er) + { + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' Table not found, exiting", + UNITEXT(__FUNCTION__) + ); + goto exit; + } + + + status = MsiDatabaseOpenViewW( hDatabase, szQuery, &hView ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + DBGERROR_HR(hr); + goto exit; + } + + status = MsiViewExecute( hView, NULL ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + DBGERROR_HR(hr); + goto exit; + } + + while ( ERROR_SUCCESS == MsiViewFetch( hView, &hRecord ) ) + { + hr = MsiUtilRecordGetString( hRecord, + CA_SECTION_ADDITION_COMPONENT, + &strComponent ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + status = MsiGetComponentStateW( hInstall, + strComponent.QueryStr(), + &installStateCurrent, + &installStateAction ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32(status); + DBGERROR_HR(hr); + goto exit; + } + + if ( MsiUtilIsInstalling( installStateCurrent, installStateAction ) || + MsiUtilIsReInstalling( installStateCurrent, installStateAction ) ) + { + + cadata->Write( IIS_INSTALL_SECTION_ADDITIONS); + + // Get the record name + hr = MsiUtilRecordGetString( hRecord, + CA_SECTION_ADDITION_NAME, + &strName ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + // Get the Section name + hr = MsiUtilRecordGetString( hRecord, + CA_SECTION_ADDITION_SECTIONNAME, + &strData ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = cadata->Write( strData.QueryStr(), strData.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + // + // Get File from binary, write to temp file + // + STACK_STRU( strFilePath, MAX_PATH * 2 ); + + hr = GenerateTempFileName ( strName.QueryStr(), + L"def", + &strFilePath); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error generating temp file name for the hotfix, hr=0x%x", hr); + goto exit; + } + + hr = MsiUtilRecordReadStreamIntoFile ( hRecord, + CA_SECTION_ADDITION_BINARYDATA, + strFilePath.QueryStr()); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error streaming binary data into file, hr=0x%x", hr); + goto exit; + } + + hr = cadata->Write( strFilePath.QueryStr(), strFilePath.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error writing custom action data, hr=0x%x", hr); + goto exit; + } + } + + if ( hRecord ) + { + MsiCloseHandle( hRecord ); + hRecord = NULL; + } + } + + +exit: + + if ( hRecord ) + { + MsiCloseHandle( hRecord ); + hRecord = NULL; + } + + if ( hView ) + { + MsiCloseHandle( hView ); + hView = NULL; + } + + if ( hDatabase ) + { + MsiCloseHandle( hDatabase ); + hDatabase = NULL; + } + + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' completed with return code hr=0x%x", + UNITEXT(__FUNCTION__), + hr ); + + + return hr; + +} +HRESULT +ExecuteInstallSectionAdditionsCA( + IN CA_DATA_READER * cadata + ) +{ + HRESULT hr = NOERROR; + + WCHAR * szSectionName = NULL; + WCHAR * szTempFileName = NULL; + + CComPtr pAdminMgr; + + + hr = CoCreateInstance(__uuidof(AppHostWritableAdminManager), + NULL, + CLSCTX_INPROC_SERVER, + __uuidof(IAppHostWritableAdminManager), + (VOID **)&pAdminMgr); + if (FAILED(hr)) + { + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, + L"CoCreateInstance failed 0x%08x", hr); + DBGERROR_HR(hr); + goto exit; + } + + + hr = cadata->Read( &szSectionName ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + hr = cadata->Read( &szTempFileName ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + // + // Set Section Defaults from temp file created during schedule + // + hr = AppendConfigSectionFromFile( szTempFileName, szSectionName ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + // + // delete temp file. No error checking. + // + ::DeleteFileW( szTempFileName ); + + if ( HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr ) + { + hr = S_OK; + } + + // + // Update config + // + hr = pAdminMgr->CommitChanges(); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + +exit: + + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' completed with return code hr=0x%x", + UNITEXT(__FUNCTION__), + hr ); + + return hr; + +} + +HRESULT +ScheduleInstallCgiRestrictionsCA( + IN MSIHANDLE hInstall, + IN CA_DATA_WRITER * cadata + ) +{ + + HRESULT hr = NOERROR; + UINT status = ERROR_SUCCESS; + + MSIHANDLE hDatabase = NULL; + MSIHANDLE hView = NULL; + MSIHANDLE hRecord = NULL; + + STACK_STRU( strData, 128 ); + STACK_STRU( strComponent, 128 ); + STACK_STRU( strName, 128 ); + + CONST WCHAR * szQuery = + L"SELECT " + L"`IISCgiRestriction`.`Name`, " + L"`IISCgiRestriction`.`Component_`, " + L"`IISCgiRestriction`.`Path`, " + L"`IISCgiRestriction`.`Allowed`, " + L"`IISCgiRestriction`.`GroupId`, " + L"`IISCgiRestriction`.`Description` " + L"FROM `IISCgiRestriction` "; + + enum { CA_CGI_NAME = 1, + CA_CGI_COMPONENT, + CA_CGI_PATH, + CA_CGI_ALLOWED, + CA_CGI_GROUPID, + CA_CGI_DESC + }; + + INSTALLSTATE installStateCurrent; + INSTALLSTATE installStateAction; + + + hDatabase = MsiGetActiveDatabase( hInstall ); + if ( !hDatabase ) + { + hr = E_UNEXPECTED; + DBGERROR_HR(hr); + goto exit; + } + // + //Does table exist + // + UINT er = ERROR_SUCCESS; + er = ::MsiDatabaseIsTablePersistentW(hDatabase, L"IISCgiRestriction"); + if (MSICONDITION_TRUE != er) + { + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' Table not found, exiting", + UNITEXT(__FUNCTION__) + ); + goto exit; + } + + cadata->Write( IIS_INSTALL_CGIRESTRICTIONS ); + + status = MsiDatabaseOpenViewW( hDatabase, szQuery, &hView ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + DBGERROR_HR(hr); + goto exit; + } + + status = MsiViewExecute( hView, NULL ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + DBGERROR_HR(hr); + goto exit; + } + + while ( ERROR_SUCCESS == MsiViewFetch( hView, &hRecord ) ) + { + hr = MsiUtilRecordGetString( hRecord, + CA_CGI_COMPONENT, + &strComponent ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + status = MsiGetComponentStateW( hInstall, + strComponent.QueryStr(), + &installStateCurrent, + &installStateAction ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32(status); + DBGERROR_HR(hr); + goto exit; + } + + if ( MsiUtilIsInstalling( installStateCurrent, installStateAction ) || + MsiUtilIsReInstalling( installStateCurrent, installStateAction ) ) + { + + // Get the Path + hr = MsiUtilRecordGetString( hRecord, + CA_CGI_PATH, + &strData ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + hr = cadata->Write( strData.QueryStr(), strData.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + // Get the Allowed + hr = MsiUtilRecordGetString( hRecord, + CA_CGI_ALLOWED, + &strData ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + hr = cadata->Write( strData.QueryStr(), strData.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + // Get the GroupId + hr = MsiUtilRecordGetString( hRecord, + CA_CGI_GROUPID, + &strData ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + hr = cadata->Write( strData.QueryStr(), strData.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + // Get the Description + hr = MsiUtilRecordGetString( hRecord, + CA_CGI_DESC, + &strData ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + hr = cadata->Write( strData.QueryStr(), strData.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + } + + if ( hRecord ) + { + MsiCloseHandle( hRecord ); + hRecord = NULL; + } + } + + +exit: + + if ( hRecord ) + { + MsiCloseHandle( hRecord ); + hRecord = NULL; + } + + if ( hView ) + { + MsiCloseHandle( hView ); + hView = NULL; + } + + if ( hDatabase ) + { + MsiCloseHandle( hDatabase ); + hDatabase = NULL; + } + + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' completed with return code hr=0x%x", + UNITEXT(__FUNCTION__), + hr ); + + return hr; + +} + +HRESULT +ScheduleUnInstallCgiRestrictionsCA( + IN MSIHANDLE hInstall, + IN CA_DATA_WRITER * cadata + ) +{ + + HRESULT hr = NOERROR; + UINT status = ERROR_SUCCESS; + + MSIHANDLE hDatabase = NULL; + MSIHANDLE hView = NULL; + MSIHANDLE hRecord = NULL; + + STACK_STRU( strData, 128 ); + STACK_STRU( strComponent, 128 ); + STACK_STRU( strName, 128 ); + + CONST WCHAR * szQuery = + L"SELECT " + L"`IISCgiRestriction`.`Name`, " + L"`IISCgiRestriction`.`Component_`, " + L"`IISCgiRestriction`.`Path`, " + L"FROM `IISCgiRestriction` "; + + enum { CA_CGI_NAME = 1, + CA_CGI_COMPONENT, + CA_CGI_PATH, + CA_CGI_ALLOWED, + CA_CGI_GROUPID, + CA_CGI_DESC + }; + + INSTALLSTATE installStateCurrent; + INSTALLSTATE installStateAction; + + hDatabase = MsiGetActiveDatabase( hInstall ); + if ( !hDatabase ) + { + hr = E_UNEXPECTED; + DBGERROR_HR(hr); + goto exit; + } + // + //Does table exist + // + UINT er = ERROR_SUCCESS; + er = ::MsiDatabaseIsTablePersistentW(hDatabase, L"IISCgiRestriction"); + if (MSICONDITION_TRUE != er) + { + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' Table not found, exiting", + UNITEXT(__FUNCTION__) + ); + goto exit; + } + + + cadata->Write( IIS_UNINSTALL_CGIRESTRICTIONS ); + + status = MsiDatabaseOpenViewW( hDatabase, szQuery, &hView ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + DBGERROR_HR(hr); + goto exit; + } + + status = MsiViewExecute( hView, NULL ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + DBGERROR_HR(hr); + goto exit; + } + + while ( ERROR_SUCCESS == MsiViewFetch( hView, &hRecord ) ) + { + hr = MsiUtilRecordGetString( hRecord, + CA_CGI_COMPONENT, + &strComponent ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + status = MsiGetComponentStateW( hInstall, + strComponent.QueryStr(), + &installStateCurrent, + &installStateAction ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32(status); + DBGERROR_HR(hr); + goto exit; + } + + if ( MsiUtilIsUnInstalling( installStateCurrent, installStateAction ) ) + { + + // Get the Path + hr = MsiUtilRecordGetString( hRecord, + CA_CGI_PATH, + &strData ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + hr = cadata->Write( strData.QueryStr(), strData.QueryCCH() ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + } + + if ( hRecord ) + { + MsiCloseHandle( hRecord ); + hRecord = NULL; + } + } + + +exit: + + if ( hRecord ) + { + MsiCloseHandle( hRecord ); + hRecord = NULL; + } + + if ( hView ) + { + MsiCloseHandle( hView ); + hView = NULL; + } + + if ( hDatabase ) + { + MsiCloseHandle( hDatabase ); + hDatabase = NULL; + } + + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' completed with return code hr=0x%x", + UNITEXT(__FUNCTION__), + hr ); + + + return hr; + +} + + +HRESULT +ExecuteInstallCgiRestrictionsCA( + IN CA_DATA_READER * cadata + ) +{ + HRESULT hr = NOERROR; + + WCHAR * szPath = NULL; + WCHAR * szAllowed = NULL; + WCHAR * szGroupId = NULL; + WCHAR * szDescription = NULL; + BOOL fAllowed = FALSE; + + CComPtr pAdminMgr; + + + hr = CoCreateInstance(__uuidof(AppHostWritableAdminManager), + NULL, + CLSCTX_INPROC_SERVER, + __uuidof(IAppHostWritableAdminManager), + (VOID **)&pAdminMgr); + if (FAILED(hr)) + { + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, + L"CoCreateInstance failed 0x%08x", hr); + DBGERROR_HR(hr); + goto exit; + } + + + while ( SUCCEEDED(hr = cadata->Read( &szPath )) ) + { + + hr = cadata->Read( &szAllowed ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + hr = cadata->Read( &szGroupId ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + hr = cadata->Read( &szDescription ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + if ( 0 == wcscmp( szAllowed, L"true" ) ) + { + fAllowed = TRUE; + } + else if ( 0 == wcscmp( szAllowed, L"false" ) ) + { + fAllowed = FALSE; + } + + hr = RegisterCgiRestriction( + pAdminMgr, + ROOT_CONFIG_PATH, + szPath, + fAllowed, + szGroupId, + szDescription + ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + } + + if ( HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr ) + { + hr = S_OK; + } + + // + // Update config + // + hr = pAdminMgr->CommitChanges(); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + +exit: + + + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' completed with return code hr=0x%x", + UNITEXT(__FUNCTION__), + hr ); + + return hr; + +} + + +HRESULT +ExecuteUnInstallCgiRestrictionsCA( + IN CA_DATA_READER * cadata + ) +{ + HRESULT hr = NOERROR; + + WCHAR * szPath = NULL; + + CComPtr pAdminMgr; + + + hr = CoCreateInstance(__uuidof(AppHostWritableAdminManager), + NULL, + CLSCTX_INPROC_SERVER, + __uuidof(IAppHostWritableAdminManager), + (VOID **)&pAdminMgr); + if (FAILED(hr)) + { + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, + L"CoCreateInstance failed 0x%08x", hr); + DBGERROR_HR(hr); + goto exit; + } + + + while ( SUCCEEDED(hr = cadata->Read( &szPath )) ) + { + hr = UnRegisterCgiRestriction( + pAdminMgr, + ROOT_CONFIG_PATH, + szPath, + FALSE + ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + hr = S_OK; + } + } + + if ( HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr ) + { + hr = S_OK; + } + + // + // Update config + // + hr = pAdminMgr->CommitChanges(); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + +exit: + + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' completed with return code hr=0x%x", + UNITEXT(__FUNCTION__), + hr ); + + return hr; +} + + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/iisca.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/iisca.h new file mode 100644 index 0000000000..40f7097845 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/iisca.h @@ -0,0 +1,255 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#pragma once + +#define _UNITEXT(quote) L##quote +#define UNITEXT(quote) _UNITEXT(quote) + + +// IIS Custom action Types +enum IIS_COSTOM_ACTION_TYPE +{ + IIS_INSTALL_MODULE = 1, + IIS_UNINSTALL_MODULE, + IIS_INSTALL_UIMODULE, + IIS_UNINSTALL_UIMODULE, + IIS_INSTALL_HANDLER, + IIS_UNINSTALL_HANDLER, + IIS_INSTALL_SECTIONSCHEMA, + IIS_UNINSTALL_SECTIONSCHEMA, + IIS_INSTALL_TRACEAREA, + IIS_INSTALL_MOFFILE, + IIS_INSTALL_DEFAULTS, + IIS_INSTALL_SECTION_ADDITIONS, + IIS_INSTALL_CGIRESTRICTIONS, + IIS_UNINSTALL_CGIRESTRICTIONS, + IIS_INSTALL_, + IIS_UNINSTALL_, + IIS_END +}; + + +HRESULT +InstallModule( + IN CONST WCHAR * szName, + IN CONST WCHAR * szImage, + IN OPTIONAL CONST WCHAR * szPreCondition, + IN OPTIONAL CONST WCHAR * szTYpe + ); + + +HRESULT +UnInstallModule( + IN CONST WCHAR * szName, + IN OPTIONAL CONST WCHAR * szPreCondition + ); + +HRESULT +RegisterSectionSchema( + IN CONST BOOL isSectionInAdminSchema, + IN CONST WCHAR * szSectionName, + IN CONST WCHAR * szOverideModeDefault, + IN OPTIONAL CONST WCHAR * szAllowDefinition, + IN OPTIONAL CONST WCHAR * szType + ); + +HRESULT +UnRegisterSectionSchema( + IN CONST BOOL isSectionInAdminSchema, + IN CONST WCHAR * szSectionName + ); + +HRESULT +RegisterUIModule( + IN CONST WCHAR * szModuleName, + IN CONST WCHAR * szModuleTypeInfo, + IN OPTIONAL CONST WCHAR * szRegisterInModulesSection, + IN OPTIONAL CONST WCHAR * szPrependToList + ); + +HRESULT +UnRegisterUIModule( + IN CONST WCHAR * szModuleName, + IN CONST WCHAR * szModuleTypeInfo + ); + +UINT +WINAPI +CheckForAdminSIDCA( + MSIHANDLE hInstall + ); + +UINT +LogMsiCustomActionError( + IN MSIHANDLE hInstall, + UINT messageId + ); + +HRESULT +InitAdminMgrForAdminConfig( + IN IAppHostWritableAdminManager * pAdminMgr, + IN CONST WCHAR * szCommitPath +); + +HRESULT +RegisterMofFile( + IN PWSTR pszFileName +); + +HRESULT +ScheduleInstallModuleCA( + IN MSIHANDLE hInstall, + IN CA_DATA_WRITER * cadata +); + +HRESULT +ScheduleUnInstallModuleCA( + IN MSIHANDLE hInstall, + IN CA_DATA_WRITER * cadata +); + +HRESULT +ExecuteInstallModuleCA( + IN CA_DATA_READER * cadata +); + +HRESULT +ExecuteUnInstallModuleCA( + IN CA_DATA_READER * cadata +); + + +HRESULT +ExecuteUnRegisterUIModuleCA( + IN CA_DATA_READER * cadata +); + + +HRESULT +ScheduleRegisterUIModuleCA( + IN MSIHANDLE hInstall, + IN CA_DATA_WRITER * cadata +); +HRESULT +ExecuteRegisterUIModuleCA( + IN CA_DATA_READER * cadata +); + +HRESULT +ScheduleUnRegisterUIModuleCA( + IN MSIHANDLE hInstall, + IN CA_DATA_WRITER * cadata +); + + +HRESULT +ScheduleInstallHandlerCA( + IN MSIHANDLE hInstall, + IN CA_DATA_WRITER * cadata + ); + +HRESULT +ScheduleUnInstallHandlerCA( + IN MSIHANDLE hInstall, + IN CA_DATA_WRITER * cadata + ); + +HRESULT +ExecuteInstallHandlerCA( + IN CA_DATA_READER * cadata + ); + +HRESULT +ExecuteUnInstallHandlerCA( + IN CA_DATA_READER * cadata + ); + +HRESULT +ExecuteUnRegisterSectionSchemaCA( + IN CA_DATA_READER * cadata +); + + +HRESULT +ScheduleRegisterSectionSchemaCA( + IN MSIHANDLE hInstall, + IN CA_DATA_WRITER * cadata +); + +HRESULT +ExecuteRegisterSectionSchemaCA( + IN CA_DATA_READER * cadata +); + +HRESULT +ScheduleUnRegisterSectionSchemaCA( + IN MSIHANDLE hInstall, + IN CA_DATA_WRITER * cadata +); + +HRESULT +ScheduleRegisterTraceAreaCA( + IN MSIHANDLE hInstall, + IN CA_DATA_WRITER * cadata +); + +HRESULT +ExecuteRegisterTraceAreaCA( + IN CA_DATA_READER * cadata +); + +HRESULT +ScheduleRegisterMofFileCA( + IN MSIHANDLE hInstall, + IN CA_DATA_WRITER * cadata +); + +HRESULT +ExecuteRegisterMofFileCA( + IN CA_DATA_READER * cadata +); + +HRESULT +ScheduleInstallSectionDefaultsCA( + IN MSIHANDLE hInstall, + IN CA_DATA_WRITER * cadata +); + +HRESULT +ExecuteInstallSectionDefaultsCA( + IN CA_DATA_READER * cadata +); + +HRESULT +ScheduleInstallSectionAdditionsCA( + IN MSIHANDLE hInstall, + IN CA_DATA_WRITER * cadata +); + +HRESULT +ExecuteInstallSectionAdditionsCA( + IN CA_DATA_READER * cadata +); + +HRESULT +ScheduleInstallCgiRestrictionsCA( + IN MSIHANDLE hInstall, + IN CA_DATA_WRITER * cadata +); + +HRESULT +ScheduleUnInstallCgiRestrictionsCA( + IN MSIHANDLE hInstall, + IN CA_DATA_WRITER * cadata +); + +HRESULT +ExecuteInstallCgiRestrictionsCA( + IN CA_DATA_READER * cadata +); + +HRESULT +ExecuteUnInstallCgiRestrictionsCA( + IN CA_DATA_READER * cadata +); diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/iisca.vcxproj b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/iisca.vcxproj new file mode 100644 index 0000000000..aced7ff216 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/iisca.vcxproj @@ -0,0 +1,131 @@ + + + + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {b54a8f61-60de-4ad9-87ca-d102f230678e} + + + + {7324770c-0871-4d73-be3d-5e2f3e9e1b1e} + Win32Proj + iisca + + + + StaticLibrary + Unicode + v141 + + + + $(IIS-Common)version;$(IIS-Common)Include;$(AdditionalIncludeDirectories) + Create + precomp.h + $(IntDir)precomp.pch + + + + $(WIX)sdk\$(WixPlatformToolset)\inc;$(AdditionalIncludeDirectories) + Level4 + + + nothrownew.obj;httpapi.lib;shlwapi.lib;ahadmin.lib;xmllite.lib;msi.lib;dutil.lib;wcautil.lib;Version.lib;%(AdditionalDependencies) + CustomAction.def + Windows + + + + + _DEBUG;_WINDOWS;_USRDLL;CUSTOMACTIONTEST_EXPORTS;%(PreprocessorDefinitions) + + + + + MaxSpeed + + + true + + + + + $(VC_ReferencesPath_x86);$(WindowsSDK_LibraryPath)\$(PlatformTarget);$(WIX)sdk\$(WixPlatformToolset)\lib\x86;%(AdditionalLibraryDirectories) + MachineX86 + + + + + $(VC_ReferencesPath_x64);$(WindowsSDK_LibraryPath)\$(PlatformTarget);$(WIX)sdk\$(WixPlatformToolset)\lib\x64;%(AdditionalLibraryDirectories) + Machinex64 + + + + + + This project is trying to import a missing file: {0}. + + + + + + \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/iiscaexp.cpp b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/iiscaexp.cpp new file mode 100644 index 0000000000..e407497402 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/iiscaexp.cpp @@ -0,0 +1,791 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#include "precomp.h" + + + +#define IIS_CONFIG_BACKUP_EXT L"IISOOBBACK" + + +typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); + +LPFN_ISWOW64PROCESS fnIsWow64Process; + +BOOL IsWow64() +{ + BOOL bIsWow64 = FALSE; + + //IsWow64Process is not available on all supported versions of Windows. + //Use GetModuleHandle to get a handle to the DLL that contains the function + //and GetProcAddress to get a pointer to the function if available. + + fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress( + GetModuleHandle(TEXT("kernel32")),"IsWow64Process"); + + if(NULL != fnIsWow64Process) + { + if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64)) + { + //handle error + } + } + return bIsWow64; +} + +/******************************************************************** +IISScheduleInstall CA - CUSTOM ACTION ENTRY POINT for reading IIS custom +table settings into CA Data + +********************************************************************/ +UINT +WINAPI +IISScheduleInstallCA( + IN MSIHANDLE hInstall + ) +{ + HRESULT hr = S_OK; + CA_DATA_WRITER cadata; + BOOL bWriteToShared = FALSE; + BOOL fCoInit = FALSE; + + IISLogInitialize(hInstall, UNITEXT(__FUNCTION__)); + + if ( SUCCEEDED( CoInitializeEx( NULL, COINIT_MULTITHREADED ) ) ) + { + fCoInit = TRUE; + } + + // + //See if we are going to update shared config + // + hr = CheckInstallToSharedConfig( hInstall, &bWriteToShared ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + if ( !bWriteToShared ) + { + //do not update config for this module + //ExecuteCA will not be scheduled. + } + // + // Schedule transactions + // + hr = MsiUtilScheduleDeferredAction( hInstall, + L"IISBeginTransactionCA", + cadata.QueryData() ); + if ( FAILED(hr) ) + { + goto exit; + } + hr = MsiUtilScheduleDeferredAction( hInstall, + L"IISRollbackTransactionCA", + cadata.QueryData() ); + if ( FAILED(hr) ) + { + goto exit; + } + hr = MsiUtilScheduleDeferredAction( hInstall, + L"IISCommitTransactionCA", + cadata.QueryData() ); + if ( FAILED(hr) ) + { + goto exit; + } + if( bWriteToShared ) + { + // + // Do the Config Install actions + // + hr = ScheduleInstallModuleCA( hInstall, &cadata ); + if ( FAILED(hr) ) + { + goto exit; + } + hr = ScheduleRegisterUIModuleCA( hInstall, &cadata ); + if ( FAILED(hr) ) + { + goto exit; + } + hr = ScheduleInstallHandlerCA( hInstall, &cadata ); + if ( FAILED(hr) ) + { + goto exit; + } + hr = ScheduleRegisterSectionSchemaCA( hInstall, &cadata ); + if ( FAILED(hr) ) + { + goto exit; + } + hr = ScheduleRegisterTraceAreaCA( hInstall, &cadata ); + if ( FAILED(hr) ) + { + goto exit; + } + hr = ScheduleInstallSectionDefaultsCA( hInstall, &cadata ); + if ( FAILED(hr) ) + { + goto exit; + } + hr = ScheduleInstallSectionAdditionsCA( hInstall, &cadata ); + if ( FAILED(hr) ) + { + goto exit; + } + hr = ScheduleInstallCgiRestrictionsCA( hInstall, &cadata ); + if ( FAILED(hr) ) + { + goto exit; + } + } + + // + // Do the Non-Config Install actions + // + hr = ScheduleRegisterMofFileCA( hInstall, &cadata ); + if ( FAILED(hr) ) + { + goto exit; + } + + + // + // Schedule deferred execute CA + // + + hr = MsiUtilScheduleDeferredAction( hInstall, + L"IISExecuteCA", + cadata.QueryData() ); + if ( FAILED(hr) ) + { + goto exit; + } + + hr = NOERROR; + + +exit: + if ( fCoInit ) + { + CoUninitialize(); + } + + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' completed with return code hr=0x%x", + UNITEXT(__FUNCTION__), + hr ); + + IISLogClose(); + + return hr; +} +/******************************************************************** +IISScheduleUninstall CA - CUSTOM ACTION ENTRY POINT for reading IIS custom +table settings into CA Data + +********************************************************************/ +UINT +WINAPI +IISScheduleUninstallCA( + IN MSIHANDLE hInstall + ) +{ + HRESULT hr = S_OK; + CA_DATA_WRITER cadata; + BOOL bWriteToShared = FALSE; + BOOL fCoInit = FALSE; + + IISLogInitialize(hInstall, UNITEXT(__FUNCTION__)); + + if ( SUCCEEDED( CoInitializeEx( NULL, COINIT_MULTITHREADED ) ) ) + { + fCoInit = TRUE; + } + + // + //See if we are going to update shared config + // + hr = CheckInstallToSharedConfig( hInstall, &bWriteToShared ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + if ( !bWriteToShared ) + { + //do not update config for this module + //ExecuteCA will not be scheduled. + } + + if( bWriteToShared ) + { + // + // Do the Config Uninstall actions + // + hr = ScheduleUnInstallModuleCA( hInstall, &cadata ); + if ( FAILED(hr) ) + { + goto exit; + } + hr = ScheduleUnRegisterUIModuleCA( hInstall, &cadata ); + if ( FAILED(hr) ) + { + goto exit; + } + hr = ScheduleUnInstallHandlerCA( hInstall, &cadata ); + if ( FAILED(hr) ) + { + goto exit; + } + hr = ScheduleUnRegisterSectionSchemaCA( hInstall, &cadata ); + if ( FAILED(hr) ) + { + goto exit; + } + hr = ScheduleUnInstallCgiRestrictionsCA( hInstall, &cadata ); + if ( FAILED(hr) ) + { + goto exit; + } + } + // + // Do the Non-Config Uninstall actions + // + + + // + // Schedule deferred execute CA + // + + hr = MsiUtilScheduleDeferredAction( hInstall, + L"IISExecuteCA", + cadata.QueryData() ); + if ( FAILED(hr) ) + { + goto exit; + } + + hr = NOERROR; + + +exit: + if ( fCoInit ) + { + CoUninitialize(); + } + + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' completed with return code hr=0x%x", + UNITEXT(__FUNCTION__), + hr ); + + IISLogClose(); + + // + // Don't fail while uninstalling. + // + return NOERROR; +} +/******************************************************************** +IISExecuteCA - CUSTOM ACTION ENTRY POINT for writing IIS custom +table settings to iis config + +********************************************************************/ +UINT +WINAPI +IISExecuteCA( + IN MSIHANDLE hInstall + ) +{ + HRESULT hr = NOERROR; + CA_DATA_READER cadata; + INT icaType = 0; + BOOL fCoInit = FALSE; + + IISLogInitialize(hInstall, UNITEXT(__FUNCTION__)); + + if ( SUCCEEDED( CoInitializeEx( NULL, COINIT_MULTITHREADED ) ) ) + { + fCoInit = TRUE; + } + // + // Retrieve parameters from ca data + // + + hr = cadata.LoadDeferredCAData( hInstall ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + while ( SUCCEEDED(hr = cadata.Read( &icaType )) ) + { + switch (icaType ) + { + case IIS_INSTALL_MODULE: + { + hr = ExecuteInstallModuleCA( &cadata ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + break; + } + case IIS_UNINSTALL_MODULE: + { + hr = ExecuteUnInstallModuleCA( &cadata ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + break; + } + case IIS_INSTALL_UIMODULE: + { + hr = ExecuteRegisterUIModuleCA( &cadata ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + break; + } + case IIS_UNINSTALL_UIMODULE: + { + hr = ExecuteUnRegisterUIModuleCA( &cadata ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + break; + } + case IIS_INSTALL_HANDLER: + { + hr = ExecuteInstallHandlerCA( &cadata ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + break; + } + case IIS_UNINSTALL_HANDLER: + { + hr = ExecuteUnInstallHandlerCA( &cadata ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + break; + } + case IIS_INSTALL_SECTIONSCHEMA: + { + hr = ExecuteRegisterSectionSchemaCA( &cadata ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + break; + } + case IIS_UNINSTALL_SECTIONSCHEMA: + { + hr = ExecuteUnRegisterSectionSchemaCA( &cadata ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + break; + } + case IIS_INSTALL_TRACEAREA: + { + hr = ExecuteRegisterTraceAreaCA( &cadata ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + break; + } + case IIS_INSTALL_MOFFILE: + { + hr = ExecuteRegisterMofFileCA( &cadata ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + break; + } + case IIS_INSTALL_DEFAULTS: + { + hr = ExecuteInstallSectionDefaultsCA( &cadata ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + break; + } + case IIS_INSTALL_SECTION_ADDITIONS: + { + hr = ExecuteInstallSectionAdditionsCA( &cadata ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + break; + } + case IIS_INSTALL_CGIRESTRICTIONS: + { + hr = ExecuteInstallCgiRestrictionsCA( &cadata ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + break; + } + case IIS_UNINSTALL_CGIRESTRICTIONS: + { + hr = ExecuteInstallCgiRestrictionsCA( &cadata ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + break; + } + default: + { + //unknown execute CA action type + hr = E_UNEXPECTED; + goto exit; + } + } + } + + if ( HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr ) + { + hr = S_OK; + } + +exit: + + if ( fCoInit ) + { + CoUninitialize(); + } + + IISLogWrite( + SETUP_LOG_SEVERITY_INFORMATION, + L"CA '%s' completed with return code hr=0x%x", + UNITEXT(__FUNCTION__), + hr ); + + IISLogClose(); + + return hr; +} + +/******************************************************************** + BeginTransaction - CUSTOM ACTION ENTRY POINT for backing up + config + + Input: deferred CustomActionData - BackupName +********************************************************************/ +UINT +WINAPI +IISBeginTransactionCA( + IN MSIHANDLE + ) + +{ + HRESULT hr = S_OK; + STACK_STRU( wzConfigSource, MAX_PATH ); + STACK_STRU( wzConfigCopy, MAX_PATH ); + DWORD dwSize = 0; + + if( IsWow64() ) + { + dwSize = ExpandEnvironmentStringsW(L"%windir%\\Sysnative\\inetsrv\\config\\applicationHost.config", + wzConfigSource.QueryStr(), + MAX_PATH + ); + } + else + { + dwSize = ExpandEnvironmentStringsW(L"%windir%\\system32\\inetsrv\\config\\applicationHost.config", + wzConfigSource.QueryStr(), + MAX_PATH + ); + } + if ( dwSize == 0 ) + { + //ExitWithLastError(hr, "failed to get ExpandEnvironmentStrings"); + goto exit; + } + wzConfigSource.SyncWithBuffer(); + hr = wzConfigCopy.Copy( wzConfigSource ); + + //add ca action as extension + + hr = wzConfigCopy.Append( L"."); + + hr = wzConfigCopy.Append( IIS_CONFIG_BACKUP_EXT); + + if ( !::CopyFileW(wzConfigSource.QueryStr(), wzConfigCopy.QueryStr(), FALSE) ) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + //ExitOnFailure2(hr, "Failed to copy config backup %S -> %S", wzConfigSource, wzConfigCopy); + } + + if( IsWow64() ) + { + dwSize = ExpandEnvironmentStringsW(L"%windir%\\Sysnative\\inetsrv\\config\\administration.config", + wzConfigSource.QueryStr(), + MAX_PATH + ); + } + else + { + dwSize = ExpandEnvironmentStringsW(L"%windir%\\system32\\inetsrv\\config\\administration.config", + wzConfigSource.QueryStr(), + MAX_PATH + ); + } + + if ( dwSize == 0 ) + { + //ExitWithLastError(hr, "failed to get ExpandEnvironmentStrings"); + goto exit; + } + wzConfigSource.SyncWithBuffer(); + hr = wzConfigCopy.Copy( wzConfigSource ); + + //add ca action as extension + + hr = wzConfigCopy.Append( L"."); + + hr = wzConfigCopy.Append( IIS_CONFIG_BACKUP_EXT); + + if ( !::CopyFileW(wzConfigSource.QueryStr(), wzConfigCopy.QueryStr(), FALSE) ) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + //ExitOnFailure2(hr, "Failed to copy config backup %S -> %S", wzConfigSource, wzConfigCopy); + } + + +exit: + + return S_OK; + +} + + +/******************************************************************** + RollbackTransaction - CUSTOM ACTION ENTRY POINT for unbacking up + config + + Input: deferred CustomActionData - BackupName +********************************************************************/ +UINT +WINAPI +IISRollbackTransactionCA( + IN MSIHANDLE + ) +{ + + HRESULT hr = S_OK; + STACK_STRU( wzConfigSource, MAX_PATH ); + STACK_STRU( wzConfigCopy, MAX_PATH ); + DWORD dwSize = 0; + + + if( IsWow64() ) + { + dwSize = ExpandEnvironmentStringsW(L"%windir%\\Sysnative\\inetsrv\\config\\applicationHost.config", + wzConfigSource.QueryStr(), + MAX_PATH + ); + } + else + { + dwSize = ExpandEnvironmentStringsW(L"%windir%\\system32\\inetsrv\\config\\applicationHost.config", + wzConfigSource.QueryStr(), + MAX_PATH + ); + } + if ( dwSize == 0 ) + { + //ExitWithLastError(hr, "failed to get ExpandEnvironmentStrings"); + goto exit; + } + wzConfigSource.SyncWithBuffer(); + hr = wzConfigCopy.Copy( wzConfigSource ); + + //add ca action as extension + + hr = wzConfigCopy.Append( L"." ); + + hr = wzConfigCopy.Append( IIS_CONFIG_BACKUP_EXT ); + + //rollback copy is reverse of start transaction + if( !::CopyFileW( wzConfigCopy.QueryStr(), wzConfigSource.QueryStr(), FALSE) ) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + //ExitOnFailure(hr, "failed to restore config backup"); + } + + if ( !::DeleteFileW( wzConfigCopy.QueryStr() ) ) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + //ExitOnFailure(hr, "failed to delete config backup"); + } + + if( IsWow64() ) + { + dwSize = ExpandEnvironmentStringsW(L"%windir%\\Sysnative\\inetsrv\\config\\administration.config", + wzConfigSource.QueryStr(), + MAX_PATH + ); + } + else + { + dwSize = ExpandEnvironmentStringsW(L"%windir%\\system32\\inetsrv\\config\\administration.config", + wzConfigSource.QueryStr(), + MAX_PATH + ); + } + if ( dwSize == 0 ) + { + //ExitWithLastError(hr, "failed to get ExpandEnvironmentStrings"); + goto exit; + } + wzConfigSource.SyncWithBuffer(); + hr = wzConfigCopy.Copy( wzConfigSource ); + + //add ca action as extension + + hr = wzConfigCopy.Append( L"." ); + + hr = wzConfigCopy.Append( IIS_CONFIG_BACKUP_EXT ); + + //rollback copy is reverse of start transaction + if( !::CopyFileW( wzConfigCopy.QueryStr(), wzConfigSource.QueryStr(), FALSE) ) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + //ExitOnFailure(hr, "failed to restore config backup"); + } + + if ( !::DeleteFileW( wzConfigCopy.QueryStr() ) ) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + //ExitOnFailure(hr, "failed to delete config backup"); + } + + +exit: + + return S_OK; + +} +/******************************************************************** + CommitTransaction - CUSTOM ACTION ENTRY POINT for unbacking up + config + + Input: deferred CustomActionData - BackupName +********************************************************************/ +UINT +WINAPI +IISCommitTransactionCA( + IN MSIHANDLE + ) +{ + HRESULT hr = S_OK; + STACK_STRU( wzConfigCopy, MAX_PATH ); + DWORD dwSize = 0; + + + + // Config AdminMgr changes already committed, just + // delete backup config file. + + if( IsWow64() ) + { + dwSize = ExpandEnvironmentStringsW(L"%windir%\\Sysnative\\inetsrv\\config\\applicationHost.config", + wzConfigCopy.QueryStr(), + MAX_PATH + ); + } + else + { + dwSize = ExpandEnvironmentStringsW(L"%windir%\\system32\\inetsrv\\config\\applicationHost.config", + wzConfigCopy.QueryStr(), + MAX_PATH + ); + } + if ( dwSize == 0 ) + { + //ExitWithLastError(hr, "failed to get ExpandEnvironmentStrings"); + goto exit; + } + wzConfigCopy.SyncWithBuffer(); + + hr = wzConfigCopy.Append( L"." ); + + hr = wzConfigCopy.Append( IIS_CONFIG_BACKUP_EXT); + + if( !::DeleteFileW(wzConfigCopy.QueryStr() ) ) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + //ExitOnFailure(hr, "failed to delete config backup"); + } + + if( IsWow64() ) + { + dwSize = ExpandEnvironmentStringsW(L"%windir%\\Sysnative\\inetsrv\\config\\administration.config", + wzConfigCopy.QueryStr(), + MAX_PATH + ); + } + else + { + dwSize = ExpandEnvironmentStringsW(L"%windir%\\system32\\inetsrv\\config\\administration.config", + wzConfigCopy.QueryStr(), + MAX_PATH + ); + } + if ( dwSize == 0 ) + { + //ExitWithLastError(hr, "failed to get ExpandEnvironmentStrings"); + goto exit; + } + wzConfigCopy.SyncWithBuffer(); + + hr = wzConfigCopy.Append( L"." ); + + hr = wzConfigCopy.Append( IIS_CONFIG_BACKUP_EXT); + + if( !::DeleteFileW(wzConfigCopy.QueryStr() ) ) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + //ExitOnFailure(hr, "failed to delete config backup"); + } + + +exit: + + return S_OK; + +} diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/iiscaexp.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/iiscaexp.h new file mode 100644 index 0000000000..184df8aff8 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/iiscaexp.h @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +UINT +WINAPI +IISScheduleInstallCA( + IN MSIHANDLE hInstall + ); + +UINT +WINAPI +IISScheduleUninstallCA( + IN MSIHANDLE hInstall + ); + +UINT +WINAPI +IISExecuteCA( + IN MSIHANDLE hInstall + ); + +UINT +WINAPI +IISBeginTransactionCA( + IN MSIHANDLE hInstall + ); + +UINT +WINAPI +IISRollbackTransactionCA( + IN MSIHANDLE hInstall + ); + +UINT +WINAPI +IISCommitTransactionCA( + IN MSIHANDLE hInstall + ); + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/modules.cpp b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/modules.cpp new file mode 100644 index 0000000000..341306461d --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/modules.cpp @@ -0,0 +1,655 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#include "precomp.h" + +// +// Local function declarations +// + +HRESULT +AddModuleToGlobalModules( + IN IAppHostWritableAdminManager * pAdminMgr, + IN CONST WCHAR * szName, + IN CONST WCHAR * szImage, + IN OPTIONAL CONST WCHAR * szPreCondition + ); + +HRESULT +AddModuleToRootModules( + IN IAppHostAdminManager * pAdminMgr, + IN CONST WCHAR * szName, + IN CONST WCHAR * szPreCondition, + IN OPTIONAL CONST WCHAR * szType + ); + +HRESULT +DeleteModuleFromRootModules( + IAppHostAdminManager * pAdminMgr, + CONST WCHAR * szName, + BOOL * pfDeleted + ); + +// +// Public functions +// + +HRESULT +InstallModule( + IN CONST WCHAR * szName, + IN CONST WCHAR * szImage, + IN OPTIONAL CONST WCHAR * szPreCondition, + IN OPTIONAL CONST WCHAR * szType + ) +{ + HRESULT hr = NOERROR; + + CComPtr pAdminMgr; + + hr = CoCreateInstance( __uuidof( AppHostWritableAdminManager ), + NULL, + CLSCTX_INPROC_SERVER, + __uuidof( IAppHostWritableAdminManager ), + (VOID **)&pAdminMgr ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + // If the type is present, this is a .Net module and + // should not be added to the globalModules + if ( ( szType == NULL ) || ( *szType == L'\0' ) ) + { + STRU strFinalImage; + WCHAR ProgFiles[64]; + WCHAR SysRoot[64]; + WCHAR SysDrive[16]; + PCWSTR szSubstFrom = NULL; + PCWSTR szSubstTo = NULL; + + if (GetEnvironmentVariable(L"ProgramFiles", + ProgFiles, + _countof(ProgFiles)) > _countof(ProgFiles) || + GetEnvironmentVariable(L"SystemRoot", + SysRoot, + _countof(SysRoot)) > _countof(SysRoot) || + GetEnvironmentVariable(L"SystemDrive", + SysDrive, + _countof(SysDrive)) > _countof(SysDrive)) + { + hr = E_UNEXPECTED; + DBGERROR_HR(hr); + goto exit; + } + + if (_wcsnicmp(szImage, ProgFiles, wcslen(ProgFiles)) == 0) + { + szSubstFrom = ProgFiles; + szSubstTo = L"%ProgramFiles%"; + } + else if (_wcsnicmp(szImage, SysRoot, wcslen(SysRoot)) == 0) + { + szSubstFrom = SysRoot; + szSubstTo = L"%SystemRoot%"; + } + else if (_wcsnicmp(szImage, SysDrive, wcslen(SysDrive)) == 0) + { + szSubstFrom = SysDrive; + szSubstTo = L"%SystemDrive%"; + } + + if (szSubstFrom != NULL) + { + if (FAILED(hr = strFinalImage.Copy(szSubstTo)) || + FAILED(hr = strFinalImage.Append(szImage + wcslen(szSubstFrom)))) + { + goto exit; + } + szImage = strFinalImage.QueryStr(); + } + + hr = AddModuleToGlobalModules( pAdminMgr, + szName, + szImage, + szPreCondition ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + } + + hr = AddModuleToRootModules( pAdminMgr, + szName, + szPreCondition, + szType ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pAdminMgr->CommitChanges(); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + +exit: + + return hr; +} + +HRESULT +UnInstallModule( + IN CONST WCHAR * szName, + IN OPTIONAL CONST WCHAR * szType + ) +{ + HRESULT hr = NOERROR; + + CComPtr pAdminMgr; + CComPtr pGlobalModulesSection; + CComPtr pGlobalModulesCollection; + + BSTR bstrAppHostConfigPath = SysAllocString( L"MACHINE/WEBROOT/APPHOST" ); + BSTR bstrGlobalModules = SysAllocString( L"system.webServer/globalModules" ); + + BOOL fChanged = FALSE; + BOOL fDeleted = FALSE; + UINT numDeleted; + + if ( !bstrAppHostConfigPath || + !bstrGlobalModules ) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR( hr ); + goto exit; + } + + hr = CoCreateInstance( __uuidof( AppHostWritableAdminManager ), + NULL, + CLSCTX_INPROC_SERVER, + __uuidof( IAppHostWritableAdminManager ), + (VOID **)&pAdminMgr ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + // + // Remove from root modules + // + + hr = DeleteModuleFromRootModules( pAdminMgr, + szName, + &fDeleted ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + if ( !fDeleted ) + { + DBGWARN(( DBG_CONTEXT, + "Expected to find %S in root modules collection\n" , + szName )); + } + + fChanged = fDeleted; + + if ( ( szType == NULL ) || ( *szType == L'\0' ) ) + { + // + // Remove from globalModules + // + + hr = pAdminMgr->GetAdminSection( bstrGlobalModules, + bstrAppHostConfigPath, + &pGlobalModulesSection ); + + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pGlobalModulesSection->get_Collection( &pGlobalModulesCollection ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + + hr = DeleteAllElementsFromCollection( pGlobalModulesCollection, + L"name", + szName, + FIND_ELEMENT_CASE_SENSITIVE, + &numDeleted ); + + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + if ( numDeleted == 0 ) + { + DBGWARN(( DBG_CONTEXT, + "Expected to find %S in globalModules list.\n", + szName )); + } + else + { + fChanged = TRUE; + } + } + + if ( fChanged ) + { + hr = pAdminMgr->CommitChanges(); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + } + +exit: + + SysFreeString( bstrAppHostConfigPath ); + SysFreeString( bstrGlobalModules ); + + return hr; +} + +// +// Local functions +// + +HRESULT +AddModuleToGlobalModules( + IN IAppHostWritableAdminManager * pAdminMgr, + IN CONST WCHAR * szName, + IN CONST WCHAR * szImage, + IN OPTIONAL CONST WCHAR * szPreCondition + ) +{ + HRESULT hr = NOERROR; + + CComPtr pGlobalModulesSection; + CComPtr pGlobalModulesCollection; + CComPtr pNewGlobalModuleElement; + + VARIANT varPropValue; + VariantInit( &varPropValue ); + + BSTR bstrAppHostConfigPath = SysAllocString( L"MACHINE/WEBROOT/APPHOST" ); + BSTR bstrGlobalModules = SysAllocString( L"system.webServer/globalModules" ); + BSTR bstrAdd = SysAllocString( L"add" ); + + if ( !bstrAppHostConfigPath || + !bstrGlobalModules || + !bstrAdd ) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR( hr ); + goto exit; + } + + // + // Get the global modules collection + // + + hr = pAdminMgr->GetAdminSection( bstrGlobalModules, + bstrAppHostConfigPath, + &pGlobalModulesSection ); + + if ( FAILED(hr) ) + { + DBGERROR_HR( hr ); + goto exit; + } + + hr = pGlobalModulesSection->get_Collection( &pGlobalModulesCollection ); + if ( FAILED(hr) ) + { + DBGERROR_HR( hr ); + goto exit; + } + + // + // Create a new module element + // + + hr = pGlobalModulesCollection->CreateNewElement( bstrAdd, + &pNewGlobalModuleElement ); + if ( FAILED(hr) ) + { + DBGERROR_HR( hr ); + goto exit; + } + + hr = VariantAssign( &varPropValue, szName ); + if ( FAILED(hr) ) + { + DBGERROR_HR( hr ); + goto exit; + } + + hr = SetElementProperty( pNewGlobalModuleElement, + L"name", + &varPropValue ); + if ( FAILED(hr) ) + { + DBGERROR_HR( hr ); + goto exit; + } + + hr = VariantAssign( &varPropValue, szImage ); + if ( FAILED(hr) ) + { + DBGERROR_HR( hr ); + goto exit; + } + + hr = SetElementProperty( pNewGlobalModuleElement, + L"image", + &varPropValue ); + if ( FAILED(hr) ) + { + DBGERROR_HR( hr ); + goto exit; + } + + if ( szPreCondition && *szPreCondition ) + { + hr = VariantAssign( &varPropValue, szPreCondition ); + if ( FAILED(hr) ) + { + DBGERROR_HR( hr ); + goto exit; + } + + hr = SetElementProperty( pNewGlobalModuleElement, + L"preCondition", + &varPropValue ); + if ( FAILED(hr) ) + { + DBGERROR_HR( hr ); + goto exit; + } + } + + // + // Add the new element + // + + hr = pGlobalModulesCollection->AddElement( pNewGlobalModuleElement ); + if ( FAILED(hr) ) + { + DBGERROR_HR( hr ); + goto exit; + } + +exit: + + VariantClear( &varPropValue ); + + SysFreeString( bstrAppHostConfigPath ); + SysFreeString( bstrGlobalModules ); + SysFreeString( bstrAdd ); + + return hr; +} + +HRESULT +AddModuleToRootModules( + IN IAppHostAdminManager * pAdminMgr, + IN CONST WCHAR * szName, + IN CONST WCHAR * szPreCondition, + IN OPTIONAL CONST WCHAR * szType + ) +{ + HRESULT hr = NOERROR; + + BOOL found = FALSE; + + CComPtr pLocation; + CComPtr pModulesSection; + CComPtr pModuleCollection; + CComPtr pNewModuleElement; + + VARIANT varPropValue; + VariantInit( &varPropValue ); + + BSTR bstrAdd = SysAllocString( L"add" ); + + if ( !bstrAdd ) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR(hr); + goto exit; + } + + hr = GetLocationFromFile( pAdminMgr, + L"MACHINE/WEBROOT/APPHOST", + L"", + &pLocation, + &found ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + if ( !found ) + { + hr = HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ); + DBGERROR(( DBG_CONTEXT, + "Failed to find root location path\n" )); + goto exit; + } + + hr = GetSectionFromLocation( pLocation, + L"system.webServer/modules", + &pModulesSection, + &found ); + + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + if ( !found ) + { + hr = HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ); + DBGERROR(( DBG_CONTEXT, + "Failed to find modules section\n" )); + goto exit; + } + + // + // Create a new module element + // + + hr = pModulesSection->get_Collection( &pModuleCollection ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pModuleCollection->CreateNewElement( bstrAdd, + &pNewModuleElement ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = VariantAssign( &varPropValue, szName ); + if ( FAILED(hr) ) + { + DBGERROR_HR( hr ); + goto exit; + } + + hr = SetElementProperty( pNewModuleElement, + L"name", + &varPropValue ); + if ( FAILED(hr) ) + { + DBGERROR_HR( hr ); + goto exit; + } + + if ( szPreCondition && *szPreCondition ) + { + hr = VariantAssign( &varPropValue, szPreCondition ); + if ( FAILED(hr) ) + { + DBGERROR_HR( hr ); + goto exit; + } + + hr = SetElementProperty( pNewModuleElement, + L"preCondition", + &varPropValue ); + if ( FAILED(hr) ) + { + DBGERROR_HR( hr ); + goto exit; + } + } + + if ( szType && *szType ) + { + hr = VariantAssign( &varPropValue, szType ); + if ( FAILED(hr) ) + { + DBGERROR_HR( hr ); + goto exit; + } + + hr = SetElementProperty( pNewModuleElement, + L"type", + &varPropValue ); + if ( FAILED(hr) ) + { + DBGERROR_HR( hr ); + goto exit; + } + } + + hr = pModuleCollection->AddElement( pNewModuleElement, + -1 ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + +exit: + + SysFreeString( bstrAdd ); + VariantClear( &varPropValue ); + + return hr; +} + +HRESULT +DeleteModuleFromRootModules( + IAppHostAdminManager * pAdminMgr, + CONST WCHAR * szName, + BOOL * pfDeleted + ) +{ + HRESULT hr = NOERROR; + + CComPtr pLocation; + CComPtr pModulesSection; + CComPtr pModulesCollection; + + UINT numDeleted; + BOOL found = FALSE; + + *pfDeleted = FALSE; + + hr = GetLocationFromFile( pAdminMgr, + L"MACHINE/WEBROOT/APPHOST", + L"", + &pLocation, + &found ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + if ( !found ) + { + DBGWARN(( DBG_CONTEXT, + "Failed to find root location path\n" )); + goto exit; + } + + hr = GetSectionFromLocation( pLocation, + L"system.webServer/modules", + &pModulesSection, + &found ); + + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + if ( !found ) + { + DBGWARN(( DBG_CONTEXT, + "Failed to find modules section in root\n" )); + goto exit; + } + + hr = pModulesSection->get_Collection( &pModulesCollection ); + + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = DeleteAllElementsFromCollection( pModulesCollection, + L"name", + szName, + FIND_ELEMENT_CASE_SENSITIVE, + &numDeleted ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + if ( numDeleted == 0 ) + { + DBGWARN(( DBG_CONTEXT, + "Failed to find %S in root modules\n", + szName )); + } + else + { + *pfDeleted = TRUE; + } + +exit: + + return hr; +} + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/mof.cpp b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/mof.cpp new file mode 100644 index 0000000000..2f13ab1dfc --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/mof.cpp @@ -0,0 +1,82 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#include "precomp.h" +#include + +HRESULT +RegisterMofFile( + __in PWSTR pszFileName +) +{ + HRESULT hr = S_OK; + WBEM_COMPILE_STATUS_INFO CompileStatusInfo; + CComPtr pCompiler; + + hr = CoCreateInstance( _uuidof(MofCompiler), + 0, + CLSCTX_INPROC_SERVER, + _uuidof(IMofCompiler), + (LPVOID *) &pCompiler); + if ( FAILED( hr ) ) + { + // + // Register the COM object if is not registered. + // + WCHAR * pszDllPath = new WCHAR[ MAX_PATH ]; + if ( pszDllPath != NULL ) + { + if ( GetSystemDirectory( pszDllPath, MAX_PATH ) != 0 ) + { + HRESULT (STDAPICALLTYPE *pfDllRegisterServer)(VOID); + + (VOID) StringCchCat( pszDllPath, MAX_PATH, L"\\wbem\\mofd.dll" ); + + HINSTANCE hLib = LoadLibraryEx( pszDllPath, + NULL, + LOAD_WITH_ALTERED_SEARCH_PATH ); + if ( hLib != NULL ) + { + pfDllRegisterServer = (HRESULT (STDAPICALLTYPE *)(VOID))GetProcAddress(hLib, "DllRegisterServer"); + if ( pfDllRegisterServer != NULL ) + { + pfDllRegisterServer(); + hr = CoCreateInstance( _uuidof(MofCompiler), + 0, + CLSCTX_INPROC_SERVER, + _uuidof(IMofCompiler), + (LPVOID *) &pCompiler); + } + FreeLibrary( hLib ); + } + } + delete [] pszDllPath; + } + if ( FAILED( hr ) ) + { + goto Finished; + } + } + + hr = pCompiler->CompileFile( pszFileName, + NULL, // namespace + NULL, // username + NULL, // authoroty + NULL, // password + 0, // option flags + 0, // class flags + 0, // instance + &CompileStatusInfo ); + if ( hr != S_OK ) + { + // + // Means failure. + // + goto Finished; + } + +Finished: + + return hr; +} + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/msiutil.cpp b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/msiutil.cpp new file mode 100644 index 0000000000..2a9b65ab37 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/msiutil.cpp @@ -0,0 +1,581 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#include "precomp.h" + +HRESULT +MsiUtilGetProperty( + IN MSIHANDLE hInstall, + __in PCWSTR szName, + __inout STRU * pstrProperty + ) +{ + HRESULT hr = NOERROR; + DWORD cch = 0; + WCHAR dummy = L'\0'; + DWORD status; + + pstrProperty->Reset(); + + // + // Get the length. + // + + status = MsiGetPropertyW( hInstall, + szName, + &dummy, + &cch ); + + if( status != ERROR_MORE_DATA ) + { + hr = HRESULT_FROM_WIN32(status); + DBGERROR_HR(hr); + goto exit; + } + + // + // Return is count of characters w/o NULL + // + + cch++; + + hr = pstrProperty->Resize( cch ); + if( FAILED( hr ) ) + { + DBGERROR_HR(hr); + goto exit; + } + + status = MsiGetPropertyW( hInstall, + szName, + pstrProperty->QueryStr(), + &cch ); + + if( status != ERROR_SUCCESS ) + { + hr = HRESULT_FROM_WIN32(status); + DBGERROR_HR(hr); + goto exit; + } + + pstrProperty->SyncWithBuffer(); + +exit: + + return hr; +} + + +HRESULT +MsiUtilScheduleDeferredAction( + IN MSIHANDLE hInstall, + __in PCWSTR szAction, + __in PCWSTR szData + ) +{ + HRESULT hr = NOERROR; + UINT status; + + status = MsiSetPropertyW( hInstall, + szAction, + szData ); + if( status != ERROR_SUCCESS ) + { + hr = HRESULT_FROM_WIN32(status); + DBGERROR_HR(hr); + goto exit; + } + + status = MsiDoActionW( hInstall, + szAction ); + + if( status != ERROR_SUCCESS ) + { + hr = HRESULT_FROM_WIN32(status ); + DBGERROR_HR(hr); + goto exit; + } + +exit: + + return hr; +} + +HRESULT +MsiUtilRecordGetInteger( + IN MSIHANDLE hRecord, + IN UINT field, + __inout UINT * pInt + ) +{ + HRESULT hr = NOERROR; + UINT tempValue = 0; + + _ASSERTE(pInt); + + tempValue = MsiRecordGetInteger(hRecord, field); + + if( MSI_NULL_INTEGER == tempValue ) + { + hr = E_UNEXPECTED; + DBGERROR(( DBG_CONTEXT, "Non-integer value encountered in Integer field, %08x\n", hr )); + goto exit; + } + + *pInt = tempValue; + +exit: + return hr; +} + +HRESULT +MsiUtilRecordGetString( + IN MSIHANDLE hRecord, + IN UINT field, + __inout STRU * pstr + ) +{ + HRESULT hr = NOERROR; + UINT status = ERROR_SUCCESS; + + DWORD cch = pstr->QuerySizeCCH(); + + status = MsiRecordGetStringW( hRecord, + field, + pstr->QueryStr(), + &cch ); + + if( ERROR_MORE_DATA == status ) + { + hr = pstr->Resize( ++cch ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + status = MsiRecordGetStringW( hRecord, + field, + pstr->QueryStr(), + &cch ); + } + + if( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32(status); + DBGERROR_HR(hr); + goto exit; + } + + hr = pstr->SetLen( cch ); + if( FAILED(hr) ) + { + hr = HRESULT_FROM_WIN32(status); + DBGERROR_HR(hr); + goto exit; + } + +exit: + + return hr; +} + +HRESULT +MsiUtilRecordReadStreamIntoFile( + IN MSIHANDLE hRecord, + IN UINT field, + IN PCWSTR szFileName + ) +{ + HRESULT hr = NOERROR; + UINT status = ERROR_SUCCESS; + HANDLE hOutputFile = INVALID_HANDLE_VALUE; + + _ASSERTE(szFileName); + + hOutputFile = CreateFileW( szFileName, + GENERIC_WRITE, + 0, + NULL, + CREATE_NEW, + FILE_ATTRIBUTE_NORMAL, + NULL); + if ( INVALID_HANDLE_VALUE == hOutputFile ) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + DBGERROR_HR(hr); + goto exit; + } + + do + { + DWORD bytesWritten = 0; + BOOL fRet = FALSE; + CHAR szBuffer[4096]; + DWORD cbBuf = sizeof(szBuffer); + + status = MsiRecordReadStream(hRecord, field, szBuffer, &cbBuf); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32(status); + DBGERROR_HR(hr); + goto exit; + } + else if ( 0 == cbBuf ) + { + //we've reached the end of the stream + break; + } + + fRet = WriteFile(hOutputFile, szBuffer, cbBuf, &bytesWritten, NULL); + if( !fRet ) + { + hr = HRESULT_FROM_WIN32(status); + DBGERROR_HR(hr); + goto exit; + } + + } while (1); + + +exit: + + if( INVALID_HANDLE_VALUE != hOutputFile) + { + CloseHandle( hOutputFile ); + hOutputFile = INVALID_HANDLE_VALUE; + } + + return hr; +} + +HRESULT +MsiUtilFormatString( + IN MSIHANDLE hInstall, + __inout STRU * pstrData + ) +{ + HRESULT hr = NOERROR; + UINT status = ERROR_SUCCESS; + MSIHANDLE hRecord = NULL; + + hRecord = MsiCreateRecord( 1 ); + if( !hRecord ) + { + hr = E_UNEXPECTED; + DBGERROR_HR(hr); + goto exit; + } + + status = MsiRecordSetStringW( hRecord, + 0, + pstrData->QueryStr() ); + if( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32(status); + DBGERROR_HR(hr); + goto exit; + } + + DWORD cch = pstrData->QuerySizeCCH(); + + status = MsiFormatRecordW( hInstall, + hRecord, + pstrData->QueryStr(), + &cch ); + if( ERROR_MORE_DATA == status ) + { + hr = pstrData->Resize( ++cch ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + status = MsiFormatRecordW( hInstall, + hRecord, + pstrData->QueryStr(), + &cch ); + } + + if( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32(status); + DBGERROR_HR(hr); + goto exit; + } + + hr = pstrData->SetLen( cch ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + +exit: + + if( hRecord ) + { + MsiCloseHandle( hRecord ); + hRecord = NULL; + } + + return hr; +} + +WCHAR CA_DATA_DELIM[] = { '^', 0 }; + +// +// BUGBUG - Prefix will barf on this +// Can I really trust this data hasn't been tampered with? +// +WCHAR * +CA_DATA_READER::ExtractString() +{ + if( !_current || *_current == 0 ) + { + return NULL; + } + + // + // String format is: + // (len - delim - data - delim) (xN) \0 + // "3^cat^4^fish^\0" + // + + // + // extract length of data + // + + WCHAR * psz = wcsstr( _current, CA_DATA_DELIM ); + + _ASSERTE( psz ); + if( psz ) + { + *psz = 0; + INT cch = wcstol( _current, NULL, 0 ); + + // + // advance to data + // + + psz++; + + // + // terminate and advance to next block + // + + _current = psz + cch; + *_current = 0; + + _current++; + } + + return psz; +} + +HRESULT +CA_DATA_WRITER::WriteInternal( + CONST WCHAR * sz, + INT n +) +{ + HRESULT hr = NOERROR; + + // + // Write out the data length + // + + WCHAR buffer[20]; + StringCchPrintfW( buffer, sizeof(buffer)/sizeof(buffer[0]), L"%d", n ); + + hr = _data.Append( buffer ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = _data.Append( CA_DATA_DELIM ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + // + // Write out the data + // + + hr = _data.Append( sz ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = _data.Append( CA_DATA_DELIM ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + +exit: + + return hr; +} + + + +BOOL +MsiUtilIsInstalling( + INSTALLSTATE isInstalled, + INSTALLSTATE isAction + ) +{ + return (INSTALLSTATE_LOCAL == isAction || + INSTALLSTATE_SOURCE == isAction || + (INSTALLSTATE_DEFAULT == isAction && + (INSTALLSTATE_LOCAL == isInstalled || + INSTALLSTATE_SOURCE == isInstalled))); +} + + +BOOL +MsiUtilIsReInstalling( + INSTALLSTATE isInstalled, + INSTALLSTATE isAction + ) +{ + return ((INSTALLSTATE_LOCAL == isAction || + INSTALLSTATE_SOURCE == isAction || + INSTALLSTATE_DEFAULT == isAction || + INSTALLSTATE_UNKNOWN == isAction) && + (INSTALLSTATE_LOCAL == isInstalled || + INSTALLSTATE_SOURCE == isInstalled)); +} + + +BOOL +MsiUtilIsUnInstalling( + INSTALLSTATE isInstalled, + INSTALLSTATE isAction + ) +{ + return ((INSTALLSTATE_ABSENT == isAction || + INSTALLSTATE_REMOVED == isAction) && + (INSTALLSTATE_LOCAL == isInstalled || + INSTALLSTATE_SOURCE == isInstalled)); +} + +HRESULT +GenerateTempFileName( + __in PCWSTR szPrefix, + __in PCWSTR szExtension, + __inout STRU * pstr +) +{ + HRESULT hr = NOERROR; + UINT status = 0; + STACK_STRU( guidName, 128 ); + GUID guid = {0}; + DWORD cch = 0; + + _ASSERTE(szPrefix); + _ASSERTE(szExtension); + _ASSERTE(pstr); + + cch = pstr->QuerySizeCCH(); + + status = GetTempPathW(cch, pstr->QueryStr()); + if ( status > cch) + { + cch = status; + hr = pstr->Resize( ++cch ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error resizing buffer, hr=0x%x", hr); + goto exit; + } + + status = GetTempPathW(cch, pstr->QueryStr()); + } + + if ( 0 == status ) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error getting temp path, hr=0x%x", hr); + goto exit; + } + + pstr->SyncWithBuffer(); + + hr = pstr->Append(L"\\"); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error apppending \\, hr=0x%x", hr); + goto exit; + } + + hr = pstr->Append(szPrefix); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error appending file prefix, hr=0x%x", hr); + goto exit; + } + + cch = guidName.QuerySizeCCH(); + hr = CoCreateGuid ( &guid ); + if ( FAILED (hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error generating the GUID, hr=0x%x", hr); + goto exit; + } + + if ( !StringFromGUID2( guid, guidName.QueryStr(), cch ) ) + { + hr = E_UNEXPECTED; + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error getting string from GUID, hr=0x%x", hr); + goto exit; + } + + guidName.SyncWithBuffer(); + + hr = pstr->Append(guidName.QueryStr()); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error appending GUID, hr=0x%x", hr); + goto exit; + } + + hr = pstr->Append(L"."); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error appending ., hr=0x%x", hr); + goto exit; + } + + hr = pstr->Append(szExtension); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + IISLogWrite(SETUP_LOG_SEVERITY_ERROR, L"Error appending extension, hr=0x%x", hr); + goto exit; + } + +exit: + if ( FAILED(hr) ) + { + IISLogWrite(SETUP_LOG_SEVERITY_INFORMATION, L"Error in function %s, hr=0x%x", UNITEXT(__FUNCTION__), hr); + } + return hr; +} \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/msiutil.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/msiutil.h new file mode 100644 index 0000000000..e7c770c534 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/msiutil.h @@ -0,0 +1,192 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#pragma once + +HRESULT +MsiUtilGetProperty( + IN MSIHANDLE hInstall, + __in PCWSTR szName, + __inout STRU * pstrProperty + ); + +HRESULT +MsiUtilScheduleDeferredAction( + IN MSIHANDLE hInstall, + __in PCWSTR szAction, + __in PCWSTR szData + ); + +HRESULT +MsiUtilRecordGetInteger( + IN MSIHANDLE hRecord, + IN UINT field, + __inout UINT * pInt + ); + +HRESULT +MsiUtilRecordGetString( + IN MSIHANDLE hRecord, + IN UINT field, + __inout STRU * pstr + ); + +HRESULT +MsiUtilRecordReadStreamIntoFile( + IN MSIHANDLE hRecord, + IN UINT field, + IN PCWSTR szFileName + ); + +HRESULT +MsiUtilFormatString( + IN MSIHANDLE hInstall, + __inout STRU * pstrData + ); + +class CA_DATA_WRITER +{ +public: + + CA_DATA_WRITER() + { + } + + HRESULT + Write( + CONST WCHAR * sz + ) + { + return WriteInternal( sz, (INT)wcslen(sz) ); + } + + HRESULT + Write( + CONST WCHAR * sz, + INT cch + ) + { + return WriteInternal( sz, cch ); + } + + HRESULT + Write( + INT n + ) + { + HRESULT hr; + + WCHAR buffer[20]; + hr = StringCchPrintfW( buffer, + sizeof(buffer)/sizeof(buffer[0]), + L"%d", + n ); + if( FAILED(hr) ) + { + return hr; + } + + return WriteInternal( buffer, (INT)wcslen(buffer) ); + } + + CONST WCHAR * + QueryData() const + { + return _data.QueryStr(); + } + +protected: + + HRESULT + WriteInternal( + CONST WCHAR * sz, + INT n + ); + + STRU _data; +}; + +class CA_DATA_READER +{ +public: + + CA_DATA_READER() : + _current( NULL ) + { + } + + ~CA_DATA_READER() + { + } + + HRESULT + LoadDeferredCAData( + MSIHANDLE hInstall + ) + { + HRESULT hr = MsiUtilGetProperty( hInstall, L"CustomActionData", &_strCustomActionData ); + _current = _strCustomActionData.QueryStr(); + return hr; + } + + HRESULT + Read( + __deref_out_z WCHAR ** psz + ) + { + *psz = ExtractString(); + if( !*psz ) + { + return HRESULT_FROM_WIN32( ERROR_NO_MORE_ITEMS ); + } + return S_OK; + } + + HRESULT + Read( + INT * pi + ) + { + CONST WCHAR * sz = ExtractString(); + if( !sz ) + { + return HRESULT_FROM_WIN32( ERROR_NO_MORE_ITEMS ); + } + *pi = wcstol( sz, NULL, 10 ); + return S_OK; + } + +private: + + WCHAR * + ExtractString(); + + STRU _strCustomActionData; + WCHAR * _current; +}; + + +BOOL +MsiUtilIsReInstalling( + INSTALLSTATE isInstalled, + INSTALLSTATE isAction + ); + +BOOL +MsiUtilIsInstalling( + INSTALLSTATE isInstalled, + INSTALLSTATE isAction + ); + +BOOL +MsiUtilIsUnInstalling( + INSTALLSTATE isInstalled, + INSTALLSTATE isAction + ); + +HRESULT +GenerateTempFileName( + __in PCWSTR szPrefix, + __in PCWSTR szExtension, + __inout STRU * pstr +); \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/packages.config b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/packages.config new file mode 100644 index 0000000000..21d9344493 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/packages.config @@ -0,0 +1,4 @@ + + + + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/precomp.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/precomp.h new file mode 100644 index 0000000000..5f32044523 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/precomp.h @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#pragma once + +// Don't throw exceptions for CComVariant failures. +// Check for VT_ERROR instead. +#define _ATL_NO_VARIANT_THROW +#define WIN32_LEAN_AND_MEAN + +#include +#include +#include +#include +#pragma warning( disable:4127 ) +#include +#include "dbgutil.h" +#include +#define IRTL_DLLEXP +#include +#include +#include +#include +#include +#include +#include + +// +// Security APIs. +// +#include +#include +#include +#include + + +#include "ahutil.h" +#include "msiutil.h" +#include "defaults.h" +#include "cgi_restrictions.h" +#include "handlers.h" +#include "tracing.h" +#include "config_custom.h" +#include "setup_log.h" +#include "httpapi.h" +#include "secutils.h" +#include "ConfigShared.h" +#include "iisca.h" +#include "iiscaexp.h" +extern HINSTANCE g_hinst; + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/schema.cpp b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/schema.cpp new file mode 100644 index 0000000000..fe39b356f0 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/schema.cpp @@ -0,0 +1,741 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#include "precomp.h" + +HRESULT +GetChildSectionGroup( + IN IAppHostSectionGroup * pParentSectionGroup, + IN CONST WCHAR * szChildGroupName, + OUT IAppHostSectionGroup ** ppChildSectionGroup + ) +{ + HRESULT hr = NOERROR; + + CComPtr pChildSectionGroup; + + VARIANT varChildGroupName; + VariantInit( &varChildGroupName ); + + *ppChildSectionGroup = NULL; + + hr = VariantAssign( &varChildGroupName, + szChildGroupName ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pParentSectionGroup->get_Item( varChildGroupName, + &pChildSectionGroup ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + *ppChildSectionGroup = pChildSectionGroup.Detach(); + +exit: + + VariantClear( &varChildGroupName ); + + return hr; +} + +HRESULT +GetRootSectionGroup( + IN IAppHostAdminManager * pAdminMgr, + IN CONST WCHAR * szConfigPath, + OUT IAppHostSectionGroup ** ppRootSectionGroup + ) +{ + HRESULT hr = NOERROR; + + CComPtr pRootSectionGroup; + CComPtr pConfigMgr; + CComPtr pConfigFile; + + BSTR bstrConfigPath = NULL; + + *ppRootSectionGroup = NULL; + + bstrConfigPath = SysAllocString( szConfigPath ); + + if( !bstrConfigPath ) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR(hr); + goto exit; + } + + hr = pAdminMgr->get_ConfigManager( &pConfigMgr ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pConfigMgr->GetConfigFile( bstrConfigPath, + &pConfigFile ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pConfigFile->get_RootSectionGroup( &pRootSectionGroup ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + *ppRootSectionGroup = pRootSectionGroup.Detach(); + +exit: + + SysFreeString( bstrConfigPath ); + + return hr; +} + +HRESULT +InitializeAdminManager( + IN CONST BOOL isSectionInAdminSchema, + IN IAppHostWritableAdminManager * pAdminMgr, + OUT CONST WCHAR ** pszCommitPath +) +{ + HRESULT hr = NOERROR; + CONST WCHAR * szAdminCommitPath = L"MACHINE/WEBROOT"; + CONST WCHAR * szAppHostCommitPath = L"MACHINE/WEBROOT/APPHOST"; + + CONST WCHAR * szCommitPath = NULL; + + *pszCommitPath = NULL; + + if(isSectionInAdminSchema) + { + szCommitPath = szAdminCommitPath; + hr = InitAdminMgrForAdminConfig( pAdminMgr, + szCommitPath ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + } + else + { + szCommitPath = szAppHostCommitPath; + } + + *pszCommitPath = szCommitPath; + +exit: + return hr; +} + +HRESULT +RegisterSectionSchema( + IN CONST BOOL isSectionInAdminSchema, + IN CONST WCHAR * szSectionName, + IN CONST WCHAR * szOverrideModeDefault, + IN OPTIONAL CONST WCHAR * szAllowDefinition, + IN OPTIONAL CONST WCHAR * szType + ) +{ + HRESULT hr = NOERROR; + + CComPtr pAdminMgr; + CComPtr pRootSectionGroup; + CComPtr pParentSectionGroup; + CComPtr pChildSectionGroup; + CComPtr pSections; + CComPtr pNewSection; + + + BSTR bstrSectionGroupName = NULL; + BSTR bstrSectionName = NULL; + BSTR bstrOverrideModeDefault = NULL; + BSTR bstrAllowDefinition = NULL; + BSTR bstrType = NULL; + + CONST WCHAR * szCommitPath = NULL; + + WCHAR * szSectionNameCopy = _wcsdup( szSectionName ); + if( !szSectionNameCopy ) + { + hr = E_OUTOFMEMORY; + goto exit; + } + szSectionName = NULL; + + // + // szSectionNameCopy is the full name of the section. The last + // segment szShortName will be registered as the name of the + // section and the other segments are section groups + // + // eg. "system.webServer/foo/bar/mysection" + // + + WCHAR * szShortName = wcsrchr( szSectionNameCopy, L'/' ); + if( szShortName == NULL ) + { + szShortName = szSectionNameCopy; + } + else + { + *szShortName++ = L'\0'; + } + + hr = CoCreateInstance( __uuidof( AppHostWritableAdminManager ), + NULL, + CLSCTX_INPROC_SERVER, + __uuidof( IAppHostWritableAdminManager ), + (VOID **)&pAdminMgr ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = InitializeAdminManager( isSectionInAdminSchema, + pAdminMgr, + &szCommitPath); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = GetRootSectionGroup( pAdminMgr, + szCommitPath, + &pRootSectionGroup); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + // + // For each section group referenced in szSectionNameCopy retrieve or + // create it. + // + + WCHAR * pszGroupName = szSectionNameCopy; + WCHAR * pszNext = NULL; + + pParentSectionGroup = pRootSectionGroup; + + if (szShortName == szSectionNameCopy) + { + goto SkipAddingGroups; + } + + while( pszGroupName ) + { + pszNext = wcschr( pszGroupName, L'/' ); + if( pszNext ) + { + *pszNext++ = 0; + } + + hr = GetChildSectionGroup( pParentSectionGroup, + pszGroupName, + &pChildSectionGroup ); + + if( hr == HRESULT_FROM_WIN32( ERROR_INVALID_INDEX ) ) + { + // + // Create the group if it does not exist + // + bstrSectionGroupName = SysAllocString( pszGroupName ); + if( !bstrSectionGroupName ) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR(hr); + goto exit; + } + + hr = pParentSectionGroup->AddSectionGroup( bstrSectionGroupName, + &pChildSectionGroup ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + } + else if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + pParentSectionGroup = pChildSectionGroup; + pChildSectionGroup.Release(); + + SysFreeString( bstrSectionGroupName ); + bstrSectionGroupName = NULL; + + pszGroupName = pszNext; + } + + SkipAddingGroups: + // + // Add the new section + // + + hr = pParentSectionGroup->get_Sections( &pSections ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + bstrSectionName = SysAllocString( szShortName ); + if( !bstrSectionName ) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR(hr); + goto exit; + } + + hr = pSections->AddSection( bstrSectionName, + &pNewSection ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + bstrOverrideModeDefault = SysAllocString( szOverrideModeDefault ); + if( !bstrOverrideModeDefault ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pNewSection->put_OverrideModeDefault( bstrOverrideModeDefault ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + if( szAllowDefinition && *szAllowDefinition ) + { + bstrAllowDefinition = SysAllocString( szAllowDefinition ); + if( !bstrAllowDefinition ) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR(hr); + goto exit; + } + + hr = pNewSection->put_AllowDefinition( bstrAllowDefinition ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + } + + if( szType && *szType ) + { + bstrType = SysAllocString( szType ); + if( !bstrType ) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR(hr); + goto exit; + } + + hr = pNewSection->put_Type( bstrType ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + } + + // + // Persist changes + // + + hr = pAdminMgr->CommitChanges(); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + +exit: + + SysFreeString( bstrSectionGroupName ); + SysFreeString( bstrSectionName ); + SysFreeString( bstrOverrideModeDefault ); + SysFreeString( bstrType ); + SysFreeString( bstrAllowDefinition ); + + free( szSectionNameCopy ); + + return hr; +} + +HRESULT +RemoveSectionDefinition( + IN IAppHostSectionGroup * pParentSection, + __in_z WCHAR * szSectionPath, + __in_z WCHAR * szSectionName + ) +{ + HRESULT hr = NOERROR; + + CComPtr pChildSectionGroup; + CComPtr pSections; + + WCHAR * pszNextPath = NULL; + + VARIANT varIndex; + VariantInit( &varIndex ); + + // + // If there are no more path segments, remove the section + // + + if( !szSectionPath ) + { + hr = pParentSection->get_Sections( &pSections ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = VariantAssign( &varIndex, szSectionName ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pSections->DeleteSection( varIndex ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + // End recursion + goto exit; + } + + // + // We have more path segments, so move to the next segment + // and call RemoveSectionDefinition recursively + // + + pszNextPath = wcschr( szSectionPath, L'/' ); + if( pszNextPath ) + { + *pszNextPath++ = 0; + } + + hr = GetChildSectionGroup( pParentSection, + szSectionPath, + &pChildSectionGroup ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = RemoveSectionDefinition( pChildSectionGroup, + pszNextPath, + szSectionName ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + // + // The section has been removed, check to see if the + // child section group is empty and clean up if it is. + // + + ULONG childCount = 0; + hr = pChildSectionGroup->get_Count( &childCount ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + if( childCount == 0 ) + { + hr = pChildSectionGroup->get_Sections( &pSections ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pSections->get_Count( &childCount ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + if( childCount == 0 ) + { + hr = VariantAssign( &varIndex, szSectionPath ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pParentSection->DeleteSectionGroup( varIndex ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + } + } + +exit: + + VariantClear( &varIndex ); + + return hr; +} + +HRESULT +RemoveSectionData( + IN IAppHostAdminManager * pAdminMgr, + IN CONST WCHAR * szSectionName, + IN CONST WCHAR * szConfigPath + ) +{ + HRESULT hr = NOERROR; + + CComPtr pSectionElement; + CComPtr pConfigMgr; + CComPtr pConfigFile; + CComPtr pLocations; + CComPtr pLocation; + + BSTR bstrSectionName = SysAllocString( szSectionName ); + BSTR bstrPath = SysAllocString( szConfigPath ); + + VARIANT varSectionName; + VariantInit( &varSectionName ); + + if( !bstrSectionName || + !bstrPath ) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR(hr); + goto exit; + } + + hr = VariantAssign( &varSectionName, szSectionName ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pAdminMgr->GetAdminSection( bstrSectionName, + bstrPath, + &pSectionElement ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pSectionElement->Clear(); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + // + // Go through the location tags and delete the section + // + + hr = pAdminMgr->get_ConfigManager( &pConfigMgr ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pConfigMgr->GetConfigFile( bstrPath, + &pConfigFile ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pConfigFile->get_Locations( &pLocations ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + DWORD count; + VARIANT varIndex; + VariantInit( &varIndex ); + + hr = pLocations->get_Count( &count ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + for( DWORD i = 0; i < count; i++ ) + { + varIndex.vt = VT_UI4; + varIndex.ulVal = i; + + hr = pLocations->get_Item( varIndex, &pLocation ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pLocation->DeleteConfigSection( varSectionName ); + if( HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ) == hr ) + { + hr = S_OK; + } + else if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + pLocation.Release(); + } + +exit: + + SysFreeString( bstrSectionName ); + SysFreeString( bstrPath ); + + return hr; +} + +HRESULT +UnRegisterSectionSchema( + IN CONST BOOL isSectionInAdminSchema, + IN CONST WCHAR * szSectionName + ) +{ + HRESULT hr = NOERROR; + + CComPtr pAdminMgr; + CComPtr pRootSectionGroup; + + CONST WCHAR * szCommitPath = NULL; + + WCHAR * szSectionNameCopy = _wcsdup( szSectionName ); + if( !szSectionNameCopy ) + { + hr = E_OUTOFMEMORY; + goto exit; + } + + // + // szSectionNameCopy is the full name of the section. The last + // segment szShortName will be registered as the name of the + // section and the other segments are section groups + // + // eg. "system.webServer/foo/bar/mysection" + // + + WCHAR * szShortName = wcsrchr( szSectionNameCopy, L'/' ); + if( szShortName == NULL ) + { + szShortName = szSectionNameCopy; + } + else + { + *szShortName++ = 0; + } + + hr = CoCreateInstance( __uuidof( AppHostWritableAdminManager ), + NULL, + CLSCTX_INPROC_SERVER, + __uuidof( IAppHostWritableAdminManager ), + (VOID **)&pAdminMgr ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = InitializeAdminManager( isSectionInAdminSchema, + pAdminMgr, + &szCommitPath); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = RemoveSectionData( pAdminMgr, + szSectionName, + szCommitPath); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = GetRootSectionGroup( pAdminMgr, + szCommitPath, + &pRootSectionGroup ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = RemoveSectionDefinition( pRootSectionGroup, + (szShortName == szSectionNameCopy) ? NULL : szSectionNameCopy, + szShortName ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pAdminMgr->CommitChanges(); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + +exit: + + free( szSectionNameCopy ); + + return hr; +} + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/secutils.cpp b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/secutils.cpp new file mode 100644 index 0000000000..8806cd667e --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/secutils.cpp @@ -0,0 +1,1125 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#include "precomp.h" + +#ifndef NT_SUCCESS +#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) +#endif + +#ifndef STATUS_SOME_NOT_MAPPED +// +// MessageId: STATUS_SOME_NOT_MAPPED +// +// MessageText: +// +// Some of the information to be translated has not been translated. +// +#define STATUS_SOME_NOT_MAPPED ((NTSTATUS)0x00000107L) +#endif + +#ifndef STATUS_NONE_MAPPED +#define STATUS_NONE_MAPPED ((NTSTATUS)0xc0000073L) +#endif + + +HRESULT +IsVistaOrGreater( + __out BOOL & fIsVistaOrGreater +) +/*++ + +Routine Description: + + Return TRUE if we are running in a Server SKU, + otherwise return FALSE. + +Arguments: + + pfIsServer - The return value. + +Return Value: + + BOOL + +--*/ +{ + HRESULT hr = S_OK; + OSVERSIONINFOEX osVersionInfoEx = { 0 }; + DWORDLONG dwlConditionMask = 0; + BOOL fReturn = FALSE; + + fIsVistaOrGreater = FALSE; + osVersionInfoEx.dwOSVersionInfoSize = sizeof( osVersionInfoEx ); + osVersionInfoEx.dwMajorVersion = 6; + + VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL ); + + fReturn = VerifyVersionInfo( + &osVersionInfoEx, + VER_MAJORVERSION, + dwlConditionMask ); + + // + // If the function fails, the return value is zero + // and GetLastError returns an error code other than ERROR_OLD_WIN_VERSION + // + if ( fReturn == FALSE && GetLastError() != ERROR_OLD_WIN_VERSION ) + { + hr = HRESULT_FROM_WIN32 ( GetLastError() ); + DBGERROR_HR( hr ); + goto Finished; + } + + fIsVistaOrGreater = ( fReturn ); + +Finished: + + return hr; + +} + +HRESULT +CreateDirectory( + __in LPCWSTR pszFileName +) +{ + HRESULT hr = S_OK; + DWORD dwFileAttributes = 0; + + dwFileAttributes = GetFileAttributes( pszFileName ); + if ( dwFileAttributes == INVALID_FILE_ATTRIBUTES ) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + + if ( hr == HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ) || + hr == HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ) ) + { + hr = S_OK; + + // + // Create the folder. + // + if ( !CreateDirectory( pszFileName, NULL ) ) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + DBGERROR_HR( hr ); + goto Finished; + } + } + else + { + DBGERROR_HR( hr ); + } + } + +Finished: + + return hr; +} + +HRESULT +AddExplicitAccessToFileDacl( + __in LPWSTR pszFilePath, + DWORD cExplicitAccess, + EXPLICIT_ACCESS rgExplicitAccess[] +) +/*++ + +Routine Description: + + Add EXPLICIT_ACCESS entries to a file DACL + +Arguments: + + pszFilePath - The path to the file where the DACL will be modified + cExplicitAccess - The count of EXPLICIT_ACCESS entires to add + rgExplicitAccess - The EXPLICIT_ACCESS entries + +Return Value: + + HRESULT + +--*/ +{ + HRESULT hr = S_OK; + DWORD dwError = ERROR_SUCCESS; + PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL; + PACL pOldFileDacl = NULL; + PACL pNewFileDacl = NULL; + + if ( pszFilePath == NULL || + cExplicitAccess == 0 || + rgExplicitAccess == NULL ) + { + hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); + goto Finished; + } + + // + // Get the current file DACL + // + dwError = GetNamedSecurityInfo( pszFilePath, + SE_FILE_OBJECT, + DACL_SECURITY_INFORMATION, + NULL, // ppsidOwner + NULL, // ppsidGroup + &pOldFileDacl, + NULL, // ppSacl + &pSecurityDescriptor ); + if ( dwError != ERROR_SUCCESS ) + { + hr = HRESULT_FROM_WIN32( dwError ); + goto Finished; + } + + // + // Create a new DACL with the EXPLICIT_ACCESS entries + // + + dwError = SetEntriesInAcl( cExplicitAccess, + rgExplicitAccess, + pOldFileDacl, + &pNewFileDacl ); + if ( dwError != ERROR_SUCCESS ) + { + hr = HRESULT_FROM_WIN32( dwError ); + goto Finished; + } + + // + // Write the new DACL + // + + dwError = SetNamedSecurityInfo( pszFilePath, + SE_FILE_OBJECT, + DACL_SECURITY_INFORMATION, + NULL, // psidOwner + NULL, // psidGroup + pNewFileDacl, + NULL ); // pSacl + if ( dwError != ERROR_SUCCESS ) + { + hr = HRESULT_FROM_WIN32( dwError ); + goto Finished; + } + +Finished: + + if ( pNewFileDacl != NULL ) + { + LocalFree( pNewFileDacl ); + pNewFileDacl = NULL; + } + + if ( pSecurityDescriptor != NULL ) + { + LocalFree( pSecurityDescriptor ); + pSecurityDescriptor = NULL; + } + + return hr; +} + +HRESULT +GrantFileAccessToIisIusrs( + __in LPWSTR pszFilePath, + DWORD dwAccessMask, + DWORD dwInheritance +) +/*++ + +Routine Description: + + This method gives the IIS_IUSRS group access to a specified file + path. In the case that this is executed on a domain controller, + this method will grant access explicitly to Local Service and + Network Service instead. + +Arguments: + + pszFilePath - The path where access is granted + dwAccessMask - Desired access to grant + dwInhertiance - Inheritance for access mask + +Return Value: + + HRESULT + +--*/ +{ + HRESULT hr = S_OK; + DWORD cExplicitAccess = 1; + PSID pSidUserAccount = NULL; + DWORD cbUserAccount = 0; + EXPLICIT_ACCESS rgExplicitAccess[ 1 ]; + + if ( pszFilePath == NULL ) + { + hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); + goto Finished; + } + + // Zero out the struct + ZeroMemory( &(rgExplicitAccess[0]), sizeof( EXPLICIT_ACCESS ) ); + + // Get the SID for IIS_IUSRS + if ( CreateWellKnownSid( WinBuiltinIUsersSid, + NULL, // DomainSid + pSidUserAccount, + &cbUserAccount ) ) + { + // + // We are expecing a FALSE return value since we + // are obtaining required buffer sizes. + // + hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA ); + goto Finished; + } + + hr = HRESULT_FROM_WIN32( GetLastError() ); + if ( hr != HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER ) ) + { + goto Finished; + } + hr = S_OK; + + pSidUserAccount = (PSID) LocalAlloc( LPTR, cbUserAccount ); + if ( pSidUserAccount == NULL ) + { + hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY ); + goto Finished; + } + + if ( !CreateWellKnownSid( WinBuiltinIUsersSid, + NULL, // DomainSid + pSidUserAccount, + &cbUserAccount ) ) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + goto Finished; + } + + // Build TRUSTEE with the IIS_IUSRS SID + BuildTrusteeWithSid( &(rgExplicitAccess[0].Trustee), pSidUserAccount ); + rgExplicitAccess[0].grfAccessPermissions = dwAccessMask; + rgExplicitAccess[0].grfAccessMode = GRANT_ACCESS; + rgExplicitAccess[0].grfInheritance = dwInheritance; + + // Add access to file DACL + hr = AddExplicitAccessToFileDacl( pszFilePath, + cExplicitAccess, + rgExplicitAccess ); + if ( FAILED( hr ) ) + { + goto Finished; + } + +Finished: + + return hr; +} + +HRESULT +GetStringSddlFromFile( + __in LPWSTR pszFileName, + __out STRU & strFileSddl, + __in BOOL fCreateIfDoesNotExist +) +/*++ + +Routine Description: + + Returns the DACL in the format SDDL for the + specified file or directory. + +Arguments: + + pszFileName - The file or directory path from to get the DACL. + strFileSddl - The file's security descriptor as string. + +Return Value: + + HRESULT + +--*/ +{ + HRESULT hr = S_OK; + DWORD dwResult = ERROR_SUCCESS; + PACL pFileObjectAcl = NULL; + PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL; + LPWSTR pszSddl = NULL; + ULONG cchSddlLen = 0; + + if ( fCreateIfDoesNotExist ) + { + hr = CreateDirectory( pszFileName ); + if ( FAILED( hr ) ) + { + DBGERROR_HR( hr ); + goto Finished; + } + } + + dwResult = GetNamedSecurityInfo( + pszFileName, + SE_FILE_OBJECT, + DACL_SECURITY_INFORMATION, + NULL, + NULL, + &pFileObjectAcl, + NULL, + &pSecurityDescriptor ); + if ( dwResult != ERROR_SUCCESS ) + { + hr = HRESULT_FROM_WIN32( dwResult ); + DBGERROR_HR( hr ); + goto Finished; + } + + if ( ! ConvertSecurityDescriptorToStringSecurityDescriptor( + pSecurityDescriptor, + SDDL_REVISION_1, + DACL_SECURITY_INFORMATION, + &pszSddl, + &cchSddlLen ) ) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + DBGERROR_HR( hr ); + goto Finished; + } + + hr = strFileSddl.Copy( pszSddl ); + if ( FAILED( hr ) ) + { + goto Finished; + } + +Finished: + + if ( pSecurityDescriptor != NULL ) + { + LocalFree( pSecurityDescriptor ); + pSecurityDescriptor = NULL; + } + + if ( pszSddl != NULL ) + { + LocalFree( pszSddl ); + pszSddl = NULL; + } + + return hr; +} + +VOID +FreeStringSids( + __in DWORD cStringSids, + __in_bcount(cStringSids) LPWSTR rgszStringSids[] +) +/*++ + +Routine Description: + + Frees the memory allocated by ConvertAccountNamesToStringSids. + +Arguments: + + cStringSids - The number of string in the array rgszStringSids. + rgszStringSids - An array of SIDs represented as string. + +Return Value: + + HRESULT + +--*/ +{ + if ( rgszStringSids == NULL ) + { + return; + } + + for ( DWORD dwIndex = 0; dwIndex < cStringSids; dwIndex ++ ) + { + LocalFree( rgszStringSids [ dwIndex ] ); + } + + LocalFree ( rgszStringSids ); +} + +HRESULT +ConvertAccountNamesToStringSids ( + __in DWORD dwNameCount, + __in_ecount(dwNameCount) LPWSTR rgszNames[], + __deref_out_ecount(*pcStringSids) LPWSTR** StringSids, + __out DWORD* pcStringSids +) +/*++ + +Routine Description: + + Converts a list of local users or groups to string SIDs. + The StringSids array must be freed via the FreeStringSids function + +Arguments: + + dwNameCount - Number of names to convert. + + rgszNames - Array of pointers to Domain\Member strings + + StringSids - Returns a pointer to an array of pointers to String SIDs. + The array should be freed via FreeStringSids. + + pcStringSids - The number of String SIDs translated. + +Return Value: + + HRESULT + +--*/ +{ + HRESULT hr = S_OK; + NTSTATUS ntStatus = ERROR_SUCCESS; + LSA_HANDLE hPolicy = NULL; + LSA_OBJECT_ATTRIBUTES ObjectAttributes = {0}; + PUNICODE_STRING pUnicodeNames = NULL; + PLSA_REFERENCED_DOMAIN_LIST pReferencedDomainList = NULL; + PLSA_TRANSLATED_SID2 pTranslatedSid = NULL; + SIZE_T cchLength = 0; + LPWSTR * rgszStringSids = NULL; + DWORD cStringSids = 0; + DWORD dwStringIndex = 0; + + HMODULE hModule = NULL; + + typedef NTSTATUS + (NTAPI * PFN_LSALOOKUPNAMES2) ( + __in LSA_HANDLE PolicyHandle, + __in ULONG Flags, // Reserved + __in ULONG Count, + __in PLSA_UNICODE_STRING Names, + __out PLSA_REFERENCED_DOMAIN_LIST *ReferencedDomains, + __out PLSA_TRANSLATED_SID2 *Sids + ); + + PFN_LSALOOKUPNAMES2 pfn = NULL; + + hModule = LoadLibrary( L"Advapi32.dll" ); + if ( hModule == NULL ) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + DBGERROR_HR( hr ); + goto Finished; + } + + pfn = ( PFN_LSALOOKUPNAMES2 ) GetProcAddress( hModule, "LsaLookupNames2" ); + if ( pfn == NULL ) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + DBGERROR_HR( hr ); + if ( hr == HRESULT_FROM_WIN32( ERROR_PROC_NOT_FOUND ) ) + { + // + // This must be an OS before Windows 2003. + // + hr = S_OK; + } + goto Finished; + } + + // + // Open the local LSA database + // + ntStatus = LsaOpenPolicy( NULL, // Open the local policy + &ObjectAttributes, + POLICY_LOOKUP_NAMES, + &hPolicy ) ; + + if ( !NT_SUCCESS( ntStatus ) ) + { + hr = HRESULT_FROM_NT( ntStatus ); + DBGERROR_HR( hr ); + goto Finished; + } + + // + // Convert the names to unicode strings + // + pUnicodeNames = (PUNICODE_STRING) LocalAlloc( + LMEM_FIXED, + sizeof(UNICODE_STRING) * dwNameCount ); + + if ( pUnicodeNames == NULL ) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR( hr ); + goto Finished; + } + + for ( DWORD dwIndex = 0; dwIndex < dwNameCount; dwIndex++ ) + { + cchLength = wcslen( rgszNames[dwIndex] ) * sizeof( *rgszNames[dwIndex] ); + if ( ( cchLength + sizeof( UNICODE_NULL ) ) > USHRT_MAX ) + { + hr = HRESULT_FROM_WIN32 ( ERROR_ARITHMETIC_OVERFLOW ); + goto Finished; + } + + pUnicodeNames[dwIndex].Buffer = rgszNames[dwIndex]; + pUnicodeNames[dwIndex].Length = ( USHORT ) cchLength; + pUnicodeNames[dwIndex].MaximumLength = ( USHORT ) ( cchLength + sizeof( UNICODE_NULL ) ); + } + + // + // Convert the names to sids + // + ntStatus = (*pfn) ( hPolicy, + 0, // Flags + dwNameCount, + pUnicodeNames, + &pReferencedDomainList, + &pTranslatedSid ); + + if ( !NT_SUCCESS( ntStatus ) ) + { + hr = HRESULT_FROM_WIN32( ntStatus ); + DBGERROR_HR( hr ); + goto Finished; + } + + // + // Some of the names could not be translated. + // This is an informational-level return value. + // + if ( ntStatus == STATUS_SOME_NOT_MAPPED ) + { + hr = HRESULT_FROM_WIN32( ntStatus ); + DBGERROR_HR( hr ); + hr = S_OK; + } + + // + // Count the number of SIDs retrieved + // + for ( DWORD dwIndex = 0; dwIndex < dwNameCount; dwIndex++ ) + { + if ( pTranslatedSid[dwIndex].Sid != NULL ) + { + cStringSids ++; + } + } + + // + // Allocate the SID list to return + // + rgszStringSids = (LPWSTR *) LocalAlloc( + LMEM_FIXED, + sizeof( LPWSTR ) * cStringSids ); + + if ( rgszStringSids == NULL ) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR( hr ); + goto Finished; + } + + // + // Construct a string SID for each name + // + dwStringIndex = 0; + for ( DWORD dwIndex = 0; dwIndex < dwNameCount; dwIndex++ ) + { + if ( pTranslatedSid[dwIndex].Sid != NULL ) + { + if ( ! ConvertSidToStringSid( + pTranslatedSid [dwIndex].Sid, + &rgszStringSids [dwStringIndex] ) ) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + DBGERROR_HR( hr ); + goto Finished; + } + dwStringIndex ++; + } + } + +Finished: + + if ( pUnicodeNames != NULL ) + { + LocalFree( pUnicodeNames ); + pUnicodeNames = NULL; + } + + if ( pReferencedDomainList != NULL ) + { + LsaFreeMemory( pReferencedDomainList ); + pReferencedDomainList = NULL; + } + + if ( pTranslatedSid != NULL ) + { + LsaFreeMemory( pTranslatedSid ); + pTranslatedSid = NULL; + } + + if ( hPolicy != NULL ) + { + LsaClose( hPolicy ); + hPolicy = NULL; + } + + // + // If the translation wasn't successful, + // free any partial translation. + // + + if ( FAILED( hr ) ) + { + if ( rgszStringSids != NULL ) + { + FreeStringSids( cStringSids, rgszStringSids ); + rgszStringSids = NULL; + } + } + + // + // Assign the output parameters + // + (*StringSids) = rgszStringSids; + (*pcStringSids) = cStringSids; + + if ( hModule != NULL ) + { + FreeLibrary( hModule ); + hModule = NULL; + } + + return hr; +} + +HRESULT +SetFileSddl( + __in LPCWSTR pszSddl, + __in LPWSTR pszPath +) +{ + HRESULT hr = S_OK; + SECURITY_ATTRIBUTES sa = { 0 }; + DWORD status = 0; + BOOL fIsVistaOrGreater = FALSE; + + sa.nLength = sizeof( sa ); + sa.bInheritHandle = FALSE; + if ( ! ConvertStringSecurityDescriptorToSecurityDescriptor( + pszSddl, + SDDL_REVISION_1, + &sa.lpSecurityDescriptor, + NULL)) + { + hr = HRESULT_FROM_WIN32 ( GetLastError() ); + DBGERROR_HR( hr ); + goto Finished; + } + + hr = IsVistaOrGreater ( fIsVistaOrGreater ); + if ( FAILED(hr) ) + { + fIsVistaOrGreater = FALSE; + hr = S_OK; + } + + if ( fIsVistaOrGreater ) + { + status = SetNamedSecurityInfo( pszPath, + SE_FILE_OBJECT, + DACL_SECURITY_INFORMATION, + NULL, + NULL, + (PACL) sa.lpSecurityDescriptor, + NULL ); + if ( status != ERROR_SUCCESS ) + { + hr = HRESULT_FROM_WIN32 (status ); + DBGERROR_HR( hr ); + goto Finished; + } + } + else + { + if ( ! SetFileSecurity( pszPath, + DACL_SECURITY_INFORMATION, + (PSECURITY_DESCRIPTOR) sa.lpSecurityDescriptor ) ) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + DBGERROR_HR( hr ); + goto Finished; + } + } + + +Finished: + + if ( sa.lpSecurityDescriptor != NULL ) + { + LocalFree( sa.lpSecurityDescriptor ); + sa.lpSecurityDescriptor = NULL; + } + + return hr; +} + +HRESULT +GetIISWPGSid( + __out STRU & strIISWPGSid +) +{ + HRESULT hr = S_OK; + LPWSTR* ppszStringSids = NULL; + DWORD cStringSids = 0; + + LPWSTR rgszIisAccountsToResolve [] = { L"IIS_WPG" }; + + hr = ConvertAccountNamesToStringSids( _countof( rgszIisAccountsToResolve ), + rgszIisAccountsToResolve, + &ppszStringSids, + &cStringSids ); + if ( FAILED( hr ) ) + { + DBGERROR_HR( hr ); + goto Finished; + } + + if ( cStringSids < 1 ) + { + hr = E_INVALIDARG; + goto Finished; + } + + hr = strIISWPGSid.Copy( ppszStringSids[0] ); + if ( FAILED( hr ) ) + { + goto Finished; + } + +Finished: + + if ( ppszStringSids != NULL ) + { + FreeStringSids( cStringSids, ppszStringSids ); + ppszStringSids = NULL; + } + + return hr; +} + +ULONG +GetRealAclSize( + __in PACL Acl + ) +/*++ + +Routine Description: + + Walks the sids in an ACL to determine it's minimum size + +Arguments: + + Acl - Acl to scan + +Return Value: + + Byte count + +--*/ +{ + PACE_HEADER Ace = FirstAce( Acl ); + int i = 0; + while (i < Acl->AceCount ) { + i++; + Ace = NextAce( Ace ); + } + + return (ULONG) ((PBYTE) Ace - (PBYTE) Acl); + +} + +HRESULT +MakeAutoInheritFromParent( + __in LPWSTR pszPath +) +{ + HRESULT hr = S_OK; + DWORD dwError; + PACL Acl; + PACE_HEADER Ace; + PSECURITY_DESCRIPTOR pSecurityDescriptor; + SECURITY_INFORMATION SecurityInfo = DACL_SECURITY_INFORMATION; + + // + // Get the current file DACL + // + dwError = GetNamedSecurityInfo( pszPath, + SE_FILE_OBJECT, + SecurityInfo, + NULL, + NULL, + &Acl, + NULL, + &pSecurityDescriptor ); + if ( dwError != ERROR_SUCCESS ) + { + hr = HRESULT_FROM_WIN32( dwError ); + DBGERROR_HR( hr ); + goto Finished; + } + + // + // Remove all the ACEs + // + Ace = FirstAce( Acl ); + int i = 0; + while ( i < Acl->AceCount ) + { + // + // The Ace was not inherited + // + if( (Ace->AceFlags & INHERITED_ACE) == 0 ) + { + if (!DeleteAce( Acl, i )) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + DBGERROR_HR( hr ); + goto Finished; + } + } + else + { + i++; + Ace = NextAce( Ace ); + } + } + Acl->AclSize = (WORD) GetRealAclSize( Acl ); + + // + // Auto-inherit + // + SecurityInfo |= UNPROTECTED_DACL_SECURITY_INFORMATION; + + dwError = SetNamedSecurityInfo( pszPath, + SE_FILE_OBJECT, + SecurityInfo, + NULL, + NULL, + Acl, + NULL ); + if ( dwError != ERROR_SUCCESS ) + { + hr = HRESULT_FROM_WIN32( dwError ); + DBGERROR_HR( hr ); + goto Finished; + } + +Finished: + + if ( pSecurityDescriptor != NULL ) + { + LocalFree( pSecurityDescriptor ); + pSecurityDescriptor = NULL; + } + + return hr; +} + +HRESULT +GrantIISWPGReadWritePermissions( + __in LPWSTR pszPath +) +{ + HRESULT hr = S_OK; + STACK_STRU( strAces, 128 ); + STACK_STRU( strFileSddl, 128 ); + STACK_STRU( strFileSddlTemp, 128 ); + STACK_STRU( strIISWPGSid, 32 ); + + hr = GetStringSddlFromFile( pszPath, + strFileSddlTemp ); + if ( FAILED( hr ) ) + { + DBGERROR_HR( hr ); + goto Finished; + } + + hr = GetIISWPGSid( strIISWPGSid ); + if ( FAILED( hr ) ) + { + DBGERROR_HR( hr ); + if ( hr == STATUS_NONE_MAPPED ) + { + // + // No maps found. + // + hr = S_OK; + } + goto Finished; + } + + // + // Add Read/Write permissions. + // + hr = strAces.Copy( L"(A;OICI;0x12019f;;;" ); + if ( FAILED( hr ) ) + { + goto Finished; + } + + hr = strAces.Append( strIISWPGSid ); + if ( FAILED( hr ) ) + { + goto Finished; + } + + hr = strAces.Append( L")", 1 ); + if ( FAILED( hr ) ) + { + goto Finished; + } + + // + // Insert the ACE before any other ACE. + // + + // + // Search for the first ACE '(' + // + LPCWSTR psz = wcschr( strFileSddlTemp.QueryStr(), SDDL_ACE_BEGINC ); + + // + // Copy the first part before the first '(' + // + hr = strFileSddl.Append( strFileSddlTemp.QueryStr(), + (DWORD)(psz - strFileSddlTemp.QueryStr()) ); + if ( FAILED( hr ) ) + { + DBGERROR_HR( hr ); + goto Finished; + } + + // + // Copy the new ACE + // + hr = strFileSddl.Append( strAces ); + if ( FAILED( hr ) ) + { + DBGERROR_HR( hr ); + goto Finished; + } + + // + // Copy the other ACEs. + // + hr = strFileSddl.Append( psz ); + if ( FAILED( hr ) ) + { + DBGERROR_HR( hr ); + goto Finished; + } + + hr = SetFileSddl( strFileSddl.QueryStr(), + pszPath ); + if ( FAILED( hr ) ) + { + DBGERROR_HR( hr ); + goto Finished; + } + +Finished: + + return hr; +} + +HRESULT +SetupAclsWow64( + LPCWSTR pwszPath +) +{ + HRESULT hr = S_OK; + HMODULE hModule = NULL; + STACK_STRU( strPath, MAX_PATH ); + + typedef UINT + (WINAPI *PFN_GETSYSTEMWOW64DIRECTORY) + ( + __out LPTSTR lpBuffer, + __in UINT uSize + ); + + PFN_GETSYSTEMWOW64DIRECTORY pfn; + + hModule = LoadLibrary( L"kernel32.dll" ); + if ( hModule == NULL ) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + DBGERROR_HR( hr ); + goto Finished; + } + pfn = ( PFN_GETSYSTEMWOW64DIRECTORY ) GetProcAddress( hModule, "GetSystemWow64DirectoryW" ); + if ( pfn == NULL ) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + DBGERROR_HR( hr ); + if ( hr == HRESULT_FROM_WIN32( ERROR_PROC_NOT_FOUND ) ) + { + // + // This must be an OS before Windows 2003. + // + hr = S_OK; + } + goto Finished; + } + + if ( ! (*pfn)( strPath.QueryStr(), + strPath.QuerySizeCCH() ) ) + { + hr = HRESULT_FROM_WIN32( GetLastError() ); + if ( hr == HRESULT_FROM_WIN32( ERROR_CALL_NOT_IMPLEMENTED ) ) + { + // + // This is not Win64. + // + hr = S_OK; + } + else + { + DBGERROR_HR( hr ); + } + goto Finished; + } + strPath.SyncWithBuffer(); + + if (pwszPath != NULL) + { + hr = strPath.Append( pwszPath ); + if ( FAILED( hr ) ) + { + goto Finished; + } + } + + hr = MakeAutoInheritFromParent( strPath.QueryStr() ); + if ( FAILED( hr ) ) + { + DBGERROR_HR( hr ); + goto Finished; + } + +Finished: + + if ( hModule != NULL ) + { + FreeLibrary( hModule ); + hModule = NULL; + } + + return hr; +} diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/secutils.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/secutils.h new file mode 100644 index 0000000000..416ffd369c --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/secutils.h @@ -0,0 +1,98 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +HRESULT +IsVistaOrGreater( + __out BOOL & fIsVistaOrGreater +); + +HRESULT +CreateDirectory( + __in LPCWSTR pszFileName +); + +HRESULT +AddExplicitAccessToFileDacl( + __in LPWSTR pszFilePath, + DWORD cExplicitAccess, + EXPLICIT_ACCESS rgExplicitAccess[] +); + +HRESULT +GrantFileAccessToIisIusrs( + __in LPWSTR pszFilePath, + DWORD dwAccessMask, + DWORD dwInheritance +); + +HRESULT +GetStringSddlFromFile( + __in LPWSTR pszFileName, + __out STRU & strFileSddl, + __in BOOL fCreateIfDoesNotExist = TRUE +); + +VOID +FreeStringSids( + __in DWORD cStringSids, + __in_bcount(cStringSids) LPWSTR rgszStringSids[] +); + +HRESULT +ConvertAccountNamesToStringSids ( + __in DWORD dwNameCount, + __in_ecount(dwNameCount) LPWSTR rgszNames[], + __deref_out_ecount(*pcStringSids) LPWSTR** StringSids, + __out DWORD* pcStringSids +); + +HRESULT +SetFileSddl( + __in LPCWSTR pszSddl, + __in LPWSTR pszPath +); + +HRESULT +GetIISWPGSid( + __out STRU & strIISWPGSid +); + +inline PACE_HEADER +FirstAce( __in PACL Acl ) +{ + return (PACE_HEADER)(((PBYTE)Acl) + sizeof( ACL )); +} + +inline PACE_HEADER +NextAce( __in PACE_HEADER Ace ) +{ + return (PACE_HEADER)(((PBYTE)Ace) + Ace->AceSize ); +} + +inline PSID +SidFromAce( __in PACE_HEADER Ace ) +{ + return (PSID)&((PACCESS_ALLOWED_ACE)Ace)->SidStart; +} + +ULONG +GetRealAclSize( + __in PACL Acl +); + + +HRESULT +MakeAutoInheritFromParent( + __in LPWSTR pszPath +); + +HRESULT +GrantIISWPGReadWritePermissions( + __in LPWSTR pszPath +); + +HRESULT +SetupAclsWow64( + LPCWSTR pwszPath +); + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/setup_log.cpp b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/setup_log.cpp new file mode 100644 index 0000000000..86a8857096 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/setup_log.cpp @@ -0,0 +1,423 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#include "precomp.h" +#include "ntassert.h" +// +// SETUP_LOG class, used only by MsiLogXXX functions not used directly by CA code +// +class SETUP_LOG +{ + +public: + + SETUP_LOG( + VOID + ) + { + _severityThreshold = SETUP_LOG_SEVERITY_INFORMATION; + } + + ~SETUP_LOG( + VOID + ) + { + } + + VOID + Initialize( + IN MSIHANDLE hInstall, + IN LPCWSTR pszCAName + ); + + VOID + Close( + VOID + ); + + VOID + Write( + IN CONST SETUP_LOG_SEVERITY setupLogSeverity, + IN LPCWSTR pszLogMessageFormat + ); + +private: + + MSIHANDLE _hInstall; + SETUP_LOG_SEVERITY _severityThreshold; + STRU _strSCANamePrefix; + +private: + HRESULT + WriteMSIMessage( + IN STRU * pstrLogMessage + ); + + HRESULT + SETUP_LOG::FmtCAName( + IN STRU * pstrFmtCAName + ); +}; + + +VOID +SETUP_LOG::Initialize( + IN MSIHANDLE hInstall, + IN LPCWSTR pszCAName + ) +/*++ + +Routine Description: + + Initialization. Opens handle to the log file and writes a message. + +Return Value: + + HRESULT + +--*/ +{ + STACK_STRU ( strMsiRegKey, 64 ); + STACK_STRU ( strStartLogMessage, MAX_PATH ); + STACK_STRU ( strMsiLoggingValue, 32 ); + DWORD dwBufLen = strMsiRegKey.QuerySizeCCH(); + DWORD status = ERROR_SUCCESS; + HKEY hKey = NULL; + + //for checking logging level + WORD i; + + // + //Set MSI handle & CA name + // + + _hInstall = hInstall; + + // + //Prefix message with CAname + // + _strSCANamePrefix.Copy( L"IISCA " ); + _strSCANamePrefix.Append( pszCAName ); + _strSCANamePrefix.Append( L" : " ); + + // + //test MsiLogging property MSI 4.0+ + // + + (VOID) MsiUtilGetProperty( hInstall, L"MsiLogging", &strMsiLoggingValue ); + + if( !strMsiLoggingValue.IsEmpty() ) + { + WCHAR * szValueBuf = strMsiLoggingValue.QueryStr(); + if( wcschr( szValueBuf, L'v' ) || wcschr( szValueBuf, L'V' ) ) + { + _severityThreshold = SETUP_LOG_SEVERITY_DEBUG ; + } + } + + if ( _severityThreshold != SETUP_LOG_SEVERITY_DEBUG ) + { + // + // Last chance - check Logging Registry Key/value + // + + status = RegOpenKeyEx( HKEY_LOCAL_MACHINE, + L"SOFTWARE\\Policies\\Microsoft\\Windows\\Installer", + 0, + KEY_QUERY_VALUE, + &hKey ); + + if ( status == ERROR_SUCCESS ) + { + status = RegQueryValueEx( hKey, + L"Logging", + NULL, + NULL, + (LPBYTE) strMsiRegKey.QueryStr(), + &dwBufLen); + + strMsiRegKey.SyncWithBuffer( ); + } + + if ( !( status != ERROR_SUCCESS ) || ( dwBufLen > strMsiRegKey.QuerySizeCCH() ) ) + { + // + //Have Logging key Value.. we will log something + // + // Check logging flags for verbosity 'v' + // + for ( i = 0; i < strMsiRegKey.QueryCCH() ; i++ ) + { + if ( strMsiRegKey.QueryStr()[ i ] == L'V' || strMsiRegKey.QueryStr()[ i ] == L'v' ) + { + _severityThreshold = SETUP_LOG_SEVERITY_DEBUG ; + break; + } + } + } + } + + // + // write the start message, prifix message with CAname + // + strStartLogMessage.Append( _strSCANamePrefix.QueryStr() ); + + strStartLogMessage.Append( L"Begin CA Setup" ); + + // + // write the message + // + + WriteMSIMessage( &strStartLogMessage ); + + + if ( hKey != NULL ) + { + RegCloseKey( hKey ); + hKey = NULL; + } + + return; +} + +VOID +SETUP_LOG::Close( + VOID + ) + +{ + STACK_STRU ( strEndLogMessage, MAX_PATH ); + + strEndLogMessage.Append( _strSCANamePrefix.QueryStr() ); + strEndLogMessage.Append( L"End CA Setup" ); + + // + // write the message + // + + WriteMSIMessage( &strEndLogMessage); + + return; +} + +VOID +SETUP_LOG::Write( + IN SETUP_LOG_SEVERITY setupLogSeverity, + IN LPCWSTR pszLogMessage + ) +/*++ + +Routine Description: + + Write a formatted message to the log file. Note that the message + will not be written to the log file if the severity is below that + of the current threshold. + +Arguments: + + setupLogSeverity - Severity of the message + pszLogMessageFormat - Format of the log message + +--*/ +{ + STACK_STRU ( struLogMessage, MAX_PATH ); + + DBG_ASSERT( pszLogMessage); + + if ( pszLogMessage == NULL ) + { + goto Exit; + } + + // + // If this message does not have high enough severity, we are done. + // + if ( setupLogSeverity < _severityThreshold ) + { + goto Exit; + } + + // + //Prefix message with CAname + // + + struLogMessage.Append( _strSCANamePrefix.QueryStr() ); + + // + // Prefix the high severity messages so we can easily spot errors. + // + + if ( setupLogSeverity == SETUP_LOG_SEVERITY_WARNING ) + { + struLogMessage.Append( L"< WARNING! > " ); + } + else if ( setupLogSeverity == SETUP_LOG_SEVERITY_ERROR ) + { + struLogMessage.Append( L"< !!ERROR!! > " ); + } + + struLogMessage.Append( pszLogMessage ); + + // + // Write to the log file + // + + WriteMSIMessage( &struLogMessage ); + +Exit: + + return; +} + +HRESULT +SETUP_LOG::WriteMSIMessage( + STRU * pstrLogMessage + ) + +{ + HRESULT hr = S_OK; + PMSIHANDLE msiRow; + UINT status = 0; + // + // get an MSI record + // + + //consider passing a parameterized string here + msiRow = MsiCreateRecord( 1 ); + if ( msiRow == NULL ) + { + hr = E_UNEXPECTED; + DBGERROR_HR(hr); + goto Exit; + } + + // + // put message in msi record + // + + status = MsiRecordSetStringW( msiRow, 1, (LPCWSTR)pstrLogMessage->QueryStr() ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + DBGERROR_HR(hr); + goto Exit; + } + + // + // send message to MSI log file + // + + status = MsiProcessMessage( _hInstall, INSTALLMESSAGE_INFO, msiRow ); + if ( ERROR_SUCCESS != status ) + { + hr = HRESULT_FROM_WIN32( status ); + DBGERROR_HR(hr); + goto Exit; + } + +Exit: + + return hr; +} + +// +//Use static global instance of SETUP_LOG class +// +static SETUP_LOG * g_pSetupLog = NULL; + +// +//MSI Log safe functions, used directly by CA code +// +VOID +IISLogInitialize( + IN MSIHANDLE hInstall, + IN LPCWSTR pszCAName + ) +{ + HRESULT hr = S_OK; + + //debug assert that it is always null. becaues previous custom action should have cleaned it up + DBG_ASSERT( g_pSetupLog == NULL ); + + if ( g_pSetupLog == NULL ) + { + g_pSetupLog = new SETUP_LOG(); + if ( g_pSetupLog == NULL ) + { + hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY ); + DBGERROR_HR(hr); + goto Exit; + } + } + + // + // init + // + + g_pSetupLog->Initialize( hInstall, pszCAName ); + +Exit: + return; +} + + +VOID +IISLogClose( + VOID + ) +{ + if ( !g_pSetupLog ) + { + goto Exit; + } + + // + // do the call + // + + g_pSetupLog->Close(); + + // + //Done with SETUP_LOG instance + // + + delete g_pSetupLog; + g_pSetupLog = NULL; + +Exit: + + return ; +} + + +VOID +IISLogWrite( + IN SETUP_LOG_SEVERITY setupLogSeverity, + IN LPCWSTR pszLogMessageFormat, + ... + ) +{ + va_list argsList; + va_start ( argsList, pszLogMessageFormat ); + + STACK_STRU ( struLogMessage, 128 ); + //debug assert that it is not null + DBG_ASSERT( g_pSetupLog ); + + if ( !g_pSetupLog ) + { + goto Exit; + } + + // + // Form struLogMessage so that we can write a single string + // + + struLogMessage.SafeVsnwprintf( pszLogMessageFormat, argsList ); + + g_pSetupLog->Write( setupLogSeverity, struLogMessage.QueryStr() ); + +Exit: + va_end ( argsList ); + return; +} diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/setup_log.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/setup_log.h new file mode 100644 index 0000000000..848fe4d0a3 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/setup_log.h @@ -0,0 +1,53 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#ifndef _SETUP_LOG_H_ +#define _SETUP_LOG_H_ + + +// +// Severity levels for setup log information. This is arranged in the +// order of increasing severity. +// +enum SETUP_LOG_SEVERITY +{ + SETUP_LOG_SEVERITY_DEBUG, + SETUP_LOG_SEVERITY_INFORMATION, + SETUP_LOG_SEVERITY_WARNING, + SETUP_LOG_SEVERITY_ERROR +}; + +//consider using an IIS prefix for Msi* methods - they conflict with MSI apis + +// +// Initalize logging once at begining of CA +// + +VOID +IISLogInitialize( + IN MSIHANDLE hInstall, + IN LPCWSTR pszCAName + ); + +// +// Close logging at end / exit of CA +// + +VOID +IISLogClose( + VOID + ); + +// +// Writes a message to msi log file +// +VOID +IISLogWrite( + IN SETUP_LOG_SEVERITY setupLogSeverity, + IN LPCWSTR pszLogMessageFormat, + ... + ); + +#endif + + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/tracing.cpp b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/tracing.cpp new file mode 100644 index 0000000000..a7e051b92e --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/tracing.cpp @@ -0,0 +1,343 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#include "precomp.h" + +HRESULT +RegisterTraceArea( + IN CONST WCHAR * szTraceProviderName, + IN CONST WCHAR * szTraceProviderGuid, + IN CONST WCHAR * szAreaName, + IN CONST WCHAR * szAreaValue +) +{ + HRESULT hr = NOERROR; + CComPtr pAdminMgr; + CComPtr pTraceProviderSection; + CComPtr pTraceProvidersCollection; + CComPtr pTraceProvider; + CComPtr pAreasElement; + CComPtr pAreasCollection; + CComPtr pAreaElement; + + BSTR bstrAppHostConfigPath = SysAllocString( L"MACHINE/WEBROOT/APPHOST" ); + BSTR bstrTracingSection = SysAllocString( L"system.webServer/tracing/traceProviderDefinitions" ); + BSTR bstrAreas = SysAllocString( L"areas" ); + + NAME_VALUE_PAIR ProviderProperties[] = + { + { L"name", CComVariant( szTraceProviderName )}, + { L"guid", CComVariant( szTraceProviderGuid )} + }; + + NAME_VALUE_PAIR AreaProperties[] = + { + { L"name", CComVariant( szAreaName )}, + { L"value", CComVariant( szAreaValue )} + }; + + if ( bstrAppHostConfigPath == NULL || + bstrTracingSection == NULL || + bstrAreas == NULL ) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR(hr); + goto exit; + } + + hr = CoCreateInstance( __uuidof( AppHostWritableAdminManager ), + NULL, + CLSCTX_INPROC_SERVER, + __uuidof( IAppHostWritableAdminManager ), + (VOID **)&pAdminMgr ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pAdminMgr->GetAdminSection( bstrTracingSection, + bstrAppHostConfigPath, + &pTraceProviderSection ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pTraceProviderSection->get_Collection( &pTraceProvidersCollection ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = GetElementFromCollection( pTraceProvidersCollection, + L"name", + szTraceProviderName, + &pTraceProvider ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + // + // Create the trace provider if it doesn't exist. + // + if ( hr == S_FALSE ) + { + hr = AddElementToCollection( pTraceProvidersCollection, + L"add", + ProviderProperties, + _countof( ProviderProperties ), + &pTraceProvider ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + } + + hr = pTraceProvider->GetElementByName( bstrAreas, + &pAreasElement ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pAreasElement->get_Collection( &pAreasCollection ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = GetElementFromCollection( pAreasCollection, + L"name", + szAreaName, + &pAreaElement ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + // + // Add the trace area if it doesn't exist. + // + if ( hr != S_FALSE ) + { + hr = S_OK; + goto exit; + } + + hr = AddElementToCollection( pAreasCollection, + L"add", + AreaProperties, + _countof( AreaProperties ), + NULL ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pAdminMgr->CommitChanges(); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + +exit: + + SysFreeString( bstrAppHostConfigPath ); + SysFreeString( bstrTracingSection ); + SysFreeString( bstrAreas ); + + return hr; +} + +HRESULT +AddElementToCollection( + IN IAppHostElementCollection * pCollection, + IN CONST WCHAR * pElementName, + IN NAME_VALUE_PAIR rgProperties[], + IN DWORD cProperties, + OUT IAppHostElement ** ppElement +) +{ + HRESULT hr = NOERROR; + CComPtr pElement; + CComPtr pProperty; + + BSTR bstrName = NULL; + BSTR bstrElementName = SysAllocString( pElementName ); + + if ( bstrElementName == NULL ) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR(hr); + goto exit; + } + + hr = pCollection->CreateNewElement( bstrElementName, + &pElement ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + for ( DWORD Index = 0; Index < cProperties; Index ++ ) + { + bstrName = SysAllocString( rgProperties[Index].Name ); + if ( bstrName == NULL ) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR(hr); + goto exit; + } + + hr = pElement->GetPropertyByName( bstrName, + &pProperty ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + if ( rgProperties[Index].Value.vt == VT_ERROR ) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR(hr); + goto exit; + } + + hr = pProperty->put_Value( rgProperties[Index].Value ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + SysFreeString( bstrName ); + pProperty.Detach()->Release(); + } + + hr = pCollection->AddElement( pElement ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + if ( ppElement != NULL ) + { + *ppElement = pElement.Detach(); + } + +exit: + + SysFreeString( bstrElementName ); + SysFreeString( bstrName ); + + return hr; +} + +HRESULT +GetElementFromCollection( + IN IAppHostElementCollection * pCollection, + IN CONST WCHAR * szIndex, + IN CONST WCHAR * szExpectedPropertyValue, + OUT IAppHostElement ** ppElement, + OUT DWORD * pIndex +) +{ + HRESULT hr = NOERROR; + DWORD dwElementCount = 0; + CComPtr pElement; + CComPtr pProperty; + + BSTR bstrPropertyName = SysAllocString( szIndex ); + + if ( bstrPropertyName == NULL ) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR(hr); + goto exit; + } + + hr = pCollection->get_Count( &dwElementCount ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + for ( DWORD Index = 0; Index < dwElementCount; Index ++ ) + { + CComVariant value; + + hr = pCollection->get_Item( CComVariant( Index ), + &pElement ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pElement->GetPropertyByName( bstrPropertyName, + &pProperty ); + if ( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pProperty->get_Value( &value ); + if ( value.vt == VT_ERROR ) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR(hr); + goto exit; + } + + if ( value.vt != VT_BSTR ) + { + hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA ); + DBGERROR_HR(hr); + goto exit; + } + + if ( _wcsicmp( value.bstrVal, szExpectedPropertyValue ) == 0 ) + { + // + // Element found. + // + *ppElement = pElement.Detach(); + if ( pIndex != NULL ) + { + *pIndex = Index; + } + hr = S_OK; + goto exit; + } + + pProperty.Detach()->Release(); + pElement.Detach()->Release(); + } + + // + // Element not found. + // + hr = S_FALSE; + +exit: + + SysFreeString( bstrPropertyName ); + + return hr; +} diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/tracing.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/tracing.h new file mode 100644 index 0000000000..087e8ded74 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/tracing.h @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#pragma once + +HRESULT +RegisterTraceArea( + IN CONST WCHAR * szTraceProviderName, + IN CONST WCHAR * szTraceProviderGuid, + IN CONST WCHAR * szAreaName, + IN CONST WCHAR * szAreaValue +); + +HRESULT +GetElementFromCollection( + IN IAppHostElementCollection * pCollection, + IN CONST WCHAR * szPropertyName, + IN CONST WCHAR * szExpectedPropertyValue, + OUT IAppHostElement ** ppElement, + OUT DWORD * pIndex = NULL +); + +struct NAME_VALUE_PAIR +{ + LPCWSTR Name; + CComVariant Value; +}; + +HRESULT +AddElementToCollection( + IN IAppHostElementCollection * pCollection, + IN CONST WCHAR * pElementName, + IN NAME_VALUE_PAIR rgProperties[], + IN DWORD cProperties, + OUT IAppHostElement ** ppElement +); diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/uimodule.cpp b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/uimodule.cpp new file mode 100644 index 0000000000..76adb89ca6 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/uimodule.cpp @@ -0,0 +1,637 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#include "precomp.h" + +class ADMINISTRATION_CONFIG_PATH_MAPPER : public IAppHostPathMapper +{ + +public: + + ADMINISTRATION_CONFIG_PATH_MAPPER( + VOID + ) : _cRefs( 1 ) + { + } + + ~ADMINISTRATION_CONFIG_PATH_MAPPER( + VOID + ) + { + } + + HRESULT + Initialize() + { + // TODO this could be more reliable. + HRESULT hr = NOERROR; + DWORD cch; + + cch = ExpandEnvironmentStringsW( + L"%windir%\\system32\\inetsrv\\config\\administration.config", + _strMappedPath.QueryStr(), + _strMappedPath.QuerySizeCCH() + ); + if( !cch ) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + goto exit; + } + + if( cch > _strMappedPath.QuerySizeCCH() ) + { + hr = _strMappedPath.Resize( cch ); + if( FAILED(hr) ) + { + goto exit; + } + + cch = ExpandEnvironmentStringsW( + L"%windir%\\system32\\inetsrv\\config\\administration.config", + _strMappedPath.QueryStr(), + _strMappedPath.QuerySizeCCH() + ); + if( !cch || + cch > _strMappedPath.QuerySizeCCH() ) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + goto exit; + } + } + + _strMappedPath.SyncWithBuffer(); + + exit: + + return hr; + + } + + ULONG + STDMETHODCALLTYPE + AddRef( + VOID + ) + { + return InterlockedIncrement( &_cRefs ); + } + + ULONG + STDMETHODCALLTYPE + Release( + VOID + ) + { + ULONG ulRet = 0; + + ulRet = InterlockedDecrement( &_cRefs ); + + if ( ulRet == 0 ) + { + delete this; + } + return ulRet; + } + + HRESULT + STDMETHODCALLTYPE + QueryInterface( + REFIID riid, + void ** ppObject + ) + { + if ( riid == __uuidof(IUnknown) || + riid == __uuidof(IAppHostPathMapper) ) + { + AddRef(); + *ppObject = (IAppHostPathMapper*) this; + return S_OK; + } + else + { + *ppObject = NULL; + return E_NOINTERFACE; + } + } + + HRESULT + STDMETHODCALLTYPE + MapPath( + BSTR bstrConfigPath, + BSTR bstrMappedPhysicalPath, + BSTR * pbstrNewPhysicalPath + ) + { + BSTR bstrNewPhysicalPath = NULL; + + if ( wcscmp( bstrConfigPath, L"MACHINE/WEBROOT" ) == 0 ) + { + bstrNewPhysicalPath = SysAllocString( _strMappedPath.QueryStr() ); + } + else + { + bstrNewPhysicalPath = SysAllocString( bstrMappedPhysicalPath ); + } + + if ( bstrNewPhysicalPath == NULL ) + { + return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY ); + } + + *pbstrNewPhysicalPath = bstrNewPhysicalPath; + return S_OK; + } + +private: + + LONG _cRefs; + STRU _strMappedPath; +}; + +HRESULT +InitAdminMgrForAdminConfig( + IN IAppHostWritableAdminManager * pAdminMgr, + IN CONST WCHAR * szCommitPath + ) +{ + HRESULT hr = NOERROR; + + VARIANT varPathMapper; + VariantInit( &varPathMapper ); + + BSTR bstrPathMapperName = SysAllocString( L"pathMapper" ); + BSTR bstrCommitPath = SysAllocString( szCommitPath ); + + ADMINISTRATION_CONFIG_PATH_MAPPER * pPathMapper = NULL; + + if( !bstrPathMapperName || !bstrCommitPath) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR(hr); + goto exit; + } + + hr = pAdminMgr->put_CommitPath( bstrCommitPath ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + pPathMapper = new ADMINISTRATION_CONFIG_PATH_MAPPER(); + if( !pPathMapper ) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR(hr); + goto exit; + } + + hr = pPathMapper->Initialize(); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + varPathMapper.vt = VT_UNKNOWN; + varPathMapper.punkVal = pPathMapper; + pPathMapper = NULL; + + hr = pAdminMgr->SetMetadata( bstrPathMapperName, varPathMapper ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + +exit: + + SysFreeString( bstrPathMapperName ); + SysFreeString( bstrCommitPath ); + + VariantClear( &varPathMapper ); + + if( pPathMapper ) + { + pPathMapper->Release(); + pPathMapper = NULL; + } + + return hr; +} + + +HRESULT +RegisterUIModule( + IN CONST WCHAR * szModuleName, + IN CONST WCHAR * szModuleTypeInfo, + IN OPTIONAL CONST WCHAR * szRegisterInModulesSection, + IN OPTIONAL CONST WCHAR * szPrependToList + ) +{ + HRESULT hr = NOERROR; + + CComPtr pAdminMgr; + CComPtr pProvidersSection; + CComPtr pProvidersCollection; + CComPtr pNewModuleElement; + CComPtr pModulesSection; + CComPtr pModulesCollection; + CComPtr pModulesCollectionElement; + + VARIANT varValue; + VariantInit( &varValue ); + DWORD dwIndex; + BOOL fAddElement = FALSE; + INT cIndex; + + BSTR bstrCommitPath = SysAllocString( L"MACHINE/WEBROOT" ); + BSTR bstrModuleProvidersName = SysAllocString( L"moduleProviders" ); + BSTR bstrAdd = SysAllocString( L"add" ); + BSTR bstrModulesSectionName = SysAllocString( L"modules" ); + + if( !bstrCommitPath || + !bstrModuleProvidersName || + !bstrAdd || + !bstrModulesSectionName ) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR(hr); + goto exit; + } + + hr = CoCreateInstance( __uuidof( AppHostWritableAdminManager ), + NULL, + CLSCTX_INPROC_SERVER, + __uuidof( IAppHostWritableAdminManager ), + (VOID **)&pAdminMgr ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = InitAdminMgrForAdminConfig( pAdminMgr, + bstrCommitPath ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pAdminMgr->GetAdminSection( bstrModuleProvidersName, + bstrCommitPath, + &pProvidersSection ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pProvidersSection->get_Collection( &pProvidersCollection ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = FindElementInCollection( + pProvidersCollection, + L"name", + szModuleName, + FIND_ELEMENT_CASE_SENSITIVE, + &dwIndex); + if (FAILED(hr)) + { + DBGERROR_HR(hr); + goto exit; + } + + if (hr == S_OK) + { + VARIANT vtIndex; + vtIndex.vt = VT_UI4; + vtIndex.ulVal = dwIndex; + + hr = pProvidersCollection->get_Item( + vtIndex, + &pNewModuleElement); + if (FAILED(hr)) + { + DBGERROR_HR(hr); + goto exit; + } + } + else + { + hr = pProvidersCollection->CreateNewElement( bstrAdd, + &pNewModuleElement ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + fAddElement = TRUE; + } + + hr = VariantAssign( &varValue, szModuleName ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = SetElementProperty( pNewModuleElement, + L"name", + &varValue ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = VariantAssign( &varValue, szModuleTypeInfo ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = SetElementProperty( pNewModuleElement, + L"type", + &varValue ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + if (fAddElement) + { + cIndex = -1; + if (szPrependToList && *szPrependToList) + { + cIndex = 0; + } + + hr = pProvidersCollection->AddElement( pNewModuleElement, + cIndex ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + } + + if( szRegisterInModulesSection && *szRegisterInModulesSection ) + { + // register global section + hr = pAdminMgr->GetAdminSection( bstrModulesSectionName, + bstrCommitPath, + &pModulesSection ); + + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pModulesSection->get_Collection( &pModulesCollection ); + + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pModulesCollection->CreateNewElement( bstrAdd, + &pModulesCollectionElement ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = VariantAssign( &varValue, szModuleName ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = SetElementProperty( pModulesCollectionElement, + L"name", + &varValue ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + cIndex = -1; + if (szPrependToList && *szPrependToList) + { + cIndex = 0; + } + + hr = pModulesCollection->AddElement( pModulesCollectionElement, + cIndex ); + if (hr == HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS)) + { + hr = S_OK; + } + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + } + + hr = pAdminMgr->CommitChanges(); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + +exit: + + SysFreeString( bstrCommitPath ); + SysFreeString( bstrModuleProvidersName ); + SysFreeString( bstrAdd ); + SysFreeString( bstrModulesSectionName ); + + VariantClear( &varValue ); + + return hr; +} + +HRESULT +UnRegisterUIModule( + IN CONST WCHAR * szModuleName, + IN CONST WCHAR * szModuleTypeInfo + ) +{ + HRESULT hr = NOERROR; + + CComPtr pAdminMgr; + CComPtr pProvidersSection; + CComPtr pProvidersCollection; + CComPtr pProviderElement; + CComPtr pModulesSection; + CComPtr pModulesCollection; + + BSTR bstrCommitPath = SysAllocString( L"MACHINE/WEBROOT" ); + BSTR bstrModuleProvidersName = SysAllocString( L"moduleProviders" ); + BSTR bstrModulesSectionName = SysAllocString( L"modules" ); + BSTR bstrType = NULL; + DWORD dwIndex; + + if( !bstrCommitPath || + !bstrModuleProvidersName || + !bstrModulesSectionName ) + { + hr = E_OUTOFMEMORY; + DBGERROR_HR(hr); + goto exit; + } + + hr = CoCreateInstance( __uuidof( AppHostWritableAdminManager ), + NULL, + CLSCTX_INPROC_SERVER, + __uuidof( IAppHostWritableAdminManager ), + (VOID **)&pAdminMgr ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = InitAdminMgrForAdminConfig( pAdminMgr, bstrCommitPath ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pAdminMgr->GetAdminSection( bstrModuleProvidersName, + bstrCommitPath, + &pProvidersSection ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pProvidersSection->get_Collection( &pProvidersCollection ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + BOOL fProvidersDeleted = FALSE; + + hr = FindElementInCollection( + pProvidersCollection, + L"name", + szModuleName, + FIND_ELEMENT_CASE_SENSITIVE, + &dwIndex); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + if (hr == S_OK) + { + VARIANT vtIndex; + vtIndex.vt = VT_UI4; + vtIndex.ulVal = dwIndex; + + hr = pProvidersCollection->get_Item( + vtIndex, + &pProviderElement); + if (FAILED(hr)) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = GetElementStringProperty( + pProviderElement, + L"type", + &bstrType); + if (FAILED(hr)) + { + DBGERROR_HR(hr); + goto exit; + } + + if (wcscmp(bstrType, szModuleTypeInfo) == 0) + { + hr = pProvidersCollection->DeleteElement(vtIndex); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + fProvidersDeleted = TRUE; + } + else + { + goto exit; + } + } + + // now remove from global section if present + hr = pAdminMgr->GetAdminSection( bstrModulesSectionName, + bstrCommitPath, + &pModulesSection ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + hr = pModulesSection->get_Collection( &pModulesCollection ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + BOOL fModulesDeleted = FALSE; + hr = DeleteElementFromCollection( pModulesCollection, + L"name", + szModuleName, + FIND_ELEMENT_CASE_SENSITIVE, + &fModulesDeleted ); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + + if( fProvidersDeleted || fModulesDeleted ) + { + hr = pAdminMgr->CommitChanges(); + if( FAILED(hr) ) + { + DBGERROR_HR(hr); + goto exit; + } + } + +exit: + + SysFreeString( bstrCommitPath ); + SysFreeString( bstrModuleProvidersName ); + SysFreeString( bstrModulesSectionName ); + SysFreeString( bstrType ); + + return hr; +} + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/wuerror.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/wuerror.h new file mode 100644 index 0000000000..a735af0cf7 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/lib/wuerror.h @@ -0,0 +1,2456 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +/*************************************************************************** +* * +* wuerror.mc -- error code definitions for Windows Update. * +* * +***************************************************************************/ +#ifndef _WUERROR_ +#define _WUERROR_ + +#if defined (_MSC_VER) && (_MSC_VER >= 1020) && !defined(__midl) +#pragma once +#endif + +#ifdef RC_INVOKED +#define _HRESULT_TYPEDEF_(_sc) _sc +#else // RC_INVOKED +#define _HRESULT_TYPEDEF_(_sc) ((HRESULT)_sc) +#endif // RC_INVOKED + + +/////////////////////////////////////////////////////////////////////////////// +// Windows Update Success Codes +/////////////////////////////////////////////////////////////////////////////// +// +// Values are 32 bit values laid out as follows: +// +// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 +// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +// +---+-+-+-----------------------+-------------------------------+ +// |Sev|C|R| Facility | Code | +// +---+-+-+-----------------------+-------------------------------+ +// +// where +// +// Sev - is the severity code +// +// 00 - Success +// 01 - Informational +// 10 - Warning +// 11 - Error +// +// C - is the Customer code flag +// +// R - is a reserved bit +// +// Facility - is the facility code +// +// Code - is the facility's status code +// +// +// Define the facility codes +// + + +// +// Define the severity codes +// + + +// +// MessageId: WU_S_SERVICE_STOP +// +// MessageText: +// +// Windows Update Agent was stopped successfully. +// +#define WU_S_SERVICE_STOP _HRESULT_TYPEDEF_(0x00240001L) + +// +// MessageId: WU_S_SELFUPDATE +// +// MessageText: +// +// Windows Update Agent updated itself. +// +#define WU_S_SELFUPDATE _HRESULT_TYPEDEF_(0x00240002L) + +// +// MessageId: WU_S_UPDATE_ERROR +// +// MessageText: +// +// Operation completed successfully but there were errors applying the updates. +// +#define WU_S_UPDATE_ERROR _HRESULT_TYPEDEF_(0x00240003L) + +// +// MessageId: WU_S_MARKED_FOR_DISCONNECT +// +// MessageText: +// +// A callback was marked to be disconnected later because the request to disconnect the operation came while a callback was executing. +// +#define WU_S_MARKED_FOR_DISCONNECT _HRESULT_TYPEDEF_(0x00240004L) + +// +// MessageId: WU_S_REBOOT_REQUIRED +// +// MessageText: +// +// The system must be restarted to complete installation of the update. +// +#define WU_S_REBOOT_REQUIRED _HRESULT_TYPEDEF_(0x00240005L) + +// +// MessageId: WU_S_ALREADY_INSTALLED +// +// MessageText: +// +// The update to be installed is already installed on the system. +// +#define WU_S_ALREADY_INSTALLED _HRESULT_TYPEDEF_(0x00240006L) + +// +// MessageId: WU_S_ALREADY_UNINSTALLED +// +// MessageText: +// +// The update to be removed is not installed on the system. +// +#define WU_S_ALREADY_UNINSTALLED _HRESULT_TYPEDEF_(0x00240007L) + +// +// MessageId: WU_S_ALREADY_DOWNLOADED +// +// MessageText: +// +// The update to be downloaded has already been downloaded. +// +#define WU_S_ALREADY_DOWNLOADED _HRESULT_TYPEDEF_(0x00240008L) + +/////////////////////////////////////////////////////////////////////////////// +// Windows Update Error Codes +/////////////////////////////////////////////////////////////////////////////// +// +// MessageId: WU_E_NO_SERVICE +// +// MessageText: +// +// Windows Update Agent was unable to provide the service. +// +#define WU_E_NO_SERVICE _HRESULT_TYPEDEF_(0x80240001L) + +// +// MessageId: WU_E_MAX_CAPACITY_REACHED +// +// MessageText: +// +// The maximum capacity of the service was exceeded. +// +#define WU_E_MAX_CAPACITY_REACHED _HRESULT_TYPEDEF_(0x80240002L) + +// +// MessageId: WU_E_UNKNOWN_ID +// +// MessageText: +// +// An ID cannot be found. +// +#define WU_E_UNKNOWN_ID _HRESULT_TYPEDEF_(0x80240003L) + +// +// MessageId: WU_E_NOT_INITIALIZED +// +// MessageText: +// +// The object could not be initialized. +// +#define WU_E_NOT_INITIALIZED _HRESULT_TYPEDEF_(0x80240004L) + +// +// MessageId: WU_E_RANGEOVERLAP +// +// MessageText: +// +// The update handler requested a byte range overlapping a previously requested range. +// +#define WU_E_RANGEOVERLAP _HRESULT_TYPEDEF_(0x80240005L) + +// +// MessageId: WU_E_TOOMANYRANGES +// +// MessageText: +// +// The requested number of byte ranges exceeds the maximum number (2^31 - 1). +// +#define WU_E_TOOMANYRANGES _HRESULT_TYPEDEF_(0x80240006L) + +// +// MessageId: WU_E_INVALIDINDEX +// +// MessageText: +// +// The index to a collection was invalid. +// +#define WU_E_INVALIDINDEX _HRESULT_TYPEDEF_(0x80240007L) + +// +// MessageId: WU_E_ITEMNOTFOUND +// +// MessageText: +// +// The key for the item queried could not be found. +// +#define WU_E_ITEMNOTFOUND _HRESULT_TYPEDEF_(0x80240008L) + +// +// MessageId: WU_E_OPERATIONINPROGRESS +// +// MessageText: +// +// Another conflicting operation was in progress. Some operations such as installation cannot be performed twice simultaneously. +// +#define WU_E_OPERATIONINPROGRESS _HRESULT_TYPEDEF_(0x80240009L) + +// +// MessageId: WU_E_COULDNOTCANCEL +// +// MessageText: +// +// Cancellation of the operation was not allowed. +// +#define WU_E_COULDNOTCANCEL _HRESULT_TYPEDEF_(0x8024000AL) + +// +// MessageId: WU_E_CALL_CANCELLED +// +// MessageText: +// +// Operation was cancelled. +// +#define WU_E_CALL_CANCELLED _HRESULT_TYPEDEF_(0x8024000BL) + +// +// MessageId: WU_E_NOOP +// +// MessageText: +// +// No operation was required. +// +#define WU_E_NOOP _HRESULT_TYPEDEF_(0x8024000CL) + +// +// MessageId: WU_E_XML_MISSINGDATA +// +// MessageText: +// +// Windows Update Agent could not find required information in the update's XML data. +// +#define WU_E_XML_MISSINGDATA _HRESULT_TYPEDEF_(0x8024000DL) + +// +// MessageId: WU_E_XML_INVALID +// +// MessageText: +// +// Windows Update Agent found invalid information in the update's XML data. +// +#define WU_E_XML_INVALID _HRESULT_TYPEDEF_(0x8024000EL) + +// +// MessageId: WU_E_CYCLE_DETECTED +// +// MessageText: +// +// Circular update relationships were detected in the metadata. +// +#define WU_E_CYCLE_DETECTED _HRESULT_TYPEDEF_(0x8024000FL) + +// +// MessageId: WU_E_TOO_DEEP_RELATION +// +// MessageText: +// +// Update relationships too deep to evaluate were evaluated. +// +#define WU_E_TOO_DEEP_RELATION _HRESULT_TYPEDEF_(0x80240010L) + +// +// MessageId: WU_E_INVALID_RELATIONSHIP +// +// MessageText: +// +// An invalid update relationship was detected. +// +#define WU_E_INVALID_RELATIONSHIP _HRESULT_TYPEDEF_(0x80240011L) + +// +// MessageId: WU_E_REG_VALUE_INVALID +// +// MessageText: +// +// An invalid registry value was read. +// +#define WU_E_REG_VALUE_INVALID _HRESULT_TYPEDEF_(0x80240012L) + +// +// MessageId: WU_E_DUPLICATE_ITEM +// +// MessageText: +// +// Operation tried to add a duplicate item to a list. +// +#define WU_E_DUPLICATE_ITEM _HRESULT_TYPEDEF_(0x80240013L) + +// +// MessageId: WU_E_INSTALL_NOT_ALLOWED +// +// MessageText: +// +// Operation tried to install while another installation was in progress or the system was pending a mandatory restart. +// +#define WU_E_INSTALL_NOT_ALLOWED _HRESULT_TYPEDEF_(0x80240016L) + +// +// MessageId: WU_E_NOT_APPLICABLE +// +// MessageText: +// +// Operation was not performed because there are no applicable updates. +// +#define WU_E_NOT_APPLICABLE _HRESULT_TYPEDEF_(0x80240017L) + +// +// MessageId: WU_E_NO_USERTOKEN +// +// MessageText: +// +// Operation failed because a required user token is missing. +// +#define WU_E_NO_USERTOKEN _HRESULT_TYPEDEF_(0x80240018L) + +// +// MessageId: WU_E_EXCLUSIVE_INSTALL_CONFLICT +// +// MessageText: +// +// An exclusive update cannot be installed with other updates at the same time. +// +#define WU_E_EXCLUSIVE_INSTALL_CONFLICT _HRESULT_TYPEDEF_(0x80240019L) + +// +// MessageId: WU_E_POLICY_NOT_SET +// +// MessageText: +// +// A policy value was not set. +// +#define WU_E_POLICY_NOT_SET _HRESULT_TYPEDEF_(0x8024001AL) + +// +// MessageId: WU_E_SELFUPDATE_IN_PROGRESS +// +// MessageText: +// +// The operation could not be performed because the Windows Update Agent is self-updating. +// +#define WU_E_SELFUPDATE_IN_PROGRESS _HRESULT_TYPEDEF_(0x8024001BL) + +// +// MessageId: WU_E_INVALID_UPDATE +// +// MessageText: +// +// An update contains invalid metadata. +// +#define WU_E_INVALID_UPDATE _HRESULT_TYPEDEF_(0x8024001DL) + +// +// MessageId: WU_E_SERVICE_STOP +// +// MessageText: +// +// Operation did not complete because the service or system was being shut down. +// +#define WU_E_SERVICE_STOP _HRESULT_TYPEDEF_(0x8024001EL) + +// +// MessageId: WU_E_NO_CONNECTION +// +// MessageText: +// +// Operation did not complete because the network connection was unavailable. +// +#define WU_E_NO_CONNECTION _HRESULT_TYPEDEF_(0x8024001FL) + +// +// MessageId: WU_E_NO_INTERACTIVE_USER +// +// MessageText: +// +// Operation did not complete because there is no logged-on interactive user. +// +#define WU_E_NO_INTERACTIVE_USER _HRESULT_TYPEDEF_(0x80240020L) + +// +// MessageId: WU_E_TIME_OUT +// +// MessageText: +// +// Operation did not complete because it timed out. +// +#define WU_E_TIME_OUT _HRESULT_TYPEDEF_(0x80240021L) + +// +// MessageId: WU_E_ALL_UPDATES_FAILED +// +// MessageText: +// +// Operation failed for all the updates. +// +#define WU_E_ALL_UPDATES_FAILED _HRESULT_TYPEDEF_(0x80240022L) + +// +// MessageId: WU_E_EULAS_DECLINED +// +// MessageText: +// +// The license terms for all updates were declined. +// +#define WU_E_EULAS_DECLINED _HRESULT_TYPEDEF_(0x80240023L) + +// +// MessageId: WU_E_NO_UPDATE +// +// MessageText: +// +// There are no updates. +// +#define WU_E_NO_UPDATE _HRESULT_TYPEDEF_(0x80240024L) + +// +// MessageId: WU_E_USER_ACCESS_DISABLED +// +// MessageText: +// +// Group Policy settings prevented access to Windows Update. +// +#define WU_E_USER_ACCESS_DISABLED _HRESULT_TYPEDEF_(0x80240025L) + +// +// MessageId: WU_E_INVALID_UPDATE_TYPE +// +// MessageText: +// +// The type of update is invalid. +// +#define WU_E_INVALID_UPDATE_TYPE _HRESULT_TYPEDEF_(0x80240026L) + +// +// MessageId: WU_E_URL_TOO_LONG +// +// MessageText: +// +// The URL exceeded the maximum length. +// +#define WU_E_URL_TOO_LONG _HRESULT_TYPEDEF_(0x80240027L) + +// +// MessageId: WU_E_UNINSTALL_NOT_ALLOWED +// +// MessageText: +// +// The update could not be uninstalled because the request did not originate from a WSUS server. +// +#define WU_E_UNINSTALL_NOT_ALLOWED _HRESULT_TYPEDEF_(0x80240028L) + +// +// MessageId: WU_E_INVALID_PRODUCT_LICENSE +// +// MessageText: +// +// Search may have missed some updates before there is an unlicensed application on the system. +// +#define WU_E_INVALID_PRODUCT_LICENSE _HRESULT_TYPEDEF_(0x80240029L) + +// +// MessageId: WU_E_MISSING_HANDLER +// +// MessageText: +// +// A component required to detect applicable updates was missing. +// +#define WU_E_MISSING_HANDLER _HRESULT_TYPEDEF_(0x8024002AL) + +// +// MessageId: WU_E_LEGACYSERVER +// +// MessageText: +// +// An operation did not complete because it requires a newer version of server. +// +#define WU_E_LEGACYSERVER _HRESULT_TYPEDEF_(0x8024002BL) + +// +// MessageId: WU_E_BIN_SOURCE_ABSENT +// +// MessageText: +// +// A delta-compressed update could not be installed because it required the source. +// +#define WU_E_BIN_SOURCE_ABSENT _HRESULT_TYPEDEF_(0x8024002CL) + +// +// MessageId: WU_E_SOURCE_ABSENT +// +// MessageText: +// +// A full-file update could not be installed because it required the source. +// +#define WU_E_SOURCE_ABSENT _HRESULT_TYPEDEF_(0x8024002DL) + +// +// MessageId: WU_E_WU_DISABLED +// +// MessageText: +// +// Access to an unmanaged server is not allowed. +// +#define WU_E_WU_DISABLED _HRESULT_TYPEDEF_(0x8024002EL) + +// +// MessageId: WU_E_CALL_CANCELLED_BY_POLICY +// +// MessageText: +// +// Operation did not complete because the DisableWindowsUpdateAccess policy was set. +// +#define WU_E_CALL_CANCELLED_BY_POLICY _HRESULT_TYPEDEF_(0x8024002FL) + +// +// MessageId: WU_E_INVALID_PROXY_SERVER +// +// MessageText: +// +// The format of the proxy list was invalid. +// +#define WU_E_INVALID_PROXY_SERVER _HRESULT_TYPEDEF_(0x80240030L) + +// +// MessageId: WU_E_INVALID_FILE +// +// MessageText: +// +// The file is in the wrong format. +// +#define WU_E_INVALID_FILE _HRESULT_TYPEDEF_(0x80240031L) + +// +// MessageId: WU_E_INVALID_CRITERIA +// +// MessageText: +// +// The search criteria string was invalid. +// +#define WU_E_INVALID_CRITERIA _HRESULT_TYPEDEF_(0x80240032L) + +// +// MessageId: WU_E_EULA_UNAVAILABLE +// +// MessageText: +// +// License terms could not be downloaded. +// +#define WU_E_EULA_UNAVAILABLE _HRESULT_TYPEDEF_(0x80240033L) + +// +// MessageId: WU_E_DOWNLOAD_FAILED +// +// MessageText: +// +// Update failed to download. +// +#define WU_E_DOWNLOAD_FAILED _HRESULT_TYPEDEF_(0x80240034L) + +// +// MessageId: WU_E_UPDATE_NOT_PROCESSED +// +// MessageText: +// +// The update was not processed. +// +#define WU_E_UPDATE_NOT_PROCESSED _HRESULT_TYPEDEF_(0x80240035L) + +// +// MessageId: WU_E_INVALID_OPERATION +// +// MessageText: +// +// The object's current state did not allow the operation. +// +#define WU_E_INVALID_OPERATION _HRESULT_TYPEDEF_(0x80240036L) + +// +// MessageId: WU_E_NOT_SUPPORTED +// +// MessageText: +// +// The functionality for the operation is not supported. +// +#define WU_E_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x80240037L) + +// +// MessageId: WU_E_WINHTTP_INVALID_FILE +// +// MessageText: +// +// The downloaded file has an unexpected content type. +// +#define WU_E_WINHTTP_INVALID_FILE _HRESULT_TYPEDEF_(0x80240038L) + +// +// MessageId: WU_E_TOO_MANY_RESYNC +// +// MessageText: +// +// Agent is asked by server to resync too many times. +// +#define WU_E_TOO_MANY_RESYNC _HRESULT_TYPEDEF_(0x80240039L) + +// +// MessageId: WU_E_NO_SERVER_CORE_SUPPORT +// +// MessageText: +// +// WUA API method does not run on Server Core installation. +// +#define WU_E_NO_SERVER_CORE_SUPPORT _HRESULT_TYPEDEF_(0x80240040L) + +// +// MessageId: WU_E_SYSPREP_IN_PROGRESS +// +// MessageText: +// +// Service is not available while sysprep is running. +// +#define WU_E_SYSPREP_IN_PROGRESS _HRESULT_TYPEDEF_(0x80240041L) + +// +// MessageId: WU_E_UNKNOWN_SERVICE +// +// MessageText: +// +// The update service is no longer registered with AU. +// +#define WU_E_UNKNOWN_SERVICE _HRESULT_TYPEDEF_(0x80240042L) + +// +// MessageId: WU_E_NO_UI_SUPPORT +// +// MessageText: +// +// There is no support for WUA UI. +// +#define WU_E_NO_UI_SUPPORT _HRESULT_TYPEDEF_(0x80240043L) + +// +// MessageId: WU_E_UNEXPECTED +// +// MessageText: +// +// An operation failed due to reasons not covered by another error code. +// +#define WU_E_UNEXPECTED _HRESULT_TYPEDEF_(0x80240FFFL) + +/////////////////////////////////////////////////////////////////////////////// +// Windows Installer minor errors +// +// The following errors are used to indicate that part of a search failed for +// MSI problems. Another part of the search may successfully return updates. +// All MSI minor codes should share the same error code range so that the caller +// tell that they are related to Windows Installer. +/////////////////////////////////////////////////////////////////////////////// +// +// MessageId: WU_E_MSI_WRONG_VERSION +// +// MessageText: +// +// Search may have missed some updates because the Windows Installer is less than version 3.1. +// +#define WU_E_MSI_WRONG_VERSION _HRESULT_TYPEDEF_(0x80241001L) + +// +// MessageId: WU_E_MSI_NOT_CONFIGURED +// +// MessageText: +// +// Search may have missed some updates because the Windows Installer is not configured. +// +#define WU_E_MSI_NOT_CONFIGURED _HRESULT_TYPEDEF_(0x80241002L) + +// +// MessageId: WU_E_MSP_DISABLED +// +// MessageText: +// +// Search may have missed some updates because policy has disabled Windows Installer patching. +// +#define WU_E_MSP_DISABLED _HRESULT_TYPEDEF_(0x80241003L) + +// +// MessageId: WU_E_MSI_WRONG_APP_CONTEXT +// +// MessageText: +// +// An update could not be applied because the application is installed per-user. +// +#define WU_E_MSI_WRONG_APP_CONTEXT _HRESULT_TYPEDEF_(0x80241004L) + +// +// MessageId: WU_E_MSP_UNEXPECTED +// +// MessageText: +// +// Search may have missed some updates because there was a failure of the Windows Installer. +// +#define WU_E_MSP_UNEXPECTED _HRESULT_TYPEDEF_(0x80241FFFL) + +/////////////////////////////////////////////////////////////////////////////// +// Protocol Talker errors +// +// The following map to SOAPCLIENT_ERRORs from atlsoap.h. These errors +// are obtained from calling GetClientError() on the CClientWebService +// object. +/////////////////////////////////////////////////////////////////////////////// +// +// MessageId: WU_E_PT_SOAPCLIENT_BASE +// +// MessageText: +// +// WU_E_PT_SOAPCLIENT_* error codes map to the SOAPCLIENT_ERROR enum of the ATL Server Library. +// +#define WU_E_PT_SOAPCLIENT_BASE _HRESULT_TYPEDEF_(0x80244000L) + +// +// MessageId: WU_E_PT_SOAPCLIENT_INITIALIZE +// +// MessageText: +// +// Same as SOAPCLIENT_INITIALIZE_ERROR - initialization of the SOAP client failed, possibly because of an MSXML installation failure. +// +#define WU_E_PT_SOAPCLIENT_INITIALIZE _HRESULT_TYPEDEF_(0x80244001L) + +// +// MessageId: WU_E_PT_SOAPCLIENT_OUTOFMEMORY +// +// MessageText: +// +// Same as SOAPCLIENT_OUTOFMEMORY - SOAP client failed because it ran out of memory. +// +#define WU_E_PT_SOAPCLIENT_OUTOFMEMORY _HRESULT_TYPEDEF_(0x80244002L) + +// +// MessageId: WU_E_PT_SOAPCLIENT_GENERATE +// +// MessageText: +// +// Same as SOAPCLIENT_GENERATE_ERROR - SOAP client failed to generate the request. +// +#define WU_E_PT_SOAPCLIENT_GENERATE _HRESULT_TYPEDEF_(0x80244003L) + +// +// MessageId: WU_E_PT_SOAPCLIENT_CONNECT +// +// MessageText: +// +// Same as SOAPCLIENT_CONNECT_ERROR - SOAP client failed to connect to the server. +// +#define WU_E_PT_SOAPCLIENT_CONNECT _HRESULT_TYPEDEF_(0x80244004L) + +// +// MessageId: WU_E_PT_SOAPCLIENT_SEND +// +// MessageText: +// +// Same as SOAPCLIENT_SEND_ERROR - SOAP client failed to send a message for reasons of WU_E_WINHTTP_* error codes. +// +#define WU_E_PT_SOAPCLIENT_SEND _HRESULT_TYPEDEF_(0x80244005L) + +// +// MessageId: WU_E_PT_SOAPCLIENT_SERVER +// +// MessageText: +// +// Same as SOAPCLIENT_SERVER_ERROR - SOAP client failed because there was a server error. +// +#define WU_E_PT_SOAPCLIENT_SERVER _HRESULT_TYPEDEF_(0x80244006L) + +// +// MessageId: WU_E_PT_SOAPCLIENT_SOAPFAULT +// +// MessageText: +// +// Same as SOAPCLIENT_SOAPFAULT - SOAP client failed because there was a SOAP fault for reasons of WU_E_PT_SOAP_* error codes. +// +#define WU_E_PT_SOAPCLIENT_SOAPFAULT _HRESULT_TYPEDEF_(0x80244007L) + +// +// MessageId: WU_E_PT_SOAPCLIENT_PARSEFAULT +// +// MessageText: +// +// Same as SOAPCLIENT_PARSEFAULT_ERROR - SOAP client failed to parse a SOAP fault. +// +#define WU_E_PT_SOAPCLIENT_PARSEFAULT _HRESULT_TYPEDEF_(0x80244008L) + +// +// MessageId: WU_E_PT_SOAPCLIENT_READ +// +// MessageText: +// +// Same as SOAPCLIENT_READ_ERROR - SOAP client failed while reading the response from the server. +// +#define WU_E_PT_SOAPCLIENT_READ _HRESULT_TYPEDEF_(0x80244009L) + +// +// MessageId: WU_E_PT_SOAPCLIENT_PARSE +// +// MessageText: +// +// Same as SOAPCLIENT_PARSE_ERROR - SOAP client failed to parse the response from the server. +// +#define WU_E_PT_SOAPCLIENT_PARSE _HRESULT_TYPEDEF_(0x8024400AL) + +// The following map to SOAP_ERROR_CODEs from atlsoap.h. These errors +// are obtained from the m_fault.m_soapErrCode member on the +// CClientWebService object when GetClientError() returned +// SOAPCLIENT_SOAPFAULT. +// +// MessageId: WU_E_PT_SOAP_VERSION +// +// MessageText: +// +// Same as SOAP_E_VERSION_MISMATCH - SOAP client found an unrecognizable namespace for the SOAP envelope. +// +#define WU_E_PT_SOAP_VERSION _HRESULT_TYPEDEF_(0x8024400BL) + +// +// MessageId: WU_E_PT_SOAP_MUST_UNDERSTAND +// +// MessageText: +// +// Same as SOAP_E_MUST_UNDERSTAND - SOAP client was unable to understand a header. +// +#define WU_E_PT_SOAP_MUST_UNDERSTAND _HRESULT_TYPEDEF_(0x8024400CL) + +// +// MessageId: WU_E_PT_SOAP_CLIENT +// +// MessageText: +// +// Same as SOAP_E_CLIENT - SOAP client found the message was malformed; fix before resending. +// +#define WU_E_PT_SOAP_CLIENT _HRESULT_TYPEDEF_(0x8024400DL) + +// +// MessageId: WU_E_PT_SOAP_SERVER +// +// MessageText: +// +// Same as SOAP_E_SERVER - The SOAP message could not be processed due to a server error; resend later. +// +#define WU_E_PT_SOAP_SERVER _HRESULT_TYPEDEF_(0x8024400EL) + +// +// MessageId: WU_E_PT_WMI_ERROR +// +// MessageText: +// +// There was an unspecified Windows Management Instrumentation (WMI) error. +// +#define WU_E_PT_WMI_ERROR _HRESULT_TYPEDEF_(0x8024400FL) + +// +// MessageId: WU_E_PT_EXCEEDED_MAX_SERVER_TRIPS +// +// MessageText: +// +// The number of round trips to the server exceeded the maximum limit. +// +#define WU_E_PT_EXCEEDED_MAX_SERVER_TRIPS _HRESULT_TYPEDEF_(0x80244010L) + +// +// MessageId: WU_E_PT_SUS_SERVER_NOT_SET +// +// MessageText: +// +// WUServer policy value is missing in the registry. +// +#define WU_E_PT_SUS_SERVER_NOT_SET _HRESULT_TYPEDEF_(0x80244011L) + +// +// MessageId: WU_E_PT_DOUBLE_INITIALIZATION +// +// MessageText: +// +// Initialization failed because the object was already initialized. +// +#define WU_E_PT_DOUBLE_INITIALIZATION _HRESULT_TYPEDEF_(0x80244012L) + +// +// MessageId: WU_E_PT_INVALID_COMPUTER_NAME +// +// MessageText: +// +// The computer name could not be determined. +// +#define WU_E_PT_INVALID_COMPUTER_NAME _HRESULT_TYPEDEF_(0x80244013L) + +// +// MessageId: WU_E_PT_REFRESH_CACHE_REQUIRED +// +// MessageText: +// +// The reply from the server indicates that the server was changed or the cookie was invalid; refresh the state of the internal cache and retry. +// +#define WU_E_PT_REFRESH_CACHE_REQUIRED _HRESULT_TYPEDEF_(0x80244015L) + +// +// MessageId: WU_E_PT_HTTP_STATUS_BAD_REQUEST +// +// MessageText: +// +// Same as HTTP status 400 - the server could not process the request due to invalid syntax. +// +#define WU_E_PT_HTTP_STATUS_BAD_REQUEST _HRESULT_TYPEDEF_(0x80244016L) + +// +// MessageId: WU_E_PT_HTTP_STATUS_DENIED +// +// MessageText: +// +// Same as HTTP status 401 - the requested resource requires user authentication. +// +#define WU_E_PT_HTTP_STATUS_DENIED _HRESULT_TYPEDEF_(0x80244017L) + +// +// MessageId: WU_E_PT_HTTP_STATUS_FORBIDDEN +// +// MessageText: +// +// Same as HTTP status 403 - server understood the request, but declined to fulfill it. +// +#define WU_E_PT_HTTP_STATUS_FORBIDDEN _HRESULT_TYPEDEF_(0x80244018L) + +// +// MessageId: WU_E_PT_HTTP_STATUS_NOT_FOUND +// +// MessageText: +// +// Same as HTTP status 404 - the server cannot find the requested URI (Uniform Resource Identifier). +// +// +#define WU_E_PT_HTTP_STATUS_NOT_FOUND _HRESULT_TYPEDEF_(0x80244019L) + +// +// MessageId: WU_E_PT_HTTP_STATUS_BAD_METHOD +// +// MessageText: +// +// Same as HTTP status 405 - the HTTP method is not allowed. +// +#define WU_E_PT_HTTP_STATUS_BAD_METHOD _HRESULT_TYPEDEF_(0x8024401AL) + +// +// MessageId: WU_E_PT_HTTP_STATUS_PROXY_AUTH_REQ +// +// MessageText: +// +// Same as HTTP status 407 - proxy authentication is required. +// +#define WU_E_PT_HTTP_STATUS_PROXY_AUTH_REQ _HRESULT_TYPEDEF_(0x8024401BL) + +// +// MessageId: WU_E_PT_HTTP_STATUS_REQUEST_TIMEOUT +// +// MessageText: +// +// Same as HTTP status 408 - the server timed out waiting for the request. +// +#define WU_E_PT_HTTP_STATUS_REQUEST_TIMEOUT _HRESULT_TYPEDEF_(0x8024401CL) + +// +// MessageId: WU_E_PT_HTTP_STATUS_CONFLICT +// +// MessageText: +// +// Same as HTTP status 409 - the request was not completed due to a conflict with the current state of the resource. +// +#define WU_E_PT_HTTP_STATUS_CONFLICT _HRESULT_TYPEDEF_(0x8024401DL) + +// +// MessageId: WU_E_PT_HTTP_STATUS_GONE +// +// MessageText: +// +// Same as HTTP status 410 - requested resource is no longer available at the server. +// +#define WU_E_PT_HTTP_STATUS_GONE _HRESULT_TYPEDEF_(0x8024401EL) + +// +// MessageId: WU_E_PT_HTTP_STATUS_SERVER_ERROR +// +// MessageText: +// +// Same as HTTP status 500 - an error internal to the server prevented fulfilling the request. +// +#define WU_E_PT_HTTP_STATUS_SERVER_ERROR _HRESULT_TYPEDEF_(0x8024401FL) + +// +// MessageId: WU_E_PT_HTTP_STATUS_NOT_SUPPORTED +// +// MessageText: +// +// Same as HTTP status 500 - server does not support the functionality required to fulfill the request. +// +#define WU_E_PT_HTTP_STATUS_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x80244020L) + +// +// MessageId: WU_E_PT_HTTP_STATUS_BAD_GATEWAY +// +// MessageText: +// +// Same as HTTP status 502 - the server, while acting as a gateway or proxy, received an invalid response from the upstream server it accessed in attempting to fulfill the request. +// +#define WU_E_PT_HTTP_STATUS_BAD_GATEWAY _HRESULT_TYPEDEF_(0x80244021L) + +// +// MessageId: WU_E_PT_HTTP_STATUS_SERVICE_UNAVAIL +// +// MessageText: +// +// Same as HTTP status 503 - the service is temporarily overloaded. +// +#define WU_E_PT_HTTP_STATUS_SERVICE_UNAVAIL _HRESULT_TYPEDEF_(0x80244022L) + +// +// MessageId: WU_E_PT_HTTP_STATUS_GATEWAY_TIMEOUT +// +// MessageText: +// +// Same as HTTP status 503 - the request was timed out waiting for a gateway. +// +#define WU_E_PT_HTTP_STATUS_GATEWAY_TIMEOUT _HRESULT_TYPEDEF_(0x80244023L) + +// +// MessageId: WU_E_PT_HTTP_STATUS_VERSION_NOT_SUP +// +// MessageText: +// +// Same as HTTP status 505 - the server does not support the HTTP protocol version used for the request. +// +#define WU_E_PT_HTTP_STATUS_VERSION_NOT_SUP _HRESULT_TYPEDEF_(0x80244024L) + +// +// MessageId: WU_E_PT_FILE_LOCATIONS_CHANGED +// +// MessageText: +// +// Operation failed due to a changed file location; refresh internal state and resend. +// +#define WU_E_PT_FILE_LOCATIONS_CHANGED _HRESULT_TYPEDEF_(0x80244025L) + +// +// MessageId: WU_E_PT_REGISTRATION_NOT_SUPPORTED +// +// MessageText: +// +// Operation failed because Windows Update Agent does not support registration with a non-WSUS server. +// +#define WU_E_PT_REGISTRATION_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x80244026L) + +// +// MessageId: WU_E_PT_NO_AUTH_PLUGINS_REQUESTED +// +// MessageText: +// +// The server returned an empty authentication information list. +// +#define WU_E_PT_NO_AUTH_PLUGINS_REQUESTED _HRESULT_TYPEDEF_(0x80244027L) + +// +// MessageId: WU_E_PT_NO_AUTH_COOKIES_CREATED +// +// MessageText: +// +// Windows Update Agent was unable to create any valid authentication cookies. +// +#define WU_E_PT_NO_AUTH_COOKIES_CREATED _HRESULT_TYPEDEF_(0x80244028L) + +// +// MessageId: WU_E_PT_INVALID_CONFIG_PROP +// +// MessageText: +// +// A configuration property value was wrong. +// +#define WU_E_PT_INVALID_CONFIG_PROP _HRESULT_TYPEDEF_(0x80244029L) + +// +// MessageId: WU_E_PT_CONFIG_PROP_MISSING +// +// MessageText: +// +// A configuration property value was missing. +// +#define WU_E_PT_CONFIG_PROP_MISSING _HRESULT_TYPEDEF_(0x8024402AL) + +// +// MessageId: WU_E_PT_HTTP_STATUS_NOT_MAPPED +// +// MessageText: +// +// The HTTP request could not be completed and the reason did not correspond to any of the WU_E_PT_HTTP_* error codes. +// +#define WU_E_PT_HTTP_STATUS_NOT_MAPPED _HRESULT_TYPEDEF_(0x8024402BL) + +// +// MessageId: WU_E_PT_WINHTTP_NAME_NOT_RESOLVED +// +// MessageText: +// +// Same as ERROR_WINHTTP_NAME_NOT_RESOLVED - the proxy server or target server name cannot be resolved. +// +#define WU_E_PT_WINHTTP_NAME_NOT_RESOLVED _HRESULT_TYPEDEF_(0x8024402CL) + +// +// MessageId: WU_E_PT_SAME_REDIR_ID +// +// MessageText: +// +// Windows Update Agent failed to download a redirector cabinet file with a new redirectorId value from the server during the recovery. +// +#define WU_E_PT_SAME_REDIR_ID _HRESULT_TYPEDEF_(0x8024502DL) + +// +// MessageId: WU_E_PT_NO_MANAGED_RECOVER +// +// MessageText: +// +// A redirector recovery action did not complete because the server is managed. +// +#define WU_E_PT_NO_MANAGED_RECOVER _HRESULT_TYPEDEF_(0x8024502EL) + +// +// MessageId: WU_E_PT_ECP_SUCCEEDED_WITH_ERRORS +// +// MessageText: +// +// External cab file processing completed with some errors. +// +#define WU_E_PT_ECP_SUCCEEDED_WITH_ERRORS _HRESULT_TYPEDEF_(0x8024402FL) + +// +// MessageId: WU_E_PT_ECP_INIT_FAILED +// +// MessageText: +// +// The external cab processor initialization did not complete. +// +#define WU_E_PT_ECP_INIT_FAILED _HRESULT_TYPEDEF_(0x80244030L) + +// +// MessageId: WU_E_PT_ECP_INVALID_FILE_FORMAT +// +// MessageText: +// +// The format of a metadata file was invalid. +// +#define WU_E_PT_ECP_INVALID_FILE_FORMAT _HRESULT_TYPEDEF_(0x80244031L) + +// +// MessageId: WU_E_PT_ECP_INVALID_METADATA +// +// MessageText: +// +// External cab processor found invalid metadata. +// +#define WU_E_PT_ECP_INVALID_METADATA _HRESULT_TYPEDEF_(0x80244032L) + +// +// MessageId: WU_E_PT_ECP_FAILURE_TO_EXTRACT_DIGEST +// +// MessageText: +// +// The file digest could not be extracted from an external cab file. +// +#define WU_E_PT_ECP_FAILURE_TO_EXTRACT_DIGEST _HRESULT_TYPEDEF_(0x80244033L) + +// +// MessageId: WU_E_PT_ECP_FAILURE_TO_DECOMPRESS_CAB_FILE +// +// MessageText: +// +// An external cab file could not be decompressed. +// +#define WU_E_PT_ECP_FAILURE_TO_DECOMPRESS_CAB_FILE _HRESULT_TYPEDEF_(0x80244034L) + +// +// MessageId: WU_E_PT_ECP_FILE_LOCATION_ERROR +// +// MessageText: +// +// External cab processor was unable to get file locations. +// +#define WU_E_PT_ECP_FILE_LOCATION_ERROR _HRESULT_TYPEDEF_(0x80244035L) + +// +// MessageId: WU_E_PT_UNEXPECTED +// +// MessageText: +// +// A communication error not covered by another WU_E_PT_* error code. +// +#define WU_E_PT_UNEXPECTED _HRESULT_TYPEDEF_(0x80244FFFL) + +/////////////////////////////////////////////////////////////////////////////// +// Redirector errors +// +// The following errors are generated by the components that download and +// parse the wuredir.cab +/////////////////////////////////////////////////////////////////////////////// +// +// MessageId: WU_E_REDIRECTOR_LOAD_XML +// +// MessageText: +// +// The redirector XML document could not be loaded into the DOM class. +// +#define WU_E_REDIRECTOR_LOAD_XML _HRESULT_TYPEDEF_(0x80245001L) + +// +// MessageId: WU_E_REDIRECTOR_S_FALSE +// +// MessageText: +// +// The redirector XML document is missing some required information. +// +#define WU_E_REDIRECTOR_S_FALSE _HRESULT_TYPEDEF_(0x80245002L) + +// +// MessageId: WU_E_REDIRECTOR_ID_SMALLER +// +// MessageText: +// +// The redirectorId in the downloaded redirector cab is less than in the cached cab. +// +#define WU_E_REDIRECTOR_ID_SMALLER _HRESULT_TYPEDEF_(0x80245003L) + +// +// MessageId: WU_E_REDIRECTOR_UNEXPECTED +// +// MessageText: +// +// The redirector failed for reasons not covered by another WU_E_REDIRECTOR_* error code. +// +#define WU_E_REDIRECTOR_UNEXPECTED _HRESULT_TYPEDEF_(0x80245FFFL) + +/////////////////////////////////////////////////////////////////////////////// +// driver util errors +// +// The device PnP enumerated device was pruned from the SystemSpec because +// one of the hardware or compatible IDs matched an installed printer driver. +// This is not considered a fatal error and the device is simply skipped. +/////////////////////////////////////////////////////////////////////////////// +// +// MessageId: WU_E_DRV_PRUNED +// +// MessageText: +// +// A driver was skipped. +// +#define WU_E_DRV_PRUNED _HRESULT_TYPEDEF_(0x8024C001L) + +// +// MessageId: WU_E_DRV_NOPROP_OR_LEGACY +// +// MessageText: +// +// A property for the driver could not be found. It may not conform with required specifications. +// +#define WU_E_DRV_NOPROP_OR_LEGACY _HRESULT_TYPEDEF_(0x8024C002L) + +// +// MessageId: WU_E_DRV_REG_MISMATCH +// +// MessageText: +// +// The registry type read for the driver does not match the expected type. +// +#define WU_E_DRV_REG_MISMATCH _HRESULT_TYPEDEF_(0x8024C003L) + +// +// MessageId: WU_E_DRV_NO_METADATA +// +// MessageText: +// +// The driver update is missing metadata. +// +#define WU_E_DRV_NO_METADATA _HRESULT_TYPEDEF_(0x8024C004L) + +// +// MessageId: WU_E_DRV_MISSING_ATTRIBUTE +// +// MessageText: +// +// The driver update is missing a required attribute. +// +#define WU_E_DRV_MISSING_ATTRIBUTE _HRESULT_TYPEDEF_(0x8024C005L) + +// +// MessageId: WU_E_DRV_SYNC_FAILED +// +// MessageText: +// +// Driver synchronization failed. +// +#define WU_E_DRV_SYNC_FAILED _HRESULT_TYPEDEF_(0x8024C006L) + +// +// MessageId: WU_E_DRV_NO_PRINTER_CONTENT +// +// MessageText: +// +// Information required for the synchronization of applicable printers is missing. +// +#define WU_E_DRV_NO_PRINTER_CONTENT _HRESULT_TYPEDEF_(0x8024C007L) + +// +// MessageId: WU_E_DRV_UNEXPECTED +// +// MessageText: +// +// A driver error not covered by another WU_E_DRV_* code. +// +#define WU_E_DRV_UNEXPECTED _HRESULT_TYPEDEF_(0x8024CFFFL) + +////////////////////////////////////////////////////////////////////////////// +// data store errors +/////////////////////////////////////////////////////////////////////////////// +// +// MessageId: WU_E_DS_SHUTDOWN +// +// MessageText: +// +// An operation failed because Windows Update Agent is shutting down. +// +#define WU_E_DS_SHUTDOWN _HRESULT_TYPEDEF_(0x80248000L) + +// +// MessageId: WU_E_DS_INUSE +// +// MessageText: +// +// An operation failed because the data store was in use. +// +#define WU_E_DS_INUSE _HRESULT_TYPEDEF_(0x80248001L) + +// +// MessageId: WU_E_DS_INVALID +// +// MessageText: +// +// The current and expected states of the data store do not match. +// +#define WU_E_DS_INVALID _HRESULT_TYPEDEF_(0x80248002L) + +// +// MessageId: WU_E_DS_TABLEMISSING +// +// MessageText: +// +// The data store is missing a table. +// +#define WU_E_DS_TABLEMISSING _HRESULT_TYPEDEF_(0x80248003L) + +// +// MessageId: WU_E_DS_TABLEINCORRECT +// +// MessageText: +// +// The data store contains a table with unexpected columns. +// +#define WU_E_DS_TABLEINCORRECT _HRESULT_TYPEDEF_(0x80248004L) + +// +// MessageId: WU_E_DS_INVALIDTABLENAME +// +// MessageText: +// +// A table could not be opened because the table is not in the data store. +// +#define WU_E_DS_INVALIDTABLENAME _HRESULT_TYPEDEF_(0x80248005L) + +// +// MessageId: WU_E_DS_BADVERSION +// +// MessageText: +// +// The current and expected versions of the data store do not match. +// +#define WU_E_DS_BADVERSION _HRESULT_TYPEDEF_(0x80248006L) + +// +// MessageId: WU_E_DS_NODATA +// +// MessageText: +// +// The information requested is not in the data store. +// +#define WU_E_DS_NODATA _HRESULT_TYPEDEF_(0x80248007L) + +// +// MessageId: WU_E_DS_MISSINGDATA +// +// MessageText: +// +// The data store is missing required information or has a NULL in a table column that requires a non-null value. +// +#define WU_E_DS_MISSINGDATA _HRESULT_TYPEDEF_(0x80248008L) + +// +// MessageId: WU_E_DS_MISSINGREF +// +// MessageText: +// +// The data store is missing required information or has a reference to missing license terms, file, localized property or linked row. +// +#define WU_E_DS_MISSINGREF _HRESULT_TYPEDEF_(0x80248009L) + +// +// MessageId: WU_E_DS_UNKNOWNHANDLER +// +// MessageText: +// +// The update was not processed because its update handler could not be recognized. +// +#define WU_E_DS_UNKNOWNHANDLER _HRESULT_TYPEDEF_(0x8024800AL) + +// +// MessageId: WU_E_DS_CANTDELETE +// +// MessageText: +// +// The update was not deleted because it is still referenced by one or more services. +// +#define WU_E_DS_CANTDELETE _HRESULT_TYPEDEF_(0x8024800BL) + +// +// MessageId: WU_E_DS_LOCKTIMEOUTEXPIRED +// +// MessageText: +// +// The data store section could not be locked within the allotted time. +// +#define WU_E_DS_LOCKTIMEOUTEXPIRED _HRESULT_TYPEDEF_(0x8024800CL) + +// +// MessageId: WU_E_DS_NOCATEGORIES +// +// MessageText: +// +// The category was not added because it contains no parent categories and is not a top-level category itself. +// +#define WU_E_DS_NOCATEGORIES _HRESULT_TYPEDEF_(0x8024800DL) + +// +// MessageId: WU_E_DS_ROWEXISTS +// +// MessageText: +// +// The row was not added because an existing row has the same primary key. +// +#define WU_E_DS_ROWEXISTS _HRESULT_TYPEDEF_(0x8024800EL) + +// +// MessageId: WU_E_DS_STOREFILELOCKED +// +// MessageText: +// +// The data store could not be initialized because it was locked by another process. +// +#define WU_E_DS_STOREFILELOCKED _HRESULT_TYPEDEF_(0x8024800FL) + +// +// MessageId: WU_E_DS_CANNOTREGISTER +// +// MessageText: +// +// The data store is not allowed to be registered with COM in the current process. +// +#define WU_E_DS_CANNOTREGISTER _HRESULT_TYPEDEF_(0x80248010L) + +// +// MessageId: WU_E_DS_UNABLETOSTART +// +// MessageText: +// +// Could not create a data store object in another process. +// +#define WU_E_DS_UNABLETOSTART _HRESULT_TYPEDEF_(0x80248011L) + +// +// MessageId: WU_E_DS_DUPLICATEUPDATEID +// +// MessageText: +// +// The server sent the same update to the client with two different revision IDs. +// +#define WU_E_DS_DUPLICATEUPDATEID _HRESULT_TYPEDEF_(0x80248013L) + +// +// MessageId: WU_E_DS_UNKNOWNSERVICE +// +// MessageText: +// +// An operation did not complete because the service is not in the data store. +// +#define WU_E_DS_UNKNOWNSERVICE _HRESULT_TYPEDEF_(0x80248014L) + +// +// MessageId: WU_E_DS_SERVICEEXPIRED +// +// MessageText: +// +// An operation did not complete because the registration of the service has expired. +// +#define WU_E_DS_SERVICEEXPIRED _HRESULT_TYPEDEF_(0x80248015L) + +// +// MessageId: WU_E_DS_DECLINENOTALLOWED +// +// MessageText: +// +// A request to hide an update was declined because it is a mandatory update or because it was deployed with a deadline. +// +#define WU_E_DS_DECLINENOTALLOWED _HRESULT_TYPEDEF_(0x80248016L) + +// +// MessageId: WU_E_DS_TABLESESSIONMISMATCH +// +// MessageText: +// +// A table was not closed because it is not associated with the session. +// +#define WU_E_DS_TABLESESSIONMISMATCH _HRESULT_TYPEDEF_(0x80248017L) + +// +// MessageId: WU_E_DS_SESSIONLOCKMISMATCH +// +// MessageText: +// +// A table was not closed because it is not associated with the session. +// +#define WU_E_DS_SESSIONLOCKMISMATCH _HRESULT_TYPEDEF_(0x80248018L) + +// +// MessageId: WU_E_DS_NEEDWINDOWSSERVICE +// +// MessageText: +// +// A request to remove the Windows Update service or to unregister it with Automatic Updates was declined because it is a built-in service and/or Automatic Updates cannot fall back to another service. +// +#define WU_E_DS_NEEDWINDOWSSERVICE _HRESULT_TYPEDEF_(0x80248019L) + +// +// MessageId: WU_E_DS_INVALIDOPERATION +// +// MessageText: +// +// A request was declined because the operation is not allowed. +// +#define WU_E_DS_INVALIDOPERATION _HRESULT_TYPEDEF_(0x8024801AL) + +// +// MessageId: WU_E_DS_SCHEMAMISMATCH +// +// MessageText: +// +// The schema of the current data store and the schema of a table in a backup XML document do not match. +// +#define WU_E_DS_SCHEMAMISMATCH _HRESULT_TYPEDEF_(0x8024801BL) + +// +// MessageId: WU_E_DS_RESETREQUIRED +// +// MessageText: +// +// The data store requires a session reset; release the session and retry with a new session. +// +#define WU_E_DS_RESETREQUIRED _HRESULT_TYPEDEF_(0x8024801CL) + +// +// MessageId: WU_E_DS_IMPERSONATED +// +// MessageText: +// +// A data store operation did not complete because it was requested with an impersonated identity. +// +#define WU_E_DS_IMPERSONATED _HRESULT_TYPEDEF_(0x8024801DL) + +// +// MessageId: WU_E_DS_UNEXPECTED +// +// MessageText: +// +// A data store error not covered by another WU_E_DS_* code. +// +#define WU_E_DS_UNEXPECTED _HRESULT_TYPEDEF_(0x80248FFFL) + +///////////////////////////////////////////////////////////////////////////// +//Inventory Errors +///////////////////////////////////////////////////////////////////////////// +// +// MessageId: WU_E_INVENTORY_PARSEFAILED +// +// MessageText: +// +// Parsing of the rule file failed. +// +#define WU_E_INVENTORY_PARSEFAILED _HRESULT_TYPEDEF_(0x80249001L) + +// +// MessageId: WU_E_INVENTORY_GET_INVENTORY_TYPE_FAILED +// +// MessageText: +// +// Failed to get the requested inventory type from the server. +// +#define WU_E_INVENTORY_GET_INVENTORY_TYPE_FAILED _HRESULT_TYPEDEF_(0x80249002L) + +// +// MessageId: WU_E_INVENTORY_RESULT_UPLOAD_FAILED +// +// MessageText: +// +// Failed to upload inventory result to the server. +// +#define WU_E_INVENTORY_RESULT_UPLOAD_FAILED _HRESULT_TYPEDEF_(0x80249003L) + +// +// MessageId: WU_E_INVENTORY_UNEXPECTED +// +// MessageText: +// +// There was an inventory error not covered by another error code. +// +#define WU_E_INVENTORY_UNEXPECTED _HRESULT_TYPEDEF_(0x80249004L) + +// +// MessageId: WU_E_INVENTORY_WMI_ERROR +// +// MessageText: +// +// A WMI error occurred when enumerating the instances for a particular class. +// +#define WU_E_INVENTORY_WMI_ERROR _HRESULT_TYPEDEF_(0x80249005L) + +///////////////////////////////////////////////////////////////////////////// +//AU Errors +///////////////////////////////////////////////////////////////////////////// +// +// MessageId: WU_E_AU_NOSERVICE +// +// MessageText: +// +// Automatic Updates was unable to service incoming requests. +// +#define WU_E_AU_NOSERVICE _HRESULT_TYPEDEF_(0x8024A000L) + +// +// MessageId: WU_E_AU_NONLEGACYSERVER +// +// MessageText: +// +// The old version of the Automatic Updates client has stopped because the WSUS server has been upgraded. +// +#define WU_E_AU_NONLEGACYSERVER _HRESULT_TYPEDEF_(0x8024A002L) + +// +// MessageId: WU_E_AU_LEGACYCLIENTDISABLED +// +// MessageText: +// +// The old version of the Automatic Updates client was disabled. +// +#define WU_E_AU_LEGACYCLIENTDISABLED _HRESULT_TYPEDEF_(0x8024A003L) + +// +// MessageId: WU_E_AU_PAUSED +// +// MessageText: +// +// Automatic Updates was unable to process incoming requests because it was paused. +// +#define WU_E_AU_PAUSED _HRESULT_TYPEDEF_(0x8024A004L) + +// +// MessageId: WU_E_AU_NO_REGISTERED_SERVICE +// +// MessageText: +// +// No unmanaged service is registered with AU. +// +#define WU_E_AU_NO_REGISTERED_SERVICE _HRESULT_TYPEDEF_(0x8024A005L) + +// +// MessageId: WU_E_AU_UNEXPECTED +// +// MessageText: +// +// An Automatic Updates error not covered by another WU_E_AU * code. +// +#define WU_E_AU_UNEXPECTED _HRESULT_TYPEDEF_(0x8024AFFFL) + +////////////////////////////////////////////////////////////////////////////// +// update handler errors +/////////////////////////////////////////////////////////////////////////////// +// +// MessageId: WU_E_UH_REMOTEUNAVAILABLE +// +// MessageText: +// +// A request for a remote update handler could not be completed because no remote process is available. +// +#define WU_E_UH_REMOTEUNAVAILABLE _HRESULT_TYPEDEF_(0x80242000L) + +// +// MessageId: WU_E_UH_LOCALONLY +// +// MessageText: +// +// A request for a remote update handler could not be completed because the handler is local only. +// +#define WU_E_UH_LOCALONLY _HRESULT_TYPEDEF_(0x80242001L) + +// +// MessageId: WU_E_UH_UNKNOWNHANDLER +// +// MessageText: +// +// A request for an update handler could not be completed because the handler could not be recognized. +// +#define WU_E_UH_UNKNOWNHANDLER _HRESULT_TYPEDEF_(0x80242002L) + +// +// MessageId: WU_E_UH_REMOTEALREADYACTIVE +// +// MessageText: +// +// A remote update handler could not be created because one already exists. +// +#define WU_E_UH_REMOTEALREADYACTIVE _HRESULT_TYPEDEF_(0x80242003L) + +// +// MessageId: WU_E_UH_DOESNOTSUPPORTACTION +// +// MessageText: +// +// A request for the handler to install (uninstall) an update could not be completed because the update does not support install (uninstall). +// +#define WU_E_UH_DOESNOTSUPPORTACTION _HRESULT_TYPEDEF_(0x80242004L) + +// +// MessageId: WU_E_UH_WRONGHANDLER +// +// MessageText: +// +// An operation did not complete because the wrong handler was specified. +// +#define WU_E_UH_WRONGHANDLER _HRESULT_TYPEDEF_(0x80242005L) + +// +// MessageId: WU_E_UH_INVALIDMETADATA +// +// MessageText: +// +// A handler operation could not be completed because the update contains invalid metadata. +// +#define WU_E_UH_INVALIDMETADATA _HRESULT_TYPEDEF_(0x80242006L) + +// +// MessageId: WU_E_UH_INSTALLERHUNG +// +// MessageText: +// +// An operation could not be completed because the installer exceeded the time limit. +// +#define WU_E_UH_INSTALLERHUNG _HRESULT_TYPEDEF_(0x80242007L) + +// +// MessageId: WU_E_UH_OPERATIONCANCELLED +// +// MessageText: +// +// An operation being done by the update handler was cancelled. +// +#define WU_E_UH_OPERATIONCANCELLED _HRESULT_TYPEDEF_(0x80242008L) + +// +// MessageId: WU_E_UH_BADHANDLERXML +// +// MessageText: +// +// An operation could not be completed because the handler-specific metadata is invalid. +// +#define WU_E_UH_BADHANDLERXML _HRESULT_TYPEDEF_(0x80242009L) + +// +// MessageId: WU_E_UH_CANREQUIREINPUT +// +// MessageText: +// +// A request to the handler to install an update could not be completed because the update requires user input. +// +#define WU_E_UH_CANREQUIREINPUT _HRESULT_TYPEDEF_(0x8024200AL) + +// +// MessageId: WU_E_UH_INSTALLERFAILURE +// +// MessageText: +// +// The installer failed to install (uninstall) one or more updates. +// +#define WU_E_UH_INSTALLERFAILURE _HRESULT_TYPEDEF_(0x8024200BL) + +// +// MessageId: WU_E_UH_FALLBACKTOSELFCONTAINED +// +// MessageText: +// +// The update handler should download self-contained content rather than delta-compressed content for the update. +// +#define WU_E_UH_FALLBACKTOSELFCONTAINED _HRESULT_TYPEDEF_(0x8024200CL) + +// +// MessageId: WU_E_UH_NEEDANOTHERDOWNLOAD +// +// MessageText: +// +// The update handler did not install the update because it needs to be downloaded again. +// +#define WU_E_UH_NEEDANOTHERDOWNLOAD _HRESULT_TYPEDEF_(0x8024200DL) + +// +// MessageId: WU_E_UH_NOTIFYFAILURE +// +// MessageText: +// +// The update handler failed to send notification of the status of the install (uninstall) operation. +// +#define WU_E_UH_NOTIFYFAILURE _HRESULT_TYPEDEF_(0x8024200EL) + +// +// MessageId: WU_E_UH_INCONSISTENT_FILE_NAMES +// +// MessageText: +// +// The file names contained in the update metadata and in the update package are inconsistent. +// +#define WU_E_UH_INCONSISTENT_FILE_NAMES _HRESULT_TYPEDEF_(0x8024200FL) + +// +// MessageId: WU_E_UH_FALLBACKERROR +// +// MessageText: +// +// The update handler failed to fall back to the self-contained content. +// +#define WU_E_UH_FALLBACKERROR _HRESULT_TYPEDEF_(0x80242010L) + +// +// MessageId: WU_E_UH_TOOMANYDOWNLOADREQUESTS +// +// MessageText: +// +// The update handler has exceeded the maximum number of download requests. +// +#define WU_E_UH_TOOMANYDOWNLOADREQUESTS _HRESULT_TYPEDEF_(0x80242011L) + +// +// MessageId: WU_E_UH_UNEXPECTEDCBSRESPONSE +// +// MessageText: +// +// The update handler has received an unexpected response from CBS. +// +#define WU_E_UH_UNEXPECTEDCBSRESPONSE _HRESULT_TYPEDEF_(0x80242012L) + +// +// MessageId: WU_E_UH_BADCBSPACKAGEID +// +// MessageText: +// +// The update metadata contains an invalid CBS package identifier. +// +#define WU_E_UH_BADCBSPACKAGEID _HRESULT_TYPEDEF_(0x80242013L) + +// +// MessageId: WU_E_UH_POSTREBOOTSTILLPENDING +// +// MessageText: +// +// The post-reboot operation for the update is still in progress. +// +#define WU_E_UH_POSTREBOOTSTILLPENDING _HRESULT_TYPEDEF_(0x80242014L) + +// +// MessageId: WU_E_UH_POSTREBOOTRESULTUNKNOWN +// +// MessageText: +// +// The result of the post-reboot operation for the update could not be determined. +// +#define WU_E_UH_POSTREBOOTRESULTUNKNOWN _HRESULT_TYPEDEF_(0x80242015L) + +// +// MessageId: WU_E_UH_POSTREBOOTUNEXPECTEDSTATE +// +// MessageText: +// +// The state of the update after its post-reboot operation has completed is unexpected. +// +#define WU_E_UH_POSTREBOOTUNEXPECTEDSTATE _HRESULT_TYPEDEF_(0x80242016L) + +// +// MessageId: WU_E_UH_NEW_SERVICING_STACK_REQUIRED +// +// MessageText: +// +// The OS servicing stack must be updated before this update is downloaded or installed. +// +#define WU_E_UH_NEW_SERVICING_STACK_REQUIRED _HRESULT_TYPEDEF_(0x80242017L) + +// +// MessageId: WU_E_UH_UNEXPECTED +// +// MessageText: +// +// An update handler error not covered by another WU_E_UH_* code. +// +#define WU_E_UH_UNEXPECTED _HRESULT_TYPEDEF_(0x80242FFFL) + +////////////////////////////////////////////////////////////////////////////// +// download manager errors +/////////////////////////////////////////////////////////////////////////////// +// +// MessageId: WU_E_DM_URLNOTAVAILABLE +// +// MessageText: +// +// A download manager operation could not be completed because the requested file does not have a URL. +// +#define WU_E_DM_URLNOTAVAILABLE _HRESULT_TYPEDEF_(0x80246001L) + +// +// MessageId: WU_E_DM_INCORRECTFILEHASH +// +// MessageText: +// +// A download manager operation could not be completed because the file digest was not recognized. +// +#define WU_E_DM_INCORRECTFILEHASH _HRESULT_TYPEDEF_(0x80246002L) + +// +// MessageId: WU_E_DM_UNKNOWNALGORITHM +// +// MessageText: +// +// A download manager operation could not be completed because the file metadata requested an unrecognized hash algorithm. +// +#define WU_E_DM_UNKNOWNALGORITHM _HRESULT_TYPEDEF_(0x80246003L) + +// +// MessageId: WU_E_DM_NEEDDOWNLOADREQUEST +// +// MessageText: +// +// An operation could not be completed because a download request is required from the download handler. +// +#define WU_E_DM_NEEDDOWNLOADREQUEST _HRESULT_TYPEDEF_(0x80246004L) + +// +// MessageId: WU_E_DM_NONETWORK +// +// MessageText: +// +// A download manager operation could not be completed because the network connection was unavailable. +// +#define WU_E_DM_NONETWORK _HRESULT_TYPEDEF_(0x80246005L) + +// +// MessageId: WU_E_DM_WRONGBITSVERSION +// +// MessageText: +// +// A download manager operation could not be completed because the version of Background Intelligent Transfer Service (BITS) is incompatible. +// +#define WU_E_DM_WRONGBITSVERSION _HRESULT_TYPEDEF_(0x80246006L) + +// +// MessageId: WU_E_DM_NOTDOWNLOADED +// +// MessageText: +// +// The update has not been downloaded. +// +#define WU_E_DM_NOTDOWNLOADED _HRESULT_TYPEDEF_(0x80246007L) + +// +// MessageId: WU_E_DM_FAILTOCONNECTTOBITS +// +// MessageText: +// +// A download manager operation failed because the download manager was unable to connect the Background Intelligent Transfer Service (BITS). +// +#define WU_E_DM_FAILTOCONNECTTOBITS _HRESULT_TYPEDEF_(0x80246008L) + +// +// MessageId: WU_E_DM_BITSTRANSFERERROR +// +// MessageText: +// +// A download manager operation failed because there was an unspecified Background Intelligent Transfer Service (BITS) transfer error. +// +#define WU_E_DM_BITSTRANSFERERROR _HRESULT_TYPEDEF_(0x80246009L) + +// +// MessageId: WU_E_DM_DOWNLOADLOCATIONCHANGED +// +// MessageText: +// +// A download must be restarted because the location of the source of the download has changed. +// +#define WU_E_DM_DOWNLOADLOCATIONCHANGED _HRESULT_TYPEDEF_(0x8024600AL) + +// +// MessageId: WU_E_DM_CONTENTCHANGED +// +// MessageText: +// +// A download must be restarted because the update content changed in a new revision. +// +#define WU_E_DM_CONTENTCHANGED _HRESULT_TYPEDEF_(0x8024600BL) + +// +// MessageId: WU_E_DM_UNEXPECTED +// +// MessageText: +// +// There was a download manager error not covered by another WU_E_DM_* error code. +// +#define WU_E_DM_UNEXPECTED _HRESULT_TYPEDEF_(0x80246FFFL) + +////////////////////////////////////////////////////////////////////////////// +// Setup/SelfUpdate errors +/////////////////////////////////////////////////////////////////////////////// +// +// MessageId: WU_E_SETUP_INVALID_INFDATA +// +// MessageText: +// +// Windows Update Agent could not be updated because an INF file contains invalid information. +// +#define WU_E_SETUP_INVALID_INFDATA _HRESULT_TYPEDEF_(0x8024D001L) + +// +// MessageId: WU_E_SETUP_INVALID_IDENTDATA +// +// MessageText: +// +// Windows Update Agent could not be updated because the wuident.cab file contains invalid information. +// +#define WU_E_SETUP_INVALID_IDENTDATA _HRESULT_TYPEDEF_(0x8024D002L) + +// +// MessageId: WU_E_SETUP_ALREADY_INITIALIZED +// +// MessageText: +// +// Windows Update Agent could not be updated because of an internal error that caused setup initialization to be performed twice. +// +#define WU_E_SETUP_ALREADY_INITIALIZED _HRESULT_TYPEDEF_(0x8024D003L) + +// +// MessageId: WU_E_SETUP_NOT_INITIALIZED +// +// MessageText: +// +// Windows Update Agent could not be updated because setup initialization never completed successfully. +// +#define WU_E_SETUP_NOT_INITIALIZED _HRESULT_TYPEDEF_(0x8024D004L) + +// +// MessageId: WU_E_SETUP_SOURCE_VERSION_MISMATCH +// +// MessageText: +// +// Windows Update Agent could not be updated because the versions specified in the INF do not match the actual source file versions. +// +#define WU_E_SETUP_SOURCE_VERSION_MISMATCH _HRESULT_TYPEDEF_(0x8024D005L) + +// +// MessageId: WU_E_SETUP_TARGET_VERSION_GREATER +// +// MessageText: +// +// Windows Update Agent could not be updated because a WUA file on the target system is newer than the corresponding source file. +// +#define WU_E_SETUP_TARGET_VERSION_GREATER _HRESULT_TYPEDEF_(0x8024D006L) + +// +// MessageId: WU_E_SETUP_REGISTRATION_FAILED +// +// MessageText: +// +// Windows Update Agent could not be updated because regsvr32.exe returned an error. +// +#define WU_E_SETUP_REGISTRATION_FAILED _HRESULT_TYPEDEF_(0x8024D007L) + +// +// MessageId: WU_E_SELFUPDATE_SKIP_ON_FAILURE +// +// MessageText: +// +// An update to the Windows Update Agent was skipped because previous attempts to update have failed. +// +#define WU_E_SELFUPDATE_SKIP_ON_FAILURE _HRESULT_TYPEDEF_(0x8024D008L) + +// +// MessageId: WU_E_SETUP_SKIP_UPDATE +// +// MessageText: +// +// An update to the Windows Update Agent was skipped due to a directive in the wuident.cab file. +// +#define WU_E_SETUP_SKIP_UPDATE _HRESULT_TYPEDEF_(0x8024D009L) + +// +// MessageId: WU_E_SETUP_UNSUPPORTED_CONFIGURATION +// +// MessageText: +// +// Windows Update Agent could not be updated because the current system configuration is not supported. +// +#define WU_E_SETUP_UNSUPPORTED_CONFIGURATION _HRESULT_TYPEDEF_(0x8024D00AL) + +// +// MessageId: WU_E_SETUP_BLOCKED_CONFIGURATION +// +// MessageText: +// +// Windows Update Agent could not be updated because the system is configured to block the update. +// +#define WU_E_SETUP_BLOCKED_CONFIGURATION _HRESULT_TYPEDEF_(0x8024D00BL) + +// +// MessageId: WU_E_SETUP_REBOOT_TO_FIX +// +// MessageText: +// +// Windows Update Agent could not be updated because a restart of the system is required. +// +#define WU_E_SETUP_REBOOT_TO_FIX _HRESULT_TYPEDEF_(0x8024D00CL) + +// +// MessageId: WU_E_SETUP_ALREADYRUNNING +// +// MessageText: +// +// Windows Update Agent setup is already running. +// +#define WU_E_SETUP_ALREADYRUNNING _HRESULT_TYPEDEF_(0x8024D00DL) + +// +// MessageId: WU_E_SETUP_REBOOTREQUIRED +// +// MessageText: +// +// Windows Update Agent setup package requires a reboot to complete installation. +// +#define WU_E_SETUP_REBOOTREQUIRED _HRESULT_TYPEDEF_(0x8024D00EL) + +// +// MessageId: WU_E_SETUP_HANDLER_EXEC_FAILURE +// +// MessageText: +// +// Windows Update Agent could not be updated because the setup handler failed during execution. +// +#define WU_E_SETUP_HANDLER_EXEC_FAILURE _HRESULT_TYPEDEF_(0x8024D00FL) + +// +// MessageId: WU_E_SETUP_INVALID_REGISTRY_DATA +// +// MessageText: +// +// Windows Update Agent could not be updated because the registry contains invalid information. +// +#define WU_E_SETUP_INVALID_REGISTRY_DATA _HRESULT_TYPEDEF_(0x8024D010L) + +// +// MessageId: WU_E_SELFUPDATE_REQUIRED +// +// MessageText: +// +// Windows Update Agent must be updated before search can continue. +// +#define WU_E_SELFUPDATE_REQUIRED _HRESULT_TYPEDEF_(0x8024D011L) + +// +// MessageId: WU_E_SELFUPDATE_REQUIRED_ADMIN +// +// MessageText: +// +// Windows Update Agent must be updated before search can continue. An administrator is required to perform the operation. +// +#define WU_E_SELFUPDATE_REQUIRED_ADMIN _HRESULT_TYPEDEF_(0x8024D012L) + +// +// MessageId: WU_E_SETUP_WRONG_SERVER_VERSION +// +// MessageText: +// +// Windows Update Agent could not be updated because the server does not contain update information for this version. +// +#define WU_E_SETUP_WRONG_SERVER_VERSION _HRESULT_TYPEDEF_(0x8024D013L) + +// +// MessageId: WU_E_SETUP_UNEXPECTED +// +// MessageText: +// +// Windows Update Agent could not be updated because of an error not covered by another WU_E_SETUP_* error code. +// +#define WU_E_SETUP_UNEXPECTED _HRESULT_TYPEDEF_(0x8024DFFFL) + +////////////////////////////////////////////////////////////////////////////// +// expression evaluator errors +/////////////////////////////////////////////////////////////////////////////// +// +// MessageId: WU_E_EE_UNKNOWN_EXPRESSION +// +// MessageText: +// +// An expression evaluator operation could not be completed because an expression was unrecognized. +// +#define WU_E_EE_UNKNOWN_EXPRESSION _HRESULT_TYPEDEF_(0x8024E001L) + +// +// MessageId: WU_E_EE_INVALID_EXPRESSION +// +// MessageText: +// +// An expression evaluator operation could not be completed because an expression was invalid. +// +#define WU_E_EE_INVALID_EXPRESSION _HRESULT_TYPEDEF_(0x8024E002L) + +// +// MessageId: WU_E_EE_MISSING_METADATA +// +// MessageText: +// +// An expression evaluator operation could not be completed because an expression contains an incorrect number of metadata nodes. +// +#define WU_E_EE_MISSING_METADATA _HRESULT_TYPEDEF_(0x8024E003L) + +// +// MessageId: WU_E_EE_INVALID_VERSION +// +// MessageText: +// +// An expression evaluator operation could not be completed because the version of the serialized expression data is invalid. +// +#define WU_E_EE_INVALID_VERSION _HRESULT_TYPEDEF_(0x8024E004L) + +// +// MessageId: WU_E_EE_NOT_INITIALIZED +// +// MessageText: +// +// The expression evaluator could not be initialized. +// +#define WU_E_EE_NOT_INITIALIZED _HRESULT_TYPEDEF_(0x8024E005L) + +// +// MessageId: WU_E_EE_INVALID_ATTRIBUTEDATA +// +// MessageText: +// +// An expression evaluator operation could not be completed because there was an invalid attribute. +// +#define WU_E_EE_INVALID_ATTRIBUTEDATA _HRESULT_TYPEDEF_(0x8024E006L) + +// +// MessageId: WU_E_EE_CLUSTER_ERROR +// +// MessageText: +// +// An expression evaluator operation could not be completed because the cluster state of the computer could not be determined. +// +#define WU_E_EE_CLUSTER_ERROR _HRESULT_TYPEDEF_(0x8024E007L) + +// +// MessageId: WU_E_EE_UNEXPECTED +// +// MessageText: +// +// There was an expression evaluator error not covered by another WU_E_EE_* error code. +// +#define WU_E_EE_UNEXPECTED _HRESULT_TYPEDEF_(0x8024EFFFL) + +////////////////////////////////////////////////////////////////////////////// +// UI errors +/////////////////////////////////////////////////////////////////////////////// +// +// MessageId: WU_E_INSTALLATION_RESULTS_UNKNOWN_VERSION +// +// MessageText: +// +// The results of download and installation could not be read from the registry due to an unrecognized data format version. +// +#define WU_E_INSTALLATION_RESULTS_UNKNOWN_VERSION _HRESULT_TYPEDEF_(0x80243001L) + +// +// MessageId: WU_E_INSTALLATION_RESULTS_INVALID_DATA +// +// MessageText: +// +// The results of download and installation could not be read from the registry due to an invalid data format. +// +#define WU_E_INSTALLATION_RESULTS_INVALID_DATA _HRESULT_TYPEDEF_(0x80243002L) + +// +// MessageId: WU_E_INSTALLATION_RESULTS_NOT_FOUND +// +// MessageText: +// +// The results of download and installation are not available; the operation may have failed to start. +// +#define WU_E_INSTALLATION_RESULTS_NOT_FOUND _HRESULT_TYPEDEF_(0x80243003L) + +// +// MessageId: WU_E_TRAYICON_FAILURE +// +// MessageText: +// +// A failure occurred when trying to create an icon in the taskbar notification area. +// +#define WU_E_TRAYICON_FAILURE _HRESULT_TYPEDEF_(0x80243004L) + +// +// MessageId: WU_E_NON_UI_MODE +// +// MessageText: +// +// Unable to show UI when in non-UI mode; WU client UI modules may not be installed. +// +#define WU_E_NON_UI_MODE _HRESULT_TYPEDEF_(0x80243FFDL) + +// +// MessageId: WU_E_WUCLTUI_UNSUPPORTED_VERSION +// +// MessageText: +// +// Unsupported version of WU client UI exported functions. +// +#define WU_E_WUCLTUI_UNSUPPORTED_VERSION _HRESULT_TYPEDEF_(0x80243FFEL) + +// +// MessageId: WU_E_AUCLIENT_UNEXPECTED +// +// MessageText: +// +// There was a user interface error not covered by another WU_E_AUCLIENT_* error code. +// +#define WU_E_AUCLIENT_UNEXPECTED _HRESULT_TYPEDEF_(0x80243FFFL) + +////////////////////////////////////////////////////////////////////////////// +// reporter errors +/////////////////////////////////////////////////////////////////////////////// +// +// MessageId: WU_E_REPORTER_EVENTCACHECORRUPT +// +// MessageText: +// +// The event cache file was defective. +// +#define WU_E_REPORTER_EVENTCACHECORRUPT _HRESULT_TYPEDEF_(0x8024F001L) + +// +// MessageId: WU_E_REPORTER_EVENTNAMESPACEPARSEFAILED +// +// MessageText: +// +// The XML in the event namespace descriptor could not be parsed. +// +#define WU_E_REPORTER_EVENTNAMESPACEPARSEFAILED _HRESULT_TYPEDEF_(0x8024F002L) + +// +// MessageId: WU_E_INVALID_EVENT +// +// MessageText: +// +// The XML in the event namespace descriptor could not be parsed. +// +#define WU_E_INVALID_EVENT _HRESULT_TYPEDEF_(0x8024F003L) + +// +// MessageId: WU_E_SERVER_BUSY +// +// MessageText: +// +// The server rejected an event because the server was too busy. +// +#define WU_E_SERVER_BUSY _HRESULT_TYPEDEF_(0x8024F004L) + +// +// MessageId: WU_E_REPORTER_UNEXPECTED +// +// MessageText: +// +// There was a reporter error not covered by another error code. +// +#define WU_E_REPORTER_UNEXPECTED _HRESULT_TYPEDEF_(0x8024FFFFL) + +// +// MessageId: WU_E_OL_INVALID_SCANFILE +// +// MessageText: +// +// An operation could not be completed because the scan package was invalid. +// +#define WU_E_OL_INVALID_SCANFILE _HRESULT_TYPEDEF_(0x80247001L) + +// +// MessageId: WU_E_OL_NEWCLIENT_REQUIRED +// +// MessageText: +// +// An operation could not be completed because the scan package requires a greater version of the Windows Update Agent. +// +#define WU_E_OL_NEWCLIENT_REQUIRED _HRESULT_TYPEDEF_(0x80247002L) + +// +// MessageId: WU_E_OL_UNEXPECTED +// +// MessageText: +// +// Search using the scan package failed. +// +#define WU_E_OL_UNEXPECTED _HRESULT_TYPEDEF_(0x80247FFFL) + +#endif //_WUERROR_ diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/wix/iisca.wxs b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/wix/iisca.wxs new file mode 100644 index 0000000000..5bf076f74d --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/wix/iisca.wxs @@ -0,0 +1,209 @@ + + + + + + + + + + + + + + + + + + + NOT SKIPINSTALLCA AND NOT( REMOVE="ALL" ) + NOT SKIPUNINSTALLCA + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + NOT SKIPINSTALLWINDOWSHOTFIX + NOT SKIPREBOOTIFREQUIRED + + + + + + + + + + + + + + + + + NOT SKIPMAKESHORTCUTELEVATED + + + + + + + + + + + + + + + + + + + + + + + NOT SKIPSETCONSOLEPROPERTIES + + + + + + + + + + + + + + + + + + + + + + + + NOT SKIPINSTALLHTTPLISTENER + NOT SKIPUNINSTALLHTTPLISTENER + + + + + + + + + + + Installed And PATCH + Installed And PATCH + Installed And PATCH + + + + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/wix/setupstrings.wxl b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/wix/setupstrings.wxl new file mode 100644 index 0000000000..ccb1a67cfb --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/wix/setupstrings.wxl @@ -0,0 +1,255 @@ + + + + + + + 1033 + + + + Shared Config Install Options + Select option for installation to IIS shared configuration + Update shared configuration on install + You are installing this module onto an IIS server that is using shared configuration. If additional IIS servers are using this shared configuration then you will need to install this module onto all of these machines. To minimize disruption of the individual web servers you will need to install this module in the following steps: First, on all but the last of the machines you should install the module without updating shared config. Do this by not selecting the checkbox + below. This will install all binaries and files necessary for the module on each machine without making any changes to shared config. Second, on the last machine you will need to verify that the user idenity you are running under has read and write access to the applicationhost.config file on the UNC share. Then you should install the module and select the update shared config option below. + + + Initializing WebConfig custom action + Updating web.config + + + + IIS Advanced Logging + Enables advanced logging of IIS pipeline data. + IIS Advanced Logging + Enables creation of custom log files with extensible field selection. + Update for IIS Advanced Logging + + + + IIS Transform Manager + Beta + Enables the Transform Manager IIS Media Services. + IIS Transform Manager + Enables creation of media transforms. + IIS Transform Manager Host + Service host for [ProductName]. + IIS Transform Manager + Batch convert on-demand media files to alternate file and container formats. + An IIS Transform Manager 1.0 Expression Encoder SP Task package is installed on the computer. You must uninstall it before you can install [ProductName]. + + Microsoft .NET Framework 3.5 is required to install [ProductName]. Use the 'Add Features Wizard' in Server Manager to install .NET Framework 3.5.1 Features or use 'Turn Windows features on or off' to turn on Microsoft .NET Framework 3.5. + [ProductName] requires Microsoft Windows Vista Service Pack 1 or later. + [ProductName] cannot be installed on Vista Home Basic. + [ProductName] requires Microsoft Windows 7 Service Pack 1 or later. + + + Microsoft Web Management Service 2 + Microsoft Web Management Service + Installs the basic features of the [ProductName]. + Microsoft Web Management Service 2 + The Web Management Service enables remote and delegated management capabilities for administrators to manage for the Web server, sites and applications present on this machine. + + + Microsoft URL Rewrite Module 1.1 for IIS 7 + Update for URL Rewrite Module 1.1 for IIS 7 + URL Rewrite + Enables URL and content rewriting capabilities to IIS 7. + User Interface + Configures the URL Rewrite Module feature in IIS Manager. + + + IIS URL Rewrite Module 2 + Update for IIS URL Rewrite Module 2 + URL Rewrite + Enables URL and content rewriting capabilities to IIS 7. + User Interface + Configures the URL Rewrite Module feature in IIS Manager. + + + Administration Pack for IIS 7.0 + Installs the basic features of the [ProductName]. + 1252 + Administration Pack for IIS 7.0 + Microsoft Corporation + This version of the operating system is not supported. [ProductName] can be installed only on Windows Server 2008, or Windows Vista Service Pack 1, and higher. + ASP.Net Features + ASP.NET includes Authorization and Error Pages features, which let you manage your authorization and custom error settings. + Authentication + ASP.Net Authentication Description. + Authorization + ASP.NET Authorization lets you configure rules for authorizing users to access your Web sites and applications. + Error Pages + ASP.NET Error Pages lets you configure HTTP error responses to return when errors occur. + Modules + ASP.Net Modules Description. + Handlers + ASP.Net Handers Description. + Configuration Editor + Configuration Editor lets you manage your configuration files in IIS Manager by letting you edit sections, attributes, elements, and collections in your configuration files. + Request Filtering + Request Filtering lets you configure filtering rules for your Web site, and restrict protocol and content behavior. + Fast CGI + FastCGI lets you configure process pool settings for the FastCGI applications on your Web server. + + + Dynamic IP Restrictions for IIS 7 Setup + + + + + + + + + + + + + Dynamic IP Restrictions for IIS 7 - Beta + Dynamic IP Restrictions for IIS 7 - Beta 2 + Dynamic IP Restrictions for IIS 7 - Beta 3 + + Dynamic IP Restrictions for IIS 7 - Release Candidate + Dynamic IP Restrictions for IIS 7 - Release Candidate 2 + Dynamic IP Restrictions for IIS 7 - Release Candidate 3 + + Dynamic IP Restrictions for IIS 7 + + Dynamic IP Restrictions for IIS 7 + Dynamic IP Restrictions User Interface for IIS 7 + + Dynamic IP Restrictions for IIS 7 - Beta was found on this machine. Please uninstall it and try again + + + WebDAV 7.5 For IIS 7.0 + The IIS 7.0 CoreWebEngine and W3SVC features must be installed to use this product. + WebDAV Server Module + WebDAV Administration User Interface + + + IIS Search Engine Optimization Toolkit 1.0 + IIS Search Engine Optimization Toolkit 1.0 + Search Engine Optimization (SEO) Toolkit 1.0 + This installer database contains the logic and data required to install IIS Search Engine Optimization Toolkit 1.0. + + + IIS Editor + + + IIS Reports + Log Parser is not installed on this machine, Please install Log Parser 2.2 from http://www.microsoft.com/downloads/details.aspx?FamilyID=890cd06b-abf8-4c25-91b2-f8d975cf8c07 and then proceed with IIS Reports installation + + + Microsoft Web Farm Framework + Microsoft External Cache + Web Farm Framework is a requisite for installing Application Request Routing. Please install the Web Farm Framework. + Microsoft Application Request Routing 3.0 + Runtime + Adds the Application Request Routing capabilities to IIS. + User Interface + Configures the Application Request Routing feature in IIS Manager. + + + Microsoft CORS Module + IIS CORS Runtime + Adds the support of cross-origin resource sharing (CORS) to IIS. + + + Microsoft IIS Compression + IIS Compression + Adds the Zlib and Brotli compression schemes to IIS. + + + IIS Team Template Module + Template Module Runtime + An example of an IIS module. + + + Microsoft Windows PowerShell snap-in for IIS 7.0 + + + IIS Manager Publishing for IIS 7.0 + Publishing User Interface + + + Application Warm-Up 1.0 for IIS 7.5 + + + + An incompatible product, [CONFLICTING_PRODUCT_NAME], is on this computer. Installation of [ProductName] cannot continue. To install this product, use Add/Remove Programs on the Control Panel to remove [CONFLICTING_PRODUCT_NAME]. + Administrator privilege is required to install [ProductName]. + IIS Version 7.0 is required to use [ProductName]. + IIS Version 7.0 or greater is required to install [ProductName]. + IIS Version 7.5 or greater is required to install [ProductName]. + IIS Version 7 or 7.5 is required to install [ProductName]. + IIS Version 8.0 or greater is required to install [ProductName]. + The beta version of [ProductName] was found on this machine. + A newer version of [ProductName] was found on this machine. + Setup cannot continue because another instance of [ProductName] is already installed on this computer. Please uninstall it first and then re-launch this installation. + The IIS 7.0 CoreWebEngine and W3SVC features must be installed to use [ProductName]. + The IIS Management Console must be installed to use [ProductName]. + Please stop both services Windows Process Activation Service (WAS) and Web Management Service (WMSvc) before installing [ProductName]. You will need to start the services after installing [ProductName]. + IIS Metabase is required to install [ProductName]. + The 64-bit version of [ProductName] cannot be installed on a 32-bit edition of Microsoft Windows. + The 32-bit version of [ProductName] cannot be installed on a 64-bit edition of Microsoft Windows. + Microsoft .NET Framework Version 2.0 or greater is required to install [ProductName]. + Microsoft .NET Framework Version 3.5 or greater is required to install [ProductName]. Use 'Add Features' under the Server Manager to install Microsoft .Net Version 3.5. + Microsoft .NET Framework Version 4.0 or greater is required to install [ProductName]. + Please install Microsoft .NET Framework Version 2.0 Service Pack 1 (or a later service pack), before installing [ProductName]. + The Windows Update (wuauserv) service cannot be disabled, it is required to install [ProductName]. + The PowerShell snap-in is part of Windows Operating System. Please install it via 'Programs and Features' or 'Server Manager'. + Microsoft Web Platform Installer Version 3.0 or greater is required to install [ProductName]. + + Setup failed to detect shared configuration. + Shared configuration is enabled for IIS. Installing [ProductName] is not supported when using shared configuration. Please disable shared configuration before installing this feature. + + Please stop World Wide Web Publishing Service (W3SVC) before installing [ProductName]. You will need to start the service after installation. + IIS PowerShell Management Console + IIS PowerShell snap-in + IIS PowerShell snap-in requires PowerShell v1.0 or v2.0 installed + IIS PowerShell snap-in requires WAS and configuration installed + This is a bogus string. + + + Microsoft Web Farm Framework Version 2.2 + Microsoft Web Farm Agent Version 2.2 + Web Farm Service + Web Farm Service + Web Farm Controller Service + Web Farm Controller Service + Web Farm Agent Service + Web Farm Agent Service + Web Platform Installer is a pre-requisite for installing Web Farm Framework. Please install the Web Plaform Installer from http://www.microsoft.com/web/downloads/platform.aspx. + Web Deployment Tool is a pre-requisite for installing Web Farm Framework. Please install the Web Deployment Tool from http://www.iis.net/download/WebDeploy. + + + Microsoft Web Hosting Framework + Web Hosting Framework + Web Hosting roles and features. + Hosting Framework + Hosting Framework provides API's and PowerShell commands for managing the Web Hosting. + Web Role + Web Role installs Dynamic WAS service and URL Rewrite provider for Web Hosting. + Antares Express + Deploys a Control Panel configuration optimized for single machine setup. + Load Balancer Role + Load Balancer Role configures Application Request Router to route based on Web Hosting rules. + Hosting Controller + Hosting Controller extends the Web Farm Framework 2.0 to work with Web Hosting. + Publishing Role + Installs support for Web Deploy and FTP publishing. + This is a PowerShell snap-in that contains cmdlets for managing Microsoft Web Hosting infrastructure. + Dynamic WAS Service + Windows Process Activation service optimized for high density Web Hosting. + Resource Metering Service + Installs the Resource Metering service that enables collecting and publishing both runtime and health information. + Resource Metering + Enables collecting and publishing runtime and health information from Web Role. + Hosting Quota Enforcement + Monitors the web sites resource usage and executes custom actions when usage quota is exceeded. + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/wix3/ElevatedShortcut.wxi b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/wix3/ElevatedShortcut.wxi new file mode 100644 index 0000000000..ee5e988a1b --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/wix3/ElevatedShortcut.wxi @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + NOT SKIPMAKESHORTCUTELEVATED + + + + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/wix3/FixPatchingBehavior.wxi b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/wix3/FixPatchingBehavior.wxi new file mode 100644 index 0000000000..ae6e3b76d5 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/wix3/FixPatchingBehavior.wxi @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + Installed And PATCH + Installed And PATCH + Installed And PATCH + + + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/wix3/HttpListener.wxi b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/wix3/HttpListener.wxi new file mode 100644 index 0000000000..68db6852d1 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/wix3/HttpListener.wxi @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + NOT SKIPINSTALLHTTPLISTENER + NOT SKIPUNINSTALLHTTPLISTENER + + + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/wix3/ShortcutConsoleProperties.wxi b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/wix3/ShortcutConsoleProperties.wxi new file mode 100644 index 0000000000..236e0f51ef --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/wix3/ShortcutConsoleProperties.wxi @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + NOT SKIPSETCONSOLEPROPERTIES + + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/wix3/WindowsHotfix.wxi b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/wix3/WindowsHotfix.wxi new file mode 100644 index 0000000000..78b26d6404 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/wix3/WindowsHotfix.wxi @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + NOT SKIPINSTALLWINDOWSHOTFIX + NOT SKIPREBOOTIFREQUIRED + + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/wix3/iisca.wxs b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/wix3/iisca.wxs new file mode 100644 index 0000000000..68324e1484 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/iisca/wix3/iisca.wxs @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + NOT SKIPINSTALLCA + (NOT SKIPUNINSTALLCA) AND (IISCOREWEBENGINEINSTALLED = "#1") AND (IISW3SVCINSTALLED = "#1") + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/include.wxi b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/include.wxi new file mode 100644 index 0000000000..e22cdce8a4 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/include.wxi @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/CHS/misc/setupstrings.wxl b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/CHS/misc/setupstrings.wxl new file mode 100644 index 0000000000..3acd415df3 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/CHS/misc/setupstrings.wxl @@ -0,0 +1,351 @@ + + + + + + + 2052 + + + + 共享配置安装选项 + 选择用于安装到 IIS 共享配置的选项 + 安装时更新共享配置 + 您要将此模块安装到使用共享配置的 IIS 服务器上。如果其他 IIS 服务器正在使用此共享配置,则您需要将此模块安装到所有这些计算机上。为了尽可能减少对各个 Web 服务器的中断,您需要按以下步骤安装此模块: 首先,在除最后一台计算机外的所有其他计算机上,安装此模块但不更新共享配置。可通过不选中下面的复选框来执行 +此操作。这将在每台计算机上安装模块所需的所有二进制文件和其他文件,而不对共享配置进行任何更改。其次,在最后一台计算机上,您需要确保运行时使用的用户标识对 UNC 共享上的 applicationhost.config 文件具有读取和写入权限。然后,您应安装此模块并选中下面的更新共享配置选项。 + + + 正在初始化 WebConfig 自定义操作 + 正在更新 web.config + + + + IIS 高级日志 + 启用 IIS 管道数据高级日志。 + IIS 高级日志 + 允许通过选择可扩展的字段来创建自定义日志文件。 + 适用于 IIS 高级日志记录的更新 + + + + IIS Transform Manager + Beta + 启用 Transform Manager IIS 媒体服务。 + IIS Transform Manager + 允许创建媒体转换。 + IIS Transform Manager 主机 + [ProductName] 的服务主机。 + IIS Transform Manager + 根据需要将媒体文件批量转换为其他文件和容器格式。 + 计算机上安装了某个 IIS Transform Manager 1.0 表达式编码器 SP 任务包。您必须先将它卸载,然后才能安装 [ProductName]。 + + 安装 [ProductName] 需要 Microsoft .NET Framework 3.5。可在服务器管理器中使用“添加功能向导”来安装 .NET Framework 3.5.1 功能,或使用“打开或关闭 Windows 功能”来打开 Microsoft .NET Framework 3.5。 + + + + IIS 数字版权管理 + Beta + 启用平滑流式处理演示的数字版权管理。 + + + 未安装 ASP.NET + + + + + + + + + 此计算机上找到了 IIS 平滑流式处理 - Beta。无法继续安装 [ProductName]。若要安装此产品,请使用控制面板中的“添加/删除程序”将 IIS 平滑流式处理 - Beta 删除。 + 此计算机上装有 IIS Media Services 的不兼容版本。无法继续安装 [ProductName]。若要安装此产品,请使用控制面板中的“添加/删除程序”将 IIS Media Services 删除。 + 此计算机上已安装了该产品的新版本,或者可以在此计算机上安装该产品的新版本。无法继续安装 [ProductName]。若要安装该产品的新版本,请使用控制面板上的“添加/删除程序”更新 IIS Media Services。 + 需要进行播放列表文件转换 + + + + + 发现早期版本的 IIS Media Services 文件 + + + + + 发现 Beta IIS Media Services 文件 + + + + + + IIS Media Pack 1.0 + 适用于 IIS Media Pack 1.0 的更新 + IIS Media Services 2.0 + 适用于 IIS Media Services 2.0 的更新 + IIS Media Services 3.0 + IIS Media Services 3.0 TAP 2 + 适用于 IIS Media Services 3.0 的更新 + IIS Media Services 功能和工具。 + IIS Media Services 5 Premium 功能和工具。 + IIS Media Services 4.0 Beta 1 + IIS Media Services 4.0 + IIS Media Services 4.5 Beta 1 + IIS Media Services 5 Premium + + Web 播放列表 + 对客户端播放在播放列表中引用的媒体资产的行为进行控制。 + 会话帮助程序 + 启用 ASP.NET 会话状态持续性。(需要适用于 Web 服务器(IIS)的 ASP.NET 角色服务)。 + 用户界面 + 在 IIS 管理器中配置 Web 播放列表功能。 + + 比特率限制 + 对客户端下载的文件的传送进行限制,从而节省带宽。 + 用户界面 + 在 IIS 管理器中配置比特率限制功能。 + + 资产 + 对客户端的按需资产启用 HTTP 自适应流式处理。 + 用户界面 + 在 IIS 管理器中配置平滑流式处理功能。 + + 频道 + 对客户端的频道广播启用 HTTP 自适应流式处理。 + 用户界面 + 在 IIS 管理器中配置实时平滑流式处理功能。 + + 数字版权管理 + 提供平滑流式处理媒体的加密和许可。 + 用户界面 + 配置 IIS 管理器中的数字版权管理功能。 + + [ProductName] 需要 Microsoft Windows Vista Service Pack 1 或更高版本。 + 无法在 Vista Home Basic 上安装 [ProductName]。 + [ProductName] 需要 Microsoft Windows 7 Service Pack 1 或更高版本。 + + + IIS 数据库管理器 + IIS 数据库管理器 + + + Microsoft Web 管理服务 2 + Microsoft Web 管理服务 + 安装 [ProductName] 的基本功能。 + Microsoft Web 管理服务 2 + Web 管理服务提供远程和委派管理功能,供管理员管理位于此计算机上的 Web 服务器、站点和应用程序。 + + + 用于 IIS 7 的 Microsoft URL 重写模块 1.1 + 对用于 IIS 7 的 URL 重写模块 1.1 的更新 + URL 重写 + 对 IIS 7 启用 URL 和内容重写功能。 + 用户界面 + 在 IIS 管理器中配置 URL 重写模块功能。 + + + IIS URL 重写模块 2 + 适用于 IIS URL 重写模块 2 的更新 + URL 重写 + 对 IIS 7 启用 URL 和内容重写功能。 + 用户界面 + 在 IIS 管理器中配置 URL 重写模块功能。 + + + Administration Pack for IIS 7.0 + 安装 [ProductName] 的基本功能。 + 1252 + Administration Pack for IIS 7.0 + Microsoft Corporation + 不支持此操作系统版本。[ProductName] 只能安装在 Windows Server 2008 或 Windows Vista Service Pack 1 及更高版本上。 + ASP.Net 功能 + ASP.NET 包括“授权”和“错误页”功能,利用这些功能,您可以管理您的授权和自定义错误设置。 + 身份验证 + ASP.Net 身份验证说明。 + 授权 + 利用 ASP.NET 授权,您可以配置规则,以便允许用户访问您的网站和应用程序。 + 错误页 + 利用 ASP.NET 错误页,您可以配置要在发生错误时返回的 HTTP 错误响应。 + 模块 + ASP.Net 模块说明。 + 处理程序 + ASP.Net 处理程序说明。 + 配置编辑器 + 利用配置编辑器,您可以编辑配置文件中的节、属性、元素和集合,从而在 IIS 管理器中管理配置文件。 + 请求筛选 + 利用请求筛选,您可以为您的网站配置筛选规则,并限制协议和内容行为。 + FastCGI + 利用 FastCGI,您可以在 Web 服务器上为 FastCGI 应用程序配置进程池设置。 + + + 安装 Dynamic IP Restrictions for IIS 7 + + + + + + + + + + + + + Dynamic IP Restrictions for IIS 7 - Beta + Dynamic IP Restrictions for IIS 7 - Beta 2 + Dynamic IP Restrictions for IIS 7 - Beta 3 + + Dynamic IP Restrictions for IIS 7 - 候选发布 + Dynamic IP Restrictions for IIS 7 - 候选发布 2 + Dynamic IP Restrictions for IIS 7 - 候选发布 3 + + Dynamic IP Restrictions for IIS 7 - RTW + + Dynamic IP Restrictions for IIS 7 + Dynamic IP Restrictions for IIS 7 用户界面 + + IIS 7 的动态 IP 限制 - 在此计算机上找到 Beta 版本。请卸载它,然后重试 + + + WebDAV 7.5 For IIS 7.0 + 若要使用此产品,必须安装 IIS 7.0 CoreWebEngine 和 W3SVC 功能。 + WebDAV 服务器模块 + WebDAV 管理用户界面 + + + IIS 搜索引擎优化工具包 1.0 + IIS 搜索引擎优化工具包 1.0 + 搜索引擎优化(SEO)工具包 1.0 + 此安装程序数据库包含安装 IIS 搜索引擎优化工具包 1.0 所需的逻辑和数据。 + + + IIS 编辑器 + + + IIS Reports + 未在此计算机上安装 Log Parser,请通过 http://www.microsoft.com/downloads/details.aspx?FamilyID=890cd06b-abf8-4c25-91b2-f8d975cf8c07 安装 Log Parser 2.2,然后继续安装 IIS Reports + + + 未找到系统必备包。请运行 setup.exe 以解析依赖关系并安装此程序。 + Microsoft SQL Server 2008 管理对象是安装 IIS 数据库管理器的必备组件。可以从 http://go.microsoft.com/fwlink/?LinkID=150946 安装 Micrsoft SQL Server 2008 管理对象。 + Microsoft SQL Server System CLR Types 是安装 IIS 数据库管理器的必备组件。可以从 http://go.microsoft.com/fwlink/?LinkID=150949 安装 Microsoft SQL Server System CLR Types。 + + + Microsoft Web Farm Framework + Microsoft External Cache + Web Farm Framework 是安装 Application Request Routing 的必备组件。请安装 Web Farm Framework。 + Microsoft Application Request Routing 2.5 + 运行时 + 向 IIS 7 添加 Application Request Routing 功能。 + 用户界面 + 在 IIS 管理器中配置应用程序请求路由功能。 + + + 用于 IIS 7.0 的 Microsoft Windows PowerShell 管理单元 + + + Microsoft Web 平台安装程序 4.0 + Microsoft Web 平台安装程序 + [ProductName] 需要 Windows XP SP2、Windows 2003 SP1、Windows Vista 或更高版本。 + [ProductName] 需要 Windows XP Service Pack 3、Windows Server 2003 Service Pack 2 或更高版本。 + + + Microsoft Windows Azure 服务安装程序 + Microsoft Windows Azure 服务安装程序 + + + Internet Information Services (IIS) 7+ 管理器 + IIS 管理器客户端 + 远程支持 + 此产品需要 Windows XP SP2、Windows 2003 SP1、Windows Vista SP1 或 Windows 7 或更高版本 + 未安装 IIS 管理控制台,但需要此控制台才能管理远程 IIS 服务器。在安装远程管理支持之前,请先安装 IIS 管理控制台,方法是打开“控制面板”->“程序”->“打开或关闭 Windows 功能”,然后在 Ineternet Information Services 功能中选择 IIS 管理控制台。 + 此产品在 Windows Server 2008、Windows Server 2008 R2 或更高版本中不是必需的。请打开服务器管理器并在 Web 服务器角色的角色服务中选择 IIS 管理控制台,从而安装 IIS 管理控制台。 + + + IIS Manager Publishing for IIS 7.0 + Publishing 用户界面 + + + Application Warm-Up 1.0 for IIS 7.5 + + + + 此计算机上安装了不兼容的产品 [CONFLICTING_PRODUCT_NAME]。无法继续安装 [ProductName]。要安装此产品,请使用控制面板上的“添加/删除程序”来删除 [CONFLICTING_PRODUCT_NAME]。 + 若要安装 [ProductName],需要管理员特权。 + 若要使用 [ProductName],需要 IIS 7.0 版。 + 若要安装 [ProductName],需要 IIS 7.0 版或更高版本。 + 安装 [ProductName] 必须具有 IIS 7.5 版或更高版本。 + 要安装 [产品名称],要求使用 IIS 版本 7 或 7.5。 + 已在此计算机上找到 [ProductName] 的 Beta 版本。 + 已在此计算机上找到 [ProductName] 的新版本。 + 安装程序无法继续,因为已在此计算机上安装了另一个 [ProductName] 实例。请先将其卸载,然后重新启动此安装。 + 若要使用 [ProductName],必须安装 IIS 7.0 CoreWebEngine 和 W3SVC 功能。 + 要使用 [ProductName],必须安装 IIS 管理控制台。 + 请先停止 Windows Process Activation Service (WAS)和 Web 管理服务(WMSvc),然后安装 [ProductName]。您将需要在安装 [ProductName] 后启动这两个服务。 + 若要安装 [ProductName],需要 IIS 元数据库。 + 无法在 32 位版本的 Microsoft Windows 上安装 64 位版本的 [ProductName]。 + 无法在 64 位版本的 Microsoft Windows 上安装 32 位版本的 [ProductName]。 + 若要安装 [ProductName],需要 Microsoft .NET Framework 2.0 版或更高版本。 + 需要有 Microsoft .NET Framework 3.5 版或更高版本才能安装 [ProductName]。使用“服务器管理器”下的“添加功能”可安装 Microsoft .Net 3.5 版。 + 需要有 Microsoft .NET Framework 4.0 版或更高版本才能安装 [ProductName]。 + 请先安装 Microsoft .NET Framework 2.0 Service Pack 1(或更高版本的 Service Pack),然后再安装 [ProductName]。 + 不能禁用 Windows Update (wuauserv)服务,安装 [ProductName] 需要此服务。 + PowerShell 管理单元是 Windows 操作系统的一部分。请通过“程序和功能”或“服务器管理器”来安装它。 + 需要有 Microsoft Web 平台安装程序 3.0 版或更高版本才能安装 [ProductName]。 + + 安装程序无法检测到共享配置。 + 已为 IIS 启用了共享配置。使用共享配置时,不支持安装 [ProductName]。请先禁用共享配置,然后再安装此功能。 + + 请在安装 [ProductName] 之前停止 World Wide Web 发布服务(W3SVC)。您将需要在安装后启动此服务。 + IIS PowerShell 管理控制台 + IIS PowerShell 管理单元 + IIS PowerShell 管理单元要求安装 PowerShell v1.0 或 v2.0 + IIS PowerShell 管理单元要求安装 WAS 和配置 + 这是一个假字符串。 + + + Microsoft Web Farm Framework 版本 2.2 + Microsoft Web 场代理版本 2.2 + Web 场服务 + Web 场服务 + Web 场控制器服务 + Web 场控制器服务 + Web 场代理服务 + Web 场代理服务 + Web 平台安装程序是安装 Web Farm Framework 的必备组件。请从 http://www.microsoft.com/web/downloads/platform.aspx 安装 Web 平台安装程序。 + Web 部署工具是安装 Web Farm Framework 的必备组件。请从 http://www.iis.net/download/WebDeploy 安装 Web 部署工具。 + + + Microsoft Web Hosting 框架 + Web Hosting 框架 + Web Hosting 角色和功能。 + Hosting 框架 + Hosting 框架提供用于管理 Web Hosting 的 API 和 PowerShell 命令。 + Web 角色 + Web 角色为 Web Hosting 安装动态 WAS 服务和 URL 重写提供程序。 + Antares Express + 部署已针对单一计算机设置优化的控制面板配置。 + 负载平衡器角色 + 负载平衡器将应用程序请求路由器配置为基于 Web Hosting 规则进行路由。 + Hosting 控制器 + Hosting 控制器扩展了 Web Farm Framework 2.0,使之能够与 Web Hosting 一起使用。 + 发布角色 + 安装针对 Web Deploy 和 FTP 发布功能的支持。 + 这是 PowerShell 管理单元,其中包含用于管理 Microsoft Web Hosting 基础架构的 cmdlet。 + 动态 WAS 服务 + 已为高密度 Web Hosting 优化了 Windows Process Activation Service。 + 资源计量服务 + 安装资源计量服务,该服务可以收集和发布运行时信息和运行状况信息。 + 资源计量 + 允许从 Web 角色收集和发布运行时信息与运行状况信息。 + 强制实施宿主配额 + 监视网站资源使用情况,并在超出使用配额时执行自定义操作。 + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/CHT/misc/setupstrings.wxl b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/CHT/misc/setupstrings.wxl new file mode 100644 index 0000000000..fc4295abf7 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/CHT/misc/setupstrings.wxl @@ -0,0 +1,351 @@ + + + + + + + 1028 + + + + 共用設定安裝選項 + 請選取安裝 IIS 共用設定的選項 + 在安裝時更新共用設定 + 您正在將這個模組安裝到使用共用設定的 IIS 伺服器上。如果有其他 IIS 伺服器也使用這個共用設定,您必須將這個模組安裝到所有電腦。若要將個別網頁伺服器發生中斷的情形降至最低,您必須依照下列步驟安裝這個模組: 首先,在所有電腦上 (最後一部電腦例外) 安裝模組,而且不要更新共用設定。請不要選取下面的核取方塊。 +這將會為每部電腦上的模組安裝所有二進位檔和必要檔案,而不會對共用設定進行任何變更。第二,在最後一部電腦上,您必須確認執行作業所使用的使用者識別具有讀取和寫入 UNC 共用上 applicationhost.config 檔案的權限。然後,您應安裝模組並選取下面的更新共用設定選項。 + + + 正在初始化 WebConfig 自訂動作 + 正在更新 web.config + + + + IIS 進階記錄 + 啟用 IIS 管線資料的進階記錄。 + IIS 進階記錄 + 啟用以可延伸的欄位選擇建立自訂記錄檔。 + IIS Advanced Logging 的更新 + + + + IIS Transform Manager + Beta + 啟用 Transform Manager IIS Media Services。 + IIS Transform Manager + 啟用媒體轉換的建立。 + IIS Transform Manager 主機 + [ProductName] 的服務主機。 + IIS Transform Manager + 將隨選媒體檔案批次轉換為替代的檔案及容器格式。 + IIS Transform Manager 1.0 Expression Encoder SP Task 套件已安裝於電腦。您必須先將它解除安裝,才能安裝 [ProductName]。 + + 需要 Microsoft .NET Framework 3.5 才能安裝 [ProductName]。請使用 [\[]伺服器管理員[\]] 中的 [\[]新增功能精靈[\]] 安裝 .NET Framework 3.5.1 功能,或者使用 [\[]開啟或關閉 Windows 功能[\]] 開啟 Microsoft .NET Framework 3.5。 + + + + IIS 數位版權管理 + Beta + 啟用 Smooth Streaming 展示檔的數位版權管理。 + + + 未安裝 ASP.NET + + + + + + + + + 在這部電腦上找到 IIS Smooth Streaming - Beta。[ProductName] 的安裝無法繼續。若要安裝這個產品,請使用 [控制台] 中的 [新增/移除程式] 移除 IIS Smooth Streaming - Beta。 + 這部電腦已經安裝不相容版本的 IIS Media Services。[ProductName] 的安裝無法繼續。若要安裝這個產品,請使用 [控制台] 中的 [新增/移除程式] 移除 IIS Media Services。 + 這部電腦可能已安裝這個產品的新版本或有新版本可供安裝。[ProductName] 的安裝無法繼續。若要安裝這個產品的新版本,請使用 [控制台] 中的 [新增/移除程式] 更新 IIS Media Services。 + 需要播放清單檔案轉換 + + + + + 找到舊的 IIS Media Services 檔案 + + + + + 找到 Beta IIS Media Services 檔案 + + + + + + IIS Media Pack 1.0 + IIS Media Pack 1.0 的更新 + IIS Media Services 2.0 + IIS Media Services 2.0 的更新 + IIS Media Services 3.0 + IIS Media Services 3.0 TAP 2 + IIS Media Services 3.0 的更新 + IIS Media Services 功能和工具。 + IIS Media Services 5 Premium 功能及工具。 + IIS Media Services 4.0 Beta 1 + IIS Media Services 4.0 + IIS Media Services 4.5 Beta 1 + IIS Media Services 5 Premium + + Web 播放清單 + 控制播放清單中參考之媒體資產的用戶端播放方式。 + Session Helper + 啟用 ASP.NET 工作階段狀態持續性 (需要網頁伺服器 (IIS) 的 ASP.NET 角色服務)。 + 使用者介面 + 設定 IIS 管理員中的 Web 播放清單功能。 + + 位元速度節流設定 + 藉由節流設定傳遞用戶端下載的檔案,以節省頻寬。 + 使用者介面 + 設定 IIS 管理員中的位元速度節流設定功能。 + + 資產 + 啟用對用戶端的隨選資產 HTTP 彈性資料流。 + 使用者介面 + 設定 IIS 管理員中的 Smooth Streaming 功能。 + + 通道 + 啟用對用戶端的通道廣播 HTTP 彈性資料流。 + 使用者介面 + 設定 IIS 管理員中的 Live Smooth Streaming 功能。 + + 數位版權管理 + 提供 Smooth Streaming 媒體的加密和授權。 + 使用者介面 + 設定 IIS 管理員中的數位版權管理功能。 + + [ProductName] 需要 Microsoft Windows Vista Service Pack 1 或更新版本。 + 無法將 [ProductName] 安裝在 Vista Home Basic 上。 + [ProductName] 需要 Microsoft Windows 7 Service Pack 1 或更新版本。 + + + IIS Database Manager + IIS Database Manager + + + Microsoft Web Management Service 2 + Microsoft Web Management Service + 安裝 [ProductName] 的基本功能。 + Microsoft Web Management Service 2 + Web Management Service 可啟用遠端及委派管理功能,讓系統管理員管理呈現在這部電腦上的網頁伺服器、站台及應用程式。 + + + Microsoft URL Rewrite Module 1.1 for IIS 7 + URL Rewrite Module 1.1 for IIS 7 的更新 + URL Rewrite + 啟用 IIS 7 的 URL 和內容重寫功能。 + 使用者介面 + 設定 IIS 管理員中的 URL Rewrite Module 功能。 + + + IIS URL Rewrite Module 2 + IIS URL Rewrite Module 2 的更新 + URL Rewrite + 啟用 IIS 7 的 URL 和內容重寫功能。 + 使用者介面 + 設定 IIS 管理員中的 URL Rewrite Module 功能。 + + + Administration Pack for IIS 7.0 + 安裝 [ProductName] 的基本功能。 + 1252 + Administration Pack for IIS 7.0 + Microsoft Corporation + 不支援這個版本的作業系統。[ProductName] 只能安裝在 Windows Server 2008 或 Windows Vista Service Pack 1 和更新版本上。 + ASP.NET 功能 + ASP.NET 包含授權和錯誤網頁功能,可讓您管理授權和自訂錯誤訊息。 + 驗證 + ASP.NET 驗證描述。 + 授權 + ASP.NET 授權可讓您設定規則,來授權使用者存取您的網站和應用程式。 + 錯誤網頁 + ASP.NET 錯誤網頁可讓您設定發生錯誤時要傳回的 HTTP 錯誤回應。 + 模組 + ASP.NET 模組描述。 + 處理常式 + ASP.NET 處理常式描述。 + 設定編輯器 + 設定編輯器可讓您管理 IIS 管理員中的設定檔案,讓您編輯設定檔案中的區段、屬性、元素和集合。 + 要求篩選 + 要求篩選可讓您為網站設定篩選規則,並限制通訊協定和內容的行為。 + Fast CGI + FastCGI 可讓您設定您的網頁伺服器上 FastCGI 應用程式的處理序集區設定。 + + + Dynamic IP Restrictions for IIS 7 安裝程式 + + + + + + + + + + + + + Dynamic IP Restrictions for IIS 7 - Beta + Dynamic IP Restrictions for IIS 7 - Beta 2 + Dynamic IP Restrictions for IIS 7 - Beta 3 + + Dynamic IP Restrictions for IIS 7 - 發行候選版本 + Dynamic IP Restrictions for IIS 7 - 發行候選版本 2 + Dynamic IP Restrictions for IIS 7 - 發行候選版本 3 + + Dynamic IP Restrictions for IIS 7 - RTW + + Dynamic IP Restrictions for IIS 7 + IIS 7 的動態 IP 限制使用者介面 + + 在這部電腦上發現 Dynamic IP Restrictions for IIS 7 - Beta 版。請解除安裝,然後再試一次 + + + WebDAV 7.5 For IIS 7.0 + 必須安裝 IIS 7.0 CoreWebEngine 和 W3SVC 功能才能使用這個產品。 + WebDAV 伺服器模組 + WebDAV Administration 使用者介面 + + + IIS Search Engine Optimization Toolkit 1.0 + IIS Search Engine Optimization Toolkit 1.0 + Search Engine Optimization (SEO) Toolkit 1.0 + 這個安裝程式資料庫內含安裝 IIS Search Engine Optimization Toolkit 1.0 所需的邏輯和資料。 + + + IIS 編輯器 + + + IIS 報告 + 這部電腦上未安裝記錄檔剖析器。請從 http://www.microsoft.com/downloads/details.aspx?FamilyID=890cd06b-abf8-4c25-91b2-f8d975cf8c07 安裝記錄檔剖析器 2.2,然後繼續安裝 IIS 報告 + + + 找不到必要條件封裝。請執行 setup.exe 解決相依性,然後再安裝這個程式。 + Microsoft SQL Server 2008 管理物件是安裝 IIS Database Manager 的必要條件。您可以從 http://go.microsoft.com/fwlink/?LinkID=150946 安裝 Micrsoft SQL Server 2008 管理物件。 + Microsoft SQL Server 系統 CLR 類型是安裝 IIS Database Manager 的必要條件。您可以從 http://go.microsoft.com/fwlink/?LinkID=150949 安裝 Microsoft SQL Server 系統 CLR 類型。 + + + Microsoft Web Farm Framework + Microsoft External Cache + Web Farm Framework 是安裝應用程式要求路由的必要條件。請安裝 Web Farm Framework。 + Microsoft Application Request Routing 2.5 + 執行階段 + 將應用程式要求路由功能新增至 IIS。 + 使用者介面 + 設定 IIS 管理員中的應用程式要求路由功能。 + + + IIS 7.0 的 Microsoft Windows PowerShell 嵌入式管理單元 + + + Microsoft Web Platform Installer 4.0 + Microsoft Web Platform Installer + [ProductName] 需要 Windows XP SP2、Windows 2003 SP1、Windows Vista 或更新版本。 + [ProductName] 需要 Windows XP Service Pack 3、Windows Server 2003 Service Pack 2 (含) 以上版本。 + + + Microsoft Windows Azure Services 安裝程式 + Microsoft Windows Azure Services 安裝程式 + + + Internet Information Services (IIS) 7+ 管理員 + IIS 管理員用戶端 + 遠端支援 + 這個產品需要 Windows XP SP2、Windows 2003 SP1、Windows Vista SP1、Windows 7 或更新版本 + 未安裝 IIS 管理主控台,但需要它才能管理遠端 IIS 伺服器。安裝遠端管理支援之前,請先安裝 IIS 管理主控台,安裝方式是開啟 [控制台]->[所有程式]->[開啟或關閉 Windows 功能],並在 Internet Information Services 功能中選取 [IIS 管理主控台]。 + 在 Windows Server 2008、Windows Server 2008 R2 或更新版本中不需要這個產品。請安裝 IIS 管理主控台,安裝方式是開啟伺服器管理員,然後在網頁伺服器角色的角色服務中選取 [IIS 管理主控台]。 + + + IIS Manager Publishing for IIS 7.0 + 發行使用者介面 + + + Application Warm-Up 1.0 for IIS 7.5 + + + + 不相容的產品 [CONFLICTING_PRODUCT_NAME] 出現在這部電腦上。無法繼續安裝 [ProductName]。若要安裝這個產品,請使用 [控制台] 的 [新增/移除程式移除 [CONFLICTING_PRODUCT_NAME]。 + 需要有系統管理員權限,才能安裝 [ProductName]。 + 需要 IIS 7.0 版才能使用 [ProductName]。 + 需要 IIS 7.0 版或更新版本,才能安裝 [ProductName]。 + 需要 IIS 7.5 版或更新版本,才能安裝 [ProductName]。 + 需要 IIS 第 7 版或第 7.5 版才能安裝 [ProductName]。 + 在這部電腦上發現 [ProductName] 的 Beta 版。 + 在這部電腦上發現 [ProductName] 較新的版本。 + 安裝程式無法繼續,因為這部電腦上已安裝另一份 [ProductName]。請先解除該安裝後,再重新啟動這個安裝。 + 必須安裝 IIS 7.0 CoreWebEngine 和 W3SVC 功能才能使用 [ProductName]。 + 必須安裝 IIS 管理主控台才能使用 [ProductName]。 + 安裝 [ProductName] 前,請先停止 Windows 處理序啟用服務 (WAS) 和 Web Management Service (WMSvc) 兩個服務。您必須在安裝 [ProductName] 後再啟動服務。 + 需要 IIS Metabase 才能安裝 [ProductName]。 + 無法將 64 位元版本的 [ProductName] 安裝在 32 位元版本的 Microsoft Windows 上。 + 無法將 32 位元版本的 [ProductName] 安裝在 64 位元版本的 Microsoft Windows 上。 + 需要 Microsoft .NET Framework 2.0 版本或更新版本,才能安裝 [ProductName]。 + 必須安裝 Microsoft .NET Framework 3.5 (含) 以上版本,才能安裝 [ProductName]。請使用伺服器管理員底下的「新增功能」安裝 Microsoft .NET 3.5 版。 + 需要 Microsoft .NET Framework 4 (含) 以上版本才能安裝 [ProductName]。 + 請先安裝 Microsoft .NET Framework 2.0 版 Service Pack 1 (或更新版的 Service Pack),再安裝 [ProductName]。 + 無法停用 Windows Update (wuauserv) 服務,需要它才能安裝 [ProductName]。 + PowerShell 嵌入式管理單元是 Windows 作業系統的一部分。請用 [程式和功能] 或 [伺服器管理員] 進行安裝。 + 需要 Microsoft Web Platform Installer 3.0 (含) 以上版本才能安裝 [ProductName]。 + + 安裝程式偵測不到共用設定。 + 已為 IIS 啟用共用設定。不支援在使用共用設定時安裝 [ProductName]。請先停用共用設定,再安裝這項功能。 + + 安裝 [ProductName] 前,請先停止 World Wide Web Publishing 服務 (W3SVC)。您必須在安裝後再啟動服務。 + IIS PowerShell 管理主控台 + IIS PowerShell 嵌入式管理單元 + IIS PowerShell 嵌入式管理單元要求必須已安裝 PowerShell v1.0 或 v2.0 + IIS PowerShell 嵌入式管理單元要求必須已安裝 WAS 和設定 + 這是假的字串。 + + + Microsoft Web Farm Framework 2.2版 + Microsoft Web Farm Agent 2.2 版 + Web 伺服陣列服務 + Web 伺服陣列服務 + Web 伺服陣列控制器服務 + Web 伺服陣列控制器服務 + Web 伺服陣列代理程式服務 + Web 伺服陣列代理程式服務 + Web Platform Installer 是安裝 Web Farm Framework 2.0 的必要元件。請從 http://www.microsoft.com/web/downloads/platform.aspx 安裝 Web Plaform Installer。 + Web Deployment Tool 是安裝 Web Farm Framework 的必要元件。請從 http://www.iis.net/download/WebDeploy 安裝 Web Deployment Tool。 + + + Microsoft Web Hosting Framework + Web Hosting Framework + Web Hosting 角色及功能。 + Hosting Framework + Hosting Framework 提供用於管理 Web Hosting 的 API 命令和 PowerShell 命令。 + Web 角色 + Web 角色會安裝 Web Hosting 的 Dynamic WAS 服務及 URL Rewrite 提供者。 + Antares Express + 部署已針對單一電腦環境最佳化的控制台設定。 + 負載平衡器角色 + 負載平衡器角色會將應用程式要求路由器設定為根據 Web Hosting 規則進行路由。 + 主機控制器 + 主機控制器會擴充 Web Farm Framework 2.0 以搭配 Web Hosting 運作。 + 發行角色 + 安裝 Web Deploy 及 FTP 發行的支援。 + 這是包含 Cmdlet 的 PowerShell 嵌入式管理單元,可用來管理 Microsoft Web Hosting 基礎結構。 + 動態 WAS 服務 + 針對高密度 Web Hosting 最佳化的 Windows Process Activation 服務。 + 資源計量服務 + 安裝資源計量服務,此服務可收集和發行執行階段和健康狀態資訊。 + 資源計量 + 可從 Web 角色收集及發行執行階段和健康狀態資訊。 + 主機配額強制 + 監視網站資源使用量,並且在超過使用量配額時執行自訂動作。 + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/CSY/misc/setupstrings.wxl b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/CSY/misc/setupstrings.wxl new file mode 100644 index 0000000000..2e4fca8c5c --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/CSY/misc/setupstrings.wxl @@ -0,0 +1,351 @@ + + + + + + + 1029 + + + + Možnosti instalace sdílené konfigurace + Vyberte možnosti instalace pro sdílenou konfiguraci služby IIS. + Při instalaci aktualizovat sdílenou konfiguraci + Tento modul instalujete na server služby IIS, který používá sdílenou konfiguraci. Používají-li tuto sdílenou konfiguraci další servery služby IIS, bude tento modul nainstalován na všechny tyto servery. Chcete-li co nejméně narušit jednotlivé webové servery, nainstalujte tento modul následovně: Nejprve na všechny servery kromě jednoho nainstalujte modul, aniž byste aktualizovali sdílenou konfiguraci. To provedete tak, že zrušíte zaškrtnutí následujícího + políčka. Tak nainstalujete všechny binární i ostatní soubory modulu na každý server, ale sdílená konfigurace zůstane beze změn. Následně na posledním serveru ověřte, zda má uživatelský účet, se kterým jste přihlášeni, dostatečná oprávnění ke čtení a zápisu do souboru applicationhost.config ve sdíleném úložišti UNC. Poté nainstalujte modul a vyberte níže uvedenou možnost aktualizace sdílené konfigurace. + + + Probíhá inicializace vlastní akce souboru web.config. + Probíhá aktualizace souboru web.config. + + + + Rozšířené protokolování Internetové informační služby + Umožňuje rozšířené protokolování dat kanálu IIS. + Rozšířené protokolování Internetové informační služby + Umožňuje vytváření vlastních souborů protokolu s rozšířeným výběrem polí. + Aktualizace pro rozšířené protokolování Internetové informační služby + + + + Správce transformace služby IIS + Beta + Povoluje správce transformace služby IIS Media Services. + Správce transformace služby IIS + Umožňuje tvorbu mediálních transformací. + Hostitel správce transformace služby IIS + Hostitel služby pro [ProductName]. + Správce transformace služby IIS + Dávkový převod souborů médií na vyžádání na jiné formáty souborů a kontejneru + V počítači je nainstalován balíček Expression Encoder SP Task Správce transformace služby IIS 1.0. Ten je třeba před instalací produktu [ProductName] odinstalovat. + + K instalaci produktu [ProductName] je vyžadováno rozhraní Microsoft .NET Framework 3.5. Můžete nainstalovat funkce rozhraní .NET Framework 3.5.1 pomocí Průvodce přidáním funkcí ve Správci serveru nebo zapnout rozhraní Microsoft .NET Framework 3.5 pomocí položky Zapnout nebo vypnout funkce systému Windows. + + + + Správa digitálních práv služby IIS + Beta + Povoluje správu digitálních práv pro prezentace Smooth Streaming. + + + Není nainstalována součást ASP.NET. + + + + + + + + + V tomto počítači byla nalezena beta verze rozšíření IIS Smooth Streaming. Instalace produktu [ProductName] nemůže pokračovat. Pokud chcete tento produkt nainstalovat, pomocí ovládacího panelu Přidat nebo odebrat programy odeberte položku IIS Smooth Streaming – Beta. + V tomto počítači je nekompatibilní verze služby IIS Media Services. Instalace produktu [ProductName] nemůže pokračovat. Pokud chcete tento produkt nainstalovat, pomocí ovládacího panelu Přidat nebo odebrat programy odeberte položku IIS Media Services. + V tomto počítači je již nainstalována nebo je k dispozici k instalaci novější verze tohoto produktu. Instalace produktu [ProductName] nemůže pokračovat. Pokud chcete nainstalovat novější verzi tohoto produktu, pomocí ovládacího panelu Přidat nebo odebrat programy aktualizujte položku IIS Media Services. + Je nutný převod souboru seznamu stop. + + + + + Byly nalezeny starší soubory služby IIS Media Services. + + + + + Byly nalezeny soubory beta verze služby IIS Media Services. + + + + + + IIS Media Pack 1.0 + Aktualizace pro sadu IIS Media Pack 1.0 + IIS Media Services 2.0 + Aktualizace pro službu IIS Media Services 2.0 + IIS Media Services 3.0 + IIS Media Services 3.0 TAP 2 + Aktualizace pro službu IIS Media Services 3.0 + Součásti a nástroje služby IIS Media Services. + Funkce a nástroje služby IIS Media Services 5 Premium + IIS Media Services 4.0 Beta 1 + IIS Media Services 4.0 + IIS Media Services 4.5 Beta 1 + IIS Media Services 5 Premium + + Webové seznamy stop + Řídí přehrávání mediálních materiálů odkazovaných v seznamech stop pro klienta. + Pomocník relace + Umožňuje trvalost stavu relace ASP.NET. (Je požadována služba role ASP.NET pro roli Webový server (IIS)). + Uživatelské rozhraní + Konfiguruje funkci Webové seznamy stop ve Správci služby IIS. + + Omezení přenosové rychlosti + Uspoří šířku pásma omezením doručování souborů stahovaných klienty. + Uživatelské rozhraní + Konfiguruje funkci Omezení přenosové rychlosti ve Správci služby IIS. + + Aktiva + Umožňuje vysílání adaptivních datových proudů protokolu HTTP aktiv na vyžádání pro klienty. + Uživatelské rozhraní + Konfiguruje funkci Smooth Streaming ve Správci služby IIS. + + Kanály + Umožňuje vysílání adaptivních datových proudů protokolu HTTP všesmerového vysílání kanálů pro klienty. + Uživatelské rozhraní + Konfiguruje funkci Live Smooth Streaming ve Správci služby IIS. + + Správa digitálních práv (DRM) + Zajišťuje šifrování a správu licencí médií Smooth Streaming. + Uživatelské rozhraní + Konfiguruje funkci správy digitálních práv ve správci služby IIS. + + [ProductName] požaduje systém Microsoft Windows Vista Service Pack 1 nebo novější. + [ProductName] nelze nainstalovat v systému Vista Home Basic. + [ProductName] požaduje systém Microsoft Windows 7 Service Pack 1 nebo novější. + + + Správce databáze služby IIS + Správce databáze služby IIS + + + Služba webové správy Microsoft 2 + Služba webové správy Microsoft + Nainstaluje základní součásti produktu [ProductName]. + Služba webové správy Microsoft 2 + Služba webové správy umožňuje vzdáleným a delegovaným funkcím správy pracovat s webovým serverem, weby a aplikacemi, které jsou uloženy v tomto počítači. + + + Microsoft URL Rewrite Module 1.1 for IIS 7 + Aktualizace pro produkt URL Rewrite Module 1.1 for IIS 7 + Přepisování adres URL + Dává službě IIS 7 možnost přepisovat adresy URL a obsah. + Uživatelské rozhraní + Konfiguruje funkci URL Rewrite Module ve Správci služby IIS. + + + IIS URL Rewrite Module 2 + Aktualizace pro produkt IIS URL Rewrite Module 2 + Přepisování adres URL + Dává službě IIS 7 možnost přepisovat adresy URL a obsah. + Uživatelské rozhraní + Konfiguruje funkci URL Rewrite Module ve Správci služby IIS. + + + Balíček pro správu služby IIS 7.0 + Nainstaluje základní součásti produktu [ProductName]. + 1250 + Balíček pro správu služby IIS 7.0 + Microsoft Corporation + Tato verze operačního systému není podporována. Produkt [ProductName] lze nainstalovat pouze v systémech Windows Server 2008 nebo Windows Vista Service Pack 1 a novějších. + Součásti ASP.NET + Technologie ASP.NET obsahuje součásti Autorizace a Chybové stránky, které umožňují spravovat nastavení autorizace a vlastních chyb. + Ověřování + Popis ověřování ASP.NET. + Autorizace + Autorizace ASP.NET umožňuje konfigurovat pravidla pro autorizaci uživatelů pro přístup k vašim webům a aplikacím. + Chybové stránky + Součást Chybové stránky ASP.NET umožňuje konfigurovat chybové odpovědi protokolu HTTP (stránky vrácené při chybě). + Moduly + Popis modulů ASP.NET. + Obslužné rutiny + Popis obslužných rutin ASP.NET. + Editor konfigurací + Editor konfigurací umožňuje spravovat konfigurační soubory ve Správci služby IIS. Umožňuje upravovat sekce, atributy, elementy a kolekce v konfiguračních souborech. + Filtrování požadavků + Funkce Filtrování žádostí umožňuje konfigurovat pravidla filtrování pro vaše weby a stanovit omezení pro protokol a chování obsahu. + FastCGI + Rozšíření FastCGI umožňuje konfigurovat nastavení fondu procesů pro aplikace FastCGI na vašem webovém serveru. + + + Dynamická omezení IP adres pro službu IIS 7 – instalace + + + + + + + + + + + + + Dynamická omezení IP adres pro službu IIS 7 – beta + Dynamická omezení IP adres pro službu IIS 7 – beta 2 + Dynamická omezení IP adres pro službu IIS 7 – beta 3 + + Dynamická omezení IP adres pro službu IIS 7 – Release Candidate + Dynamická omezení IP adres pro službu IIS 7 – Release Candidate 2 + Dynamická omezení IP adres pro službu IIS 7 – Release Candidate 3 + + Dynamická omezení IP adres pro službu IIS 7 – RTW + + Dynamická omezení IP adres pro službu IIS 7 + Uživatelské rozhraní pro dynamického omezení IP adres pro službu IIS 7 + + Na tomto serveru byla zjištěn dynamická omezení IP adres pro službu IIS 7 – Beta. Odinstalujte službu a opakujte akci. + + + WebDAV 7.5 pro službu IIS 7.0 + Tento produkt lze používat pouze tehdy, jsou-li nainstalovány součásti webového jádra a W3SVC služby IIS 7.0. + Modul serveru WebDAV + Uživatelské rozhraní pro správu protokolu WebDAV + + + Sada nástrojů optimalizace pro vyhledávací weby 1.0 + Sada nástrojů optimalizace pro vyhledávací weby 1.0 + Sada nástrojů optimalizace pro vyhledávací weby (SEO) 1.0 + Databáze instalačního programu obsahuje logiku a data vyžadovaná k instalaci sady nástrojů optimalizace pro vyhledávací weby služby IIS ve verzi 1.0. + + + Editor služby IIS + + + Sestavy služby IIS + V tomto počítači není nainstalován analyzátor protokolu Log Parser. Nainstalujte nástroj Log Parser 2.2 ze stránky http://www.microsoft.com/downloads/details.aspx?FamilyID=890cd06b-abf8-4c25-91b2-f8d975cf8c07 a pokračujte dále v instalaci součásti Sestavy služby IIS. + + + Nebyly nalezeny požadované balíčky. Spusťte soubor setup.exe, abyste vyřešili potíže se závislostmi, a potom nainstalujte tento program. + Microsoft SQL Server 2008 Management Objects je požadovaným produktem pro instalaci Správce databáze služby IIS. Produkt Microsoft SQL Server 2008 Management Objects lze nainstalovat ze stránky http://go.microsoft.com/fwlink/?LinkID=150946. + Microsoft SQL Server System CLR Types je požadovaným produktem pro instalaci Správce databáze služby IIS. Produkt Microsoft SQL Server System CLR Types lze nainstalovat ze stránky http://go.microsoft.com/fwlink/?LinkID=150949. + + + Microsoft Web Farm Framework + Microsoft External Cache + Technologie Směrování žádostí na aplikace požaduje, aby byla nainstalováno rozhraní Web Farm Framework. Nainstalujte rozhraní Web Farm Framework. + Microsoft Application Request Routing 2.5 + Modul runtime + Přidá do služby IIS možnosti směrování žádostí na aplikace. + Uživatelské rozhraní + Konfiguruje funkci směrování žádostí na aplikace ve správci služby IIS. + + + Modul snap-in Microsoft Windows PowerShell pro službu IIS 7.0 + + + Instalace webové platformy Microsoft 4.0 + Instalační služba webové platformy Microsoft + Produkt [ProductName] požaduje systém Windows XP SP2, Windows 2003 SP1, Windows Vista nebo novější. + Produkt [ProductName] vyžaduje systém Windows XP Service Pack 3, Windows Server 2003 Service Pack 2 nebo novější. + + + Instalační program služby Microsoft Windows Azure Services + Instalační program služby Microsoft Windows Azure Services + + + Správce Internetové informační služby (IIS) 7+ + Klient Správce služby IIS + Podpora vzdálené komunikace + Tento produkt vyžaduje systém Windows XP SP2, Windows 2003 SP1, Windows Vista SP1, Windows 7 nebo novější. + Není nainstalována konzola pro správu služby IIS, která je nutná pro správu vzdálených serverů služby IIS. Před instalací podpory vzdálené správy nainstalujte konzolu pro správu služby IIS: Přejděte na Ovládací panely ->Programy-> Zapnout nebo vypnout funkce systému Windows a v součásti Internetová informační služba vyberte položku Konzola pro správu služby IIS. + Tento produkt není požadován v systémech Windows Server 2008 nebo Windows Server 2008 R2 nebo novějších. Nainstalujte konzolu pro správu služby IIS otevřením Správce serveru a výběrem položky Konzola pro správu služby IIS v uzlu Služby rolí pro roli Webový server. + + + Publikování Správce služby IIS pro službu IIS 7.0 + Uživatelské rozhraní publikování + + + Application Warm-Up 1.0 pro službu IIS 7.5 + + + + V tomto počítači je nekompatibilní produkt [CONFLICTING_PRODUCT_NAME]. Instalace produktu [ProductName] nemůže pokračovat. Chcete-li tento produkt nainstalovat, odeberte pomocí funkce Přidat nebo odebrat programy v Ovládacích panelech produkt [CONFLICTING_PRODUCT_NAME]. + K instalaci produktu [ProductName] jsou nutná oprávnění správce. + Produkt [ProductName] lze používat pouze ve verzi 7.0 služby IIS. + K instalaci produktu [ProductName] je požadována služba IIS verze 7.0 nebo vyšší. + K instalaci produktu [ProductName] je požadována služba IIS verze 7.5 nebo vyšší. + K instalaci produktu [ProductName] je vyžadována služba IIS verze 7 nebo 7.5. + V tomto počítači byla nalezena beta verze produktu [ProductName]. + V tomto počítači byla nalezena novější verze produktu [ProductName]. + Instalační program nemůže pokračovat, protože v tomto počítači je již nainstalována jiná instance produktu [ProductName]. Odinstalujte tuto instanci a poté znovu spusťte instalaci. + Produkt [ProductName] lze používat pouze tehdy, jsou-li nainstalovány součásti webového jádra a W3SVC služby IIS 7.0. + Produkt [ProductName] lze používat pouze v případě, že je nainstalována konzola pro správu služby IIS. + Před instalací produktu [ProductName] je třeba zastavit Aktivační službu procesů systému Windows (WAS) a Službu webové správy (WMSvc). Po instalaci produktu [ProductName] bude třeba tyto služby opět spustit. + K instalaci produktu [ProductName] je požadována metabáze služby IIS. + 64bitovou verzi produktu [ProductName] nelze nainstalovat do 32bitové edice systému Microsoft Windows. + 32bitovou verzi produktu [ProductName] nelze nainstalovat do 64bitové edice systému Microsoft Windows. + K instalaci produktu [ProductName] je požadováno rozhraní Microsoft .NET Framework 2.0 nebo vyšší. + K instalaci produktu [ProductName] je vyžadováno rozhraní Microsoft .NET Framework 3.5 nebo vyšší. Nainstalujte toto rozhraní pomocí tlačítka Přidat funkce ve správci serveru. + K instalaci produktu [ProductName] je vyžadováno rozhraní Microsoft .NET Framework 4.0 nebo vyšší. + Před instalací produktu [ProductName] nainstalujte rozhraní Microsoft .NET Framework verze 2.0 Service Pack 1 (nebo novější aktualizaci Service Pack). + Služba Windows Update (wuauserv) nemůže být zakázána. Je požadována pro instalaci produktu [ProductName]. + Modul snap-in PowerShell je součástí operačního systému Windows. Nainstalujte jej prostřednictvím ovládacího panelu Programy a funkce nebo prostřednictvím Správce serveru. + K instalaci produktu [ProductName] je vyžadována Instalace webové platformy společnosti Microsoft verze 3.0 nebo vyšší. + + Instalačnímu programu se nepodařilo zjistit sdílenou konfiguraci. + Pro službu IIS je povolena sdílená konfigurace. Instalace produktu [ProductName] není podporována při použití sdílené konfigurace. Před instalací této součásti je třeba sdílenou konfiguraci zakázat. + + Před instalací produktu [ProductName] zastavte Službu publikování na webu (W3SVC). Po instalaci bude třeba ji opět spustit. + Konzola pro správu prostředí PowerShell služby IIS + Modul snap-in PowerShell služby IIS + Modul snap-in PowerShell služby IIS požaduje, aby byl nainstalována součást PowerShell v1.0 nebo v2.0. + Modul snap-in PowerShell služby IIS požaduje, aby byl nainstalována služba WAS a konfigurace. + Toto je nepravý řetězec. + + + Rozhraní Microsoft Web Farm Framework verze 2.2 + Agent Microsoft Web Farm verze 2.2 + Služba Web Farm + Služba Web Farm + Služba řadiče Web Farm + Služba řadiče Web Farm + Služba agenta Web Farm + Služba agenta Web Farm + K instalaci rozhraní Web Farm Framework je vyžadován průvodce Instalace webové platformy. Nainstalujte jej z adresy http://www.microsoft.com/web/downloads/platform.aspx. + K instalaci rozhraní Web Farm Framework je vyžadován Nástroj pro nasazení webu. Nainstalujte jej z adresy http://www.iis.net/download/WebDeploy. + + + Architektura webových hostitelských služeb společnosti Microsoft + Architektura webových hostitelských služeb + Role a funkce webových hostitelských služeb + Architektura hostitelských služeb + Architektura hostitelských služeb poskytuje příkazy rozhraní API a prostředí PowerShell pro správu webových hostitelských služeb. + Webová role + Webová role nainstaluje Dynamickou službu WAS a zprostředkovatele pro přepis adresy URL pro webové hostitelské služby. + Antares Express + Nasadí konfiguraci ovládacích panelů optimalizovanou pro instalaci v jednom počítači. + Role nástroje pro vyrovnávání zatížení + Role nástroje pro vyrovnávání zatížení nakonfiguruje směrovač žádostí aplikace na směrování na základě pravidel webových hostitelských služeb. + Řadič hostingu + Řadič hostitelských služeb rozšiřuje rozhraní Web Farm Framework 2.0 na práci s webovými hostitelskými službami. + Role publikování + Nainstaluje podporu pro nasazení webu a publikování FTP. + Jde o modul snap-in prostředí PowerShell obsahující rutiny umožňující správu infrastruktury Microsoft Web Hosting. + Dynamická služba WAS + Aktivační služba procesů systému Windows optimalizovaná pro webové hostitelské služby s vysokou hustotou + Služba měření četnosti odesílání dat ze zdrojů + Nainstaluje službu měření četnosti odesílání dat ze zdrojů, která umožňuje shromažďovat a publikovat informace o běhu i o stavu. + Resource Metering + Povolí shromažďování a publikování informací o běhu a stavu z webové role. + Vynucení kvóty hostitelských služeb + Monitoruje využití prostředků na webech a v případě překročení kvóty použití spustí vlastní akce. + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/DEU/misc/setupstrings.wxl b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/DEU/misc/setupstrings.wxl new file mode 100644 index 0000000000..436243b9ad --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/DEU/misc/setupstrings.wxl @@ -0,0 +1,351 @@ + + + + + + + 1031 + + + + Installationsoptionen für freigegebene Konfiguration + Wählen Sie eine Option für die Installation in der freigegebenen IIS-Konfiguration aus. + Freigegebene Konfiguration bei Installation aktualisieren + Die Installation des Moduls erfolgt auf einem IIS-Server, der eine freigegebene Konfiguration verwendet. Wenn weitere IIS-Server diese freigegebene Konfiguration verwenden, müssen Sie dieses Modul auf allen beteiligten Computern installieren. Um Unterbrechungen auf den einzelnen Webservern zu vermeiden, beachten Sie bei der Installation des Moduls die folgenden Schritte: Führen Sie die Modulinstallation auf allen bis auf dem letzten Computer durch, ohne die freigegebene Konfiguration zu aktualisieren. Deaktivieren Sie hierzu das folgende + Kontrollkästchen. Dadurch werden alle Binärdateien und andere für das Modul benötigten Dateien auf jedem Computer installiert, ohne Änderungen an der freigegebenen Konfiguration vorzunehmen. Anschließend müssen Sie auf dem letzten Computer sicherstellen, dass das verwendete Benutzerkonto über Lese- und Schreibzugriff auf die Datei "applicationhost.config" auf der UNC-Freigabe verfügt. Installieren Sie dann das Modul, und aktivieren Sie dabei die folgend gezeigte Option zum Aktualisieren der freigegebenen Konfiguration. + + + Die benutzerdefinierte WebConfig-Aktion wird initialisiert. + "web.config" wird aktualisiert. + + + + IIS Advanced Logging + Aktiviert die erweiterte Protokollierung von IIS-Pipelinedaten. + IIS Advanced Logging + Aktiviert die Erstellung von Protokolldateien mit umfangreicher Feldauswahl. + Update für IIS Advanced Logging + + + + IIS Transform Manager + Beta + Aktiviert die Transform Manager IIS Media Services. + IIS Transform Manager + Aktiviert die Erstellung von Medientransformationen. + IIS Transform Manager-Host + Diensthost für [ProductName]. + IIS Transform Manager + Bedarfsgesteuerte Batchkonvertierung von Mediendateien in andere Datei- und Containerformate. + Ein IIS Transform Manager 1.0 Expression Encoder SP-Aufgabenpaket ist auf dem Computer installiert. Sie müssen das Paket deinstallieren, bevor Sie [ProductName] installieren können. + + Microsoft .NET Framework 3.5 ist für die Installation von [ProductName] erforderlich. Verwenden Sie den Assistenten zum Hinzufügen von Features im Server-Manager, um .NET Framework 3.5.1-Features zu installieren, oder verwenden Sie die Option "Windows-Features ein- oder ausschalten" zum Aktivieren von Microsoft .NET Framework 3.5. + + + + IIS-Verwaltung digitaler Rechte (DRM) + Beta + Aktiviert die Verwaltung digitaler Rechte (DRM) für Smooth Streaming-Präsentationen. + + + ASP.NET ist nicht installiert. + + + + + + + + + IIS Smooth Streaming Beta wurde auf diesem Computer gefunden. Die Installation von [ProductName] kann nicht fortgesetzt werden. Um dieses Produkt zu installieren, können Sie IIS Smooth Streaming Beta über die Funktion "Software" in der Systemsteuerung entfernen. + Auf diesem Computer befindet sich eine inkompatible Version der IIS Media Services. Die Installation von [ProductName] kann nicht fortgesetzt werden. Um dieses Produkt zu installieren, können Sie IIS Media Services über die Funktion "Software" in der Systemsteuerung entfernen. + Eine neuere Version dieses Produkts ist entweder bereits installiert oder für die Installation auf diesem Computer verfügbar. Die Installation von [ProductName] kann nicht fortgesetzt werden. Zum Installieren einer neueren Version des Produkts rufen Sie die Systemsteuerung auf, wählen 'Software' und aktualisieren dann die IIS Media Services. + Die Konvertierung der Wiedergabelistendatei ist erforderlich. + + + + + Es wurden ältere IIS Media Services-Dateien gefunden. + + + + + Es wurden IIS Media Services-Dateien der Betaversion gefunden. + + + + + + IIS Media Pack 1.0 + Update für IIS Media Pack 1.0 + IIS Media Services 2.0 + Update für IIS Media Services 2.0 + IIS Media Services 3.0 + IIS Media Services 3.0 TAP 2 + Update für IIS Media Services 3.0 + Features und Tools der IIS Media Services. + Features und Tools der IIS Media Services 5 Premium. + IIS Media Services 4.0 Beta 1 + IIS Media Services 4.0 + IIS Media Services 4.5 Beta 1 + IIS Media Services 5 Premium + + Internet-Wiedergabelisten + Steuert die Clientwiedergabe von Medienobjekten, auf die in Wiedergabelisten verwiesen wird. + Session Helper + Aktiviert die Dauerhaftigkeit des ASP.NET-Sitzungszustands (erfordert den ASP.NET-Rollendienst für Webserver (IIS)). + Benutzeroberfläche + Konfiguriert das Feature 'Internet-Wiedergabelisten' im IIS-Manager. + + Bitratendrosselung + Spart Bandbreite durch Drosselung der Übermittlung von Dateien ein, die von Clients heruntergeladen wurden. + Benutzeroberfläche + Konfiguriert das Feature 'Bitratendrosselung' im IIS-Manager. + + Objekte + Aktiviert adaptives HTTP-Streaming von bedarfsgesteuerten Objekten an Clients. + Benutzeroberfläche + Konfiguriert das Feature 'Smooth Streaming' im IIS-Manager. + + Kanäle + Aktiviert adaptives HTTP-Streaming von Kanalübertragungen an Clients. + Benutzeroberfläche + Konfiguriert das Live Smooth Streaming-Feature im IIS-Manager. + + Verwaltung digitaler Rechte (DRM) + Stellt Verschlüsselung und Lizenzierung für Smooth Streaming-Medien bereit. + Benutzeroberfläche + Konfiguriert die Funktion zur Verwaltung digitaler Rechte (DRM) im IIS-Manager. + + [ProductName] erfordert Microsoft Windows Vista Service Pack 1 oder höher. + [ProductName] darf nicht unter Vista Home Basic installiert werden. + [ProductName] erfordert Microsoft Windows 7 Service Pack 1 oder höher. + + + IIS-Datenbank-Manager + IIS-Datenbank-Manager + + + Microsoft-Webverwaltungsdienst 2 + Microsoft-Webverwaltungsdienst + Installiert die grundlegenden Features von [ProductName]. + Microsoft-Webverwaltungsdienst 2 + Der Webverwaltungsdienst bietet Remote- und delegierte Verwaltungsfunktionen für Administratoren zur Verwaltung des Webservers, der Websites und der Anwendungen auf diesem Computer. + + + Microsoft URL Rewrite-Modul 1.1 für IIS 7 + Update für das URL Rewrite-Modul 1.1 für IIS 7 + URL Rewrite + Aktiviert URL- und Inhaltsumschreibfunktionen für IIS 7. + Benutzeroberfläche + Konfiguriert das Feature 'URL Rewrite-Modul' im IIS-Manager. + + + IIS-URL-Rewrite-Modul 2 + Update für IIS-URL-Rewrite-Modul 2 + URL Rewrite + Aktiviert URL- und Inhaltsumschreibfunktionen für IIS 7. + Benutzeroberfläche + Konfiguriert das Feature 'URL Rewrite-Modul' im IIS-Manager. + + + Administration Pack für IIS 7.0 + Installiert die grundlegenden Features von [ProductName]. + 1252 + Administration Pack für IIS 7.0 + Microsoft Corporation + Diese Version des Betriebssystems wird nicht unterstützt. [ProductName] kann nur unter Windows Server 2008 oder Windows Vista Service Pack 1 und höher installiert werden. + ASP.NET-Features + ASP.NET umfasst Features für Autorisierung und Fehlerseiten, mit denen Sie die Autorisierungs- und benutzerdefinierten Fehlereinstellungen verwalten können. + Authentifizierung + ASP.NET-Authentifizierungsbeschreibung. + Autorisierung + Mit der ASP.NET-Autorisierung können Sie Regeln für die Autorisierung von Benutzern für den Zugriff auf Websites und Anwendungen konfigurieren. + Fehlerseiten + Mit den ASP.NET-Fehlerseiten können Sie HTTP-Fehlerreaktionen konfigurieren. + Module + ASP.NET-Modulbeschreibung. + Handler + ASP.NET-Handlerbeschreibung. + Konfigurations-Editor + Mit dem Konfigurations-Editor können Sie Konfigurationsdateien im IIS-Manager verwalten, indem Sie Abschnitte, Attribute, Elemente und Sammlungen der Konfigurationsdateien bearbeiten. + Anforderungsfilterung + Bei der Anforderungsfilterung können Sie Filterregeln für Ihre Website konfigurieren und das Protokoll- und Inhaltsverhalten beschränken. + FastCGI + Mit 'FastCGI' können Sie Prozesspooleinstellungen für die FastCGI-Anwendungen auf Ihrem Webserver konfigurieren. + + + Dynamische IP-Einschränkungen für die IIS 7-Konfiguration + + + + + + + + + + + + + Dynamische IP-Einschränkungen für IIS 7 - Beta + Dynamische IP-Einschränkungen für IIS 7 - Beta 2 + Dynamische IP-Einschränkungen für IIS 7 - Beta 3 + + Dynamische IP-Einschränkungen für IIS 7 - Release Candidate + Dynamische IP-Einschränkungen für IIS 7 - Release Candidate 2 + Dynamische IP-Einschränkungen für IIS 7 - Release Candidate 3 + + Dynamische IP-Einschränkungen für IIS 7 - RTW + + Dynamische IP-Einschränkungen für IIS 7 + Dynamische IP-Einschränkungen - Benutzeroberfläche für IIS 7 + + Dynamische IP-Einschränkungen für IIS 7 - Beta wurde auf diesem Computer gefunden. Deinstallieren Sie diese Anwendung, und versuchen Sie es erneut. + + + WebDAV 7.5 für IIS 7.0 + Die IIS 7.0-Features CoreWebEngine und W3SVC müssen für die Verwendung dieses Produkts installiert sein. + WebDAV-Servermodul + WebDAV-Administrationsbenutzeroberfläche + + + IIS Search Engine Optimization Toolkit 1.0 + IIS Search Engine Optimization Toolkit 1.0 + Search Engine Optimization (SEO) Toolkit 1.0 + Diese Installer-Datenbank enthält die zum Installieren von IIS Search Engine Optimization Toolkit 1.0 erforderliche Logik. + + + IIS-Editor + + + IIS-Berichte + Der Protokollparser ist nicht auf diesem Computer installiert. Installieren Sie Log Parser 2.2 über http://www.microsoft.com/downloads/details.aspx?FamilyID=890cd06b-abf8-4c25-91b2-f8d975cf8c07, und setzen Sie dann die Installation der IIS-Berichte fort. + + + Erforderliche Pakete wurden nicht gefunden. Führen Sie 'setup.exe' aus, um Abhängigkeiten aufzulösen und dieses Programm zu installieren. + Microsoft SQL Server 2008 Management Objects ist eine Voraussetzung für die Installation von IIS-Datenbank-Manager. Sie können Microsoft SQL Server 2008 Management Objects über http://go.microsoft.com/fwlink/?LinkID=150946 installieren. + Microsoft SQL Server System CLR Types ist eine Voraussetzung für die Installation von IIS-Datenbank-Manager. Sie können Microsoft SQL Server System CLR Types über http://go.microsoft.com/fwlink/?LinkID=150949 installieren. + + + Microsoft Web Farm Framework + Microsoft External Cache + Web Farm Framework ist eine Voraussetzung für die Installation des Routings von Anwendungsanforderungen. Installieren Sie Web Farm Framework. + Microsoft Application Request Routing 2.5 + Laufzeit + Fügt die Funktionen des Routings von Anwendungsanforderungen zu IIS hinzu. + Benutzeroberfläche + Konfiguriert das Feature "Routing von Anwendungsanforderungen" im IIS-Manager. + + + Microsoft Windows PowerShell snap-in für IIS 7.0 + + + Microsoft-Webplattform-Installer 4.0 + Microsoft-Webplattform-Installer + [ProductName] erfordert Windows XP SP2, Windows 2003 SP1, Windows Vista oder höher. + [ProductName] benötigt Windows XP Service Pack 3, Windows Server 2003 Service Pack 2 oder höher. + + + Microsoft Windows Azure Services Installer + Microsoft Windows Azure Services Installer + + + Internetinformationsdienste (IIS) 7+-Manager + IIS-Manager-Client + Remotesupport + Das Produkt erfordert Windows XP SP2, Windows 2003 SP1, Windows Vista SP1 oder Windows 7 oder höher. + Die IIS-Verwaltungskonsole ist nicht installiert, sie ist aber zur Verwaltung von Remote-IIS-Servern erforderlich. Installieren Sie die IIS-Verwaltungskonsole vor der Installation des Remoteverwaltungssupports durch Öffnen von 'Systemsteuerung->Programme->Windows-Funktionen ein- oder ausschalten' und Auswahl der IIS-Verwaltungskonsole im Feature 'Internetinformationsdienste'. + Dieses Produkt ist in Windows Server 2008 oder Windows Server 2008 R2 oder höher nicht erforderlich. Installieren Sie die IIS-Verwaltungskonsole durch Öffnen des Server-Managers und Auswahl der IIS-Verwaltungskonsole in den Rollendiensten für die Webserverrolle. + + + IIS-Manager-Publishing für IIS 7.0 + Publishing-Benutzeroberfläche + + + Application Warm-Up 1.0 für IIS 7.5 + + + + Ein inkompatibles Produkt ( [CONFLICTING_PRODUCT_NAME]) ist auf dem Computer. installiert. Die Installation von [ProductName] kann nicht fortgesetzt werden. Verwenden Sie zum Installieren dieses Produkts "Software" in der Systemsteuerung, um [CONFLICTING_PRODUCT_NAME] zu entfernen. + Administratorberechtigungen sind für die Installation von [ProductName] erforderlich. + IIS Version 7.0 ist für die Verwendung von [ProductName] erforderlich. + IIS Version 7.0 oder höher ist für die Installation von [ProductName] erforderlich. + IIS Version 7.5 oder höher ist für die Installation von [ProductName] erforderlich. + IIS Version 7.0 oder 7.5 ist für die Installation von [ProductName] erforderlich. + Eine Betaversion von [ProductName] wurde auf diesem Computer gefunden. + Eine neuere Version von [ProductName] wurde auf diesem Computer gefunden. + Die Installation kann nicht fortgesetzt werden, da eine andere Instanz von [ProductName] bereits auf diesem Computer installiert ist. Deinstallieren Sie diese zuerst, und starten Sie die Installation dann erneut. + Die IIS 7.0-Features CoreWebEngine und W3SVC müssen für die Verwendung von [ProductName] installiert sein. + Die IIS-Verwaltungskonsole muss für die Verwendung von [ProductName] installiert sein. + Halten Sie die den Windows-Prozessaktivierungsdienst (WAS) und den Webverwaltungsdienst (WMSvc) vor der Installation von [ProductName] an. Sie müssen die Dienste nach der Installation von [ProductName] wieder starten. + IIS-Metabasis ist für die Installation von [ProductName] erforderlich. + Die 64-Bit-Version von [ProductName] kann nicht in einer 32-Bit-Version von Microsoft Windows installiert werden. + Die 32-Bit-Version von [ProductName] kann nicht in einer 64-Bit-Version von Microsoft Windows installiert werden. + Microsoft .NET Framework Version 2.0 oder höher ist für die Installation von [ProductName] erforderlich. + Microsoft .NET Framework Version 3.5 oder höher ist für die Installation von [ProductName] erforderlich. Verwenden Sie die Option "Features hinzufügen" im Server-Manager, um Microsoft .Net Version 3.5 zu installieren. + Microsoft .NET Framework Version 4.0 oder höher ist für die Installation von [ProductName] erforderlich. + Installieren Sie Microsoft .NET Framework Version 2.0 Service Pack 1 (oder ein höheres Service Pack) vor der Installation von [ProductName]. + Der Windows Update (wuauserv)-Dienst kann nicht deaktiviert werden, er ist zur Installation von [ProductName] erforderlich. + Das PowerShell-Snap-In ist Teil des Windows-Betriebssystems. Installieren Sie es über 'Programme und Funktionen' oder 'Server-Manager'. + Microsoft-Webplattform-Installer Version 3.0 oder höher ist für die Installation von [ProductName] erforderlich. + + Die freigegebene Konfiguration konnte nicht ermittelt werden. + Die freigegebene Konfiguration ist für IIS aktiviert. Die Installation von [ProductName] wird bei Verwendung der freigegebenen Konfiguration nicht unterstützt. Deaktivieren Sie die freigegebene Konfiguration vor der Installation des Features. + + Halten Sie den WWW-Publishingdienst (W3SVC) vor der Installation von [ProductName] an. Sie müssen den Dienst nach der Installation wieder starten. + IIS-PowerShell-Verwaltungskonsole + IIS-PowerShell-Snap-In + Das IIS-PowerShell-Snap-In erfordert die Installation von PowerShell v1.0 oder v2.0. + Das IIS-PowerShell-Snap-In erfordert die Installation des Windows-Prozessaktivierungsdiensts und der Konfiguration. + Dies ist eine Platzhalter-Zeichenfolge. + + + Microsoft Web Farm Framework Version 2.2 + Microsoft Webfarm-Agent Version 2.2 + Webfarmdienst + Webfarmdienst + Webfarm-Controllerdienst + Webfarm-Controllerdienst + Webfarm-Agent-Dienst + Webfarm-Agent-Dienst + Webplattform-Installer ist eine Voraussetzung für die Installation von Web Farm Framework. Installieren Sie den Webplattform-Installer von "http://www.microsoft.com/web/downloads/platform.aspx". + Die Webbereitstellungstools sind eine Voraussetzung für die Installation von Web Farm Framework. Installieren Sie das Webbereitstellungstool von "http://www.iis.net/download/WebDeploy". + + + Microsoft Web Hosting Framework + Web Hosting Framework + Rollen und Funktionen für Web Hosting. + Hosting Framework + Hosting Framework stellt APIs und PowerShell-Befehle zum Verwalten von Web Hosting zur Verfügung. + Webrolle + Die Webrolle installiert den dynamischen WAS-Dienst und den URL-Rewrite-Anbieter für Web Hosting. + Antares Express + Stellt eine Systemsteuerungskonfiguration bereit, die für die Einrichtung eines einzelnen Computers optimiert ist. + Lastenausgleichsrolle + Die Lastenausgleichsrolle konfiguriert den Anwendungsanforderungsrouter für Routing basierend auf Web Hosting-Regeln. + Hostingcontroller + Der Hostingcontroller erweitert Web Farm Framework 2.0 für die Zusammenarbeit mit Web Hosting. + Veröffentlichungsrolle + Installiert Unterstützung für Web Deploy und FTP-Veröffentlichung. + Hierbei handelt es sich um ein PowerShell-Snap-In mit Cmdlets zur Verwaltung der Microsoft Web Hosting-Infrastruktur. + Dynamischer WAS-Dienst + Windows-Prozessaktivierungsdienst, der für HD-Web Hosting optimiert ist. + Resource Metering-Dienst + Installiert den Resource Metering-Dienst, der das Sammeln und Veröffentlichen von Laufzeit- und Systemintegritätsinformationen ermöglicht. + Resource Metering + Aktiviert das Sammeln und Veröffentlichen von Laufzeit- und Systemintegritätsinformationen aus der Webrolle. + Durchsetzung des Hostingkontingents + Überwacht den Website-Ressourceneinsatz und führt benutzerdefinierte Aktionen aus, wenn das Verwendungskontingent überschritten wurde. + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/ESN/misc/setupstrings.wxl b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/ESN/misc/setupstrings.wxl new file mode 100644 index 0000000000..ea1579e794 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/ESN/misc/setupstrings.wxl @@ -0,0 +1,351 @@ + + + + + + + 3082 + + + + Opciones de instalación de la configuración compartida + Seleccionar la opción de instalación en la configuración compartida de IIS + Actualizar configuración compartida al instalar + Está instalando este módulo en un servidor IIS que usa una configuración compartida. Si otros servidores IIS usan esta configuración compartida, tendrá que instalar este módulo en todas estas máquinas. Para minimizar las interrupciones de los servidores web individuales, tendrá que instalar este módulo realizando los pasos siguientes. En primer lugar, en todas las máquinas, excepto en la última, debe instalar el módulo sin actualizar la configuración compartida. Hágalo sin activar la casilla + siguiente. Esto instalará todos los binarios y archivos necesarios para el módulo en cada máquina sin modificar la configuración compartida. En segundo lugar, en la última máquina tendrá que comprobar que la identidad del usuario con la que está trabajando tiene acceso de lectura y escritura al archivo applicationhost.config del recurso compartido UNC. Después, debe instalar el módulo y seleccionar la opción de actualización de configuración compartida que figura a continuación. + + + Inicialización de acción personalizada de WebConfig + Actualización de archivo web.config + + + + Registro avanzado de IIS + Permite el registro avanzado de datos de canalización de IIS. + Registro avanzado de IIS + Permite la creación de archivos de registro personalizados con selección de campos extensible. + Actualización de Advanced Logging de IIS + + + + Transform Manager para IIS + Beta + Habilita los Servicios multimedia de IIS para Transform Manager. + Transform Manager para IIS + Habilita la creación de transformaciones multimedia. + Host de Transform Manager para IIS + Host de servicios para [ProductName]. + Transform Manager para IIS + Permite convertir por lotes archivos multimedia a petición para alternar formatos de archivo y contenedor. + Existe un paquete de tareas de IIS Transform Manager 1.0 Expression Encoder SP instalado en el equipo. Deberá desinstalarlo antes de instalar [ProductName]. + + Se necesita Microsoft .NET Framework 3.5 para instalar [ProductName]. Use el 'Asistente para agregar características' del Administrador del servidor para instalar las características de .NET Framework 3.5.1 o la opción 'Activar o desactivar las características de Windows' para activar Microsoft .NET Framework 3.5. + + + + Administración de derechos digitales de IIS + Beta + Habilita la administración de derechos digitales de presentaciones de transmisión por secuencias suave. + + + ASP.NET no está instalado + + + + + + + + + Se encontró IIS Smooth Streaming - Beta en este equipo. La instalación de [ProductName] no puede continuar. Para instalar este producto, use Agregar o quitar programas en el Panel de control para quitar IIS Smooth Streaming - Beta. + Este equipo cuenta con una versión no compatible de Servicios multimedia de IIS. La instalación de [ProductName] no puede continuar. Para instalar este producto, use Agregar o quitar programas en el Panel de control para quitar Servicios multimedia de IIS. + Una versión más reciente de este producto está ya instalada o disponible para instalarla en este equipo. La instalación de [ProductName] no puede continuar. Para instalar la versión más reciente de este producto, use Agregar o quitar programas en el Panel de control para actualizar Servicios multimedia de IIS. + Conversión necesaria de archivo de lista de reproducción + + + + + Archivos de versiones anteriores de Servicios multimedia de IIS encontrados + + + + + Versión beta de los Servicios Multimedia de IIS encontrada + + + + + + IIS Media Pack 1.0 + Actualización de IIS Media Pack 1.0 + Servicios multimedia 2.0 de IIS + Actualización de Servicios multimedia 2.0 de IIS + Servicios multimedia 3.0 de IIS + Servicios multimedia 3.0 de IIS (TAP 2) + Actualización de Servicios multimedia 3.0 de IIS + Características y herramientas de Servicios multimedia de IIS. + Características y herramientas de Servicios multimedia de IIS 5 Premium. + Servicios multimedia 4.0 beta 1 de IIS + Servicios multimedia 4.0 de IIS + Servicios multimedia 4.5 beta 1 de IIS + Servicios multimedia de IIS 5 Premium + + Listas de reproducción en web + Controla la reproducción en clientes de recursos multimedia digitales a los que se hace referencia en listas de reproducción. + Aplicación auxiliar para sesiones + Habilita la persistencia de estado de sesión de ASP.NET. Requiere el servicio de rol ASP.NET para el rol Servidor web (IIS). + Interfaz de usuario + Configura la característica Listas de reproducción en web en el Administrador de IIS. + + Limitación de velocidad de bits + Ahorra ancho de banda limitando la entrega de archivos descargados por los clientes. + Interfaz de usuario + Configura la característica Limitación de velocidad de bits en el Administrador de IIS. + + Activos + Habilita la transmisión por secuencias adaptativa HTTP de archivos a petición a los clientes. + Interfaz de usuario + Configura la característica Transmisión por secuencias suave en el Administrador de IIS. + + Canales + Habilita la transmisión por secuencias adaptativa HTTP de las difusiones de canal a los clientes. + Interfaz de usuario + Configura la característica Live Smooth Streaming en el Administrador de IIS. + + Administración de derechos digitales + Proporciona cifrado y licencias de medios de transmisión por secuencias suave. + Interfaz de usuario + Configura la característica de administración de derechos digitales en el administrador de IIS. + + [ProductName] requiere Microsoft Windows Vista Service Pack 1 o posterior. + [ProductName] no se puede instalar en Vista Home Basic. + [ProductName] requiere Microsoft Windows 7 Service Pack 1 o posterior. + + + Administrador de bases de datos de IIS + Administrador de bases de datos de IIS + + + Servicio de administración web de Microsoft 2 + Servicio de administración web de Microsoft + Instala las características básicas de [ProductName]. + Servicio de administración web de Microsoft 2 + El Servicio de administración web habilita funciones de administración remota y delegada para quienes administren los sitios, las aplicaciones y el servidor web presentes en este equipo. + + + Módulo URL Rewrite 1.1 para IIS 7 + Actualización de Módulo URL Rewrite 1.1 para IIS 7 + URL Rewrite + Habilita la reescritura de direcciones URL y contenido en IIS 7. + Interfaz de usuario + Configura la característica Módulo URL Rewrite en el Administrador de IIS. + + + Módulo URL Rewrite 2 de IIS + Actualización de Módulo URL Rewrite 2 de IIS + URL Rewrite + Habilita la reescritura de direcciones URL y contenido en IIS 7. + Interfaz de usuario + Configura la característica Módulo URL Rewrite en el Administrador de IIS. + + + Administration Pack para IIS 7.0 + Instala las características básicas de [ProductName]. + 1252 + Administration Pack para IIS 7.0 + Microsoft Corporation + No se admite esta versión del sistema operativo. [ProductName] se puede instalar sólo en Windows Server 2008 o Windows Vista Service Pack 1 y posterior. + Características de ASP.NET + ASP.NET incluye las características Autorización y Páginas de errores, que permiten administrar la autorización y la configuración de errores personalizada. + Autenticación + Descripción de autenticación ASP.NET. + Autorización + Autorización de ASP.NET permite configurar reglas para autorizar a usuarios a obtener acceso a sitios y aplicaciones web. + Páginas de errores + Páginas de errores de ASP.NET permite configurar respuestas a errores HTTP para devolverlas cuando se producen errores. + Módulos + Descripción de módulos de ASP.NET. + Controladores + Descripción de controladores de ASP.NET. + Editor de configuración + El Editor de configuración permite administrar los archivos de configuración en el Administrador de IIS. Permite editar secciones, atributos, elementos y colecciones en los archivos de configuración. + Filtrado de solicitudes + Filtrado de solicitudes permite configurar reglas de filtrado para un sitio web y restringir el comportamiento de protocolo y contenido. + FastCGI + FastCGI permite configurar grupos de procesos para aplicaciones FastCGI del servidor web. + + + Programa de instalación de Restricciones de IP dinámicas para IIS 7 + + + + + + + + + + + + + Restricciones de IP dinámicas para IIS 7 - Beta + Restricciones de IP dinámicas para IIS 7 - Beta 2 + Restricciones de IP dinámicas para IIS 7 - Beta 3 + + Restricciones de IP dinámicas para IIS 7 - Release Candidate + Restricciones de IP dinámicas para IIS 7 - Release Candidate 2 + Restricciones de IP dinámicas para IIS 7 - Release Candidate 3 + + Restricciones de IP dinámicas para IIS 7 - RTW + + Restricciones de IP dinámicas para IIS 7 + Interfaz de usuario de Restricciones de IP dinámicas para IIS 7 + + Se encontraron restricciones de IP dinámicas para IIS 7 - Beta en esta máquina. Desinstálelo e inténtelo de nuevo. + + + WebDAV 7.5 para IIS 7.0 + Deben instalarse las características CoreWebEngine y W3SVC de IIS 7.0 para usar este producto. + Módulo de servidor de WebDAV + Interfaz de usuario de administración de WebDAV + + + Herramientas de optimización para el motor de búsqueda de IIS 1.0 + Herramientas de optimización para el motor de búsqueda de IIS 1.0 + Herramientas de optimización para el motor de búsqueda (SEO) de IIS 1.0 + Esta base de datos de instalador contiene la lógica y los datos necesarios para instalar las Herramientas de optimización para el motor de búsqueda de IIS 1.0. + + + Editor de IIS + + + Informes de IIS + Log Parser no está instalado en esta máquina. Instale Log Parser 2.2 desde http://www.microsoft.com/downloads/details.aspx?FamilyID=890cd06b-abf8-4c25-91b2-f8d975cf8c07 y después continúe con la instalación de Informes de IIS. + + + No se encontraron algunos paquetes de requisitos previos. Ejecute setup.exe para resolver las dependencias e instalar este programa. + Objetos de administración de Microsoft SQL Server 2008 es un requisito previo para instalar el Administrador de bases de datos de IIS. Puede instalar Objetos de administración de Microsoft SQL Server 2008 desde http://go.microsoft.com/fwlink/?LinkID=150946 . + Microsoft SQL Server System CLR Types es un requisito previo para instalar el Administrador de bases de datos de IIS. Puede instalar Microsoft SQL Server System CLR Types desde http://go.microsoft.com/fwlink/?LinkID=150949 . + + + Microsoft Web Farm Framework + Microsoft External Cache + Web Farm Framework es un requisito para instalar Enrutamiento de solicitud de aplicaciones. Instale Web Farm Framework. + Enrutamiento de solicitud de aplicaciones de Microsoft 2.5 + Runtime + Agrega las capacidades de Enrutamiento de solicitud de aplicaciones a IIS. + Interfaz de usuario + Configura la característica Enrutamiento de solicitud de aplicaciones en el Administrador de IIS. + + + Complemento PowerShell de Microsoft Windows para IIS 7.0 + + + Instalador de plataforma web 4.0 de Microsoft + Instalador de plataforma web de Microsoft + [ProductName] requiere Windows XP SP2, Windows 2003 SP1, Windows Vista o posterior. + [ProductName] requiere Windows XP Service Pack 3, Windows Server 2003 Service Pack 2 o posterior. + + + Instalador de Microsoft Windows Azure Services + Instalador de Microsoft Windows Azure Services + + + Administrador de Internet Information Services (IIS) 7 o posterior + Cliente del Administrador de IIS + Compatibilidad con comunicación remota + Este producto requiere Windows XP SP2, Windows 2003 SP1, Windows Vista SP1, Windows 7 o posterior. + La Consola de administración de IIS no está instalada, pero es necesaria para administrar servidores IIS remotos. Instale la Consola de administración de IIS antes de instalar la compatibilidad con administración remota. Para ello, abra 'Panel de control->Programas->Activar o desactivar las características de Windows' y seleccione Consola de administración de IIS en la característica Internet Information Services. + Este producto no es necesario en Windows Server 2008 ni Windows Server 2008 R2 o posterior. Para instalar la Consola de administración de IIS, abra el Administrador del servidor y seleccione Consola de administración de IIS en los servicios del rol Servidor web. + + + Servicio de publicación del Administrador de IIS para IIS 7.0 + Interfaz de usuario para publicación + + + Application Warm-Up 1.0 para IIS 7.5 + + + + El equipo tiene un producto no compatible, [CONFLICTING_PRODUCT_NAME]. No es posible continuar con la instalación de [ProductName]. Para instalar este producto, vaya a Panel de control > Agregar o quitar programas para quitar [CONFLICTING_PRODUCT_NAME]. + Es necesario el privilegio de administrador para instalar [ProductName]. + Es necesaria la versión 7.0 de IIS para usar [ProductName]. + Es necesaria la versión 7.0 o posterior de IIS para instalar [ProductName]. + Es necesaria la versión 7.5 o posterior de IIS para instalar [ProductName]. + Se requiere la versión 7 o 7.5 de IIS para instalar [ProductName]. + Se encontró la versión beta de [ProductName] en esta máquina. + Se encontró una versión más reciente de [ProductName] en esta máquina. + El programa de instalación no puede continuar porque ya hay instalada otra instancia de [ProductName] en esta máquina. Desinstale primero esa instancia y vuelva a iniciar esta instalación. + Deben estar instaladas las características CoreWebEngine y W3SVC de IIS 7.0 para usar [ProductName]. + Para usar [ProductName], debe estar instalada la Consola de administración de IIS. + Detenga los servicios WAS (Windows Process Activation) y WMSvc (Servicio de administración web) antes de instalar [ProductName]. Deberá iniciar los servicios después de instalar [ProductName]. + Es necesaria la metabase de IIS para instalar [ProductName]. + No se puede instalar la versión de 64 bits de [ProductName] en una edición de 32 bits de Microsoft Windows. + No se puede instalar la versión de 32 bits de [ProductName] en una edición de 64 bits de Microsoft Windows. + Es necesario Microsoft .NET Framework 2.0 o posterior para instalar [ProductName]. + Se requiere Microsoft .NET Framework, versión 3.5 o posterior, para instalar [ProductName]. Use la opción 'Agregar características' del Administrador del servidor para instalar Microsoft .Net, versión 3.5. + Se requiere Microsoft .NET Framework, versión 4.0 o posterior, para instalar [ProductName]. + Instale Microsoft .NET Framework 2.0 Service Pack 1 (o un Service Pack posterior) antes de instalar [ProductName]. + No se puede deshabilitar el servicio Windows Update (wuauserv), porque es necesario para instalar [ProductName]. + El complemento PowerShell forma parte del sistema operativo Windows. Instálelo desde 'Programas y características' o 'Administrador del servidor'. + Se requiere Instalador de plataforma web de Microsoft, versión 3.0 o posterior, para instalar [ProductName]. + + El programa de instalación no detectó ninguna configuración compartida. + Está habilitada la configuración compartida para IIS. No se admite la instalación de [ProductName] cuando se usa configuración compartida. Deshabilite la configuración compartida antes de instalar esta característica. + + Detenga el servicio de publicación World Wide Web (W3SVC) antes de instalar [ProductName]. Deberá iniciar el servicio después de la instalación. + Consola de administración de PowerShell para IIS + Complemento PowerShell para IIS + El complemento PowerShell para IIS requiere que esté instalado PowerShell v1.0 o v2.0. + El complemento PowerShell para IIS requiere que estén instalados el servicio WAS y la configuración. + This is a bogus string. + + + Microsoft Web Farm Framework versión 2.2 + Microsoft Web Farm Agent versión 2.2 + Servicio de Web Farm + Servicio de Web Farm + Servicio de controlador de Web Farm + Servicio de controlador de Web Farm + Servicio de agente de Web Farm + Servicio de agente de Web Farm + El Instalador de plataforma web es un requisito previo para instalar Web Farm Framework. Instale el Instalador de plataforma web desde http://www.microsoft.com/web/downloads/platform.aspx. + La Herramienta de implementación web es un requisito previo para instalar Web Farm Framework. Instale la Herramienta de implementación web desde http://www.iis.net/download/WebDeploy. + + + Microsoft Web Hosting Framework + Web Hosting Framework + Roles y características de Microsoft Web Hosting. + Hosting Framework + Hosting Framework ofrece comandos de las API y PowerShell para administrar Web Hosting. + Rol web + El rol web instala el servicio WAS dinámico y el proveedor de URL Rewrite para Web Hosting. + Antares Express + Implementa una configuración de Panel de control optimizada para la configuración de un único equipo. + Rol Equilibrador de carga + El rol Equilibrador de carga configura Application Request Router para enrutar en función de las reglas de Web Hosting. + Controlador de hospedaje + El controlador de hospedaje amplía Web Farm Framework 2.0 para que funcione con Web Hosting. + Rol de publicación + Instala el soporte para la publicación FTP y de Web Deploy. + Se trata de un complemento de PowerShell que contiene cmdlets para administrar la infraestructura de Microsoft Web Hosting. + Servicio WAS dinámico + Servicio WAS (Windows Process Activation) optimizado para hospedaje web de alta densidad. + Servicio de medición de recursos + Instala el servicio Medición de recursos que habilita la recopilación y la publicación de información de estado y en tiempo de ejecución. + Medición de recursos + Habilita la recopilación y publicación de información de estado y en tiempo de ejecución del rol web. + Cumplimiento de cuota de hospedaje + Supervisa el uso de recursos de los sitios web y ejecuta acciones personalizadas si se supera la cuota. + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/FRA/misc/setupstrings.wxl b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/FRA/misc/setupstrings.wxl new file mode 100644 index 0000000000..c00688e50c --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/FRA/misc/setupstrings.wxl @@ -0,0 +1,352 @@ + + + + + + + 1036 + + + + Options d'installation pour la configuration partagée + Sélectionnez une option pour l'installation dans une partagée IIS + Mettre à jour la configuration partagée lors de l'installation + Vous installez ce module sur un serveur IIS qui utilise une configuration partagée. Si des serveurs IIS supplémentaires utilisent cette configuration partagée, vous devez installer ce module sur tous ces ordinateurs. Pour réduire le risque d'interruptions sur les différents serveurs Web, installez ce module en respectant les étapes suivantes : premièrement, sur tous les ordinateurs à l'exception du dernier, vous devez installer le module sans mettre à jour la configuration partagée. Pour ce faire, n'activez pas la case à cocher + ci-dessous. Cette opération installe l'ensemble des fichiers et ressources binaires requis pour le module sur chaque ordinateur sans apporter de modifications à la configuration partagée. Deuxièmement, sur le dernier ordinateur, vous devez vérifier que l'identité d'utilisateur que vous utilisez actuellement dispose d'un accès en lecture/écriture au fichier applicationhost.config du partage UNC. Vous devez ensuite installer le module et sélectionner l'option de mise à jour de la configuration partagée ci-dessous. + + + Initialisation de l'action personnalisée WebConfig + Mise à jour de web.config + + + + IIS Advanced Logging + Active la journalisation avancée des données de pipeline IIS. + IIS Advanced Logging + Permet la création de fichiers journaux personnalisés avec une sélection de champ extensible. + Mise à jour pour IIS Advanced Logging + + + + IIS Transform Manager + Bêta + Active IIS Services Multimédia pour Transform Manager. + IIS Transform Manager + Active la création de transformations multimédias. + Hôte IIS Transform Manager + Hôte de service pour [ProductName]. + IIS Transform Manager + Convertir sous forme de lot sur demande les fichiers multimédias en d'autres formats de fichier et de conteneur. + Un package IIS Transform Manager 1.0 Expression Encoder SP Task est installé sur l'ordinateur. Vous devez le désinstaller avant d'installer [ProductName]. + + Microsoft .NET Framework 3.5 est requis pour installer [ProductName]. Utilisez l'Assistant Ajout de fonctionnalités du Gestionnaire de serveur pour installer le composant Fonctionnalités du .NET Framework 3.5.1, ou utilisez l'option Activer ou désactiver des fonctionnalités Windows pour activer Microsoft .NET Framework 3.5. + + + + Gestion des droits numériques (DRM) IIS + Bêta + Active la gestion des droits numériques (DRM) des présentations de diffusion en continu lisse. + + + ASP.NET n'est pas installé + + + + + + + + + Diffusion en continu lisse IIS - Bêta a été détecté sur cet ordinateur. L'installation de [ProductName] ne peut pas continuer. Pour installer ce produit, utilisez Ajouter ou supprimer des programmes dans le Panneau de configuration afin de supprimer Diffusion en continu lisse IIS - Bêta. + Une version incompatible d'IIS Services Multimédia se trouve sur cet ordinateur. L'installation de [ProductName] ne peut pas continuer. Pour installer ce produit, utilisez Ajouter ou supprimer des programme dans le Panneau de configuration afin de supprimer IIS Services Multimédia. + Une version plus récente de ce produit est déjà installée ou disponible à l'installation sur cet ordinateur. L'installation de [ProductName] ne peut pas continuer. Pour installer la version la plus récente de ce produit, utilisez Ajouter ou supprimer des programme dans le Panneau de configuration pour mettre à jour IIS Services Multimédia. + Conversion du fichier de sélections requise + + + + + Anciens fichiers IIS Services Multimédia trouvés + + + + + Fichiers IIS Services Multimédia Bêta trouvés + + + + + + IIS Pack Multimédia 1.0 + Mise à jour pour IIS Pack Multimédia 1.0 + IIS Services Multimédia 2.0 + Mise à jour pour IIS Services Multimédia 2.0 + IIS Services Multimédia 3.0 + IIS Services Multimédia 3.0 TAP 2 + Mise à jour pour IIS Services Multimédia 3.0 + Fonctionnalités et outils IIS Services Multimédia. + Fonctionnalités et outils IIS Media Services 5. + IIS Services Multimédia 4.0 Bêta 1 + IIS Services Multimédia 4.0 + IIS Services Multimédia 4.5 Bêta 1 + IIS Media Services 5 Premium + + Sélections Web + Contrôle la lecture sur le client des fichiers multimédias référencés dans les sélections. + Session Helper + Active la persistance d'état de session ASP.NET. (Requiert le service de rôle ASP.NET pour le serveur Web (IIS)). + Interface utilisateur + Configure la fonctionnalité Sélections Web dans le Gestionnaire des services Internet. + + Bit Rate Throttling + Économise la bande passante en limitant la remise de fichiers téléchargés par les clients. + Interface utilisateur + Configure la fonctionnalité Bit Rate Throttling dans le Gestionnaire des services Internet. + + Éléments + Active la diffusion adaptive en continu HTTP d’éléments à la demande sur les clients. + Interface utilisateur + Configure la fonctionnalité de diffusion en continu lisse dans le Gestionnaire des services Internet. + + Canaux + Active la diffusion adaptive en continu HTTP de canaux sur les clients. + Interface utilisateur + Configure la fonctionnalité Live Smooth Streaming dans le Gestionnaire des services Internet. + + Gestion des droits numériques (DRM) + Fournit le chiffrement et la licence des médias de diffusion en continu lisse. + Interface utilisateur + Configure la fonctionnalité Gestion des droits numériques (DRM) dans le Gestionnaire des services Internet. + + [ProductName] requiert Microsoft Windows Vista Service Pack 1 ou version ultérieure. + [ProductName] ne peut pas être installé sur Vista Édition Familiale Basique. + [ProductName] requiert Microsoft Windows 7 Service Pack 1 ou version ultérieure. + + + Gestionnaire de bases de données IIS + Gestionnaire de bases de données IIS + + + Service de gestion Web Microsoft 2 + Service de gestion Web Microsoft + Installe les fonctionnalités de base de [ProductName]. + Service de gestion Web Microsoft 2 + Le service de gestion Web offre des fonctionnalités de gestion déléguée et à distance permettant aux administrateurs de gérer le serveur Web, les sites et les applications présents sur cet ordinateur. + + + Module de réécriture d'URL 1.1 Microsoft pour IIS 7 + Mise à jour pour le Module de réécriture d'URL 1.1 pour IIS 7 + Réécriture d'URL + Active des fonctionnalités de réécriture d'URL et de contenu pour IIS 7. + Interface utilisateur + Configure la fonctionnalité Module de réécriture d'URL dans le Gestionnaire des services Internet. + + + Module de réécriture d'URL 2 d'IIS + Mise à jour pour le Module de réécriture d'URL 2 d'IIS + Réécriture d'URL + Active des fonctionnalités de réécriture d'URL et de contenu pour IIS 7. + Interface utilisateur + Configure la fonctionnalité Module de réécriture d'URL dans le Gestionnaire des services Internet. + + + Pack d'administration IIS 7.0 + Installe les fonctionnalités de base de [ProductName]. + 1252 + Pack d'administration IIS 7.0 + Microsoft Corporation + Cette version du système d'exploitation n'est pas prise en charge. [ProductName] ne peut être installé que sur Windows Server 2008 ou Windows Vista Service Pack 1 et versions ultérieures. + Fonctionnalités ASP.Net + ASP.NET comprend les fonctionnalités d'autorisation et de pages d'erreurs, qui vous permettent de gérer les paramètres d'autorisations et d'erreurs personnalisées. + Authentification + Description de l'authentification ASP.Net. + Autorisation + L'autorisation ASP.NET vous permet de configurer des règles pour autoriser les utilisateurs à accéder à vos applications et sites Web. + Pages d'erreurs + Les pages d'erreurs ASP.NET vous permettent de configurer les réponses d'erreurs HTTP à retourner lorsque des erreurs se produisent. + Modules + Description des modules ASP.Net. + Gestionnaires + Description des gestionnaires ASP.Net. + Éditeur de configuration + L'éditeur de configuration vous permet de gérer vos fichiers de configuration dans le Gestionnaire des services Internet en vous permettant de modifier des sections, des attributs, des éléments et des collections dans vos fichiers de configuration. + Filtrage des demandes + Le filtrage des demandes vous permet de configurer les règles de filtrage pour votre site Web et de limiter le comportement du protocole et du contenu. + FastCGI + FastCGI vous permet de configurer les paramètres du pool de processus pour les applications FastCGI sur votre serveur Web. + + + Programme d'installation de Restrictions dynamiques d'adresse IP pour IIS 7 + + + + + + + + + + + + + Restrictions dynamiques d'adresse IP pour IIS 7 - Bêta + Restrictions dynamiques d'adresse IP pour IIS 7 - Bêta 2 + Restrictions dynamiques d'adresse IP pour IIS 7 - Bêta 3 + + Restrictions dynamiques d'adresse IP pour IIS 7 - version finale (RC) + Restrictions dynamiques d'adresse IP pour IIS 7 - version finale (RC) 2 + Restrictions dynamiques d'adresse IP pour IIS 7 - version finale (RC) 3 + + Restrictions dynamiques d'adresse IP pour IIS 7 - RTW + + Restrictions dynamiques d'adresse IP pour IIS 7 + Interface utilisateur de Restrictions dynamiques d'adresse IP pour IIS 7 + + Restrictions d'adressage IP dynamique pour IIS 7 - Une version bêta a été détectée sur cet ordinateur. Désinstallez-la, puis réessayez + + + WebDAV 7.5 pour IIS 7.0 + Les fonctionnalités IIS 7.0 CoreWebEngine et W3SVC doivent être installées pour utiliser ce produit. + Module serveur WebDAV + Interface utilisateur de l'administration WebDAV + + + Kit de ressources d'optimisation du référencement d'un site auprès d'un moteur de recherche IIS 1.0 + Kit de ressources d'optimisation du référencement d'un site auprès d'un moteur de recherche IIS 1.0 + Kit de ressources d'optimisation du référencement d'un site auprès d'un moteur de recherche (SEO) 1.0 + La base de données de ce programme d'installation contient la logique et les données requises pour installer le Kit de ressources d'optimisation du référencement d'un site auprès d'un moteur de recherche IIS 1.0. + + + Éditeur IIS + + + Rapports IIS + Log Parser n'est pas installé sur cet ordinateur. Installez Log Parser 2.2 à partir de http://www.microsoft.com/downloads/details.aspx?FamilyID=890cd06b-abf8-4c25-91b2-f8d975cf8c07, puis installez les rapports IIS + + + Les packages de composants requis sont introuvables. Exécutez setup.exe pour résoudre les dépendances et installer ce programme. + Microsoft SQL Server 2008 Management Objects doit être installé avant l'installation du Gestionnaire de bases de données IIS. Vous pouvez installer Microsoft SQL Server 2008 Management Objects à partir de http://go.microsoft.com/fwlink/?LinkID=150946 . + Microsoft SQL Server System CLR Types doit être installé avant l'installation du Gestionnaire de bases de données IIS. Vous pouvez installer Microsoft SQL Server System CLR Types à partir de http://go.microsoft.com/fwlink/?LinkID=150949. + + + Microsoft Web Farm Framework + Microsoft External Cache + Web Farm Framework est un composant requis pour l'installation d'Application Request Routing. Installez Web Farm Framework. + Microsoft Application Request Routing 2.5 + Exécution + Ajoute les fonctionnalités d'Application Request Routing à IIS. + Interface utilisateur + Configure la fonctionnalité Application Request Routing dans le Gestionnaire des services Internet. + + + Composant logiciel enfichable Microsoft Windows PowerShell pour IIS 7.0 + + + Microsoft Web Platform Installer 4.0 + + Microsoft Web Platform Installer + [ProductName] requiert Windows XP SP2, Windows 2003 SP1, Windows Vista ou versions ultérieures. + [ProductName] requiert Windows XP Service Pack 3, Windows Server 2003 Service Pack 2 ou versions ultérieures. + + + Programme d'installation des services Microsoft Windows Azure + Programme d'installation des services Microsoft Windows Azure + + + Gestionnaire des services Internet (IIS) 7+ + Client du Gestionnaire des services Internet + Support à distance + Ce produit requiert Windows XP SP2, Windows 2003 SP1, Windows Vista SP1, Windows 7 ou une version supérieure + La console de gestion IIS n'est pas installée, mais est requise pour gérer les serveurs IIS distants. Installez la console de gestion IIS avant d'installer le support de gestion à distance en ouvrant 'Panneau de configuration->Programmes->Activer ou désactiver des fonctionnalités Windows' et en sélectionnant la console de gestion IIS dans la fonctionnalité Services Internet. + Ce produit n'est pas requis dans Windows Server 2008 ou Windows Server 2008 R2 ou une version ultérieure. Installez la console de gestion IIS en ouvrant le Gestionnaire de serveur et en sélectionnant la console de gestion IIS dans les services de rôle pour le rôle Serveur Web. + + + Gestionnaire de publication pour IIS 7.0 + Interface utilisateur de publication + + + Application Warm-Up 1.0 pour IIS 7.5 + + + + Un produit incompatible, [CONFLICTING_PRODUCT_NAME], se trouve sur cet ordinateur. Impossible de poursuivre l'installation de [ProductName]. Pour installer ce produit, utilisez Ajouter/Supprimer les programmes dans le Panneau de configuration pour supprimer [CONFLICTING_PRODUCT_NAME]. + Des privilèges administrateur sont requis pour installer [ProductName]. + IIS version 7.0 est requis pour utiliser [ProductName]. + IIS version 7.0 ou supérieure est requis pour installer [ProductName]. + IIS version 7.5 ou supérieure est requis pour installer [ProductName]. + IIS version 7 ou 7.5 est requis pour installer [ProductName]. + La version bêta de [ProductName] est installée sur cet ordinateur. + Une version plus récente de [ProductName] est installée sur cet ordinateur. + Le programme d'installation ne peut pas continuer car une autre instance de [ProductName] est déjà installée sur cet ordinateur. Désinstallez-la, puis relancez l'installation. + Les fonctionnalités IIS 7.0 CoreWebEngine et W3SVC doivent être installées pour utiliser [ProductName]. + Les fonctionnalités de la console de gestion IIS doivent être installées pour utiliser [ProductName]. + Arrêtez les services d'activation des processus Windows (WAS) et de gestion Web (WMSvc) avant d'installer [ProductName]. Vous devrez redémarrer les services après avoir installé [ProductName]. + La métabase IIS est requise pour installer [ProductName]. + La version 64 bits de [ProductName] ne peut pas être installée sur une édition 32 bits de Microsoft Windows. + La version 32 bits de [ProductName] ne peut pas être installée sur une édition 64 bits de Microsoft Windows. + Microsoft .NET Framework version 2.0 ou supérieure est requise pour installer [ProductName]. + Microsoft .NET Framework version 3.5 ou supérieure est requis pour installer [ProductName]. Utilisez l'option d'ajout de fonctionnalités du Gestionnaire de serveur pour installer Microsoft .NET Framework version 3.5. + Microsoft .NET Framework version 4.0 ou supérieure est requis pour installer [ProductName]. + Installez Microsoft .NET Framework version 2.0 Service Pack 1 (ou SP supérieur), avant d'installer [ProductName]. + Le service Windows Update (wuauserv) ne peut pas être désactivé, il est requis pour installer [ProductName]. + Le composant logiciel enfichable PowerShell fait partie du système d'exploitation Windows. Installez-le via 'Programmes et fonctionnalités' ou 'Gestionnaire de serveur'. + Microsoft Web Platform Installer version 3.0 ou supérieure est requis pour installer [ProductName]. + + Le programme d'installation n'a pas réussi à détecter la configuration partagée. + La configuration partagée est activée pour IIS. L'installation de [ProductName] n'est pas prise en charge lors de l'utilisation d'une configuration partagée. Désactivez la configuration partagée avant d'installer cette fonctionnalité. + + Arrêtez le service de publication World Wide Web (W3SVC) avant d'installer [ProductName]. Vous devrez le redémarrer après l'installation. + Console de gestion PowerShell IIS + Composant logiciel enfichable PowerShell IIS + Le composant logiciel enfichable PowerShell IIS requiert PowerShell v1.0 ou v2.0 + Le composant logiciel enfichable PowerShell IIS requiert WAS et une configuration + Chaîne d'exemple. + + + Microsoft Web Farm Framework Version 2.2 + Microsoft Web Farm Agent Version 2.2 + Service de batterie de serveurs Web + Service de batterie de serveurs Web + Service du contrôleur de batterie de serveurs Web + Service du contrôleur de batterie de serveurs Web + Service de l'agent de batterie de serveurs Web + Service de l'agent de batterie de serveurs Web + Web Platform Installer est un composant requis pour l'installation de Web Farm Framework 2.0. Installez Web Platform Installer à partir de http://www.microsoft.com/web/downloads/platform.aspx. + L'Outil de déploiement Web est un composant requis pour l'installation de Web Farm Framework. Installez l'Outil de déploiement Web à partir de http://www.iis.net/download/WebDeploy. + + + Microsoft Web Hosting Framework + Web Hosting Framework + Rôles et fonctionnalités de l'hébergement Web. + Hosting Framework + Hosting Framework fournit les commandes des API et de PowerShell pour la gestion de l'hébergement Web. + Rôle Web + Le rôle Web installe le service dynamique WAS et le fournisseur de réécriture d'URL pour l'hébergement Web. + Antares Express + Déploie une configuration du Panneau de configuration optimisée pour l'installation sur un seul ordinateur. + Rôle de l'équilibrage de charge + Le rôle de l'équilibrage de charge configure le routeur des requêtes d'applications pour diriger les règles d'hébergement Web. + Contrôleur d'hébergement + Le contrôleur d'hébergement étend Web Farm Framework 2.0 pour être utilisé avec l'hébergement Web. + Rôle de publication + Installe le support pour le déploiement Web et la publication FTP. + Il s'agit d'un composant logiciel enfichable PowerShell qui contient des applets de commande pour gérer l'infrastructure Microsoft Web Hosting. + Service WAS dynamique + Service d'activation de processus Windows optimisé pour l'hébergement Web grande densité. + Service Contrôle des ressources + Installe le service Contrôle des ressources qui permet de collecter et de publier des informations d'exécution et d'intégration. + Contrôle des ressources + Active la collecte et la publication des informations sur l'exécution et l'intégration à partir du rôle Web. + Hébergement de l'application des quotas + Surveille l'utilisation des ressources des sites Web et exécute des actions personnalisées lorsque le quota d'utilisation est dépassé. + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/ITA/misc/setupstrings.wxl b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/ITA/misc/setupstrings.wxl new file mode 100644 index 0000000000..238a9292f9 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/ITA/misc/setupstrings.wxl @@ -0,0 +1,351 @@ + + + + + + + 1040 + + + + Opzioni di installazione configurazione condivisa + Selezionare un'opzione per l'installazione nella configurazione condivisa di IIS + Aggiorna configurazione condivisa al momento dell'installazione + Questo modulo verrà installato su un server IIS che utilizza una configurazione condivisa. Se altri server IIS utilizzano la medesima configurazione condivisa, sarà necessario installare il modulo in ciascuno di essi. Per ridurre al minimo l'interruzione dei servizi dei singoli server Web, sarà necessario installare il modulo attenendosi alla procedura seguente: in tutti i computer tranne l'ultimo installare il modulo senza aggiornare la configurazione condivisa. A tale scopo, non selezionare la casella di controllo sotto. +In questo modo, verranno installati tutti i dati binari e i file necessari per il modulo in ogni computer senza apportare modifiche alla configurazione condivisa. A questo punto, nell'ultimo computer sarà necessario verificare che l'identità dell'utente in uso disponga di accesso in lettura e scrittura al file applicationhost.config nella condivisione UNC. Installare quindi il modulo e selezionare l'opzione di configurazione aggiornata sotto. + + + Inizializzazione dell'azione personalizzata WebConfig + Aggiornamento di web.config + + + + Registrazione avanzata IIS + Consente la registrazione avanzata dei della pipeline IIS. + Registrazione avanzata IIS + Consente la creazione di file di registro personalizzati con selezione campi estendibile. + Aggiornamento per IIS Advanced Logging + + + + IIS Transform Manager + Beta + Abilita IIS Media Services di Transform Manager. + IIS Transform Manager + Abilita la creazione di trasformazioni multimediali. + Host di IIS Transform Manager + Host del servizio per [ProductName]. + IIS Transform Manager + Esegue la conversione batch dei file multimediali su richiesta per alternare formati di file e contenitori. + Nel computer è installato un pacchetto IIS Transform Manager 1.0 Expression Encoder SP Task. È necessario disinstallarlo prima di eseguire l'installazione di [ProductName]. + + Per installare [ProductName] è necessario Microsoft .NET Framework 3.5. Utilizzare 'Aggiunta guidata funzionalità' in Server Manager per installare Funzionalità di .NET Framework 3.5.1 oppure utilizzare 'Attiva o disattiva le funzionalità Windows' per attivare Microsoft .NET Framework 3.5. + + + + IIS Digital Rights Management + Beta + Abilita Digital Rights Management di presentazioni Smooth Streaming. + + + ASP.NET non installato + + + + + + + + + IIS Smooth Streaming - Beta rilevato in questo computer. Impossibile continuare l'installazione di [ProductName]. Per installare il prodotto, utilizzare Installazione applicazioni nel Pannello di controllo per rimuovere IIS Smooth Streaming - Beta. + Una versione non compatibile di IIS Media Services è stata rilevata in questo computer. Impossibile continuare l'installazione di [ProductName]. Per installare il prodotto, utilizzare Installazione applicazioni nel Pannello di controllo per rimuovere IIS Media Services. + Nel computer in uso è già installata o disponibile per l'installazione una versione più recente del prodotto. Impossibile continuare l'installazione di [ProductName]. Per installare la versione più recente del prodotto, utilizzare Installazione applicazioni nel Pannello di controllo per aggiornare IIS Media Services. + Conversione file elenco di riproduzione obbligatoria + + + + + Rilevati file di una versione precedente di IIS Media Services + + + + + Rilevati file di una versione beta di IIS Media Services + + + + + + IIS Media Pack 1.0 + Aggiornamento per IIS Media Pack 1.0 + IIS Media Services 2.0 + Aggiornamento per IIS Media Services 2.0 + IIS Media Services 3.0 + IIS Media Services 3.0 TAP 2 + Aggiornamento per IIS Media Services 3.0 + Funzionalità e strumenti di IIS Media Services. + Funzionalità e strumenti di IIS Media Services 5 Premium. + IIS Media Services 4.0 Beta 1 + IIS Media Services 4.0 + IIS Media Services 4.5 Beta 1 + IIS Media Services 5 Premium + + Web Playlists + Controlla la riproduzione del client di asset di file multimediali a cui si fa riferimento negli elenchi di riproduzione. + Session Helper + Consente la persistenza dello stato della sessione ASP.NET. Richiede il servizio ruolo ASP.NET per Server Web (IIS). + Interfaccia utente + Configura la funzionalità Web Playlists in Gestione IIS. + + Bit Rate Throttling + Riduce la larghezza di banda necessaria limitando il recapito dei file scaricati dai client. + Interfaccia utente + Configura la funzionalità Bit Rate Throttling in Gestione IIS. + + Asset + Consente il flusso adattivo HTTP degli asset su richiesta nei client. + Interfaccia utente + Configura la funzionalità Smooth Streaming in Gestione IIS. + + Canali + Consente il flusso adattivo HTTP delle trasmissioni di canale ai client. + Interfaccia utente + Configura la funzionalità Live Smooth Streaming in Gestione IIS. + + Digital Rights Management + Fornisce crittografia e licenze dei file multimediali Smooth Streaming. + Interfaccia utente + Configura la funzionalità Digital Rights Management in Gestione IIS. + + [ProductName] richiede Microsoft Windows Vista Service Pack 1 o versione successiva. + Impossibile installare [ProductName] in Vista Home Basic. + [ProductName] richiede Microsoft Windows 7 Service Pack 1 o versione successiva. + + + IIS Database Manager + IIS Database Manager + + + Servizio Gestione Web Microsoft 2 + Servizio Gestione Web Microsoft + Installa le funzionalità di base di [ProductName]. + Servizio Gestione Web Microsoft 2 + Il servizio Gestione Web offre agli amministratori funzionalità di gestione remota e delegata per il server Web, i siti e le applicazioni presenti nel computer. + + + Microsoft URL Rewrite Module 1.1 per IIS 7 + Aggiornamento per URL Rewrite Module 1.1 per IIS 7 + URL Rewrite + Abilita le funzionalità di riscrittura del contenuto e degli URL in IIS 7. + Interfaccia utente + Configura la funzionalità URL Rewrite Module in Gestione IIS. + + + IIS URL Rewrite Module 2 + Aggiornamento per IIS URL Rewrite Module 2 + URL Rewrite + Abilita le funzionalità di riscrittura del contenuto e degli URL in IIS 7. + Interfaccia utente + Configura la funzionalità URL Rewrite Module in Gestione IIS. + + + Administration Pack per IIS 7.0 + Installa le funzionalità di base di [ProductName]. + 1252 + Administration Pack per IIS 7.0 + Microsoft Corporation + Questa versione del sistema operativo non è supportata. [ProductName] può essere installato solo con Windows Server 2008 o Windows Vista Service Pack 1 e versioni successive. + Funzionalità ASP.Net + ASP.NET include le funzionalità Pagine errori e autorizzazione, che consentono di gestire le impostazioni di errori personalizzati e di autorizzazione. + Autenticazione + Descrizione dell'autenticazione ASP.Net. + Autorizzazione + L'autorizzazione ASP.NET consente di configurare le regole per autorizzare gli utenti ad accedere a siti Web e applicazioni. + Pagine errori + Le pagine errori ASP.NET consentono di configurare le risposte di errore HTTP da restituire in caso di errori. + Moduli + Descrizione dei moduli ASP.Net. + Gestori + Descrizione dei gestori ASP.Net. + Editor di configurazione + Editor di configurazione consente di gestire i file di configurazione in Gestione IIS offrendo la possibilità di modificare sezioni, attributi, elementi e raccolte all'interno dei file di configurazione. + Filtro richieste + Filtro richieste consente di configurare le regole di filtro per il sito Web e di limitare il comportamento di protocollo e contenuto. + FastCGI + FastCGI consente di configurare le impostazioni del pool di processi per le applicazioni FastCGI del server Web. + + + Restrizioni IP dinamico per l'installazione di IIS 7 + + + + + + + + + + + + + Restrizioni IP dinamico per IIS 7 - Beta + Restrizioni IP dinamico per IIS 7 - Beta 2 + Restrizioni IP dinamico per IIS 7 - Beta 3 + + Restrizioni IP dinamico per IIS 7 - Versione finale candidata + Restrizioni IP dinamico per IIS 7 - Versione finale candidata 2 + Restrizioni IP dinamico per IIS 7 - Versione finale candidata 3 + + Restrizioni IP dinamico per IIS 7 - RTW + + Restrizioni IP dinamico per IIS 7 + Interfaccia utente di Restrizioni IP dinamico per IIS 7 + + Restrizioni IP dinamico per IIS 7 - Beta rilevato nel computer. Disinstallarlo, quindi riprovare + + + WebDAV 7.5 per IIS 7.0 + Per utilizzare questo prodotto, è necessario installare le funzionalità CoreWebEngine e W3SVC di IIS 7.0. + Modulo server WebDAV + Interfaccia utente di amministrazione WebDAV + + + IIS Search Engine Optimization Toolkit 1.0 + IIS Search Engine Optimization Toolkit 1.0 + Search Engine Optimization (SEO) Toolkit 1.0 + Il database del programma di installazione contiene la logica e i dati necessari per l'installazione di IIS Search Engine Optimization Toolkit 1.0. + + + Editor IIS + + + Report IIS + Log Parser non installato nel computer in uso. Installare Log Parser 2.2 dal sito Web http://www.microsoft.com/downloads/details.aspx?FamilyID=890cd06b-abf8-4c25-91b2-f8d975cf8c07, quindi continuare con l'installazione di Report IIS. + + + Pacchetti dei prerequisiti non trovati. Eseguire setup.exe per risolvere le dipendenze e installare il programma. + Microsoft SQL Server 2008 Management Objects è un prerequisito per l'installazione di IIS Database Manager. È possibile installare Microsoft SQL Server 2008 Management Objects dal sito http://go.microsoft.com/fwlink/?LinkID=150946. + Microsoft SQL Server System CLR Types è un prerequisito per l'installazione di IIS Database Manager. È possibile installare Microsoft SQL Server System CLR Types dal sito http://go.microsoft.com/fwlink/?LinkID=150949. + + + Microsoft Web Farm Framework + Microsoft External Cache + Web Farm Framework è un requisito per l'installazione di Application Request Routing. Installare Web Farm Framework. + Microsoft Application Request Routing 2.5 + Runtime + Aggiunge le funzionalità di Application Request Routing a IIS. + Interfaccia utente + Configura la funzionalità Application Request Routing in Gestione IIS. + + + Snap-in di Microsoft Windows PowerShell per IIS 7.0 + + + Installazione guidata piattaforma Web Microsoft 4.0 + Installazione guidata piattaforma Web Microsoft + [ProductName] richiede Windows XP SP2, Windows 2003 SP1, Windows Vista o versione successiva. + [ProductName] richiede Windows XP Service Pack 3, Windows Server 2003 Service Pack 2 o versione successiva. + + + Programma di installazione servizi Microsoft Windows Azure + Programma di installazione servizi Microsoft Windows Azure + + + Gestione Internet Information Services (IIS) 7+ + Client Gestione IIS + Remoting Support + Per questo prodotto è necessario Windows XP SP2, Windows 2003 SP1, Windows Vista SP1, Windows 7 o versione successiva + La Console di gestione IIS necessaria per la gestione dei server IIS remoti non è installata. Installare la Console di gestione IIS prima di installare il supporto di gestione remoto. A tale scopo, aprire "Pannello di controllo->Programmi->Attiva o disattiva le funzionalità Windows" e selezionare Console di gestione IIS nella funzionalità Internet Information Services. + Questo prodotto non è necessario in Windows Server 2008 o in Windows Server 2008 R2 o versione successiva. Per installare la Console di gestione IIS, aprire Gestione server e selezionare la Console di gestione IIS nei Servizi ruolo per il ruolo Server Web. + + + IIS Manager Publishing per IIS 7.0 + Interfaccia utente di pubblicazione + + + Application Warm-Up 1.0 per IIS 7.5 + + + + Nel computer è installato un prodotto incompatibile, [CONFLICTING_PRODUCT_NAME]. Non è possibile continuare l'installazione di [ProductName]. Per installare il prodotto, utilizzare Installazione applicazioni nel Pannello di controllo e rimuovere [CONFLICTING_PRODUCT_NAME]. + Per installare [ProductName], sono richiesti i privilegi di amministratore. + Per utilizzare [ProductName], è richiesto IIS versione 7.0. + Per installare [ProductName], è richiesto IIS versione 7.0 o versione successiva. + Per installare [ProductName] è necessario IIS 7.5 o versione successiva. + Per installare [ProductName] è necessario IIS versione 7 o 7.5. + Versione beta di [ProductName] rilevata nel computer in uso. + Nel computer in uso è stata rilevata una versione più recente di [ProductName]. + L'installazione non può continuare poiché un'altra istanza di [ProductName] è già installata nel computer in uso. Disinstallarla e quindi riavviare l'installazione. + Per utilizzare [ProductName], è necessario installare le funzionalità CoreWebEngine e W3SVC di IIS 7.0. + Per utilizzare [ProductName], è necessario installare la Console di gestione IIS. + Arrestare Servizio Attivazione processo Windows (WAS) e Servizio di gestione Web (WMSvc) prima di installare [ProductName]. Avviare i servizi dopo l'installazione di [ProductName]. + Per installare [ProductName], è richiesta la metabase IIS. + Impossibile installare la versione a 64 bit di [ProductName] in un'edizione a 32 bit di Microsoft Windows. + Impossibile installare la versione a 32 bit di [ProductName] in un'edizione a 64 bit di Microsoft Windows. + Per installare [ProductName], è richiesto Microsoft .NET Framework versione 2.0 o versione successiva. + Microsoft .NET Framework versione 3.5 o successiva necessario per installare [ProductName]. Utilizzare 'Aggiungi funzionalità' in Server Manager per installare Microsoft .NET versione 3.5. + Microsoft .NET Framework versione 4.0 o successiva necessario per installare [ProductName]. + Prima di installare [ProductName], installare Microsoft .NET Framework versione 2.0 Service Pack 1 o versione successiva. + Impossibile disabilitare il servizio Windows Update (wuauserv). È richiesto per installare [ProductName]. + Lo snap-in di PowerShell fa parte del sistema operativo Windows. Installarlo mediante 'Programmi e funzionalità' o 'Server Manager'. + Installazione guidata piattaforma Web di Microsoft versione 3.0 o successiva necessaria per installare [ProductName]. + + Impossibile rilevare la configurazione condivisa. + Configurazione condivisa abilitata per IIS. L'installazione di [ProductName] non è supportata quando si utilizza la configurazione condivisa. Disabilitare la configurazione condivisa prima di installare questa funzionalità. + + Arrestare il Servizio Pubblicazione sul Web (W3SVC) prima di installare [ProductName]. Avviare il servizio dopo l'installazione. + Console di gestione IIS PowerShell + Snap-in di IIS PowerShell + Lo snap-in di IIS PowerShell richiede l'installazione di PowerShell v1.0 o v2.0 + Lo snap-in di IIS PowerShell richiede l'installazione di WAS e della configurazione + Stringa non valida. + + + Microsoft Web Farm Framework versione 2.2 + Microsoft Web Farm Agent versione 2.2 + Servizio Web Farm + Servizio Web Farm + Servizio controller Web Farm + Servizio controller Web Farm + Servizio agente Web Farm + Servizio agente Web Farm + L'Installazione guidata piattaforma Web è un prerequisito per l'installazione di Web Farm Framework. Eseguire l'Installazione guidata piattaforma Web dall'indirizzo http://www.microsoft.com/web/downloads/platform.aspx. + Lo Strumento di distribuzione Web è un prerequisito per l'installazione di Web Farm Framework. Installare lo Strumento di distribuzione Web dall'indirizzo http://www.iis.net/download/WebDeploy. + + + Microsoft Web Hosting Framework + Web Hosting Framework + Ruoli e funzionalità di Web Hosting. + Framework di hosting + Framework di hosting fornisce le API e i comandi PowerShell per la gestione di Web Hosting. + Ruolo Web + Ruolo Web esegue l'installazione del Servizio Attivazione processo Windows dinamico e del provider di URL Rewrite per Web Hosting. + Antares Express + Esegue la distribuzione di una configurazione del Pannello di controllo ottimizzata per l'installazione su singolo computer. + Ruolo bilanciamento del carico + Ruolo bilanciamento del carico configura Application Request Router per il routing in base alle regole di Web Hosting. + Controller di hosting + Controller di hosting estende Web Farm Framework 2.0 per consentirne il funzionamento con Web Hosting. + Ruolo di pubblicazione + Installa il supporto per la pubblicazione mediante Distribuzione Web e FTP. + Lo snap-in di PowerShell contiene i cmdlet per gestire l'infrastruttura Microsoft Web Hosting. + Servizio Attivazione processo Windows dinamico + Servizio Attivazione processo Windows dinamico ottimizzato per Web Hosting ad alta densità. + Servizio Misurazione risorse + Installa il servizio Misurazione risorse che abilita la raccolta e la pubblicazione delle informazioni sul runtime e sull'integrità. + Misurazione risorse + Abilita la raccolta e la pubblicazione delle informazioni sul runtime e sull'integrità da parte di Ruolo Web. + Imposizione quota hosting + Esegue il monitoraggio dell'utilizzo delle risorse dei siti Web ed esegue azioni personalizzate quando la quota relativa all'utilizzo viene superata. + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/JPN/misc/setupstrings.wxl b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/JPN/misc/setupstrings.wxl new file mode 100644 index 0000000000..ac70825d59 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/JPN/misc/setupstrings.wxl @@ -0,0 +1,351 @@ + + + + + + + 1041 + + + + 共有構成のインストール オプション + IIS 共有構成をインストールするためのオプションを選択します + インストール時に共有構成を更新する + 共有構成を使用する IIS サーバーに、このモジュールをインストールしようとしています。その他の IIS サーバーでこの共有構成を使用している場合は、これらすべてのコンピューターにこのモジュールをインストールする必要があります。個々の Web サーバーの障害を最小限に抑えるには、以下の手順でこのモジュールをインストールします。まず、最後の 1 台を除くすべてのコンピューターに、共有構成を更新せずにモジュールをインストールします。そのためには、下のチェック ボックスをオフにします。 +これにより、共有構成に変更を加えることなく、各コンピューターでモジュールに必要なバイナリとファイルがすべてインストールされます。次に、最後のコンピューターで、実行に使用しているユーザー ID が、UNC 共有にある applicationhost.config ファイルに対する読み取りと書き込みのアクセス権を持っていることを確認します。そのうえで、モジュールをインストールし、下にある [インストール時に共有構成を更新する] チェック ボックスをオンにします。 + + + WebConfig カスタム アクションを初期化しています + web.config を更新しています + + + + IIS 詳細ログ + IIS パイプライン データの詳細ログを有効にします。 + IIS 詳細ログ + 拡張可能なフィールド選択機能を備えたカスタム ログ ファイルの作成を有効にします。 + IIS 詳細ログの更新 + + + + IIS Transform Manager + Beta + Transform Manager の IIS Media Services を有効にします。 + IIS Transform Manager + メディア変換の作成を有効にします。 + IIS Transform Manager ホスト + [ProductName] 用のサービス ホスト。 + IIS Transform Manager + オンデマンド メディア ファイルを代替ファイルおよびコンテナー形式にバッチで変換します。 + IIS Transform Manager 1.0 Expression Encoder SP Task パッケージがコンピューターにインストールされています。[ProductName] をインストールする前にそのパッケージをアンインストールする必要があります。 + + [ProductName] をインストールするには、Microsoft .NET Framework 3.5 が必要です。サーバー マネージャーの機能の追加ウィザードを使用して .NET Framework 3.5.1 の各機能をインストールするか、[Windows の機能の有効化または無効化] を使用して Microsoft .NET Framework 3.5 を有効にします。 + + + + IIS デジタル著作権管理 + Beta + Smooth Streaming プレゼンテーションのデジタル著作権管理を有効にします。 + + + ASP.NET がインストールされていません + + + + + + + + + このコンピューターで、IIS Smooth Streaming - Beta が見つかりました。[ProductName] のインストールを続行できません。この製品をインストールするには、コントロール パネルの [プログラムの追加と削除] を使用して、IIS Smooth Streaming - Beta をアンインストールしてください。 + このコンピューターには、互換性のないバージョンの IIS Media Services が存在します。[ProductName] のインストールを続行できません。この製品をインストールするには、コントロール パネルの [プログラムの追加と削除] を使用して、IIS Media Services をアンインストールしてください。 + このコンピューターには、この製品の新しいバージョンが既にインストールされているか、新しいバージョンを入手してインストールすることができます。[ProductName] のインストールを続行できません。この製品のより新しいバージョンをインストールするには、コントロール パネルの [プログラムの追加と削除] を使用して、IIS Media Services を更新してください。 + プレイリスト ファイルの変換が必要 + + + + + 古い IIS Media Services ファイルが見つかりました + + + + + ベータ版の IIS Media Services ファイルが見つかりました + + + + + + IIS Media Pack 1.0 + IIS Media Pack 1.0 の更新 + IIS Media Services 2.0 + IIS Media Services 2.0 の更新 + IIS Media Services 3.0 + IIS Media Services 3.0 TAP 2 + IIS Media Services 3.0 の更新 + IIS Media Services の機能とツール。 + IIS Media Services 5 Premium の機能およびツール。 + IIS Media Services 4.0 Beta 1 + IIS Media Services 4.0 + IIS Media Services 4.5 Beta 1 + IIS Media Services 5 Premium + + Web プレイリスト + プレイリストで参照されたメディア アセットに対するクライアントの再生を制御します。 + セッション ヘルパー + ASP.NET セッション状態保持を有効にします (Web サーバー (IIS) の ASP.NET 役割サービスが必要)。 + ユーザー インターフェイス + IIS マネージャーで Web プレイリスト機能を構成します。 + + ビット レート調整 + クライアントによってダウンロードされるファイルの配信を制限することによって帯域幅を節約します。 + ユーザー インターフェイス + IIS マネージャーでビット レート調整機能を構成します。 + + アセット + クライアントに対し、オンデマンド アセットの HTTP アダプティブ ストリーミングを有効にします。 + ユーザー インターフェイス + IIS マネージャーで Smooth Streaming 機能を構成します。 + + チャネル + クライアントに対し、チャネル ブロードキャストの HTTP アダプティブ ストリーミングを有効にします。 + ユーザー インターフェイス + IIS Manager で Live Smooth Streaming 機能を構成します。 + + デジタル著作権管理 + Smooth Streaming メディアの暗号化とライセンスを提供します。 + ユーザー インターフェイス + IIS マネージャーでデジタル著作権管理機能を構成します。 + + [ProductName] には Microsoft Windows Vista Service Pack 1 以降が必要です。 + [ProductName] を Vista Home Basic にインストールすることはできません。 + [ProductName] には Microsoft Windows 7 Service Pack 1 以降が必要です。 + + + IIS Database Manager + IIS Database Manager + + + Microsoft Web Management Service 2 + Microsoft Web Management Service + [ProductName] の基本的な機能をインストールします。 + Microsoft Web Management Service 2 + Web 管理サービスでは、管理者がこのコンピューターの Web サーバー、サイトおよびアプリケーションを管理する機能をリモートで操作したり、委任したりすることができます。 + + + Microsoft URL Rewrite Module 1.1 for IIS 7 + URL Rewrite Module 2 for IIS 7 の更新 + URL 書き換え + IIS 7 への URL およびコンテンツの書き換え機能を有効にします。 + ユーザー インターフェイス + URL 書き換えモジュール機能を IIS マネージャーで構成します。 + + + IIS URL Rewrite Module 2 + IIS URL Rewrite Module 2 の更新プログラム + URL 書き換え + IIS 7 への URL およびコンテンツの書き換え機能を有効にします。 + ユーザー インターフェイス + URL 書き換えモジュール機能を IIS マネージャーで構成します。 + + + Administration Pack for IIS 7.0 + [ProductName] の基本的な機能をインストールします。 + 1252 + Administration Pack for IIS 7.0 + Microsoft Corporation + このバージョンのオペレーティング システムはサポートされません。[ProductName] は、Windows Server 2008 か、または Windows Vista Service Pack 1 以降にのみインストールできます。 + ASP.Net の機能 + ASP.NET には、承認とエラー ページの機能があり、それを使って承認やカスタム エラーの設定を管理できます。 + 認証 + ASP.Net 認証の説明。 + 承認 + ASP.NET の承認では、Web サイトおよびアプリケーションへのユーザーのアクセスを承認するための規則を構成できます。 + エラー ページ + ASP.NET エラー ページでは、エラー発生時に返す HTTP エラー応答を構成できます。 + モジュール + ASP.Net モジュールの説明。 + ハンドラー + ASP.Net ハンドラーの説明。 + 構成エディター + 構成エディターを使用して、IIS マネージャー内の構成ファイルを管理できます。構成ファイル内のセクション、属性、要素、およびコレクションを編集することができます。 + 要求のフィルタリング + 要求のフィルタリングでは、Web サイトのフィルタリング規則を構成したり、プロトコルやコンテンツの動作を制限したりできます。 + Fast CGI + FastCGI では、Web サーバー上の FastCGI アプリケーション用のプロセス プール設定を構成できます。 + + + Dynamic IP Restrictions for IIS 7 セットアップ + + + + + + + + + + + + + Dynamic IP Restrictions for IIS 7 - Beta + Dynamic IP Restrictions for IIS 7 - Beta 2 + Dynamic IP Restrictions for IIS 7 - Beta 3 + + Dynamic IP Restrictions for IIS 7 - リリース候補 + Dynamic IP Restrictions for IIS 7 - リリース候補 2 + Dynamic IP Restrictions for IIS 7 - リリース候補 3 + + Dynamic IP Restrictions for IIS 7 - RTW + + Dynamic IP Restrictions for IIS 7 + Dynamic IP Restrictions for IIS 7 のユーザー インターフェイス + + このコンピューターに Dynamic IP Restrictions for IIS 7 - Beta が見つかりました。アンインストールしてからやり直してください + + + WebDAV 7.5 For IIS 7.0 + この製品を使用するには、IIS 7.0 の CoreWebEngine および W3SVC 機能をインストールする必要があります。 + WebDAV サーバー モジュール + WebDAV 管理ユーザー インターフェイス + + + IIS Search Engine Optimization ツールキット 1.0 + IIS Search Engine Optimization ツールキット 1.0 + Search Engine Optimization (SEO) ツールキット 1.0 + このインストーラー データベースには、IIS Search Engine Optimization ツールキット 1.0 のインストールに必要なロジックとデータが含まれています。 + + + IIS エディター + + + IIS レポート + このコンピューターには、Log Parser がインストールされていません。http://www.microsoft.com/downloads/details.aspx?FamilyID=890cd06b-abf8-4c25-91b2-f8d975cf8c07 から Log Parser 2.2 をインストールし、IIS レポートのインストールを続行してください。 + + + 前提条件のパッケージが見つかりませんでした。setup.exe を実行して依存関係を解決してから、このプログラムをインストールしてください。 + IIS Database Manager のインストールの前提条件として、Microsoft SQL Server 2008 管理オブジェクトが必要です。Micrsoft SQL Server 2008 管理オブジェクトは http://go.microsoft.com/fwlink/?LinkID=150946 からインストールできます。 + IIS Database Manager のインストールの前提要件として、Microsoft SQL Server System CLR Types が必要です。Microsoft SQL Server System CLR Types は、http://go.microsoft.com/fwlink/?LinkID=150949 からインストールできます。 + + + Microsoft Web Farm Framework + Microsoft External Cache + アプリケーション要求ルーティング処理の前提条件として、Web Farm Framework が必要です。Web Farm Framework をインストールしてください。 + Microsoft Application Request Routing 2.5 + ランタイム + アプリケーション要求ルーティング処理の機能を IIS に追加します。 + ユーザー インターフェイス + アプリケーション要求ルーティング処理の機能を IIS マネージャーで構成します。 + + + Microsoft Windows PowerShell snap-in for IIS 7.0 + + + Microsoft Web Platform Installer 4.0 + Microsoft Web Platform Installer + [ProductName] には、Windows XP SP2、Windows 2003 SP1、Windows Vista 以降が必要です。 + [ProductName] には、Windows XP Service Pack 3、Windows Server 2003 Service Pack 2 以降が必要です。 + + + Microsoft Windows Azure サービス インストーラー + Microsoft Windows Azure サービス インストーラー + + + インターネット インフォメーション サービス (IIS) 7 以上のマネージャー + IIS マネージャー クライアント + リモート処理サポート + この製品には、Windows XP SP2、Windows 2003 SP1、Windows Vista SP1、または Windows 7 以上が必要です。 + リモート IIS サーバーを管理するために必要な IIS 管理コンソールがインストールされていません。コントロール パネルの [プログラム] で、[Windows の機能の有効化または無効化] を開き、Ineternet Information Services 機能から [IIS 管理コンソール] を選択して、IIS 管理コンソールをインストールしてから、リモート管理サポートをインストールしてください。 + この製品は、Windows Server 2008 または Windows Server 2008 R2 以上では必須ではありません。サーバー マネージャーを開き、Web サーバーの役割の役割サービスで [IIS 管理コンソール] を選択して、IIS 管理コンソールをインストールしてください。 + + + IIS Manager Publishing for IIS 7.0 + Publishing のユーザー インターフェイス + + + Application Warm-Up 1.0 for IIS 7.5 + + + + 互換性のない製品 [CONFLICTING_PRODUCT_NAME] がこのコンピューター上にあります。[ProductName] のインストールを続行できません。この製品をインストールするには、[コントロール パネル] の [プログラムの追加と削除] を使用して、[CONFLICTING_PRODUCT_NAME] を削除してください。 + [ProductName] をインストールするには管理者特権が必要です。 + [ProductName] を使用するには、IIS Version 7.0 が必要です。 + [ProductName] をインストールするには、IIS Version 7.0 以降が必要です。 + [ProductName] をインストールするには、IIS Version 7.5 以降が必要です。 + [ProductName] をインストールするには、IIS Version 7 または 7.5 が必要です。 + このコンピューターに [ProductName] のベータ版が見つかりました。 + このコンピューターに、より新しいバージョンの [ProductName] が見つかりました。 + このコンピューターには、[ProductName] の別のインスタンスが既にインストールされているため、セットアップを続行できません。最初にアンインストールしてから、再度インストールを行ってください。 + [ProductName] を使用するには、IIS 7.0 の CoreWebEngine および W3SVC 機能をインストールする必要があります。 + [ProductName] を使用するには、IIS 管理コンソールをインストールする必要があります。 + Windows プロセス起動サービス (WAS) と Web 管理サービス (WMSvc) の両方のサービスを停止してから、[ProductName] をインストールしてください。[ProductName] のインストール後にサービスを起動する必要があります。 + [ProductName] をインストールするには、IIS メタベースが必要です。 + 64 ビット版の [ProductName] を 32 ビット版の Microsoft Windows にインストールすることはできません。 + 32 ビット版の [ProductName] を 64 ビット版の Microsoft Windows にインストールすることはできません。 + [ProductName] をインストールするには、Microsoft .NET Framework Version 2.0 以降が必要です。 + [ProductName] をインストールするには、Microsoft .NET Framework Version 3.5 以降が必要です。サーバー マネージャーの [機能の追加] を使用して、Microsoft .Net Version 3.5 をインストールしてください。 + [ProductName] をインストールするには、Microsoft .NET Framework Version 4.0 以降が必要です。 + [ProductName] をインストールする前に、Microsoft .NET Framework Version 2.0 Service Pack 1 (またはそれ以降の Service Pack) をインストールしてください。 + Windows Update (wuauserv) サービスを無効にすることはできません。[ProductName] をインストールする場合は必須です。 + PowerShell スナップインは、Windows オペレーティング システムに付属しています。[プログラムと機能] またはサーバー マネージャーからインストールしてください。 + [ProductName] をインストールするには、Microsoft Web Platform Installer Version 3.0 以降が必要です。 + + 共有構成を検出できませんでした。 + IIS に対して共有構成が有効になっています。共有構成を使用している場合、[ProductName] をインストールすることはサポートされません。この機能をインストールする場合は、あらかじめ共有構成を無効にしてください。 + + [ProductName] をインストールする前に、World Wide Web 発行サービス (W3SVC) を停止してください。インストール後は、このサービスを起動する必要があります。 + IIS PowerShell 管理コンソール + IIS PowerShell スナップイン + IIS PowerShell スナップインを使用するには、PowerShell v1.0 または v2.0 がインストールされている必要があります。 + IIS PowerShell スナップインを使用するには、WAS および構成がインストールされている必要があります。 + これは仮の文字列です。 + + + Microsoft Web Farm Framework Version 2.2 + Microsoft Web Farm Agent Version 2.2 + Web Farm サービス + Web Farm サービス + Web Farm コントローラー サービス + Web Farm コントローラー サービス + Web Farm エージェント サービス + Web Farm エージェント サービス + Web Farm Framework をインストールする前提条件として、Web Platform Installer が必要です。http://www.microsoft.com/web/downloads/platform.aspx から Web Platform Installer をインストールしてください。 + Web Farm Framework をインストールする前提条件として、Web 配置ツールが必要です。http://www.microsoft.com/downloads/details.aspx?displaylang=ja&FamilyID=c7ca4240-5427-42ba-bd46-29a755549e37 (x64) または、http://www.microsoft.com/downloads/details.aspx?displaylang=ja&FamilyID=f2b0fe35-15ae-4638-b72e-f96535c64591 (x86) から Web 配置ツールをインストールしてください。 + + + Microsoft Web Hosting Framework + Web Hosting Framework + Web ホスティングの役割と機能。 + Hosting Framework + Hosting Framework は、Web ホスティングを管理するための API と PowerShell コマンドを提供します。 + Web ロール + Web ロールは、Web ホスティングのための動的 WAS サービスおよび URL 書き換えプロバイダーをインストールします。 + Antares Express + シングル コンピューター セットアップ用に最適化されたコントロール パネルの構成を展開します。 + 負荷分散装置の役割 + 負荷分散装置の役割は、Web ホスティングの規則を基にしてルーティングするようにアプリケーション要求ルーターを構成します。 + ホスティング コントローラー + ホスティング コントローラーは、Web ホスティングと連携するように Web Farm Framework 2.0 を拡張します。 + Publishing ロール + Web 配置および FTP 発行のサポートをインストールします。 + これは、Microsoft Web Hosting インフラストラクチャを管理するためのコマンドレットを含む PowerShell スナップインです。 + 動的 WAS サービス + 高密度な Web ホスティング用に最適化された Windows プロセス アクティブ化サービス。 + リソース メータリング サービス + ランタイムおよび正常性情報の両方の収集と発行を有効にする、リソース メータリング サービスをインストールします。 + リソース メータリング + Web ロールからのランタイムおよび正常性情報の収集と発行を有効にします。 + ホスティング クォータの強制 + Web サイトのリソースの使用率を監視し、使用率のクォータを超えた場合にカスタム アクションを実行します。 + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/KOR/misc/setupstrings.wxl b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/KOR/misc/setupstrings.wxl new file mode 100644 index 0000000000..f4cb5f3312 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/KOR/misc/setupstrings.wxl @@ -0,0 +1,351 @@ + + + + + + + 1042 + + + + 공유 구성 설치 옵션 + IIS 공유 구성 설치 옵션을 선택합니다. + 설치 시 공유 구성 업데이트 + 공유 구성을 사용 중인 IIS 서버에 이 모듈을 설치하는 중입니다. 이 공유 구성을 사용하는 IIS 서버가 더 있는 경우 해당하는 모든 컴퓨터에 이 모듈을 설치해야 합니다. 각 웹 서버의 장애를 최소화하려면 다음 절차에 따라 이 모듈을 설치해야 합니다. 첫째, 마지막 컴퓨터를 제외한 모든 컴퓨터에서 공유 구성을 업데이트하지 않고 모듈을 설치합니다. 아래의 확인란을 선택하지 않고 이 작업을 실행하십시오. +이렇게 하면 공유 구성을 변경하지 않고 모듈에 필요한 모든 파일 및 이진 파일이 각 컴퓨터에 설치됩니다. 둘째, 마지막 컴퓨터에서 사용자가 실행 중인 사용자 ID에 UNC 공유의 applicationhost.config 파일에 대한 읽기 및 쓰기 권한이 있는지 확인합니다. 그런 다음 모듈을 설치하고 아래의 업데이트 공유 구성 옵션을 선택합니다. + + + WebConfig 사용자 지정 작업을 초기화하는 중 + web.config 업데이트 중 + + + + IIS 고급 로깅 + IIS 파이프라인 데이터의 고급 로깅을 사용합니다. + IIS 고급 로깅 + 확장 가능한 필드 선택으로 사용자 지정 로그 파일을 만들 수 있도록 설정합니다. + IIS 고급 로깅 업데이트 + + + + IIS Transform Manager + 베타 + Transform Manager IIS 미디어 서비스를 활성화합니다. + IIS Transform Manager + 미디어 변환을 만들 수 있도록 설정합니다. + IIS Transform Manager 호스트 + [ProductName]의 서비스 호스트입니다. + IIS Transform Manager + 요청 시 미디어 파일을 대체 파일 및 컨테이너 형식으로 일괄 변환합니다. + 컴퓨터에 IIS Transform Manager 1.0 Expression Encoder SP 작업 패키지가 설치되어 있습니다. [ProductName]을(를) 설치하기 전에 IIS Transform Manager 1.0 Expression Encoder SP 작업 패키지를 제거해야 합니다. + + [ProductName]을(를) 설치하려면 Microsoft .NET Framework 3.5가 필요합니다. 서버 관리자에서 '기능 추가 마법사'를 사용하여 .NET Framework 3.5.1 기능을 설치하거나 'Windows 기능 사용/사용 안 함'을 사용하여 Microsoft .NET Framework 3.5 기능을 활성화합니다. + + + + IIS 디지털 권한 관리 + 베타 + 부드러운 스트리밍 프레젠테이션의 디지털 권한 관리를 활성화합니다. + + + ASP.NET이 설치되어 있지 않습니다. + + + + + + + + + 이 컴퓨터에 IIS 부드러운 스트리밍 - 베타가 있으므로 [ProductName] 설치를 계속할 수 없습니다. 이 제품을 설치하려면 제어판의 [프로그램 추가/제거]를 사용하여 IIS 부드러운 스트리밍 - 베타를 제거하십시오. + 이 컴퓨터에 IIS 미디어 서비스의 비호환 버전이 있으므로 [ProductName] 설치를 계속할 수 없습니다. 이 제품을 설치하려면 제어판의 [프로그램 추가/제거]를 사용하여 IIS 미디어 서비스를 제거하십시오. + 컴퓨터에 이 제품의 최신 버전이 이미 설치되어 있거나 설치에 사용할 수 있으므로 [ProductName] 설치를 계속할 수 없습니다. 이 제품의 최신 버전을 설치하려면 [제어판]에서 [프로그램 추가/제거]를 사용하여 IIS Media Services를 업데이트하십시오. + 재생 목록 파일 변환이 필요합니다. + + + + + 이전 IIS 미디어 서비스 파일이 있습니다. + + + + + 베타 IIS 미디어 서비스 파일이 있습니다. + + + + + + IIS Media Pack 1.0 + IIS Media Pack 1.0에 대한 업데이트 + IIS Media Services 2.0 + IIS Media Services 2.0에 대한 업데이트 + IIS Media Services 3.0 + IIS 미디어 서비스 3.0 TAP 2 + IIS Media Services 3.0에 대한 업데이트 + IIS Media Services 기능 및 도구입니다. + IIS Media Services 5 Premium 기능 및 도구입니다. + IIS 미디어 서비스 4.0 베타 1 + IIS 미디어 서비스 4.0 + IIS 미디어 서비스 4.5 베타 1 + IIS Media Services 5 Premium + + 웹 재생 목록 + 재생 목록에 참조된 미디어 자산의 클라이언트 재생을 제어합니다. + Session Helper + ASP.NET 세션 상태가 지속되도록 설정합니다(웹 서버(IIS)에 대한 ASP.NET 역할 서비스 필요). + 사용자 인터페이스 + IIS 관리자에서 웹 재생 목록 기능을 구성합니다. + + 비트 전송률 제한 + 클라이언트가 다운로드하는 파일 전달을 제한하여 대역폭을 절약합니다. + 사용자 인터페이스 + IIS 관리자에서 비트 전송률 제한 기능을 구성합니다. + + 자산 + 클라이언트에 대한 주문형 자산의 HTTP 적응 스트리밍을 사용하도록 설정합니다. + 사용자 인터페이스 + IIS 관리자에서 부드러운 스트리밍 기능을 구성합니다. + + 채널 + 클라이언트에 대한 채널 브로드캐스트의 HTTP 적응 스트리밍을 사용하도록 설정합니다. + 사용자 인터페이스 + IIS 관리자에서 Live Smooth Streaming 기능을 구성합니다. + + 디지털 권한 관리 + 부드러운 스트리밍 미디어의 암호화 및 라이선스를 제공합니다. + 사용자 인터페이스 + IIS 관리자의 디지털 권한 관리 기능을 구성합니다. + + [ProductName]에는 Microsoft Windows Vista 서비스 팩 1 이상이 필요합니다. + [ProductName]은(는) Vista Home Basic에 설치할 수 없습니다. + [ProductName]에는 Microsoft Windows 7 서비스 팩 1 이상이 필요합니다. + + + IIS 데이터베이스 관리자 + IIS 데이터베이스 관리자 + + + Microsoft Web Management Service 2 + Microsoft Web Management Service + [ProductName]의 기본 기능을 설치합니다. + Microsoft Web Management Service 2 + Web Management Service를 사용하면 관리자가 원격 및 위임된 관리 기능을 사용하여 이 컴퓨터에 있는 웹 서버, 사이트 및 응용 프로그램을 관리할 수 있습니다. + + + IIS 7용 Microsoft URL 재작성 모듈 1.1 + IIS 7용 URL 재작성 모듈 1.1에 대한 업데이트 + URL 재작성 + IIS 7에 대한 URL 및 콘텐츠 재작성 기능을 활성화합니다. + 사용자 인터페이스 + IIS 관리자에서 URL 재작성 모듈 기능을 구성합니다. + + + IIS URL 재작성 모듈 2 + IIS URL 재작성 모듈 2에 대한 업데이트 + URL 재작성 + IIS 7에 대한 URL 및 콘텐츠 재작성 기능을 활성화합니다. + 사용자 인터페이스 + IIS 관리자에서 URL 재작성 모듈 기능을 구성합니다. + + + IIS 7.0 관리 팩 + [ProductName]의 기본 기능을 설치합니다. + 1252 + IIS 7.0 관리 팩 + Microsoft Corporation + 이 운영 체제 버전은 지원되지 않습니다. [ProductName]은(는) Windows Server 2008 또는 Windows Vista 서비스 팩 1 이상에만 설치할 수 있습니다. + ASP.NET 기능 + ASP.NET에는 권한 부여 및 사용자 지정 오류 설정을 관리하는 데 사용할 수 있는 권한 부여 및 오류 페이지 기능이 있습니다. + 인증 + ASP.NET 인증에 대한 설명입니다. + 권한 부여 + ASP.NET 권한 부여를 사용하여 사용자에게 웹 사이트 및 응용 프로그램에 액세스할 수 있는 권한을 부여하는 규칙을 구성할 수 있습니다. + 오류 페이지 + ASP.NET 오류 페이지를 사용하여 오류가 발생했을 때 반환할 HTTP 오류 응답을 구성할 수 있습니다. + 모듈 + ASP.NET 모듈에 대한 설명입니다. + 처리기 + ASP.NET 처리기에 대한 설명입니다. + 구성 편집기 + 구성 편집기를 통해 구성 파일의 섹션, 특성, 요소 및 컬렉션을 편집하여 IIS 관리자의 구성 파일을 관리할 수 있습니다. + 요청 필터링 + 요청 필터링을 사용하여 웹 사이트에 대한 필터링 규칙을 구성하고 프로토콜 및 콘텐츠 동작을 제한할 수 있습니다. + Fast CGI + FastCGI를 사용하여 웹 서버의 FastCGI 응용 프로그램에 대한 프로세스 풀 설정을 구성할 수 있습니다. + + + IIS 7 설치에 대한 동적 IP 제한 + + + + + + + + + + + + + IIS 7용 동적 IP 제한 - 베타 + IIS 7용 동적 IP 제한 - 베타 2 + IIS 7용 동적 IP 제한 - 베타 3 + + IIS 7용 동적 IP 제한 - 릴리스 후보 + IIS 7용 동적 IP 제한 - 릴리스 후보 2 + IIS 7용 동적 IP 제한 - 릴리스 후보 3 + + IIS 7용 동적 IP 제한 - RTW + + IIS 7용 동적 IP 제한 + IIS 7용 동적 IP 제한 사용자 인터페이스 + + 이 시스템에서 IIS 7 - 베타에 대한 동적 IP 제한 사항이 발견되었습니다. 이 제한 사항을 제거한 후 다시 시도하십시오. + + + IIS 7.0용 WebDAV 7.5 + 이 제품을 사용하려면 IIS 7.0 CoreWebEngine 및 W3SVC 기능이 설치되어 있어야 합니다. + WebDAV 서버 모듈 + WebDAV 관리 사용자 인터페이스 + + + IIS 검색 엔진 최적화 도구 키트 1.0 + IIS 검색 엔진 최적화 도구 키트 1.0 + 검색 엔진 최적화(SEO) 도구 키트 1.0 + 이 설치 프로그램 데이터베이스에는 IIS 검색 엔진 최적화 도구 키트 1.0을 설치하는 데 필요한 논리 및 데이터가 들어 있습니다. + + + IIS 편집기 + + + IIS 보고서 + 이 컴퓨터에 Log Parser가 설치되어 있지 않습니다. http://www.microsoft.com/downloads/details.aspx?FamilyID=890cd06b-abf8-4c25-91b2-f8d975cf8c07에서 Log Parser 2.2를 설치한 다음 IIS 보고서 설치를 계속하십시오. + + + 필수 구성 요소 패키지가 없습니다. setup.exe를 실행하여 종속성을 해결한 다음 이 프로그램을 설치하십시오. + IIS 데이터베이스 관리자를 설치하려면 Microsoft SQL Server 2008 관리 개체가 설치되어 있어야 합니다. http://go.microsoft.com/fwlink/?LinkID=150946에서 Microsoft SQL Server 2008 관리 개체를 설치할 수 있습니다. + IIS 데이터베이스 관리자를 설치하려면 Microsoft SQL Server System CLR Types가 설치되어 있어야 합니다. http://go.microsoft.com/fwlink/?LinkID=150949에서 Microsoft SQL Server System CLR Types를 설치할 수 있습니다. + + + Microsoft Web Farm Framework + Microsoft External Cache + 응용 프로그램 요청 라우팅을 설치하려면 Web Farm Framework가 설치되어 있어야 합니다. Web Farm Framework를 설치하십시오. + Microsoft 응용 프로그램 요청 라우팅 버전 2.5 + 런타임 + IIS에 응용 프로그램 요청 라우팅 기능을 추가합니다. + 사용자 인터페이스 + IIS 관리자에서 응용 프로그램 요청 라우팅 기능을 구성합니다. + + + IIS 7.0용 Microsoft Windows PowerShell 스냅인 + + + Microsoft 웹 플랫폼 설치 관리자 4.0 + Microsoft 웹 플랫폼 설치 관리자 + [ProductName]에는 Windows XP SP2, Windows 2003 SP1, Windows Vista 이상이 필요합니다. + [ProductName]을(를) 사용하려면 Windows XP 서비스 팩 3, Windows Server 2003 서비스 팩 2 이상이 필요합니다. + + + Microsoft Windows Azure Services 설치 관리자 + Microsoft Windows Azure Services 설치 관리자 + + + IIS(인터넷 정보 서비스) 7+ 관리자 + IIS 관리자 클라이언트 + 원격 지원 + 이 제품에는 Windows XP SP2, Windows 2003 SP1, Windows Vista SP1, Windows 7 이상이 있어야 합니다. + 원격 IIS 서버 관리에 필요한 IIS 관리 콘솔이 설치되어 있지 않습니다. 원격 관리 지원을 설치하기 전에 '제어판->프로그램->Windows 기능 사용/사용 안 함'을 열고 인터넷 정보 서비스 기능에서 IIS 관리 콘솔을 선택하여 IIS 관리 콘솔을 설치하십시오. + 이 제품은 Windows Server 2008 또는 Windows Server 2008 R2 이상에서 필수 사항이 아닙니다. 서버 관리자를 열고 웹 서버 역할에 대한 역할 서비스에서 IIS 관리 콘솔을 선택하여 IIS 관리 콘솔을 설치하십시오. + + + IIS 7.0용 IIS 관리자 게시 + 게시 사용자 인터페이스 + + + IIS 7.5용 응용 프로그램 웜업 + + + + 이 컴퓨터에 호환되지 않는 제품 [CONFLICTING_PRODUCT_NAME]이(가) 있습니다. [ProductName]의 설치를 계속할 수 없습니다. 이 제품을 설치하려면 제어판에서 프로그램 추가/제거를 사용하여 [CONFLICTING_PRODUCT_NAME]을(를) 제거하십시오. + [ProductName]을(를) 설치하려면 관리자 권한이 있어야 합니다. + [ProductName]을(를) 사용하려면 IIS 버전 7.0이 있어야 합니다. + [ProductName]을(를) 설치하려면 IIS 버전 7.0 이상이 있어야 합니다. + [ProductName]을(를) 설치하려면 IIS 버전 7.5 이상이 있어야 합니다. + [ProductName]을(를) 설치하려면 IIS 버전 7 또는 7.5가 있어야 합니다. + 이 컴퓨터에 [ProductName]의 베타 버전이 설치되어 있습니다. + 이 컴퓨터에 [ProductName]의 상위 버전이 설치되어 있습니다. + 컴퓨터에 [ProductName]의 다른 인스턴스가 이미 설치되어 있어서 설치를 계속할 수 없습니다. 먼저 해당 인스턴스를 제거한 다음 설치 프로그램을 다시 시작하십시오. + [ProductName]을(를) 사용하려면 IIS 7.0 CoreWebEngine 및 W3SVC 기능이 설치되어 있어야 합니다. + [ProductName]을(를) 사용하려면 IIS 관리 콘솔이 설치되어 있어야 합니다. + [ProductName]을(를) 설치하기 전에 WAS(Windows Process Activation Service) 및 WMSvc(Web Management Service)를 모두 중지하십시오. [ProductName]을(를) 설치한 후에 해당 서비스를 시작해야 합니다. + [ProductName]을(를) 설치하려면 IIS 메타베이스가 있어야 합니다. + [ProductName] 64비트 버전은 Microsoft Windows 32비트 버전에 설치할 수 없습니다. + [ProductName] 32비트 버전은 Microsoft Windows 64비트 버전에 설치할 수 없습니다. + [ProductName]을(를) 설치하려면 Microsoft .NET Framework 버전 2.0 이상이 설치되어 있어야 합니다. + [ProductName]을(를) 설치하려면 Microsoft .NET Framework 버전 3.5 이상이 필요합니다. 서버 관리자에서 '기능 추가'를 사용하여 Microsoft .Net 버전 3.5를 설치하십시오. + [ProductName]을(를) 설치하려면 Microsoft .NET Framework 버전 4.0 이상이 필요합니다. + [ProductName]을(를) 설치하기 전에 Microsoft .NET Framework 버전 2.0 서비스 팩 1 이상을 설치하십시오. + [ProductName]을(를) 설치하는 데 필요하므로 Windows Update(wuauserv) 서비스를 비활성화할 수 없습니다. + PowerShell 스냅인은 Windows 운영 체제에 포함되어 있습니다. '프로그램 및 기능' 또는 '서버 관리자'를 사용하여 설치하십시오. + [ProductName]을(를) 설치하려면 Microsoft 웹 플랫폼 설치 관리자 버전 3.0 이상이 필요합니다. + + 설치 프로그램이 공유 구성을 검색하지 못했습니다. + IIS에 대해 공유 구성이 활성화되어 있습니다. 공유 구성을 사용하는 경우 [ProductName]을(를) 설치할 수 없습니다. 이 기능을 설치하려면 공유 구성을 비활성화하십시오. + + [ProductName]을(를) 설치하려면 먼저 W3SVC(World Wide Web Publishing Service)를 중지하십시오. 설치 후 해당 서비스를 다시 시작해야 합니다. + IIS PowerShell 관리 콘솔 + IIS PowerShell 스냅인 + IIS PowerShell 스냅인을 사용하려면 PowerShell v1.0 또는 v2.0이 설치되어 있어야 합니다. + IIS PowerShell 스냅인을 사용하려면 WAS 및 구성이 설치되어 있어야 합니다. + 임시 문자열입니다. + + + Microsoft Web Farm Framework 버전 2.2 + Microsoft 웹 팜 에이전트 버전 2.2 + 웹 팜 서비스 + 웹 팜 서비스 + 웹 팜 컨트롤러 서비스 + 웹 팜 컨트롤러 서비스 + 웹 팜 에이전트 서비스 + 웹 팜 에이전트 서비스 + Web Farm Framework를 설치하려면 웹 플랫폼 설치 관리자가 설치되어 있어야 합니다. 웹 플랫폼 설치 관리자는 http://www.microsoft.com/web/downloads/platform.aspx에서 설치하십시오. + Web Farm Framework를 설치하려면 웹 배포 도구가 설치되어 있어야 합니다. 웹 배포 도구는 http://www.iis.net/download/WebDeploy에서 설치하십시오. + + + Microsoft Web Hosting Framework + Web Hosting Framework + 웹 호스팅 역할 및 기능입니다. + Hosting Framework + Hosting Framework는 웹 호스팅을 관리하기 위한 API 및 PowerShell 명령을 제공합니다. + 웹 역할 + 웹 역할은 웹 호스팅용 동적 WAS 서비스 및 URL 재작성 공급자를 설치합니다. + Antares Express + 단일 컴퓨터 설치에 대해 최적화된 제어판 구성을 배포합니다. + 부하 분산 장치 역할 + 부하 분산 장치 역할은 웹 호스팅 규칙을 기반으로 라우팅하기 위한 응용 프로그램 요청 라우터를 구성합니다. + 호스팅 컨트롤러 + 호스팅 컨트롤러는 웹 호스팅과 작동하도록 Web Farm Framework 2.0을 확장합니다. + 게시 역할 + 웹 배포 및 FTP 게시에 대한 지원을 설치합니다. + Microsoft Web Hosting 인프라 관리를 위한 cmdlets가 포함된 PowerShell 스냅인입니다. + 동적 WAS 서비스 + 고밀도 웹 호스팅에 대해 최적화된 Windows Process Activation Service입니다. + 리소스 계량 서비스 + 런타임 및 상태 정보를 둘 다 수집하고 게시하는 리소스 계량 서비스를 설치합니다. + 리소스 계량 + 웹 역할의 런타임 및 상태 정보를 수집하고 게시할 수 있습니다. + 호스팅 할당량 적용 + 웹 사이트 리소스 사용을 모니터링하고 사용 할당량을 초과하면 사용자 지정 작업을 실행합니다. + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/PLK/misc/setupstrings.wxl b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/PLK/misc/setupstrings.wxl new file mode 100644 index 0000000000..fccd7b5d05 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/PLK/misc/setupstrings.wxl @@ -0,0 +1,351 @@ + + + + + + + 1045 + + + + Opcje instalacji w konfiguracji udostępnionej + Wybierz opcję instalacji w konfiguracji udostępnionej usług IIS + Aktualizuj konfigurację udostępnioną podczas instalacji + Ten moduł zostanie zainstalowany na serwerze usług IIS korzystającym z konfiguracji udostępnionej. Jeśli z tej konfiguracji udostępnionej korzysta więcej serwerów usług IIS, należy zainstalować ten moduł na wszystkich tych komputerach. Aby zminimalizować zakłócenia pracy poszczególnych serwerów sieci Web, najlepiej jest zainstalować ten moduł w następujący sposób: Najpierw zainstaluj moduł na wszystkich komputerach z wyjątkiem ostatniego bez aktualizowania konfiguracji udostępnionej. W tym celu nie zaznaczaj poniższego pola wyboru. + Wtedy na wszystkich komputerach zostaną zainstalowane wszystkie pliki binarne i inne wymagane przez moduł, ale nie zostaną wprowadzone żadne zmiany w konfiguracji udostępnionej. Następnie na ostatnim komputerze sprawdź, czy używana tożsamość użytkownika ma dostęp z prawem do zapisu i odczytu do pliku applicationhost.config w udziale UNC. Jeśli ma, zainstaluj moduł i wybierz poniższą opcję aktualizacji konfiguracji udostępnionej. + + + Inicjowanie akcji niestandardowej WebConfig + Aktualizowanie pliku web.config + + + + Zaawansowane rejestrowanie usług IIS + Włącza zaawansowane rejestrowanie danych potoku usług IIS. + Zaawansowane rejestrowanie usług IIS + Umożliwia tworzenie niestandardowych plików dziennika przy użyciu rozszerzalnego wyboru pól. + Aktualizacja zaawansowanego rejestrowania usług IIS + + + + Menedżer transformat usług IIS + Beta + Włącza menedżera transformat usług IIS Media. + Menedżer transformat usług IIS + Włącza tworzenie transformat plików multimedialnych. + Host menedżera transformat usług IIS + Host usługi programu [ProductName]. + Menedżer transformat usług IIS + Konwersja wsadowa plików multimedialnych na żądnie w celu zmiany formatów kontenerów i plików. + Na komputerze zainstalowano pakiet „IIS Transform Manager 1.0 Expression Encoder SP Task”. Należy go odinstalować przed zainstalowaniem produktu [ProductName]. + + Do zainstalowania produktu [ProductName] jest wymagany program Microsoft .NET Framework w wersji 3.5. Aby zainstalować funkcje programu .NET Framework 3.5.1, należy użyć Kreatora dodawania funkcji w Menedżerze serwerów. Aby włączyć program Microsoft .NET Framework 3.5, należy użyć apletu Włącz lub wyłącz funkcje systemu Windows. + + + + Zarządzanie prawami cyfrowymi w usługach IIS + Beta + Włącza zarządzanie prawami cyfrowymi prezentacji w formacie Smooth Streaming. + + + Niezainstalowany program ASP.NET + + + + + + + + + Na tym komputerze wykryto funkcję Płynne przesyłanie strumieniowe w wersji beta. Nie można kontynuować instalacji produktu [ProductName]. Aby zainstalować ten produkt, usuń funkcję Płynne przesyłanie strumieniowe w wersji beta, używając apletu Dodaj/Usuń programy w Panelu sterowania. + Na tym komputerze znajduje się niezgodna wersja usług IIS Media Services. Nie można kontynuować instalacji produktu [ProductName]. Aby zainstalować ten produkt, usuń usługi IIS Media Services, używając apletu Dodaj/Usuń programy w Panelu sterowania. + Nowsza wersja tego produktu jest już zainstalowana lub dostępna do zainstalowania na tym komputerze. Nie można kontynuować instalacji produktu [ProductName]. Aby zainstalować nowszą wersję tego produktu, używaj apletu Dodaj/Usuń programy w Panelu sterowania w celu zaktualizowania usług IIS Media Services. + Wymagana konwersja pliku listy odtwarzania + + + + + Odnaleziono starsze pliki usług IIS Media Services + + + + + Odnaleziono pliki usług IIS Media Services w wersji beta + + + + + + IIS Media Pack 1.0 + Aktualizacja pakietu IIS Media Pack 1.0 + IIS Media Services 2.0 + Aktualizacja usług IIS Media Services 2.0 + IIS Media Services 3.0 + IIS Media Services 3.0 TAP 2 + Aktualizacja usług IIS Media Services 3.0 + Funkcje i narzędzia usług IIS Media Services. + Funkcje i narzędzia usług IIS Media Services 5 Premium. + Usługi IIS Media 4.0 w wersji beta 1 + IIS Media Services 4.0 + IIS Media Services 4.5 w wersji beta 1 + IIS Media Services 5 Premium + + Listy odtwarzania w sieci Web + Steruje odtwarzaniem przez klienta zasobów multimedialnych wymienionych na listach odtwarzania. + Pomocnik sesji + Umożliwia utrwalanie stanu sesji programu ASP.NET. (Wymaga usługi roli programu ASP.NET dla serwera sieci Web [IIS]). + Interfejs użytkownika + Konfiguruje funkcję Listy odtwarzania w sieci Web w Menedżerze usług IIS. + + Ograniczanie szybkości transmisji bitów + Oszczędza przepustowość, ograniczając dostarczanie plików pobieranych przez klientów. + Interfejs użytkownika + Konfiguruje funkcję Ograniczanie szybkości transmisji bitów w Menedżerze usług IIS. + + Zasoby + Włącza adaptacyjne przesyłanie strumieniowe zasobów na żądanie przez protokół HTTP do klientów. + Interfejs użytkownika + Konfiguruje funkcję Płynne przesyłanie strumieniowe w Menedżerze usług IIS. + + Kanały + Włącza adaptacyjne przesyłanie strumieniowe emisji kanałów przez protokół HTTP do klientów. + Interfejs użytkownika + Konfiguruje funkcję Płynne przesyłanie strumieniowe na żywo w Menedżerze usług IIS. + + Zarządzanie prawami cyfrowymi + Realizuje szyfrowanie i licencjonowanie plików multimedialnych w formacie Smooth Streaming. + Interfejs użytkownika + Konfiguruje funkcję zarządzania prawami cyfrowymi w module Menedżer usług IIS. + + Produkt [ProductName] wymaga systemu Microsoft Windows Vista z dodatkiem Service Pack 1 lub nowszym. + Produktu [ProductName] nie można zainstalować w systemie Vista Home Basic. + Produkt [ProductName] wymaga systemu Microsoft Windows 7 z dodatkiem Service Pack 1 lub nowszym. + + + Menedżer baz danych usług IIS + Menedżer baz danych usług IIS + + + Usługa zarządzania siecią Web firmy Microsoft 2 + Usługa zarządzania siecią Web firmy Microsoft + Instaluje podstawowe funkcje produktu [ProductName]. + Usługa zarządzania siecią Web firmy Microsoft 2 + Usługa zarządzania siecią Web zawiera mechanizmy zarządzania zdalnego i delegowanego, dzięki którym administratorzy mogą skutecznie zarządzać serwerem sieci Web, witrynami i aplikacjami obecnymi na komputerze. + + + Moduł ponownego zapisywania adresów URL firmy Microsoft w wersji 1.1 dla usług IIS 7 + Aktualizacja Modułu ponownego zapisywania adresów URL firmy Microsoft w wersji 1.1 dla usług IIS 7 + Ponowne zapisywanie adresów URL + Włącza funkcje ponownego zapisywania adresów URL i zawartości w usługach IIS 7. + Interfejs użytkownika + Konfiguruje funkcję Moduł ponownego zapisywania adresów URL w Menedżerze usług IIS. + + + Moduł ponownego zapisywania adresów URL usług IIS w wersji 2 + Aktualizacja modułu ponownego zapisywania adresów URL usług IIS w wersji 2 + Ponowne zapisywanie adresów URL + Włącza funkcje ponownego zapisywania adresów URL i zawartości w usługach IIS 7. + Interfejs użytkownika + Konfiguruje funkcję Moduł ponownego zapisywania adresów URL w Menedżerze usług IIS. + + + Pakiet administracyjny dla usług IIS 7.0 + Instaluje podstawowe funkcje produktu [ProductName]. + 1252 + Pakiet administracyjny dla usług IIS 7.0 + Microsoft Corporation + Ta wersja systemu operacyjnego jest nieobsługiwana. Produkt [ProductName] można zainstalować tylko w systemie Windows Server 2008 lub Windows Vista z dodatkiem Service Pack 1 lub nowszym. + Funkcje programu ASP.NET + Program ASP.NET zawiera funkcje Autoryzacja i Strony błędów, które umożliwiają zarządzanie ustawieniami autoryzacji i błędów niestandardowych. + Uwierzytelnianie + Opis funkcji Uwierzytelnianie programu ASP.NET. + Autoryzacja + Funkcja Autoryzacja programu ASP.NET umożliwia konfigurowanie reguł dotyczących autoryzacji użytkowników uzyskujących dostęp do witryn i aplikacji sieci Web. + Strony błędów + Funkcja Strony błędów programu ASP.NET umożliwia konfigurowanie odpowiedzi na błędy protokołu HTTP, które będą zwracane w przypadku wystąpienia błędów. + Moduły + Opis funkcji Moduły programu ASP.NET. + Obsługa + Opis funkcji Obsługa programu ASP.NET. + Edytor konfiguracji + Edytor konfiguracji służy do zarządzania plikami konfiguracji w Menedżerze usług IIS, umożliwiając edytowanie sekcji, atrybutów, elementów i kolekcji w plikach konfiguracji. + Filtrowanie żądań + Filtrowanie żądań umożliwia konfigurowania reguł filtrowania dla witryny sieci Web oraz ograniczanie zachowania protokołu i zawartości. + FastCGI + Funkcja FastCGI umożliwia konfigurowanie ustawień puli procesów dla aplikacji FastCGI na serwerze sieci Web. + + + Dynamiczne ograniczenia adresów IP dla Instalatora usług IIS 7 + + + + + + + + + + + + + Dynamiczne ograniczenia adresów IP dla usług IIS 7 — wersja Beta + Dynamiczne ograniczenia adresów IP dla usług IIS 7 — wersja Beta 2 + Dynamiczne ograniczenia adresów IP dla usług IIS 7 — wersja Beta 3 + + Dynamiczne ograniczenia adresów IP dla usług IIS 7 — wersja Release Candidate + Dynamiczne ograniczenia adresów IP dla usług IIS 7 — wersja Release Candidate 2 + Dynamiczne ograniczenia adresów IP dla usług IIS 7 — wersja Release Candidate 3 + + Dynamiczne ograniczenia adresów IP dla usług IIS 7 — wersja RTW + + Dynamiczne ograniczenia adresów IP dla usług IIS 7 + Interfejs użytkownika funkcji Dynamiczne ograniczenia adresów IP dla usług IIS 7 + + Dynamiczne ograniczenia adresu IP w usługach IIS 7 — na komputerze znaleziono wersję beta. Odinstaluj ją i spróbuj ponownie + + + WebDAV 7.5 dla usług IIS 7.0 + Aby można było używać tego produktu, muszą być zainstalowane funkcje CoreWebEngine i W3SVC usług IIS 7.0. + Moduł serwera WebDAV + Interfejs użytkownika administracji funkcją WebDAV + + + Zestaw narzędzi do optymalizacji aparatu wyszukiwania usług IIS w wersji 1.0 + Zestaw narzędzi do optymalizacji aparatu wyszukiwania usług IIS w wersji 1.0 + Zestaw narzędzi do optymalizacji aparatu wyszukiwania (SEO) w wersji 1.0 + Ta baza danych instalatora zawiera logikę i dane wymagane do zainstalowania narzędzia do optymalizacji aparatu wyszukiwania usług IIS w wersji 1.0. + + + Edytor usług IIS + + + Raporty usług IIS + Analizator dzienników nie jest zainstalowany na tym komputerze; zainstaluj funkcję Analizator dzienników w wersji 2.2 spod adresu http://www.microsoft.com/downloads/details.aspx?FamilyID=890cd06b-abf8-4c25-91b2-f8d975cf8c07, a następnie kontynuuj instalowanie funkcji Raporty usług IIS. + + + Nie można odnaleźć wstępnie wymaganych pakietów. Uruchom plik setup.exe, aby rozpoznać zależności i zainstalować ten program. + Program Microsoft SQL Server 2008 Management Objects jest wstępnie wymaganym składnikiem instalacji Menedżera baz danych usług IIS. Program Microsoft SQL Server 2008 Management Objects można zainstalować spod adresu http://go.microsoft.com/fwlink/?LinkID=150946. + Program Microsoft SQL Server System CLR Types jest wstępnie wymaganym składnikiem instalacji Menedżera baz danych usług IIS. Program Microsoft SQL Server System CLR Types można zainstalować spod adresu http://go.microsoft.com/fwlink/?LinkID=150946. + + + Microsoft Web Farm Framework + Zewnętrzna pamięć podręczna firmy Microsoft + Struktura farmy sieci Web jest wymaganym składnikiem instalacji funkcji Routing żądań aplikacji. Zainstaluj strukturę farmy sieci Web. + Routing żądań aplikacji firmy Microsoft 2.5 + Wersja wykonawcza + Dodaje funkcje routingu żądań aplikacji do usług IIS. + Interfejs użytkownika + Konfiguruje funkcję routingu żądań aplikacji w module Menedżer usług IIS. + + + Przystawka środowiska Microsoft Windows PowerShell dla usług IIS 7.0 + + + Instalator platformy Microsoft Web 4.0 + Instalator platformy sieci Web firmy Microsoft + Produkt [ProductName] wymaga systemu Windows XP z dodatkiem SP2, Windows 2003 z dodatkiem SP1, Windows Vista lub nowszego. + Program [ProductName] wymaga systemu Windows XP z dodatkiem Service Pack 3, Windows Server 2003 z dodatkiem Service Pack 2 lub nowszego. + + + Instalator usług Microsoft Windows Azure + Instalator usług Microsoft Windows Azure + + + Menedżer internetowych usług informacyjnych (IIS) 7+ + Klient Menedżera usług IIS + Obsługa operacji zdalnych + Ten produkt wymaga systemu Windows XP z dodatkiem SP2, Windows 2003 z dodatkiem SP1, Windows Vista z dodatkiem SP1, Windows 7 lub nowszego + Konsola zarządzania usługami IIS nie jest zainstalowana, ale jest wymagana do zarządzania zdalnymi serwerami usług IIS. Zainstaluj Konsolę zarządzania usługami IIS przed zainstalowaniem obsługi operacji zdalnych, klikając polecenia Panel sterowania -> Programy -> Włącz lub wyłącz funkcje systemu Windows i wybierając opcję Konsola zarządzania usługami IIS w funkcji Internetowe usługi informacyjne. + Ten produkt nie jest wymagany w systemach Windows Server 2008 i Windows Server 2008 R2 ani w nowszych. Zainstaluj Konsolę zarządzania usługami IIS, otwierając Menedżera serwera i wybierając pozycję Konsola zarządzania usługami IIS z usług roli dla roli Serwer sieci Web. + + + Publikowanie Menedżera usług IIS dla usług IIS 7.0 + Interfejs użytkownika funkcji Publikowanie + + + Zwiększanie gotowości aplikacji w wersji 1.0 dla usług IIS 7.5 + + + + Na tym komputerze znajduje się niezgodny produkt: [CONFLICTING_PRODUCT_NAME]. Nie można kontynuować instalowania produktu [ProductName]. Aby zainstalować ten produkt, usuń produkt [CONFLICTING_PRODUCT_NAME] za pomocą apletu Dodaj/Usuń programy w Panelu sterowania. + Do zainstalowania produktu [ProductName] jest wymagane uprawnienie administratora. + Do używania produktu [ProductName] są wymagane usługi IIS w wersji 7.0. + Do używania produktu [ProductName] są wymagane usługi IIS w wersji 7.0 lub nowsze. + Do używania produktu [ProductName] są wymagane usługi IIS w wersji 7.5 lub nowsze. + Do zainstalowania produktu [ProductName] wymagany jest program IIS 7 lub 7.5. + Odnaleziono wersję beta produktu [ProductName] na tym komputerze. + Odnaleziono nowszą wersję produktu [ProductName] na tym komputerze. + Instalator nie może kontynuować, ponieważ na tym komputerze jest już zainstalowane inne wystąpienie produktu [ProductName]. Odinstaluj je, a następnie ponownie rozpocznij tę instalację. + Aby można było używać produktu [ProductName], muszą być zainstalowane funkcje CoreWebEngine i W3SVC usług IIS 7.0. + Aby można było używać produktu [ProductName], musi być zainstalowana Konsola zarządzania usługami IIS. + Przed zainstalowaniem produktu [ProductName] zatrzymaj usługę aktywacji procesów systemu Windows (WAS) i usługę zarządzania siecią Web (WMSvc). Te usługi trzeba będzie uruchomić po zainstalowaniu produktu [ProductName]. + Do zainstalowania produktu [ProductName] jest wymagana metabaza usług IIS. + Nie można zainstalować 64-bitowej wersji produktu [ProductName] w 32-bitowej wersji systemu Microsoft Windows. + Nie można zainstalować 32-bitowej wersji produktu [ProductName] w 64-bitowej wersji systemu Microsoft Windows. + Do zainstalowania produktu [ProductName] jest wymagany program .NET Framework w wersji 2.0 lub nowszy. + Do zainstalowania programu [ProductName] jest potrzebny program Microsoft .NET Framework w wersji 3.5 lub nowszej. Naciśnij przycisk „Dodaj funkcje” w sekcji Menedżer serwera, aby zainstalować program Microsoft .Net w wersji 3.5. + Do zainstalowania programu [ProductName] jest wymagany program Microsoft .NET Framework w wersji 4.0 lub nowszej. + Przed zainstalowaniem produktu [ProductName] zainstaluj dodatek Service Pack 1 (lub nowszy) dla programu Microsoft .NET Framework w wersji 2.0. + Nie można wyłączyć usługi Windows Update (wuauserv), ponieważ jest ona wymagana do zainstalowania produktu [ProductName]. + Przystawka PowerShell stanowi część systemu operacyjnego Windows. Zainstaluj ją za pomocą menu Programy i funkcje lub narzędzia Menedżer serwera. + Do zainstalowania programu [ProductName] jest wymagany instalator platformy sieci Web firmy Microsoft w wersji 3.0 lub nowszej. + + Instalator nie może wykryć konfiguracji udostępnionej. + Konfiguracja udostępniona jest włączona dla usług IIS. Instalowanie produktu [ProductName] jest nieobsługiwane, gdy jest używana konfiguracja udostępniona. Wyłącz konfigurację udostępnioną przed zainstalowaniem tej funkcji. + + Zatrzymaj usługę publikowania w sieci World Wide Web (W3SVC) przed zainstalowaniem produktu [ProductName]. Tę usługę trzeba będzie uruchomić po instalacji. + Konsola zarządzania środowiskiem IIS PowerShell + Przystawka IIS PowerShell + Przystawka IIS PowerShell wymaga zainstalowanego środowiska PowerShell w wersji 1.0 lub 2.0. + Przystawka IIS PowerShell wymaga zainstalowanej usługi WAS oraz konfiguracji. + To jest nieprawdziwy ciąg. + + + Microsoft Web Farm Framework 2.2 + Microsoft Web Farm Agent 2.2 + Usługa kolektywu serwerów sieci Web + Usługa kolektywu serwerów sieci Web + Usługa kontrolera kolektywu serwerów sieci Web + Usługa kontrolera kolektywu serwerów sieci Web + Usługa agenta kolektywu serwerów sieci Web + Usługa agenta kolektywu serwerów sieci Web + Do zainstalowania składnika Web Farm Framework jest wymagany instalator platformy sieci Web. Zainstaluj instalatora platformy sieci Web ze strony http://www.microsoft.com/web/downloads/platform.aspx. + Do zainstalowania składnika Web Farm Framework jest wymagane narzędzie Web Deployment. Zainstaluj narzędzie Web Deployment ze strony http://www.iis.net/download/WebDeploy. + + + Microsoft Web Hosting Framework + Web Hosting Framework + Role i funkcje obsługi hostingu sieci Web. + Hosting Framework + Składnik Hosting Framework udostępnia interfejsy API i polecenia programu PowerShell do zarządzania hostingiem sieci Web. + Rola sieci Web + Rola sieci Web instaluje usługę Dynamiczna usługa WAS i dostawcę Moduł ponownego zapisywania adresów URL na potrzeby hostingu sieci Web. + Antares Express + Wdraża konfigurację Panelu sterowania zoptymalizowaną pod kątem konfiguracji jednego komputera. + Rola Usługa równoważenia obciążenia + Rola Usługa równoważenia obciążenia konfiguruje router żądań aplikacji do routingu na podstawie reguł hostingu sieci Web. + Kontroler hostingu + Kontroler hostingu rozszerza funkcje składnika Web Farm Framework 2.0 o współdziałanie z hostingiem sieci Web. + Rola publikowania + Instaluje obsługę narzędzia Web Deploy i publikowana FTP. + To jest przystawka PowerShell zawierająca aplety poleceń służące do zarządzania infrastrukturą Microsoft Web Hosting. + Dynamiczna usługa WAS + Usługa aktywacji procesów systemu Windows zoptymalizowana pod kątem hostingu sieci Web o dużej gęstości. + Usługa pomiaru użycia zasobów + Instaluje usługę pomiaru użycia zasobów, która umożliwia gromadzenie i publikowanie informacji na temat środowiska wykonawczego i kondycji. + Miernik zasobów + Umożliwia gromadzenie i publikowanie informacji na temat środowiska wykonawczego i kondycji pochodzących z roli sieci Web. + Wymuszanie przydziału hostingu + Monitoruje użycie zasobów witryn sieci Web i w razie przekroczenia przydziału użycia wykonuje akcje niestandardowe. + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/PTB/misc/setupstrings.wxl b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/PTB/misc/setupstrings.wxl new file mode 100644 index 0000000000..4fdfeffca5 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/PTB/misc/setupstrings.wxl @@ -0,0 +1,351 @@ + + + + + + + 1046 + + + + Opções de Instalação da Configuração Compartilhada + Selecionar a opção de instalação na configuração compartilhada do IIS + Atualizar configuração compartilhada na instalação + Você está instalando este módulo em um servidor do IIS que usa a configuração compartilhada. Se outros servidores do IIS estiverem usando essa configuração compartilhada, você precisará instalar este módulo em todos os computadores. Para minimizar interrupções de servidores Web individuais, será preciso instalar este módulo de acordo com as seguintes etapas: primeiro, em todos os computadores, com exceção do último, você deverá instalar o módulo sem atualizar a configuração compartilhada. Para isso, não marque a caixa de seleção + a seguir. Isso instalará todos os binários e arquivos necessários para o módulo em cada computador sem fazer alterações na configuração compartilhada. Em segundo lugar, no último computador, será preciso verificar se a identidade do usuário usada por você na execução tem acesso de leitura e gravação ao arquivo applicationhost.config no compartilhamento UNC. Em seguida, instale o módulo e selecione a opção abaixo de atualização da configuração compartilhada. + + + Inicializando a ação personalizada do WebConfig + Atualizando o web.config + + + + Registro em Log Avançado do IIS + Habilita o registro em log avançado dos dados de pipeline do IIS. + Registro em Log Avançado do IIS + Habilita a criação de arquivos de log personalizados com seleção de campo extensível. + Atualização para o Registro em Log Avançado do IIS + + + + IIS Transform Manager + Beta + Habilita o IIS Media Services do Transform Manager. + IIS Transform Manager + Habilita a criação de transformações de mídia. + Host do IIS Transform Manager + Host de serviço de [ProductName]. + IIS Transform Manager + Conversão em lote de arquivos de mídia por demanda para formatos de arquivo e de contêiner alternativos. + Um pacote de Tarefa do Expression Encoder SP do IIS Transform Manager 1.0 está instalado no computador. Desinstale-o para que possa instalar o [ProductName]. + + O Microsoft .NET Framework 3.5 é exigido para instalar o produto [ProductName]. Use o "Assistente Adicionar Recursos" no Gerenciador do Servidor para instalar os Recursos do .NET Framework 3.5.1 ou use a opção "Ativar ou desativar os recursos do Windows" para ativar o Microsoft .NET Framework 3.5. + + + + Gerenciamento de Direitos Digitais do IIS + Beta + Habilita o Gerenciamento de Direitos Digitais de apresentações de Smooth Streaming. + + + O ASP.NET Não Está Instalado + + + + + + + + + O IIS Smooth Streaming - Beta foi encontrado no computador. Não é possível continuar a instalação do [ProductName]. Para instalar o produto, use Adicionar/Remover Programas no Painel de Controle para remover o IIS Smooth Streaming - Beta. + Uma versão incompatível do IIS Media Services está no computador. Não é possível continuar a instalação do [ProductName]. Para instalar o produto, use Adicionar/Remover Programas no Painel de Controle para remover o IIS Media Services. + Uma versão mais recente do produto já está instalada ou disponível para instalação neste computador. Não é possível continuar a instalação do [ProductName]. Para instalar a versão mais recente do produto, use Adicionar/Remover Programas no Painel de Controle para atualizar o IIS Media Services. + Conversão do Arquivo da Lista de Reprodução Necessária + + + + + Arquivos Antigos do IIS Media Services Encontrados + + + + + Arquivos do IIS Media Services Beta Encontrados + + + + + + IIS Media Pack 1.0 + Atualização para o IIS Media Pack 1.0 + IIS Media Services 2.0 + Atualização para o IIS Media Services 2.0 + IIS Media Services 3.0 + IIS Media Services 3.0 TAP 2 + Atualização para o IIS Media Services 3.0 + Recursos e ferramentas do IIS Media Services. + Recursos e ferramentas do IIS Media Services 5 Premium. + IIS Media Services 4.0 Beta 1 + IIS Media Services 4.0 + IIS Media Services 4.5 Beta 1 + IIS Media Services 5 Premium + + Web Playlists + Controla a reprodução no cliente de ativos de mídia referenciados em listas de reprodução. + Auxiliar de Sessão + Habilita a persistência do estado de sessão do ASP.NET. (Requer o serviço de função do ASP.NET para o Servidor Web (IIS)). + Interface do Usuário + Configura o recurso Web Playlists no Gerenciador do IIS. + + Limitação da Taxa de Bits + Economiza largura de banda limitando a entrega de arquivos baixados por clientes. + Interface do Usuário + Configura o recurso Limitação da Taxa de Bits no Gerenciador do IIS. + + Ativos + Habilita o streaming HTTP adaptável de ativos por demanda para clientes. + Interface do Usuário + Configura o recurso Smooth Streaming no Gerenciador do IIS. + + Canais + Habilita o streaming HTTP adaptável de difusões de canais para clientes. + Interface do Usuário + Configura o recurso Live Smooth Streaming no Gerenciador do IIS. + + Gerenciamento de Direitos Digitais + Fornece criptografia e licenciamento de mídia Smooth Streaming. + Interface do Usuário + Configura o recurso de Gerenciamento de Direitos Digitais no Gerenciador do IIS. + + O [ProductName] requer o Microsoft Windows Vista Service Pack 1 ou posterior. + Não é possível instalar o [ProductName] no Vista Home Basic. + O [ProductName] requer o Microsoft Windows 7 Service Pack 1 ou posterior. + + + Gerenciador de Banco de Dados do IIS + Gerenciador de Banco de Dados do IIS + + + Serviço de Gerenciamento da Web 2 da Microsoft + Serviço de Gerenciamento da Web da Microsoft + Instala os recursos básicos do [ProductName]. + Serviço de Gerenciamento da Web 2 da Microsoft + O Serviço de Gerenciamento da Web habilita recursos de gerenciamento remotos e delegados para que os administradores gerenciem o servidor Web, os sites e os aplicativos presentes neste computador. + + + Módulo 1.1 de Reescrita de URL da Microsoft para IIS 7 + Atualização do Módulo 1.1 de Reescrita de URL para IIS 7 + Reescrita de URL + Habilita os recursos de reescrita de conteúdo e URL do IIS 7. + Interface do Usuário + Configura o recurso do Módulo de Reescrita de URL no Gerenciador do IIS. + + + Módulo 2 de Reescrita de URL do IIS + Atualização do Módulo 2 de Reescrita de URL do IIS + Reescrita de URL + Habilita os recursos de reescrita de conteúdo e URL do IIS 7. + Interface do Usuário + Configura o recurso do Módulo de Reescrita de URL no Gerenciador do IIS. + + + Administration Pack para IIS 7.0 + Instala os recursos básicos do [ProductName]. + 1252 + Administration Pack para IIS 7.0 + Microsoft Corporation + Não há suporte a esta versão do sistema operacional. Só é possível instalar o [ProductName] no Windows Server 2008 ou no Windows Vista Service Pack 1 ou posterior. + Recursos do ASP.Net + O ASP.NET inclui os recursos Páginas de Erro e Autorização, que permitem o gerenciamento das configurações de erro personalizadas e de autorizações. + Autenticação + Descrição da Autenticação do ASP.Net. + Autorização + A Autorização do ASP.NET permite a configuração de regras para autorizar usuários a acessar seus sites e aplicativos. + Páginas de Erro + As Páginas de Erro do ASP.NET permitem a configuração de respostas de erro de HTTP retornadas quando um erro ocorre. + Módulos + Descrição dos Módulos do ASP.Net. + Manipuladores + Descrição dos Manipuladores do ASP.Net. + Editor de Configurações + O Editor de Configurações permite o gerenciamento de arquivos de configuração no Gerenciador do IIS por meio da edição de seções, atributos, elementos e coleções nos arquivos de configuração. + Filtragem de Solicitações + A Filtragem de Solicitações permite a configuração de regras de filtragem para o seu site, protocolo restrito e comportamento de conteúdo. + FastCGI + O FastCGI permite a definição de configurações do pool de processos para os aplicativos FastCGI no servidor Web. + + + Instalação de Restrições de IP Dinâmico para IIS 7 + + + + + + + + + + + + + Restrições de IP Dinâmico para IIS 7 - Beta + Restrições de IP Dinâmico para IIS 7 - Beta 2 + Restrições de IP Dinâmico para IIS 7 - Beta 3 + + Restrições de IP Dinâmico para IIS 7 - Versão Release Candidate + Restrições de IP Dinâmico para IIS 7 - Versão Release Candidate 2 + Restrições de IP Dinâmico para IIS 7 - Versão Release Candidate 3 + + Restrições de IP Dinâmico para IIS 7 - RTW + + Restrições de IP Dinâmico para IIS 7 + Interface do Usuário de Restrições de IP Dinâmico para IIS 7 + + Restrições de IP Dinâmico para IIS 7 - Beta encontradas neste computador. Desinstale-as e tente novamente + + + WebDAV 7.5 para IIS 7.0 + Os recursos CoreWebEngine e W3SVC do IIS 7.0 devem ser instalados para usar este produto. + Módulo do Servidor WebDAV + Interface do Usuário de Administração do WebDAV + + + Toolkit de Otimização do Mecanismo de Pesquisa do IIS 1.0 + Toolkit de Otimização do Mecanismo de Pesquisa do IIS 1.0 + Toolkit de SEO (Otimização do Mecanismo de Pesquisa) 1.0 + Este banco de dados de instalador contém a lógica e os dados necessários para instalar o Kit de Ferramentas de Otimização do Mecanismo de Pesquisa do IIS 1.0. + + + Editor do IIS + + + Relatórios do IIS + O Analisador de Log não foi instalado neste computador. Instale o Analisador de Log 2.2 de http://www.microsoft.com/downloads/details.aspx?FamilyID=890cd06b-abf8-4c25-91b2-f8d975cf8c07 e continue a instalação dos Relatórios do IIS + + + Os pacotes de pré-requisito não foram encontrados. Execute setup.exe para resolver as dependências e instalar o programa. + O Microsoft SQL Server 2008 Management Objects é um pré-requisito para a instalação do Gerenciador de Banco de Dados do IIS. É possível instalar o Microsoft SQL Server 2008 Management Objects de http://go.microsoft.com/fwlink/?LinkID=150946. + Os Microsoft SQL Server System CLR Types são um pré-requisito para a instalação do Gerenciador de Banco de Dados do IIS. É possível instalar os Microsoft SQL Server System CLR Types de http://go.microsoft.com/fwlink/?LinkID=150949. + + + Microsoft Web Farm Framework + Microsoft External Cache + O Web Farm Framework é um requisito para a instalação do Application Request Routing. Instale o Web Farm Framework. + Microsoft Application Request Routing 2.5 + Tempo de Execução + Adiciona os recursos de Roteamento de Solicitações de Aplicativo no IIS. + Interface do Usuário + Configura o recurso de Roteamento de Solicitações de Aplicativo no Gerenciador do IIS. + + + Snap-in do Microsoft Windows PowerShell para o IIS 7.0 + + + Microsoft Web Platform Installer 4.0 + Microsoft Web Platform Installer + O [ProductName] requer o Windows XP SP2, o Windows 2003 SP1, o Windows Vista ou posterior. + O [ProductName] exige o Windows XP Service Pack 3, o Windows Server 2003 Service Pack 2 ou versão posterior. + + + Instalador de Serviços do Microsoft Windows Azure + Instalador de Serviços do Microsoft Windows Azure + + + Gerenciador do IIS (Serviços de Informações da Internet) 7+ + Cliente do Gerenciador do IIS + Suporte Remoto + Este produto requer o Windows XP SP2, o Windows 2003 SP1, o Windows Vista SP1, o Windows 7 ou mais recente + O Console de Gerenciamento do IIS não foi instalado, mas é necessário para o gerenciamento de servidores remotos do IIS. Para instalar o Console de Gerenciamento do IIS antes de instalar o suporte de gerenciamento remoto, abra o 'Painel de Controle->Programas->Ativar ou Desativar Recursos do Windows' e selecione o Console de Gerenciamento do IIS no recurso Serviços de Informações da Internet. + Este produto não é necessário no Windows Server 2008 ou no Windows Server 2008 R2 ou mais recente. Para instalar o Console de Gerenciamento do IIS, abra o Gerenciador do Servidor e selecione o Console de Gerenciamento do IIS em Serviços de Função para a Função de Servidor Web. + + + IIS Manager Publishing para IIS 7.0 + Interface do Usuário de Publicação + + + Application Warm-Up 1.0 para IIS 7.5 + + + + Este computador contém um produto incompatível, [CONFLICTING_PRODUCT_NAME]. A instalação do [ProductName] não pode continuar. Para instalar esse produto, use Adicionar/Remover Programas no Painel de Controle para remover o [CONFLICTING_PRODUCT_NAME]. + São necessários privilégios de Administrador para instalar o [ProductName]. + É necessário o IIS Versão 7.0 para usar o [ProductName]. + É necessário o IIS Versão 7.0 ou posterior para instalar o [ProductName]. + É necessário o IIS Versão 7.5 ou posterior para instalar o [ProductName]. + É necessário o IIS versão 7 ou 7.5 para instalar o [ProductName]. + A versão beta do [ProductName] foi encontrada no computador. + Uma versão mais recente do [ProductName] foi encontrada no computador. + Não é possível continuar a instalação, pois outra instância do [ProductName] já está instalada no computador. Desinstale a versão antiga e reinicie a instalação. + Os recursos CoreWebEngine e W3SVC do IIS 7.0 devem estar instalados para usar o [ProductName]. + O Console de Gerenciamento do IIS deve estar instalado para usar o [ProductName]. + Interrompa o WAS (Serviço de Ativação de Processos do Windows) e o WMSvc (Serviço de Gerenciamento da Web) antes de instalar o [ProductName]. Será necessário instalar os serviços após a instalação do [ProductName]. + É necessária a Metabase do IIS para instalar o [ProductName]. + Não é possível instalar a versão de 64 bits do [ProductName] em uma edição de 32 bits do Microsoft Windows. + Não é possível instalar a versão de 32 bits do [ProductName] em uma edição de 64 bits do Microsoft Windows. + É necessário o Microsoft .NET Framework Versão 2.0 ou posterior para instalar o [ProductName]. + O Microsoft .NET Framework Versão 3.5 ou posterior é necessário para instalar o [ProductName]. Use 'Adicionar Recursos' no Gerenciador do Servidor para instalar o Microsoft .Net Versão 3.5. + O Microsoft .NET Framework Versão 4.0 ou posterior é necessário para instalar o [ProductName]. + Instale o Microsoft .NET Framework Service Pack 1 Versão 2.0, ou um service pack posterior, antes de instalar o [ProductName]. + Não é possível desabilitar o serviço Windows Update (wuauserv), pois ele é necessário para instalar o [ProductName]. + O snap-in do PowerShell é parte o Sistema Operacional Windows. Instale o snap-in por meio dos 'Programas e Recursos' ou 'Gerenciador do Servidor'. + O Microsoft Web Platform Installer Versão 3.0 ou posterior é necessário para instalar o [ProductName]. + + A instalação não detectou configurações compartilhadas. + A configuração compartilhada está habilitada para o IIS. Não há suporte à instalação do [ProductName] quando é usada uma configuração compartilhada. Desabilite a configuração compartilhada antes de instalar este recurso. + + Interrompa o Serviço de Publicação na World Wide Web (W3SVC) antes de instalar o [ProductName]. Será necessário iniciar o serviço após a instalação. + Console de Gerenciamento do PowerShell do IIS + Snap-in do PowerShell do IIS + O snap-in do PowerShell do IIS requer o PowerShell versão 1.0 ou 2.0 instalado + O snap-in do PowerShell do IIS requer WAS e configuração instalados + Cadeia de caracteres inválida. + + + Estrutura do Microsoft Web Farm Versão 2.2 + Agente do Microsoft Web Farm Versão 2.2 + Serviço de Web Farm + Serviço de Web Farm + Serviço Controlador de Web Farm + Serviço Controlador de Web Farm + Serviço de Agente de Web Farm + Serviço de Agente de Web Farm + O Web Plaform Installer é um pré-requisito para instalar a Estrutura do Web Farm. Instale o Web Plaform Installer a partir de http://www.microsoft.com/web/downloads/platform.aspx. + A Ferramenta de Implantação da Web é um pré-requisito para instalar a Estrutura do Web Farm. Instale a Ferramenta de Implantação da Web a partir de http://www.iis.net/download/WebDeploy. + + + Estrutura de Hospedagem na Web da Microsoft + Estrutura de Hospedagem na Web + Funções e recursos de Hospedagem na Web. + Estrutura de Hospedagem + A Estrutura de Hospedagem oferece comandos de API e PowerShell para gerenciamento de Hospedagem na Web. + Função da Web + A Função Web instala o serviço WAS Dinâmico e o provedor de Reescrita de URL de Hospedagem na Web. + Antares Express + Implanta uma configuração do Painel de Controle otimizada para configuração de máquina única. + Função do Balanceador de Carga + A Função do Balanceador de Carga configura o Roteador de Solicitação de Aplicativo para rotear com base nas regras de Hospedagem na Web. + Controlador de Hospedagem + O Controlador de Hospedagem estende a Estrutura do Web Farm 2.0 para trabalhar com Hospedagem na Web. + Função de Publicação + Instala suporte para Implantação da Web e publicação em FTP. + Este é um snap-in do PowerShellque contém cmdlets para gerenciar a infraestrutura de Hospedagem na Web da Microsoft. + Serviço WAS Dinâmico + Serviço de Ativação de Processos do Windows otimizado para Hospedagem na Web de alta densidade. + Serviço de Medição de Recursos + Instala o serviço de Medição de Recursos que habilita a coleta e a publicação de informações de integridade e tempo de execução. + Medição de Recursos + Habilita a coleta e a publicação de informações de tempo de execução e integridade a partir da Função Web. + Imposição de Cota de Hospedagem + Monitora o uso de recursos de sites e executa ações personalizadas quando a cota de uso é excedida. + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/RUS/misc/setupstrings.wxl b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/RUS/misc/setupstrings.wxl new file mode 100644 index 0000000000..e9613c04ec --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/RUS/misc/setupstrings.wxl @@ -0,0 +1,351 @@ + + + + + + + 1049 + + + + Параметры установки общей конфигурации + Выбор параметров установки общей конфигурации IIS + Обновить общую конфигурацию при установке + Вы устанавливаете этот модуль на сервер IIS, использующий общую конфигурацию. Если дополнительные серверы IIS используют эту общую конфигурацию, вам необходимо установить этот модуль на все эти компьютеры. Чтобы минимизировать нарушение работы отдельных веб-серверов, вам потребуется устанавливать этот модуль в соответствии с шагами, описанными ниже. Сначала следует установить модуль на все компьютеры, кроме последнего, не обновляя при этом общую конфигурацию. Для этого не устанавливайте флажок ниже. +При этом на каждый компьютер будут установлены все файлы, необходимые для модуля, но не будет изменена общая конфигурация. Затем на последнем компьютере следует убедиться в том, что у используемой для работы учетной записи есть права чтения и записи файла applicationhost.config, расположенного на общем ресурсе UNC. Затем следует установить модуль и установить флажок "Обновить общую конфигурацию" ниже. + + + Инициализируется настраиваемое действие WebConfig + Обновляется файл web.config + + + + Расширенное ведение журнала IIS + Обеспечивает расширенные возможности ведения журнала данных конвейера IIS. + Расширенное ведение журнала IIS + Позволяет создавать настраиваемые файлы журналов с расширяемым набором полей. + Обновление для расширенного ведения журнала + + + + IIS Transform Manager + Бета-версия + Включает диспетчер Transform Manager IIS Media Services. + IIS Transform Manager + Включает создание преобразований мультимедиа. + Узел диспетчера IIS Transform Manager + Узел службы для [ProductName]. + IIS Transform Manager + Пакетное преобразование файлов мультимедиа в альтернативные форматы файлов и контейнеров по запросу. + На компьютере установлен пакет задач IIS Transform Manager 1.0 Expression Encoder SP. Его следует удалить перед установкой [ProductName]. + + Microsoft .NET Framework 3.5 требуется для установки [ProductName]. Используйте мастер добавления компонентов в диспетчере сервера, чтобы установить компоненты .NET Framework 3.5.1, или используйте параметр "Включение или отключение компонентов Windows", чтобы включить Microsoft .NET Framework 3.5. + + + + IIS: управление цифровыми правами + Бета-версия + Включает управление цифровыми правами для презентаций Smooth Streaming. + + + ASP.NET не установлен + + + + + + + + + На компьютере обнаружена бета-версия IIS Smooth Streaming. Установка [ProductName] не будет продолжена. Чтобы установить этот продукт, используйте компонент "Установка и удаление программ" панели управления для удаления бета-версии IIS Smooth Streaming. + На компьютере имеется несовместимая версия служб IIS Media Services. Установка [ProductName] не будет продолжена. Чтобы установить этот продукт, используйте компонент "Установка и удаление программ" панели управления для удаления служб IIS Media Services. + Более новая версия этого продукта уже установлена или доступна для установки на этом компьютере. Установка [ProductName] не будет продолжена. Чтобы установить более новую версию этой программы, используйте элемент панели управления "Установка и удаление программ" для обновления служб мультимедиа IIS. + Необходимо преобразовать файл списка воспроизведения + + + + + Обнаружены старые файлы служб IIS Media + + + + + Обнаружены старые файлы бета-версии служб IIS Media + + + + + + IIS Media Pack 1.0 + Обновление для IIS Media Pack 1.0 + IIS Media Services 2.0 + Обновление для IIS Media Services 2.0 + IIS Media Services 3.0 + IIS Media Services 3.0 TAP 2 + Обновление для IIS Media Services 3.0 + Средства и компоненты IIS Media Services. + Средства и компоненты IIS Media Services 5 Premium. + Бета-версия 1 служб IIS Media Services 4.0 + Службы IIS Media Services 4.0 + Бета-версия 1 служб IIS Media Services 4.5 + IIS Media Services 5 Premium + + Веб-списки воспроизведения + Управляет воспроизведением клиентами данных мультимедиа, на которые есть ссылки в списках воспроизведения. + Модуль поддержки сеансов + Поддерживает сохранение сеансов ASP.NET. (Требуется служба роли ASP.NET ля веб-сервера (IIS)). + Пользовательский интерфейс + Настройка компонента веб-списков воспроизведения в диспетчере IIS. + + Регулирование скорости + Экономия полосы пропускания путем регулирования доставки файлов, загружаемых клиентами. + Пользовательский интерфейс + Настройка функции регулирования скорости в диспетчере IIS. + + Файлы + Поддерживает адаптивную потоковую передачу файлов по запросу клиентам. + Пользовательский интерфейс + Настройка Smooth Streaming в диспетчере IIS. + + Каналы + Поддерживает адаптивную потоковую передачу при канальной широковещательной трансляции клиентам. + Пользовательский интерфейс + Настраивает компонент Live Smooth Streaming в диспетчере IIS. + + Управление цифровыми правами + Обеспечивает шифрование и лицензирование содержимого Smooth Streaming. + Пользовательский интерфейс + Настройка функции управления цифровыми правами в диспетчере IIS. + + Для [ProductName] требуется Microsoft Windows Vista с пакетом обновления 1 (SP1) или более поздней версии. + Невозможно установить [ProductName] в операционной системе Vista Home Basic. + Для [ProductName] требуется Microsoft Windows 7 с пакетом обновления 1 (SP1) или более поздней версии. + + + Диспетчер баз данных IIS + Диспетчер баз данных IIS + + + Служба веб-управления 2 (Майкрософт) + Служба веб-управления (Майкрософт) + Установка основных компонентов [ProductName]. + Служба веб-управления 2 (Майкрософт) + Служба управления сетью предоставляет для администраторов удаленные и делегированные возможности управления веб-сервером, сайтами и приложениями, существующими на данном компьютере. + + + Модуль 1.1 видоизменения URL-адресов (Майкрософт) для IIS 7 + Обновление для модуля 1.1 видоизменения URL-адресов для IIS 7 + Видоизменение URL-адресов + Включает функции, отвечающие за видоизменение URL-адресов и содержимого в IIS 7. + Пользовательский интерфейс + Настраивает компонент "модуль видоизменения URL-адресов" в диспетчере служб IIS. + + + Модуль переопределения URL-адресов 2 для IIS + Обновление для модуля 2 переопределения URL-адресов для IIS + Видоизменение URL-адресов + Включает функции, отвечающие за видоизменение URL-адресов и содержимого в IIS 7. + Пользовательский интерфейс + Настраивает компонент "модуль видоизменения URL-адресов" в диспетчере служб IIS. + + + Пакет администрирования IIS 7.0 + Установка основных компонентов [ProductName]. + 1251 + Пакет администрирования IIS 7.0 + Корпорация Майкрософт + Эта версия операционной системы не поддерживается. [ProductName] можно установить только в Windows Server 2008 или Windows Vista с пакетом обновления 1 (SP1) или более поздних версий. + Компоненты ASP.Net + В ASP.NET содержатся компоненты авторизации и страниц ошибок, позволяющие управлять параметрами авторизации и настраиваемых сообщений об ошибках. + Проверка подлинности + Описание проверки подлинности ASP.Net. + Авторизация + Модуль проверки подлинности ASP.NET позволяет настраивать правила проверки подлинности пользователей для доступа к веб-сайтам и приложениям. + Страницы ошибок + Страницы ошибок ASP.NET позволяют настраивать отклики на ошибки HTTP, отображаемые при возникновении таких ошибок. + Модули + Описание модулей ASP.Net. + Обработчики + Описание обработчиков ASP.Net. + Редактор конфигураций + Редактор конфигурации позволяет управлять файлами конфигурации в диспетчере IIS, обеспечивая возможность изменять разделы, атрибуты, элементы и семейства в файлах конфигурации. + Фильтрация запросов + Фильтрация запросов позволяет настраивать правила фильтрации для веб-сайта, ограничивать поведение протоколов и содержимого. + Fast CGI + FastCGI позволяет настраивать параметры пула процессов для приложений FastCGI на веб-сервере. + + + Программа установки ограничения динамических IP-адресов для IIS 7 + + + + + + + + + + + + + Ограничения динамических IP-адресов для IIS 7 - бета-версия + Ограничения динамических IP-адресов для IIS 7 - бета-версия 2 + Ограничения динамических IP-адресов для IIS 7 - бета-версия 3 + + Ограничения динамических IP-адресов для IIS 7 - версия-кандидат + Ограничения динамических IP-адресов для IIS 7 - версия-кандидат 2 + Ограничения динамических IP-адресов для IIS 7 - версия-кандидат 3 + + Ограничения динамических IP-адресов для IIS 7 - рабочий выпуск + + Ограничения динамических IP-адресов для IIS 7 + Пользовательский интерфейс ограничения динамических IP-адресов для IIS 7 + + Ограничения динамического IP-адреса для IIS 7 - на компьютере обнаружена бета-версия. Удалите ее и повторите попытку + + + WebDAV 7.5 для IIS 7.0 + Для использования этого продукта необходимо установить компоненты IIS 7.0 CoreWebEngine и W3SVC. + Серверный модуль WebDAV + Пользовательский интерфейс администрирования WebDAV + + + Инструменты оптимизации IIS Search Engine 1.0 + Инструменты оптимизации IIS Search Engine 1.0 + Инструменты оптимизации Search Engine (SEO) 1.0 + Эта база данных установщика содержит логику и данные, необходимые для установки инструментов оптимизации IIS Search Engine 1.0. + + + Редактор IIS + + + Отчеты IIS + Программа Log Parser не установлена на этом компьютере. Установите программу Log Parser 2.2 с сайта http://www.microsoft.com/downloads/details.aspx?FamilyID=890cd06b-abf8-4c25-91b2-f8d975cf8c07, затем установите отчеты IIS. + + + Необходимые компоненты не найдены. Запустите setup.exe, чтобы установить необходимые зависимые компоненты и установить эту программу. + Управляющие объекты Microsoft SQL Server 2008 являются необходимым условием для установки диспетчера базы данных IIS. Управляющие объекты Micrsoft SQL Server 2008 можно установить на странице http://go.microsoft.com/fwlink/?LinkID=150946. + Системные типы Microsoft SQL Server System CLR Types являются необходимым условием для установки диспетчера базы данных IIS. Системные типы Microsoft SQL Server System CLR Types можно установить на странице http://go.microsoft.com/fwlink/?LinkID=150949. + + + Microsoft Web Farm Framework + Microsoft External Cache + Для установки маршрутизации запросов приложений требуется установить платформу веб-фермы. Установите платформу веб-фермы. + Microsoft Application Request Routing 2.5 + Среда выполнения + Добавляет функции маршрутизации запросов приложений в IIS. + Пользовательский интерфейс + Настраивает функцию маршрутизации запросов приложений в диспетчере IIS. + + + Оснастка Microsoft Windows PowerShell для IIS 7.0 + + + Установщик веб-платформы Майкрософт 4.0 + Установщик веб-платформы Майкрософт + Для [ProductName] требуется Windows XP SP2, Windows 2003 SP1, Windows Vista или более поздняя версия. + Для [ProductName] требуется Windows XP с пакетом обновления 3, Windows Server 2003 с пакетом обновления 2, или более поздние версии. + + + Установщик служб Microsoft Windows Azure + Установщик служб Microsoft Windows Azure + + + Диспетчер служб IIS 7+ + Клиент диспетчера IIS + Поддержка удаленной работы + Для этого продукта требуется Windows XP с пакетом обновления 2 (SP2), Windows 2003 с пакетом обновления 1 (SP1), Windows Vista с пакетом обновления 1 (SP1), Windows 7 или более новая система + Консоль управления IIS не установлена, но она необходима для управления удаленными серверами IIS. Установите консоль управления IIS перед установкой поддержки удаленного управления. Для этого в панели управления откройте "Программы", "Включение или отключение компонентов Windows", и выберите консоль управления IIS среди компонентов IIS. + Этот продукт не требуется при использовании Windows Server 2008, Windows Server 2008 R2 и более новых систем. Установите консоль управления IIS, открыв диспетчер сервера и выбрав консоль управления IIS в службах ролей для роли веб-сервера. + + + Публикация диспетчера IIS 7.0 + Пользовательский интерфейс публикации + + + Application Warm-Up 1.0 для IIS 7.5 + + + + На компьютере установлен несовместимый продукт: [CONFLICTING_PRODUCT_NAME]. Установку [ProductName] продолжить невозможно. Чтобы установить этот продукт, удалите CONFLICTING_PRODUCT_NAME] в разделе "Добавление и удаление программ" в панели управления. + Для установки [ProductName] требуются права администратора. + Для использования [ProductName] требуется IIS версии 7.0. + Для установки [ProductName] требуется IIS версии 7.0 или более поздней. + Для установки [ProductName] требуется IIS версии 7.5 или более поздней. + Для установки [ProductName] требуется IIS версии 7 или 7.5. + На компьютере обнаружена бета-версия [ProductName]. + На компьютере обнаружена более поздняя версия [ProductName]. + Программа установки не может продолжить работу, поскольку на компьютере уже установлен другой экземпляр [ProductName]. Удалите его, затем заново запустите эту установку. + Для использования [ProductName] необходимо установить компоненты IIS 7.0 CoreWebEngine и W3SVC. + Для использования [ProductName] требуется установить консоль управления IIS. + Перед установкой [ProductName] остановите службу активации Windows (WAS) и службу веб-управления (WMSvc). Эти службы нужно будет запустить после установки [ProductName]. + Для установки [ProductName] требуется метабаза IIS. + 64-разрядную версию [ProductName] нельзя установить на 32-разрядный выпуск Microsoft Windows. + 32-разрядную версию [ProductName] нельзя установить на 64-разрядный выпуск Microsoft Windows. + Для установки [ProductName] требуется Microsoft .NET Framework версии 2.0 или более поздней. + Для установки [ProductName] требуется Microsoft .NET Framework версии 3.5 или более поздней. Воспользуйтесь функцией диспетчера сервера "Добавить функции", чтобы установить Microsoft .Net версии 3.5. + Для установки [ProductName] требуется Microsoft .NET Framework версии 4.0 или более поздней. + Перед установкой [ProductName] установите Microsoft .NET Framework версии 2.0 с пакетом обновления 1 (SP1)или более поздним. + Службу Windows Update (wuauserv) невозможно отключить, она необходима для установки [ProductName]. + Оснастка PowerShell является частью операционной системы Windows. Установите ее с помощью элемента панели управления "Программы и компоненты" или диспетчера сервера. + Для установки [ProductName] требуется установщик веб-платформы Майкрософт, версии 3.0 или более поздней. + + Программа установки не обнаружила общую конфигурацию. + Для IIS включена общая конфигурация. Установка [ProductName] не поддерживается при использовании общей конфигурации. Отключите общую конфигурацию перед установкой этого компонента. + + Перед установкой [ProductName] необходимо остановить службу веб-публикаций (W3SVC). Эту службу нужно будет включить после установки. + Консоль управления IIS PowerShell + Оснастка IIS PowerShell + Для оснастки IIS PowerShell требуется PowerShell v1.0 или v2.0 + Для оснастки IIS PowerShell требуется установить WAS и конфигурацию + Пустая строка. + + + Платформа веб-ферм Майкрософт 2.2 + Агент веб-ферм Майкрософт 2.2 + Служба Web Farm Service + Служба Web Farm Service + Служба Web Farm Controller Service + Служба Web Farm Controller Service + Служба Web Farm Agent Service + Служба Web Farm Agent Service + Установщик веб-платформы является необходимым компонентом для установки платформы веб-ферм. Установите установщик веб-платформы с сайта http://www.microsoft.com/web/downloads/platform.aspx. + Инструмент веб-развертывания является необходимым компонентом для установки платформы веб-ферм. Установите инструмент веб-развертывания с сайта http://www.iis.net/download/WebDeploy. + + + Платформа веб-размещения Майкрософт + Платформа веб-размещения + Роли и компоненты веб-размещения. + Платформа размещения + Платформа размещения предоставляет API и команды PowerShell для управления веб-размещением. + Веб-роль + Веб-роль устанавливает динамическую службу WAS и поставщик переопределения URL-адресов для веб-размещения. + Antares Express + Развертывание панели управления в конфигурации, оптимизированной для установки на одном компьютере. + Роль подсистемы балансировки нагрузки + Роль подсистемы балансировки нагрузки позволяет настроить в маршрутизаторе запросов приложений маршрутизацию на основе правил веб-размещения. + Контроллер размещения + Контроллер размещения расширяет платформу веб-ферм 2.0, позволяя ей работать с веб-размещением. + Публикация — роль + Установка средств поддержки веб-развертывания и FTP-публикации. + Эта оснастка PowerShell, которая содержит командлеты для управления инфраструктурой Microsoft Web Hosting. + Динамическая служба WAS + Служба активации Windows, оптимизированная для веб-размещения высокой плотности. + Служба контроля ресурсов + Установка службы контроля ресурсов, которая позволяет собирать и публиковать сведения о среде выполнения и работоспособности. + Resource Metering + Позволяет собирать с веб-роли сведения о среде выполнения и работоспособности и публиковать их. + Применение квот размещения + Служит для отслеживания использования ресурсов веб-сайтами и выполнения настраиваемых действий при превышении квот. + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/TRK/misc/setupstrings.wxl b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/TRK/misc/setupstrings.wxl new file mode 100644 index 0000000000..83599c3b1c --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/loc/TRK/misc/setupstrings.wxl @@ -0,0 +1,351 @@ + + + + + + + 1055 + + + + Paylaşılan Yapılandırma Yükleme Seçenekleri + IIS paylaşılan yapılandırmasına yükleme seçeneğini belirtin + Yüklerken paylaşılan yapılandırmayı güncelleştir + Bu modülü paylaşılan yapılandırma kullanan bir IIS sunucusuna yüklüyorsunuz. Bu paylaşılan yapılandırmayı kullanan ek IIS sunucuları varsa, bu modülü söz konusu makinelerin tümüne yüklemeniz gerekir. Web sunucularında oluşabilecek kesintileri en az indirmek için bu modülü şu adımları kullanarak yüklemeniz gerekir: İlk olarak, sonuncu hariç tüm makinelerde paylaşılan yapılandırmayı güncelleştirmeden modülü yüklemeniz gerekir. Bunu, aşağıdaki onay kutusunu seçmeden yapın. +Bu işlem, paylaşılan yapılandırmada hiçbir değişiklik yapmadan modül için gereken tüm ikili ve diğer dosyaları her bir makineye yükler. İkinci olarak, sonuncu makinede, altında çalıştığınız kullanıcı kimliğinin UNC paylaşımındaki applicationhost.config dosyasında okuma ve yazma erişimi olduğunu doğrulamalısınız. Sonra, modülü yüklemeli ve aşağıdaki paylaşılan yapılandırmayı güncelleştirme seçeneğini seçmeniz gerekir. + + + WebConfig özel eylemi başlatılıyor + web.config güncelleştiriliyor + + + + IIS Gelişmiş Günlüğü + IIS ardışık düzen verileri için gelişmiş günlüğü etkinleştirir. + IIS Gelişmiş Günlüğü + Genişletilebilir alan seçimi olan özel günlük dosyaları oluşturmaya olanak tanır. + IIS Gelişmiş Günlüğü Güncelleştirmesi + + + + IIS Dönüşüm Yöneticisi + Beta + Dönüşüm Yöneticisi IIS Medya Hizmetleri'ni etkinleştirir. + IIS Dönüşüm Yöneticisi + Medya dönüşümleri oluşturmayı etkinleştirir. + IIS Dönüşüm Yöneticisi Ana Bilgisayarı + [ProductName] için hizmet ana bilgisayarı. + IIS Dönüşüm Yöneticisi + İsteğe bağlı medya dosyalarını alternatif dosya ve kapsayıcı biçimlerine toplu olarak dönüştürün. + Bir IIS Transform Manager 1.0 Expression Encoder SP Task paketi bilgisayarda yüklü. [ProductName] ürününü yüklemeden önce bunu kaldırmalısınız. + + [ProductName] ürününü yüklemek için Microsoft .NET Framework 3.5 gereklidir. Sunucu Yöneticisi'ndeki 'Özellik Ekleme Sihirbazı'nı kullanarak .NET Framework 3.5.1 Özellikleri'ni yükleyin veya 'Windows özelliklerini aç veya kapat'ı kullanarak Microsoft .NET Framework 3.5'i açın. + + + + IIS Dijital Hak Yönetimi + Beta + Kesintisiz Akış sunularında Dijital Hak Yönetimini etkinleştirir. + + + ASP.NET Yüklü Değil + + + + + + + + + Bu bilgisayarda IIS Kesintisiz Akış - Beta bulundu. [ProductName] yüklemesi devam edemez. Bu ürünü yüklemek için, Denetim Masası'ndaki Program Ekle/Kaldır'ı kullanarak IIS Kesintisiz Akış - Beta'yı kaldırın. + Bu bilgisayarda IIS Medya Hizmetleri'nin uyumsuz bir sürümü var. [ProductName] yüklemesi devam edemez. Bu ürünü yüklemek için, Denetim Masası'ndaki Program Ekle/Kaldır'ı kullanarak IIS Medya Hizmetleri'ni kaldırın. + Bu ürünün daha yeni bir sürümü bu bilgisayarda yüklü veya bu bilgisayara yüklenebilir durumda. [ProductName] yüklemesi devam edemiyor. Bu ürünün yeni sürümünü yüklemek için, Denetim Masası'ndaki Program Ekle/Kaldır'ı kullanarak IIS Medya Hizmetleri'ni güncelleştirin. + Çalma Listesi Dosyasının Dönüştürülmesi Gerekiyor + + + + + Eski IIS Medya Hizmetleri Dosyaları Bulundu + + + + + Beta IIS Medya Hizmetleri Dosyaları Bulundu + + + + + + IIS Medya Paketi 1.0 + IIS Medya Paketi 1.0 Güncelleştirmesi + IIS Medya Hizmetleri 2.0 + IIS Medya Paketi 2.0 Güncelleştirmesi + IIS Medya Hizmetleri 3.0 + IIS Medya Hizmetleri 3.0 TAP 2 + IIS Medya Paketi 3.0 Güncelleştirmesi + IIS Medya Paketi özellikleri ve araçları. + IIS Media Services 5 Premium özellikleri ve araçları. + IIS Medya Hizmetleri 4.0 Beta 1 + IIS Medya Hizmetleri 4.0 + IIS Medya Hizmetleri 4.5 Beta 1 + IIS Media Services 5 Premium + + Web Çalma Listeleri + İstemcinin, çalma listelerinde başvurulan medya listelerini kayıttan yürütmesini denetler. + Oturum Yardımcısı + ASP.NET oturum durumu kalıcılığını etkinleştirir. (Web Sunucusu (IIS) için ASP.NET rol hizmetini gerektirir.) + Kullanıcı Arabirimi + IIS Yöneticisi'nde Web Çalma Listeleri özelliğini yapılandırır. + + Bit Hızı Azaltma + İstemcilerin karşıdan yüklediği dosyaların teslimini yavaşlatarak bant genişliğinden tasarruf sağlar. + Kullanıcı Arabirimi + IIS Yöneticisi'nde Bit Hızı Azaltma özelliğini yapılandırır. + + Varlıklar + İsteğe bağlı varlıkların istemcilere HTTP ile uyarlamalı akışını etkinleştirir. + Kullanıcı Arabirimi + IIS Yöneticisi'nde Kesintisiz Akış özelliğini yapılandırır. + + Kanallar + Kanal yayınlarının istemcilere HTTP ile uyarlamalı akışını etkinleştirir. + Kullanıcı Arabirimi + IIS Yöneticisi'nde Canlı Kesintisiz Akış özelliğini yapılandırır. + + Dijital Hak Yönetimi + Kesintisiz Akış medyası için şifreleme ve lisanslama sağlar. + Kullanıcı Arabirimi + IIS Yöneticisi'nde Dijital Hak Yönetimi özelliğini yapılandırır. + + [ProductName] için Microsoft Windows Vista Service Pack 1 veya üstü gereklidir. + [ProductName], Vista Home Basic üzerine yüklenemez. + [ProductName] için Microsoft Windows 7 Service Pack 1 veya üstü gereklidir. + + + IIS Veritabanı Yöneticisi + IIS Veritabanı Yöneticisi + + + Microsoft Web Yönetimi Hizmeti 2 + Microsoft Web Yönetimi Hizmeti + [ProductName] ürününün temel özelliklerini yükler. + Microsoft Web Yönetimi Hizmeti 2 + Web Yönetimi Hizmeti, yöneticilerin bu makinede bulunan Web sunucularını, siteleri ve uygulamaları yönetmeleri için uzaktan ve temsilci seçilmiş yönetim becerileri sağlar. + + + IIS 7 için Microsoft URL Yeniden Yazma Modülü 1.1 + IIS 7 için URL Yeniden Yazma Modülü 1.1 Güncelleştirmesi + URL Yeniden Yazma + IIS 7'nin URL ve içerik yeniden yazma yeteneklerini etkinleştirir. + Kullanıcı Arabirimi + IIS Yöneticisi'nde URL Yeniden Yazma Modülü özelliğini yapılandırır. + + + IIS URL Yeniden Yazma Modülü 2 + IIS URL Yeniden Yazma Modülü 2 Güncelleştirmesi + URL Yeniden Yazma + IIS 7'nin URL ve içerik yeniden yazma yeteneklerini etkinleştirir. + Kullanıcı Arabirimi + IIS Yöneticisi'nde URL Yeniden Yazma Modülü özelliğini yapılandırır. + + + IIS 7.0 için Yönetim Paketi + [ProductName] ürününün temel özelliklerini yükler. + 1254 + IIS 7.0 için Yönetim Paketi + Microsoft Corporation + İşletim sisteminin bu sürümü desteklenmiyor. [ProductName] yalnızca Windows Server 2008 ya da Windows Vista Service Pack 1 ve üstü üzerine yüklenebilir. + ASP.Net Özellikleri + ASP.NET, yetkilendirme ve özel hata ayarlarınızı yönetmenizi sağlayan Yetkilendirme ve Hata Sayfaları özelliklerini içerir. + Kimlik Doğrulaması + ASP.Net Kimlik Doğrulaması Açıklaması. + Yetkilendirme + ASP.NET Yetkilendirme, kullanıcılara Web sitelerinize ve uygulamalarınıza erişme yetkisi verme kurallarını yapılandırmanızı sağlar. + Hata Sayfaları + ASP.NET Hata Sayfaları, hata oluştuğunda döndürülen HTTP hata yanıtlarını yapılandırmanızı sağlar. + Modüller + ASP.Net Modülleri Açıklaması. + İşleyiciler + ASP.Net İşleyiciler Açıklaması. + Yapılandırma Düzenleyicisi + Yapılandırma Düzenleyicisi, IIS Yöneticisi'nde yapılandırma dosyalarındaki bölümleri, öznitelikleri, öğeleri ve koleksiyonları düzenlemenize olanak tanıyarak yapılandırma dosyalarınızı yönetmenizi sağlar. + İstek Filtreleme + İstek Filtreleme, Web siteniz için filtreleme kurallarını yapılandırmanızı, protokol ve içerik davranışını kısıtlamanızı sağlar. + FastCGI + FastCGI, Web sunucunuzdaki FastCGI uygulamaları için işlem havuzu ayarlarını yapılandırmanızı sağlar. + + + IIS 7 için Dinamik IP Kısıtlamaları Kurulumu + + + + + + + + + + + + + IIS 7 için Dinamik IP Kısıtlamaları - Beta + IIS 7 için Dinamik IP Kısıtlamaları - Beta 2 + IIS 7 için Dinamik IP Kısıtlamaları - Beta 3 + + IIS 7 için Dinamik IP Kısıtlamaları - Sürüm Adayı + IIS 7 için Dinamik IP Kısıtlamaları - Sürüm Adayı 2 + IIS 7 için Dinamik IP Kısıtlamaları - Sürüm Adayı 3 + + IIS 7 için Dinamik IP Kısıtlamaları - RTW + + IIS 7 için Dinamik IP Kısıtlamaları + IIS 7 için Dinamik IP Kısıtlamaları Kullanıcı Arabirimi + + Bu makinede IIS 7 - Beta için Dinamik IP Kısıtlamaları bulundu. Lütfen kaldırın ve yeniden deneyin + + + IIS 7.0 için WebDAV 7.5 + Bu ürünü kullanmak için IIS 7.0 CoreWebEngine ve W3SVC özellikleri yüklenmelidir. + WebDAV Sunucu Modülü + WebDAV Yönetimi Kullanıcı Arabirimi + + + IIS Arama Alt Yapısı İyileştirme Araç Seti 1.0 + IIS Arama Alt Yapısı İyileştirme Araç Seti 1.0 + Arama Alt Yapısı İyileştirme (SEO) Araç Seti 1.0 + Bu yükleyici veritabanı IIS Arama Alt Yapısı İyileştirme Araç Seti 1.0'ı yüklemek için gereken mantığı ve verileri içermektedir. + + + IIS Düzenleyicisi + + + IIS Raporları + Bu makinede Günlük Ayrıştırıcısı yüklü değil. Lütfen http://www.microsoft.com/downloads/details.aspx?FamilyID=890cd06b-abf8-4c25-91b2-f8d975cf8c07 adresinden Günlük Ayrıştırıcısı 2.2 sürümünü yükleyin ve sonra IIS Raporları yüklemesine devam edin + + + Önkoşul paketler bulunamadı. Bağımlılıkları çözümlemek ve bu programı yüklemek için lütfen setup.exe'yi çalıştırın. + Microsoft SQL Server 2008 Yönetim Nesneleri, IIS Veritabanı Yöneticisi'ni yüklemek için bir önkoşuldur. Microsoft SQL Server 2008 Yönetim Nesneleri'ni http://go.microsoft.com/fwlink/?LinkID=150946 adresinden yükleyebilirsiniz. + Microsoft SQL Server Sistem CLR Türleri, IIS Veritabanı Yöneticisi'ni yüklemek için bir önkoşuldur. Microsoft SQL Server Sistem CLR Türleri'ni http://go.microsoft.com/fwlink/?LinkID=150949 adresinden yükleyebilirsiniz. + + + Microsoft Web Grubu Çerçevesi + Microsoft Dış Önbellek + Web Grubu Çerçevesi, Uygulama İsteği Yönlendirme için bir önkoşuldur. Lütfen Web Grubu Çerçevesi'ni yükleyin. + Microsoft Uygulama İsteği Yönlendirme 2.5 + Çalışma Zamanı + IIS'ye Uygulama İsteği Yönlendirme özellikleri ekler. + Kullanıcı Arabirimi + IIS Yöneticisi'nde Uygulama İsteği Yönlendirme özelliğini yapılandırır. + + + IIS 7.0 için Microsoft Windows PowerShell ek bileşeni + + + Microsoft Web Platformu Yükleyicisi 4.0 + Microsoft Web Platformu Yükleyicisi + [ProductName] için Windows XP SP2, Windows 2003 SP1, Windows Vista veya üstü gereklidir. + [ProductName] için Windows XP Service Pack 3, Windows Server 2003 Service Pack 2 veya üstü gereklidir. + + + Microsoft Windows Azure Hizmetleri Yükleyicisi + Microsoft Windows Azure Hizmetleri Yükleyicisi + + + Internet Information Services (IIS) 7+ Yöneticisi + IIS Yöneticisi İstemcisi + Uzaktan İletişim Desteği + Bu ürün için Windows XP SP2, Windows 2003 SP1, Windows Vista SP1, Windows 7 veya daha üstü gereklidir + IIS Yönetim Konsolu yüklenmedi ancak uzak IIS Sunucularını yönetmek için gerekiyor. Uzaktan yönetim desteğini yüklemeden önce lütfen 'Denetim Masası -> Programlar -> Windows Özelliklerini Aç veya Kapat'ı açın ve Internet Information Services özelliğinde IIS Yönetimi Konsolu'nu seçin. + Bu ürün Windows Server 2008, Windows Server 2008 R2 veya daha üstünde gerekli değildir. IIS Yönetim Konsolu'nu yüklemek üzere lütfen Sunucu Yöneticisi'ni açın ve Web Sunucusu Rolü için Rol Hizmetleri'nde IIS Yönetim Konsolu'nu seçin. + + + IIS 7.0 için IIS Yöneticisi Yayımlama + Yayımlama Kullanıcı Arabirimi + + + IIS 7.5 için Application Warm-Up 1.0 + + + + Bu bilgisayarda uyumsuz bir ürün ([CONFLICTING_PRODUCT_NAME]) mevcut. [ProductName] ürününün yüklemesi devam edemiyor. Bu ürünü yüklemek için [CONFLICTING_PRODUCT_NAME] ürününü kaldırmak amacıyla Denetim Masası'ndaki Program Ekle/Kaldır'ı kullanın. + [ProductName] ürününü yüklemek için yönetici ayrıcalıkları gereklidir. + [ProductName] ürününü kullanmak için IIS Sürüm 7.0 gereklidir. + [ProductName] ürününü yüklemek için IIS Sürüm 7.0 veya üstü gereklidir. + [ProductName] ürününü yüklemek için IIS Sürüm 7.5 veya üstü gereklidir. + [ProductName] ürününü yüklemek için IIS Sürüm 7 veya 7.5 gereklidir. + Bu makinede [ProductName] ürününün beta sürümü bulundu. + Bu makinede [ProductName] ürününün daha yeni bir sürümü bulundu. + Bu bilgisayara başka bir [ProductName] örneği önceden yüklendiğinden Kurulum devam edemiyor. Lütfen önce onu kaldırın ve sonra bu yükleme işlemini yeniden başlatın. + [ProductName] ürününü kullanmak için IIS 7.0 CoreWebEngine ve W3SVC özellikleri yüklenmelidir. + [ProductName] ürününü kullanmak için IIS Yönetim Konsolu yüklenmelidir. + [ProductName] ürününü yüklemeden önce lütfen Windows İşlem Etkinleştirme Hizmeti (WAS) ve Web Yönetimi Hizmeti (WMSvc) hizmetlerinin ikisini de durdurun. [ProductName] yüklendikten sonra hizmetleri yeniden başlatmanız gerekir. + [ProductName] ürününü yüklemek için IIS Metatabanı gereklidir. + [ProductName] ürünün 64-bit sürümü Microsoft Windows'un 32-bit bir sürümüne yüklenemez. + [ProductName] ürünün 32-bit sürümü Microsoft Windows'un 64-bit bir sürümüne yüklenemez. + [ProductName] ürününü yüklemek için Microsoft .NET Framework Sürüm 2.0 veya üstü gereklidir. + [ProductName] ürününü yüklemek için Microsoft .NET Framework Sürüm 3.5 veya üstü gereklidir. Microsoft .Net Sürüm 3.5'i yüklemek için Sunucu Yöneticisi altındaki 'Özellik Ekle' seçeneğini kullanın. + [ProductName] ürününü yüklemek için Microsoft .NET Framework Sürüm 4.0 veya üstü gereklidir. + [ProductName] ürününü yüklemeden önce lütfen Microsoft .NET Framework Sürüm 2.0 Service Pack 1'i (veya daha yeni bir hizmet paketini) yükleyin. + Windows Update (wuauserv) hizmeti devre dışı bırakılamaz; [ProductName] ürününü yüklemek için gereklidir. + PowerShell ek bileşeni Windows İşletim Sisteminin bir parçasıdır. Lütfen 'Programlar ve Özellikler' veya 'Sunucu Yöneticisi' aracılığıyla yükleyin. + [ProductName] ürününü yüklemek için Microsoft Web Platformu Yükleyicisi 3.0 veya üstü gereklidir. + + Kurulum paylaşılan yapılandırmayı silemedi. + IIS için paylaşılan yapılandırma etkin. Paylaşılan yapılandırma kullanılırken [ProductName] ürününün yüklenmesi desteklenmiyor. Bu özelliği yüklemeden önce lütfen paylaşılan yapılandırmayı devre dışı bırakın. + + [ProductName] ürününü yüklemeden önce lütfen World Wide Web Yayımlama Hizmeti'ni (W3SVC) durdurun. Yükleme işleminden sonra hizmeti yeniden başlatmanız gerekir. + IIS PowerShell Yönetim Konsolu + IIS PowerShell ek bileşeni + IIS PowerShell ek bileşeni için PowerShell v1.0 veya v2.0 yüklü olmalıdır + IIS PowerShell ek bileşeni için WAS ve yapılandırma yüklü olmalıdır + Bu hatalı bir dizedir. + + + Microsoft Web Grubu Çerçevesi Sürüm 2.2 + Microsoft Web Grubu Aracısı Sürüm 2.2 + Web Grubu Hizmeti + Web Grubu Hizmeti + Web Grubu Denetleyicisi Hizmeti + Web Grubu Denetleyicisi Hizmeti + Web Grubu Aracısı Hizmeti + Web Grubu Aracısı Hizmeti + Web Grubu Çerçevesi'ni yüklemek için Web Platformu Yükleyicisi bir önkoşuldur. Lütfen http://www.microsoft.com/web/downloads/platform.aspx adresinden Web Platformu Yükleyicisi'ni yükleyin. + Web Grubu Çerçevesi'ni yüklemek için Web Dağıtım Aracı bir önkoşuldur. Lütfen http://www.iis.net/download/WebDeploy adresinden Web Dağıtımı Aracı'nı yükleyin. + + + Microsoft Web Barındırma Çerçevesi + Web Barındırma Çerçevesi + Web Barındırma rolleri ve özellikleri. + Barındırma Çerçevesi + Barındırma Çerçevesi, Web Barındırma'yı yönetmek için API'ler ve PowerShell komutları sağlar. + Web Rolü + Web Rolü, Web Barındırma için Dinamik WAS hizmetini ve URL Yeniden Yazma sağlayıcısını yükler. + Antares Express + Tek makineli kurulum için en iyi duruma getirilen bir Denetim Masası yapılandırmasını dağıtır. + Yük Dengeleyici Rolü + Yük Dengeleyici Rolü, Uygulama İstek Yönlendiricisini Web Barındırma kurallarına göre yönlendirecek şekilde yapılandırır. + Barındırma Denetleyicisi + Barındırma Denetleyicisi, Web Grubu Çerçevesi 2.0'ı Web Barındırma ile çalışacak şekilde genişletir. + Yayımlama Rolü + Web Dağıtımı ve FTP yayımlama için desteği yükler. + Bu, Microsoft Web Barındırma altyapısını yönetmeyi sağlayan cmdlet'ler içeren bir PowerShell ek bileşenidir. + Dinamik WAS Hizmeti + Yüksek yoğunluklu Web Barındırma için en iyi duruma getirilmiş Windows İşlem Etkinleştirme hizmeti. + Kaynak Ölçümü Hizmeti + Çalışma zamanı ve sistem bilgisi toplamayı ve yayımlamayı sağlayan Kaynak Ölçümü hizmetini yükler. + Kaynak Ölçümü + Web Rolünden çalışma zamanı ve sistem bilgisi toplamayı ve yayımlamayı sağlar. + Barındırma Kota Uygulama + Web sitesi kaynak kullanımını izler ve kullanım kotası aşıldığında özel eylemler uygular. + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/dutil.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/dutil.h new file mode 100644 index 0000000000..2a830b7c83 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/dutil.h @@ -0,0 +1,181 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#pragma once +//------------------------------------------------------------------------------------------------- +// +// Header for utility layer that provides standard support for asserts, exit macros +// +//------------------------------------------------------------------------------------------------- + +#define DAPI __stdcall +#define DAPIV __cdecl // used only for functions taking variable length arguments + +#define DAPI_(type) EXTERN_C type DAPI +#define DAPIV_(type) EXTERN_C type DAPIV + + +// enums +enum REPORT_LEVEL { + REPORT_NONE, // turns off report (only valid for XXXSetLevel()) + REPORT_STANDARD, // written if reporting is on + REPORT_VERBOSE, // written only if verbose reporting is on + REPORT_DEBUG, // reporting useful when debugging code + REPORT_ERROR, // always gets reported, but can never be specified + }; + +// asserts and traces +#ifdef DEBUG + +typedef BOOL (DAPI *DUTIL_ASSERTDISPLAYFUNCTION)(LPCSTR sz); + +extern "C" void DAPI Dutil_SetAssertModule(__in HMODULE hAssertModule); +extern "C" void DAPI Dutil_SetAssertDisplayFunction(__in DUTIL_ASSERTDISPLAYFUNCTION pfn); +extern "C" void DAPI Dutil_Assert(const CHAR* szFile, int iLine); +extern "C" void DAPI Dutil_AssertSz(const CHAR* szFile, int iLine, const CHAR *szMsg); + +extern "C" void DAPI Dutil_TraceSetLevel(__in REPORT_LEVEL ll, __in BOOL fTraceFilenames); +extern "C" REPORT_LEVEL DAPI Dutil_TraceGetLevel(); +extern "C" void __cdecl Dutil_Trace(__in LPCSTR szFile, __in int iLine, __in REPORT_LEVEL rl, __in LPCSTR szMessage, ...); +extern "C" void __cdecl Dutil_TraceError(__in LPCSTR szFile, __in int iLine, __in REPORT_LEVEL rl, __in HRESULT hr, __in LPCSTR szMessage, ...); + +#endif + +#if defined DEBUG + +#define AssertSetModule(m) (void)Dutil_SetAssertModule(m) +#define AssertSetDisplayFunction(pfn) (void)Dutil_SetAssertDisplayFunction(pfn) +#define Assert(f) ((f) ? (void)0 : (void)Dutil_Assert(__FILE__, __LINE__)) +#define AssertSz(f, sz) ((f) ? (void)0 : (void)Dutil_AssertSz(__FILE__, __LINE__, sz)) + +#define TraceSetLevel(l, f) (void)Dutil_TraceSetLevel(l, f) +#define TraceGetLevel() (REPORT_LEVEL)Dutil_TraceGetLevel() +#define Trace(l, f) (void)Dutil_Trace(__FILE__, __LINE__, l, f, NULL) +#define Trace1(l, f, s) (void)Dutil_Trace(__FILE__, __LINE__, l, f, s) +#define Trace2(l, f, s, t) (void)Dutil_Trace(__FILE__, __LINE__, l, f, s, t) +#define Trace3(l, f, s, t, u) (void)Dutil_Trace(__FILE__, __LINE__, l, f, s, t, u) + +#define TraceError(x, f) (void)Dutil_TraceError(__FILE__, __LINE__, REPORT_ERROR, x, f, NULL) +#define TraceError1(x, f, s) (void)Dutil_TraceError(__FILE__, __LINE__, REPORT_ERROR, x, f, s) +#define TraceError2(x, f, s, t) (void)Dutil_TraceError(__FILE__, __LINE__, REPORT_ERROR, x, f, s, t) +#define TraceError3(x, f, s, t, u) (void)Dutil_TraceError(__FILE__, __LINE__, REPORT_ERROR, x, f, s, t, u) + +#define TraceErrorDebug(x, f) (void)Dutil_TraceError(__FILE__, __LINE__, REPORT_DEBUG, x, f, NULL) +#define TraceErrorDebug1(x, f, s) (void)Dutil_TraceError(__FILE__, __LINE__, REPORT_DEBUG, x, f, s) +#define TraceErrorDebug2(x, f, s, t) (void)Dutil_TraceError(__FILE__, __LINE__, REPORT_DEBUG, x, f, s, t) +#define TraceErrorDebug3(x, f, s, t, u) (void)Dutil_TraceError(__FILE__, __LINE__, REPORT_DEBUG, x, f, s, t, u) + +#else // !DEBUG + +#define AssertSetModule(m) +#define AssertSetDisplayFunction(pfn) +#define Assert(f) +#define AssertSz(f, sz) + +#define TraceSetLevel(l, f) +#define Trace(l, f) +#define Trace1(l, f, s) +#define Trace2(l, f, s, t) +#define Trace3(l, f, s, t, u) + +#define TraceError(x, f) +#define TraceError1(x, f, s) +#define TraceError2(x, f, s, t) +#define TraceError3(x, f, s, t, u) + +#define TraceErrorDebug(x, f) +#define TraceErrorDebug1(x, f, s) +#define TraceErrorDebug2(x, f, s, t) +#define TraceErrorDebug3(x, f, s, t, u) + +#endif // DEBUG + + +// ExitTrace can be overriden +#ifndef ExitTrace +#define ExitTrace TraceError +#endif +#ifndef ExitTrace1 +#define ExitTrace1 TraceError1 +#endif +#ifndef ExitTrace2 +#define ExitTrace2 TraceError2 +#endif +#ifndef ExitTrace3 +#define ExitTrace3 TraceError3 +#endif + +// Exit macros +#define ExitFunction() { goto LExit; } +#define ExitFunction1(x) { x; goto LExit; } + +#define ExitOnLastError(x, s) { x = ::GetLastError(); x = HRESULT_FROM_WIN32(x); if (FAILED(x)) { ExitTrace(x, s); goto LExit; } } +#define ExitOnLastError1(x, f, s) { x = ::GetLastError(); x = HRESULT_FROM_WIN32(x); if (FAILED(x)) { ExitTrace1(x, f, s); goto LExit; } } +#define ExitOnLastError2(x, f, s, t) { x = ::GetLastError(); x = HRESULT_FROM_WIN32(x); if (FAILED(x)) { ExitTrace2(x, f, s, t); goto LExit; } } + +#define ExitOnLastErrorDebugTrace(x, s) { x = ::GetLastError(); x = HRESULT_FROM_WIN32(x); if (FAILED(x)) { TraceErrorDebug(x, s); goto LExit; } } +#define ExitOnLastErrorDebugTrace1(x, f, s) { x = ::GetLastError(); x = HRESULT_FROM_WIN32(x); if (FAILED(x)) { TraceErrorDebug1(x, f, s); goto LExit; } } +#define ExitOnLastErrorDebugTrace2(x, f, s, t) { x = ::GetLastError(); x = HRESULT_FROM_WIN32(x); if (FAILED(x)) { TraceErrorDebug2(x, f, s, t); goto LExit; } } + +#define ExitWithLastError(x, s) { x = ::GetLastError(); x = HRESULT_FROM_WIN32(x); if (!FAILED(x)) { x = E_FAIL; } ExitTrace(x, s); goto LExit; } +#define ExitWithLastError1(x, f, s) { x = ::GetLastError(); x = HRESULT_FROM_WIN32(x); if (!FAILED(x)) { x = E_FAIL; } ExitTrace1(x, f, s); goto LExit; } +#define ExitWithLastError2(x, f, s, t) { x = ::GetLastError(); x = HRESULT_FROM_WIN32(x); if (!FAILED(x)) { x = E_FAIL; } ExitTrace2(x, f, s, t); goto LExit; } + +#define ExitOnFailure(x, s) if (FAILED(x)) { ExitTrace(x, s); goto LExit; } +#define ExitOnFailure1(x, f, s) if (FAILED(x)) { ExitTrace1(x, f, s); goto LExit; } +#define ExitOnFailure2(x, f, s, t) if (FAILED(x)) { ExitTrace2(x, f, s, t); goto LExit; } +#define ExitOnFailure3(x, f, s, t, u) if (FAILED(x)) { ExitTrace3(x, f, s, t, u); goto LExit; } + +#define ExitOnFailureDebugTrace(x, s) if (FAILED(x)) { TraceErrorDebug(x, s); goto LExit; } +#define ExitOnFailureDebugTrace1(x, f, s) if (FAILED(x)) { TraceErrorDebug1(x, f, s); goto LExit; } +#define ExitOnFailureDebugTrace2(x, f, s, t) if (FAILED(x)) { TraceErrorDebug2(x, f, s, t); goto LExit; } +#define ExitOnFailureDebugTrace3(x, f, s, t, u) if (FAILED(x)) { TraceErrorDebug3(x, f, s, t, u); goto LExit; } + +#define ExitOnNull(p, x, e, s) if (NULL == p) { x = e; ExitTrace(x, s); goto LExit; } +#define ExitOnNull1(p, x, e, f, s) if (NULL == p) { x = e; ExitTrace1(x, f, s); goto LExit; } +#define ExitOnNull2(p, x, e, f, s, t) if (NULL == p) { x = e; ExitTrace2(x, f, s, t); goto LExit; } + +#define ExitOnNullWithLastError(p, x, s) if (NULL == p) { x = ::GetLastError(); x = HRESULT_FROM_WIN32(x); if (!FAILED(x)) { x = E_FAIL; } ExitTrace(x, s); goto LExit; } +#define ExitOnNullWithLastError1(p, x, f, s) if (NULL == p) { x = ::GetLastError(); x = HRESULT_FROM_WIN32(x); if (!FAILED(x)) { x = E_FAIL; } ExitTrace1(x, f, s); goto LExit; } + +#define ExitOnNullDebugTrace(p, x, e, s) if (NULL == p) { x = e; TraceErrorDebug(x, s); goto LExit; } +#define ExitOnNullDebugTrace1(p, x, e, f, s) if (NULL == p) { x = e; TraceErrorDebug1(x, f, s); goto LExit; } + +#define ExitOnNtError(x, s) if (NT_ERROR(x)) { ExitTrace(x, s); goto LExit; } +#define ExitOnNtError1(x, f, s) if (NT_ERROR(x)) { ExitTrace1(x, f, s); goto LExit; } + + +// release macros +#define ReleaseObject(x) if (x) { x->Release(); } +#define ReleaseVariant(x) { ::VariantClear(&x); } +#define ReleaseNullObject(x) if (x) { (x)->Release(); x = NULL; } +#define ReleaseCertificate(x) if (x) { ::CertFreeCertificateContext(x); x=NULL; } + + +// useful defines and macros +#define Unused(x) ((void)x) + +#ifndef MAXSIZE_T +#define MAXSIZE_T ((SIZE_T)~((SIZE_T)0)) +#endif + + +#if 1 +#define countof(ary) (sizeof(ary) / sizeof(ary[0])) +#else +#ifndef __cplusplus +#define countof(ary) (sizeof(ary) / sizeof(ary[0])) +#else +template static char countofVerify(void const *, T) throw() { return 0; } +template static void countofVerify(T *const, T *const *) throw() {}; +#define countof(arr) (sizeof(countofVerify(arr,&(arr))) * sizeof(arr)/sizeof(*(arr))) +#endif +#endif + + +#ifndef MAXSIZE_T +#define MAXSIZE_T ((SIZE_T)~((SIZE_T)0)) +#endif + +#define E_NOMOREITEMS HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) +#define AddRefAndRelease(x) { x->AddRef(); x->Release(); } diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/memutil.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/memutil.h new file mode 100644 index 0000000000..36077b0fc6 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/memutil.h @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#pragma once +//------------------------------------------------------------------------------------------------- +// +// Header for memory helper functions. +// +//------------------------------------------------------------------------------------------------- + +#ifdef __cplusplus +extern "C" { +#endif + +#define ReleaseMem(p) if (p) { MemFree(p); } +#define ReleaseNullMem(p) if (p) { MemFree(p); p = NULL; } + + +HRESULT DAPI MemInitialize(); +void DAPI MemUninitialize(); + +LPVOID DAPI MemAlloc( + __in SIZE_T cbSize, + __in BOOL fZero + ); +LPVOID DAPI MemReAlloc( + __in LPVOID pv, + __in SIZE_T cbSize, + __in BOOL fZero + ); + +HRESULT DAPI MemFree( + __in LPVOID pv + ); +SIZE_T DAPI MemSize( + __in LPVOID pv + ); + +#ifdef __cplusplus +} +#endif + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/precomp.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/precomp.h new file mode 100644 index 0000000000..e41eecd4e4 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/precomp.h @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#pragma once + +#include +#include +#include +#include + +const WCHAR MAGIC_MULTISZ_DELIM = 128; + +#include "wcautil.h" +#include "memutil.h" +#include "strutil.h" diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/qtexec.cpp b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/qtexec.cpp new file mode 100644 index 0000000000..45d0945f62 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/qtexec.cpp @@ -0,0 +1,276 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +//------------------------------------------------------------------------------------------------- +// +// Executes command line instructions without popping up a shell. +// +//------------------------------------------------------------------------------------------------- + +#include "precomp.h" + +#define OUTPUT_BUFFER 1024 + + +#define ONEMINUTE 60000 + +static HRESULT CreatePipes( + __out HANDLE *phOutRead, + __out HANDLE *phOutWrite, + __out HANDLE *phErrWrite, + __out HANDLE *phInRead, + __out HANDLE *phInWrite + ) +{ + Assert(phOutRead); + Assert(phOutWrite); + Assert(phErrWrite); + Assert(phInRead); + Assert(phInWrite); + + HRESULT hr = S_OK; + SECURITY_ATTRIBUTES sa; + HANDLE hOutTemp = INVALID_HANDLE_VALUE; + HANDLE hInTemp = INVALID_HANDLE_VALUE; + + HANDLE hOutRead = INVALID_HANDLE_VALUE; + HANDLE hOutWrite = INVALID_HANDLE_VALUE; + HANDLE hErrWrite = INVALID_HANDLE_VALUE; + HANDLE hInRead = INVALID_HANDLE_VALUE; + HANDLE hInWrite = INVALID_HANDLE_VALUE; + + // Fill out security structure so we can inherit handles + ::ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.bInheritHandle = TRUE; + sa.lpSecurityDescriptor = NULL; + + // Create pipes + if (!::CreatePipe(&hOutTemp, &hOutWrite, &sa, 0)) + ExitOnLastError(hr, "failed to create output pipe"); + + if (!::CreatePipe(&hInRead, &hInTemp, &sa, 0)) + ExitOnLastError(hr, "failed to create input pipe"); + + + // Duplicate output pipe so standard error and standard output write to + // the same pipe + if (!::DuplicateHandle(::GetCurrentProcess(), hOutWrite, ::GetCurrentProcess(), &hErrWrite, 0, TRUE, DUPLICATE_SAME_ACCESS)) + ExitOnLastError(hr, "failed to duplicate write handle"); + + // We need to create new output read and input write handles that are + // non inheritable. Otherwise it creates handles that can't be closed. + if (!::DuplicateHandle(::GetCurrentProcess(), hOutTemp, ::GetCurrentProcess(), &hOutRead, 0, FALSE, DUPLICATE_SAME_ACCESS)) + ExitOnLastError(hr, "failed to duplicate output pipe"); + + if (!::DuplicateHandle(::GetCurrentProcess(), hInTemp, ::GetCurrentProcess(), &hInWrite, 0, FALSE, DUPLICATE_SAME_ACCESS)) + ExitOnLastError(hr, "failed to duplicate input pipe"); + + // now that everything has succeeded, assign to the outputs + *phOutRead = hOutRead; + hOutRead = INVALID_HANDLE_VALUE; + + *phOutWrite = hOutWrite; + hOutWrite = INVALID_HANDLE_VALUE; + + *phErrWrite = hErrWrite; + hErrWrite = INVALID_HANDLE_VALUE; + + *phInRead = hInRead; + hInRead = INVALID_HANDLE_VALUE; + + *phInWrite = hInWrite; + hInWrite = INVALID_HANDLE_VALUE; + +LExit: + if (INVALID_HANDLE_VALUE != hOutRead) + ::CloseHandle(hOutRead); + if (INVALID_HANDLE_VALUE != hOutWrite) + ::CloseHandle(hOutWrite); + if (INVALID_HANDLE_VALUE != hErrWrite) + ::CloseHandle(hErrWrite); + if (INVALID_HANDLE_VALUE != hInRead) + ::CloseHandle(hInRead); + if (INVALID_HANDLE_VALUE != hInWrite) + ::CloseHandle(hInWrite); + if (INVALID_HANDLE_VALUE != hOutTemp) + ::CloseHandle(hOutTemp); + if (INVALID_HANDLE_VALUE != hInTemp) + ::CloseHandle(hInTemp); + + return hr; +} + +static HRESULT LogOutput( + __in HANDLE hRead + ) +{ + BYTE *pBuffer = NULL; + LPWSTR szLog = NULL; + LPWSTR szTemp = NULL; + LPWSTR pEnd = NULL; + LPWSTR pNext = NULL; + LPSTR szWrite = NULL; + DWORD dwBytes = OUTPUT_BUFFER; + BOOL bFirst = TRUE; + BOOL bUnicode = TRUE; + HRESULT hr = S_OK; + + // Get buffer for output + pBuffer = (BYTE *)MemAlloc(OUTPUT_BUFFER, FALSE); + ExitOnNull(pBuffer, hr, E_OUTOFMEMORY, "Failed to allocate buffer for output."); + + while (0 != dwBytes) + { + ::ZeroMemory(pBuffer, OUTPUT_BUFFER); + if(!::ReadFile(hRead, pBuffer, OUTPUT_BUFFER - 1, &dwBytes, NULL) && GetLastError() != ERROR_BROKEN_PIPE) + { + ExitOnLastError(hr, "Failed to read from handle."); + } + + // Check for UNICODE or ANSI output + if (bFirst) + { + if ((isgraph(pBuffer[0]) && isgraph(pBuffer[1])) || + (isgraph(pBuffer[0]) && isspace(pBuffer[1])) || + (isspace(pBuffer[0]) && isgraph(pBuffer[1])) || + (isspace(pBuffer[0]) && isspace(pBuffer[1]))) + bUnicode = FALSE; + bFirst = FALSE; + } + + // Keep track of output + if (bUnicode) + { + hr = StrAllocConcat(&szLog, (LPWSTR)pBuffer, 0); + ExitOnFailure(hr, "failed to concatenate output strings"); + } + else + { + hr = StrAllocStringAnsi(&szTemp, (LPSTR)pBuffer, 0, CP_OEMCP); + ExitOnFailure(hr, "failed to allocate output string"); + hr = StrAllocConcat(&szLog, szTemp, 0); + ExitOnFailure(hr, "failed to concatenate output strings"); + } + + // Log each line of the output + pNext = szLog; + pEnd = wcschr(szLog, L'\r'); + if (NULL == pEnd) + pEnd = wcschr(szLog, L'\n'); + while (pEnd && *pEnd) + { + // Find beginning of next line + pEnd[0] = 0; + pEnd++; + if ((pEnd[0] == L'\r') || (pEnd[0] == L'\n')) + pEnd++; + + // Log output + hr = StrAnsiAllocString(&szWrite, pNext, 0, CP_OEMCP); + ExitOnFailure(hr, "failed to convert output to ANSI"); + WcaLog(LOGMSG_STANDARD, szWrite); + + // Next line + pNext = pEnd; + pEnd = wcschr(pNext, L'\r'); + if (NULL == pEnd) + pEnd = wcschr(pNext, L'\n'); + } + + hr = StrAllocString(&szTemp, pNext, 0); + ExitOnFailure(hr, "failed to allocate string"); + + hr = StrAllocString(&szLog, szTemp, 0); + ExitOnFailure(hr, "failed to allocate string"); + } + + // Print any text that didn't end with a new line + if (szLog && *szLog) + { + hr = StrAnsiAllocString(&szWrite, szLog, 0, CP_OEMCP); + ExitOnFailure(hr, "failed to convert output to ANSI"); + WcaLog(LOGMSG_VERBOSE, szWrite); + } + +LExit: + if (NULL != pBuffer) + MemFree(pBuffer); + + ReleaseNullStr(szLog); + ReleaseNullStr(szTemp); + ReleaseNullStr(szWrite); + + return hr; +} + +HRESULT QuietExec( + __in LPWSTR wzCommand, + __in DWORD dwTimeout + ) +{ + HRESULT hr = S_OK; + PROCESS_INFORMATION oProcInfo; + STARTUPINFOW oStartInfo; + DWORD dwExitCode = ERROR_SUCCESS; + HANDLE hOutRead = INVALID_HANDLE_VALUE; + HANDLE hOutWrite = INVALID_HANDLE_VALUE; + HANDLE hErrWrite = INVALID_HANDLE_VALUE; + HANDLE hInRead = INVALID_HANDLE_VALUE; + HANDLE hInWrite = INVALID_HANDLE_VALUE; + + memset(&oProcInfo, 0, sizeof(oProcInfo)); + memset(&oStartInfo, 0, sizeof(oStartInfo)); + + // Create output redirect pipes + hr = CreatePipes(&hOutRead, &hOutWrite, &hErrWrite, &hInRead, &hInWrite); + ExitOnFailure(hr, "failed to create output pipes"); + + // Set up startup structure + oStartInfo.cb = sizeof(STARTUPINFOW); + oStartInfo.dwFlags = STARTF_USESTDHANDLES; + oStartInfo.hStdInput = hInRead; + oStartInfo.hStdOutput = hOutWrite; + oStartInfo.hStdError = hErrWrite; + + WcaLog(LOGMSG_VERBOSE, "%S", wzCommand); + + if (::CreateProcessW(NULL, + wzCommand, // command line + NULL, // security info + NULL, // thread info + TRUE, // inherit handles + ::GetPriorityClass(::GetCurrentProcess()) | CREATE_NO_WINDOW, // creation flags + NULL, // environment + NULL, // cur dir + &oStartInfo, + &oProcInfo)) + { + ::CloseHandle(oProcInfo.hThread); + + // Close child output/input handles so it doesn't hang + ::CloseHandle(hOutWrite); + ::CloseHandle(hErrWrite); + ::CloseHandle(hInRead); + + // Log output + LogOutput(hOutRead); + + // Wait for everything to finish + ::WaitForSingleObject(oProcInfo.hProcess, dwTimeout); + if (!::GetExitCodeProcess(oProcInfo.hProcess, &dwExitCode)) + dwExitCode = ERROR_SEM_IS_SET; + ::CloseHandle(hOutRead); + ::CloseHandle(hInWrite); + ::CloseHandle(oProcInfo.hProcess); + } + else + ExitOnLastError(hr, "Command failed to execute."); + + hr = HRESULT_FROM_WIN32(dwExitCode); + ExitOnFailure(hr, "Command line returned an error."); + +LExit: + return hr; +} + diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/strutil.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/strutil.h new file mode 100644 index 0000000000..151003329e --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/strutil.h @@ -0,0 +1,165 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#pragma once +//------------------------------------------------------------------------------------------------- +// +// Header for string helper functions. +// +//------------------------------------------------------------------------------------------------- + +#ifdef __cplusplus +extern "C" { +#endif + +#define ReleaseStr(pwz) if (pwz) { StrFree(pwz); } +#define ReleaseNullStr(pwz) if (pwz) { StrFree(pwz); pwz = NULL; } +#define ReleaseBSTR(bstr) if (bstr) { ::SysFreeString(bstr); } +#define ReleaseNullBSTR(bstr) if (bstr) { ::SysFreeString(bstr); bstr = NULL; } + +HRESULT DAPI StrAlloc( + __inout LPWSTR* ppwz, + __in DWORD_PTR cch + ); +HRESULT DAPI StrAnsiAlloc( + __inout LPSTR* ppz, + __in DWORD_PTR cch + ); +HRESULT DAPI StrAllocString( + __inout LPWSTR* ppwz, + __in LPCWSTR wzSource, + __in DWORD_PTR cchSource + ); +HRESULT DAPI StrAnsiAllocString( + __inout LPSTR* ppsz, + __in LPCWSTR wzSource, + __in DWORD_PTR cchSource, + __in UINT uiCodepage + ); +HRESULT DAPI StrAllocStringAnsi( + __inout LPWSTR* ppwz, + __in LPCSTR szSource, + __in DWORD_PTR cchSource, + __in UINT uiCodepage + ); +HRESULT DAPI StrAllocPrefix( + __inout LPWSTR* ppwz, + __in LPCWSTR wzPrefix, + __in DWORD_PTR cchPrefix + ); +HRESULT DAPI StrAllocConcat( + __inout LPWSTR* ppwz, + __in LPCWSTR wzSource, + __in DWORD_PTR cchSource + ); +HRESULT __cdecl StrAllocFormatted( + __inout LPWSTR* ppwz, + __in LPCWSTR wzFormat, + ... + ); +HRESULT __cdecl StrAnsiAllocFormatted( + __inout LPSTR* ppsz, + __in LPCSTR szFormat, + ... + ); +HRESULT DAPI StrAllocFormattedArgs( + __inout LPWSTR* ppwz, + __in LPCWSTR wzFormat, + __in va_list args + ); +HRESULT DAPI StrAnsiAllocFormattedArgs( + __inout LPSTR* ppsz, + __in LPCSTR szFormat, + __in va_list args + ); + +HRESULT DAPI StrMaxLength( + __in LPVOID p, + __out DWORD_PTR* pcch + ); +HRESULT DAPI StrSize( + __in LPVOID p, + __out DWORD_PTR* pcb + ); + +HRESULT DAPI StrFree( + __in LPVOID p + ); + +HRESULT DAPI StrCurrentTime( + __inout LPWSTR* ppwz, + __in BOOL fGMT + ); +HRESULT DAPI StrCurrentDateTime( + __inout LPWSTR* ppwz, + __in BOOL fGMT + ); + +HRESULT DAPI StrHexEncode( + __in_ecount(cbSource) const BYTE* pbSource, + __in DWORD_PTR cbSource, + __out_ecount(cchDest) LPWSTR wzDest, + __in DWORD_PTR cchDest + ); +HRESULT DAPI StrHexDecode( + __in LPCWSTR wzSource, + __out_bcount(cbDest) BYTE* pbDest, + __in DWORD_PTR cbDest + ); + +HRESULT DAPI StrAllocBase85Encode( + __in_bcount(cbSource) const BYTE* pbSource, + __in DWORD_PTR cbSource, + __inout LPWSTR* pwzDest + ); +HRESULT DAPI StrAllocBase85Decode( + __in LPCWSTR wzSource, + __out BYTE** hbDest, + __out DWORD_PTR* pcbDest + ); + +HRESULT DAPI MultiSzLen( + __in LPCWSTR pwzMultiSz, + __out DWORD_PTR* pcch + ); +HRESULT DAPI MultiSzPrepend( + __inout LPWSTR* ppwzMultiSz, + __inout_opt DWORD_PTR *pcchMultiSz, + __in LPCWSTR pwzInsert + ); +HRESULT DAPI MultiSzFindSubstring( + __in LPCWSTR pwzMultiSz, + __in LPCWSTR pwzSubstring, + __out_opt DWORD_PTR* pdwIndex, + __out_opt LPCWSTR* ppwzFoundIn + ); +HRESULT DAPI MultiSzFindString( + __in LPCWSTR pwzMultiSz, + __in LPCWSTR pwzString, + __out DWORD_PTR* pdwIndex, + __out LPCWSTR* ppwzFound + ); +HRESULT DAPI MultiSzRemoveString( + __inout LPWSTR* ppwzMultiSz, + __in DWORD_PTR dwIndex + ); +HRESULT DAPI MultiSzInsertString( + __inout LPWSTR* ppwzMultiSz, + __inout_opt DWORD_PTR *pcchMultiSz, + __in DWORD_PTR dwIndex, + __in LPCWSTR pwzInsert + ); +HRESULT DAPI MultiSzReplaceString( + __inout LPWSTR* ppwzMultiSz, + __in DWORD_PTR dwIndex, + __in LPCWSTR pwzString + ); + +LPCWSTR wcsistr( + IN LPCWSTR wzString, + IN LPCWSTR wzCharSet + ); + +#ifdef __cplusplus +} +#endif diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/wcalog.cpp b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/wcalog.cpp new file mode 100644 index 0000000000..b162bd6152 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/wcalog.cpp @@ -0,0 +1,150 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +//------------------------------------------------------------------------------------------------- +// +// Windows Installer XML CustomAction utility library logging functions +// +//------------------------------------------------------------------------------------------------- + +#include "precomp.h" + + +/******************************************************************** + IsVerboseLogging() - internal helper function to detect if doing + verbose logging + +********************************************************************/ +static BOOL IsVerboseLogging() +{ + static int iVerbose = -1; + + if (0 > iVerbose) + { + iVerbose = WcaIsPropertySet("LOGVERBOSE"); + if (0 == iVerbose) // if the property wasn't set, check the registry to see if the logging policy was turned on + { + HKEY hkey = NULL; + WCHAR rgwc[16] = { 0 }; + DWORD cb = sizeof(rgwc); + if (ERROR_SUCCESS == ::RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Policies\\Microsoft\\Windows\\Installer", 0, KEY_QUERY_VALUE, &hkey)) + { + if (ERROR_SUCCESS == ::RegQueryValueExW(hkey, L"Logging", 0, NULL, reinterpret_cast(rgwc), &cb)) + { + for (LPCWSTR pwc = rgwc; (cb / sizeof(WCHAR)) > static_cast(pwc - rgwc) && *pwc; pwc++) + { + if (L'v' == *pwc || L'V' == *pwc) + { + iVerbose = 1; + break; + } + } + } + + ::RegCloseKey(hkey); + } + } + } + + Assert(iVerbose >= 0); + return (BOOL)iVerbose; +} + + +/******************************************************************** + WcaLog() - outputs trace and log info + +*******************************************************************/ +extern "C" void WcaLog( + __in LOGLEVEL llv, + __in const char* fmt, ... + ) +{ + static char szFmt[LOG_BUFFER]; + static char szBuf[LOG_BUFFER]; + static bool fInLogPrint = false; + + // prevent re-entrant logprints. (recursion issues between assert/logging code) + if (fInLogPrint) + return; + fInLogPrint = true; + + if (LOGMSG_STANDARD == llv || + (LOGMSG_VERBOSE == llv && IsVerboseLogging()) +#ifdef DEBUG + || LOGMSG_TRACEONLY == llv +#endif + ) + { + va_list args; + va_start(args, fmt); + + LPCSTR szLogName = WcaGetLogName(); + if (szLogName[0] != 0) + StringCchPrintfA(szFmt, countof(szFmt), "%s: %s", szLogName, fmt); + else + StringCchCopyA(szFmt, countof(szFmt), fmt); + + StringCchVPrintfA(szBuf, countof(szBuf), szFmt, args); + va_end(args); + +#ifdef DEBUG + // always write to the log in debug +#else + if (llv == LOGMSG_STANDARD || (llv == LOGMSG_VERBOSE && IsVerboseLogging())) +#endif + { + PMSIHANDLE hrec = MsiCreateRecord(1); + + ::MsiRecordSetStringA(hrec, 0, szBuf); + // TODO: Recursion on failure. May not be safe to assert from here. + WcaProcessMessage(INSTALLMESSAGE_INFO, hrec); + } + +#if DEBUG + StringCchCatA(szBuf, countof(szBuf), "\n"); + OutputDebugStringA(szBuf); +#endif + } + + fInLogPrint = false; + return; +} + + +/******************************************************************** + WcaDisplayAssert() - called before Assert() dialog shows + + NOTE: writes the assert string to the MSI log +********************************************************************/ +extern "C" BOOL WcaDisplayAssert( + __in LPCSTR sz + ) +{ + WcaLog(LOGMSG_STANDARD, "Debug Assert Message: %s", sz); + return TRUE; +} + + +/******************************************************************** + WcaLogError() - called before ExitOnXXX() macro exists the function + + NOTE: writes the hresult and error string to the MSI log +********************************************************************/ +extern "C" void WcaLogError( + __in HRESULT hr, + __in LPCSTR szMessage, + ... + ) +{ + char szBuffer[LOG_BUFFER]; + va_list dots; + + va_start(dots, szMessage); + StringCchVPrintfA(szBuffer, countof(szBuffer), szMessage, dots); + va_end(dots); + + // log the message if using Wca common layer + if (WcaIsInitialized()) + WcaLog(LOGMSG_STANDARD, "Error 0x%x: %s", hr, szBuffer); +} diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/wcascript.cpp b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/wcascript.cpp new file mode 100644 index 0000000000..b0a55946f9 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/wcascript.cpp @@ -0,0 +1,447 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +//------------------------------------------------------------------------------------------------- +// +// Windows Installer XML CustomAction utility library CaScript functions +// +//------------------------------------------------------------------------------------------------- + +#include "precomp.h" + + +static HRESULT CaScriptFileName( + __in WCA_ACTION action, + __in WCA_CASCRIPT script, + __in BOOL fImpersonated, + __in LPCWSTR wzScriptKey, + __out LPWSTR* pwzScriptName + ); + + +/******************************************************************** + WcaCaScriptCreateKey() - creates a unique script key for this + CustomAction. + +********************************************************************/ +extern "C" HRESULT WIXAPI WcaCaScriptCreateKey( + __out LPWSTR* ppwzScriptKey + ) +{ + AssertSz(WcaIsInitialized(), "WcaInitialize() should have been called before calling this function."); + HRESULT hr = S_OK; + + hr = StrAllocStringAnsi(ppwzScriptKey, WcaGetLogName(), 0, CP_ACP); + ExitOnFailure(hr, "Failed to create script key."); + +LExit: + return hr; +} + + +/******************************************************************** + WcaCaScriptCreate() - creates the appropriate script for this + CustomAction Script Key. + +********************************************************************/ +extern "C" HRESULT WIXAPI WcaCaScriptCreate( + __in WCA_ACTION action, + __in WCA_CASCRIPT script, + __in BOOL fImpersonated, + __in LPCWSTR wzScriptKey, + __in BOOL fAppend, + __in WCA_CASCRIPT_HANDLE* phScript + ) +{ + HRESULT hr = S_OK; + LPWSTR pwzScriptPath = NULL; + HANDLE hScriptFile = INVALID_HANDLE_VALUE; + + hr = CaScriptFileName(action, script, fImpersonated, wzScriptKey, &pwzScriptPath); + ExitOnFailure(hr, "Failed to calculate script file name."); + + hScriptFile = ::CreateFileW(pwzScriptPath, GENERIC_WRITE, FILE_SHARE_READ, NULL, fAppend ? OPEN_ALWAYS : CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); + if (INVALID_HANDLE_VALUE == hScriptFile) + { + ExitWithLastError1(hr, "Failed to open CaScript: %S", pwzScriptPath); + } + + if (fAppend && INVALID_SET_FILE_POINTER == ::SetFilePointer(hScriptFile, 0, NULL, FILE_END)) + { + ExitWithLastError(hr, "Failed to seek to end of file."); + } + + *phScript = reinterpret_cast(MemAlloc(sizeof(WCA_CASCRIPT_STRUCT), TRUE)); + ExitOnNull(*phScript, hr, E_OUTOFMEMORY, "Failed to allocate space for cascript handle."); + + (*phScript)->pwzScriptPath = pwzScriptPath; + pwzScriptPath = NULL; + (*phScript)->hScriptFile = hScriptFile; + hScriptFile = INVALID_HANDLE_VALUE; + +LExit: + if (INVALID_HANDLE_VALUE != hScriptFile) + { + ::CloseHandle(hScriptFile); + } + + ReleaseStr(pwzScriptPath); + return hr; +} + + +/******************************************************************** + WcaCaScriptOpen() - opens the appropriate script for this CustomAction + Script Key. + +********************************************************************/ +extern "C" HRESULT WIXAPI WcaCaScriptOpen( + __in WCA_ACTION action, + __in WCA_CASCRIPT script, + __in BOOL fImpersonated, + __in LPCWSTR wzScriptKey, + __in WCA_CASCRIPT_HANDLE* phScript + ) +{ + HRESULT hr = S_OK; + LPWSTR pwzScriptPath = NULL; + HANDLE hScriptFile = INVALID_HANDLE_VALUE; + + hr = CaScriptFileName(action, script, fImpersonated, wzScriptKey, &pwzScriptPath); + ExitOnFailure(hr, "Failed to calculate script file name."); + + hScriptFile = ::CreateFileW(pwzScriptPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); + if (INVALID_HANDLE_VALUE == hScriptFile) + { + ExitWithLastError1(hr, "Failed to open CaScript: %S", pwzScriptPath); + } + + *phScript = reinterpret_cast(MemAlloc(sizeof(WCA_CASCRIPT_STRUCT), TRUE)); + ExitOnNull(*phScript, hr, E_OUTOFMEMORY, "Failed to allocate space for cascript handle."); + + (*phScript)->pwzScriptPath = pwzScriptPath; + pwzScriptPath = NULL; + (*phScript)->hScriptFile = hScriptFile; + hScriptFile = INVALID_HANDLE_VALUE; + +LExit: + if (INVALID_HANDLE_VALUE != hScriptFile) + { + ::CloseHandle(hScriptFile); + } + + ReleaseStr(pwzScriptPath); + return hr; +} + + +/******************************************************************** + WcaCaScriptClose() - closes an open script handle. + +********************************************************************/ +extern "C" void WIXAPI WcaCaScriptClose( + __in WCA_CASCRIPT_HANDLE hScript, + __in WCA_CASCRIPT_CLOSE closeOperation + ) +{ + if (hScript) + { + if (INVALID_HANDLE_VALUE != hScript->hScriptFile) + { + ::CloseHandle(hScript->hScriptFile); + } + + if (hScript->pwzScriptPath) + { + if (WCA_CASCRIPT_CLOSE_DELETE == closeOperation) + { + ::DeleteFileW(hScript->pwzScriptPath); + } + + StrFree(hScript->pwzScriptPath); + } + + MemFree(hScript); + } +} + + +/******************************************************************** + WcaCaScriptReadAsCustomActionData() - read the ca script into a format + that is useable by other CA data + functions. + +********************************************************************/ +extern "C" HRESULT WIXAPI WcaCaScriptReadAsCustomActionData( + __in WCA_CASCRIPT_HANDLE hScript, + __out LPWSTR* ppwzCustomActionData + ) +{ + HRESULT hr = S_OK; + LARGE_INTEGER liScriptSize = { 0 }; + BYTE* pbData = NULL; + DWORD cbData = 0; + + if (!::GetFileSizeEx(hScript->hScriptFile, &liScriptSize)) + { + ExitWithLastError(hr, "Failed to get size of ca script file."); + } + + if (0 != liScriptSize.HighPart || 0 != (liScriptSize.LowPart % sizeof(WCHAR))) + { + hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); + ExitOnFailure(hr, "Invalid data read from ca script."); + } + + cbData = liScriptSize.LowPart; + pbData = static_cast(MemAlloc(cbData, TRUE)); + ExitOnNull(pbData, hr, E_OUTOFMEMORY, "Failed to allocate memory to read in ca script."); + + if (INVALID_SET_FILE_POINTER == ::SetFilePointer(hScript->hScriptFile, 0, NULL, FILE_BEGIN)) + { + ExitWithLastError(hr, "Failed to reset to beginning of ca script."); + } + + DWORD cbTotalRead = 0; + DWORD cbRead = 0; + do + { + if (!::ReadFile(hScript->hScriptFile, pbData + cbTotalRead, cbData - cbTotalRead, &cbRead, NULL)) + { + ExitWithLastError(hr, "Failed to read from ca script."); + } + + cbTotalRead += cbRead; + } while (cbRead && cbTotalRead < cbData); + + if (cbTotalRead != cbData) + { + hr = E_UNEXPECTED; + ExitOnFailure(hr, "Failed to completely read ca script."); + } + + // Add one to the allocated space because the data stored in the script is not + // null terminated. After copying the memory over, we'll ensure the string is + // null terminated. + DWORD cchData = cbData / sizeof(WCHAR) + 1; + hr = StrAlloc(ppwzCustomActionData, cchData); + ExitOnFailure(hr, "Failed to copy ca script."); + + CopyMemory(*ppwzCustomActionData, pbData, cbData); + (*ppwzCustomActionData)[cchData - 1] = L'\0'; + +LExit: + ReleaseMem(pbData); + return hr; +} + + +/******************************************************************** + WcaCaScriptWriteString() - writes a string to the ca script. + +********************************************************************/ +extern "C" HRESULT WIXAPI WcaCaScriptWriteString( + __in WCA_CASCRIPT_HANDLE hScript, + __in LPCWSTR wzValue + ) +{ + HRESULT hr = S_OK; + DWORD cbFile = 0; + DWORD cbWrite = 0; + DWORD cbTotalWritten = 0; + WCHAR delim[] = { MAGIC_MULTISZ_DELIM }; // magic char followed by NULL terminator + + cbFile = ::SetFilePointer(hScript->hScriptFile, 0, NULL, FILE_END); + if (INVALID_SET_FILE_POINTER == cbFile) + { + ExitWithLastError(hr, "Failed to move file pointer to end of file."); + } + + // If there is existing data in the file, append on the magic delimeter + // before adding our new data on the end of the file. + if (0 < cbFile) + { + cbWrite = sizeof(delim); + cbTotalWritten = 0; + while (cbTotalWritten < cbWrite) + { + DWORD cbWritten = 0; + if (!::WriteFile(hScript->hScriptFile, reinterpret_cast(delim) + cbTotalWritten, cbWrite - cbTotalWritten, &cbWritten, NULL)) + { + ExitWithLastError(hr, "Failed to write data to ca script."); + } + + cbTotalWritten += cbWritten; + } + } + + cbWrite = lstrlenW(wzValue) * sizeof(WCHAR); + cbTotalWritten = 0; + while (cbTotalWritten < cbWrite) + { + DWORD cbWritten = 0; + if (!::WriteFile(hScript->hScriptFile, reinterpret_cast(wzValue) + cbTotalWritten, cbWrite - cbTotalWritten, &cbWritten, NULL)) + { + ExitWithLastError(hr, "Failed to write data to ca script."); + } + + cbTotalWritten += cbWritten; + } + +LExit: + return hr; +} + + +/******************************************************************** + WcaCaScriptWriteNumber() - writes a number to the ca script. + +********************************************************************/ +extern "C" HRESULT WIXAPI WcaCaScriptWriteNumber( + __in WCA_CASCRIPT_HANDLE hScript, + __in DWORD dwValue + ) +{ + HRESULT hr = S_OK; + WCHAR wzBuffer[13] = { 0 }; + + hr = ::StringCchPrintfW(wzBuffer, countof(wzBuffer), L"%u", dwValue); + ExitOnFailure(hr, "Failed to convert number into string."); + + hr = WcaCaScriptWriteString(hScript, wzBuffer); + ExitOnFailure(hr, "Failed to write number to script."); + +LExit: + return hr; +} + + +/******************************************************************** + WcaCaScriptFlush() - best effort function to get script written to + disk. + +********************************************************************/ +extern "C" void WIXAPI WcaCaScriptFlush( + __in WCA_CASCRIPT_HANDLE hScript + ) +{ + ::FlushFileBuffers(hScript->hScriptFile); +} + + +/******************************************************************** + WcaCaScriptCleanup() - best effort clean-up of any cascripts left + over from this install/uninstall. + +********************************************************************/ +extern "C" void WIXAPI WcaCaScriptCleanup( + __in LPCWSTR wzProductCode, + __in BOOL fImpersonated + ) +{ + HRESULT hr = S_OK; + WCHAR wzTempPath[MAX_PATH]; + LPWSTR pwzWildCardPath = NULL; + WIN32_FIND_DATAW fd = { 0 }; + HANDLE hff = INVALID_HANDLE_VALUE; + LPWSTR pwzDeletePath = NULL; + + if (fImpersonated) + { + if (!::GetTempPathW(countof(wzTempPath), wzTempPath)) + { + ExitWithLastError(hr, "Failed to get temp path."); + } + } + else + { + if (!::GetWindowsDirectoryW(wzTempPath, countof(wzTempPath))) + { + ExitWithLastError(hr, "Failed to get windows path."); + } + + hr = ::StringCchCatW(wzTempPath, countof(wzTempPath), L"\\Installer\\"); + ExitOnFailure(hr, "Failed to concat Installer directory on windows path string."); + } + + hr = StrAllocFormatted(&pwzWildCardPath, L"%swix%s.*.???", wzTempPath, wzProductCode); + ExitOnFailure(hr, "Failed to allocate wildcard path to ca scripts."); + + hff = ::FindFirstFileW(pwzWildCardPath, &fd); + if (INVALID_HANDLE_VALUE == hff) + { + ExitWithLastError1(hr, "Failed to find files with pattern: %S", pwzWildCardPath); + } + + do + { + hr = StrAllocFormatted(&pwzDeletePath, L"%s%s", wzTempPath, fd.cFileName); + if (SUCCEEDED(hr)) + { + if (!::DeleteFileW(pwzDeletePath)) + { + DWORD er = ::GetLastError(); + WcaLog(LOGMSG_VERBOSE, "Failed to clean up CAScript file: %S, er: %d", fd.cFileName, er); + } + } + else + { + WcaLog(LOGMSG_VERBOSE, "Failed to allocate path to clean up CAScript file: %S, hr: 0x%x", fd.cFileName, hr); + } + } while(::FindNextFileW(hff, &fd)); + +LExit: + if (INVALID_HANDLE_VALUE == hff) + { + ::FindClose(hff); + } + + ReleaseStr(pwzDeletePath); + ReleaseStr(pwzWildCardPath); + return; +} + + +static HRESULT CaScriptFileName( + __in WCA_ACTION action, + __in WCA_CASCRIPT script, + __in BOOL fImpersonated, + __in LPCWSTR wzScriptKey, + __out LPWSTR* ppwzScriptName + ) +{ + HRESULT hr = S_OK; + WCHAR wzTempPath[MAX_PATH]; + LPWSTR pwzProductCode = NULL; + WCHAR chInstallOrUninstall = action == WCA_ACTION_INSTALL ? L'i' : L'u'; + WCHAR chScheduledOrRollback = script == WCA_CASCRIPT_SCHEDULED ? L's' : L'r'; + WCHAR chUserOrMachine = fImpersonated ? L'u' : L'm'; + + if (fImpersonated) + { + if (!::GetTempPathW(countof(wzTempPath), wzTempPath)) + { + ExitWithLastError(hr, "Failed to get temp path."); + } + } + else + { + if (!::GetWindowsDirectoryW(wzTempPath, countof(wzTempPath))) + { + ExitWithLastError(hr, "Failed to get windows path."); + } + + hr = ::StringCchCatW(wzTempPath, countof(wzTempPath), L"\\Installer\\"); + ExitOnFailure(hr, "Failed to concat Installer directory on windows path string."); + } + + hr = WcaGetProperty(L"ProductCode", &pwzProductCode); + ExitOnFailure(hr, "Failed to get ProductCode."); + + hr = StrAllocFormatted(ppwzScriptName, L"%swix%s.%s.%c%c%c", wzTempPath, pwzProductCode, wzScriptKey, chScheduledOrRollback, chUserOrMachine, chInstallOrUninstall); + ExitOnFailure(hr, "Failed to allocate path to ca script."); + +LExit: + ReleaseStr(pwzProductCode); + return hr; +} diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/wcautil.cpp b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/wcautil.cpp new file mode 100644 index 0000000000..5f7bbda74d --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/wcautil.cpp @@ -0,0 +1,201 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +//------------------------------------------------------------------------------------------------- +// +// Windows Installer XML CustomAction utility library. +// +//------------------------------------------------------------------------------------------------- + +#include "precomp.h" + +// globals +HMODULE g_hInstCADLL; + +// statics +static BOOL s_fInitialized; +static MSIHANDLE s_hInstall; +static MSIHANDLE s_hDatabase; +static char s_szCustomActionLogName[32]; +static UINT s_iRetVal; + + +/******************************************************************** + WcaGlobalInitialize() - initializes the Wca library, should be + called once per custom action Dll during + DllMain on DLL_PROCESS_ATTACH + +********************************************************************/ +extern "C" void WcaGlobalInitialize( + __in HINSTANCE hInst + ) +{ + g_hInstCADLL = hInst; + MemInitialize(); + + AssertSetModule(g_hInstCADLL); + AssertSetDisplayFunction(WcaDisplayAssert); +} + + +/******************************************************************** + WcaGlobalFinalize() - finalizes the Wca library, should be the + called once per custom action Dll during + DllMain on DLL_PROCESS_DETACH + +********************************************************************/ +extern "C" void WcaGlobalFinalize() +{ +#ifdef DEBUG + if (WcaIsInitialized()) + { + CHAR szBuf[2048]; + StringCchPrintfA(szBuf, countof(szBuf), "CustomAction %s called WcaInitialize() but not WcaTerminate()", WcaGetLogName()); + + AssertSz(FALSE, szBuf); + } +#endif + MemUninitialize(); + g_hInstCADLL = NULL; +} + + +/******************************************************************** + WcaInitialize() - initializes the Wca framework, should be the first + thing called by all CustomActions + +********************************************************************/ +extern "C" HRESULT WcaInitialize( + __in MSIHANDLE hInstall, + __in const char* szCustomActionLogName + ) +{ + // these statics should be called once per CustomAction invocation. + // Darwin does doesn't preserve DLL state across CustomAction calls so + // these should always be initialized to NULL. If that behavior changes + // we would need to do a careful review of all of our module/global data. + AssertSz(!s_fInitialized, "WcaInitialize() should only be called once per CustomAction"); + Assert(NULL == s_hInstall); + Assert(NULL == s_hDatabase); + Assert(0 == *s_szCustomActionLogName); + + HRESULT hr = S_OK; + + s_fInitialized = TRUE; + s_iRetVal = ERROR_SUCCESS; // assume all will go well + + s_hInstall = hInstall; + s_hDatabase = ::MsiGetActiveDatabase(s_hInstall); // may return null if deferred CustomAction + + hr = ::StringCchCopyA(s_szCustomActionLogName, countof(s_szCustomActionLogName), szCustomActionLogName); + ExitOnFailure1(hr, "Failed to copy CustomAction log name: %s", szCustomActionLogName); + + Assert(s_hInstall); +LExit: + if (FAILED(hr)) + { + if (s_hDatabase) + { + ::MsiCloseHandle(s_hDatabase); + s_hDatabase = NULL; + } + + s_hInstall = NULL; + s_fInitialized = FALSE; + } + + return hr; +} + + +/******************************************************************** + WcaFinalize() - cleans up after the Wca framework, should be the last + thing called by all CustomActions + +********************************************************************/ +extern "C" UINT WcaFinalize( + __in UINT iReturnValue + ) +{ + // clean up after our initialization + if (s_hDatabase) + { + ::MsiCloseHandle(s_hDatabase); + s_hDatabase = NULL; + } + + s_hInstall = NULL; + s_fInitialized = FALSE; + + // if no error occurred during the processing of the CusotmAction return the passed in return value + // otherwise return the previous failure + return (ERROR_SUCCESS == s_iRetVal) ? iReturnValue : s_iRetVal; +} + + +/******************************************************************** + WcaIsInitialized() - determines if WcaInitialize() has been called + +********************************************************************/ +extern "C" BOOL WcaIsInitialized() +{ + return s_fInitialized; +} + + +/******************************************************************** + WcaGetInstallHandle() - gets the handle to the active install session + +********************************************************************/ +extern "C" MSIHANDLE WcaGetInstallHandle() +{ + AssertSz(s_hInstall, "WcaInitialize() should be called before attempting to access the install handle."); + return s_hInstall; +} + + +/******************************************************************** + WcaGetDatabaseHandle() - gets the handle to the active database + + NOTE: this function can only be used in immediate CustomActions. + Deferred CustomActions do not have access to the active + database. +********************************************************************/ +extern "C" MSIHANDLE WcaGetDatabaseHandle() +{ + AssertSz(s_hDatabase, "WcaInitialize() should be called before attempting to access the install handle. Also note that deferred CustomActions do not have access to the active database."); + return s_hDatabase; +} + + +/******************************************************************** + WcaGetLogName() - gets the name of the CustomAction used in logging + +********************************************************************/ +extern "C" const char* WcaGetLogName() +{ + return s_szCustomActionLogName; +} + + +/******************************************************************** + WcaSetReturnValue() - sets the value to return from the CustomAction + +********************************************************************/ +extern "C" void WcaSetReturnValue( + __in UINT iReturnValue + ) +{ + s_iRetVal = iReturnValue; +} + + +/******************************************************************** + WcaCancelDetected() - determines if the user has canceled yet + + NOTE: returns true when WcaSetReturnValue() is set to ERROR_INSTALL_USEREXIT +********************************************************************/ +extern "C" BOOL WcaCancelDetected() +{ + return ERROR_INSTALL_USEREXIT == s_iRetVal; +} diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/wcautil.h b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/wcautil.h new file mode 100644 index 0000000000..8265e27735 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/wcautil.h @@ -0,0 +1,344 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#pragma once +//------------------------------------------------------------------------------------------------- +// +// Windows Installer XML CustomAction utility library. +// +//------------------------------------------------------------------------------------------------- + +#ifdef __cplusplus +extern "C" { +#endif + +#define WIXAPI __stdcall +#define ExitTrace WcaLogError +#define ExitTrace1 WcaLogError +#define ExitTrace2 WcaLogError +#define ExitTrace3 WcaLogError + +#include "dutil.h" + +#define MessageExitOnLastError(x, e, s) { x = ::GetLastError(); x = HRESULT_FROM_WIN32(x); if (FAILED(x)) { ExitTrace(x, "%s", s); WcaErrorMessage(e, x, MB_OK, 0); goto LExit; } } +#define MessageExitOnLastError1(x, e, f, s) { x = ::GetLastError(); x = HRESULT_FROM_WIN32(x); if (FAILED(x)) { ExitTrace1(x, f, s); WcaErrorMessage(e, x, MB_OK, 1, s); goto LExit; } } + +#define MessageExitOnFailure(x, e, s) if (FAILED(x)) { ExitTrace(x, "%s", s); WcaErrorMessage(e, x, INSTALLMESSAGE_ERROR | MB_OK, 0); goto LExit; } +#define MessageExitOnFailure1(x, e, f, s) if (FAILED(x)) { ExitTrace1(x, f, s); WcaErrorMessage(e, x, INSTALLMESSAGE_ERROR | MB_OK, 1, s); goto LExit; } +#define MessageExitOnFailure2(x, e, f, s, t) if (FAILED(x)) { ExitTrace2(x, f, s, t); WcaErrorMessage(e, x, INSTALLMESSAGE_ERROR | MB_OK, 2, s, t); goto LExit; } +#define MessageExitOnFailure3(x, e, f, s, t, u) if (FAILED(x)) { ExitTrace2(x, f, s, t, u); WcaErrorMessage(e, x, INSTALLMESSAGE_ERROR | MB_OK, 3, s, t, u); goto LExit; } + +#define MessageExitOnNullWithLastError(p, x, e, s) if (NULL == p) { x = ::GetLastError(); x = HRESULT_FROM_WIN32(x); if (!FAILED(x)) { x = E_FAIL; } ExitTrace(x, "%s", s); WcaErrorMessage(e, x, MB_OK, 0); goto LExit; } +#define MessageExitOnNullWithLastError1(p, x, e, f, s) if (NULL == p) { x = ::GetLastError(); x = HRESULT_FROM_WIN32(x); if (!FAILED(x)) { x = E_FAIL; } ExitTrace(x, f, s); WcaErrorMessage(e, x, MB_OK, 1, s); goto LExit; } +#define MessageExitOnNullWithLastError2(p, x, e, f, s, t) if (NULL == p) { x = ::GetLastError(); x = HRESULT_FROM_WIN32(x); if (!FAILED(x)) { x = E_FAIL; } ExitTrace(x, f, s, t); WcaErrorMessage(e, x, MB_OK, 2, s, t); goto LExit; } + +#define MAX_DARWIN_KEY 73 +#define MAX_DARWIN_COLUMN 255 + +// Generic action enum. +enum WCA_ACTION +{ + WCA_ACTION_NONE, + WCA_ACTION_INSTALL, + WCA_ACTION_UNINSTALL, +}; + +enum WCA_CASCRIPT +{ + WCA_CASCRIPT_SCHEDULED, + WCA_CASCRIPT_ROLLBACK, +}; + +enum WCA_CASCRIPT_CLOSE +{ + WCA_CASCRIPT_CLOSE_PRESERVE, + WCA_CASCRIPT_CLOSE_DELETE, +}; + +typedef struct WCA_CASCRIPT_STRUCT +{ + LPWSTR pwzScriptPath; + HANDLE hScriptFile; +} *WCA_CASCRIPT_HANDLE; + +void WIXAPI WcaGlobalInitialize( + __in HINSTANCE hInst + ); +void WIXAPI WcaGlobalFinalize(); + +HRESULT WIXAPI WcaInitialize( + __in MSIHANDLE hInstall, + __in const char* szCustomActionLogName + ); +UINT WIXAPI WcaFinalize( + __in UINT iReturnValue + ); +BOOL WIXAPI WcaIsInitialized(); + +MSIHANDLE WIXAPI WcaGetInstallHandle(); +MSIHANDLE WIXAPI WcaGetDatabaseHandle(); + +const char* WIXAPI WcaGetLogName(); + +void WIXAPI WcaSetReturnValue( + __in UINT iReturnValue + ); +BOOL WIXAPI WcaCancelDetected(); + +const int LOG_BUFFER = 2048; +enum LOGLEVEL +{ + LOGMSG_TRACEONLY, // Never written to the log file (except in DEBUG builds) + LOGMSG_VERBOSE, // Written to log when LOGVERBOSE + LOGMSG_STANDARD // Written to log whenever informational logging is enabled +}; + +void __cdecl WcaLog( + __in LOGLEVEL llv, + __in const char* fmt, ... + ); +BOOL WIXAPI WcaDisplayAssert( + __in LPCSTR sz + ); +void __cdecl WcaLogError( + __in HRESULT hr, + __in LPCSTR szMessage, + ... + ); + + +UINT WIXAPI WcaProcessMessage( + __in INSTALLMESSAGE eMessageType, + __in MSIHANDLE hRecord + ); +UINT __cdecl WcaErrorMessage( + __in int iError, + __in HRESULT hrError, + __in UINT uiType, + __in DWORD cArgs, + ... + ); +HRESULT WIXAPI WcaProgressMessage( + __in UINT uiCost, + __in BOOL fExtendProgressBar + ); + +BOOL WIXAPI WcaIsInstalling( + __in INSTALLSTATE isInstalled, + __in INSTALLSTATE isAction + ); +BOOL WIXAPI WcaIsReInstalling( + __in INSTALLSTATE isInstalled, + __in INSTALLSTATE isAction + ); +BOOL WIXAPI WcaIsUninstalling( + __in INSTALLSTATE isInstalled, + __in INSTALLSTATE isAction + ); + +HRESULT WIXAPI WcaSetComponentState( + __in LPCWSTR wzComponent, + __in INSTALLSTATE isState + ); + +HRESULT WIXAPI WcaTableExists( + __in LPCWSTR wzTable + ); + +HRESULT WIXAPI WcaOpenView( + __in LPCWSTR wzSql, + __out MSIHANDLE* phView + ); +HRESULT WIXAPI WcaExecuteView( + __in MSIHANDLE hView, + __in MSIHANDLE hRec + ); +HRESULT WIXAPI WcaOpenExecuteView( + __in LPCWSTR wzSql, + __out MSIHANDLE* phView + ); +HRESULT WIXAPI WcaFetchRecord( + __in MSIHANDLE hView, + __out MSIHANDLE* phRec + ); +HRESULT WIXAPI WcaFetchSingleRecord( + __in MSIHANDLE hView, + __out MSIHANDLE* phRec + ); + +HRESULT WIXAPI WcaGetProperty( + __in LPCWSTR wzProperty, + __inout LPWSTR* ppwzData + ); +HRESULT WIXAPI WcaGetFormattedProperty( + __in LPCWSTR wzProperty, + __out LPWSTR* ppwzData + ); +HRESULT WIXAPI WcaGetFormattedString( + __in LPCWSTR wzString, + __out LPWSTR* ppwzData + ); +HRESULT WIXAPI WcaGetIntProperty( + __in LPCWSTR wzProperty, + __inout int* piData + ); +HRESULT WIXAPI WcaGetTargetPath( + __in LPCWSTR wzFolder, + __out LPWSTR* ppwzData + ); +HRESULT WIXAPI WcaSetProperty( + __in LPCWSTR wzPropertyName, + __in LPCWSTR wzPropertyValue + ); +HRESULT WIXAPI WcaSetIntProperty( + __in LPCWSTR wzPropertyName, + __in int nPropertyValue + ); +BOOL WIXAPI WcaIsPropertySet( + __in LPCSTR szProperty + ); + +HRESULT WIXAPI WcaGetRecordInteger( + __in MSIHANDLE hRec, + __in UINT uiField, + __inout int* piData + ); +HRESULT WIXAPI WcaGetRecordString( + __in MSIHANDLE hRec, + __in UINT uiField, + __inout LPWSTR* ppwzData + ); +HRESULT WIXAPI WcaGetRecordFormattedString( + __in MSIHANDLE hRec, + __in UINT uiField, + __inout LPWSTR* ppwzData + ); + +HRESULT WIXAPI WcaAllocStream(__inout BYTE** ppbData, __in DWORD cbData); +HRESULT WIXAPI WcaFreeStream(__in BYTE* pbData); + +HRESULT WIXAPI WcaGetRecordStream( + __in MSIHANDLE hRecBinary, + __in UINT uiField, + __inout BYTE** ppbData, + __inout DWORD* pcbData + ); +HRESULT WIXAPI WcaSetRecordString( + __in MSIHANDLE hRec, + __in UINT uiField, + __in LPCWSTR wzData + ); +HRESULT WIXAPI WcaSetRecordInteger( + __in MSIHANDLE hRec, + __in UINT uiField, + __in int iValue + ); + +HRESULT WIXAPI WcaDoDeferredAction( + __in LPCWSTR wzAction, + __in LPCWSTR wzCustomActionData, + __in UINT uiCost + ); +DWORD WIXAPI WcaCountOfCustomActionDataRecords( + __in LPCWSTR wzData + ); +HRESULT WIXAPI WcaReadStringFromCaData( + __inout LPWSTR* ppwzCustomActionData, + __inout LPWSTR* ppwzString + ); +HRESULT WIXAPI WcaReadIntegerFromCaData( + __inout LPWSTR* ppwzCustomActionData, + __inout int* piResult + ); +HRESULT WIXAPI WcaReadStreamFromCaData( + __inout LPWSTR* ppwzCustomActionData, + __out BYTE** ppbData, + __out DWORD_PTR* pcbData + ); +HRESULT WIXAPI WcaWriteStringToCaData( + __in LPCWSTR wzString, + __inout LPWSTR* ppwzCustomActionData + ); +HRESULT WIXAPI WcaWriteIntegerToCaData( + __in int i, + __inout LPWSTR* ppwzCustomActionData + ); +HRESULT WIXAPI WcaWriteStreamToCaData( + __in_bcount(cbData) const BYTE* pbData, + __in DWORD cbData, + __inout LPWSTR* ppwzCustomActionData + ); + +HRESULT __cdecl WcaAddTempRecord( + __inout MSIHANDLE* phTableView, + __inout MSIHANDLE* phColumns, + __in LPCWSTR wzTable, + __in UINT uiUniquifyColumn, + __in UINT cColumns, + ... + ); + +HRESULT WIXAPI WcaDumpTable( + __in LPCWSTR wzTable + ); + + +HRESULT WIXAPI WcaCaScriptCreateKey( + __out LPWSTR* ppwzScriptKey + ); + +HRESULT WIXAPI WcaCaScriptCreate( + __in WCA_ACTION action, + __in WCA_CASCRIPT script, + __in BOOL fImpersonated, + __in LPCWSTR wzScriptKey, + __in BOOL fAppend, + __out WCA_CASCRIPT_HANDLE* phScript + ); + +HRESULT WIXAPI WcaCaScriptOpen( + __in WCA_ACTION action, + __in WCA_CASCRIPT script, + __in BOOL fImpersonated, + __in LPCWSTR wzScriptKey, + __out WCA_CASCRIPT_HANDLE* phScript + ); + +void WIXAPI WcaCaScriptClose( + __in WCA_CASCRIPT_HANDLE hScript, + __in WCA_CASCRIPT_CLOSE closeOperation + ); + +HRESULT WIXAPI WcaCaScriptReadAsCustomActionData( + __in WCA_CASCRIPT_HANDLE hScript, + __out LPWSTR* ppwzCustomActionData + ); + +HRESULT WIXAPI WcaCaScriptWriteString( + __in WCA_CASCRIPT_HANDLE hScript, + __in LPCWSTR wzValue + ); + +HRESULT WIXAPI WcaCaScriptWriteNumber( + __in WCA_CASCRIPT_HANDLE hScript, + __in DWORD dwValue + ); + +void WIXAPI WcaCaScriptFlush( + __in WCA_CASCRIPT_HANDLE hScript + ); + +void WIXAPI WcaCaScriptCleanup( + __in LPCWSTR wzProductCode, + __in BOOL fImpersonated + ); + + +HRESULT QuietExec( + __in LPWSTR wzCommand, + __in DWORD dwTimeout + ); + +#ifdef __cplusplus +} +#endif diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/wcawrap.cpp b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/wcawrap.cpp new file mode 100644 index 0000000000..490a5d6713 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/IIS-Setup/wcautil/wcawrap.cpp @@ -0,0 +1,1419 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +//------------------------------------------------------------------------------------------------- +// +// Windows Installer XML CustomAction utility library wrappers for MSI API +// +//------------------------------------------------------------------------------------------------- + +#include "precomp.h" + + +/******************************************************************** + WcaProcessMessage() - sends a message from the CustomAction + +********************************************************************/ +extern "C" UINT WcaProcessMessage( + __in INSTALLMESSAGE eMessageType, + __in MSIHANDLE hRecord + ) +{ + UINT er = ::MsiProcessMessage(WcaGetInstallHandle(), eMessageType, hRecord); + if (ERROR_INSTALL_USEREXIT == er || IDCANCEL == er) + WcaSetReturnValue(ERROR_INSTALL_USEREXIT); + + return er; +} + + +/******************************************************************** + WcaErrorMessage() - sends an error message from the CustomAction using + the Error table + + NOTE: Any and all var_args (...) must be WCHAR* +********************************************************************/ +extern "C" UINT WcaErrorMessage( + __in int iError, + __in HRESULT hrError, + __in UINT uiType, + __in DWORD cArgs, + ... + ) +{ + UINT er; + MSIHANDLE hRec = NULL; + va_list args; + + uiType |= INSTALLMESSAGE_ERROR; // ensure error type is set + hRec = ::MsiCreateRecord(cArgs + 2); + if (!hRec) + { + er = ERROR_OUTOFMEMORY; + ExitOnFailure(HRESULT_FROM_WIN32(er), "failed to create record when sending error message"); + } + + er = ::MsiRecordSetInteger(hRec, 1, iError); + ExitOnFailure(HRESULT_FROM_WIN32(er), "failed to set error code into error message"); + + er = ::MsiRecordSetInteger(hRec, 2, hrError); + ExitOnFailure(HRESULT_FROM_WIN32(er), "failed to set hresult code into error message"); + + va_start(args, cArgs); + for (DWORD i = 0; i < cArgs; i++) + { + er = ::MsiRecordSetStringW(hRec, i + 3, va_arg(args, WCHAR*)); + ExitOnFailure(HRESULT_FROM_WIN32(er), "failed to set string string into error message"); + } + va_end(args); + + er = WcaProcessMessage(static_cast(uiType), hRec); +LExit: + if (hRec) + ::MsiCloseHandle(hRec); + + return er; +} + + +/******************************************************************** + WcaProgressMessage() - extends the progress bar or sends a progress + update from the CustomAction + +********************************************************************/ +extern "C" HRESULT WcaProgressMessage( + __in UINT uiCost, + __in BOOL fExtendProgressBar + ) +{ + static BOOL fExplicitProgressMessages = FALSE; + + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + MSIHANDLE hRec = ::MsiCreateRecord(3); + + // if aren't extending the progress bar and we haven't switched into explicit message mode + if (!fExtendProgressBar && !fExplicitProgressMessages) + { + AssertSz(::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_SCHEDULED) || + ::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_COMMIT) || + ::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_ROLLBACK), "can only send progress bar messages in a deferred CustomAction"); + + // tell Darwin to use explicit progress messages + ::MsiRecordSetInteger(hRec, 1, 1); + ::MsiRecordSetInteger(hRec, 2, 1); + ::MsiRecordSetInteger(hRec, 3, 0); + + er = WcaProcessMessage(INSTALLMESSAGE_PROGRESS, hRec); + if (0 == er || IDOK == er || IDYES == er) + hr = S_OK; + else if (IDABORT == er || IDCANCEL == er) + { + WcaSetReturnValue(ERROR_INSTALL_USEREXIT); // note that the user said exit + ExitFunction1(hr = S_FALSE); + } + else + hr = E_UNEXPECTED; + ExitOnFailure(hr, "failed to tell Darwin to use explicit progress messages"); + + fExplicitProgressMessages = TRUE; + } +#if DEBUG + else if (fExtendProgressBar) // if we are extending the progress bar, make sure we're not deferred + { + AssertSz(!::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_SCHEDULED), "cannot add ticks to progress bar length from deferred CustomAction"); + } +#endif + + // send the progress message + ::MsiRecordSetInteger(hRec, 1, (fExtendProgressBar) ? 3 : 2); + ::MsiRecordSetInteger(hRec, 2, uiCost); + ::MsiRecordSetInteger(hRec, 3, 0); + + er = WcaProcessMessage(INSTALLMESSAGE_PROGRESS, hRec); + if (0 == er || IDOK == er || IDYES == er) + { + hr = S_OK; + } + else if (IDABORT == er || IDCANCEL == er) + { + WcaSetReturnValue(ERROR_INSTALL_USEREXIT); // note that the user said exit + hr = S_FALSE; + } + else + hr = E_UNEXPECTED; + +LExit: + if (hRec) + ::MsiCloseHandle(hRec); + + return hr; +} + + +/******************************************************************** + WcaIsInstalling() - determines if a pair of installstates means install + +********************************************************************/ +extern "C" BOOL WcaIsInstalling( + __in INSTALLSTATE isInstalled, + __in INSTALLSTATE isAction + ) +{ + return (INSTALLSTATE_LOCAL == isAction || + INSTALLSTATE_SOURCE == isAction || + (INSTALLSTATE_DEFAULT == isAction && + (INSTALLSTATE_LOCAL == isInstalled || + INSTALLSTATE_SOURCE == isInstalled))); +} + +/******************************************************************** + WcaIsReInstalling() - determines if a pair of installstates means install + +********************************************************************/ +extern "C" BOOL WcaIsReInstalling( + __in INSTALLSTATE isInstalled, + __in INSTALLSTATE isAction + ) +{ + return ((INSTALLSTATE_LOCAL == isAction || + INSTALLSTATE_SOURCE == isAction || + INSTALLSTATE_DEFAULT == isAction) && + (INSTALLSTATE_LOCAL == isInstalled || + INSTALLSTATE_SOURCE == isInstalled)); +} + + +/******************************************************************** + WcaIsUninstalling() - determines if a pair of installstates means uninstall + +********************************************************************/ +extern "C" BOOL WcaIsUninstalling( + __in INSTALLSTATE isInstalled, + __in INSTALLSTATE isAction + ) +{ + return ((INSTALLSTATE_ABSENT == isAction || + INSTALLSTATE_REMOVED == isAction) && + (INSTALLSTATE_LOCAL == isInstalled || + INSTALLSTATE_SOURCE == isInstalled)); +} + + +/******************************************************************** + WcaSetComponentState() - sets the install state of a Component + +********************************************************************/ +extern "C" HRESULT WcaSetComponentState( + __in LPCWSTR wzComponent, + __in INSTALLSTATE isState + ) +{ + UINT er = ::MsiSetComponentStateW(WcaGetInstallHandle(), wzComponent, isState); + if (ERROR_INSTALL_USEREXIT == er) + WcaSetReturnValue(er); + + return HRESULT_FROM_WIN32(er); +} + + +/******************************************************************** + WcaTableExists() - determines if installing database contains a table + +********************************************************************/ +extern "C" HRESULT WcaTableExists( + __in LPCWSTR wzTable + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + +// NOTE: The following line of commented out code should work in a +// CustomAction but does not in Windows Installer v1.1 + // er = ::MsiDatabaseIsTablePersistentW(hDatabase, wzTable); + + // a "most elegant" workaround a Darwin v1.1 bug + PMSIHANDLE hRec; + er = ::MsiDatabaseGetPrimaryKeysW(WcaGetDatabaseHandle(), wzTable, &hRec); + + if (ERROR_SUCCESS == er) + hr = S_OK; + else if (ERROR_INVALID_TABLE == er) + hr = S_FALSE; + else + hr = E_FAIL; + Assert(SUCCEEDED(hr)); + + return hr; +} + + +/******************************************************************** + WcaOpenView() - opens a view on the installing database + +********************************************************************/ +extern "C" HRESULT WcaOpenView( + __in LPCWSTR wzSql, + __out MSIHANDLE* phView + ) +{ + if (!wzSql || !*wzSql|| !phView) + return E_INVALIDARG; + + HRESULT hr = S_OK; + UINT er = ::MsiDatabaseOpenViewW(WcaGetDatabaseHandle(), wzSql, phView); + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure1(hr, "failed to open view on database with SQL: %S", wzSql); + +LExit: + return hr; +} + + +/******************************************************************** + WcaExecuteView() - executes a parameterized open view on the installing database + +********************************************************************/ +extern "C" HRESULT WcaExecuteView( + __in MSIHANDLE hView, + __in MSIHANDLE hRec + ) +{ + if (!hView) + return E_INVALIDARG; + AssertSz(hRec, "Use WcaOpenExecuteView() if you don't need to pass in a record"); + + HRESULT hr = S_OK; + UINT er = ::MsiViewExecute(hView, hRec); + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure(hr, "failed to execute view"); + +LExit: + return hr; +} + + +/******************************************************************** + WcaOpenExecuteView() - opens and executes a view on the installing database + +********************************************************************/ +extern "C" HRESULT WcaOpenExecuteView( + __in LPCWSTR wzSql, + __out MSIHANDLE* phView + ) +{ + if (!wzSql || !*wzSql|| !phView) + return E_INVALIDARG; + + HRESULT hr = S_OK; + UINT er = ::MsiDatabaseOpenViewW(WcaGetDatabaseHandle(), wzSql, phView); + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure(hr, "failed to open view on database"); + + er = ::MsiViewExecute(*phView, NULL); + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure(hr, "failed to execute view"); + +LExit: + return hr; +} + + +/******************************************************************** + WcaFetchRecord() - gets the next record from a view on the installing database + +********************************************************************/ +extern "C" HRESULT WcaFetchRecord( + __in MSIHANDLE hView, + __out MSIHANDLE* phRec + ) +{ + if (!hView|| !phRec) + return E_INVALIDARG; + + HRESULT hr = S_OK; + UINT er = ::MsiViewFetch(hView, phRec); + hr = HRESULT_FROM_WIN32(er); + if (FAILED(hr) && E_NOMOREITEMS != hr) + ExitOnFailure(hr, "failed to fetch record from view"); + +LExit: + return hr; +} + + +/******************************************************************** + WcaFetchSingleRecord() - gets a single record from a view on the installing database + +********************************************************************/ +extern "C" HRESULT WcaFetchSingleRecord( + __in MSIHANDLE hView, + __out MSIHANDLE* phRec + ) +{ + if (!hView|| !phRec) + return E_INVALIDARG; + + HRESULT hr = S_OK; + UINT er = ::MsiViewFetch(hView, phRec); + if (ERROR_NO_MORE_ITEMS == er) + hr = S_FALSE; + else + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure(hr, "failed to fetch single record from view"); + +#ifdef DEBUG // only do this in debug to verify that a single record was returned + MSIHANDLE hRecTest; + er = ::MsiViewFetch(hView, &hRecTest); + AssertSz(ERROR_NO_MORE_ITEMS == er && NULL == hRecTest, "WcaSingleFetch() did not fetch a single record"); + ::MsiCloseHandle(hRecTest); +#endif + +LExit: + return hr; +} + + +/******************************************************************** + WcaGetProperty - gets a string property value from the active install + +********************************************************************/ +extern "C" HRESULT WcaGetProperty( + __in LPCWSTR wzProperty, + __inout LPWSTR* ppwzData + ) +{ + if (!wzProperty || !*wzProperty || !ppwzData) + return E_INVALIDARG; + + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + DWORD_PTR cch = 0; + + if (!*ppwzData) + { + er = ::MsiGetPropertyW(WcaGetInstallHandle(), wzProperty, L"", (DWORD *)&cch); + if (ERROR_MORE_DATA == er || ERROR_SUCCESS == er) + { + hr = StrAlloc(ppwzData, ++cch); + } + else + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure1(hr, "Failed to allocate string for Property '%S'", wzProperty); + } + else + { + hr = StrMaxLength(*ppwzData, &cch); + ExitOnFailure(hr, "Failed to get previous size of property data string."); + } + + er = ::MsiGetPropertyW(WcaGetInstallHandle(), wzProperty, *ppwzData, (DWORD *)&cch); + if (ERROR_MORE_DATA == er) + { + Assert(*ppwzData); + hr = StrAlloc(ppwzData, ++cch); + ExitOnFailure1(hr, "Failed to allocate string for Property '%S'", wzProperty); + + er = ::MsiGetPropertyW(WcaGetInstallHandle(), wzProperty, *ppwzData, (DWORD *)&cch); + } + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure1(hr, "Failed to get data for property '%S'", wzProperty); + +LExit: + return hr; +} + + +/******************************************************************** + WcaGetFormattedProperty - gets a formatted string property value from + the active install + +********************************************************************/ +extern "C" HRESULT WcaGetFormattedProperty( + __in LPCWSTR wzProperty, + __out LPWSTR* ppwzData + ) +{ + if (!wzProperty || !*wzProperty || !ppwzData) + return E_INVALIDARG; + + HRESULT hr = S_OK; + LPWSTR pwzPropertyValue = NULL; + + + hr = WcaGetProperty(wzProperty, &pwzPropertyValue); + ExitOnFailure1(hr, "failed to get %S", wzProperty); + + hr = WcaGetFormattedString(pwzPropertyValue, ppwzData); + ExitOnFailure2(hr, "failed to get formatted value for property: '%S' with value: '%S'", wzProperty, pwzPropertyValue); + +LExit: + ReleaseStr(pwzPropertyValue); + return hr; +} + + +/******************************************************************** + WcaGetFormattedString - gets a formatted string value from + the active install + +********************************************************************/ +extern "C" HRESULT WcaGetFormattedString( + __in LPCWSTR wzString, + __out LPWSTR* ppwzData + ) +{ + if (!wzString || !*wzString || !ppwzData) + return E_INVALIDARG; + + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + PMSIHANDLE hRecord = ::MsiCreateRecord(1); + DWORD_PTR cch = 0; + + er = ::MsiRecordSetStringW(hRecord, 0, wzString); + ExitOnFailure1(hr = HRESULT_FROM_WIN32(er), "Failed to set record field 0 with '%S'", wzString); + + if (!*ppwzData) + { + er = ::MsiFormatRecordW(WcaGetInstallHandle(), hRecord, L"", (DWORD *)&cch); + if (ERROR_MORE_DATA == er || ERROR_SUCCESS == er) + { + hr = StrAlloc(ppwzData, ++cch); + } + else + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure1(hr, "Failed to allocate string for formatted string: '%S'", wzString); + } + else + { + hr = StrMaxLength(*ppwzData, &cch); + ExitOnFailure(hr, "Failed to get previous size of property data string"); + } + + er = ::MsiFormatRecordW(WcaGetInstallHandle(), hRecord, *ppwzData, (DWORD *)&cch); + if (ERROR_MORE_DATA == er) + { + hr = StrAlloc(ppwzData, ++cch); + ExitOnFailure1(hr, "Failed to allocate string for formatted string: '%S'", wzString); + + er = ::MsiFormatRecordW(WcaGetInstallHandle(), hRecord, *ppwzData, (DWORD *)&cch); + } + ExitOnFailure1(hr = HRESULT_FROM_WIN32(er), "Failed to get formatted string: '%S'", wzString); + +LExit: + return hr; +} + + +/******************************************************************** + WcaGetIntProperty - gets an integer property value from the active install + +********************************************************************/ +extern "C" HRESULT WcaGetIntProperty( + __in LPCWSTR wzProperty, + __inout int* piData + ) +{ + if (!piData) + return E_INVALIDARG; + + HRESULT hr = S_OK; + UINT er; + + WCHAR wzValue[32]; + DWORD cch = countof(wzValue) - 1; + + er = ::MsiGetPropertyW(WcaGetInstallHandle(), wzProperty, wzValue, &cch); + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure1(hr, "Failed to get data for property '%S'", wzProperty); + + *piData = wcstol(wzValue, NULL, 10); + +LExit: + return hr; +} + + +/******************************************************************** + WcaGetTargetPath - gets the target path for a specified folder + +********************************************************************/ +extern "C" HRESULT WcaGetTargetPath( + __in LPCWSTR wzFolder, + __out LPWSTR* ppwzData + ) +{ + if (!wzFolder || !*wzFolder || !ppwzData) + return E_INVALIDARG; + + HRESULT hr = S_OK; + + UINT er = ERROR_SUCCESS; + DWORD_PTR cch = 0; + + if (!*ppwzData) + { + er = ::MsiGetTargetPathW(WcaGetInstallHandle(), wzFolder, L"", (DWORD*)&cch); + if (ERROR_MORE_DATA == er || ERROR_SUCCESS == er) + { + cch++; //Add one for the null terminator + hr = StrAlloc(ppwzData, cch); + } + else + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure1(hr, "Failed to allocate string for target path of folder: '%S'", wzFolder); + } + else + { + hr = StrMaxLength(*ppwzData, &cch); + ExitOnFailure(hr, "Failed to get previous size of string"); + } + + er = ::MsiGetTargetPathW(WcaGetInstallHandle(), wzFolder, *ppwzData, (DWORD*)&cch); + if (ERROR_MORE_DATA == er) + { + cch++; + hr = StrAlloc(ppwzData, cch); + ExitOnFailure1(hr, "Failed to allocate string for target path of folder: '%S'", wzFolder); + + er = ::MsiGetTargetPathW(WcaGetInstallHandle(), wzFolder, *ppwzData, (DWORD*)&cch); + } + ExitOnFailure1(hr = HRESULT_FROM_WIN32(er), "Failed to get target path for folder '%S'", wzFolder); + +LExit: + return hr; +} + + +/******************************************************************** + WcaSetProperty - sets a string property value in the active install + +********************************************************************/ +extern "C" HRESULT WcaSetProperty( + __in LPCWSTR wzPropertyName, + __in LPCWSTR wzPropertyValue + ) +{ + if (!wzPropertyName || !*wzPropertyName || !wzPropertyValue) + return E_INVALIDARG; + + UINT er = ::MsiSetPropertyW(WcaGetInstallHandle(), wzPropertyName, wzPropertyValue); + HRESULT hr = HRESULT_FROM_WIN32(er); + ExitOnFailure1(hr, "failed to set property: %S", wzPropertyName); + +LExit: + return hr; +} + + +/******************************************************************** + WcaSetIntProperty - sets a integer property value in the active install + +********************************************************************/ +extern "C" HRESULT WcaSetIntProperty( + __in LPCWSTR wzPropertyName, + __in int nPropertyValue + ) +{ + if (!wzPropertyName || !*wzPropertyName) + return E_INVALIDARG; + + // 12 characters should be enough for a 32-bit int: 10 digits, 1 sign, 1 null + WCHAR wzPropertyValue[13]; + HRESULT hr = StringCchPrintfW(wzPropertyValue, countof(wzPropertyValue), L"%d", nPropertyValue); + ExitOnFailure1(hr, "failed to convert into string property value: %d", nPropertyValue); + + UINT er = ::MsiSetPropertyW(WcaGetInstallHandle(), wzPropertyName, wzPropertyValue); + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure1(hr, "failed to set property: %S", wzPropertyName); + +LExit: + return hr; +} + + +/******************************************************************** + WcaIsPropertySet() - returns TRUE if property is set + +********************************************************************/ +extern "C" BOOL WcaIsPropertySet( + __in LPCSTR szProperty + ) +{ + DWORD cchProperty = 0; + UINT er = ::MsiGetPropertyA(WcaGetInstallHandle(), szProperty, "", &cchProperty); + AssertSz(ERROR_INVALID_PARAMETER != er && ERROR_INVALID_HANDLE != er, "Unexpected return value from ::MsiGetProperty()"); + + return 0 < cchProperty; // property is set if the length is greater than zero +} + + +/******************************************************************** + WcaGetRecordInteger() - gets an integer field out of a record + + NOTE: returns S_FALSE if the field was null +********************************************************************/ +extern "C" HRESULT WcaGetRecordInteger( + __in MSIHANDLE hRec, + __in UINT uiField, + __inout int* piData + ) +{ + if (!hRec || !piData) + return E_INVALIDARG; + + HRESULT hr = S_OK; + *piData = ::MsiRecordGetInteger(hRec, uiField); + if (MSI_NULL_INTEGER == *piData) + hr = S_FALSE; + +//LExit: + return hr; +} + + +/******************************************************************** + WcaGetRecordString() - gets a string field out of a record + +********************************************************************/ +extern "C" HRESULT WcaGetRecordString( + __in MSIHANDLE hRec, + __in UINT uiField, + __inout LPWSTR* ppwzData + ) +{ + if (!hRec || !ppwzData) + return E_INVALIDARG; + + HRESULT hr = S_OK; + UINT er; + DWORD_PTR cch = 0; + + if (!*ppwzData) + { + er = ::MsiRecordGetStringW(hRec, uiField, L"", (DWORD*)&cch); + if (ERROR_MORE_DATA == er || ERROR_SUCCESS == er) + { + hr = StrAlloc(ppwzData, ++cch); + } + else + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure(hr, "Failed to allocate memory for record string"); + } + else + { + hr = StrMaxLength(*ppwzData, &cch); + ExitOnFailure(hr, "Failed to get previous size of string"); + } + + er = ::MsiRecordGetStringW(hRec, uiField, *ppwzData, (DWORD*)&cch); + if (ERROR_MORE_DATA == er) + { + hr = StrAlloc(ppwzData, ++cch); + ExitOnFailure(hr, "Failed to allocate memory for record string"); + + er = ::MsiRecordGetStringW(hRec, uiField, *ppwzData, (DWORD*)&cch); + } + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure(hr, "Failed to get string from record"); + +LExit: + return hr; +} + + +/******************************************************************** + HideNulls() - internal helper function to escape [~] in formatted strings + +********************************************************************/ +static void HideNulls( + __in LPWSTR wzData + ) +{ + LPWSTR pwz = wzData; + + while(*pwz) + { + if (pwz[0] == L'[' && pwz[1] == L'~' && pwz[2] == L']') // found a null [~] + { + pwz[0] = L'!'; // turn it into !$! + pwz[1] = L'$'; + pwz[2] = L'!'; + pwz += 3; + } + else + pwz++; + } +} + + +/******************************************************************** + RevealNulls() - internal helper function to unescape !$! in formatted strings + +********************************************************************/ +static void RevealNulls( + __in LPWSTR wzData + ) +{ + LPWSTR pwz = wzData; + + while(*pwz) + { + if (pwz[0] == L'!' && pwz[1] == L'$' && pwz[2] == L'!') // found the fake null !$! + { + pwz[0] = L'['; // turn it back into [~] + pwz[1] = L'~'; + pwz[2] = L']'; + pwz += 3; + } + else + pwz++; + } +} + + +/******************************************************************** + WcaGetRecordFormattedString() - gets formatted string filed from record + +********************************************************************/ +extern "C" HRESULT WcaGetRecordFormattedString( + __in MSIHANDLE hRec, + __in UINT uiField, + __inout LPWSTR* ppwzData + ) +{ + if (!hRec || !ppwzData) + return E_INVALIDARG; + + HRESULT hr = S_OK; + UINT er; + DWORD_PTR cch = 0; + PMSIHANDLE hRecFormat; + + // get the format string + hr = WcaGetRecordString(hRec, uiField, ppwzData); + ExitOnFailure(hr, "failed to get string from record"); + + if (!**ppwzData) + ExitFunction(); + + // hide the nulls '[~]' so we can get them back after formatting + HideNulls(*ppwzData); + + // set up the format record + hRecFormat = ::MsiCreateRecord(1); + ExitOnNull(hRecFormat, hr, E_UNEXPECTED, "Failed to create record to format string"); + hr = WcaSetRecordString(hRecFormat, 0, *ppwzData); + ExitOnFailure(hr, "failed to set string to format record"); + + // format the string + hr = StrMaxLength(*ppwzData, &cch); + ExitOnFailure(hr, "failed to get max length of string"); + + er = ::MsiFormatRecordW(WcaGetInstallHandle(), hRecFormat, *ppwzData, (DWORD*)&cch); + if (ERROR_MORE_DATA == er) + { + hr = StrAlloc(ppwzData, ++cch); + ExitOnFailure(hr, "Failed to allocate memory for record string"); + + er = ::MsiFormatRecordW(WcaGetInstallHandle(), hRecFormat, *ppwzData, (DWORD*)&cch); + } + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure(hr, "Failed to format string"); + + // put the nulls back + RevealNulls(*ppwzData); + +LExit: + return hr; +} + + +/******************************************************************** + WcaAllocStream() - creates a byte stream of the specified size + + NOTE: Use WcaFreeStream() to release the byte stream +********************************************************************/ +extern "C" HRESULT WcaAllocStream( + __inout BYTE** ppbData, + __in DWORD cbData + ) +{ + Assert(ppbData); + HRESULT hr; + BYTE* pbNewData; + + if (*ppbData) + pbNewData = (BYTE*)MemReAlloc(*ppbData, cbData, TRUE); + else + pbNewData = (BYTE*)MemAlloc(cbData, TRUE); + + if (!pbNewData) + ExitOnLastError(hr, "Failed to allocate string"); + *ppbData = pbNewData; + pbNewData = NULL; + + hr = S_OK; +LExit: + if (pbNewData) + MemFree(pbNewData); + + return hr; +} + + +/******************************************************************** + WcaFreeStream() - frees a byte stream + +********************************************************************/ +extern "C" HRESULT WcaFreeStream( + __in BYTE* pbData + ) +{ + if (!pbData) + return E_INVALIDARG; + + HRESULT hr = MemFree(pbData); + return hr; +} + + +/******************************************************************** + WcaReadRecordStream() - gets a byte stream field from record + +********************************************************************/ +extern "C" HRESULT WcaGetRecordStream( + __in MSIHANDLE hRecBinary, + __in UINT uiField, + __inout BYTE** ppbData, + __inout DWORD* pcbData + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + if (!hRecBinary || !ppbData || !pcbData) + return E_INVALIDARG; + + *pcbData = 0; + er = ::MsiRecordReadStream(hRecBinary, uiField, NULL, pcbData); + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure(hr, "failed to get size of stream"); + + hr = WcaAllocStream(ppbData, *pcbData); + ExitOnFailure(hr, "failed to allocate data for stream"); + + er = ::MsiRecordReadStream(hRecBinary, uiField, (char*)*ppbData, pcbData); + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure(hr, "failed to read from stream"); + +LExit: + return hr; +} + + +/******************************************************************** + WcaSetRecordString() - set a string field in record + +********************************************************************/ +extern "C" HRESULT WcaSetRecordString( + __in MSIHANDLE hRec, + __in UINT uiField, + __in LPCWSTR wzData + ) +{ + if (!hRec || !wzData) + return E_INVALIDARG; + + HRESULT hr = S_OK; + UINT er = ::MsiRecordSetStringW(hRec, uiField, wzData); + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure(hr, "failed to set string in record"); + +LExit: + return hr; +} + + +/******************************************************************** + WcaSetRecordInteger() - set a integer field in record + +********************************************************************/ +extern "C" HRESULT WcaSetRecordInteger( + __in MSIHANDLE hRec, + __in UINT uiField, + __in int iValue + ) +{ + if (!hRec) + return E_INVALIDARG; + + HRESULT hr = S_OK; + UINT er = ::MsiRecordSetInteger(hRec, uiField, iValue); + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure(hr, "failed to set integer in record"); + +LExit: + return hr; +} + + +/******************************************************************** + + WcaDoDeferredAction() - schedules an action at this point in the script + +********************************************************************/ +extern "C" HRESULT WcaDoDeferredAction( + __in LPCWSTR wzAction, + __in LPCWSTR wzCustomActionData, + __in UINT uiCost + ) +{ + HRESULT hr = S_OK; + UINT er; + + if (wzCustomActionData && *wzCustomActionData) + { + er = ::MsiSetPropertyW(WcaGetInstallHandle(), wzAction, wzCustomActionData); + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure(hr, "Failed to set CustomActionData for deferred action"); + } + + if (0 < uiCost) + { + hr = WcaProgressMessage(uiCost, TRUE); // add ticks to the progress bar + // TODO: handle the return codes correctly + } + + er = ::MsiDoActionW(WcaGetInstallHandle(), wzAction); + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure(hr, "Failed MsiDoAction on deferred action"); + +LExit: + return hr; +} + + +/******************************************************************** + WcaCountOfCustomActionDataRecords() - counts the number of records + passed to a deferred CustomAction + +********************************************************************/ +extern "C" DWORD WcaCountOfCustomActionDataRecords( + __in LPCWSTR wzData + ) +{ + if (!wzData) + return E_INVALIDARG; + + WCHAR delim[] = {MAGIC_MULTISZ_DELIM, 0}; // magic char followed by NULL terminator + DWORD dwCount = 0; + + // Loop through until there are no delimiters, we are at the end of the string, or the delimiter is the last character in the string + for (LPCWSTR pwzCurrent = wzData; pwzCurrent && *pwzCurrent && *(pwzCurrent + 1); pwzCurrent = wcsstr(pwzCurrent, delim)) + { + dwCount++; + pwzCurrent++; + } + + return dwCount; +} + + +/******************************************************************** + BreakDownCustomActionData() - internal helper to chop up CustomActionData + + NOTE: this modifies the passed in data +********************************************************************/ +static LPWSTR BreakDownCustomActionData( + __inout LPWSTR* ppwzData + ) +{ + if (!ppwzData) + return NULL; + if (0 == *ppwzData) + return NULL; + + WCHAR delim[] = {MAGIC_MULTISZ_DELIM, 0}; // magic char followed by Null terminator + + LPWSTR pwzReturn = *ppwzData; + LPWSTR pwz = wcsstr(pwzReturn, delim); + if (pwz) + { + *pwz = 0; + *ppwzData = pwz + 1; + } + else + *ppwzData = 0; + + return pwzReturn; +} + + +/******************************************************************** + WcaReadStringFromCaData() - reads a string out of the CustomActionData + + NOTE: this modifies the passed in ppwzCustomActionData variable +********************************************************************/ +extern "C" HRESULT WcaReadStringFromCaData( + __inout LPWSTR* ppwzCustomActionData, + __inout LPWSTR* ppwzString + ) +{ + HRESULT hr = S_OK; + + LPCWSTR pwz = BreakDownCustomActionData(ppwzCustomActionData); + if (!pwz) + return E_NOMOREITEMS; + + hr = StrAllocString(ppwzString, pwz, 0); + ExitOnFailure(hr, "failed to allocate memory for string"); + + hr = S_OK; +LExit: + return hr; +} + + +/******************************************************************** + WcaReadIntegerFromCaData() - reads an integer out of the CustomActionData + + NOTE: this modifies the passed in ppwzCustomActionData variable +********************************************************************/ +extern "C" HRESULT WcaReadIntegerFromCaData( + __inout LPWSTR* ppwzCustomActionData, + __inout int* piResult + ) +{ + LPCWSTR pwz = BreakDownCustomActionData(ppwzCustomActionData); + if (!pwz) + return E_NOMOREITEMS; + + *piResult = wcstol(pwz, NULL, 10); + return S_OK; +} + + +/******************************************************************** + WcaReadStreamFromCaData() - reads a stream out of the CustomActionData + + NOTE: this modifies the passed in ppwzCustomActionData variable + NOTE: returned stream should be freed with WcaFreeStream() +********************************************************************/ +extern "C" HRESULT WcaReadStreamFromCaData( + __inout LPWSTR* ppwzCustomActionData, + __out BYTE** ppbData, + __out DWORD_PTR* pcbData + ) +{ + HRESULT hr; + + LPCWSTR pwz = BreakDownCustomActionData(ppwzCustomActionData); + if (!pwz) + return E_NOMOREITEMS; + + hr = StrAllocBase85Decode(pwz, ppbData, pcbData); + ExitOnFailure(hr, "failed to decode string into stream"); + +LExit: + return hr; +} + + +/******************************************************************** + WcaWriteStringToCaData() - adds a string to the CustomActionData to + feed a deferred CustomAction + +********************************************************************/ +extern "C" HRESULT WcaWriteStringToCaData( + __in LPCWSTR wzString, + __inout LPWSTR* ppwzCustomActionData + ) +{ + HRESULT hr = S_OK; + WCHAR delim[] = {MAGIC_MULTISZ_DELIM, 0}; // magic char followed by NULL terminator + + if (!ppwzCustomActionData) + return E_INVALIDARG; + + DWORD cchString = lstrlenW(wzString) + 1; // assume we'll be adding the delim + DWORD_PTR cchCustomActionData = 0; + + if (*ppwzCustomActionData) + { + hr = StrMaxLength(*ppwzCustomActionData, &cchCustomActionData); + ExitOnFailure(hr, "failed to get length of custom action data"); + } + + if ((cchCustomActionData - lstrlenW(*ppwzCustomActionData)) < cchString + 1) + { + cchCustomActionData += cchString + 1 + 255; // add 255 for good measure + hr = StrAlloc(ppwzCustomActionData, cchCustomActionData); + ExitOnFailure(hr, "Failed to allocate memory for CustomActionData string"); + ExitOnNull(*ppwzCustomActionData, hr, E_OUTOFMEMORY, "Failed to allocate memory for CustomActionData string"); + } + + if (**ppwzCustomActionData) // if data exists toss the delimiter on before adding more to the end + StringCchCatW(*ppwzCustomActionData, cchCustomActionData, delim); + StringCchCatW(*ppwzCustomActionData, cchCustomActionData, wzString); + +LExit: + return hr; +} + + +/******************************************************************** + WcaWriteStringToCaData() - adds an integer to the CustomActionData to + feed a deferred CustomAction + +********************************************************************/ +extern "C" HRESULT WcaWriteIntegerToCaData( + __in int i, + __inout LPWSTR* ppwzCustomActionData + ) +{ + WCHAR wzBuffer[13]; + StringCchPrintfW(wzBuffer, countof(wzBuffer), L"%d", i); + + return WcaWriteStringToCaData(wzBuffer, ppwzCustomActionData); +} + + +/******************************************************************** + WcaWriteStringToCaData() - adds a byte stream to the CustomActionData to + feed a deferred CustomAction + +********************************************************************/ +extern "C" HRESULT WcaWriteStreamToCaData( + __in_bcount(cbData) const BYTE* pbData, + __in DWORD cbData, + __inout LPWSTR* ppwzCustomActionData + ) +{ + HRESULT hr; + LPWSTR pwzData = NULL; + + hr = StrAllocBase85Encode(pbData, cbData, &pwzData); + ExitOnFailure(hr, "failed to encode data into string"); + + hr = WcaWriteStringToCaData(pwzData, ppwzCustomActionData); + +LExit: + ReleaseStr(pwzData); + return hr; +} + + +/******************************************************************** +WcaAddTempRecord - adds a temporary record to the active database + +NOTE: you cannot use PMSIHANDLEs for the __in/__out parameters +NOTE: uiUniquifyColumn can be 0 if no column needs to be made unique +********************************************************************/ +extern "C" HRESULT WcaAddTempRecord( + __inout MSIHANDLE* phTableView, + __inout MSIHANDLE* phColumns, + __in LPCWSTR wzTable, + __in UINT uiUniquifyColumn, + __in UINT cColumns, + ... + ) +{ + Assert(phTableView && phColumns); + + static DWORD dwUniquifyValue = ::GetTickCount(); + + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + LPWSTR pwzQuery = NULL; + PMSIHANDLE hTempRec; + DWORD i; + va_list args; + + LPWSTR pwzData = NULL; + LPWSTR pwzUniquify = NULL; + + // + // if we don't have a table and it's columns already + // + if (NULL == *phTableView) + { + // set the query + hr = StrAllocFormatted(&pwzQuery, L"SELECT * FROM `%s`",wzTable); + ExitOnFailure(hr, "failed to allocate string for query"); + + // Open and Execute the temp View + hr = WcaOpenExecuteView(pwzQuery, phTableView); + ExitOnFailure1(hr, "failed to openexecute temp view with query %S", pwzQuery); + } + + if (NULL == *phColumns) + { + // use GetColumnInfo to populate the datatype record + er = ::MsiViewGetColumnInfo(*phTableView, MSICOLINFO_TYPES, phColumns); + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure1(hr, "failed to columns for table: %S", wzTable); + } + AssertSz(::MsiRecordGetFieldCount(*phColumns) == cColumns, "passed in argument does not match number of columns in table"); + + // + // create the temp record + // + hTempRec = ::MsiCreateRecord(cColumns); + ExitOnNull1(hTempRec, hr, E_UNEXPECTED, "could not create temp record for table: %S", wzTable); + + // + // loop through all the columns filling in the data + // + va_start(args, cColumns); + for (i = 1; i <= cColumns; i++) + { + hr = WcaGetRecordString(*phColumns, i, &pwzData); + ExitOnFailure1(hr, "failed to get the data type for %d", i); + + // if data type is string write string + if (L's' == *pwzData || L'S' == *pwzData || L'g' == *pwzData || L'G' == *pwzData || L'l' == *pwzData || L'L' == *pwzData) + { + LPCWSTR wz = va_arg(args, WCHAR*); + + // if this is the column that is supposed to be unique add the time stamp on the end + if (uiUniquifyColumn == i) + { + hr = StrAllocFormatted(&pwzUniquify, L"%s%u", wz, ++dwUniquifyValue); // up the count so we have no collisions on the unique name + ExitOnFailure1(hr, "failed to allocate string for unique column: %d", uiUniquifyColumn); + + wz = pwzUniquify; + } + + er = ::MsiRecordSetStringW(hTempRec, i, wz); + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure1(hr, "failed to set string value at position %d", i); + } + // if data type is integer write integer + else if (L'i' == *pwzData || L'I' == *pwzData || L'j' == *pwzData || L'J' == *pwzData) + { + AssertSz(uiUniquifyColumn != i, "Cannot uniquify an integer column"); + int iData = va_arg(args, int); + + er = ::MsiRecordSetInteger(hTempRec, i, iData); + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure1(hr, "failed to set integer value at position %d", i); + } + else + { + // not supporting binary streams so error out + hr = HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH); + ExitOnFailure2(hr, "unsupported data type '%S' in column: %d", pwzData, i); + } + } + va_end(args); + + // + // add the temporary record to the MSI + // + er = ::MsiViewModify(*phTableView, MSIMODIFY_INSERT_TEMPORARY, hTempRec); + hr = HRESULT_FROM_WIN32(er); + if (FAILED(hr)) + { + MSIDBERROR dbErr; + WCHAR wzBuf[MAX_PATH]; + DWORD cchBuf = countof(wzBuf); + + dbErr = ::MsiViewGetErrorW(*phTableView, wzBuf, &cchBuf); + ExitOnFailure2(hr, "failed to add temporary row, dberr: %d, err: %S", dbErr, wzBuf); + } + +LExit: + ReleaseStr(pwzUniquify); + ReleaseStr(pwzData); + ReleaseStr(pwzQuery); + + return hr; +} + + +/******************************************************************** +WcaDumpTable - dumps a table to the log file + +********************************************************************/ +extern "C" HRESULT WIXAPI WcaDumpTable( + __in LPCWSTR wzTable + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + LPWSTR pwzQuery = NULL; + PMSIHANDLE hView; + PMSIHANDLE hColumns; + DWORD cColumns = 0; + PMSIHANDLE hRec; + + LPWSTR pwzData = NULL; + LPWSTR pwzPrint = NULL; + + hr = StrAllocFormatted(&pwzQuery, L"SELECT * FROM `%s`",wzTable); + ExitOnFailure(hr, "failed to allocate string for query"); + + // Open and Execute the temp View + hr = WcaOpenExecuteView(pwzQuery, &hView); + ExitOnFailure1(hr, "failed to openexecute temp view with query %S", pwzQuery); + + // Use GetColumnInfo to populate the names of the columns. + er = ::MsiViewGetColumnInfo(hView, MSICOLINFO_NAMES, &hColumns); + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure1(hr, "failed to columns for table: %S", wzTable); + + cColumns = ::MsiRecordGetFieldCount(hColumns); + + WcaLog(LOGMSG_STANDARD, "--- Begin Table Dump %S ---", wzTable); + + // Loop through all the columns filling in the data. + for (DWORD i = 1; i <= cColumns; i++) + { + hr = WcaGetRecordString(hColumns, i, &pwzData); + ExitOnFailure1(hr, "failed to get the column name for %d", i); + + hr = StrAllocConcat(&pwzPrint, pwzData, 0); + ExitOnFailure(hr, "Failed to add column name."); + + hr = StrAllocConcat(&pwzPrint, L"\t", 1); + ExitOnFailure(hr, "Failed to add column name."); + } + + WcaLog(LOGMSG_STANDARD, "%S", pwzPrint); + + // Now dump the actual rows. + while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) + { + if (pwzPrint && *pwzPrint) + { + *pwzPrint = L'\0'; + } + + for (DWORD i = 1; i <= cColumns; i++) + { + hr = WcaGetRecordString(hRec, i, &pwzData); + ExitOnFailure1(hr, "failed to get the column name for %d", i); + + hr = StrAllocConcat(&pwzPrint, pwzData, 0); + ExitOnFailure(hr, "Failed to add column name."); + + hr = StrAllocConcat(&pwzPrint, L"\t", 1); + ExitOnFailure(hr, "Failed to add column name."); + } + + WcaLog(LOGMSG_STANDARD, "%S", pwzPrint); + } + + WcaLog(LOGMSG_STANDARD, "--- End Table Dump %S ---", wzTable); + +LExit: + ReleaseStr(pwzPrint); + ReleaseStr(pwzData); + ReleaseStr(pwzQuery); + + return hr; +} diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/bitmaps/AspNetCoreModule.ico b/src/Installers/Windows/AspNetCoreModule-Setup/bitmaps/AspNetCoreModule.ico new file mode 100644 index 0000000000000000000000000000000000000000..bcafd4a5b717c275d5faa24c71b494ce9696c4a9 GIT binary patch literal 894 zcmaKrOD{t~6vw9#dn>VHCAQ)Vh>e}ZUTh?2P*kewqN-YN78>toQPNggTGfZDt5hG@ zu%c4WD6L209ShDiHMzMObI+MMIp_C3GnvdqhzDO%5`sAel_nsRj1bBIhZIT!XY$O* zh8lPDDjPawwe3=2TcbchRYTI^ z+4WAd#=bOTS)7tf$~X*>LqI#NK6=@^Zgl_b;xNrAsB(N}Hb(kyZ8-e22@LN-TeWSC zm2r72@whis-Eu`!ZJm%W6${{QyPB&pA9wb8HXrXU!0v8C(Qxqg`lzo}gj;dWgOdU8 z_Ah@L4W9t7>Zp&)V|l>0qn;S*RLUAef)+~HEfDD-#T2Ej%RF01_L{ z0T1T)dFZuO$I7Bvuh!2FvT*KuW0(HMq&Ybc&kg^_Ma++3b%BZkm&DW`uzo@wE{&=2 K7$(Mlf%Y4T_a{vN literal 0 HcmV?d00001 diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/bitmaps/bannrbmp.bmp b/src/Installers/Windows/AspNetCoreModule-Setup/bitmaps/bannrbmp.bmp new file mode 100644 index 0000000000000000000000000000000000000000..8507592b05e61465063f395f77824e3f6b00a9a5 GIT binary patch literal 5950 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 JuAHcB zqbSKPU~maWQ_j@NWhH50nLeg z6mS8KNh+`%p|~P=`g|_g#4wOvgL63s>wUc?SZ#_6XZv=AdBphC;EJDG23Hiu#QgND ziY?ZubEgtbcisl`ZKLA%^0uj_zYH%}rfuh!F<%I+EJ+4zcHuuQM|+gDJZ#D->@Uj= zV_6%v>7eV9n8VlCI^UyQuYgDMz_A=anXTGuOTCwG;bxffrxp)->tRxEAZ3*-Q#d8V rC%{Kxpa5qSV_@Sryl917b|?a${wu4tw%-z8^82O*|G!A_oXP(NBma{m literal 0 HcmV?d00001 diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/bitmaps/dlgbmp.bmp b/src/Installers/Windows/AspNetCoreModule-Setup/bitmaps/dlgbmp.bmp new file mode 100644 index 0000000000000000000000000000000000000000..c3810b4037ef343c5842ce36025c0dd06e26b6d1 GIT binary patch literal 20396 zcmd422T)sElRqeM1Pp#)3?`dwvJuIE0h19Kkwr2Y0U`$j2ID|ZMnn-!5FkKgi43;M zIfyJUCYp>*HgS3NpP8NaZM~VP{bqKjRjPBkfA`$`)4hHAp6*k+n!5T9_(N3*qy!)! z1ORNVKY*((0J(ydZbs_w}<;K6s zzYHfNAh<@azyAjOS36gq0pxcHo)K){ARq@2k`vq@C%9?{)LzpjxJh_};F{>a2=VPZ zcZqJ15Zt(VeX&2~Ux7bc0>T?N{{R4P-5?~qed{*y4WfG_*Z7~-Tet6!-=&~r7SyrK zc_14=b%jL? ze3CmkeN(x}2>^tETQ{$Nrp zkOANY8Vl#MMka=~%vE z;cP_BK&3mA4i#aC%=^-9wnEvWB^-YL1OkR*m#{Z!BP3Pv_J(;ktc3I9%%rF)d1M3q zC7H;$2AW|pxBX!}u;!WX8JaEIL9inG$)c8KhEM)#u4gujz_S8aQJ;oNAE8wTO>!nJ z^%mmD`-A)1Hoznh&yr|+td93r(_QDi6?sZwo^S<-bOheFV6tLdfh{?IP{`kwaqiVR zF%qEqba(|=TY(nZtN7RWFl9FmPM>&76>P^tyyIUsL6j8N_%w%Q5mB2<4LR_1o{C>b z(z98MD5H7$snpIG9Xxh;Q=gbjs%HC4A_iE^%I<1Fav0&&=aQ)&d;wOVb@riV)<`dL zl!S`VFteGPtHekY1C<8Dp8oqe@*ngG3NovDU?yfWg_NP)L$GITCwill{#O9~iE>${ z0qN0o!Of+(b*Fm?g(}WHY)&BPI>$%FLU*TOk*BXQ)^!@o7L9ht5jva})ceAjA9b+J zF{uM%8!^%udj0l6E2WuPsEOO2K_!fYCC)f~~!WzY%A&A!twi2aJHO9SLom}{A0paNPoHHxei%3*qP&x9{3lUcSt7BW-0hG{@`h7 z)U0?aI<;q7g!lqRJD7KF^Yn(>aPEsRwtGmUFiC_+?g6Urkntba`y`u^c9R* z)B4&ZT5UPd;_{j&%2(X3J{kzS0;KRZ1q7Gl7ex@S&5Y|yWJp!I`+SKC3UB9t{YP^Q ztqfjve>~Tk93&4dUZevgGuwdH>q4(P1k8nGKvzq5FeQi(!kt={fXKe>E z^C;z`uVvy6Pb1GVzVkfEEHgv!u#&sb>7hM+SN_b?qA|6UM5OW9B(q68#eRu=w_Dp*nq1*|9t{Ee;E%IdZH}W}|m6Y34 z{3W~=WDCnjO6)()$`#dbyQkH_4i2)3!}Fl!-}f+lO1S}%5{^uoC0bCl5t_Oh;jGvg@V5r4e1G?6xy){i z%eu>mcrHF3`L#t`Oi`R>)dCBvj1hvtP}!LXBBom>I?G3yS-G{J*T>OtpW8J~D=jPT z#jm}A&6?yk<;VZQZ2I>QLBT*Ni&MJZjQ@;@O$aRI#*+vY*0swLnAx+W^|7$>SZs7g z@K{SMr_T5o9LT>XFhR2>4=!3hTff*mvpV*(D<_GXv`;-N{GtcGVD!Xom!@HMJP;vDN2KIl0?UZN)L+HRs;F86KME zogkN7v*e||{M6$9xenbQpSQs@os8?f+XR%fuzkfm`hh;~A0FxQJ%Y{-)XjvflRi@A z&&ONM-o`u;90w%z3Na?Psbldr(C0gE*_nJ-(szdE<{SCr8r!%1r}5@@`V;%Uo_9~I zbisEL86sZbV_)?85Y!5B=$4ETjnO+fVq7LTz9PSPq$|AFDr$<=sHxl2cT1(EnjLBn z+<|{J`G~aP%L!;Oo3;HBomRWO>HBo7Tm&}BkXEW@h9@4XD-C#Xq|8!ljDQ-4J0_@< zj>CEt?bt<#Vi-E}YKACV+SaC(+rLydRn{}4Sksly`EuSfERF1-bDes?Vuk)3gy*3b zN!u9XVJuhWkwC@$vIg_gVD99q_|wmzjh6hl{E{cx^Z8Wbx$g&%Sq?svfnjg01OrR^ zL4FfrmKa_`{kjE6veZU>vVrS>0hYc2I&W)3=d+U66~xA~R_tyg`qe^V!}BgUiNUpM zJN`4SdE-b?jdN^E7}n>mQjMa!4m@09Vht1A)-;^%iONVN3@ns&pjQyc+xzgCpPQx9 z#O~b+uc%jjRDp7550XH;;A|tL z=4sHp=aEret>TLT!<+uLMCan_mj%qQJ|W17)-xFdH|D%v3%fqTs|Ig5g&&dydW*yw zC$A&gy*jgzl-9D3ouSi>o!(301VQk2&w zlkbJ4Zw*%GyQsFK^vljTW*c1T11;KXrR*{yyi47^%|v1T3pE^EU4JxaKq_CFP6j6E zB+qE8iE&}X=Yv;j9jK+Qnoj0&CSZyf1Xr0Q_fnly5FR5{hs~c`UJO084#lr_aU-07ZeY@ z0^FrZ$*=ic&emsk^K(!{!QK85vGAe7D}Y~f4r0wr;u%`%-Ks6T0xv`0GUU!BH(+C8 zIsN4q*SLg#mfpPBai5Ukr&sl_M@@+6KmYr9^dIzZr}-3Yw5$h!gxC-~&PEInn)UK4 zKolCxx(-}BzcJah^sbHlB_f-+sm3Q|KeF)Iy2xTns-Re9fVSCf+SL^n3O|M=$1BH^?VP1mTW>oDZ;y^2V zJ+4yG`Xm|P^GSp7pLm71BX;pbsi|+f8C|~CTWuNjoPAiVPTbFtt35>ApSVhJDF<6s+B{Y zsK>*s^N1;$A^)-ulTyszVE*$orHQTQ9)1IH=A_&sxJPP1@3EeU3>p|M2F^rqXlCH= zdf%>6O;oVX(|cy^_~^_JvpuVc^%PaEbYI0aFQ>=%(K+|mQ!{MGZgipTGU@~DX3T$< z8c*#tgPZkJD>%0=wna%L^4!}n8)S5DgYi$Z-*T%JE6oZj4Qw^BCO(a|uJa^$xLN%W z*7yATI}@w{M+YUzM0UC-6+^!->B^ZvOp#9@QZ{G`5&06AC#dxio7S1i?)f>qQ99-D~h-VdbwZVZ>k;hxAJ)6bmwdT&G9gk8z7sjNrJv=U>?ni1;$@ zsPa#ToNzmTA3%xd(7vyGUHcI%z|Q_+w~%W$Z(lEW9ar<}_v?|0%KrZ#K>Y=RrbD4H z6QvoJ6IKDUvhS=w@An1;rH0UK)w(E)-c809nOn9unfOfUbr#~iy%as=&LNM+Vg$}r z&=uJp$p@67)2cQ2f{c4enN`0 zM9Noy7j)KZV-sdf!-9DXTq6ZTL88cCLNKRQq=ZEy!S8$p&=nv*;7w_Gf2fEbSqCpV z(*2uvr`R{TK7$b2lTHM1vShlpxzPA!Mxnv>#;CYPNs%w_#>Xw756uU^kmaKm<1)wKX9}uS#o-{8W!a) zt<+D=M!K}Mcu{2XtoOq}hv{4U#ph>sw)mOvNu<+b%VLDL&{n;$>Ln3Lsgr(k$72fT z<){4j8z<_u8oB*?nrpeX4)u;#Cq4G-Ibg&o!1JgY$r5%w2Ql56vsn39z3&So*>nbl z%{sZF>$(NSuOkE$O~XiE3Z9BJnlnCjA~zc^_f_O!-%jf|PB`oHF#mppi*#3F_rU}$ z;uBcxX&KvqulqU04aP|%mzsneOv4@LYh$LtYr_6GejL|e0Wgn48|}u_Xtz|qXD~Qf zcTv)x1CwOhvHoV6Rr&23aJG@-q(&6~p-NHaK`)+4qWcIV+UUE~=R@g_rYN*1n2AT~ zL9y-CR^llBFTw@G7uEva`V^JMQ!9OmK7~|fZF_o`m*UyT*;6a!8!)DpU{y~owiD%6lOZwq z_1IgkXel8N){<`flGns>lq;eagCC811&i4dL2y09hvv>n^D6V__d~20l;k5{jI}S( z^sY8d?z9OIm3(7_rF_UY#b;fP@g>yPAx|3ac{2$h7^IlW z#~Qr%%~=l)Q)p<&9k>qziQ?%`BS5TDcgMNqw1xvE8c|N`1OwX`kikzerqBL`JD92^ zK6>2{T$1mMMIu`3Y-DL=-?k$DzaEE7pqji#VKoobdIe5PVJ9afw|bJcBsg4p zg)^AVx{R`NJaw(+Q;-z1vzN>zhTKONrOVaDW6+vjZ$i((rqGz0T)H3S8!2slaBCRr zy&!Uip6_&Gw$ouZ%n;dhCN#+<4H>mb(7N7Mzmc`t#4VW0=Q^SW%sy3^#A{<$yzu?Z^>SS^iI5X-6F{6rX8$Xoo_l4+?^_?KA!W(AnNj~Ut`m8!#1@8om>}wIn!O= zvtcR*(ipJ42t$2j1|^vweB@AuOKJ(;!|VFAifE25R9D8Vv4Fb5)DL>ZK2eYv z;7YRgbzod;bH$6`74hD@gQlb;^sKnA?x!wjS3#?OmB;KR_jaL>7A%SD znBhZmI*201lv_2%P2vh5&5`lDhHvw%voe1!Lhp%j!4V>c&l#FnUaEFu+bMv1#eQc4 z&EK7iPg3>r&{S&RnmDKvUMiLok4HYO(@y=k-VUa1UwTG#?#kqZ*mYyv#Xlf~)W+PF zw$ACmkDDK3%6SHV);goVa8hbucGR=q?#_l-x1>+R+pj+JIiK-XD%5h3@3q8&MN zcym^{Ve@u#K3i!dH5=RY%I`r6J#jejvb|-Qg-uV&Nt7?+Ui1|p6N~(?GVF$(;1M&Q zuEP4y&OVP1b=mA(eal1c5=lkzUcS@k_3IURpOMQtKGeN&%d%?S(&G8|yo2%{E6n$} zqN4=|F85#0Wnw)uOVf_{KG&M9VCLSs3?3dQEj2}0>Iu;M-f>U;dRh0Ak*nhm^zKYi zp$4`p<}kcGs;3TT8qeHkkPg6mBUR-)n{Icbn}=LB+3ck@%?&O*?^-vPZn5$ixJ$K# zI6X>UZxZ_E9%J`Xl1FgPP)|LA?kU9Qi1WRfrfhhW4mXzPZW1F+BWp}8+|~tV#Q7m` zG3)60!Uw0{K|M1`)$vyVG&-ZPuJj>e`n#QeS0^K5ewY?@>x&NOx#Q5~jbCEos>Rkk z4do^w+V9etH!zM--OP3FKe{|5IQ&_m=_G?mW?e7+j+6S}-)+ts=6Vdr-}>=le+O=R zY*e@eK%DK0Up2BVI9(pM@=RbAs>rM!Wz~$Cg^7?js(WylflB=C9BiG}RHR<1y)Vzt z6sCcm*f>DQ;yF|$oUaQ`Z1FVIN>$?p*~9Ax8zK}n$b2qX(II@)YwTc^?SNV{`=ir3 zEmylrLQc^@_YeY_lMxY`%P09@@W8F!6pjRGm-KN${3Ai zE|6|qe0&K7lE=OO`e(^(GY&NZGb3*{2{)E`{dT9rF~MtdU6!WkHA zgUXe*=PAk+mID$Wc!Ivei_+>>a{x?itre^^lkl*7-jDFl()PI3V4-#q ze;;ye&lddLs0upzl3pZ7pyDi?Q_h;0R;{6hgs(uOB;iPOU+liiu=t+adWu7pL6{ zAk&=B#vCw4qSy7sKfGTDTH+HONy`;WayUYii?m$Odha$g+}XQCp2W73cKtxNET9Lc z?k{d_+u*8hMIV|cxv|6nVRj$S>E3VgF%sw;$*v$&YDXu>z%$@ zh9r8tH*Q97mm*QbK?+N{C6HtcP3{wSeTF<(8cK6kpTq7!#ayAwoI-O?ha!WZPU_^D z@LXPpKeteSy|`+vP9GviBdu=M__DH#3MuQt|6|%joHJtcY+7!hw2)_t)=;+ zhQ#$oL16@xCH~$s<5DLzB{Lh}xCK(kX$Ga>__3g%-YT0{?{A!Bz z<#IUGr|F6I=?#gXMMXXOX!+FPL%&?s$!iCjA1{uQr~5+5du))!B4)BK#4@6zW}(?Y z*KR*1#-y5GSZAl4i!eZqJ!-&-UkgHm~RNF(S zl3(n;-1GFyvu^wNAH;>fK%3{CGJo7KDx_H0QVC%2*n6%V@oVtu1zK~Z)jo1r|GoVP zTHjDt?lRYjQ|ZiT{rQ*9AMAd&f80s?ai9DU*C%1sND{)dsQTmz5WjQsMzegcO6J&S z%LbC#vJDpZ3F4rp#a#jR2RfkRWm^f81s?(>J!D>FP1E8>r^x~ec1zcu6L+(+C0bfyVmuBHd^dHO6FmVnM8a* z{pl58aIXBo;ep%58w}Lw3ScO6=|X!2Pzs)9+J+d&j1OG_(tTP-GQ{r7{6F;xneo9l zR{+z;t@T(q>FDz}7^go^A)d19k$vF!e+-a=vxcO?OMacp80NZHGLeH7Z~Bn7Ct_aj zE@|bx;t)fT#brM%8qv0AvyZO;jo6QKtT6$Lh+?U-mYu_Rro3H;FNc@gv{6m&TCcS| zzfD^BCPYl0Z&}lvZ0B3p#L_Ca<2aO>f_D9GmH(bnl)2uE<;Y#5o5oZr6#c$@61=5F~*`4toye99_O`eEo6pq zgNBIDu@HG+Tw{mkxu)v#tP4r3C%QCl@ct>|47w0iIHqGDbHL zyT499(+|Cgn*gi^oCj6h`ENNoweYLsF5>uXeKKsPeCarLSNih<%D*T1SA+oP`u`El ze|HNwKtB^CSKm0?(QK0O)?#Xk^E(0{9{-it-)m$D7w1N;t{H-X6zIv>3-PLL877B2 zqGp9l+kn-+n)AR<^wU1saWyy6`EkFFf<0|#f~1GZ{u_r72w8lvoEJNj_19Xx7z+rL z@zccZ5D2~ad&+-B82Dcgz3E#E_LRB;2;^S7$$3lowJYqMKEC#i|4}fz(3m{to=(+M!ntUi|6eDI?czd}*O@?brXK_M77^_fwt^ zZU3=zmVa`w+89-Fb3FL(iT)MwO7pxkV_tOx_+Qbai+!2+!E_XP95~X ziEzf!<;c!%!=3zQ8Grtv&xCG||H}C9HHl~S@3v)(&j8~88yZcS@134;XDSV+(mz@f z4ldRu-vEfZ{+|6mAZva5jaLAb8-u$SkMB#i9t1z%xdMy={s)W%;^psty?!&Jh8sVY zJlLE(E;s^Y4F3b2zg5Yi;+{1&D-ryl_AUDSd~xUS(VYylZ+U?IsK&9EjPAbv(KiP9 zcXfjOI_5T>-v1{LC6Lg1H*if=XYN>h``}{Z&s#bY{I}fx0az>AzrP>#`9{CYpa9_h z(<{KUCcyKy^TnTl|6x0UMC-dsQ;QkHQRTwf`RenHMu29;Kal%d^^U?kVs7aq`1#;2 zQ#-+`@2ktl_k|j}egXV4zsZE(=->Hu{({loH*OKIFWL0wk30Vj2WO^yQ7;qN=3B#Q z)z|(qAoO|hx9t7_kYNA(r^Sy&=m4<)xon8yDA=u}x;;4P#h>PX5l!6p{7c*U`tm|E&G<)B#48zqP7qh4{M@m?x&<7(ypDcUv}kun60N9!-hOvM2Dw{OB?J9Kam^ zywq2d(?RSU@K-TpqJ_4W$Bm|Fl)hJg6ggR-nAoEdzOk+9`H=Wfs-BOJ7}R5%2l7H0gA*mzm5*?8x9B=tMD=QNQvze3aBh4dKcytU7A_^Sap6T(uG2 z_k)}~zyE2UD;?i#(3%Ui!=osgNpAFu>?3cFm6DElxf=8|C{Qpf&Iqk#i%m~?xI$qT zJ!%Gz@z*AlljJ{fUl*rOF`1pvZg!~Y_MnIMYRcq+7pnQD_Vvl9P{m{OMH*@@KizA7 zbvcX;mI!ld2G1bVcfiN8(}xbClw0?b7vb-8_w%aN)2X;M zOqE&%_f=K;yDtb(7t;Z?$JW*MI+DEB2#->~a2E|uj_E$htgk4!k4i=GOMGDt3^&5w zO!~YRq8fdmn)vdm!oNQJo7>XFTB~MfX;*-UFF76l)%>5eH*!q@w-*E3pJBUuv-arK zsLl%H(J!j_&NkV#*B?^hgD4vthCelOOu-NArJX~DH$2F}wh}ZCehwqak=&0NLPUr& zIU-1VF>S_3ZIpvwXm+u|hW5JG>bJx_qgZ_Pk7h<76MR4a1KVWrL@rxABDmhG7{vEP zhnm9R1L8@Ghbc@!Nx3XPg$|I&fK5HV_~8ewC~LCHt_wMUOGf>Qa>TZLk+Y!-A@G+*v(6q(w*3gQFRR}-LDw!EIh3yz zqJ`oy*N99Emo^FOtY_4saa5?*39aGZBoDRXLn=hh(6~=h3o2k|b@|!gvxa&u9;lc< z;CAyQusX;Z@<{^#61j5e)z9u_RJBH#5o0BbW-)D-b@W!PwdGSn!1D&*u1KnsO^ete zbfexg*K2>wuS;oyn}^a8947>%6(`c`Jn%iUs8|_wfb&g>xtM>^v%M&riy?lk>906$ z%~fb4#XoBslJnb*PIsfQ>K6@7PKur-Z5}Ht@LHtq#eM4TD~)b^@h{%;|31vvD)smZ z8BVWmJZ)KA*I__a$CjG0x7fau(biXP)DW3J)D|8zD(XT+#IqeZgm}EUx7G7!4H+KBQ+lSlT z4p-nO#3Bv0Mv*p!z~!Ck{EJQT?ig5<&rS+ zgmV|n1eFSNu!`4JDrs#}lup42JMQ~9^zf1Q-G_Gv)Za@yK*iJQDSuRj9Z}9xkP@@* z2xrU2)6f8p^f^auI`yDB`dqn&w0Ha7s<l zFC*&EBnpp9Zk>2Pr9JD9>rGqER|`~rlvs8bU7BV|yI~-TgzYx!ul@`5HHA)$J03$8= zkcc6_-Tc|kZscO#q20Pr%i$JKz3F0$Ft^y%eLIsRcWvf1=)zhX-F z#FOgmg0Y2tZHokAEk04;$SQCtMj%X&3j`D*qXhgD(ezG(e&zGao}sxrynTHVMxY&rE1}WH8Xn7LeR&1 zeRzy{r3x%uxT9Vo$t-ZA`HN!wlb!~)h+4%A2f-Mx6joCjrS=?+kIOzTa^>0# zfgx=9%n=Xx#Hb3!a=}DUr2+*T|Ljk<>0It`t*T4;7&_y#Eo+?K)q~2$K6Sz`E)3%| z8)5Cw_nu6`5V}dS+=_l_?{DJc6ghD$63GQ)vBI=3jOlK0uQcVjgV%bF!J4)a76ojD=e^!Rs-xU~$0Mbs$U}*R&vkNWYC~gP z@UNt*GPX5m-lQ)?MBogE0d6T_gMu3j+yQDcv;%DhV-@7?xWQsi%-u3Rr!t zC=n#wNKnY3ETvU`Zky=kovq`QO7!rox~#jhEV{=ab(dW=Z+NxO!vmxcK2~f(VUb+M zF>0q4M<%c_3fDo|C@2KJ5b|_FETU6^&T8hZzSE+aw^2qSLf+r@az`DohmD%H>m*#> z;y^m@A2!OatH^QmZ;FXTY`*)?kDzbejZZO^vUV}n%W8xbN$goJITZWYf`O7=HK^-g zp!!%M8dSvs%a3QzKVXZ>{~WY&ED1cRr-@%>JE_y8PiBWl<;N)YJ=>+u`x%UV$mOxj zr2qr*CkTzFP?(t~d}m!}2jnm6tHva{*(As z(!a>P&T;#O<+2CR9HvjV>Wgxmgj7LFjw5WDBF5Rv@z5Nav>F-ZPq)^(RIq|$B6CS0 zmB2MWWC5{;0(PymC^3mLD1kMFy;`{Lmp9gKM#i9!@+UY&|NLU&pckVFu>uKE?O&9%QX?BHZ(x z9;u!~iH@Bg{~qR1ug}dEgx@Ja ztF0YIL^J={n)KiBwd;}oPq}i$34s$TLJHKB)1?@;I#1M^T=*$GcX5-TV!Ocp)w9^W zGTri9dh-?hr!bGVUP{PM85xS;F#e2)igXWk1%7o~6`|{G8qh&J;t$eLZFHYKgLWzO zz?*+B&ai0>Y{zQi5-(e>GDjxbV=_v`zloVhpHn8!*_Z4i_j$V!d3 z(sUaU?8)@rA(hN|K=-^L`dph6Ju?Szcwc_>XV1Pmn3qu7Z4DnpuGjYhGw(G8rR*Ly zKhFkXp|!_M=8}!E=JxG89;@{w6wvA0Gmam|hdd^DYI^k=V(f0}!rO^}-4R`MK$s(| zTIdLhOUJ2*blR5wI>FkM?SqhW6sk!})7&>PNz$<8`n{@zH7>F&_AIzg4G+NK2YeEz0ElT< za|7S*OB~wQ9cdS)(*UHBsZI6T+3>ca7jyJJGU3ufHTq{Pl~ztbHKTM+Rc^(VwJ#(H zR`DnHz~4{i?U_Tgz-zdYQ-Dd@2V0t=2H{DK`*K3;PAKo>!jX%|e9a2T7s*Lu1uFjG zNOI<5z0GXBJ&bwILzpquqL% zab?ulg03A1#g&iUm__Nbqmw#xPzBQvc&-Q+EVMh|O}CdiBD%yyr%Xa9gG{tl zq}R+NakI2uV!r$iA;IdiX||u?dsQ$&1JnYXMS^&1D2^e#goV( zi$?DFb#%*scw|h6eu`0A|7|1)!Cs^RO3klHVf1dtDyTx@^dIR00G!aD;5WeC*~ya< z0?B_}V*i_u|6PZH;yZw+2@2-c-+ckMd(D%Yx(erf*jd|+V_*wCH7IlH6OP|V(4nSQ z`UGsy7ydr${j7&oG}dal%Ekuj@%;V%6oe8q0tHiD|8<8TYl@n4a&dZ+Ogshhaap3; zYqCghx>(Fo@jCWWd5jZjHE8H&e+->SLeq2XE*G8X*;poH6OKWGT&q2d8c%b8o4=Ml zxjrs0sah+&OI@uQ@*Yr&;iKqb;6Mu#yq+tw5dF}jH?z%Bc)xr20 zgGAaiKIEsMF3BKn;EDj7usumeqHfzjXlOQbm<--xNIT~x$@2_Lq6OA=Hga+wZjW2(rH--S1OZmjU@hRp+LxN6^#OpDiyM ze%XOBj>-C00Gsj5+}Vk7OKbvvwn&ZWnWpf$y^SnNm;33wqaIhKSrFxks|bfsS;eNy zlP6CBfCn`vTrvpX9j9~s;LJ~d=aBzsCyQ_cFsXC7zCciTdAoIoutzvQIRyzQdkcu# znZwyX1v`^votwa?Ys-q*Y+`lN0@i(h)TN@I?R#}J#6tn>Jb; zmMcM%kOC6QB`h-TIA%sZ9Gr0dT$jA8;_#sH<)Bu{5ixKy(M0YLH4o=m?>UQ z*=Y%bOt#_ro%!%&GsrD$bA?&Fzo|ZVOq@@Dg$c^7_!ik~gAK|@)r=r?K7Hy?ttcgp z3z`iI0}^x56on5f!0*vlZx}LE*O3s8mkT5nY405-X`oOj^_G5L)^A=|bN2|o(xrwE zY%wYj^Hb||@Q25!9^e+s}2D;v?30<#M z)dL5O;aHJMnXgF9?uroT;FEu)=ml1{BocX*3$Jsg4R8SjN$qhhR8N zb|k)zrm&47pVte*bA4<;Ux*tA`y1Tna3)o*j%=GA>$RNx*+zL|e}eI(PYB4 z)_r08l12W)$p*`QI#LrK5l8{?n4?~m8auw|mrgjhbD)ybbEU{b|(P_)Owgn*U=vR2+PdHpj zK_QpGby2R43#6_{(_?$*Gj4e%Q#6KTTm^FXBs@b^CHesPm>N7%$FKCUsL2k0S4QmZ z6@cq2tivt-89t4@Jsm1V(X5wy;6T`fEtS+PF)h?9P7Yy2O5gH{l4jRQNKz{jHgqg8}?5`NL(k(=8g>{rTwQ;62XNzpVl6#!d`X5 zBY97}Jw5Xjl7PD40Z57=5zxLY4bYG@H~LheCgZ(vJdHz=(>RJT&0l1fAojRmm0b%q zb#TNkeHL27{)A5$+#q5|5y8bGqjJwCo}%1GkJ_lt6g+|C(okX*f_N<@RsiR}=I$r6EE9|I;5$AcUnykZc2{+!!Q{>ixJm1*_ z8YGD>-ovo6Ghb(_Gwdd3a@eQnNSr7rIJ#Zx^Z&T7VfUP)Ni;2e_ef1pTExT zIx}p|aa}A-j+7?VDlreH8!R1(xZceO?jKZJRb^RcS<=}6NjC>ReiDhUrp=?Uq0yj= zw^#J%O^$F8c8X)h0QW#so3M$oB`4sb96Wy$MdS5|M46LdioZl3T-=V~7|w z01+1FL-S#iYFToaF@g*#-;=oiP*6Q;E^CVOo^*{`Y?N4O*fHMGE732G9IY2(LqCBL zsnW{pEXqeP)Ce(3K5=<&w4IZz9s2PD8`sN!VyyuHFeOn_s5ibaJ$KKj3S$2lH=WkI z0;Xu;d?F%bTI>P0Z?CfC$ZxziK4CW+aUBL8ks_?({Mi{l>Lt5G-m)7@C&~vNG#F>9 zCN4Gkqn1T`A<3h9%EcJjwV;H9(EcqM|1vUvUSs`?T6rHeQxZqEOOLF&O|Udng-b`f zkcfLY5waHeSjv#<5{vPiWNdUbord2*Q7(niMt>O5v1jT!92Xt6ubW-d?)RnK4%~#Q2EPAYP^MHub$}(Be6XgFr__=OFnCyw zgw4KvN|remz%9eym1DGo(<~X=E(0UExNAf4D}@4>LC5exKxn zuuL$-PEupTMdECSkMHTI6t@oCYm*>nD5y;1B6~Wd*>ehHhXCm6XNdM!653epW%*y2tB{`$ng2E5h*c>o|tS1YDHI~BgpCqa@|_~~$mK=4dr zu}93Dr|YA&^(;@Fq*Z#f-~ktQIX&wk?a!QCsZ1rPcAJXg*CveGM0hsN7G zI3MM+`Ui4cd}abyElO638Wby`GHdi?z+&d&?N$lp^yt7m2J1WHM{qt(Rcaudb3r3AMD^0lH1>%ERsV6 z66VrQ(G@o2FWyQl37KhDN%z9DxbQk?@Exd-vYji_`7{A<4;G27a#z{Rd(G;^vzkv< zS?Sx>>vW`kyOjyf)7vnxjZ=?fyjh};ie-UyJ^qc*n;J;`D#x{@;r~efjbC)Z+CmvjDNnp>VP?XtlKiB9!ZqMqRX;S_3Q_}19+6lVK0p8&?AS!v1{0`w z7G!PJeU012<=LzPV$Ha7+?Gg=es+1UA8;0Q=W3Kr8;G}Jo5fqbeEgU&LDDa;Vg9Yx#q$m-;su*hPD7pL83ixM zSUaEoUF@9sV0S+q@#0$awwwSFwQTkP0eC8Ij=S^QZQCx9PZn5*uqIg#TpZxPIJ(DgiH!6SvE#_`6bvSSLzS zTQ+M-XBf&3&FhsAy49ThxfPMt6wIbnzw|b04*O$h1WF5J;~2$DhdrnZ$wSAA#A33O zws9zYk_oGbPWpSkDOg9glZD>@wV#s$4zG7!HrF?E&9WJ9t}fJ_6te6}v)v*Ck*!zd zE-i^PSrRR>T4{1YOsdO@yJCOm=U-c~dE@CTd*b&Pa&ntgVVWl+=ljb0N48G*bStk$@!c2SdfrDX_Z(Gvc*ix$^0Kj=W0T7^ zIoD2qRh^Bl8x5wc*Zpjs{eD}@;v&J7J`>y~b3N|aJiF+sP;<|mHCK#uoi=n&J-zYN zQqRt?KOK{AOxOCe{x0wAuUbW!#dmX``l{+hPr7!y@Y0**k(mc(UDMdO>dR`SD@*Tw z=Zr1)HEQ>5FN`_r*XyD6H?iY{%dg`%4P}Z%bzTKcSY8=sWm|E7w~SM+m#<%}39tHnAhLj>b_gWD%e>uQ67wxJ zaMsiLMd5F)t`vLCSbaORtCwrZ#U(!`A2ge(q|>Bi?=IG0#@_Sy~GC%$gcHePQLLFi%ev zgAJ^256|vCv%5a_z%!*i*VEU%{H^}>>UO7X+S+r!$=|9^eX+W$J3PcM`t3~n_j2(w zpVj=+6Zz2kC;eXZK8~k{BGkM$O>+6GbS*AzuFWCEB`nBHLgV+Dse@d4B zRptNBv&tdS^<=>{z1Lm)%VLb}F08-vb=A_tG4oF!?K~f*9Xx+!$g`pi5xrdI#%5mE jpKiLHtK99Ps;Q(z+4L$T@R3Oh=4z3Rfw0Ln?Eg&w-stkc literal 0 HcmV?d00001 diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/build/copy-outputs.targets b/src/Installers/Windows/AspNetCoreModule-Setup/build/copy-outputs.targets new file mode 100644 index 0000000000..bdc59f4f6d --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/build/copy-outputs.targets @@ -0,0 +1,18 @@ + + + + + + + + $(Configuration)\$(PlatformShortname)\ + + + + + + + \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/build/exports.props b/src/Installers/Windows/AspNetCoreModule-Setup/build/exports.props new file mode 100644 index 0000000000..512b082102 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/build/exports.props @@ -0,0 +1,13 @@ + + + + + + $(MSBuildThisFileDirectory)..\ + + + + $(MSBuildThisFileDirectory)..\ + + + \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/build/settings.props b/src/Installers/Windows/AspNetCoreModule-Setup/build/settings.props new file mode 100644 index 0000000000..ba1ca74632 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/build/settings.props @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/build/settings/common.props b/src/Installers/Windows/AspNetCoreModule-Setup/build/settings/common.props new file mode 100644 index 0000000000..0130b6e5ab --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/build/settings/common.props @@ -0,0 +1,53 @@ + + + + + + + x64 + x86 + + + + + + 10.0.15063.0 + $(IisOobWinSdkVersion) + Unicode + bin\$(Configuration)\$(PlatformShortname)\ + obj\$(Configuration)\$(PlatformShortname)\ + + + + + + + Level3 + + + + + + + + _DEBUG;%(PreprocessorDefinitions) + + + + + NDEBUG;%(PreprocessorDefinitions) + + + + + WIN32;%(PreprocessorDefinitions) + + + + \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/build/settings/debug.props b/src/Installers/Windows/AspNetCoreModule-Setup/build/settings/debug.props new file mode 100644 index 0000000000..710f5553d0 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/build/settings/debug.props @@ -0,0 +1,29 @@ + + + + + + true + true + false + + + + + + + true + Disabled + true + EnableFastChecks + MultiThreadedDebug + + + false + false + true + /JMC- + + + + \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/build/settings/release.props b/src/Installers/Windows/AspNetCoreModule-Setup/build/settings/release.props new file mode 100644 index 0000000000..d7eb8ffa35 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/build/settings/release.props @@ -0,0 +1,51 @@ + + + + + + + true + true + + + + + + + false + false + true + + + + + + + Full + Speed + false + MultiThreaded + true + + + true + true + UseLinkTimeCodeGeneration + + + + \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/build/submodule.props b/src/Installers/Windows/AspNetCoreModule-Setup/build/submodule.props new file mode 100644 index 0000000000..00046cf191 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/build/submodule.props @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/build/versions.props b/src/Installers/Windows/AspNetCoreModule-Setup/build/versions.props new file mode 100644 index 0000000000..3be2245e72 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/build/versions.props @@ -0,0 +1,38 @@ + + + + + 7 + 1 + + + $([MSBuild]::Multiply(12,$([MSBuild]::Subtract($([System.DateTime]::Now.Year), 2016)))) + $([MSBuild]::Add( $([MSBuild]::Subtract($([System.DateTime]::Now.Month), 10)), $(VersionDateMonths))) + $([System.DateTime]::Now.ToString("dd")) + $([System.String]::Concat($([System.Int32]::Parse('$(VersionDateTotalMonths)').ToString("D3")), $(VersionDateDays))) + $(VersionBuildMajor) + $([System.DateTime]::Now.ToString("HHmm")) + + + + + /DPRODUCT_MAJOR=$(PRODUCT_MAJOR) %(AdditionalOptions) + + + /DPRODUCT_MINOR=$(PRODUCT_MINOR) %(AdditionalOptions) + + + /DBUILD_MAJOR=$(BUILD_MAJOR) %(AdditionalOptions) + + + /DBUILD_MINOR=$(BUILD_MINOR) %(AdditionalOptions) + + + + + PRODUCT_MAJOR=$(PRODUCT_MAJOR);$(ResourceCompilePreprocessorDefinitions) + PRODUCT_MINOR=$(PRODUCT_MINOR);$(ResourceCompilePreprocessorDefinitions) + BUILD_MAJOR=$(BUILD_MAJOR);$(ResourceCompilePreprocessorDefinitions) + BUILD_MINOR=$(BUILD_MINOR);$(ResourceCompilePreprocessorDefinitions) + + \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/license/license.rtf b/src/Installers/Windows/AspNetCoreModule-Setup/license/license.rtf new file mode 100644 index 0000000000..91c46e44c4 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/license/license.rtf @@ -0,0 +1,97 @@ +{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033\deflangfe2052{\fonttbl{\f0\fswiss\fprq2\fcharset0 Tahoma;}{\f1\froman\fprq2\fcharset2 Symbol;}{\f2\froman\fprq2\fcharset0 Times New Roman;}{\f3\fswiss\fprq2\fcharset0 Calibri;}{\f4\fnil\fcharset2 Symbol;}} +{\colortbl ;\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;} +{\stylesheet{ Normal;}{\s1 heading 1;}} +{\*\generator Riched20 10.0.10586}\viewkind4\uc1 +\pard\nowidctlpar\sb120\sa120\b\f0\fs22 MICROSOFT SOFTWARE LICENSE TERMS\fs20\par + +\pard\brdrb\brdrs\brdrw10\brsp20 \nowidctlpar\sb120\sa120\fs22 MICROSOFT ASP.NET CORE MODULE\fs20\par + +\pard\widctlpar\sb120\sa120 These license terms are an agreement between Microsoft Corporation (or based on where you live, one of its affiliates) and you. Please read them. They apply to the software named above, which includes the media on which you received it, if any. The terms also apply to any Microsoft\b0\par + +\pard\nowidctlpar\fi-360\li360\sb120\sa120\tx360\f1\'b7\tab\f0 updates,\par +\f1\'b7\tab\f0 supplements,\par +\f1\'b7\tab\f0 Internet-based services, and\par +\f1\'b7\tab\f0 support services\par + +\pard\nowidctlpar\sb120\sa120 for this software, unless other terms accompany those items. If so, those terms apply.\par +\b BY USING THE SOFTWARE, YOU ACCEPT THESE TERMS. IF YOU DO NOT ACCEPT THEM, DO NOT USE THE SOFTWARE.\par + +\pard\brdrt\brdrs\brdrw10\brsp20 \nowidctlpar\sb120\sa120 IF YOU COMPLY WITH THESE LICENSE TERMS, YOU HAVE THE RIGHTS BELOW.\par + +\pard\nowidctlpar\s1\fi-357\li357\sb120\sa120\tx360 1.\tab INSTALLATION AND USE RIGHTS. \b0\f2\par + +\pard\widctlpar\fi-363\li720\sb120\sa120\b\f0 a.\~\~\~ Installation and Use.\b0 You may install and use any number of copies of the software to design, develop and test your programs.\b\par +b.\~\~\~ Third Party Programs.\b0 The software may include third party programs that Microsoft, not the third party, licenses to you under this agreement. Notices, if any, for the third party program are included for your information only.\b\par + +\pard\widctlpar\fi-357\li357\sb120\sa120\kerning36 2.\tab ADDITIONAL LICENSING REQUIREMENTS AND/OR USE RIGHTS.\par + +\pard\widctlpar\fi-363\li720\sb120\sa120\kerning0 a.\~\~\~ DISTRIBUTABLE CODE.\~ \b0 The software is comprised of Distributable Code. \ldblquote Distributable Code\rdblquote is code that you are permitted to distribute in programs you develop if you comply with the terms below.\b\par + +\pard\widctlpar\fi-357\li1077\sb120\sa120 i.\~\~\~\~\~ Right to Use and Distribute. \b0\par + +\pard{\pntext\f4\'B7\tab}{\*\pn\pnlvlblt\pnf4\pnindent0{\pntxtb\'B7}}\fi-360\li1797\sb120\sa120 You may copy and distribute the object code form of the software.\par +{\pntext\f4\'B7\tab}Third Party Distribution. You may permit distributors of your programs to copy and distribute the Distributable Code as part of those programs.\par + +\pard\widctlpar\fi-357\li1077\sb120\sa120\b ii.\~\~\~ Distribution Requirements.\b0 \b For any Distributable Code you distribute, you must\b0\par + +\pard{\pntext\f4\'B7\tab}{\*\pn\pnlvlblt\pnf4\pnindent0{\pntxtb\'B7}}\fi-360\li1797\sb120\sa120 add significant primary functionality to it in your programs;\par +{\pntext\f4\'B7\tab}require distributors and external end users to agree to terms that protect it at least as much as this agreement;\par +{\pntext\f4\'B7\tab}display your valid copyright notice on your programs; and\par +{\pntext\f4\'B7\tab}indemnify, defend, and hold harmless Microsoft from any claims, including attorneys\rquote fees, related to the distribution or use of your programs.\par + +\pard\widctlpar\fi-357\li1077\sb120\sa120\b iii.\~\~ Distribution Restrictions.\b0 \b You may not\b0\par + +\pard{\pntext\f4\'B7\tab}{\*\pn\pnlvlblt\pnf4\pnindent0{\pntxtb\'B7}}\fi-360\li1797\sb120\sa120 alter any copyright, trademark or patent notice in the Distributable Code;\par +{\pntext\f4\'B7\tab}use Microsoft\rquote s trademarks in your programs\rquote names or in a way that suggests your programs come from or are endorsed by Microsoft;\par +{\pntext\f4\'B7\tab}include Distributable Code in malicious, deceptive or unlawful programs; or\par +{\pntext\f4\'B7\tab}modify or distribute the source code of any Distributable Code so that any part of it becomes subject to an Excluded License. An Excluded License is one that requires, as a condition of use, modification or distribution, that\par +{\pntext\f4\'B7\tab}the code be disclosed or distributed in source code form; or\par +{\pntext\f4\'B7\tab}others have the right to modify it.\f2\par + +\pard\widctlpar\fi-357\li357\sb120\sa120\b\f0 3.\tab\kerning36 SCOPE OF LICENSE. \b0 The software is licensed, not sold. This agreement only gives you some rights to use the software. Microsoft reserves all other rights. Unless applicable law gives you more rights despite this limitation, you may use the software only as expressly permitted in this agreement. In doing so, you must comply with any technical limitations in the software that only allow you to use it in certain ways. You may not\b\par + +\pard{\pntext\f4\'B7\tab}{\*\pn\pnlvlblt\pnf4\pnindent0{\pntxtb\'B7}}\fi-360\li1797\sb120\sa120\kerning0\b0 work around any technical limitations in the software;\par +{\pntext\f4\'B7\tab}reverse engineer, decompile or disassemble the software, except and only to the extent that applicable law expressly permits, despite this limitation;\par +{\pntext\f4\'B7\tab}publish the software for others to copy;\par +{\pntext\f4\'B7\tab}rent, lease or lend the software;\par +{\pntext\f4\'B7\tab}transfer the software or this agreement to any third party; or\par +{\pntext\f4\'B7\tab}use the software for commercial software hosting services.\par + +\pard\widctlpar\fi-357\li357\sb120\sa120\b 4.\tab\cf1\highlight2 DATA.\cf0\highlight0\b0 The software may collect information about you and your use of the software, and send that to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may opt-out of many of these scenarios, but not all, as described in the product documentation. You can learn more about data collection and use in the help documentation and the privacy statement at {{\field{\*\fldinst{HYPERLINK https://privacy.microsoft.com/en-us/privacystatement }}{\fldrslt{https://privacy.microsoft.com/en-us/privacystatement\ul0\cf0}}}}\f0\fs20 . {\f3\fs22{\field{\*\fldinst{HYPERLINK http://go.microsoft.com/fwlink/?LinkID=528096Your }}{\fldrslt{http://go.microsoft.com/fwlink/?LinkID=528096\f0\fs20 Your\ul0\cf0}}}}\f0\fs20 use of the software operates as your consent to these practices.\par +\b 5.\tab\kerning36 BACKUP COPY. \b0 You may make one backup copy of the software. You may use it only to reinstall the software.\b\par +6.\tab DOCUMENTATION. \b0 Any person that has valid access to your computer or internal network may copy and use the documentation for your internal, reference purposes.\b\par +7.\tab EXPORT RESTRICTIONS. \b0 The software is subject to United States export laws and regulations. You must comply with all domestic and international export laws and regulations that apply to the software. These laws include restrictions on destinations, end users and end use. For additional information, see {{\field{\*\fldinst{HYPERLINK www.microsoft.com/exporting }}{\fldrslt{www.microsoft.com/exporting\ul0\cf0}}}}\f0\fs20 .\b\par +8.\tab SUPPORT SERVICES. \b0 Because this software is \ldblquote as is,\rdblquote we may not provide support services for it.\b\par +9.\tab ENTIRE AGREEMENT. \b0 This agreement, and the terms for supplements, updates, Internet-based services and support services that you use, are the entire agreement for the software and support services.\b\par +10.\tab APPLICABLE LAW.\par + +\pard\widctlpar\fi-363\li720\sb120\sa120\kerning0 a.\tab United States. \b0 If you acquired the software in the United States, Washington state law governs the interpretation of this agreement and applies to claims for breach of it, regardless of conflict of laws principles. The laws of the state where you live govern all other claims, including claims under state consumer protection laws, unfair competition laws, and in tort.\b\par +b.\~\~\~ Outside the United States. If you acquired the software in any other country, the laws of that country apply.\par + +\pard\widctlpar\fi-357\li357\sb120\sa120\kerning36 11.\tab LEGAL EFFECT. \b0 This agreement describes certain legal rights. You may have other rights under the laws of your country. You may also have rights with respect to the party from whom you acquired the software. This agreement does not change your rights under the laws of your country if the laws of your country do not permit it to do so.\b\par +12.\tab DISCLAIMER OF WARRANTY. THE SOFTWARE IS LICENSED \ldblquote AS-IS.\rdblquote YOU BEAR THE RISK OF USING IT. MICROSOFT GIVES NO EXPRESS WARRANTIES, GUARANTEES OR CONDITIONS. YOU MAY HAVE ADDITIONAL CONSUMER RIGHTS OR STATUTORY GUARANTEES UNDER YOUR LOCAL LAWS WHICH THIS AGREEMENT CANNOT CHANGE. TO THE EXTENT PERMITTED UNDER YOUR LOCAL LAWS, MICROSOFT EXCLUDES THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.\par + +\pard\widctlpar\li357\sb120\sa120\kerning0 FOR AUSTRALIA \endash YOU HAVE STATUTORY GUARANTEES UNDER THE AUSTRALIAN CONSUMER LAW AND NOTHING IN THESE TERMS IS INTENDED TO AFFECT THOSE RIGHTS.\b0\par + +\pard\widctlpar\fi-357\li357\sb120\sa120\kerning36\b 13.LIMITATION ON AND EXCLUSION OF REMEDIES AND DAMAGES. YOU CAN RECOVER FROM MICROSOFT AND ITS SUPPLIERS ONLY DIRECT DAMAGES UP TO U.S. $5.00. YOU CANNOT RECOVER ANY OTHER DAMAGES, INCLUDING CONSEQUENTIAL, LOST PROFITS, SPECIAL, INDIRECT OR INCIDENTAL DAMAGES.\par + +\pard\widctlpar\li357\sb120\sa120\kerning0\b0 This limitation applies to\par + +\pard{\pntext\f4\'B7\tab}{\*\pn\pnlvlblt\pnf4\pnindent0{\pntxtb\'B7}}\fi-270\li720\sb120\sa120 anything related to the software, services, content (including code) on third party Internet sites, or third party programs; and\par +{\pntext\f4\'B7\tab}claims for breach of contract, breach of warranty, guarantee or condition, strict liability, negligence, or other tort to the extent permitted by applicable law.\par + +\pard\widctlpar\sb120\sa120 It also applies even if Microsoft knew or should have known about the possibility of the damages. The above limitation or exclusion may not apply to you because your country may not allow the exclusion or limitation of incidental, consequential or other damages.\par +\lang9 Please note: As this software is distributed in Quebec, Canada, some of the clauses in this agreement are provided below in French.\lang1033\par +\lang9 Remarque : Ce logiciel \'e9tant distribu\'e9 au Qu\'e9bec, Canada, certaines des clauses dans ce contrat sont fournies ci-dessous en fran\'e7ais.\lang1033\par +\kerning36\b EXON\'c9RATION DE GARANTIE. \b0 Le logiciel vis\'e9 par une licence est offert \'ab tel quel \'bb. Toute utilisation de ce logiciel est \'e0 votre seule risque et p\'e9ril. Microsoft n\rquote accorde aucune autre garantie expresse. Vous pouvez b\'e9n\'e9ficier de droits additionnels en vertu du droit local sur la protection des consommateurs, que ce contrat ne peut modifier. La ou elles sont permises par le droit locale, les garanties implicites de qualit\'e9 marchande, d\rquote ad\'e9quation \'e0 un usage particulier et d\rquote absence de contrefa\'e7on sont exclues.\b\par +LIMITATION DES DOMMAGES-INT\'c9R\'caTS ET EXCLUSION DE RESPONSABILIT\'c9 POUR LES DOMMAGES. \b0 Vous pouvez obtenir de Microsoft et de ses fournisseurs une indemnisation en cas de dommages directs uniquement \'e0 hauteur de 5,00 $ US. Vous ne pouvez pr\'e9tendre \'e0 aucune indemnisation pour les autres dommages, y compris les dommages sp\'e9ciaux, indirects ou accessoires et pertes de b\'e9n\'e9fices.\b\par +\kerning0\b0\lang9 Cette limitation concerne :\lang1033\par + +\pard{\pntext\f4\'B7\tab}{\*\pn\pnlvlblt\pnf4\pnindent0{\pntxtb\'B7}}\fi-720\li720\sb120\sa120\lang9 tout ce qui est reli\'e9 au logiciel, aux services ou au contenu (y compris le code) figurant sur des sites Internet tiers ou dans des programmes tiers ; et\par +{\pntext\f4\'B7\tab}les r\'e9clamations au titre de violation de contrat ou de garantie, ou au titre de responsabilit\'e9 stricte, de n\'e9gligence ou d\rquote une autre faute dans la limite autoris\'e9e par la loi en vigueur.\lang1033\par + +\pard\widctlpar\sb120\sa120\lang9 Elle s\rquote applique \'e9galement, m\'eame si Microsoft connaissait ou devrait conna\'eetre l\rquote\'e9ventualit\'e9 d\rquote un tel dommage. Si votre pays n\rquote autorise pas l\rquote exclusion ou la limitation de responsabilit\'e9 pour les dommages indirects, accessoires ou de quelque nature que ce soit, il se peut que la limitation ou l\rquote exclusion ci-dessus ne s\rquote appliquera pas \'e0 votre \'e9gard.\lang1033\par +\kerning36\b\fs19 EFFET JURIDIQUE. \b0 Le pr\'e9sent contrat d\'e9crit certains droits juridiques. Vous pourriez avoir d\rquote autres droits pr\'e9vus par les lois de votre pays. Le pr\'e9sent contrat ne modifie pas les droits que vous conf\'e8rent les lois de votre pays si celles-ci ne le permettent pas.\b\par +\kerning0\b0\f2\fs20\par +} + \ No newline at end of file diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/setupstrings.wxl b/src/Installers/Windows/AspNetCoreModule-Setup/setupstrings.wxl new file mode 100644 index 0000000000..5ac48523c5 --- /dev/null +++ b/src/Installers/Windows/AspNetCoreModule-Setup/setupstrings.wxl @@ -0,0 +1,52 @@ + + + + 1033 + + + Microsoft ASP.NET Core Module + Microsoft ASP.NET Core Module V2 + ASP.NET Core IIS Runtime + Adds the support of asp.net core application to IIS. + Microsoft ASP.NET Core Module for IIS Express + Microsoft ASP.NET Core Module V2 for IIS Express + IIS Express 8.0 or higher is not installed. + + + + Microsoft Corporation + An incompatible product, [CONFLICTING_PRODUCT_NAME], is on this computer. Installation of [ProductName] cannot continue. To install this product, use Add/Remove Programs on the Control Panel to remove [CONFLICTING_PRODUCT_NAME]. + Administrator privilege is required to install [ProductName]. + IIS Version 7.0 is required to use [ProductName]. + IIS Version 7.0 or greater is required to install [ProductName]. + IIS Version 7.5 or greater is required to install [ProductName]. + IIS Version 7 or 7.5 is required to install [ProductName]. + IIS Version 8.0 or greater is required to install [ProductName]. + The beta version of [ProductName] was found on this machine. + A newer version of [ProductName] was found on this machine. + Setup cannot continue because another instance of [ProductName] is already installed on this computer. Please uninstall it first and then re-launch this installation. + The IIS 7.0 CoreWebEngine and W3SVC features must be installed to use [ProductName]. + The IIS Management Console must be installed to use [ProductName]. + Please stop both services Windows Process Activation Service (WAS) and Web Management Service (WMSvc) before installing [ProductName]. You will need to start the services after installing [ProductName]. + IIS Metabase is required to install [ProductName]. + The 64-bit version of [ProductName] cannot be installed on a 32-bit edition of Microsoft Windows. + The 32-bit version of [ProductName] cannot be installed on a 64-bit edition of Microsoft Windows. + Microsoft .NET Framework Version 2.0 or greater is required to install [ProductName]. + Microsoft .NET Framework Version 3.5 or greater is required to install [ProductName]. Use 'Add Features' under the Server Manager to install Microsoft .Net Version 3.5. + Microsoft .NET Framework Version 4.0 or greater is required to install [ProductName]. + Please install Microsoft .NET Framework Version 2.0 Service Pack 1 (or a later service pack), before installing [ProductName]. + The Windows Update (wuauserv) service cannot be disabled, it is required to install [ProductName]. + The PowerShell snap-in is part of Windows Operating System. Please install it via 'Programs and Features' or 'Server Manager'. + Microsoft Web Platform Installer Version 3.0 or greater is required to install [ProductName]. + + Setup failed to detect shared configuration. + Shared configuration is enabled for IIS. Installing [ProductName] is not supported when using shared configuration. Please disable shared configuration before installing this feature. + + Please stop World Wide Web Publishing Service (W3SVC) before installing [ProductName]. You will need to start the service after installation. + IIS PowerShell Management Console + IIS PowerShell snap-in + IIS PowerShell snap-in requires PowerShell v1.0 or v2.0 installed + IIS PowerShell snap-in requires WAS and configuration installed + This is a bogus string. + + diff --git a/src/Installers/Windows/WindowsHostingBundle/ANCM.wxs b/src/Installers/Windows/WindowsHostingBundle/ANCM.wxs index 367daa45ed..71c6a3cc36 100644 --- a/src/Installers/Windows/WindowsHostingBundle/ANCM.wxs +++ b/src/Installers/Windows/WindowsHostingBundle/ANCM.wxs @@ -4,14 +4,14 @@ - - + + + + + + + + + + + + + @@ -15,6 +28,7 @@ + diff --git a/src/Installers/Windows/Wix.props b/src/Installers/Windows/Wix.props index 61c4ca9f6c..f2737edad2 100644 --- a/src/Installers/Windows/Wix.props +++ b/src/Installers/Windows/Wix.props @@ -2,7 +2,6 @@ $(AspNetCoreMajorVersion).$(AspNetCoreMinorVersion).$(AspNetCorePatchVersion).0 - Release x64 ENU diff --git a/src/Installers/Windows/Wix.targets b/src/Installers/Windows/Wix.targets index a40275cd06..85eecfa243 100644 --- a/src/Installers/Windows/Wix.targets +++ b/src/Installers/Windows/Wix.targets @@ -12,7 +12,7 @@ - + @@ -39,4 +39,5 @@ $(DefineConstants);BundleProviderKey=$(BundleProviderKey);BundleUpgradeCode=$(BundleUpgradeCode) + diff --git a/src/Installers/Windows/clone_and_build_ancm.ps1 b/src/Installers/Windows/clone_and_build_ancm.ps1 deleted file mode 100644 index cc76a869d9..0000000000 --- a/src/Installers/Windows/clone_and_build_ancm.ps1 +++ /dev/null @@ -1,105 +0,0 @@ -# -# This builds installers for AspNetCoreModule. -# This script requires internal-only access to the code which generates ANCM installers. -# -#requires -version 5 -[cmdletbinding()] -param( - [string]$GitCredential, - [string]$Configuration = 'Release', - [string]$BuildNumber = 't000', - [string]$AncmSourceBranch = 'release/2.1', - [string]$SignType = '' -) - -$ErrorActionPreference = 'Stop' - -$repoRoot = Resolve-Path "$PSScriptRoot/../../../" - -Import-Module -Scope Local "$repoRoot/scripts/common.psm1" -Force - -$msbuild = Get-MSBuildPath -Prerelease -requires 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64' - -# get wix -[version] $wixVer = '3.11.1' -$wixToolSetRoot = "$repoRoot/obj/tools/wix/$wixVer/" -$downloadFile = "$wixToolSetRoot/wix-binaries.zip" -if (-not (Test-Path $downloadFile)) { - [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 - $downloadUrl = "https://github.com/wixtoolset/wix3/releases/download/wix$($wixVer.Major)$($wixVer.Minor)$($wixVer.Build)rtm/wix$($wixVer.Major)$($wixVer.Minor)-binaries.zip" - Write-Host "Downloading fix $wixVer from $downloadUrl" - New-Item -Type Directory $wixToolSetRoot -ErrorAction Ignore | Out-Null - Invoke-WebRequest -UseBasicParsing -Uri $downloadUrl -OutFile $downloadFile - Expand-Archive $downloadFile -DestinationPath $wixToolSetRoot -} - -# get nuget.exe -$nuget = "$repoRoot/obj/tools/nuget.exe" -if (-not (Test-Path $nuget)) { - Invoke-WebRequest -UseBasicParsing -Uri 'https://dist.nuget.org/win-x86-commandline/latest/nuget.exe' -OutFile $nuget -} - -Push-Location $PSScriptRoot - -try { - if ($GitCredential) { - # Disable prompts for passwords - $env:GIT_TERMINAL_PROMPT = 0 - } - - if (-not (Test-Path ancm/)) { - Invoke-Block { - & git clone "https://${GitCredential}@devdiv.visualstudio.com/DefaultCollection/DevDiv/_git/AspNetCoreModule-Setup" ` - --branch $AncmSourceBranch ` - --recursive ` - ancm/ - } - } - - Invoke-Block -WorkingDir ancm/ { - & git submodule update --init --recursive - } - - Invoke-Block -WorkingDir ancm/ { - New-Item .deps -ItemType Directory -ErrorAction Ignore | Out-Null - Copy-Item "$repoRoot/obj/dependencies.g.props" .deps/dependencies.g.props - & $msbuild artifactfetcher/artifactfetcher.csproj ` - '-t:Restore' ` - "-p:RestoreAdditionalProjectSources=$repoRoot/artifacts/build" - } - - Invoke-Block -WorkingDir ancm/ { - & $nuget restore ANCM-Setup.sln - } - - Invoke-Block -WorkingDir ancm/IIS-Common/lib/ { - & $nuget restore packages.config - } - - Invoke-Block { & $msbuild ` - ancm/Setup.msbuild ` - -m ` - -v:m ` - -nodeReuse:false ` - -clp:Summary ` - "-t:BuildCustomAction;Build" ` - "-p:WixToolPath=$wixToolSetRoot" ` - "-p:WixTargetsPath=$wixToolSetRoot\Wix.targets" ` - "-p:WixTasksPath=$wixToolSetRoot\wixtasks.dll" ` - "-p:WixNativeCATargetsPath=$wixToolSetRoot\sdk\wix.nativeca.targets" ` - "-p:Configuration=$Configuration" ` - "-p:BuildNumber=$BuildNumber" ` - "-p:SignType=$SignType" ` - "-bl:$repoRoot/artifacts/logs/ancn.msbuild.binlog" - } - - $outputPath = "$repoRoot/artifacts/bin/$Configuration/installers/en-US/" - New-Item $outputPath -ItemType Directory -ErrorAction Ignore | Out-Null - Copy-Item -Recurse "ancm/bin/AspNetCoreModuleV1/$Configuration/x64/en-us/*" $outputPath - Copy-Item -Recurse "ancm/bin/AspNetCoreModuleV1/$Configuration/x86/en-us/*" $outputPath - Copy-Item -Recurse "ancm/bin/AspNetCoreModuleV2/$Configuration/x64/en-us/*" $outputPath - Copy-Item -Recurse "ancm/bin/AspNetCoreModuleV2/$Configuration/x86/en-us/*" $outputPath -} -finally { - Pop-Location -} From 74d9728e95b7ed2108e8e1974443ba286859de78 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Fri, 9 Nov 2018 12:49:58 -0800 Subject: [PATCH 458/471] Reorganize source code in preparation to move into aspnet/AspNetCore Prior to reorganization, this source code was found in https://github.com/aspnet/JsonPatch/tree/218064c300a7cf5a76669e133340a98a0c5517a5 --- .appveyor.yml | 17 -- .gitattributes | 52 ---- .github/ISSUE_TEMPLATE.md | 3 - .gitignore | 39 --- .travis.yml | 27 -- CONTRIBUTING.md | 4 - Directory.Build.props | 20 -- Directory.Build.targets | 7 - JsonPatch.sln | 63 ----- LICENSE.txt | 14 -- NuGet.config | 7 - NuGetPackageVerifier.json | 7 - README.md | 9 - build.cmd | 2 - build.sh | 8 - build/Key.snk | Bin 596 -> 0 bytes build/dependencies.props | 29 --- build/repo.props | 15 -- build/sources.props | 17 -- korebuild-lock.txt | 2 - korebuild.json | 4 - run.cmd | 2 - run.ps1 | 196 --------------- run.sh | 231 ------------------ src/Directory.Build.props | 7 - .../JsonPatch/src}/Adapters/IObjectAdapter.cs | 0 .../src}/Adapters/IObjectAdapterWithTest.cs | 0 .../JsonPatch/src}/Adapters/ObjectAdapter.cs | 0 .../Converters/JsonPatchDocumentConverter.cs | 0 .../TypedJsonPatchDocumentConverter.cs | 0 .../src}/Exceptions/JsonPatchException.cs | 0 .../JsonPatch/src}/Helpers/GetValueResult.cs | 0 .../src}/Helpers/JsonPatchProperty.cs | 0 .../JsonPatch/src}/IJsonPatchDocument.cs | 0 .../src}/Internal/ConversionResult.cs | 0 .../src}/Internal/ConversionResultProvider.cs | 0 .../src}/Internal/DictionaryAdapterOfTU.cs | 0 .../src}/Internal/DynamicObjectAdapter.cs | 0 .../JsonPatch/src}/Internal/ErrorReporter.cs | 0 .../JsonPatch/src}/Internal/IAdapter.cs | 0 .../JsonPatch/src}/Internal/ListAdapter.cs | 0 .../JsonPatch/src}/Internal/ObjectVisitor.cs | 0 .../JsonPatch/src}/Internal/ParsedPath.cs | 0 .../JsonPatch/src}/Internal/PathHelpers.cs | 0 .../JsonPatch/src}/Internal/PocoAdapter.cs | 0 .../JsonPatch/src}/JsonPatchDocument.cs | 0 .../JsonPatch/src}/JsonPatchDocumentOfT.cs | 0 .../JsonPatch/src}/JsonPatchError.cs | 0 .../Microsoft.AspNetCore.JsonPatch.csproj | 6 +- .../JsonPatch/src}/Operations/Operation.cs | 0 .../src}/Operations/OperationBase.cs | 0 .../JsonPatch/src}/Operations/OperationOfT.cs | 0 .../src}/Operations/OperationType.cs | 0 .../JsonPatch/src/Properties/AssemblyInfo.cs | 7 + .../src}/Properties/Resources.Designer.cs | 0 .../JsonPatch/src}/Resources.resx | 0 .../JsonPatch/src}/baseline.netcore.json | 0 .../test}/CustomNamingStrategyTests.cs | 0 .../AnonymousObjectIntegrationTest.cs | 0 .../DictionaryIntegrationTest.cs | 0 .../DynamicObjectIntegrationTest.cs | 0 .../ExpandoObjectIntegrationTest.cs | 0 .../IntegrationTests/ListIntegrationTest.cs | 0 .../NestedObjectIntegrationTest.cs | 0 .../SimpleObjectIntegrationTest.cs | 0 .../test}/Internal/DictionaryAdapterTest.cs | 0 .../Internal/DynamicObjectAdapterTest.cs | 0 .../test}/Internal/ListAdapterTest.cs | 0 .../test}/Internal/ObjectVisitorTest.cs | 0 .../test}/Internal/ParsedPathTests.cs | 0 .../test}/Internal/PocoAdapterTest.cs | 0 .../test}/JsonPatchDocumentGetPathTest.cs | 0 ...nPatchDocumentJsonPropertyAttributeTest.cs | 0 .../JsonPatch/test}/JsonPatchDocumentTest.cs | 0 ...icrosoft.AspNetCore.JsonPatch.Tests.csproj | 11 + .../JsonPatch/test}/OperationBaseTests.cs | 0 .../JsonPatch/test}/TestErrorLogger.cs | 0 .../test}/TestObjectModels/Customer.cs | 0 .../TestObjectModels/DynamicTestObject.cs | 0 .../test}/TestObjectModels/InheritedObject.cs | 0 .../test}/TestObjectModels/NestedObject.cs | 0 .../test}/TestObjectModels/SimpleObject.cs | 0 .../SimpleObjectWithNestedObject.cs | 0 .../Properties/AssemblyInfo.cs | 7 - test/Directory.Build.props | 18 -- ...Microsoft.AspNetCore.JsonPatch.Test.csproj | 20 -- version.props | 12 - 87 files changed, 21 insertions(+), 842 deletions(-) delete mode 100644 .appveyor.yml delete mode 100644 .gitattributes delete mode 100644 .github/ISSUE_TEMPLATE.md delete mode 100644 .gitignore delete mode 100644 .travis.yml delete mode 100644 CONTRIBUTING.md delete mode 100644 Directory.Build.props delete mode 100644 Directory.Build.targets delete mode 100644 JsonPatch.sln delete mode 100644 LICENSE.txt delete mode 100644 NuGet.config delete mode 100644 NuGetPackageVerifier.json delete mode 100644 README.md delete mode 100644 build.cmd delete mode 100755 build.sh delete mode 100644 build/Key.snk delete mode 100644 build/dependencies.props delete mode 100644 build/repo.props delete mode 100644 build/sources.props delete mode 100644 korebuild-lock.txt delete mode 100644 korebuild.json delete mode 100644 run.cmd delete mode 100644 run.ps1 delete mode 100755 run.sh delete mode 100644 src/Directory.Build.props rename src/{Microsoft.AspNetCore.JsonPatch => Features/JsonPatch/src}/Adapters/IObjectAdapter.cs (100%) rename src/{Microsoft.AspNetCore.JsonPatch => Features/JsonPatch/src}/Adapters/IObjectAdapterWithTest.cs (100%) rename src/{Microsoft.AspNetCore.JsonPatch => Features/JsonPatch/src}/Adapters/ObjectAdapter.cs (100%) rename src/{Microsoft.AspNetCore.JsonPatch => Features/JsonPatch/src}/Converters/JsonPatchDocumentConverter.cs (100%) rename src/{Microsoft.AspNetCore.JsonPatch => Features/JsonPatch/src}/Converters/TypedJsonPatchDocumentConverter.cs (100%) rename src/{Microsoft.AspNetCore.JsonPatch => Features/JsonPatch/src}/Exceptions/JsonPatchException.cs (100%) rename src/{Microsoft.AspNetCore.JsonPatch => Features/JsonPatch/src}/Helpers/GetValueResult.cs (100%) rename src/{Microsoft.AspNetCore.JsonPatch => Features/JsonPatch/src}/Helpers/JsonPatchProperty.cs (100%) rename src/{Microsoft.AspNetCore.JsonPatch => Features/JsonPatch/src}/IJsonPatchDocument.cs (100%) rename src/{Microsoft.AspNetCore.JsonPatch => Features/JsonPatch/src}/Internal/ConversionResult.cs (100%) rename src/{Microsoft.AspNetCore.JsonPatch => Features/JsonPatch/src}/Internal/ConversionResultProvider.cs (100%) rename src/{Microsoft.AspNetCore.JsonPatch => Features/JsonPatch/src}/Internal/DictionaryAdapterOfTU.cs (100%) rename src/{Microsoft.AspNetCore.JsonPatch => Features/JsonPatch/src}/Internal/DynamicObjectAdapter.cs (100%) rename src/{Microsoft.AspNetCore.JsonPatch => Features/JsonPatch/src}/Internal/ErrorReporter.cs (100%) rename src/{Microsoft.AspNetCore.JsonPatch => Features/JsonPatch/src}/Internal/IAdapter.cs (100%) rename src/{Microsoft.AspNetCore.JsonPatch => Features/JsonPatch/src}/Internal/ListAdapter.cs (100%) rename src/{Microsoft.AspNetCore.JsonPatch => Features/JsonPatch/src}/Internal/ObjectVisitor.cs (100%) rename src/{Microsoft.AspNetCore.JsonPatch => Features/JsonPatch/src}/Internal/ParsedPath.cs (100%) rename src/{Microsoft.AspNetCore.JsonPatch => Features/JsonPatch/src}/Internal/PathHelpers.cs (100%) rename src/{Microsoft.AspNetCore.JsonPatch => Features/JsonPatch/src}/Internal/PocoAdapter.cs (100%) rename src/{Microsoft.AspNetCore.JsonPatch => Features/JsonPatch/src}/JsonPatchDocument.cs (100%) rename src/{Microsoft.AspNetCore.JsonPatch => Features/JsonPatch/src}/JsonPatchDocumentOfT.cs (100%) rename src/{Microsoft.AspNetCore.JsonPatch => Features/JsonPatch/src}/JsonPatchError.cs (100%) rename src/{Microsoft.AspNetCore.JsonPatch => Features/JsonPatch/src}/Microsoft.AspNetCore.JsonPatch.csproj (51%) rename src/{Microsoft.AspNetCore.JsonPatch => Features/JsonPatch/src}/Operations/Operation.cs (100%) rename src/{Microsoft.AspNetCore.JsonPatch => Features/JsonPatch/src}/Operations/OperationBase.cs (100%) rename src/{Microsoft.AspNetCore.JsonPatch => Features/JsonPatch/src}/Operations/OperationOfT.cs (100%) rename src/{Microsoft.AspNetCore.JsonPatch => Features/JsonPatch/src}/Operations/OperationType.cs (100%) create mode 100644 src/Features/JsonPatch/src/Properties/AssemblyInfo.cs rename src/{Microsoft.AspNetCore.JsonPatch => Features/JsonPatch/src}/Properties/Resources.Designer.cs (100%) rename src/{Microsoft.AspNetCore.JsonPatch => Features/JsonPatch/src}/Resources.resx (100%) rename src/{Microsoft.AspNetCore.JsonPatch => Features/JsonPatch/src}/baseline.netcore.json (100%) rename {test/Microsoft.AspNetCore.JsonPatch.Test => src/Features/JsonPatch/test}/CustomNamingStrategyTests.cs (100%) rename {test/Microsoft.AspNetCore.JsonPatch.Test => src/Features/JsonPatch/test}/IntegrationTests/AnonymousObjectIntegrationTest.cs (100%) rename {test/Microsoft.AspNetCore.JsonPatch.Test => src/Features/JsonPatch/test}/IntegrationTests/DictionaryIntegrationTest.cs (100%) rename {test/Microsoft.AspNetCore.JsonPatch.Test => src/Features/JsonPatch/test}/IntegrationTests/DynamicObjectIntegrationTest.cs (100%) rename {test/Microsoft.AspNetCore.JsonPatch.Test => src/Features/JsonPatch/test}/IntegrationTests/ExpandoObjectIntegrationTest.cs (100%) rename {test/Microsoft.AspNetCore.JsonPatch.Test => src/Features/JsonPatch/test}/IntegrationTests/ListIntegrationTest.cs (100%) rename {test/Microsoft.AspNetCore.JsonPatch.Test => src/Features/JsonPatch/test}/IntegrationTests/NestedObjectIntegrationTest.cs (100%) rename {test/Microsoft.AspNetCore.JsonPatch.Test => src/Features/JsonPatch/test}/IntegrationTests/SimpleObjectIntegrationTest.cs (100%) rename {test/Microsoft.AspNetCore.JsonPatch.Test => src/Features/JsonPatch/test}/Internal/DictionaryAdapterTest.cs (100%) rename {test/Microsoft.AspNetCore.JsonPatch.Test => src/Features/JsonPatch/test}/Internal/DynamicObjectAdapterTest.cs (100%) rename {test/Microsoft.AspNetCore.JsonPatch.Test => src/Features/JsonPatch/test}/Internal/ListAdapterTest.cs (100%) rename {test/Microsoft.AspNetCore.JsonPatch.Test => src/Features/JsonPatch/test}/Internal/ObjectVisitorTest.cs (100%) rename {test/Microsoft.AspNetCore.JsonPatch.Test => src/Features/JsonPatch/test}/Internal/ParsedPathTests.cs (100%) rename {test/Microsoft.AspNetCore.JsonPatch.Test => src/Features/JsonPatch/test}/Internal/PocoAdapterTest.cs (100%) rename {test/Microsoft.AspNetCore.JsonPatch.Test => src/Features/JsonPatch/test}/JsonPatchDocumentGetPathTest.cs (100%) rename {test/Microsoft.AspNetCore.JsonPatch.Test => src/Features/JsonPatch/test}/JsonPatchDocumentJsonPropertyAttributeTest.cs (100%) rename {test/Microsoft.AspNetCore.JsonPatch.Test => src/Features/JsonPatch/test}/JsonPatchDocumentTest.cs (100%) create mode 100644 src/Features/JsonPatch/test/Microsoft.AspNetCore.JsonPatch.Tests.csproj rename {test/Microsoft.AspNetCore.JsonPatch.Test => src/Features/JsonPatch/test}/OperationBaseTests.cs (100%) rename {test/Microsoft.AspNetCore.JsonPatch.Test => src/Features/JsonPatch/test}/TestErrorLogger.cs (100%) rename {test/Microsoft.AspNetCore.JsonPatch.Test => src/Features/JsonPatch/test}/TestObjectModels/Customer.cs (100%) rename {test/Microsoft.AspNetCore.JsonPatch.Test => src/Features/JsonPatch/test}/TestObjectModels/DynamicTestObject.cs (100%) rename {test/Microsoft.AspNetCore.JsonPatch.Test => src/Features/JsonPatch/test}/TestObjectModels/InheritedObject.cs (100%) rename {test/Microsoft.AspNetCore.JsonPatch.Test => src/Features/JsonPatch/test}/TestObjectModels/NestedObject.cs (100%) rename {test/Microsoft.AspNetCore.JsonPatch.Test => src/Features/JsonPatch/test}/TestObjectModels/SimpleObject.cs (100%) rename {test/Microsoft.AspNetCore.JsonPatch.Test => src/Features/JsonPatch/test}/TestObjectModels/SimpleObjectWithNestedObject.cs (100%) delete mode 100644 src/Microsoft.AspNetCore.JsonPatch/Properties/AssemblyInfo.cs delete mode 100644 test/Directory.Build.props delete mode 100644 test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj delete mode 100644 version.props diff --git a/.appveyor.yml b/.appveyor.yml deleted file mode 100644 index 4eea96ab69..0000000000 --- a/.appveyor.yml +++ /dev/null @@ -1,17 +0,0 @@ -init: -- git config --global core.autocrlf true -branches: - only: - - dev - - /^release\/.*$/ - - /^(.*\/)?ci-.*$/ -build_script: -- ps: .\run.ps1 default-build -clone_depth: 1 -environment: - global: - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true - DOTNET_CLI_TELEMETRY_OPTOUT: 1 -test: 'off' -deploy: 'off' -os: Visual Studio 2017 diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index d4ee1cb7f3..0000000000 --- a/.gitattributes +++ /dev/null @@ -1,52 +0,0 @@ -*.doc diff=astextplain -*.DOC diff=astextplain -*.docx diff=astextplain -*.DOCX diff=astextplain -*.dot diff=astextplain -*.DOT diff=astextplain -*.pdf diff=astextplain -*.PDF diff=astextplain -*.rtf diff=astextplain -*.RTF diff=astextplain - -*.jpg binary -*.png binary -*.gif binary - -*.cs text=auto diff=csharp -*.vb text=auto -*.resx text=auto -*.c text=auto -*.cpp text=auto -*.cxx text=auto -*.h text=auto -*.hxx text=auto -*.py text=auto -*.rb text=auto -*.java text=auto -*.html text=auto -*.htm text=auto -*.css text=auto -*.scss text=auto -*.sass text=auto -*.less text=auto -*.js text=auto -*.lisp text=auto -*.clj text=auto -*.sql text=auto -*.php text=auto -*.lua text=auto -*.m text=auto -*.asm text=auto -*.erl text=auto -*.fs text=auto -*.fsx text=auto -*.hs text=auto - -*.csproj text=auto -*.vbproj text=auto -*.fsproj text=auto -*.dbproj text=auto -*.sln text=auto eol=crlf - -*.sh eol=lf diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index 101a084f0a..0000000000 --- a/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,3 +0,0 @@ -THIS ISSUE TRACKER IS CLOSED - please log new issues here: https://github.com/aspnet/Home/issues - -For information about this change, see https://github.com/aspnet/Announcements/issues/283 diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 2e8ec28064..0000000000 --- a/.gitignore +++ /dev/null @@ -1,39 +0,0 @@ -[Oo]bj/ -[Bb]in/ -TestResults/ -.nuget/ -.build/ -.testPublish/ -*.sln.ide/ -_ReSharper.*/ -packages/ -artifacts/ -PublishProfiles/ -.vs/ -bower_components/ -node_modules/ -debugSettings.json -project.lock.json -*.user -*.suo -*.cache -*.docstates -_ReSharper.* -nuget.exe -*net45.csproj -*net451.csproj -*k10.csproj -*.psess -*.vsp -*.pidb -*.userprefs -*DS_Store -*.ncrunchsolution -*.*sdf -*.ipch -.settings -*.sln.ide -node_modules -*launchSettings.json -*.orig -global.json diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 64bdbb4441..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,27 +0,0 @@ -language: csharp -sudo: false -dist: trusty -env: - global: - - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true - - DOTNET_CLI_TELEMETRY_OPTOUT: 1 -mono: none -os: -- linux -- osx -osx_image: xcode8.2 -addons: - apt: - packages: - - libunwind8 -branches: - only: - - dev - - /^release\/.*$/ - - /^(.*\/)?ci-.*$/ -before_install: -- if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; ln -s - /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib - /usr/local/lib/; fi -script: -- ./build.sh diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 64ff041d5c..0000000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,4 +0,0 @@ -Contributing -====== - -Information on contributing to this repo is in the [Contributing Guide](https://github.com/aspnet/Home/blob/dev/CONTRIBUTING.md) in the Home repo. diff --git a/Directory.Build.props b/Directory.Build.props deleted file mode 100644 index 88b93729bb..0000000000 --- a/Directory.Build.props +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - Microsoft ASP.NET Core - https://github.com/aspnet/JsonPatch - git - $(MSBuildThisFileDirectory) - $(MSBuildThisFileDirectory)build\Key.snk - true - true - true - - diff --git a/Directory.Build.targets b/Directory.Build.targets deleted file mode 100644 index 53b3f6e1da..0000000000 --- a/Directory.Build.targets +++ /dev/null @@ -1,7 +0,0 @@ - - - $(MicrosoftNETCoreApp20PackageVersion) - $(MicrosoftNETCoreApp21PackageVersion) - $(NETStandardLibrary20PackageVersion) - - diff --git a/JsonPatch.sln b/JsonPatch.sln deleted file mode 100644 index f0b6a578f1..0000000000 --- a/JsonPatch.sln +++ /dev/null @@ -1,63 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26815.3 -MinimumVisualStudioVersion = 15.0.26730.03 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{430B59ED-F960-4D3A-8FFE-3370008E168D}" - ProjectSection(SolutionItems) = preProject - src\Directory.Build.props = src\Directory.Build.props - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{36CD6341-AB44-44EB-B3AA-BF98C89FECDD}" - ProjectSection(SolutionItems) = preProject - test\Directory.Build.props = test\Directory.Build.props - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.JsonPatch", "src\Microsoft.AspNetCore.JsonPatch\Microsoft.AspNetCore.JsonPatch.csproj", "{4D55F4D8-633B-462F-A5B1-FEB84BD2D534}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.JsonPatch.Test", "test\Microsoft.AspNetCore.JsonPatch.Test\Microsoft.AspNetCore.JsonPatch.Test.csproj", "{81C20848-E063-4E12-AC40-0B55A532C16C}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C430C499-382D-47BD-B351-CF8F89C08CD2}" - ProjectSection(SolutionItems) = preProject - .appveyor.yml = .appveyor.yml - .gitattributes = .gitattributes - .gitignore = .gitignore - .travis.yml = .travis.yml - build.cmd = build.cmd - build.ps1 = build.ps1 - build.sh = build.sh - CONTRIBUTING.md = CONTRIBUTING.md - Directory.Build.props = Directory.Build.props - Directory.Build.targets = Directory.Build.targets - LICENSE.txt = LICENSE.txt - NuGet.config = NuGet.config - NuGetPackageVerifier.json = NuGetPackageVerifier.json - README.md = README.md - version.xml = version.xml - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {4D55F4D8-633B-462F-A5B1-FEB84BD2D534}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4D55F4D8-633B-462F-A5B1-FEB84BD2D534}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4D55F4D8-633B-462F-A5B1-FEB84BD2D534}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4D55F4D8-633B-462F-A5B1-FEB84BD2D534}.Release|Any CPU.Build.0 = Release|Any CPU - {81C20848-E063-4E12-AC40-0B55A532C16C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {81C20848-E063-4E12-AC40-0B55A532C16C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {81C20848-E063-4E12-AC40-0B55A532C16C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {81C20848-E063-4E12-AC40-0B55A532C16C}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {4D55F4D8-633B-462F-A5B1-FEB84BD2D534} = {430B59ED-F960-4D3A-8FFE-3370008E168D} - {81C20848-E063-4E12-AC40-0B55A532C16C} = {36CD6341-AB44-44EB-B3AA-BF98C89FECDD} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {9FFA3EB9-8740-4434-BC8C-F3D595161B59} - EndGlobalSection -EndGlobal diff --git a/LICENSE.txt b/LICENSE.txt deleted file mode 100644 index 7b2956ecee..0000000000 --- a/LICENSE.txt +++ /dev/null @@ -1,14 +0,0 @@ -Copyright (c) .NET Foundation and Contributors - -All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); you may not use -this file except in compliance with the License. You may obtain a copy of the -License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software distributed -under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -CONDITIONS OF ANY KIND, either express or implied. See the License for the -specific language governing permissions and limitations under the License. diff --git a/NuGet.config b/NuGet.config deleted file mode 100644 index e32bddfd51..0000000000 --- a/NuGet.config +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/NuGetPackageVerifier.json b/NuGetPackageVerifier.json deleted file mode 100644 index b153ab1515..0000000000 --- a/NuGetPackageVerifier.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "Default": { - "rules": [ - "DefaultCompositeRule" - ] - } -} \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index 6c27b76d9d..0000000000 --- a/README.md +++ /dev/null @@ -1,9 +0,0 @@ -JsonPatch -=== -AppVeyor: [![AppVeyor](https://ci.appveyor.com/api/projects/status/51gggjks5k3q6pr5/branch/dev?svg=true)](https://ci.appveyor.com/project/aspnetci/JsonPatch/branch/dev) - -Travis: [![Travis](https://travis-ci.org/aspnet/JsonPatch.svg?branch=dev)](https://travis-ci.org/aspnet/JsonPatch) - -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. - - diff --git a/build.cmd b/build.cmd deleted file mode 100644 index c0050bda12..0000000000 --- a/build.cmd +++ /dev/null @@ -1,2 +0,0 @@ -@ECHO OFF -PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0run.ps1' default-build %*; exit $LASTEXITCODE" diff --git a/build.sh b/build.sh deleted file mode 100755 index 98a4b22765..0000000000 --- a/build.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -# Call "sync" between "chmod" and execution to prevent "text file busy" error in Docker (aufs) -chmod +x "$DIR/run.sh"; sync -"$DIR/run.sh" default-build "$@" diff --git a/build/Key.snk b/build/Key.snk deleted file mode 100644 index e10e4889c125d3120cd9e81582243d70f7cbb806..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098=Iw=HCsnz~#iVhm& zj%TU(_THUee?3yHBjk$37ysB?i5#7WD$={H zV4B!OxRPrb|8)HPg~A}8P>^=#y<)56#=E&NzcjOtPK~<4n6GHt=K$ro*T(lhby_@U zEk(hLzk1H)0yXj{A_5>fk-TgNoP|q6(tP2xo8zt8i%212CWM#AeCd?`hS|4~L({h~Moo(~vy&3Z z1uI}`fd^*>o=rwbAGymj6RM^pZm(*Kfhs+Y1#`-2JPWZMK8@;ZWCk2+9bX4YP);~fj-BU*R zQPvWv$89!{Rl9wM+zR>_TSkn^voYxA?2G iKnV#iZ6Ah`K>b=@=IjYJXrxL124zR(38)nxe+&q_$QXwJ diff --git a/build/dependencies.props b/build/dependencies.props deleted file mode 100644 index 55c598b536..0000000000 --- a/build/dependencies.props +++ /dev/null @@ -1,29 +0,0 @@ - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - - - - - 2.1.3-rtm-15802 - 4.5.0 - 2.0.0 - 2.1.2 - 15.6.1 - 4.7.49 - 2.0.3 - 11.0.2 - 0.8.0 - 2.3.1 - 2.4.0-beta.1.build3945 - - - - - - - - 2.1.0 - 2.1.1 - - \ No newline at end of file diff --git a/build/repo.props b/build/repo.props deleted file mode 100644 index dab1601c88..0000000000 --- a/build/repo.props +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - Internal.AspNetCore.Universe.Lineup - 2.1.0-rc1-* - https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json - - - - - - - diff --git a/build/sources.props b/build/sources.props deleted file mode 100644 index 9215df9751..0000000000 --- a/build/sources.props +++ /dev/null @@ -1,17 +0,0 @@ - - - - - $(DotNetRestoreSources) - - $(RestoreSources); - https://dotnet.myget.org/F/dotnet-core/api/v3/index.json; - https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json; - https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json; - - - $(RestoreSources); - https://api.nuget.org/v3/index.json; - - - diff --git a/korebuild-lock.txt b/korebuild-lock.txt deleted file mode 100644 index 251c227c83..0000000000 --- a/korebuild-lock.txt +++ /dev/null @@ -1,2 +0,0 @@ -version:2.1.3-rtm-15802 -commithash:a7c08b45b440a7d2058a0aa1eaa3eb6ba811976a diff --git a/korebuild.json b/korebuild.json deleted file mode 100644 index 678d8bb948..0000000000 --- a/korebuild.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/release/2.1/tools/korebuild.schema.json", - "channel": "release/2.1" -} diff --git a/run.cmd b/run.cmd deleted file mode 100644 index d52d5c7e68..0000000000 --- a/run.cmd +++ /dev/null @@ -1,2 +0,0 @@ -@ECHO OFF -PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0run.ps1' %*; exit $LASTEXITCODE" diff --git a/run.ps1 b/run.ps1 deleted file mode 100644 index 27dcf848f8..0000000000 --- a/run.ps1 +++ /dev/null @@ -1,196 +0,0 @@ -#!/usr/bin/env powershell -#requires -version 4 - -<# -.SYNOPSIS -Executes KoreBuild commands. - -.DESCRIPTION -Downloads korebuild if required. Then executes the KoreBuild command. To see available commands, execute with `-Command help`. - -.PARAMETER Command -The KoreBuild command to run. - -.PARAMETER Path -The folder to build. Defaults to the folder containing this script. - -.PARAMETER Channel -The channel of KoreBuild to download. Overrides the value from the config file. - -.PARAMETER DotNetHome -The directory where .NET Core tools will be stored. - -.PARAMETER ToolsSource -The base url where build tools can be downloaded. Overrides the value from the config file. - -.PARAMETER Update -Updates KoreBuild to the latest version even if a lock file is present. - -.PARAMETER ConfigFile -The path to the configuration file that stores values. Defaults to korebuild.json. - -.PARAMETER ToolsSourceSuffix -The Suffix to append to the end of the ToolsSource. Useful for query strings in blob stores. - -.PARAMETER Arguments -Arguments to be passed to the command - -.NOTES -This function will create a file $PSScriptRoot/korebuild-lock.txt. This lock file can be committed to source, but does not have to be. -When the lockfile is not present, KoreBuild will create one using latest available version from $Channel. - -The $ConfigFile is expected to be an JSON file. It is optional, and the configuration values in it are optional as well. Any options set -in the file are overridden by command line parameters. - -.EXAMPLE -Example config file: -```json -{ - "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/dev/tools/korebuild.schema.json", - "channel": "dev", - "toolsSource": "https://aspnetcore.blob.core.windows.net/buildtools" -} -``` -#> -[CmdletBinding(PositionalBinding = $false)] -param( - [Parameter(Mandatory = $true, Position = 0)] - [string]$Command, - [string]$Path = $PSScriptRoot, - [Alias('c')] - [string]$Channel, - [Alias('d')] - [string]$DotNetHome, - [Alias('s')] - [string]$ToolsSource, - [Alias('u')] - [switch]$Update, - [string]$ConfigFile, - [string]$ToolsSourceSuffix, - [Parameter(ValueFromRemainingArguments = $true)] - [string[]]$Arguments -) - -Set-StrictMode -Version 2 -$ErrorActionPreference = 'Stop' - -# -# Functions -# - -function Get-KoreBuild { - - $lockFile = Join-Path $Path 'korebuild-lock.txt' - - if (!(Test-Path $lockFile) -or $Update) { - Get-RemoteFile "$ToolsSource/korebuild/channels/$Channel/latest.txt" $lockFile $ToolsSourceSuffix - } - - $version = Get-Content $lockFile | Where-Object { $_ -like 'version:*' } | Select-Object -first 1 - if (!$version) { - Write-Error "Failed to parse version from $lockFile. Expected a line that begins with 'version:'" - } - $version = $version.TrimStart('version:').Trim() - $korebuildPath = Join-Paths $DotNetHome ('buildtools', 'korebuild', $version) - - if (!(Test-Path $korebuildPath)) { - Write-Host -ForegroundColor Magenta "Downloading KoreBuild $version" - New-Item -ItemType Directory -Path $korebuildPath | Out-Null - $remotePath = "$ToolsSource/korebuild/artifacts/$version/korebuild.$version.zip" - - try { - $tmpfile = Join-Path ([IO.Path]::GetTempPath()) "KoreBuild-$([guid]::NewGuid()).zip" - Get-RemoteFile $remotePath $tmpfile $ToolsSourceSuffix - if (Get-Command -Name 'Expand-Archive' -ErrorAction Ignore) { - # Use built-in commands where possible as they are cross-plat compatible - Expand-Archive -Path $tmpfile -DestinationPath $korebuildPath - } - else { - # Fallback to old approach for old installations of PowerShell - Add-Type -AssemblyName System.IO.Compression.FileSystem - [System.IO.Compression.ZipFile]::ExtractToDirectory($tmpfile, $korebuildPath) - } - } - catch { - Remove-Item -Recurse -Force $korebuildPath -ErrorAction Ignore - throw - } - finally { - Remove-Item $tmpfile -ErrorAction Ignore - } - } - - return $korebuildPath -} - -function Join-Paths([string]$path, [string[]]$childPaths) { - $childPaths | ForEach-Object { $path = Join-Path $path $_ } - return $path -} - -function Get-RemoteFile([string]$RemotePath, [string]$LocalPath, [string]$RemoteSuffix) { - if ($RemotePath -notlike 'http*') { - Copy-Item $RemotePath $LocalPath - return - } - - $retries = 10 - while ($retries -gt 0) { - $retries -= 1 - try { - Invoke-WebRequest -UseBasicParsing -Uri $($RemotePath + $RemoteSuffix) -OutFile $LocalPath - return - } - catch { - Write-Verbose "Request failed. $retries retries remaining" - } - } - - Write-Error "Download failed: '$RemotePath'." -} - -# -# Main -# - -# Load configuration or set defaults - -$Path = Resolve-Path $Path -if (!$ConfigFile) { $ConfigFile = Join-Path $Path 'korebuild.json' } - -if (Test-Path $ConfigFile) { - try { - $config = Get-Content -Raw -Encoding UTF8 -Path $ConfigFile | ConvertFrom-Json - if ($config) { - if (!($Channel) -and (Get-Member -Name 'channel' -InputObject $config)) { [string] $Channel = $config.channel } - if (!($ToolsSource) -and (Get-Member -Name 'toolsSource' -InputObject $config)) { [string] $ToolsSource = $config.toolsSource} - } - } - catch { - Write-Warning "$ConfigFile could not be read. Its settings will be ignored." - Write-Warning $Error[0] - } -} - -if (!$DotNetHome) { - $DotNetHome = if ($env:DOTNET_HOME) { $env:DOTNET_HOME } ` - elseif ($env:USERPROFILE) { Join-Path $env:USERPROFILE '.dotnet'} ` - elseif ($env:HOME) {Join-Path $env:HOME '.dotnet'}` - else { Join-Path $PSScriptRoot '.dotnet'} -} - -if (!$Channel) { $Channel = 'dev' } -if (!$ToolsSource) { $ToolsSource = 'https://aspnetcore.blob.core.windows.net/buildtools' } - -# Execute - -$korebuildPath = Get-KoreBuild -Import-Module -Force -Scope Local (Join-Path $korebuildPath 'KoreBuild.psd1') - -try { - Set-KoreBuildSettings -ToolsSource $ToolsSource -DotNetHome $DotNetHome -RepoPath $Path -ConfigFile $ConfigFile - Invoke-KoreBuildCommand $Command @Arguments -} -finally { - Remove-Module 'KoreBuild' -ErrorAction Ignore -} diff --git a/run.sh b/run.sh deleted file mode 100755 index 834961fc3a..0000000000 --- a/run.sh +++ /dev/null @@ -1,231 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -# -# variables -# - -RESET="\033[0m" -RED="\033[0;31m" -YELLOW="\033[0;33m" -MAGENTA="\033[0;95m" -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -[ -z "${DOTNET_HOME:-}" ] && DOTNET_HOME="$HOME/.dotnet" -verbose=false -update=false -repo_path="$DIR" -channel='' -tools_source='' -tools_source_suffix='' - -# -# Functions -# -__usage() { - echo "Usage: $(basename "${BASH_SOURCE[0]}") command [options] [[--] ...]" - echo "" - echo "Arguments:" - echo " command The command to be run." - echo " ... Arguments passed to the command. Variable number of arguments allowed." - echo "" - echo "Options:" - echo " --verbose Show verbose output." - echo " -c|--channel The channel of KoreBuild to download. Overrides the value from the config file.." - echo " --config-file The path to the configuration file that stores values. Defaults to korebuild.json." - echo " -d|--dotnet-home The directory where .NET Core tools will be stored. Defaults to '\$DOTNET_HOME' or '\$HOME/.dotnet." - echo " --path The directory to build. Defaults to the directory containing the script." - echo " -s|--tools-source|-ToolsSource The base url where build tools can be downloaded. Overrides the value from the config file." - echo " --tools-source-suffix|-ToolsSourceSuffix The suffix to append to tools-source. Useful for query strings." - echo " -u|--update Update to the latest KoreBuild even if the lock file is present." - echo "" - echo "Description:" - echo " This function will create a file \$DIR/korebuild-lock.txt. This lock file can be committed to source, but does not have to be." - echo " When the lockfile is not present, KoreBuild will create one using latest available version from \$channel." - - if [[ "${1:-}" != '--no-exit' ]]; then - exit 2 - fi -} - -get_korebuild() { - local version - local lock_file="$repo_path/korebuild-lock.txt" - if [ ! -f "$lock_file" ] || [ "$update" = true ]; then - __get_remote_file "$tools_source/korebuild/channels/$channel/latest.txt" "$lock_file" "$tools_source_suffix" - fi - version="$(grep 'version:*' -m 1 "$lock_file")" - if [[ "$version" == '' ]]; then - __error "Failed to parse version from $lock_file. Expected a line that begins with 'version:'" - return 1 - fi - version="$(echo "${version#version:}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" - local korebuild_path="$DOTNET_HOME/buildtools/korebuild/$version" - - { - if [ ! -d "$korebuild_path" ]; then - mkdir -p "$korebuild_path" - local remote_path="$tools_source/korebuild/artifacts/$version/korebuild.$version.zip" - tmpfile="$(mktemp)" - echo -e "${MAGENTA}Downloading KoreBuild ${version}${RESET}" - if __get_remote_file "$remote_path" "$tmpfile" "$tools_source_suffix"; then - unzip -q -d "$korebuild_path" "$tmpfile" - fi - rm "$tmpfile" || true - fi - - source "$korebuild_path/KoreBuild.sh" - } || { - if [ -d "$korebuild_path" ]; then - echo "Cleaning up after failed installation" - rm -rf "$korebuild_path" || true - fi - return 1 - } -} - -__error() { - echo -e "${RED}error: $*${RESET}" 1>&2 -} - -__warn() { - echo -e "${YELLOW}warning: $*${RESET}" -} - -__machine_has() { - hash "$1" > /dev/null 2>&1 - return $? -} - -__get_remote_file() { - local remote_path=$1 - local local_path=$2 - local remote_path_suffix=$3 - - if [[ "$remote_path" != 'http'* ]]; then - cp "$remote_path" "$local_path" - return 0 - fi - - local failed=false - if __machine_has wget; then - wget --tries 10 --quiet -O "$local_path" "${remote_path}${remote_path_suffix}" || failed=true - else - failed=true - fi - - if [ "$failed" = true ] && __machine_has curl; then - failed=false - curl --retry 10 -sSL -f --create-dirs -o "$local_path" "${remote_path}${remote_path_suffix}" || failed=true - fi - - if [ "$failed" = true ]; then - __error "Download failed: $remote_path" 1>&2 - return 1 - fi -} - -# -# main -# - -command="${1:-}" -shift - -while [[ $# -gt 0 ]]; do - case $1 in - -\?|-h|--help) - __usage --no-exit - exit 0 - ;; - -c|--channel|-Channel) - shift - channel="${1:-}" - [ -z "$channel" ] && __usage - ;; - --config-file|-ConfigFile) - shift - config_file="${1:-}" - [ -z "$config_file" ] && __usage - if [ ! -f "$config_file" ]; then - __error "Invalid value for --config-file. $config_file does not exist." - exit 1 - fi - ;; - -d|--dotnet-home|-DotNetHome) - shift - DOTNET_HOME="${1:-}" - [ -z "$DOTNET_HOME" ] && __usage - ;; - --path|-Path) - shift - repo_path="${1:-}" - [ -z "$repo_path" ] && __usage - ;; - -s|--tools-source|-ToolsSource) - shift - tools_source="${1:-}" - [ -z "$tools_source" ] && __usage - ;; - --tools-source-suffix|-ToolsSourceSuffix) - shift - tools_source_suffix="${1:-}" - [ -z "$tools_source_suffix" ] && __usage - ;; - -u|--update|-Update) - update=true - ;; - --verbose|-Verbose) - verbose=true - ;; - --) - shift - break - ;; - *) - break - ;; - esac - shift -done - -if ! __machine_has unzip; then - __error 'Missing required command: unzip' - exit 1 -fi - -if ! __machine_has curl && ! __machine_has wget; then - __error 'Missing required command. Either wget or curl is required.' - exit 1 -fi - -[ -z "${config_file:-}" ] && config_file="$repo_path/korebuild.json" -if [ -f "$config_file" ]; then - if __machine_has jq ; then - if jq '.' "$config_file" >/dev/null ; then - config_channel="$(jq -r 'select(.channel!=null) | .channel' "$config_file")" - config_tools_source="$(jq -r 'select(.toolsSource!=null) | .toolsSource' "$config_file")" - else - __warn "$config_file is invalid JSON. Its settings will be ignored." - fi - elif __machine_has python ; then - if python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'))" >/dev/null ; then - config_channel="$(python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['channel'] if 'channel' in obj else '')")" - config_tools_source="$(python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['toolsSource'] if 'toolsSource' in obj else '')")" - else - __warn "$config_file is invalid JSON. Its settings will be ignored." - fi - else - __warn 'Missing required command: jq or pyton. Could not parse the JSON file. Its settings will be ignored.' - fi - - [ ! -z "${config_channel:-}" ] && channel="$config_channel" - [ ! -z "${config_tools_source:-}" ] && tools_source="$config_tools_source" -fi - -[ -z "$channel" ] && channel='dev' -[ -z "$tools_source" ] && tools_source='https://aspnetcore.blob.core.windows.net/buildtools' - -get_korebuild -set_korebuildsettings "$tools_source" "$DOTNET_HOME" "$repo_path" "$config_file" -invoke_korebuild_command "$command" "$@" diff --git a/src/Directory.Build.props b/src/Directory.Build.props deleted file mode 100644 index 4b89a431e7..0000000000 --- a/src/Directory.Build.props +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/src/Microsoft.AspNetCore.JsonPatch/Adapters/IObjectAdapter.cs b/src/Features/JsonPatch/src/Adapters/IObjectAdapter.cs similarity index 100% rename from src/Microsoft.AspNetCore.JsonPatch/Adapters/IObjectAdapter.cs rename to src/Features/JsonPatch/src/Adapters/IObjectAdapter.cs diff --git a/src/Microsoft.AspNetCore.JsonPatch/Adapters/IObjectAdapterWithTest.cs b/src/Features/JsonPatch/src/Adapters/IObjectAdapterWithTest.cs similarity index 100% rename from src/Microsoft.AspNetCore.JsonPatch/Adapters/IObjectAdapterWithTest.cs rename to src/Features/JsonPatch/src/Adapters/IObjectAdapterWithTest.cs diff --git a/src/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs b/src/Features/JsonPatch/src/Adapters/ObjectAdapter.cs similarity index 100% rename from src/Microsoft.AspNetCore.JsonPatch/Adapters/ObjectAdapter.cs rename to src/Features/JsonPatch/src/Adapters/ObjectAdapter.cs diff --git a/src/Microsoft.AspNetCore.JsonPatch/Converters/JsonPatchDocumentConverter.cs b/src/Features/JsonPatch/src/Converters/JsonPatchDocumentConverter.cs similarity index 100% rename from src/Microsoft.AspNetCore.JsonPatch/Converters/JsonPatchDocumentConverter.cs rename to src/Features/JsonPatch/src/Converters/JsonPatchDocumentConverter.cs diff --git a/src/Microsoft.AspNetCore.JsonPatch/Converters/TypedJsonPatchDocumentConverter.cs b/src/Features/JsonPatch/src/Converters/TypedJsonPatchDocumentConverter.cs similarity index 100% rename from src/Microsoft.AspNetCore.JsonPatch/Converters/TypedJsonPatchDocumentConverter.cs rename to src/Features/JsonPatch/src/Converters/TypedJsonPatchDocumentConverter.cs diff --git a/src/Microsoft.AspNetCore.JsonPatch/Exceptions/JsonPatchException.cs b/src/Features/JsonPatch/src/Exceptions/JsonPatchException.cs similarity index 100% rename from src/Microsoft.AspNetCore.JsonPatch/Exceptions/JsonPatchException.cs rename to src/Features/JsonPatch/src/Exceptions/JsonPatchException.cs diff --git a/src/Microsoft.AspNetCore.JsonPatch/Helpers/GetValueResult.cs b/src/Features/JsonPatch/src/Helpers/GetValueResult.cs similarity index 100% rename from src/Microsoft.AspNetCore.JsonPatch/Helpers/GetValueResult.cs rename to src/Features/JsonPatch/src/Helpers/GetValueResult.cs diff --git a/src/Microsoft.AspNetCore.JsonPatch/Helpers/JsonPatchProperty.cs b/src/Features/JsonPatch/src/Helpers/JsonPatchProperty.cs similarity index 100% rename from src/Microsoft.AspNetCore.JsonPatch/Helpers/JsonPatchProperty.cs rename to src/Features/JsonPatch/src/Helpers/JsonPatchProperty.cs diff --git a/src/Microsoft.AspNetCore.JsonPatch/IJsonPatchDocument.cs b/src/Features/JsonPatch/src/IJsonPatchDocument.cs similarity index 100% rename from src/Microsoft.AspNetCore.JsonPatch/IJsonPatchDocument.cs rename to src/Features/JsonPatch/src/IJsonPatchDocument.cs diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/ConversionResult.cs b/src/Features/JsonPatch/src/Internal/ConversionResult.cs similarity index 100% rename from src/Microsoft.AspNetCore.JsonPatch/Internal/ConversionResult.cs rename to src/Features/JsonPatch/src/Internal/ConversionResult.cs diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/ConversionResultProvider.cs b/src/Features/JsonPatch/src/Internal/ConversionResultProvider.cs similarity index 100% rename from src/Microsoft.AspNetCore.JsonPatch/Internal/ConversionResultProvider.cs rename to src/Features/JsonPatch/src/Internal/ConversionResultProvider.cs diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/DictionaryAdapterOfTU.cs b/src/Features/JsonPatch/src/Internal/DictionaryAdapterOfTU.cs similarity index 100% rename from src/Microsoft.AspNetCore.JsonPatch/Internal/DictionaryAdapterOfTU.cs rename to src/Features/JsonPatch/src/Internal/DictionaryAdapterOfTU.cs diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/DynamicObjectAdapter.cs b/src/Features/JsonPatch/src/Internal/DynamicObjectAdapter.cs similarity index 100% rename from src/Microsoft.AspNetCore.JsonPatch/Internal/DynamicObjectAdapter.cs rename to src/Features/JsonPatch/src/Internal/DynamicObjectAdapter.cs diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/ErrorReporter.cs b/src/Features/JsonPatch/src/Internal/ErrorReporter.cs similarity index 100% rename from src/Microsoft.AspNetCore.JsonPatch/Internal/ErrorReporter.cs rename to src/Features/JsonPatch/src/Internal/ErrorReporter.cs diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/IAdapter.cs b/src/Features/JsonPatch/src/Internal/IAdapter.cs similarity index 100% rename from src/Microsoft.AspNetCore.JsonPatch/Internal/IAdapter.cs rename to src/Features/JsonPatch/src/Internal/IAdapter.cs diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/ListAdapter.cs b/src/Features/JsonPatch/src/Internal/ListAdapter.cs similarity index 100% rename from src/Microsoft.AspNetCore.JsonPatch/Internal/ListAdapter.cs rename to src/Features/JsonPatch/src/Internal/ListAdapter.cs diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/ObjectVisitor.cs b/src/Features/JsonPatch/src/Internal/ObjectVisitor.cs similarity index 100% rename from src/Microsoft.AspNetCore.JsonPatch/Internal/ObjectVisitor.cs rename to src/Features/JsonPatch/src/Internal/ObjectVisitor.cs diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/ParsedPath.cs b/src/Features/JsonPatch/src/Internal/ParsedPath.cs similarity index 100% rename from src/Microsoft.AspNetCore.JsonPatch/Internal/ParsedPath.cs rename to src/Features/JsonPatch/src/Internal/ParsedPath.cs diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/PathHelpers.cs b/src/Features/JsonPatch/src/Internal/PathHelpers.cs similarity index 100% rename from src/Microsoft.AspNetCore.JsonPatch/Internal/PathHelpers.cs rename to src/Features/JsonPatch/src/Internal/PathHelpers.cs diff --git a/src/Microsoft.AspNetCore.JsonPatch/Internal/PocoAdapter.cs b/src/Features/JsonPatch/src/Internal/PocoAdapter.cs similarity index 100% rename from src/Microsoft.AspNetCore.JsonPatch/Internal/PocoAdapter.cs rename to src/Features/JsonPatch/src/Internal/PocoAdapter.cs diff --git a/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocument.cs b/src/Features/JsonPatch/src/JsonPatchDocument.cs similarity index 100% rename from src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocument.cs rename to src/Features/JsonPatch/src/JsonPatchDocument.cs diff --git a/src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs b/src/Features/JsonPatch/src/JsonPatchDocumentOfT.cs similarity index 100% rename from src/Microsoft.AspNetCore.JsonPatch/JsonPatchDocumentOfT.cs rename to src/Features/JsonPatch/src/JsonPatchDocumentOfT.cs diff --git a/src/Microsoft.AspNetCore.JsonPatch/JsonPatchError.cs b/src/Features/JsonPatch/src/JsonPatchError.cs similarity index 100% rename from src/Microsoft.AspNetCore.JsonPatch/JsonPatchError.cs rename to src/Features/JsonPatch/src/JsonPatchError.cs diff --git a/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj b/src/Features/JsonPatch/src/Microsoft.AspNetCore.JsonPatch.csproj similarity index 51% rename from src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj rename to src/Features/JsonPatch/src/Microsoft.AspNetCore.JsonPatch.csproj index 9bd08214f6..3708e92927 100644 --- a/src/Microsoft.AspNetCore.JsonPatch/Microsoft.AspNetCore.JsonPatch.csproj +++ b/src/Features/JsonPatch/src/Microsoft.AspNetCore.JsonPatch.csproj @@ -9,9 +9,9 @@ - - - + + + diff --git a/src/Microsoft.AspNetCore.JsonPatch/Operations/Operation.cs b/src/Features/JsonPatch/src/Operations/Operation.cs similarity index 100% rename from src/Microsoft.AspNetCore.JsonPatch/Operations/Operation.cs rename to src/Features/JsonPatch/src/Operations/Operation.cs diff --git a/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationBase.cs b/src/Features/JsonPatch/src/Operations/OperationBase.cs similarity index 100% rename from src/Microsoft.AspNetCore.JsonPatch/Operations/OperationBase.cs rename to src/Features/JsonPatch/src/Operations/OperationBase.cs diff --git a/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationOfT.cs b/src/Features/JsonPatch/src/Operations/OperationOfT.cs similarity index 100% rename from src/Microsoft.AspNetCore.JsonPatch/Operations/OperationOfT.cs rename to src/Features/JsonPatch/src/Operations/OperationOfT.cs diff --git a/src/Microsoft.AspNetCore.JsonPatch/Operations/OperationType.cs b/src/Features/JsonPatch/src/Operations/OperationType.cs similarity index 100% rename from src/Microsoft.AspNetCore.JsonPatch/Operations/OperationType.cs rename to src/Features/JsonPatch/src/Operations/OperationType.cs 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/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs b/src/Features/JsonPatch/src/Properties/Resources.Designer.cs similarity index 100% rename from src/Microsoft.AspNetCore.JsonPatch/Properties/Resources.Designer.cs rename to src/Features/JsonPatch/src/Properties/Resources.Designer.cs diff --git a/src/Microsoft.AspNetCore.JsonPatch/Resources.resx b/src/Features/JsonPatch/src/Resources.resx similarity index 100% rename from src/Microsoft.AspNetCore.JsonPatch/Resources.resx rename to src/Features/JsonPatch/src/Resources.resx diff --git a/src/Microsoft.AspNetCore.JsonPatch/baseline.netcore.json b/src/Features/JsonPatch/src/baseline.netcore.json similarity index 100% rename from src/Microsoft.AspNetCore.JsonPatch/baseline.netcore.json rename to src/Features/JsonPatch/src/baseline.netcore.json diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/CustomNamingStrategyTests.cs b/src/Features/JsonPatch/test/CustomNamingStrategyTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.JsonPatch.Test/CustomNamingStrategyTests.cs rename to src/Features/JsonPatch/test/CustomNamingStrategyTests.cs diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/AnonymousObjectIntegrationTest.cs b/src/Features/JsonPatch/test/IntegrationTests/AnonymousObjectIntegrationTest.cs similarity index 100% rename from test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/AnonymousObjectIntegrationTest.cs rename to src/Features/JsonPatch/test/IntegrationTests/AnonymousObjectIntegrationTest.cs diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/DictionaryIntegrationTest.cs b/src/Features/JsonPatch/test/IntegrationTests/DictionaryIntegrationTest.cs similarity index 100% rename from test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/DictionaryIntegrationTest.cs rename to src/Features/JsonPatch/test/IntegrationTests/DictionaryIntegrationTest.cs diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/DynamicObjectIntegrationTest.cs b/src/Features/JsonPatch/test/IntegrationTests/DynamicObjectIntegrationTest.cs similarity index 100% rename from test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/DynamicObjectIntegrationTest.cs rename to src/Features/JsonPatch/test/IntegrationTests/DynamicObjectIntegrationTest.cs diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/ExpandoObjectIntegrationTest.cs b/src/Features/JsonPatch/test/IntegrationTests/ExpandoObjectIntegrationTest.cs similarity index 100% rename from test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/ExpandoObjectIntegrationTest.cs rename to src/Features/JsonPatch/test/IntegrationTests/ExpandoObjectIntegrationTest.cs diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/ListIntegrationTest.cs b/src/Features/JsonPatch/test/IntegrationTests/ListIntegrationTest.cs similarity index 100% rename from test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/ListIntegrationTest.cs rename to src/Features/JsonPatch/test/IntegrationTests/ListIntegrationTest.cs diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/NestedObjectIntegrationTest.cs b/src/Features/JsonPatch/test/IntegrationTests/NestedObjectIntegrationTest.cs similarity index 100% rename from test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/NestedObjectIntegrationTest.cs rename to src/Features/JsonPatch/test/IntegrationTests/NestedObjectIntegrationTest.cs diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/SimpleObjectIntegrationTest.cs b/src/Features/JsonPatch/test/IntegrationTests/SimpleObjectIntegrationTest.cs similarity index 100% rename from test/Microsoft.AspNetCore.JsonPatch.Test/IntegrationTests/SimpleObjectIntegrationTest.cs rename to src/Features/JsonPatch/test/IntegrationTests/SimpleObjectIntegrationTest.cs diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Internal/DictionaryAdapterTest.cs b/src/Features/JsonPatch/test/Internal/DictionaryAdapterTest.cs similarity index 100% rename from test/Microsoft.AspNetCore.JsonPatch.Test/Internal/DictionaryAdapterTest.cs rename to src/Features/JsonPatch/test/Internal/DictionaryAdapterTest.cs diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Internal/DynamicObjectAdapterTest.cs b/src/Features/JsonPatch/test/Internal/DynamicObjectAdapterTest.cs similarity index 100% rename from test/Microsoft.AspNetCore.JsonPatch.Test/Internal/DynamicObjectAdapterTest.cs rename to src/Features/JsonPatch/test/Internal/DynamicObjectAdapterTest.cs diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Internal/ListAdapterTest.cs b/src/Features/JsonPatch/test/Internal/ListAdapterTest.cs similarity index 100% rename from test/Microsoft.AspNetCore.JsonPatch.Test/Internal/ListAdapterTest.cs rename to src/Features/JsonPatch/test/Internal/ListAdapterTest.cs diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Internal/ObjectVisitorTest.cs b/src/Features/JsonPatch/test/Internal/ObjectVisitorTest.cs similarity index 100% rename from test/Microsoft.AspNetCore.JsonPatch.Test/Internal/ObjectVisitorTest.cs rename to src/Features/JsonPatch/test/Internal/ObjectVisitorTest.cs diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Internal/ParsedPathTests.cs b/src/Features/JsonPatch/test/Internal/ParsedPathTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.JsonPatch.Test/Internal/ParsedPathTests.cs rename to src/Features/JsonPatch/test/Internal/ParsedPathTests.cs diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Internal/PocoAdapterTest.cs b/src/Features/JsonPatch/test/Internal/PocoAdapterTest.cs similarity index 100% rename from test/Microsoft.AspNetCore.JsonPatch.Test/Internal/PocoAdapterTest.cs rename to src/Features/JsonPatch/test/Internal/PocoAdapterTest.cs diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentGetPathTest.cs b/src/Features/JsonPatch/test/JsonPatchDocumentGetPathTest.cs similarity index 100% rename from test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentGetPathTest.cs rename to src/Features/JsonPatch/test/JsonPatchDocumentGetPathTest.cs diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs b/src/Features/JsonPatch/test/JsonPatchDocumentJsonPropertyAttributeTest.cs similarity index 100% rename from test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentJsonPropertyAttributeTest.cs rename to src/Features/JsonPatch/test/JsonPatchDocumentJsonPropertyAttributeTest.cs diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentTest.cs b/src/Features/JsonPatch/test/JsonPatchDocumentTest.cs similarity index 100% rename from test/Microsoft.AspNetCore.JsonPatch.Test/JsonPatchDocumentTest.cs rename to src/Features/JsonPatch/test/JsonPatchDocumentTest.cs 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..5aca855c9c --- /dev/null +++ b/src/Features/JsonPatch/test/Microsoft.AspNetCore.JsonPatch.Tests.csproj @@ -0,0 +1,11 @@ + + + + netcoreapp2.1;net461 + + + + + + + diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/OperationBaseTests.cs b/src/Features/JsonPatch/test/OperationBaseTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.JsonPatch.Test/OperationBaseTests.cs rename to src/Features/JsonPatch/test/OperationBaseTests.cs diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/TestErrorLogger.cs b/src/Features/JsonPatch/test/TestErrorLogger.cs similarity index 100% rename from test/Microsoft.AspNetCore.JsonPatch.Test/TestErrorLogger.cs rename to src/Features/JsonPatch/test/TestErrorLogger.cs diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/TestObjectModels/Customer.cs b/src/Features/JsonPatch/test/TestObjectModels/Customer.cs similarity index 100% rename from test/Microsoft.AspNetCore.JsonPatch.Test/TestObjectModels/Customer.cs rename to src/Features/JsonPatch/test/TestObjectModels/Customer.cs diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/TestObjectModels/DynamicTestObject.cs b/src/Features/JsonPatch/test/TestObjectModels/DynamicTestObject.cs similarity index 100% rename from test/Microsoft.AspNetCore.JsonPatch.Test/TestObjectModels/DynamicTestObject.cs rename to src/Features/JsonPatch/test/TestObjectModels/DynamicTestObject.cs diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/TestObjectModels/InheritedObject.cs b/src/Features/JsonPatch/test/TestObjectModels/InheritedObject.cs similarity index 100% rename from test/Microsoft.AspNetCore.JsonPatch.Test/TestObjectModels/InheritedObject.cs rename to src/Features/JsonPatch/test/TestObjectModels/InheritedObject.cs diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/TestObjectModels/NestedObject.cs b/src/Features/JsonPatch/test/TestObjectModels/NestedObject.cs similarity index 100% rename from test/Microsoft.AspNetCore.JsonPatch.Test/TestObjectModels/NestedObject.cs rename to src/Features/JsonPatch/test/TestObjectModels/NestedObject.cs diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/TestObjectModels/SimpleObject.cs b/src/Features/JsonPatch/test/TestObjectModels/SimpleObject.cs similarity index 100% rename from test/Microsoft.AspNetCore.JsonPatch.Test/TestObjectModels/SimpleObject.cs rename to src/Features/JsonPatch/test/TestObjectModels/SimpleObject.cs diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/TestObjectModels/SimpleObjectWithNestedObject.cs b/src/Features/JsonPatch/test/TestObjectModels/SimpleObjectWithNestedObject.cs similarity index 100% rename from test/Microsoft.AspNetCore.JsonPatch.Test/TestObjectModels/SimpleObjectWithNestedObject.cs rename to src/Features/JsonPatch/test/TestObjectModels/SimpleObjectWithNestedObject.cs diff --git a/src/Microsoft.AspNetCore.JsonPatch/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.JsonPatch/Properties/AssemblyInfo.cs deleted file mode 100644 index 08e6f5e01c..0000000000 --- a/src/Microsoft.AspNetCore.JsonPatch/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,7 +0,0 @@ - -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Runtime.CompilerServices; - -[assembly: InternalsVisibleTo("Microsoft.AspNetCore.JsonPatch.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] diff --git a/test/Directory.Build.props b/test/Directory.Build.props deleted file mode 100644 index 98685a5e13..0000000000 --- a/test/Directory.Build.props +++ /dev/null @@ -1,18 +0,0 @@ - - - - - netcoreapp2.1 - $(DeveloperBuildTestTfms) - $(StandardTestTfms);netcoreapp2.0 - $(StandardTestTfms);net461 - - - - - - - - - - diff --git a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj b/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj deleted file mode 100644 index ce1d92802d..0000000000 --- a/test/Microsoft.AspNetCore.JsonPatch.Test/Microsoft.AspNetCore.JsonPatch.Test.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - $(StandardTestTfms) - - - - - - - - - - - - - - - - diff --git a/version.props b/version.props deleted file mode 100644 index 669c874829..0000000000 --- a/version.props +++ /dev/null @@ -1,12 +0,0 @@ - - - 2.1.1 - rtm - $(VersionPrefix) - $(VersionPrefix)-$(VersionSuffix)-final - t000 - a- - $(FeatureBranchVersionPrefix)$(VersionSuffix)-$([System.Text.RegularExpressions.Regex]::Replace('$(FeatureBranchVersionSuffix)', '[^\w-]', '-')) - $(VersionSuffix)-$(BuildNumber) - - From 59ed8df382a76b8a0d1b19853318614b87ed171d Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Fri, 9 Nov 2018 13:05:31 -0800 Subject: [PATCH 459/471] Add targets and tools for ensuring consistent package versions between servicing builds --- Directory.Build.props | 8 ++ Directory.Build.targets | 31 ++++ build/SharedFx.targets | 2 +- build/buildorder.props | 2 - build/dependencies.props | 1 + build/repo.props | 15 +- build/repo.targets | 44 +++++- build/submodules.props | 1 - build/tasks/RepoTasks.csproj | 1 + ...ch-updates.md => PreparingPatchUpdates.md} | 10 +- eng/Baseline.props | 100 +++++++++++++ eng/Dependencies.props | 46 ++++++ eng/PatchConfig.props | 13 ++ eng/ProjectReferences.props | 7 + eng/targets/CSharp.Common.props | 14 ++ eng/targets/CSharp.Common.targets | 5 + eng/targets/Packaging.targets | 30 ++++ eng/targets/ResolveReferences.targets | 135 ++++++++++++++++++ .../BaselineGenerator.csproj | 15 ++ eng/tools/BaselineGenerator/Program.cs | 132 +++++++++++++++++ eng/tools/BaselineGenerator/README.md | 10 ++ eng/tools/BaselineGenerator/baseline.xml | 13 ++ eng/tools/Directory.Build.props | 3 + eng/tools/Directory.Build.targets | 2 + eng/tools/tools.sln | 34 +++++ src/DataProtection/Directory.Build.props | 16 --- src/Packages/Directory.Build.props | 4 +- version.props | 5 + 28 files changed, 665 insertions(+), 34 deletions(-) rename docs/{preparing-patch-updates.md => PreparingPatchUpdates.md} (74%) create mode 100644 eng/Baseline.props create mode 100644 eng/Dependencies.props create mode 100644 eng/PatchConfig.props create mode 100644 eng/ProjectReferences.props create mode 100644 eng/targets/CSharp.Common.props create mode 100644 eng/targets/CSharp.Common.targets create mode 100644 eng/targets/Packaging.targets create mode 100644 eng/targets/ResolveReferences.targets create mode 100644 eng/tools/BaselineGenerator/BaselineGenerator.csproj create mode 100644 eng/tools/BaselineGenerator/Program.cs create mode 100644 eng/tools/BaselineGenerator/README.md create mode 100644 eng/tools/BaselineGenerator/baseline.xml create mode 100644 eng/tools/Directory.Build.props create mode 100644 eng/tools/Directory.Build.targets create mode 100644 eng/tools/tools.sln diff --git a/Directory.Build.props b/Directory.Build.props index bdb885cd9f..c0f5b99d35 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -34,5 +34,13 @@ true + + netcoreapp2.1;net461 + + + + + + diff --git a/Directory.Build.targets b/Directory.Build.targets index 30ce3e3322..052fb09136 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -1,9 +1,39 @@ + + $(AssemblyName) + false + + + + + + + true + $(PackagesInPatch.Contains(' $(PackageId);')) + + + + + true + + false + + + + + $(BaselinePackageVersion).0 + $(BaselinePackageVersion).0 + $(BaselinePackageVersion) + + true + + false + $(IsImplementationProject) true false @@ -14,4 +44,5 @@ + diff --git a/build/SharedFx.targets b/build/SharedFx.targets index 84d2aee45c..2ab7352634 100644 --- a/build/SharedFx.targets +++ b/build/SharedFx.targets @@ -33,7 +33,7 @@ - + $(_MetapackageSrcRoot)$(MetapackageName)\ $(_WorkRoot)pkg\$(MetapackageName)\ diff --git a/build/buildorder.props b/build/buildorder.props index 1cb0f6cec8..55aceb0800 100644 --- a/build/buildorder.props +++ b/build/buildorder.props @@ -7,7 +7,6 @@ - @@ -30,7 +29,6 @@ - diff --git a/build/dependencies.props b/build/dependencies.props index dda2ffa595..e0fdd5fcc2 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -15,6 +15,7 @@ $(KoreBuildVersion) $(KoreBuildVersion) + 2.1.3-rtm-15842 diff --git a/build/repo.props b/build/repo.props index ec2fe7ab7f..a44dd76881 100644 --- a/build/repo.props +++ b/build/repo.props @@ -2,9 +2,8 @@ true - false - - public + true + false false true @@ -42,6 +41,16 @@ + + + + + + diff --git a/build/repo.targets b/build/repo.targets index cde696935c..0c1125bd51 100644 --- a/build/repo.targets +++ b/build/repo.targets @@ -16,18 +16,52 @@ SetTeamCityBuildNumberToVersion;$(PrepareDependsOn);VerifyPackageArtifactConfig;VerifyExternalDependencyConfig;PrepareOutputPaths $(CleanDependsOn);CleanArtifacts;CleanRepoArtifacts - $(RestoreDependsOn);InstallDotNet - $(CompileDependsOn);BuildRepositories + $(RestoreDependsOn);InstallDotNet;RestoreProjects + $(CompileDependsOn);BuildProjects;PackProjects;BuildRepositories $(PackageDependsOn);BuildMetapackages;CheckExpectedPackagesExist - $(TestDependsOn);_TestRepositories - $(GetArtifactInfoDependsOn);ResolveRepoInfo + $(TestDependsOn);TestProjects;_TestRepositories + $(GetArtifactInfoDependsOn);GetProjectArtifactInfo;ResolveRepoInfo - + + + + + + + + $(MSBuildThisFileDirectory)..\eng\ProjectReferences.props + + + + + @(_ProjectReferenceProvider->'', '%0A ') + + + ]]> + + + + + + + + + + + + + + MicrosoftNETCoreAppPackageVersion=$(MicrosoftNETCoreAppPackageVersion); diff --git a/build/submodules.props b/build/submodules.props index 8b30d5efcb..8030fb219f 100644 --- a/build/submodules.props +++ b/build/submodules.props @@ -77,6 +77,5 @@ - 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/preparing-patch-updates.md b/docs/PreparingPatchUpdates.md similarity index 74% rename from docs/preparing-patch-updates.md rename to docs/PreparingPatchUpdates.md index 87821935de..34813e8162 100644 --- a/docs/preparing-patch-updates.md +++ b/docs/PreparingPatchUpdates.md @@ -10,11 +10,15 @@ In order to prepare this repo to build a new servicing update, the following cha + 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 +* 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 list of repositories which will contain changes in [build/submodules.props](/build/submodules.props). +* 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. diff --git a/eng/Baseline.props b/eng/Baseline.props new file mode 100644 index 0000000000..acae8786c0 --- /dev/null +++ b/eng/Baseline.props @@ -0,0 +1,100 @@ + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + 2.1.6 + + + + 2.1.1 + + + + + 2.1.1 + + + + + + + + + + 2.1.1 + + + + + + + + + + + + + + + 2.1.1 + + + + + 2.1.1 + + + + + + + + + 2.1.1 + + + + + + + + 2.1.1 + + + + + + + + 0.4.1 + + + + + + + + 2.1.1 + + + + + + + + 2.1.1 + + + + + + + + 2.1.1 + + + + + + + \ No newline at end of file diff --git a/eng/Dependencies.props b/eng/Dependencies.props new file mode 100644 index 0000000000..917b401b0a --- /dev/null +++ b/eng/Dependencies.props @@ -0,0 +1,46 @@ + + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/eng/PatchConfig.props b/eng/PatchConfig.props new file mode 100644 index 0000000000..91e93a17fe --- /dev/null +++ b/eng/PatchConfig.props @@ -0,0 +1,13 @@ + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + + + + + Microsoft.AspNetCore; + Microsoft.AspNetCore.Server.IISIntegration; + + + + diff --git a/eng/ProjectReferences.props b/eng/ProjectReferences.props new file mode 100644 index 0000000000..7381583fb8 --- /dev/null +++ b/eng/ProjectReferences.props @@ -0,0 +1,7 @@ + + + + + + + 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..69ad343564 --- /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/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..d3d753a5ba --- /dev/null +++ b/eng/tools/BaselineGenerator/Program.cs @@ -0,0 +1,132 @@ +// Copyright (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; + + 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); + + 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 = $"{source}/{id}/{version}"; + using (var file = File.Create(nupkgPath)) + { + Console.WriteLine($"Downloading {url}"); + var response = await client.GetStreamAsync(url); + 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..3687f918d6 --- /dev/null +++ b/eng/tools/BaselineGenerator/baseline.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + 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/src/DataProtection/Directory.Build.props b/src/DataProtection/Directory.Build.props index b18bd3713f..deb7bb4ee6 100644 --- a/src/DataProtection/Directory.Build.props +++ b/src/DataProtection/Directory.Build.props @@ -5,20 +5,4 @@ - - false - - - - - - - - - - - - - - diff --git a/src/Packages/Directory.Build.props b/src/Packages/Directory.Build.props index b917f91a06..fe11cd2f09 100644 --- a/src/Packages/Directory.Build.props +++ b/src/Packages/Directory.Build.props @@ -3,9 +3,7 @@ false + true - - - diff --git a/version.props b/version.props index 3e4178aafa..f0cbed211d 100644 --- a/version.props +++ b/version.props @@ -11,6 +11,8 @@ $(PreReleaseLabel)-$(BuildNumber) $(PreReleaseBrandingLabel) Build $(BuildNumber) + + true false true @@ -32,6 +34,9 @@ $(VersionSuffix)+$(VersionMetadata) release/$(AspNetCoreMajorVersion).$(AspNetCoreMinorVersion) + + + $(AspNetCoreMajorVersion).$(AspNetCoreMinorVersion).$([MSBuild]::Subtract($(AspNetCorePatchVersion), 1)) From 27a47d07c55256368c2fa4b44c1eb7fda94a1a4f Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Fri, 9 Nov 2018 13:06:13 -0800 Subject: [PATCH 460/471] Reorganize the src/WebSockets/ folder to follow new source code organization conventions --- src/Middleware/Middleware.sln | 120 +++++++++++++++ src/Middleware/WebSockets/README.md | 12 ++ .../AutobahnTestAppAspNet4.csproj.aspnet4 | 0 .../AutobahnTestAppAspNet4/EchoSocket.ashx | 0 .../AutobahnTestAppAspNet4/EchoSocket.ashx.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../AutobahnTestAppAspNet4/Web.Debug.config | 0 .../AutobahnTestAppAspNet4/Web.Release.config | 0 .../samples/AutobahnTestAppAspNet4/Web.config | 0 .../AutobahnTestAppAspNet4/packages.config | 0 .../AutobahnTestAppAspNet4/wstest-spec.json | 0 .../AutobahnTestAppHttpListener/App.config | 0 .../AutobahnTestAppHttpListener.csproj.net461 | 0 .../AutobahnTestAppHttpListener/Program.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../WebSockets/samples/EchoApp/EchoApp.csproj | 16 ++ .../WebSockets/samples/EchoApp/Program.cs | 0 .../EchoApp/Properties/launchSettings.json | 0 .../WebSockets/samples/EchoApp/Startup.cs | 0 .../samples/EchoApp/wwwroot/index.html | 0 .../WebSockets/samples/TestServer/App.config | 0 .../WebSockets/samples/TestServer/Program.cs | 0 .../TestServer/Properties/AssemblyInfo.cs | 0 .../samples/TestServer/TestServer.csproj | 0 .../WebSockets}/setup-wstest.ps1 | 0 .../WebSockets}/setup-wstest.sh | 0 .../src}/ExtendedWebSocketAcceptContext.cs | 0 .../WebSockets/src}/Internal/Constants.cs | 0 .../src}/Internal/HandshakeHelpers.cs | 0 .../Microsoft.AspNetCore.WebSockets.csproj | 6 +- .../WebSockets/src}/WebSocketMiddleware.cs | 0 .../src}/WebSocketMiddlewareExtensions.cs | 0 .../WebSockets/src}/WebSocketOptions.cs | 0 .../WebSockets/src}/baseline.netcore.json | 0 .../AutobahnTestApp/AutobahnTestApp.csproj | 22 +-- .../test/AutobahnTestApp/Program.cs | 0 .../Properties/launchSettings.json | 0 .../WebSockets/test/AutobahnTestApp/README.md | 0 .../test/AutobahnTestApp/Startup.cs | 0 .../TestResources/testCert.pfx | Bin .../TestResources/testCert.txt | 0 .../scripts/RunAutobahnTests.ps1 | 0 .../scripts/autobahn.spec.json | 0 .../Autobahn/AutobahnCaseResult.cs | 0 .../Autobahn/AutobahnExpectations.cs | 0 .../Autobahn/AutobahnResult.cs | 0 .../Autobahn/AutobahnServerResult.cs | 0 .../Autobahn/AutobahnSpec.cs | 0 .../Autobahn/AutobahnTester.cs | 0 .../ConformanceTests}/Autobahn/Executable.cs | 0 .../ConformanceTests}/Autobahn/Expectation.cs | 0 .../ConformanceTests}/Autobahn/ServerSpec.cs | 0 .../test/ConformanceTests}/Autobahn/Wstest.cs | 0 .../test/ConformanceTests}/AutobahnTests.cs | 0 .../test/ConformanceTests}/Helpers.cs | 0 .../test/ConformanceTests}/Http.config | 0 ...NetCore.WebSockets.ConformanceTests.csproj | 15 ++ .../SkipIfWsTestNotPresentAttribute.cs | 0 .../WebSockets/test/Directory.Build.props | 27 ++++ .../test/UnitTests}/BufferStream.cs | 0 .../test/UnitTests}/DuplexStream.cs | 0 .../test/UnitTests}/IWebHostPortExtensions.cs | 0 .../UnitTests}/KestrelWebSocketHelpers.cs | 0 ...crosoft.AspNetCore.WebSockets.Tests.csproj | 14 ++ .../test/UnitTests}/SendReceiveTests.cs | 0 .../UnitTests}/WebSocketMiddlewareTests.cs | 0 .../test/UnitTests}/WebSocketPair.cs | 0 src/WebSockets/.gitignore | 31 ---- src/WebSockets/Directory.Build.props | 20 --- src/WebSockets/Directory.Build.targets | 7 - src/WebSockets/NuGetPackageVerifier.json | 7 - src/WebSockets/README.md | 19 --- src/WebSockets/WebSockets.sln | 145 ------------------ src/WebSockets/build.cmd | 3 - src/WebSockets/build.sh | 7 - src/WebSockets/build/Key.snk | Bin 596 -> 0 bytes src/WebSockets/build/dependencies.props | 39 ----- src/WebSockets/build/repo.props | 18 --- src/WebSockets/build/repo.targets | 9 -- src/WebSockets/build/sources.props | 17 -- src/WebSockets/samples/EchoApp/EchoApp.csproj | 19 --- src/WebSockets/src/Directory.Build.props | 7 - src/WebSockets/test/Directory.Build.props | 22 --- ...pNetCore.WebSockets.ConformanceTest.csproj | 18 --- ...icrosoft.AspNetCore.WebSockets.Test.csproj | 21 --- src/WebSockets/version.props | 12 -- 86 files changed, 218 insertions(+), 435 deletions(-) create mode 100644 src/Middleware/Middleware.sln create mode 100644 src/Middleware/WebSockets/README.md rename src/{ => Middleware}/WebSockets/samples/AutobahnTestAppAspNet4/AutobahnTestAppAspNet4.csproj.aspnet4 (100%) rename src/{ => Middleware}/WebSockets/samples/AutobahnTestAppAspNet4/EchoSocket.ashx (100%) rename src/{ => Middleware}/WebSockets/samples/AutobahnTestAppAspNet4/EchoSocket.ashx.cs (100%) rename src/{ => Middleware}/WebSockets/samples/AutobahnTestAppAspNet4/Properties/AssemblyInfo.cs (100%) rename src/{ => Middleware}/WebSockets/samples/AutobahnTestAppAspNet4/Web.Debug.config (100%) rename src/{ => Middleware}/WebSockets/samples/AutobahnTestAppAspNet4/Web.Release.config (100%) rename src/{ => Middleware}/WebSockets/samples/AutobahnTestAppAspNet4/Web.config (100%) rename src/{ => Middleware}/WebSockets/samples/AutobahnTestAppAspNet4/packages.config (100%) rename src/{ => Middleware}/WebSockets/samples/AutobahnTestAppAspNet4/wstest-spec.json (100%) rename src/{ => Middleware}/WebSockets/samples/AutobahnTestAppHttpListener/App.config (100%) rename src/{ => Middleware}/WebSockets/samples/AutobahnTestAppHttpListener/AutobahnTestAppHttpListener.csproj.net461 (100%) rename src/{ => Middleware}/WebSockets/samples/AutobahnTestAppHttpListener/Program.cs (100%) rename src/{ => Middleware}/WebSockets/samples/AutobahnTestAppHttpListener/Properties/AssemblyInfo.cs (100%) create mode 100644 src/Middleware/WebSockets/samples/EchoApp/EchoApp.csproj rename src/{ => Middleware}/WebSockets/samples/EchoApp/Program.cs (100%) rename src/{ => Middleware}/WebSockets/samples/EchoApp/Properties/launchSettings.json (100%) rename src/{ => Middleware}/WebSockets/samples/EchoApp/Startup.cs (100%) rename src/{ => Middleware}/WebSockets/samples/EchoApp/wwwroot/index.html (100%) rename src/{ => Middleware}/WebSockets/samples/TestServer/App.config (100%) rename src/{ => Middleware}/WebSockets/samples/TestServer/Program.cs (100%) rename src/{ => Middleware}/WebSockets/samples/TestServer/Properties/AssemblyInfo.cs (100%) rename src/{ => Middleware}/WebSockets/samples/TestServer/TestServer.csproj (100%) rename src/{WebSockets/build => Middleware/WebSockets}/setup-wstest.ps1 (100%) rename src/{WebSockets/build => Middleware/WebSockets}/setup-wstest.sh (100%) mode change 100755 => 100644 rename src/{WebSockets/src/Microsoft.AspNetCore.WebSockets => Middleware/WebSockets/src}/ExtendedWebSocketAcceptContext.cs (100%) rename src/{WebSockets/src/Microsoft.AspNetCore.WebSockets => Middleware/WebSockets/src}/Internal/Constants.cs (100%) rename src/{WebSockets/src/Microsoft.AspNetCore.WebSockets => Middleware/WebSockets/src}/Internal/HandshakeHelpers.cs (100%) rename src/{WebSockets/src/Microsoft.AspNetCore.WebSockets => Middleware/WebSockets/src}/Microsoft.AspNetCore.WebSockets.csproj (54%) rename src/{WebSockets/src/Microsoft.AspNetCore.WebSockets => Middleware/WebSockets/src}/WebSocketMiddleware.cs (100%) rename src/{WebSockets/src/Microsoft.AspNetCore.WebSockets => Middleware/WebSockets/src}/WebSocketMiddlewareExtensions.cs (100%) rename src/{WebSockets/src/Microsoft.AspNetCore.WebSockets => Middleware/WebSockets/src}/WebSocketOptions.cs (100%) rename src/{WebSockets/src/Microsoft.AspNetCore.WebSockets => Middleware/WebSockets/src}/baseline.netcore.json (100%) rename src/{ => Middleware}/WebSockets/test/AutobahnTestApp/AutobahnTestApp.csproj (75%) rename src/{ => Middleware}/WebSockets/test/AutobahnTestApp/Program.cs (100%) rename src/{ => Middleware}/WebSockets/test/AutobahnTestApp/Properties/launchSettings.json (100%) rename src/{ => Middleware}/WebSockets/test/AutobahnTestApp/README.md (100%) rename src/{ => Middleware}/WebSockets/test/AutobahnTestApp/Startup.cs (100%) rename src/{ => Middleware}/WebSockets/test/AutobahnTestApp/TestResources/testCert.pfx (100%) rename src/{ => Middleware}/WebSockets/test/AutobahnTestApp/TestResources/testCert.txt (100%) rename src/{ => Middleware}/WebSockets/test/AutobahnTestApp/scripts/RunAutobahnTests.ps1 (100%) rename src/{ => Middleware}/WebSockets/test/AutobahnTestApp/scripts/autobahn.spec.json (100%) rename src/{WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest => Middleware/WebSockets/test/ConformanceTests}/Autobahn/AutobahnCaseResult.cs (100%) rename src/{WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest => Middleware/WebSockets/test/ConformanceTests}/Autobahn/AutobahnExpectations.cs (100%) rename src/{WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest => Middleware/WebSockets/test/ConformanceTests}/Autobahn/AutobahnResult.cs (100%) rename src/{WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest => Middleware/WebSockets/test/ConformanceTests}/Autobahn/AutobahnServerResult.cs (100%) rename src/{WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest => Middleware/WebSockets/test/ConformanceTests}/Autobahn/AutobahnSpec.cs (100%) rename src/{WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest => Middleware/WebSockets/test/ConformanceTests}/Autobahn/AutobahnTester.cs (100%) rename src/{WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest => Middleware/WebSockets/test/ConformanceTests}/Autobahn/Executable.cs (100%) rename src/{WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest => Middleware/WebSockets/test/ConformanceTests}/Autobahn/Expectation.cs (100%) rename src/{WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest => Middleware/WebSockets/test/ConformanceTests}/Autobahn/ServerSpec.cs (100%) rename src/{WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest => Middleware/WebSockets/test/ConformanceTests}/Autobahn/Wstest.cs (100%) rename src/{WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest => Middleware/WebSockets/test/ConformanceTests}/AutobahnTests.cs (100%) rename src/{WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest => Middleware/WebSockets/test/ConformanceTests}/Helpers.cs (100%) rename src/{WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest => Middleware/WebSockets/test/ConformanceTests}/Http.config (100%) create mode 100644 src/Middleware/WebSockets/test/ConformanceTests/Microsoft.AspNetCore.WebSockets.ConformanceTests.csproj rename src/{WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest => Middleware/WebSockets/test/ConformanceTests}/SkipIfWsTestNotPresentAttribute.cs (100%) create mode 100644 src/Middleware/WebSockets/test/Directory.Build.props rename src/{WebSockets/test/Microsoft.AspNetCore.WebSockets.Test => Middleware/WebSockets/test/UnitTests}/BufferStream.cs (100%) rename src/{WebSockets/test/Microsoft.AspNetCore.WebSockets.Test => Middleware/WebSockets/test/UnitTests}/DuplexStream.cs (100%) rename src/{WebSockets/test/Microsoft.AspNetCore.WebSockets.Test => Middleware/WebSockets/test/UnitTests}/IWebHostPortExtensions.cs (100%) rename src/{WebSockets/test/Microsoft.AspNetCore.WebSockets.Test => Middleware/WebSockets/test/UnitTests}/KestrelWebSocketHelpers.cs (100%) create mode 100644 src/Middleware/WebSockets/test/UnitTests/Microsoft.AspNetCore.WebSockets.Tests.csproj rename src/{WebSockets/test/Microsoft.AspNetCore.WebSockets.Test => Middleware/WebSockets/test/UnitTests}/SendReceiveTests.cs (100%) rename src/{WebSockets/test/Microsoft.AspNetCore.WebSockets.Test => Middleware/WebSockets/test/UnitTests}/WebSocketMiddlewareTests.cs (100%) rename src/{WebSockets/test/Microsoft.AspNetCore.WebSockets.Test => Middleware/WebSockets/test/UnitTests}/WebSocketPair.cs (100%) delete mode 100644 src/WebSockets/.gitignore delete mode 100644 src/WebSockets/Directory.Build.props delete mode 100644 src/WebSockets/Directory.Build.targets delete mode 100644 src/WebSockets/NuGetPackageVerifier.json delete mode 100644 src/WebSockets/README.md delete mode 100644 src/WebSockets/WebSockets.sln delete mode 100644 src/WebSockets/build.cmd delete mode 100755 src/WebSockets/build.sh delete mode 100644 src/WebSockets/build/Key.snk delete mode 100644 src/WebSockets/build/dependencies.props delete mode 100644 src/WebSockets/build/repo.props delete mode 100644 src/WebSockets/build/repo.targets delete mode 100644 src/WebSockets/build/sources.props delete mode 100644 src/WebSockets/samples/EchoApp/EchoApp.csproj delete mode 100644 src/WebSockets/src/Directory.Build.props delete mode 100644 src/WebSockets/test/Directory.Build.props delete mode 100644 src/WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest/Microsoft.AspNetCore.WebSockets.ConformanceTest.csproj delete mode 100644 src/WebSockets/test/Microsoft.AspNetCore.WebSockets.Test/Microsoft.AspNetCore.WebSockets.Test.csproj delete mode 100644 src/WebSockets/version.props 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..cc5ea2afc1 --- /dev/null +++ b/src/Middleware/WebSockets/samples/EchoApp/EchoApp.csproj @@ -0,0 +1,16 @@ + + + + netcoreapp2.1;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/WebSockets/src/Microsoft.AspNetCore.WebSockets/Microsoft.AspNetCore.WebSockets.csproj b/src/Middleware/WebSockets/src/Microsoft.AspNetCore.WebSockets.csproj similarity index 54% rename from src/WebSockets/src/Microsoft.AspNetCore.WebSockets/Microsoft.AspNetCore.WebSockets.csproj rename to src/Middleware/WebSockets/src/Microsoft.AspNetCore.WebSockets.csproj index c5c5c8fbfb..5ff6bed15f 100644 --- a/src/WebSockets/src/Microsoft.AspNetCore.WebSockets/Microsoft.AspNetCore.WebSockets.csproj +++ b/src/Middleware/WebSockets/src/Microsoft.AspNetCore.WebSockets.csproj @@ -10,9 +10,9 @@ - - - + + + 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/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 75% rename from src/WebSockets/test/AutobahnTestApp/AutobahnTestApp.csproj rename to src/Middleware/WebSockets/test/AutobahnTestApp/AutobahnTestApp.csproj index 175f724c74..5cd27d8a7e 100644 --- a/src/WebSockets/test/AutobahnTestApp/AutobahnTestApp.csproj +++ b/src/Middleware/WebSockets/test/AutobahnTestApp/AutobahnTestApp.csproj @@ -3,6 +3,7 @@ netcoreapp2.1 $(TargetFrameworks);netcoreapp2.0 + true @@ -10,21 +11,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..76281207ee --- /dev/null +++ b/src/Middleware/WebSockets/test/ConformanceTests/Microsoft.AspNetCore.WebSockets.ConformanceTests.csproj @@ -0,0 +1,15 @@ + + + + netcoreapp2.1 + $(TargetFrameworks);netcoreapp2.0 + + + + + + + + + + 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..3e2de2026d --- /dev/null +++ b/src/Middleware/WebSockets/test/Directory.Build.props @@ -0,0 +1,27 @@ + + + + + + + true + + + + + + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 0.5.1 + 2.1.2 + 2.1.2 + 2.1.1 + + + 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/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 6c76a5608f..0000000000 --- a/src/WebSockets/Directory.Build.props +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - Microsoft ASP.NET Core - https://github.com/aspnet/WebSockets - git - $(MSBuildThisFileDirectory) - $(MSBuildThisFileDirectory)build\Key.snk - true - true - true - - diff --git a/src/WebSockets/Directory.Build.targets b/src/WebSockets/Directory.Build.targets deleted file mode 100644 index 53b3f6e1da..0000000000 --- a/src/WebSockets/Directory.Build.targets +++ /dev/null @@ -1,7 +0,0 @@ - - - $(MicrosoftNETCoreApp20PackageVersion) - $(MicrosoftNETCoreApp21PackageVersion) - $(NETStandardLibrary20PackageVersion) - - 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 e10e4889c125d3120cd9e81582243d70f7cbb806..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098=Iw=HCsnz~#iVhm& zj%TU(_THUee?3yHBjk$37ysB?i5#7WD$={H zV4B!OxRPrb|8)HPg~A}8P>^=#y<)56#=E&NzcjOtPK~<4n6GHt=K$ro*T(lhby_@U zEk(hLzk1H)0yXj{A_5>fk-TgNoP|q6(tP2xo8zt8i%212CWM#AeCd?`hS|4~L({h~Moo(~vy&3Z z1uI}`fd^*>o=rwbAGymj6RM^pZm(*Kfhs+Y1#`-2JPWZMK8@;ZWCk2+9bX4YP);~fj-BU*R zQPvWv$89!{Rl9wM+zR>_TSkn^voYxA?2G iKnV#iZ6Ah`K>b=@=IjYJXrxL124zR(38)nxe+&q_$QXwJ diff --git a/src/WebSockets/build/dependencies.props b/src/WebSockets/build/dependencies.props deleted file mode 100644 index 6d1c938c0c..0000000000 --- a/src/WebSockets/build/dependencies.props +++ /dev/null @@ -1,39 +0,0 @@ - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - - - - - 2.1.3-rtm-15802 - 2.0.0 - 2.1.2 - 15.6.1 - 2.0.3 - 4.5.1 - 2.3.1 - 2.4.0-beta.1.build3945 - - - - - - - - 2.1.1 - 2.1.1 - 2.1.1 - 2.1.1 - 2.1.1 - 0.5.1 - 2.1.2 - 2.1.2 - 2.1.1 - 2.1.0 - 2.1.1 - 2.1.1 - 2.1.1 - 2.1.1 - 2.1.1 - - \ No newline at end of file diff --git a/src/WebSockets/build/repo.props b/src/WebSockets/build/repo.props deleted file mode 100644 index de99df697a..0000000000 --- a/src/WebSockets/build/repo.props +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - Internal.AspNetCore.Universe.Lineup - 2.1.0-rc1-* - https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json - - - - - - - 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/build/sources.props b/src/WebSockets/build/sources.props deleted file mode 100644 index 9215df9751..0000000000 --- a/src/WebSockets/build/sources.props +++ /dev/null @@ -1,17 +0,0 @@ - - - - - $(DotNetRestoreSources) - - $(RestoreSources); - https://dotnet.myget.org/F/dotnet-core/api/v3/index.json; - https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json; - https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json; - - - $(RestoreSources); - https://api.nuget.org/v3/index.json; - - - diff --git a/src/WebSockets/samples/EchoApp/EchoApp.csproj b/src/WebSockets/samples/EchoApp/EchoApp.csproj deleted file mode 100644 index f5696ccf03..0000000000 --- a/src/WebSockets/samples/EchoApp/EchoApp.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - netcoreapp2.1;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/test/Directory.Build.props b/src/WebSockets/test/Directory.Build.props deleted file mode 100644 index be781a6b15..0000000000 --- a/src/WebSockets/test/Directory.Build.props +++ /dev/null @@ -1,22 +0,0 @@ - - - - - netcoreapp2.1 - $(DeveloperBuildTestTfms) - netcoreapp2.1;netcoreapp2.0 - $(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 79e3839b12..0000000000 --- a/src/WebSockets/test/Microsoft.AspNetCore.WebSockets.ConformanceTest/Microsoft.AspNetCore.WebSockets.ConformanceTest.csproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - netcoreapp2.1 - $(TargetFrameworks);netcoreapp2.0 - - - - - - - - - - - - - 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 c906aa0f91..0000000000 --- a/src/WebSockets/test/Microsoft.AspNetCore.WebSockets.Test/Microsoft.AspNetCore.WebSockets.Test.csproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - $(StandardTestTfms) - - - - - - - - - - - - - - - - - diff --git a/src/WebSockets/version.props b/src/WebSockets/version.props deleted file mode 100644 index 669c874829..0000000000 --- a/src/WebSockets/version.props +++ /dev/null @@ -1,12 +0,0 @@ - - - 2.1.1 - rtm - $(VersionPrefix) - $(VersionPrefix)-$(VersionSuffix)-final - t000 - a- - $(FeatureBranchVersionPrefix)$(VersionSuffix)-$([System.Text.RegularExpressions.Regex]::Replace('$(FeatureBranchVersionSuffix)', '[^\w-]', '-')) - $(VersionSuffix)-$(BuildNumber) - - From 32622d1a0afdd4387e89d454c555a85729451933 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Fri, 9 Nov 2018 13:06:34 -0800 Subject: [PATCH 461/471] Remove the JsonPatch git submodule --- .gitmodules | 4 ---- modules/JsonPatch | 1 - 2 files changed, 5 deletions(-) delete mode 160000 modules/JsonPatch diff --git a/.gitmodules b/.gitmodules index 76458daf89..5eaf7683cc 100644 --- a/.gitmodules +++ b/.gitmodules @@ -66,10 +66,6 @@ path = modules/JavaScriptServices url = https://github.com/aspnet/JavaScriptServices.git branch = release/2.1 -[submodule "modules/JsonPatch"] - path = modules/JsonPatch - url = https://github.com/aspnet/JsonPatch.git - branch = release/2.1 [submodule "modules/KestrelHttpServer"] path = modules/KestrelHttpServer url = https://github.com/aspnet/KestrelHttpServer.git diff --git a/modules/JsonPatch b/modules/JsonPatch deleted file mode 160000 index 218064c300..0000000000 --- a/modules/JsonPatch +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 218064c300a7cf5a76669e133340a98a0c5517a5 From 979f72a839dcdc96f74326e2e7086efb9811231d Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Fri, 9 Nov 2018 13:08:02 -0800 Subject: [PATCH 462/471] Update PR validation to run a real build --- .azure/pipelines/fast-pr-validation.yml | 31 ++++++++----------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/.azure/pipelines/fast-pr-validation.yml b/.azure/pipelines/fast-pr-validation.yml index c88e0a520a..b634a55889 100644 --- a/.azure/pipelines/fast-pr-validation.yml +++ b/.azure/pipelines/fast-pr-validation.yml @@ -3,28 +3,17 @@ trigger: - release/* jobs: -- template: project-ci.yml +- template: jobs/default-build.yml parameters: - buildArgs: "/t:FastCheck" -- 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' + jobName: PR_FastCheck + jobDisplayName: Fast Check + agentOs: Windows + buildArgs: "/p:FastCheck" +- template: jobs/default-build.yml + parameters: + jobName: Windows_Build + jobDisplayName: "Build: Windows" + agentOs: Windows - template: jobs/iisintegration-job.yml parameters: variables: From fd5156e88b88d3736c08ce3305fe9212d227edfc Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Fri, 9 Nov 2018 14:05:43 -0800 Subject: [PATCH 463/471] Updating BuildTools from 2.1.3-rtm-15842 to 2.1.3-rtm-15843 [auto-updated: buildtools] --- korebuild-lock.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 08f95645f0..7e1e575c87 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.3-rtm-15842 -commithash:b631cb7a2b982cbbfc4d2e02be66c6612f9e3afd +version:2.1.3-rtm-15843 +commithash:651ca3c2d8f764b0b36be231cf45f19b1dd4bd2c From 1c8df01d09984b528b79747f1a5f8faf36cc4df4 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Fri, 9 Nov 2018 14:09:09 -0800 Subject: [PATCH 464/471] Update PR validation to fix the FastCheck config and IIS tests --- .azure/pipelines/fast-pr-validation.yml | 5 ++++- .azure/pipelines/jobs/default-build.yml | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.azure/pipelines/fast-pr-validation.yml b/.azure/pipelines/fast-pr-validation.yml index b634a55889..5449521778 100644 --- a/.azure/pipelines/fast-pr-validation.yml +++ b/.azure/pipelines/fast-pr-validation.yml @@ -8,12 +8,15 @@ jobs: jobName: PR_FastCheck jobDisplayName: Fast Check agentOs: Windows - buildArgs: "/p:FastCheck" + buildArgs: "/t:FastCheck" - 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: variables: diff --git a/.azure/pipelines/jobs/default-build.yml b/.azure/pipelines/jobs/default-build.yml index d39a7e1e22..065e4d1770 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: From dfacde4deee8520bd3c5c165863f426a726e2bb0 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Fri, 9 Nov 2018 14:23:04 -0800 Subject: [PATCH 465/471] Fix /t:FastCheck for local-projects --- build/repo.targets | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/build/repo.targets b/build/repo.targets index 0c1125bd51..9e7e303327 100644 --- a/build/repo.targets +++ b/build/repo.targets @@ -250,7 +250,7 @@ - + + + + $(BuildProperties);DesignTimeBuild=true + + + + DependsOnTargets="_SetDesignTimeBuild;ComputeGraph;VerifyPackageArtifactConfig;VerifyAllReposHaveNuGetPackageVerifier" /> From 7338d749d05d885bba924c432ec03699f531dece Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Fri, 9 Nov 2018 14:52:25 -0800 Subject: [PATCH 466/471] Updating BuildTools from 2.1.3-rtm-15843 to 2.1.3-rtm-15844 [auto-updated: buildtools] --- korebuild-lock.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 7e1e575c87..7d2ac1cf8c 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.3-rtm-15843 -commithash:651ca3c2d8f764b0b36be231cf45f19b1dd4bd2c +version:2.1.3-rtm-15844 +commithash:8d031079e81ea30446712d48f7e8e9539fb92907 From 1ab08d70ef462dddcf71f3b419493b10db081eae Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Fri, 9 Nov 2018 16:17:15 -0800 Subject: [PATCH 467/471] Reorganize source code in preparation to move into aspnet/AspNetCore Prior to reorganization, this source code was found in https://github.com/aspnet/HtmlAbstractions/tree/252ae0c434d93f5bfaf949c35edb9ef59730d0a3 --- .appveyor.yml | 17 - .gitattributes | 51 -- .github/ISSUE_TEMPLATE.md | 3 - .gitignore | 40 -- .travis.yml | 27 - CONTRIBUTING.md | 4 - Directory.Build.props | 24 - Directory.Build.targets | 7 - HtmlAbstractions.sln | 90 --- LICENSE.txt | 14 - NuGet.config | 7 - NuGetPackageVerifier.json | 7 - README.md | 9 - build.cmd | 2 - build.sh | 8 - build/Key.snk | Bin 596 -> 0 bytes build/dependencies.props | 28 - build/repo.props | 15 - build/sources.props | 17 - korebuild-lock.txt | 2 - korebuild.json | 4 - run.cmd | 2 - run.ps1 | 196 ------ run.sh | 231 ------- .../Abstractions/src}/HtmlContentBuilder.cs | 0 .../src}/HtmlContentBuilderExtensions.cs | 0 .../src}/HtmlFormattableString.cs | 0 .../Abstractions/src}/HtmlString.cs | 0 .../Abstractions/src}/IHtmlContent.cs | 0 .../Abstractions/src}/IHtmlContentBuilder.cs | 0 .../src}/IHtmlContentContainer.cs | 0 ...rosoft.AspNetCore.Html.Abstractions.csproj | 4 +- .../src/Properties/AssemblyInfo.cs | 8 + .../Abstractions/src}/baseline.netcore.json | 0 .../test}/HtmlContentBuilderExtensionsTest.cs | 0 .../test}/HtmlContentBuilderTest.cs | 0 .../test}/HtmlFormattableStringTest.cs | 0 ....AspNetCore.Html.Abstractions.Tests.csproj | 12 + .../Properties/AssemblyInfo.cs | 8 - .../EncoderServiceCollectionExtensions.cs | 83 --- .../Microsoft.Extensions.WebEncoders.csproj | 19 - .../Testing/HtmlTestEncoder.cs | 104 ---- .../Testing/JavaScriptTestEncoder.cs | 104 ---- .../Testing/UrlTestEncoder.cs | 104 ---- .../WebEncoderOptions.cs | 21 - .../baseline.netcore.json | 564 ------------------ test/Directory.Build.props | 17 - ...t.AspNetCore.Html.Abstractions.Test.csproj | 12 - ...EncoderServiceCollectionExtensionsTests.cs | 90 --- .../HtmlTestEncoderTest.cs | 26 - ...rosoft.Extensions.WebEncoders.Tests.csproj | 15 - version.props | 12 - 52 files changed, 22 insertions(+), 1986 deletions(-) delete mode 100644 .appveyor.yml delete mode 100644 .gitattributes delete mode 100644 .github/ISSUE_TEMPLATE.md delete mode 100644 .gitignore delete mode 100644 .travis.yml delete mode 100644 CONTRIBUTING.md delete mode 100644 Directory.Build.props delete mode 100644 Directory.Build.targets delete mode 100644 HtmlAbstractions.sln delete mode 100644 LICENSE.txt delete mode 100644 NuGet.config delete mode 100644 NuGetPackageVerifier.json delete mode 100644 README.md delete mode 100644 build.cmd delete mode 100755 build.sh delete mode 100644 build/Key.snk delete mode 100644 build/dependencies.props delete mode 100644 build/repo.props delete mode 100644 build/sources.props delete mode 100644 korebuild-lock.txt delete mode 100644 korebuild.json delete mode 100644 run.cmd delete mode 100644 run.ps1 delete mode 100755 run.sh rename src/{Microsoft.AspNetCore.Html.Abstractions => Html/Abstractions/src}/HtmlContentBuilder.cs (100%) rename src/{Microsoft.AspNetCore.Html.Abstractions => Html/Abstractions/src}/HtmlContentBuilderExtensions.cs (100%) rename src/{Microsoft.AspNetCore.Html.Abstractions => Html/Abstractions/src}/HtmlFormattableString.cs (100%) rename src/{Microsoft.AspNetCore.Html.Abstractions => Html/Abstractions/src}/HtmlString.cs (100%) rename src/{Microsoft.AspNetCore.Html.Abstractions => Html/Abstractions/src}/IHtmlContent.cs (100%) rename src/{Microsoft.AspNetCore.Html.Abstractions => Html/Abstractions/src}/IHtmlContentBuilder.cs (100%) rename src/{Microsoft.AspNetCore.Html.Abstractions => Html/Abstractions/src}/IHtmlContentContainer.cs (100%) rename src/{Microsoft.AspNetCore.Html.Abstractions => Html/Abstractions/src}/Microsoft.AspNetCore.Html.Abstractions.csproj (74%) mode change 100755 => 100644 create mode 100644 src/Html/Abstractions/src/Properties/AssemblyInfo.cs rename src/{Microsoft.AspNetCore.Html.Abstractions => Html/Abstractions/src}/baseline.netcore.json (100%) rename {test/Microsoft.AspNetCore.Html.Abstractions.Test => src/Html/Abstractions/test}/HtmlContentBuilderExtensionsTest.cs (100%) rename {test/Microsoft.AspNetCore.Html.Abstractions.Test => src/Html/Abstractions/test}/HtmlContentBuilderTest.cs (100%) rename {test/Microsoft.AspNetCore.Html.Abstractions.Test => src/Html/Abstractions/test}/HtmlFormattableStringTest.cs (100%) create mode 100644 src/Html/Abstractions/test/Microsoft.AspNetCore.Html.Abstractions.Tests.csproj delete mode 100644 src/Microsoft.AspNetCore.Html.Abstractions/Properties/AssemblyInfo.cs delete mode 100644 src/Microsoft.Extensions.WebEncoders/EncoderServiceCollectionExtensions.cs delete mode 100755 src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.csproj delete mode 100644 src/Microsoft.Extensions.WebEncoders/Testing/HtmlTestEncoder.cs delete mode 100644 src/Microsoft.Extensions.WebEncoders/Testing/JavaScriptTestEncoder.cs delete mode 100644 src/Microsoft.Extensions.WebEncoders/Testing/UrlTestEncoder.cs delete mode 100644 src/Microsoft.Extensions.WebEncoders/WebEncoderOptions.cs delete mode 100644 src/Microsoft.Extensions.WebEncoders/baseline.netcore.json delete mode 100644 test/Directory.Build.props delete mode 100755 test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.csproj delete mode 100644 test/Microsoft.Extensions.WebEncoders.Tests/EncoderServiceCollectionExtensionsTests.cs delete mode 100644 test/Microsoft.Extensions.WebEncoders.Tests/HtmlTestEncoderTest.cs delete mode 100755 test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj delete mode 100644 version.props diff --git a/.appveyor.yml b/.appveyor.yml deleted file mode 100644 index 4eea96ab69..0000000000 --- a/.appveyor.yml +++ /dev/null @@ -1,17 +0,0 @@ -init: -- git config --global core.autocrlf true -branches: - only: - - dev - - /^release\/.*$/ - - /^(.*\/)?ci-.*$/ -build_script: -- ps: .\run.ps1 default-build -clone_depth: 1 -environment: - global: - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true - DOTNET_CLI_TELEMETRY_OPTOUT: 1 -test: 'off' -deploy: 'off' -os: Visual Studio 2017 diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 66abdf279e..0000000000 --- a/.gitattributes +++ /dev/null @@ -1,51 +0,0 @@ -*.doc diff=astextplain -*.DOC diff=astextplain -*.docx diff=astextplain -*.DOCX diff=astextplain -*.dot diff=astextplain -*.DOT diff=astextplain -*.pdf diff=astextplain -*.PDF diff=astextplain -*.rtf diff=astextplain -*.RTF diff=astextplain - -*.jpg binary -*.png binary -*.gif binary - -*.cs text=auto diff=csharp -*.vb text=auto -*.resx text=auto -*.c text=auto -*.cpp text=auto -*.cxx text=auto -*.h text=auto -*.hxx text=auto -*.py text=auto -*.rb text=auto -*.java text=auto -*.html text=auto -*.htm text=auto -*.css text=auto -*.scss text=auto -*.sass text=auto -*.less text=auto -*.js text=auto -*.lisp text=auto -*.clj text=auto -*.sql text=auto -*.php text=auto -*.lua text=auto -*.m text=auto -*.asm text=auto -*.erl text=auto -*.fs text=auto -*.fsx text=auto -*.hs text=auto - -*.csproj text=auto -*.vbproj text=auto -*.fsproj text=auto -*.dbproj text=auto -*.sln text=auto eol=crlf -*.sh eol=lf \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index 101a084f0a..0000000000 --- a/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,3 +0,0 @@ -THIS ISSUE TRACKER IS CLOSED - please log new issues here: https://github.com/aspnet/Home/issues - -For information about this change, see https://github.com/aspnet/Announcements/issues/283 diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 6da3c6a3e9..0000000000 --- a/.gitignore +++ /dev/null @@ -1,40 +0,0 @@ -[Oo]bj/ -[Bb]in/ -TestResults/ -.nuget/ -*.sln.ide/ -_ReSharper.*/ -packages/ -artifacts/ -PublishProfiles/ -.vs/ -bower_components/ -node_modules/ -**/wwwroot/lib/ -debugSettings.json -project.lock.json -*.user -*.suo -*.cache -*.docstates -_ReSharper.* -nuget.exe -*net45.csproj -*net451.csproj -*k10.csproj -*.psess -*.vsp -*.pidb -*.userprefs -*DS_Store -*.ncrunchsolution -*.*sdf -*.ipch -.settings -*.sln.ide -node_modules -**/[Cc]ompiler/[Rr]esources/**/*.js -*launchSettings.json -.build/ -.testPublish/ -global.json diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 64bdbb4441..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,27 +0,0 @@ -language: csharp -sudo: false -dist: trusty -env: - global: - - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true - - DOTNET_CLI_TELEMETRY_OPTOUT: 1 -mono: none -os: -- linux -- osx -osx_image: xcode8.2 -addons: - apt: - packages: - - libunwind8 -branches: - only: - - dev - - /^release\/.*$/ - - /^(.*\/)?ci-.*$/ -before_install: -- if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; ln -s - /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib - /usr/local/lib/; fi -script: -- ./build.sh diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 64ff041d5c..0000000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,4 +0,0 @@ -Contributing -====== - -Information on contributing to this repo is in the [Contributing Guide](https://github.com/aspnet/Home/blob/dev/CONTRIBUTING.md) in the Home repo. diff --git a/Directory.Build.props b/Directory.Build.props deleted file mode 100644 index b7176c688d..0000000000 --- a/Directory.Build.props +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - https://github.com/aspnet/HtmlAbstractions - git - $(MSBuildThisFileDirectory) - $(MSBuildThisFileDirectory)build\Key.snk - true - true - true - - - - - - - diff --git a/Directory.Build.targets b/Directory.Build.targets deleted file mode 100644 index 53b3f6e1da..0000000000 --- a/Directory.Build.targets +++ /dev/null @@ -1,7 +0,0 @@ - - - $(MicrosoftNETCoreApp20PackageVersion) - $(MicrosoftNETCoreApp21PackageVersion) - $(NETStandardLibrary20PackageVersion) - - diff --git a/HtmlAbstractions.sln b/HtmlAbstractions.sln deleted file mode 100644 index 5ee1cb4612..0000000000 --- a/HtmlAbstractions.sln +++ /dev/null @@ -1,90 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26127.0 -MinimumVisualStudioVersion = 15.0.26730.03 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A5A15F1C-885A-452A-A731-B0173DDBD913}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{F31FF137-390C-49BF-A3BD-7C6ED3597C21}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.Html.Abstractions", "src\Microsoft.AspNetCore.Html.Abstractions\Microsoft.AspNetCore.Html.Abstractions.csproj", "{68A28E4A-3ADE-4187-9625-4FF185887CB3}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.Html.Abstractions.Test", "test\Microsoft.AspNetCore.Html.Abstractions.Test\Microsoft.AspNetCore.Html.Abstractions.Test.csproj", "{2D187B88-94BD-4A39-AC97-F8F8B9363301}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B4962A29-BE69-4A18-9B4F-B803EEE31EAA}" - ProjectSection(SolutionItems) = preProject - NuGetPackageVerifier.json = NuGetPackageVerifier.json - EndProjectSection -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Extensions.WebEncoders", "src\Microsoft.Extensions.WebEncoders\Microsoft.Extensions.WebEncoders.csproj", "{DD2CE416-765E-4000-A03E-C2FF165DA1B6}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Extensions.WebEncoders.Tests", "test\Microsoft.Extensions.WebEncoders.Tests\Microsoft.Extensions.WebEncoders.Tests.csproj", "{7AE2731D-43CD-4CF8-850A-4914DE2CE930}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|Mixed Platforms = Debug|Mixed Platforms - Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU - Release|Mixed Platforms = Release|Mixed Platforms - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {68A28E4A-3ADE-4187-9625-4FF185887CB3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {68A28E4A-3ADE-4187-9625-4FF185887CB3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {68A28E4A-3ADE-4187-9625-4FF185887CB3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {68A28E4A-3ADE-4187-9625-4FF185887CB3}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {68A28E4A-3ADE-4187-9625-4FF185887CB3}.Debug|x86.ActiveCfg = Debug|Any CPU - {68A28E4A-3ADE-4187-9625-4FF185887CB3}.Debug|x86.Build.0 = Debug|Any CPU - {68A28E4A-3ADE-4187-9625-4FF185887CB3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {68A28E4A-3ADE-4187-9625-4FF185887CB3}.Release|Any CPU.Build.0 = Release|Any CPU - {68A28E4A-3ADE-4187-9625-4FF185887CB3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {68A28E4A-3ADE-4187-9625-4FF185887CB3}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {68A28E4A-3ADE-4187-9625-4FF185887CB3}.Release|x86.ActiveCfg = Release|Any CPU - {68A28E4A-3ADE-4187-9625-4FF185887CB3}.Release|x86.Build.0 = Release|Any CPU - {2D187B88-94BD-4A39-AC97-F8F8B9363301}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2D187B88-94BD-4A39-AC97-F8F8B9363301}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2D187B88-94BD-4A39-AC97-F8F8B9363301}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {2D187B88-94BD-4A39-AC97-F8F8B9363301}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {2D187B88-94BD-4A39-AC97-F8F8B9363301}.Debug|x86.ActiveCfg = Debug|Any CPU - {2D187B88-94BD-4A39-AC97-F8F8B9363301}.Debug|x86.Build.0 = Debug|Any CPU - {2D187B88-94BD-4A39-AC97-F8F8B9363301}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2D187B88-94BD-4A39-AC97-F8F8B9363301}.Release|Any CPU.Build.0 = Release|Any CPU - {2D187B88-94BD-4A39-AC97-F8F8B9363301}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {2D187B88-94BD-4A39-AC97-F8F8B9363301}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {2D187B88-94BD-4A39-AC97-F8F8B9363301}.Release|x86.ActiveCfg = Release|Any CPU - {2D187B88-94BD-4A39-AC97-F8F8B9363301}.Release|x86.Build.0 = Release|Any CPU - {DD2CE416-765E-4000-A03E-C2FF165DA1B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DD2CE416-765E-4000-A03E-C2FF165DA1B6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DD2CE416-765E-4000-A03E-C2FF165DA1B6}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {DD2CE416-765E-4000-A03E-C2FF165DA1B6}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {DD2CE416-765E-4000-A03E-C2FF165DA1B6}.Debug|x86.ActiveCfg = Debug|Any CPU - {DD2CE416-765E-4000-A03E-C2FF165DA1B6}.Debug|x86.Build.0 = Debug|Any CPU - {DD2CE416-765E-4000-A03E-C2FF165DA1B6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DD2CE416-765E-4000-A03E-C2FF165DA1B6}.Release|Any CPU.Build.0 = Release|Any CPU - {DD2CE416-765E-4000-A03E-C2FF165DA1B6}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {DD2CE416-765E-4000-A03E-C2FF165DA1B6}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {DD2CE416-765E-4000-A03E-C2FF165DA1B6}.Release|x86.ActiveCfg = Release|Any CPU - {DD2CE416-765E-4000-A03E-C2FF165DA1B6}.Release|x86.Build.0 = Release|Any CPU - {7AE2731D-43CD-4CF8-850A-4914DE2CE930}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7AE2731D-43CD-4CF8-850A-4914DE2CE930}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7AE2731D-43CD-4CF8-850A-4914DE2CE930}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {7AE2731D-43CD-4CF8-850A-4914DE2CE930}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {7AE2731D-43CD-4CF8-850A-4914DE2CE930}.Debug|x86.ActiveCfg = Debug|Any CPU - {7AE2731D-43CD-4CF8-850A-4914DE2CE930}.Debug|x86.Build.0 = Debug|Any CPU - {7AE2731D-43CD-4CF8-850A-4914DE2CE930}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7AE2731D-43CD-4CF8-850A-4914DE2CE930}.Release|Any CPU.Build.0 = Release|Any CPU - {7AE2731D-43CD-4CF8-850A-4914DE2CE930}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {7AE2731D-43CD-4CF8-850A-4914DE2CE930}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {7AE2731D-43CD-4CF8-850A-4914DE2CE930}.Release|x86.ActiveCfg = Release|Any CPU - {7AE2731D-43CD-4CF8-850A-4914DE2CE930}.Release|x86.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {68A28E4A-3ADE-4187-9625-4FF185887CB3} = {A5A15F1C-885A-452A-A731-B0173DDBD913} - {2D187B88-94BD-4A39-AC97-F8F8B9363301} = {F31FF137-390C-49BF-A3BD-7C6ED3597C21} - {DD2CE416-765E-4000-A03E-C2FF165DA1B6} = {A5A15F1C-885A-452A-A731-B0173DDBD913} - {7AE2731D-43CD-4CF8-850A-4914DE2CE930} = {F31FF137-390C-49BF-A3BD-7C6ED3597C21} - EndGlobalSection -EndGlobal diff --git a/LICENSE.txt b/LICENSE.txt deleted file mode 100644 index 7b2956ecee..0000000000 --- a/LICENSE.txt +++ /dev/null @@ -1,14 +0,0 @@ -Copyright (c) .NET Foundation and Contributors - -All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); you may not use -this file except in compliance with the License. You may obtain a copy of the -License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software distributed -under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -CONDITIONS OF ANY KIND, either express or implied. See the License for the -specific language governing permissions and limitations under the License. diff --git a/NuGet.config b/NuGet.config deleted file mode 100644 index e32bddfd51..0000000000 --- a/NuGet.config +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/NuGetPackageVerifier.json b/NuGetPackageVerifier.json deleted file mode 100644 index b153ab1515..0000000000 --- a/NuGetPackageVerifier.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "Default": { - "rules": [ - "DefaultCompositeRule" - ] - } -} \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index a1e3579e7a..0000000000 --- a/README.md +++ /dev/null @@ -1,9 +0,0 @@ -HtmlAbstractions -========== -AppVeyor: [![AppVeyor](https://ci.appveyor.com/api/projects/status/cu9y78vsdp19e5on/branch/dev?svg=true)](https://ci.appveyor.com/project/aspnetci/htmlabstractions/branch/dev) - -Travis: [![Travis](https://travis-ci.org/aspnet/HtmlAbstractions.svg?branch=dev)](https://travis-ci.org/aspnet/HtmlAbstractions) - -HTML abstractions used for building HTML content, including types such as `HtmlString` and `IHtmlContent`. - -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. diff --git a/build.cmd b/build.cmd deleted file mode 100644 index c0050bda12..0000000000 --- a/build.cmd +++ /dev/null @@ -1,2 +0,0 @@ -@ECHO OFF -PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0run.ps1' default-build %*; exit $LASTEXITCODE" diff --git a/build.sh b/build.sh deleted file mode 100755 index 98a4b22765..0000000000 --- a/build.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -# Call "sync" between "chmod" and execution to prevent "text file busy" error in Docker (aufs) -chmod +x "$DIR/run.sh"; sync -"$DIR/run.sh" default-build "$@" diff --git a/build/Key.snk b/build/Key.snk deleted file mode 100644 index e10e4889c125d3120cd9e81582243d70f7cbb806..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098=Iw=HCsnz~#iVhm& zj%TU(_THUee?3yHBjk$37ysB?i5#7WD$={H zV4B!OxRPrb|8)HPg~A}8P>^=#y<)56#=E&NzcjOtPK~<4n6GHt=K$ro*T(lhby_@U zEk(hLzk1H)0yXj{A_5>fk-TgNoP|q6(tP2xo8zt8i%212CWM#AeCd?`hS|4~L({h~Moo(~vy&3Z z1uI}`fd^*>o=rwbAGymj6RM^pZm(*Kfhs+Y1#`-2JPWZMK8@;ZWCk2+9bX4YP);~fj-BU*R zQPvWv$89!{Rl9wM+zR>_TSkn^voYxA?2G iKnV#iZ6Ah`K>b=@=IjYJXrxL124zR(38)nxe+&q_$QXwJ diff --git a/build/dependencies.props b/build/dependencies.props deleted file mode 100644 index 3c314a3476..0000000000 --- a/build/dependencies.props +++ /dev/null @@ -1,28 +0,0 @@ - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - - - - - 2.1.3-rtm-15802 - 2.0.0 - 2.1.2 - 15.6.1 - 2.0.3 - 4.5.0 - 2.3.1 - 2.4.0-beta.1.build3945 - - - - - - - - 2.1.0 - 2.1.1 - 2.1.1 - 2.1.1 - - \ No newline at end of file diff --git a/build/repo.props b/build/repo.props deleted file mode 100644 index dab1601c88..0000000000 --- a/build/repo.props +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - Internal.AspNetCore.Universe.Lineup - 2.1.0-rc1-* - https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json - - - - - - - diff --git a/build/sources.props b/build/sources.props deleted file mode 100644 index 9215df9751..0000000000 --- a/build/sources.props +++ /dev/null @@ -1,17 +0,0 @@ - - - - - $(DotNetRestoreSources) - - $(RestoreSources); - https://dotnet.myget.org/F/dotnet-core/api/v3/index.json; - https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json; - https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json; - - - $(RestoreSources); - https://api.nuget.org/v3/index.json; - - - diff --git a/korebuild-lock.txt b/korebuild-lock.txt deleted file mode 100644 index 251c227c83..0000000000 --- a/korebuild-lock.txt +++ /dev/null @@ -1,2 +0,0 @@ -version:2.1.3-rtm-15802 -commithash:a7c08b45b440a7d2058a0aa1eaa3eb6ba811976a diff --git a/korebuild.json b/korebuild.json deleted file mode 100644 index 678d8bb948..0000000000 --- a/korebuild.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/release/2.1/tools/korebuild.schema.json", - "channel": "release/2.1" -} diff --git a/run.cmd b/run.cmd deleted file mode 100644 index d52d5c7e68..0000000000 --- a/run.cmd +++ /dev/null @@ -1,2 +0,0 @@ -@ECHO OFF -PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0run.ps1' %*; exit $LASTEXITCODE" diff --git a/run.ps1 b/run.ps1 deleted file mode 100644 index 27dcf848f8..0000000000 --- a/run.ps1 +++ /dev/null @@ -1,196 +0,0 @@ -#!/usr/bin/env powershell -#requires -version 4 - -<# -.SYNOPSIS -Executes KoreBuild commands. - -.DESCRIPTION -Downloads korebuild if required. Then executes the KoreBuild command. To see available commands, execute with `-Command help`. - -.PARAMETER Command -The KoreBuild command to run. - -.PARAMETER Path -The folder to build. Defaults to the folder containing this script. - -.PARAMETER Channel -The channel of KoreBuild to download. Overrides the value from the config file. - -.PARAMETER DotNetHome -The directory where .NET Core tools will be stored. - -.PARAMETER ToolsSource -The base url where build tools can be downloaded. Overrides the value from the config file. - -.PARAMETER Update -Updates KoreBuild to the latest version even if a lock file is present. - -.PARAMETER ConfigFile -The path to the configuration file that stores values. Defaults to korebuild.json. - -.PARAMETER ToolsSourceSuffix -The Suffix to append to the end of the ToolsSource. Useful for query strings in blob stores. - -.PARAMETER Arguments -Arguments to be passed to the command - -.NOTES -This function will create a file $PSScriptRoot/korebuild-lock.txt. This lock file can be committed to source, but does not have to be. -When the lockfile is not present, KoreBuild will create one using latest available version from $Channel. - -The $ConfigFile is expected to be an JSON file. It is optional, and the configuration values in it are optional as well. Any options set -in the file are overridden by command line parameters. - -.EXAMPLE -Example config file: -```json -{ - "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/dev/tools/korebuild.schema.json", - "channel": "dev", - "toolsSource": "https://aspnetcore.blob.core.windows.net/buildtools" -} -``` -#> -[CmdletBinding(PositionalBinding = $false)] -param( - [Parameter(Mandatory = $true, Position = 0)] - [string]$Command, - [string]$Path = $PSScriptRoot, - [Alias('c')] - [string]$Channel, - [Alias('d')] - [string]$DotNetHome, - [Alias('s')] - [string]$ToolsSource, - [Alias('u')] - [switch]$Update, - [string]$ConfigFile, - [string]$ToolsSourceSuffix, - [Parameter(ValueFromRemainingArguments = $true)] - [string[]]$Arguments -) - -Set-StrictMode -Version 2 -$ErrorActionPreference = 'Stop' - -# -# Functions -# - -function Get-KoreBuild { - - $lockFile = Join-Path $Path 'korebuild-lock.txt' - - if (!(Test-Path $lockFile) -or $Update) { - Get-RemoteFile "$ToolsSource/korebuild/channels/$Channel/latest.txt" $lockFile $ToolsSourceSuffix - } - - $version = Get-Content $lockFile | Where-Object { $_ -like 'version:*' } | Select-Object -first 1 - if (!$version) { - Write-Error "Failed to parse version from $lockFile. Expected a line that begins with 'version:'" - } - $version = $version.TrimStart('version:').Trim() - $korebuildPath = Join-Paths $DotNetHome ('buildtools', 'korebuild', $version) - - if (!(Test-Path $korebuildPath)) { - Write-Host -ForegroundColor Magenta "Downloading KoreBuild $version" - New-Item -ItemType Directory -Path $korebuildPath | Out-Null - $remotePath = "$ToolsSource/korebuild/artifacts/$version/korebuild.$version.zip" - - try { - $tmpfile = Join-Path ([IO.Path]::GetTempPath()) "KoreBuild-$([guid]::NewGuid()).zip" - Get-RemoteFile $remotePath $tmpfile $ToolsSourceSuffix - if (Get-Command -Name 'Expand-Archive' -ErrorAction Ignore) { - # Use built-in commands where possible as they are cross-plat compatible - Expand-Archive -Path $tmpfile -DestinationPath $korebuildPath - } - else { - # Fallback to old approach for old installations of PowerShell - Add-Type -AssemblyName System.IO.Compression.FileSystem - [System.IO.Compression.ZipFile]::ExtractToDirectory($tmpfile, $korebuildPath) - } - } - catch { - Remove-Item -Recurse -Force $korebuildPath -ErrorAction Ignore - throw - } - finally { - Remove-Item $tmpfile -ErrorAction Ignore - } - } - - return $korebuildPath -} - -function Join-Paths([string]$path, [string[]]$childPaths) { - $childPaths | ForEach-Object { $path = Join-Path $path $_ } - return $path -} - -function Get-RemoteFile([string]$RemotePath, [string]$LocalPath, [string]$RemoteSuffix) { - if ($RemotePath -notlike 'http*') { - Copy-Item $RemotePath $LocalPath - return - } - - $retries = 10 - while ($retries -gt 0) { - $retries -= 1 - try { - Invoke-WebRequest -UseBasicParsing -Uri $($RemotePath + $RemoteSuffix) -OutFile $LocalPath - return - } - catch { - Write-Verbose "Request failed. $retries retries remaining" - } - } - - Write-Error "Download failed: '$RemotePath'." -} - -# -# Main -# - -# Load configuration or set defaults - -$Path = Resolve-Path $Path -if (!$ConfigFile) { $ConfigFile = Join-Path $Path 'korebuild.json' } - -if (Test-Path $ConfigFile) { - try { - $config = Get-Content -Raw -Encoding UTF8 -Path $ConfigFile | ConvertFrom-Json - if ($config) { - if (!($Channel) -and (Get-Member -Name 'channel' -InputObject $config)) { [string] $Channel = $config.channel } - if (!($ToolsSource) -and (Get-Member -Name 'toolsSource' -InputObject $config)) { [string] $ToolsSource = $config.toolsSource} - } - } - catch { - Write-Warning "$ConfigFile could not be read. Its settings will be ignored." - Write-Warning $Error[0] - } -} - -if (!$DotNetHome) { - $DotNetHome = if ($env:DOTNET_HOME) { $env:DOTNET_HOME } ` - elseif ($env:USERPROFILE) { Join-Path $env:USERPROFILE '.dotnet'} ` - elseif ($env:HOME) {Join-Path $env:HOME '.dotnet'}` - else { Join-Path $PSScriptRoot '.dotnet'} -} - -if (!$Channel) { $Channel = 'dev' } -if (!$ToolsSource) { $ToolsSource = 'https://aspnetcore.blob.core.windows.net/buildtools' } - -# Execute - -$korebuildPath = Get-KoreBuild -Import-Module -Force -Scope Local (Join-Path $korebuildPath 'KoreBuild.psd1') - -try { - Set-KoreBuildSettings -ToolsSource $ToolsSource -DotNetHome $DotNetHome -RepoPath $Path -ConfigFile $ConfigFile - Invoke-KoreBuildCommand $Command @Arguments -} -finally { - Remove-Module 'KoreBuild' -ErrorAction Ignore -} diff --git a/run.sh b/run.sh deleted file mode 100755 index 834961fc3a..0000000000 --- a/run.sh +++ /dev/null @@ -1,231 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -# -# variables -# - -RESET="\033[0m" -RED="\033[0;31m" -YELLOW="\033[0;33m" -MAGENTA="\033[0;95m" -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -[ -z "${DOTNET_HOME:-}" ] && DOTNET_HOME="$HOME/.dotnet" -verbose=false -update=false -repo_path="$DIR" -channel='' -tools_source='' -tools_source_suffix='' - -# -# Functions -# -__usage() { - echo "Usage: $(basename "${BASH_SOURCE[0]}") command [options] [[--] ...]" - echo "" - echo "Arguments:" - echo " command The command to be run." - echo " ... Arguments passed to the command. Variable number of arguments allowed." - echo "" - echo "Options:" - echo " --verbose Show verbose output." - echo " -c|--channel The channel of KoreBuild to download. Overrides the value from the config file.." - echo " --config-file The path to the configuration file that stores values. Defaults to korebuild.json." - echo " -d|--dotnet-home The directory where .NET Core tools will be stored. Defaults to '\$DOTNET_HOME' or '\$HOME/.dotnet." - echo " --path The directory to build. Defaults to the directory containing the script." - echo " -s|--tools-source|-ToolsSource The base url where build tools can be downloaded. Overrides the value from the config file." - echo " --tools-source-suffix|-ToolsSourceSuffix The suffix to append to tools-source. Useful for query strings." - echo " -u|--update Update to the latest KoreBuild even if the lock file is present." - echo "" - echo "Description:" - echo " This function will create a file \$DIR/korebuild-lock.txt. This lock file can be committed to source, but does not have to be." - echo " When the lockfile is not present, KoreBuild will create one using latest available version from \$channel." - - if [[ "${1:-}" != '--no-exit' ]]; then - exit 2 - fi -} - -get_korebuild() { - local version - local lock_file="$repo_path/korebuild-lock.txt" - if [ ! -f "$lock_file" ] || [ "$update" = true ]; then - __get_remote_file "$tools_source/korebuild/channels/$channel/latest.txt" "$lock_file" "$tools_source_suffix" - fi - version="$(grep 'version:*' -m 1 "$lock_file")" - if [[ "$version" == '' ]]; then - __error "Failed to parse version from $lock_file. Expected a line that begins with 'version:'" - return 1 - fi - version="$(echo "${version#version:}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" - local korebuild_path="$DOTNET_HOME/buildtools/korebuild/$version" - - { - if [ ! -d "$korebuild_path" ]; then - mkdir -p "$korebuild_path" - local remote_path="$tools_source/korebuild/artifacts/$version/korebuild.$version.zip" - tmpfile="$(mktemp)" - echo -e "${MAGENTA}Downloading KoreBuild ${version}${RESET}" - if __get_remote_file "$remote_path" "$tmpfile" "$tools_source_suffix"; then - unzip -q -d "$korebuild_path" "$tmpfile" - fi - rm "$tmpfile" || true - fi - - source "$korebuild_path/KoreBuild.sh" - } || { - if [ -d "$korebuild_path" ]; then - echo "Cleaning up after failed installation" - rm -rf "$korebuild_path" || true - fi - return 1 - } -} - -__error() { - echo -e "${RED}error: $*${RESET}" 1>&2 -} - -__warn() { - echo -e "${YELLOW}warning: $*${RESET}" -} - -__machine_has() { - hash "$1" > /dev/null 2>&1 - return $? -} - -__get_remote_file() { - local remote_path=$1 - local local_path=$2 - local remote_path_suffix=$3 - - if [[ "$remote_path" != 'http'* ]]; then - cp "$remote_path" "$local_path" - return 0 - fi - - local failed=false - if __machine_has wget; then - wget --tries 10 --quiet -O "$local_path" "${remote_path}${remote_path_suffix}" || failed=true - else - failed=true - fi - - if [ "$failed" = true ] && __machine_has curl; then - failed=false - curl --retry 10 -sSL -f --create-dirs -o "$local_path" "${remote_path}${remote_path_suffix}" || failed=true - fi - - if [ "$failed" = true ]; then - __error "Download failed: $remote_path" 1>&2 - return 1 - fi -} - -# -# main -# - -command="${1:-}" -shift - -while [[ $# -gt 0 ]]; do - case $1 in - -\?|-h|--help) - __usage --no-exit - exit 0 - ;; - -c|--channel|-Channel) - shift - channel="${1:-}" - [ -z "$channel" ] && __usage - ;; - --config-file|-ConfigFile) - shift - config_file="${1:-}" - [ -z "$config_file" ] && __usage - if [ ! -f "$config_file" ]; then - __error "Invalid value for --config-file. $config_file does not exist." - exit 1 - fi - ;; - -d|--dotnet-home|-DotNetHome) - shift - DOTNET_HOME="${1:-}" - [ -z "$DOTNET_HOME" ] && __usage - ;; - --path|-Path) - shift - repo_path="${1:-}" - [ -z "$repo_path" ] && __usage - ;; - -s|--tools-source|-ToolsSource) - shift - tools_source="${1:-}" - [ -z "$tools_source" ] && __usage - ;; - --tools-source-suffix|-ToolsSourceSuffix) - shift - tools_source_suffix="${1:-}" - [ -z "$tools_source_suffix" ] && __usage - ;; - -u|--update|-Update) - update=true - ;; - --verbose|-Verbose) - verbose=true - ;; - --) - shift - break - ;; - *) - break - ;; - esac - shift -done - -if ! __machine_has unzip; then - __error 'Missing required command: unzip' - exit 1 -fi - -if ! __machine_has curl && ! __machine_has wget; then - __error 'Missing required command. Either wget or curl is required.' - exit 1 -fi - -[ -z "${config_file:-}" ] && config_file="$repo_path/korebuild.json" -if [ -f "$config_file" ]; then - if __machine_has jq ; then - if jq '.' "$config_file" >/dev/null ; then - config_channel="$(jq -r 'select(.channel!=null) | .channel' "$config_file")" - config_tools_source="$(jq -r 'select(.toolsSource!=null) | .toolsSource' "$config_file")" - else - __warn "$config_file is invalid JSON. Its settings will be ignored." - fi - elif __machine_has python ; then - if python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'))" >/dev/null ; then - config_channel="$(python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['channel'] if 'channel' in obj else '')")" - config_tools_source="$(python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['toolsSource'] if 'toolsSource' in obj else '')")" - else - __warn "$config_file is invalid JSON. Its settings will be ignored." - fi - else - __warn 'Missing required command: jq or pyton. Could not parse the JSON file. Its settings will be ignored.' - fi - - [ ! -z "${config_channel:-}" ] && channel="$config_channel" - [ ! -z "${config_tools_source:-}" ] && tools_source="$config_tools_source" -fi - -[ -z "$channel" ] && channel='dev' -[ -z "$tools_source" ] && tools_source='https://aspnetcore.blob.core.windows.net/buildtools' - -get_korebuild -set_korebuildsettings "$tools_source" "$DOTNET_HOME" "$repo_path" "$config_file" -invoke_korebuild_command "$command" "$@" diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilder.cs b/src/Html/Abstractions/src/HtmlContentBuilder.cs similarity index 100% rename from src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilder.cs rename to src/Html/Abstractions/src/HtmlContentBuilder.cs diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilderExtensions.cs b/src/Html/Abstractions/src/HtmlContentBuilderExtensions.cs similarity index 100% rename from src/Microsoft.AspNetCore.Html.Abstractions/HtmlContentBuilderExtensions.cs rename to src/Html/Abstractions/src/HtmlContentBuilderExtensions.cs diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/HtmlFormattableString.cs b/src/Html/Abstractions/src/HtmlFormattableString.cs similarity index 100% rename from src/Microsoft.AspNetCore.Html.Abstractions/HtmlFormattableString.cs rename to src/Html/Abstractions/src/HtmlFormattableString.cs diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/HtmlString.cs b/src/Html/Abstractions/src/HtmlString.cs similarity index 100% rename from src/Microsoft.AspNetCore.Html.Abstractions/HtmlString.cs rename to src/Html/Abstractions/src/HtmlString.cs diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/IHtmlContent.cs b/src/Html/Abstractions/src/IHtmlContent.cs similarity index 100% rename from src/Microsoft.AspNetCore.Html.Abstractions/IHtmlContent.cs rename to src/Html/Abstractions/src/IHtmlContent.cs diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/IHtmlContentBuilder.cs b/src/Html/Abstractions/src/IHtmlContentBuilder.cs similarity index 100% rename from src/Microsoft.AspNetCore.Html.Abstractions/IHtmlContentBuilder.cs rename to src/Html/Abstractions/src/IHtmlContentBuilder.cs diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/IHtmlContentContainer.cs b/src/Html/Abstractions/src/IHtmlContentContainer.cs similarity index 100% rename from src/Microsoft.AspNetCore.Html.Abstractions/IHtmlContentContainer.cs rename to src/Html/Abstractions/src/IHtmlContentContainer.cs diff --git a/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.csproj b/src/Html/Abstractions/src/Microsoft.AspNetCore.Html.Abstractions.csproj old mode 100755 new mode 100644 similarity index 74% rename from src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.csproj rename to src/Html/Abstractions/src/Microsoft.AspNetCore.Html.Abstractions.csproj index 271cc6c7fa..f914769d17 --- a/src/Microsoft.AspNetCore.Html.Abstractions/Microsoft.AspNetCore.Html.Abstractions.csproj +++ b/src/Html/Abstractions/src/Microsoft.AspNetCore.Html.Abstractions.csproj @@ -1,8 +1,8 @@  - Microsoft ASP.NET Core ASP.NET Core HTML abstractions used for building HTML content. + Commonly used types: Microsoft.AspNetCore.Html.HtmlString Microsoft.AspNetCore.Html.IHtmlContent @@ -12,7 +12,7 @@ Microsoft.AspNetCore.Html.IHtmlContent - + 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/Microsoft.AspNetCore.Html.Abstractions/baseline.netcore.json b/src/Html/Abstractions/src/baseline.netcore.json similarity index 100% rename from src/Microsoft.AspNetCore.Html.Abstractions/baseline.netcore.json rename to src/Html/Abstractions/src/baseline.netcore.json diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlContentBuilderExtensionsTest.cs b/src/Html/Abstractions/test/HtmlContentBuilderExtensionsTest.cs similarity index 100% rename from test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlContentBuilderExtensionsTest.cs rename to src/Html/Abstractions/test/HtmlContentBuilderExtensionsTest.cs diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlContentBuilderTest.cs b/src/Html/Abstractions/test/HtmlContentBuilderTest.cs similarity index 100% rename from test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlContentBuilderTest.cs rename to src/Html/Abstractions/test/HtmlContentBuilderTest.cs diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlFormattableStringTest.cs b/src/Html/Abstractions/test/HtmlFormattableStringTest.cs similarity index 100% rename from test/Microsoft.AspNetCore.Html.Abstractions.Test/HtmlFormattableStringTest.cs rename to src/Html/Abstractions/test/HtmlFormattableStringTest.cs 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/Microsoft.AspNetCore.Html.Abstractions/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.Html.Abstractions/Properties/AssemblyInfo.cs deleted file mode 100644 index bde0132dbb..0000000000 --- a/src/Microsoft.AspNetCore.Html.Abstractions/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Reflection; -using System.Resources; -using System.Runtime.CompilerServices; - -[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Html.Abstractions.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] diff --git a/src/Microsoft.Extensions.WebEncoders/EncoderServiceCollectionExtensions.cs b/src/Microsoft.Extensions.WebEncoders/EncoderServiceCollectionExtensions.cs deleted file mode 100644 index 72f5e369a1..0000000000 --- a/src/Microsoft.Extensions.WebEncoders/EncoderServiceCollectionExtensions.cs +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Text.Encodings.Web; -using Microsoft.Extensions.DependencyInjection.Extensions; -using Microsoft.Extensions.Options; -using Microsoft.Extensions.WebEncoders; - -namespace Microsoft.Extensions.DependencyInjection -{ - /// - /// Extension methods for setting up web encoding services in an . - /// - public static class EncoderServiceCollectionExtensions - { - /// - /// Adds , and - /// to the specified . - /// - /// The . - /// The so that additional calls can be chained. - public static IServiceCollection AddWebEncoders(this IServiceCollection services) - { - if (services == null) - { - throw new ArgumentNullException(nameof(services)); - } - - services.AddOptions(); - - // Register the default encoders - // We want to call the 'Default' property getters lazily since they perform static caching - services.TryAddSingleton( - CreateFactory(() => HtmlEncoder.Default, settings => HtmlEncoder.Create(settings))); - services.TryAddSingleton( - CreateFactory(() => JavaScriptEncoder.Default, settings => JavaScriptEncoder.Create(settings))); - services.TryAddSingleton( - CreateFactory(() => UrlEncoder.Default, settings => UrlEncoder.Create(settings))); - - return services; - } - - /// - /// Adds , and - /// to the specified . - /// - /// The . - /// An to configure the provided . - /// The so that additional calls can be chained. - public static IServiceCollection AddWebEncoders(this IServiceCollection services, Action setupAction) - { - if (services == null) - { - throw new ArgumentNullException(nameof(services)); - } - - if (setupAction == null) - { - throw new ArgumentNullException(nameof(setupAction)); - } - - services.AddWebEncoders(); - services.Configure(setupAction); - - return services; - } - - private static Func CreateFactory( - Func defaultFactory, - Func customSettingsFactory) - { - return serviceProvider => - { - var settings = serviceProvider - ?.GetService>() - ?.Value - ?.TextEncoderSettings; - return (settings != null) ? customSettingsFactory(settings) : defaultFactory(); - }; - } - } -} diff --git a/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.csproj b/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.csproj deleted file mode 100755 index 5e6b3392b5..0000000000 --- a/src/Microsoft.Extensions.WebEncoders/Microsoft.Extensions.WebEncoders.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - Microsoft .NET Extensions - Contains registration and configuration APIs to add the core framework encoders to a dependency injection container. - netstandard2.0 - $(NoWarn);CS1591 - true - true - aspnetcore - - - - - - - - - diff --git a/src/Microsoft.Extensions.WebEncoders/Testing/HtmlTestEncoder.cs b/src/Microsoft.Extensions.WebEncoders/Testing/HtmlTestEncoder.cs deleted file mode 100644 index 162ce4f6c1..0000000000 --- a/src/Microsoft.Extensions.WebEncoders/Testing/HtmlTestEncoder.cs +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.IO; -using System.Text.Encodings.Web; - -namespace Microsoft.Extensions.WebEncoders.Testing -{ - /// - /// Encoder used for unit testing. - /// - public sealed class HtmlTestEncoder : HtmlEncoder - { - public override int MaxOutputCharactersPerInputCharacter - { - get { return 1; } - } - - public override string Encode(string value) - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - if (value.Length == 0) - { - return string.Empty; - } - - return $"HtmlEncode[[{value}]]"; - } - - public override void Encode(TextWriter output, char[] value, int startIndex, int characterCount) - { - if (output == null) - { - throw new ArgumentNullException(nameof(output)); - } - - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - if (characterCount == 0) - { - return; - } - - output.Write("HtmlEncode[["); - output.Write(value, startIndex, characterCount); - output.Write("]]"); - } - - public override void Encode(TextWriter output, string value, int startIndex, int characterCount) - { - if (output == null) - { - throw new ArgumentNullException(nameof(output)); - } - - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - if (characterCount == 0) - { - return; - } - - output.Write("HtmlEncode[["); - output.Write(value.Substring(startIndex, characterCount)); - output.Write("]]"); - } - - public override bool WillEncode(int unicodeScalar) - { - return false; - } - - public override unsafe int FindFirstCharacterToEncode(char* text, int textLength) - { - return -1; - } - - public override unsafe bool TryEncodeUnicodeScalar( - int unicodeScalar, - char* buffer, - int bufferLength, - out int numberOfCharactersWritten) - { - if (buffer == null) - { - throw new ArgumentNullException(nameof(buffer)); - } - - numberOfCharactersWritten = 0; - return false; - } - } -} \ No newline at end of file diff --git a/src/Microsoft.Extensions.WebEncoders/Testing/JavaScriptTestEncoder.cs b/src/Microsoft.Extensions.WebEncoders/Testing/JavaScriptTestEncoder.cs deleted file mode 100644 index bef4461676..0000000000 --- a/src/Microsoft.Extensions.WebEncoders/Testing/JavaScriptTestEncoder.cs +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.IO; -using System.Text.Encodings.Web; - -namespace Microsoft.Extensions.WebEncoders.Testing -{ - /// - /// Encoder used for unit testing. - /// - public class JavaScriptTestEncoder : JavaScriptEncoder - { - public override int MaxOutputCharactersPerInputCharacter - { - get { return 1; } - } - - public override string Encode(string value) - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - if (value.Length == 0) - { - return string.Empty; - } - - return $"JavaScriptEncode[[{value}]]"; - } - - public override void Encode(TextWriter output, char[] value, int startIndex, int characterCount) - { - if (output == null) - { - throw new ArgumentNullException(nameof(output)); - } - - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - if (characterCount == 0) - { - return; - } - - output.Write("JavaScriptEncode[["); - output.Write(value, startIndex, characterCount); - output.Write("]]"); - } - - public override void Encode(TextWriter output, string value, int startIndex, int characterCount) - { - if (output == null) - { - throw new ArgumentNullException(nameof(output)); - } - - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - if (characterCount == 0) - { - return; - } - - output.Write("JavaScriptEncode[["); - output.Write(value.Substring(startIndex, characterCount)); - output.Write("]]"); - } - - public override bool WillEncode(int unicodeScalar) - { - return false; - } - - public override unsafe int FindFirstCharacterToEncode(char* text, int textLength) - { - return -1; - } - - public override unsafe bool TryEncodeUnicodeScalar( - int unicodeScalar, - char* buffer, - int bufferLength, - out int numberOfCharactersWritten) - { - if (buffer == null) - { - throw new ArgumentNullException(nameof(buffer)); - } - - numberOfCharactersWritten = 0; - return false; - } - } -} \ No newline at end of file diff --git a/src/Microsoft.Extensions.WebEncoders/Testing/UrlTestEncoder.cs b/src/Microsoft.Extensions.WebEncoders/Testing/UrlTestEncoder.cs deleted file mode 100644 index 295bda63e8..0000000000 --- a/src/Microsoft.Extensions.WebEncoders/Testing/UrlTestEncoder.cs +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.IO; -using System.Text.Encodings.Web; - -namespace Microsoft.Extensions.WebEncoders.Testing -{ - /// - /// Encoder used for unit testing. - /// - public class UrlTestEncoder : UrlEncoder - { - public override int MaxOutputCharactersPerInputCharacter - { - get { return 1; } - } - - public override string Encode(string value) - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - if (value.Length == 0) - { - return string.Empty; - } - - return $"UrlEncode[[{value}]]"; - } - - public override void Encode(TextWriter output, char[] value, int startIndex, int characterCount) - { - if (output == null) - { - throw new ArgumentNullException(nameof(output)); - } - - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - if (characterCount == 0) - { - return; - } - - output.Write("UrlEncode[["); - output.Write(value, startIndex, characterCount); - output.Write("]]"); - } - - public override void Encode(TextWriter output, string value, int startIndex, int characterCount) - { - if (output == null) - { - throw new ArgumentNullException(nameof(output)); - } - - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - if (characterCount == 0) - { - return; - } - - output.Write("UrlEncode[["); - output.Write(value.Substring(startIndex, characterCount)); - output.Write("]]"); - } - - public override bool WillEncode(int unicodeScalar) - { - return false; - } - - public override unsafe int FindFirstCharacterToEncode(char* text, int textLength) - { - return -1; - } - - public override unsafe bool TryEncodeUnicodeScalar( - int unicodeScalar, - char* buffer, - int bufferLength, - out int numberOfCharactersWritten) - { - if (buffer == null) - { - throw new ArgumentNullException(nameof(buffer)); - } - - numberOfCharactersWritten = 0; - return false; - } - } -} \ No newline at end of file diff --git a/src/Microsoft.Extensions.WebEncoders/WebEncoderOptions.cs b/src/Microsoft.Extensions.WebEncoders/WebEncoderOptions.cs deleted file mode 100644 index 2f5e770a0c..0000000000 --- a/src/Microsoft.Extensions.WebEncoders/WebEncoderOptions.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Text.Encodings.Web; - -namespace Microsoft.Extensions.WebEncoders -{ - /// - /// Specifies options common to all three encoders (HtmlEncode, JavaScriptEncode, UrlEncode). - /// - public sealed class WebEncoderOptions - { - /// - /// Specifies which code points are allowed to be represented unescaped by the encoders. - /// - /// - /// If this property is null, then the encoders will use their default allow lists. - /// - public TextEncoderSettings TextEncoderSettings { get; set; } - } -} diff --git a/src/Microsoft.Extensions.WebEncoders/baseline.netcore.json b/src/Microsoft.Extensions.WebEncoders/baseline.netcore.json deleted file mode 100644 index 6da0ae0754..0000000000 --- a/src/Microsoft.Extensions.WebEncoders/baseline.netcore.json +++ /dev/null @@ -1,564 +0,0 @@ -{ - "AssemblyIdentity": "Microsoft.Extensions.WebEncoders, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", - "Types": [ - { - "Name": "Microsoft.Extensions.WebEncoders.WebEncoderOptions", - "Visibility": "Public", - "Kind": "Class", - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_TextEncoderSettings", - "Parameters": [], - "ReturnType": "System.Text.Encodings.Web.TextEncoderSettings", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_TextEncoderSettings", - "Parameters": [ - { - "Name": "value", - "Type": "System.Text.Encodings.Web.TextEncoderSettings" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.Extensions.WebEncoders.Testing.HtmlTestEncoder", - "Visibility": "Public", - "Kind": "Class", - "Sealed": true, - "BaseType": "System.Text.Encodings.Web.HtmlEncoder", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_MaxOutputCharactersPerInputCharacter", - "Parameters": [], - "ReturnType": "System.Int32", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Encode", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.String", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Encode", - "Parameters": [ - { - "Name": "output", - "Type": "System.IO.TextWriter" - }, - { - "Name": "value", - "Type": "System.Char[]" - }, - { - "Name": "startIndex", - "Type": "System.Int32" - }, - { - "Name": "characterCount", - "Type": "System.Int32" - } - ], - "ReturnType": "System.Void", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Encode", - "Parameters": [ - { - "Name": "output", - "Type": "System.IO.TextWriter" - }, - { - "Name": "value", - "Type": "System.String" - }, - { - "Name": "startIndex", - "Type": "System.Int32" - }, - { - "Name": "characterCount", - "Type": "System.Int32" - } - ], - "ReturnType": "System.Void", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "WillEncode", - "Parameters": [ - { - "Name": "unicodeScalar", - "Type": "System.Int32" - } - ], - "ReturnType": "System.Boolean", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "FindFirstCharacterToEncode", - "Parameters": [ - { - "Name": "text", - "Type": "System.Char*" - }, - { - "Name": "textLength", - "Type": "System.Int32" - } - ], - "ReturnType": "System.Int32", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "TryEncodeUnicodeScalar", - "Parameters": [ - { - "Name": "unicodeScalar", - "Type": "System.Int32" - }, - { - "Name": "buffer", - "Type": "System.Char*" - }, - { - "Name": "bufferLength", - "Type": "System.Int32" - }, - { - "Name": "numberOfCharactersWritten", - "Type": "System.Int32", - "Direction": "Out" - } - ], - "ReturnType": "System.Boolean", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.Extensions.WebEncoders.Testing.JavaScriptTestEncoder", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "System.Text.Encodings.Web.JavaScriptEncoder", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_MaxOutputCharactersPerInputCharacter", - "Parameters": [], - "ReturnType": "System.Int32", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Encode", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.String", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Encode", - "Parameters": [ - { - "Name": "output", - "Type": "System.IO.TextWriter" - }, - { - "Name": "value", - "Type": "System.Char[]" - }, - { - "Name": "startIndex", - "Type": "System.Int32" - }, - { - "Name": "characterCount", - "Type": "System.Int32" - } - ], - "ReturnType": "System.Void", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Encode", - "Parameters": [ - { - "Name": "output", - "Type": "System.IO.TextWriter" - }, - { - "Name": "value", - "Type": "System.String" - }, - { - "Name": "startIndex", - "Type": "System.Int32" - }, - { - "Name": "characterCount", - "Type": "System.Int32" - } - ], - "ReturnType": "System.Void", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "WillEncode", - "Parameters": [ - { - "Name": "unicodeScalar", - "Type": "System.Int32" - } - ], - "ReturnType": "System.Boolean", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "FindFirstCharacterToEncode", - "Parameters": [ - { - "Name": "text", - "Type": "System.Char*" - }, - { - "Name": "textLength", - "Type": "System.Int32" - } - ], - "ReturnType": "System.Int32", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "TryEncodeUnicodeScalar", - "Parameters": [ - { - "Name": "unicodeScalar", - "Type": "System.Int32" - }, - { - "Name": "buffer", - "Type": "System.Char*" - }, - { - "Name": "bufferLength", - "Type": "System.Int32" - }, - { - "Name": "numberOfCharactersWritten", - "Type": "System.Int32", - "Direction": "Out" - } - ], - "ReturnType": "System.Boolean", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.Extensions.WebEncoders.Testing.UrlTestEncoder", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "System.Text.Encodings.Web.UrlEncoder", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_MaxOutputCharactersPerInputCharacter", - "Parameters": [], - "ReturnType": "System.Int32", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Encode", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.String", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Encode", - "Parameters": [ - { - "Name": "output", - "Type": "System.IO.TextWriter" - }, - { - "Name": "value", - "Type": "System.Char[]" - }, - { - "Name": "startIndex", - "Type": "System.Int32" - }, - { - "Name": "characterCount", - "Type": "System.Int32" - } - ], - "ReturnType": "System.Void", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Encode", - "Parameters": [ - { - "Name": "output", - "Type": "System.IO.TextWriter" - }, - { - "Name": "value", - "Type": "System.String" - }, - { - "Name": "startIndex", - "Type": "System.Int32" - }, - { - "Name": "characterCount", - "Type": "System.Int32" - } - ], - "ReturnType": "System.Void", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "WillEncode", - "Parameters": [ - { - "Name": "unicodeScalar", - "Type": "System.Int32" - } - ], - "ReturnType": "System.Boolean", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "FindFirstCharacterToEncode", - "Parameters": [ - { - "Name": "text", - "Type": "System.Char*" - }, - { - "Name": "textLength", - "Type": "System.Int32" - } - ], - "ReturnType": "System.Int32", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "TryEncodeUnicodeScalar", - "Parameters": [ - { - "Name": "unicodeScalar", - "Type": "System.Int32" - }, - { - "Name": "buffer", - "Type": "System.Char*" - }, - { - "Name": "bufferLength", - "Type": "System.Int32" - }, - { - "Name": "numberOfCharactersWritten", - "Type": "System.Int32", - "Direction": "Out" - } - ], - "ReturnType": "System.Boolean", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.Extensions.DependencyInjection.EncoderServiceCollectionExtensions", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "AddWebEncoders", - "Parameters": [ - { - "Name": "services", - "Type": "Microsoft.Extensions.DependencyInjection.IServiceCollection" - } - ], - "ReturnType": "Microsoft.Extensions.DependencyInjection.IServiceCollection", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "AddWebEncoders", - "Parameters": [ - { - "Name": "services", - "Type": "Microsoft.Extensions.DependencyInjection.IServiceCollection" - }, - { - "Name": "setupAction", - "Type": "System.Action" - } - ], - "ReturnType": "Microsoft.Extensions.DependencyInjection.IServiceCollection", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - } - ] -} \ No newline at end of file diff --git a/test/Directory.Build.props b/test/Directory.Build.props deleted file mode 100644 index 0b706cbca5..0000000000 --- a/test/Directory.Build.props +++ /dev/null @@ -1,17 +0,0 @@ - - - - - netcoreapp2.1 - $(DeveloperBuildTestTfms) - netcoreapp2.1;netcoreapp2.0 - $(StandardTestTfms);net461 - - - - - - - - - diff --git a/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.csproj b/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.csproj deleted file mode 100755 index 1577693497..0000000000 --- a/test/Microsoft.AspNetCore.Html.Abstractions.Test/Microsoft.AspNetCore.Html.Abstractions.Test.csproj +++ /dev/null @@ -1,12 +0,0 @@ - - - - $(StandardTestTfms) - - - - - - - - diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/EncoderServiceCollectionExtensionsTests.cs b/test/Microsoft.Extensions.WebEncoders.Tests/EncoderServiceCollectionExtensionsTests.cs deleted file mode 100644 index 0178bba2d5..0000000000 --- a/test/Microsoft.Extensions.WebEncoders.Tests/EncoderServiceCollectionExtensionsTests.cs +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Text.Encodings.Web; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.WebEncoders.Testing; -using Xunit; - -namespace Microsoft.Extensions.WebEncoders -{ - public class EncoderServiceCollectionExtensionsTests - { - [Fact] - public void AddWebEncoders_WithoutOptions_RegistersDefaultEncoders() - { - // Arrange - var serviceCollection = new ServiceCollection(); - - // Act - serviceCollection.AddWebEncoders(); - - // Assert - var serviceProvider = serviceCollection.BuildServiceProvider(); - Assert.Same(HtmlEncoder.Default, serviceProvider.GetRequiredService()); // default encoder - Assert.Same(HtmlEncoder.Default, serviceProvider.GetRequiredService()); // as singleton instance - Assert.Same(JavaScriptEncoder.Default, serviceProvider.GetRequiredService()); // default encoder - Assert.Same(JavaScriptEncoder.Default, serviceProvider.GetRequiredService()); // as singleton instance - Assert.Same(UrlEncoder.Default, serviceProvider.GetRequiredService()); // default encoder - Assert.Same(UrlEncoder.Default, serviceProvider.GetRequiredService()); // as singleton instance - } - - [Fact] - public void AddWebEncoders_WithOptions_RegistersEncodersWithCustomCodeFilter() - { - // Arrange - var serviceCollection = new ServiceCollection(); - - // Act - serviceCollection.AddWebEncoders(options => - { - options.TextEncoderSettings = new TextEncoderSettings(); - options.TextEncoderSettings.AllowCharacters("ace".ToCharArray()); // only these three chars are allowed - }); - - // Assert - var serviceProvider = serviceCollection.BuildServiceProvider(); - - var htmlEncoder = serviceProvider.GetRequiredService(); - Assert.Equal("abcde", htmlEncoder.Encode("abcde")); - Assert.Same(htmlEncoder, serviceProvider.GetRequiredService()); // as singleton instance - - var javaScriptEncoder = serviceProvider.GetRequiredService(); - Assert.Equal(@"a\u0062c\u0064e", javaScriptEncoder.Encode("abcde")); - Assert.Same(javaScriptEncoder, serviceProvider.GetRequiredService()); // as singleton instance - - var urlEncoder = serviceProvider.GetRequiredService(); - Assert.Equal("a%62c%64e", urlEncoder.Encode("abcde")); - Assert.Same(urlEncoder, serviceProvider.GetRequiredService()); // as singleton instance - } - - [Fact] - public void AddWebEncoders_DoesNotOverrideExistingRegisteredEncoders() - { - // Arrange - var serviceCollection = new ServiceCollection(); - - // Act - serviceCollection.AddSingleton(); - serviceCollection.AddSingleton(); - // we don't register an existing URL encoder - serviceCollection.AddWebEncoders(options => - { - options.TextEncoderSettings = new TextEncoderSettings(); - options.TextEncoderSettings.AllowCharacters("ace".ToCharArray()); // only these three chars are allowed - }); - - // Assert - var serviceProvider = serviceCollection.BuildServiceProvider(); - - var htmlEncoder = serviceProvider.GetRequiredService(); - Assert.Equal("HtmlEncode[[abcde]]", htmlEncoder.Encode("abcde")); - - var javaScriptEncoder = serviceProvider.GetRequiredService(); - Assert.Equal("JavaScriptEncode[[abcde]]", javaScriptEncoder.Encode("abcde")); - - var urlEncoder = serviceProvider.GetRequiredService(); - Assert.Equal("a%62c%64e", urlEncoder.Encode("abcde")); - } - } -} diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/HtmlTestEncoderTest.cs b/test/Microsoft.Extensions.WebEncoders.Tests/HtmlTestEncoderTest.cs deleted file mode 100644 index baafedc4de..0000000000 --- a/test/Microsoft.Extensions.WebEncoders.Tests/HtmlTestEncoderTest.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using Xunit; - -namespace Microsoft.Extensions.WebEncoders.Testing -{ - public class HtmlTestEncoderTest - { - [Theory] - [InlineData("", "")] - [InlineData("abcd", "HtmlEncode[[abcd]]")] - [InlineData("<<''\"\">>", "HtmlEncode[[<<''\"\">>]]")] - public void StringEncode_EncodesAsExpected(string input, string expectedOutput) - { - // Arrange - var encoder = new HtmlTestEncoder(); - - // Act - var output = encoder.Encode(input); - - // Assert - Assert.Equal(expectedOutput, output); - } - } -} diff --git a/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj b/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj deleted file mode 100755 index 247ccd19b3..0000000000 --- a/test/Microsoft.Extensions.WebEncoders.Tests/Microsoft.Extensions.WebEncoders.Tests.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - - $(StandardTestTfms) - - - - - - - - - - - diff --git a/version.props b/version.props deleted file mode 100644 index 669c874829..0000000000 --- a/version.props +++ /dev/null @@ -1,12 +0,0 @@ - - - 2.1.1 - rtm - $(VersionPrefix) - $(VersionPrefix)-$(VersionSuffix)-final - t000 - a- - $(FeatureBranchVersionPrefix)$(VersionSuffix)-$([System.Text.RegularExpressions.Regex]::Replace('$(FeatureBranchVersionSuffix)', '[^\w-]', '-')) - $(VersionSuffix)-$(BuildNumber) - - From de9609b34388d5472a84f4fe968d7d5d3a359e98 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Mon, 12 Nov 2018 09:05:17 -0800 Subject: [PATCH 468/471] Remove implicit reference to InteralAspNetCoreSdk (#3998) --- .../ANCMPackageResolver/ANCMPackageResolver.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/ANCMPackageResolver/ANCMPackageResolver.csproj b/src/Installers/Windows/AspNetCoreModule-Setup/ANCMPackageResolver/ANCMPackageResolver.csproj index 591599ecca..561936aeaf 100644 --- a/src/Installers/Windows/AspNetCoreModule-Setup/ANCMPackageResolver/ANCMPackageResolver.csproj +++ b/src/Installers/Windows/AspNetCoreModule-Setup/ANCMPackageResolver/ANCMPackageResolver.csproj @@ -7,6 +7,7 @@ + From ed1976b8627ced537e1aa354b017faa5a0b90619 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 13 Nov 2018 10:02:59 -0800 Subject: [PATCH 469/471] Update BuildTools to 2.1.3-rtm-15845 --- build/repo.targets | 8 +------- korebuild-lock.txt | 4 ++-- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/build/repo.targets b/build/repo.targets index 9e7e303327..602356a33f 100644 --- a/build/repo.targets +++ b/build/repo.targets @@ -306,14 +306,8 @@ Condition=" @(ExternalDependency->WithMetadataValue('Version', '')->Count()) != 0 " /> - - - $(BuildProperties);DesignTimeBuild=true - - - + DependsOnTargets="ComputeGraph;VerifyPackageArtifactConfig;VerifyAllReposHaveNuGetPackageVerifier" /> diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 7d2ac1cf8c..65061b1d21 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.3-rtm-15844 -commithash:8d031079e81ea30446712d48f7e8e9539fb92907 +version:2.1.3-rtm-15845 +commithash:c808c3c16cbc75c88ee39abd2e15569657312474 From ccd098ecad2dfb3404410a6d6eee629dbff3d9a8 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 13 Nov 2018 10:28:42 -0800 Subject: [PATCH 470/471] Update DataProtection to use custom reference resolution This changes DataProtection to build as projects instead of a pseudo-submodule. It replaces Package and ProjectReference with items which custom targets then resolve. --- .azure/pipelines/fast-pr-validation.yml | 2 +- Directory.Build.targets | 11 +++++-- build/PackageArchive.targets | 4 +-- build/buildorder.props | 1 - build/repo.props | 1 + build/repo.targets | 17 +++++++---- build/submodules.props | 1 - eng/Dependencies.props | 10 +++++-- eng/ProjectReferences.props | 9 ++++++ ...NetCore.DataProtection.Abstractions.csproj | 2 +- ...e.DataProtection.Abstractions.Tests.csproj | 4 +-- ...etCore.DataProtection.AzureKeyVault.csproj | 9 ++---- ....DataProtection.AzureKeyVault.Tests.csproj | 9 ++---- ...NetCore.DataProtection.AzureStorage.csproj | 7 ++--- ...e.DataProtection.AzureStorage.Tests.csproj | 9 ++---- ...NetCore.Cryptography.Internal.Tests.csproj | 2 +- ...pNetCore.Cryptography.KeyDerivation.csproj | 2 +- ...re.Cryptography.KeyDerivation.Tests.csproj | 4 +-- ...Microsoft.AspNetCore.DataProtection.csproj | 21 ++++++-------- ...oft.AspNetCore.DataProtection.Tests.csproj | 10 +++---- src/DataProtection/Directory.Build.props | 8 ----- ...spNetCore.DataProtection.Extensions.csproj | 7 ++--- ...ore.DataProtection.Extensions.Tests.csproj | 5 ++-- ...oft.AspNetCore.DataProtection.Redis.csproj | 7 ++--- ...pNetCore.DataProtection.Redis.Tests.csproj | 7 ++--- ...AspNetCore.DataProtection.SystemWeb.csproj | 7 ++--- src/DataProtection/dependencies.props | 29 ------------------- .../samples/AzureBlob/AzureBlob.csproj | 13 ++++----- .../AzureKeyVault/AzureKeyVault.csproj | 15 ++++------ .../CustomEncryptorSample.csproj | 11 +++---- .../KeyManagementSample.csproj | 4 +-- .../samples/NonDISample/NonDISample.csproj | 2 +- src/DataProtection/samples/Redis/Redis.csproj | 11 +++---- src/DataProtection/version.props | 18 ------------ 34 files changed, 104 insertions(+), 175 deletions(-) delete mode 100644 src/DataProtection/Directory.Build.props delete mode 100644 src/DataProtection/dependencies.props delete mode 100644 src/DataProtection/version.props diff --git a/.azure/pipelines/fast-pr-validation.yml b/.azure/pipelines/fast-pr-validation.yml index 5449521778..216f257ef1 100644 --- a/.azure/pipelines/fast-pr-validation.yml +++ b/.azure/pipelines/fast-pr-validation.yml @@ -16,7 +16,7 @@ jobs: agentOs: Windows beforeBuild: - powershell: "& ./src/IISIntegration/tools/UpdateIISExpressCertificate.ps1" - displayName: Setup IISExpress test certificates" + displayName: Setup IISExpress test certificates - template: jobs/iisintegration-job.yml parameters: variables: diff --git a/Directory.Build.targets b/Directory.Build.targets index a382d031d9..eea5ccac3a 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -22,9 +22,16 @@ - $(BaselinePackageVersion).0 $(BaselinePackageVersion).0 - $(BaselinePackageVersion) + + $(BaselinePackageVersion) + $(BaselinePackageVersion) diff --git a/build/PackageArchive.targets b/build/PackageArchive.targets index 5ba1cadcf8..c92c5455d3 100644 --- a/build/PackageArchive.targets +++ b/build/PackageArchive.targets @@ -8,9 +8,7 @@ - - - + DotNetRestoreSourcePropsPath=$(GeneratedRestoreSourcesPropsPath); diff --git a/build/buildorder.props b/build/buildorder.props index d3dd091d55..89ee48312e 100644 --- a/build/buildorder.props +++ b/build/buildorder.props @@ -12,7 +12,6 @@ - diff --git a/build/repo.props b/build/repo.props index 9023800398..dbda0b55d0 100644 --- a/build/repo.props +++ b/build/repo.props @@ -46,6 +46,7 @@ $(IntermediateDir)sources.g.props $(IntermediateDir)branding.g.props - SetTeamCityBuildNumberToVersion;$(PrepareDependsOn);VerifyPackageArtifactConfig;VerifyExternalDependencyConfig;PrepareOutputPaths + SetTeamCityBuildNumberToVersion;$(PrepareDependsOn) + $(PrepareDependsOn);VerifyPackageArtifactConfig;VerifyExternalDependencyConfig;PrepareOutputPaths $(CleanDependsOn);CleanArtifacts;CleanRepoArtifacts $(RestoreDependsOn);InstallDotNet;RestoreProjects - $(CompileDependsOn);BuildProjects;PackProjects;BuildRepositories - $(PackageDependsOn);BuildMetapackages;CheckExpectedPackagesExist - $(TestDependsOn);TestProjects;_TestRepositories - $(GetArtifactInfoDependsOn);GetProjectArtifactInfo;ResolveRepoInfo + $(CompileDependsOn);BuildProjects + $(CompileDependsOn);PackProjects;BuildRepositories + $(PackageDependsOn);PackProjects + $(PackageDependsOn);BuildMetapackages;CheckExpectedPackagesExist + $(TestDependsOn);TestProjects + $(TestDependsOn);_TestRepositories + $(GetArtifactInfoDependsOn);GetProjectArtifactInfo + $(GetArtifactInfoDependsOn);ResolveRepoInfo @@ -246,7 +251,7 @@ - + diff --git a/build/submodules.props b/build/submodules.props index d921cff07f..8db8e4fe1f 100644 --- a/build/submodules.props +++ b/build/submodules.props @@ -54,7 +54,6 @@ - diff --git a/eng/Dependencies.props b/eng/Dependencies.props index 6df8435a82..a8a2f8543d 100644 --- a/eng/Dependencies.props +++ b/eng/Dependencies.props @@ -11,11 +11,15 @@ - - - + + + + + + + diff --git a/eng/ProjectReferences.props b/eng/ProjectReferences.props index de8f54f37a..7d310275de 100644 --- a/eng/ProjectReferences.props +++ b/eng/ProjectReferences.props @@ -2,6 +2,15 @@ + + + + + + + + + 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 94ea16f046..6199bd2b24 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 8a3e7b2de7..95a7d299fc 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 be4ade7f7a..a8b6486901 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 2a67e3345b..9bc42b1842 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 ac98d14665..668f7ca459 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 3f6b273467..46b39d41bd 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 7f505ef53a..81986fba41 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 deb7bb4ee6..0000000000 --- a/src/DataProtection/Directory.Build.props +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - 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 24bd4c8933..da0be5fc69 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/Redis/src/Microsoft.AspNetCore.DataProtection.Redis.csproj b/src/DataProtection/Redis/src/Microsoft.AspNetCore.DataProtection.Redis.csproj index 45ed6e5bc3..c5742bf3de 100644 --- a/src/DataProtection/Redis/src/Microsoft.AspNetCore.DataProtection.Redis.csproj +++ b/src/DataProtection/Redis/src/Microsoft.AspNetCore.DataProtection.Redis.csproj @@ -14,11 +14,8 @@ - - - - - + + diff --git a/src/DataProtection/Redis/test/Microsoft.AspNetCore.DataProtection.Redis.Tests.csproj b/src/DataProtection/Redis/test/Microsoft.AspNetCore.DataProtection.Redis.Tests.csproj index 426f2c2681..6bf56165bd 100644 --- a/src/DataProtection/Redis/test/Microsoft.AspNetCore.DataProtection.Redis.Tests.csproj +++ b/src/DataProtection/Redis/test/Microsoft.AspNetCore.DataProtection.Redis.Tests.csproj @@ -5,11 +5,8 @@ - - - - - + + 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/dependencies.props b/src/DataProtection/dependencies.props deleted file mode 100644 index 7a7089d81f..0000000000 --- a/src/DataProtection/dependencies.props +++ /dev/null @@ -1,29 +0,0 @@ - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - - - - - 2.1.3-rtm-15822 - - - - - 2.1.1 - 2.1.1 - 2.1.0 - 2.1.1 - 2.1.1 - 2.1.1 - 2.1.1 - 2.1.1 - 2.1.1 - 2.1.1 - 2.1.1 - 2.1.1 - - diff --git a/src/DataProtection/samples/AzureBlob/AzureBlob.csproj b/src/DataProtection/samples/AzureBlob/AzureBlob.csproj index 5863e186ab..226c012c96 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 cd9e5cd193..05fe9a940b 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 3fd8400239..5dfda97978 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 89141c6a0e..dffd36b3d5 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 b305f80bf0..1573ddc7b1 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 22e398ef9f..eae640279c 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 6ecf2553b6..0000000000 --- a/src/DataProtection/version.props +++ /dev/null @@ -1,18 +0,0 @@ - - - 2.1.1 - rtm - $(VersionPrefix) - $(VersionPrefix)-$(VersionSuffix)-final - t000 - a- - $(FeatureBranchVersionPrefix)$(VersionSuffix)-$([System.Text.RegularExpressions.Regex]::Replace('$(FeatureBranchVersionSuffix)', '[^\w-]', '-')) - $(VersionSuffix)-$(BuildNumber) - - 0.4.1 - rtm - $(ExperimentalVersionPrefix) - $(ExperimentalVersionPrefix)-$(ExperimentalVersionSuffix)-final - $(ExperimentalVersionSuffix)-$(BuildNumber) - - From 25812764031111560a7585fbd4eee4ab5f5092f8 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Tue, 13 Nov 2018 18:34:13 +0000 Subject: [PATCH 471/471] Updating BuildTools from 2.1.3-rtm-15845 to 2.1.3-rtm-15846 [auto-updated: buildtools] --- korebuild-lock.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 65061b1d21..c662868420 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.3-rtm-15845 -commithash:c808c3c16cbc75c88ee39abd2e15569657312474 +version:2.1.3-rtm-15846 +commithash:2444fbdf4f909c90222129d39cc2f588bb14b414